source: trunk/server/source3/lib/popt_common.c

Last change on this file was 953, checked in by dmik, 9 years ago

samba server: Properly derive log file suffix from program name.

The code removing the path didn't expect back slashes or the
.exe extension in the name and could result into invalid
(no log file at all) or strange (ending with .exe) log file
names.

File size: 15.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Common popt routines
4
5 Copyright (C) Tim Potter 2001,2002
6 Copyright (C) Jelmer Vernooij 2002,2003
7 Copyright (C) James Peach 2006
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "includes.h"
24#include "system/filesys.h"
25#include "popt_common.h"
26
27/* Handle command line options:
28 * -d,--debuglevel
29 * -s,--configfile
30 * -O,--socket-options
31 * -V,--version
32 * -l,--log-base
33 * -n,--netbios-name
34 * -W,--workgroup
35 * -i,--scope
36 */
37
38enum {OPT_OPTION=1};
39
40extern bool override_logfile;
41
42#ifdef __OS2__
43static void set_logfile(poptContext con, const char * arg, bool setcmdline)
44#else
45static void set_logfile(poptContext con, const char * arg)
46#endif
47{
48
49 char *lfile = NULL;
50 const char *pname;
51
52 /* Find out basename of current program */
53#ifdef __OS2__
54 char *fname = SMB_STRDUP(_getname(poptGetInvocationName(con)));
55 _remext(fname);
56 pname = fname;
57#else
58 pname = strrchr_m(poptGetInvocationName(con),'/');
59
60 if (!pname)
61 pname = poptGetInvocationName(con);
62 else
63 pname++;
64#endif
65
66 if (asprintf(&lfile, "%s/log.%s", arg, pname) < 0) {
67 return;
68 }
69 lp_set_logfile(lfile);
70#ifdef __OS2__
71 if (setcmdline) {
72 lp_set_cmdline("log file", lfile);
73 }
74 SAFE_FREE(fname);
75#endif
76
77 SAFE_FREE(lfile);
78}
79
80static bool PrintSambaVersionString;
81
82static void popt_s3_talloc_log_fn(const char *message)
83{
84 DEBUG(0,("%s", message));
85}
86
87static void popt_common_callback(poptContext con,
88 enum poptCallbackReason reason,
89 const struct poptOption *opt,
90 const char *arg, const void *data)
91{
92
93 if (reason == POPT_CALLBACK_REASON_PRE) {
94#ifdef __OS2__
95 set_logfile(con, get_dyn_LOGFILEBASE(), false);
96#else
97 set_logfile(con, get_dyn_LOGFILEBASE());
98#endif
99 talloc_set_log_fn(popt_s3_talloc_log_fn);
100 talloc_set_abort_fn(smb_panic);
101 return;
102 }
103
104 if (reason == POPT_CALLBACK_REASON_POST) {
105
106 if (PrintSambaVersionString) {
107 printf( "Version %s\n", samba_version_string());
108 exit(0);
109 }
110
111 if (is_default_dyn_CONFIGFILE()) {
112 if(getenv("SMB_CONF_PATH")) {
113 set_dyn_CONFIGFILE(getenv("SMB_CONF_PATH"));
114 }
115 }
116
117 /* Further 'every Samba program must do this' hooks here. */
118 return;
119 }
120
121 switch(opt->val) {
122 case OPT_OPTION:
123 if (!lp_set_option(arg)) {
124 fprintf(stderr, "Error setting option '%s'\n", arg);
125 exit(1);
126 }
127 break;
128
129 case 'd':
130 if (arg) {
131 lp_set_cmdline("log level", arg);
132 }
133 break;
134
135 case 'V':
136 PrintSambaVersionString = True;
137 break;
138
139 case 'O':
140 if (arg) {
141 lp_do_parameter(-1, "socket options", arg);
142 }
143 break;
144
145 case 's':
146 if (arg) {
147 set_dyn_CONFIGFILE(arg);
148 }
149 break;
150
151 case 'n':
152 if (arg) {
153 set_global_myname(arg);
154 }
155 break;
156
157 case 'l':
158 if (arg) {
159#ifdef __OS2__
160 set_logfile(con, arg, true);
161#else
162 set_logfile(con, arg);
163#endif
164 override_logfile = True;
165 set_dyn_LOGFILEBASE(arg);
166 }
167 break;
168
169 case 'i':
170 if (arg) {
171 set_global_scope(arg);
172 }
173 break;
174
175 case 'W':
176 if (arg) {
177 set_global_myworkgroup(arg);
178 }
179 break;
180 }
181}
182
183struct poptOption popt_common_connection[] = {
184 { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
185 { "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use",
186 "SOCKETOPTIONS" },
187 { "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" },
188 { "workgroup", 'W', POPT_ARG_STRING, NULL, 'W', "Set the workgroup name", "WORKGROUP" },
189 { "scope", 'i', POPT_ARG_STRING, NULL, 'i', "Use this Netbios scope", "SCOPE" },
190
191 POPT_TABLEEND
192};
193
194struct poptOption popt_common_samba[] = {
195 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
196 { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
197 { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
198 { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Base name for log files", "LOGFILEBASE" },
199 { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
200 { "option", 0, POPT_ARG_STRING, NULL, OPT_OPTION, "Set smb.conf option from command line", "name=value" },
201 POPT_TABLEEND
202};
203
204struct poptOption popt_common_configfile[] = {
205 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
206 { "configfile", 0, POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
207 POPT_TABLEEND
208};
209
210struct poptOption popt_common_version[] = {
211 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)popt_common_callback },
212 { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
213 POPT_TABLEEND
214};
215
216struct poptOption popt_common_debuglevel[] = {
217 { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
218 { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
219 POPT_TABLEEND
220};
221
222struct poptOption popt_common_option[] = {
223 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)popt_common_callback },
224 { "option", 0, POPT_ARG_STRING, NULL, OPT_OPTION, "Set smb.conf option from command line", "name=value" },
225 POPT_TABLEEND
226};
227
228/* Handle command line options:
229 * --sbindir
230 * --bindir
231 * --swatdir
232 * --lmhostsfile
233 * --libdir
234 * --modulesdir
235 * --shlibext
236 * --lockdir
237 * --statedir
238 * --cachedir
239 * --piddir
240 * --smb-passwd-file
241 * --private-dir
242 */
243
244enum dyn_item{
245 DYN_SBINDIR = 1,
246 DYN_BINDIR,
247 DYN_SWATDIR,
248 DYN_LMHOSTSFILE,
249 DYN_LIBDIR,
250 DYN_MODULESDIR,
251 DYN_SHLIBEXT,
252 DYN_LOCKDIR,
253 DYN_STATEDIR,
254 DYN_CACHEDIR,
255 DYN_PIDDIR,
256 DYN_SMB_PASSWD_FILE,
257 DYN_PRIVATE_DIR,
258};
259
260
261static void popt_dynconfig_callback(poptContext con,
262 enum poptCallbackReason reason,
263 const struct poptOption *opt,
264 const char *arg, const void *data)
265{
266
267 switch (opt->val) {
268 case DYN_SBINDIR:
269 if (arg) {
270 set_dyn_SBINDIR(arg);
271 }
272 break;
273
274 case DYN_BINDIR:
275 if (arg) {
276 set_dyn_BINDIR(arg);
277 }
278 break;
279
280 case DYN_SWATDIR:
281 if (arg) {
282 set_dyn_SWATDIR(arg);
283 }
284 break;
285
286 case DYN_LMHOSTSFILE:
287 if (arg) {
288 set_dyn_LMHOSTSFILE(arg);
289 }
290 break;
291
292 case DYN_LIBDIR:
293 if (arg) {
294 set_dyn_LIBDIR(arg);
295 }
296 break;
297
298 case DYN_MODULESDIR:
299 if (arg) {
300 set_dyn_MODULESDIR(arg);
301 }
302 break;
303
304 case DYN_SHLIBEXT:
305 if (arg) {
306 set_dyn_SHLIBEXT(arg);
307 }
308 break;
309
310 case DYN_LOCKDIR:
311 if (arg) {
312 set_dyn_LOCKDIR(arg);
313 }
314 break;
315
316 case DYN_STATEDIR:
317 if (arg) {
318 set_dyn_STATEDIR(arg);
319 }
320 break;
321
322 case DYN_CACHEDIR:
323 if (arg) {
324 set_dyn_CACHEDIR(arg);
325 }
326 break;
327
328 case DYN_PIDDIR:
329 if (arg) {
330 set_dyn_PIDDIR(arg);
331 }
332 break;
333
334 case DYN_SMB_PASSWD_FILE:
335 if (arg) {
336 set_dyn_SMB_PASSWD_FILE(arg);
337 }
338 break;
339
340 case DYN_PRIVATE_DIR:
341 if (arg) {
342 set_dyn_PRIVATE_DIR(arg);
343 }
344 break;
345
346 }
347}
348
349const struct poptOption popt_common_dynconfig[] = {
350
351 { NULL, '\0', POPT_ARG_CALLBACK, (void *)popt_dynconfig_callback },
352
353 { "sbindir", '\0' , POPT_ARG_STRING, NULL, DYN_SBINDIR,
354 "Path to sbin directory", "SBINDIR" },
355 { "bindir", '\0' , POPT_ARG_STRING, NULL, DYN_BINDIR,
356 "Path to bin directory", "BINDIR" },
357 { "swatdir", '\0' , POPT_ARG_STRING, NULL, DYN_SWATDIR,
358 "Path to SWAT installation directory", "SWATDIR" },
359 { "lmhostsfile", '\0' , POPT_ARG_STRING, NULL, DYN_LMHOSTSFILE,
360 "Path to lmhosts file", "LMHOSTSFILE" },
361 { "libdir", '\0' , POPT_ARG_STRING, NULL, DYN_LIBDIR,
362 "Path to shared library directory", "LIBDIR" },
363 { "modulesdir", '\0' , POPT_ARG_STRING, NULL, DYN_MODULESDIR,
364 "Path to shared modules directory", "MODULESDIR" },
365 { "shlibext", '\0' , POPT_ARG_STRING, NULL, DYN_SHLIBEXT,
366 "Shared library extension", "SHLIBEXT" },
367 { "lockdir", '\0' , POPT_ARG_STRING, NULL, DYN_LOCKDIR,
368 "Path to lock file directory", "LOCKDIR" },
369 { "statedir", '\0' , POPT_ARG_STRING, NULL, DYN_STATEDIR,
370 "Path to persistent state file directory", "STATEDIR" },
371 { "cachedir", '\0' , POPT_ARG_STRING, NULL, DYN_CACHEDIR,
372 "Path to temporary cache file directory", "CACHEDIR" },
373 { "piddir", '\0' , POPT_ARG_STRING, NULL, DYN_PIDDIR,
374 "Path to PID file directory", "PIDDIR" },
375 { "smb-passwd-file", '\0' , POPT_ARG_STRING, NULL, DYN_SMB_PASSWD_FILE,
376 "Path to smbpasswd file", "SMB_PASSWD_FILE" },
377 { "private-dir", '\0' , POPT_ARG_STRING, NULL, DYN_PRIVATE_DIR,
378 "Path to private data directory", "PRIVATE_DIR" },
379
380 POPT_TABLEEND
381};
382
383/****************************************************************************
384 * get a password from a a file or file descriptor
385 * exit on failure
386 * ****************************************************************************/
387
388static void get_password_file(struct user_auth_info *auth_info)
389{
390 int fd = -1;
391 char *p;
392 bool close_it = False;
393 char *spec = NULL;
394 char pass[128];
395
396 if ((p = getenv("PASSWD_FD")) != NULL) {
397 if (asprintf(&spec, "descriptor %s", p) < 0) {
398 return;
399 }
400 sscanf(p, "%d", &fd);
401 close_it = false;
402 } else if ((p = getenv("PASSWD_FILE")) != NULL) {
403 fd = sys_open(p, O_RDONLY, 0);
404 spec = SMB_STRDUP(p);
405 if (fd < 0) {
406 fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
407 spec, strerror(errno));
408 exit(1);
409 }
410 close_it = True;
411 }
412
413 if (fd < 0) {
414 fprintf(stderr, "fd = %d, < 0\n", fd);
415 exit(1);
416 }
417
418 for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
419 p && p - pass < sizeof(pass);) {
420 switch (read(fd, p, 1)) {
421 case 1:
422 if (*p != '\n' && *p != '\0') {
423 *++p = '\0'; /* advance p, and null-terminate pass */
424 break;
425 }
426 case 0:
427 if (p - pass) {
428 *p = '\0'; /* null-terminate it, just in case... */
429 p = NULL; /* then force the loop condition to become false */
430 break;
431 } else {
432 fprintf(stderr, "Error reading password from file %s: %s\n",
433 spec, "empty password\n");
434 SAFE_FREE(spec);
435 exit(1);
436 }
437
438 default:
439 fprintf(stderr, "Error reading password from file %s: %s\n",
440 spec, strerror(errno));
441 SAFE_FREE(spec);
442 exit(1);
443 }
444 }
445 SAFE_FREE(spec);
446
447 set_cmdline_auth_info_password(auth_info, pass);
448 if (close_it) {
449 close(fd);
450 }
451}
452
453static void get_credentials_file(struct user_auth_info *auth_info,
454 const char *file)
455{
456 XFILE *auth;
457 fstring buf;
458 uint16 len = 0;
459 char *ptr, *val, *param;
460
461 if ((auth=x_fopen(file, O_RDONLY, 0)) == NULL)
462 {
463 /* fail if we can't open the credentials file */
464 d_printf("ERROR: Unable to open credentials file!\n");
465 exit(-1);
466 }
467
468 while (!x_feof(auth))
469 {
470 /* get a line from the file */
471 if (!x_fgets(buf, sizeof(buf), auth))
472 continue;
473 len = strlen(buf);
474
475 if ((len) && (buf[len-1]=='\n'))
476 {
477 buf[len-1] = '\0';
478 len--;
479 }
480 if (len == 0)
481 continue;
482
483 /* break up the line into parameter & value.
484 * will need to eat a little whitespace possibly */
485 param = buf;
486 if (!(ptr = strchr_m (buf, '=')))
487 continue;
488
489 val = ptr+1;
490 *ptr = '\0';
491
492 /* eat leading white space */
493 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
494 val++;
495
496 if (strwicmp("password", param) == 0) {
497 set_cmdline_auth_info_password(auth_info, val);
498 } else if (strwicmp("username", param) == 0) {
499 set_cmdline_auth_info_username(auth_info, val);
500 } else if (strwicmp("domain", param) == 0) {
501 set_global_myworkgroup(val);
502 }
503 memset(buf, 0, sizeof(buf));
504 }
505 x_fclose(auth);
506}
507
508/* Handle command line options:
509 * -U,--user
510 * -A,--authentication-file
511 * -k,--use-kerberos
512 * -N,--no-pass
513 * -S,--signing
514 * -P --machine-pass
515 * -e --encrypt
516 * -C --use-ccache
517 */
518
519
520static void popt_common_credentials_callback(poptContext con,
521 enum poptCallbackReason reason,
522 const struct poptOption *opt,
523 const char *arg, const void *data)
524{
525 struct user_auth_info *auth_info = talloc_get_type_abort(
526 *((const char **)data), struct user_auth_info);
527 char *p;
528
529 if (reason == POPT_CALLBACK_REASON_PRE) {
530 set_cmdline_auth_info_username(auth_info, "GUEST");
531
532 if (getenv("LOGNAME")) {
533 set_cmdline_auth_info_username(auth_info,
534 getenv("LOGNAME"));
535 }
536
537 if (getenv("USER")) {
538 char *puser = SMB_STRDUP(getenv("USER"));
539 if (!puser) {
540 exit(ENOMEM);
541 }
542 set_cmdline_auth_info_username(auth_info, puser);
543
544 if ((p = strchr_m(puser,'%'))) {
545 size_t len;
546 *p = 0;
547 len = strlen(p+1);
548 set_cmdline_auth_info_password(auth_info, p+1);
549 memset(strchr_m(getenv("USER"),'%')+1,'X',len);
550 }
551 SAFE_FREE(puser);
552 }
553
554 if (getenv("PASSWD")) {
555 set_cmdline_auth_info_password(auth_info,
556 getenv("PASSWD"));
557 }
558
559 if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
560 get_password_file(auth_info);
561 }
562
563 return;
564 }
565
566 switch(opt->val) {
567 case 'U':
568 {
569 char *lp;
570 char *puser = SMB_STRDUP(arg);
571
572 if ((lp=strchr_m(puser,'%'))) {
573 size_t len;
574 *lp = 0;
575 set_cmdline_auth_info_username(auth_info,
576 puser);
577 set_cmdline_auth_info_password(auth_info,
578 lp+1);
579 len = strlen(lp+1);
580 memset(strchr_m(arg,'%')+1,'X',len);
581 } else {
582 set_cmdline_auth_info_username(auth_info,
583 puser);
584 }
585 SAFE_FREE(puser);
586 }
587 break;
588
589 case 'A':
590 get_credentials_file(auth_info, arg);
591 break;
592
593 case 'k':
594#ifndef HAVE_KRB5
595 d_printf("No kerberos support compiled in\n");
596 exit(1);
597#else
598 set_cmdline_auth_info_use_krb5_ticket(auth_info);
599#endif
600 break;
601
602 case 'S':
603 if (!set_cmdline_auth_info_signing_state(auth_info, arg)) {
604 fprintf(stderr, "Unknown signing option %s\n", arg );
605 exit(1);
606 }
607 break;
608 case 'P':
609 set_cmdline_auth_info_use_machine_account(auth_info);
610 break;
611 case 'N':
612 set_cmdline_auth_info_password(auth_info, "");
613 break;
614 case 'e':
615 set_cmdline_auth_info_smb_encrypt(auth_info);
616 break;
617 case 'C':
618 set_cmdline_auth_info_use_ccache(auth_info, true);
619 break;
620 }
621}
622
623static struct user_auth_info *global_auth_info;
624
625void popt_common_set_auth_info(struct user_auth_info *auth_info)
626{
627 global_auth_info = auth_info;
628}
629
630struct poptOption popt_common_credentials[] = {
631 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE,
632 (void *)popt_common_credentials_callback, 0,
633 (const char *)&global_auth_info },
634 { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" },
635 { "no-pass", 'N', POPT_ARG_NONE, NULL, 'N', "Don't ask for a password" },
636 { "kerberos", 'k', POPT_ARG_NONE, NULL, 'k', "Use kerberos (active directory) authentication" },
637 { "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
638 { "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" },
639 {"machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password" },
640 {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
641 {"use-ccache", 'C', POPT_ARG_NONE, NULL, 'C',
642 "Use the winbind ccache for authentication" },
643 POPT_TABLEEND
644};
Note: See TracBrowser for help on using the repository browser.