tdb: version 1.4.12
[samba4-gss.git] / lib / cmdline / cmdline.c
bloba42707238f62733286a1605c32ee9a74ec8de718
1 /*
2 * Copyright (c) 2020 Andreas Schneider <asn@samba.org>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "includes.h"
19 #include "lib/param/param.h"
20 #include "dynconfig/dynconfig.h"
21 #include "auth/gensec/gensec.h"
22 #include "libcli/smb/smb_util.h"
23 #include "cmdline_private.h"
24 #include "lib/util/util_process.h"
26 #include <samba/version.h>
28 static TALLOC_CTX *cmdline_mem_ctx;
29 static struct loadparm_context *cmdline_lp_ctx;
30 static struct cli_credentials *cmdline_creds;
31 static samba_cmdline_load_config cmdline_load_config_fn;
32 static struct samba_cmdline_daemon_cfg cmdline_daemon_cfg;
34 static NTSTATUS (*cli_credentials_set_machine_account_fn)(
35 struct cli_credentials *cred,
36 struct loadparm_context *lp_ctx) =
37 cli_credentials_set_machine_account;
39 /* PRIVATE */
40 bool samba_cmdline_set_talloc_ctx(TALLOC_CTX *mem_ctx)
42 if (cmdline_mem_ctx != NULL) {
43 return false;
46 cmdline_mem_ctx = mem_ctx;
47 return true;
50 TALLOC_CTX *samba_cmdline_get_talloc_ctx(void)
52 return cmdline_mem_ctx;
55 static void _samba_cmdline_talloc_log(const char *message)
57 D_ERR("%s", message);
60 bool samba_cmdline_init_common(TALLOC_CTX *mem_ctx)
62 bool ok;
64 ok = samba_cmdline_set_talloc_ctx(mem_ctx);
65 if (!ok) {
66 return false;
69 cmdline_daemon_cfg = (struct samba_cmdline_daemon_cfg) {
70 .fork = true,
73 fault_setup();
76 * Log to stderr by default.
77 * This can be changed to stdout using the option: --debug-stdout
79 setup_logging(getprogname(), DEBUG_DEFAULT_STDERR);
81 talloc_set_log_fn(_samba_cmdline_talloc_log);
82 talloc_set_abort_fn(smb_panic);
84 return true;
87 bool samba_cmdline_set_load_config_fn(samba_cmdline_load_config fn)
89 cmdline_load_config_fn = fn;
90 return true;
93 /* PUBLIC */
94 bool samba_cmdline_set_lp_ctx(struct loadparm_context *lp_ctx)
96 if (lp_ctx == NULL) {
97 return false;
99 cmdline_lp_ctx = lp_ctx;
101 return true;
104 struct loadparm_context *samba_cmdline_get_lp_ctx(void)
106 return cmdline_lp_ctx;
109 bool samba_cmdline_set_creds(struct cli_credentials *creds)
111 if (creds == NULL) {
112 return false;
115 TALLOC_FREE(cmdline_creds);
116 cmdline_creds = creds;
118 return true;
121 struct cli_credentials *samba_cmdline_get_creds(void)
123 return cmdline_creds;
126 struct samba_cmdline_daemon_cfg *samba_cmdline_get_daemon_cfg(void)
128 return &cmdline_daemon_cfg;
131 void samba_cmdline_set_machine_account_fn(
132 NTSTATUS (*fn) (struct cli_credentials *cred,
133 struct loadparm_context *lp_ctx))
135 cli_credentials_set_machine_account_fn = fn;
139 * Are the strings p and option equal from the point of view of option
140 * parsing, meaning is the next character '\0' or '='.
142 static bool strneq_cmdline_exact(const char *p, const char *option, size_t len)
144 if (strncmp(p, option, len) == 0) {
145 if (p[len] == 0 || p[len] == '=') {
146 return true;
149 return false;
153 * Return true if the argument to the option should be redacted.
155 * The option name is presumed to contain the substring "pass". It is checked
156 * against a list of options that specify secrets. If it is there, the value
157 * should be redacted and we return early.
159 * Otherwise, it is checked against a list of known safe options. If it is
160 * there, we return false.
162 * If the option is not in either list, we assume it might be secret and
163 * redact the argument, but warn loudly about it. The hope is that developers
164 * will see what they're doing and add the option to the appropriate list.
166 * If true is returned, *ulen will be set to the apparent length of the
167 * option. It is set to zero if false is returned (we don't need it in that
168 * case).
170 static bool is_password_option(const char *p, size_t *ulen)
172 size_t i, len;
173 static const char *must_burn[] = {
174 "--password",
175 "--newpassword",
176 "--password2",
177 "--adminpass",
178 "--dnspass",
179 "--machinepass",
180 "--krbtgtpass",
181 "--fixed-password",
183 static const char *allowed[] = {
184 "--bad-password-count-reset",
185 "--badpassword-frequency",
186 "--change-user-password",
187 "--force-initialized-passwords",
188 "--machine-pass", /* distinct from --machinepass */
189 "--managed-password-interval",
190 "--no-pass",
191 "--no-pass2",
192 "--no-passthrough",
193 "--no-password",
194 "--passcmd",
195 "--passwd",
196 "--passwd_path",
197 "--password-file",
198 "--password-from-stdin",
199 "--random-password",
200 "--smbpasswd-style",
201 "--strip-passed-output",
202 "--with-smbpasswd-file",
205 char *equals = NULL;
206 *ulen = 0;
208 for (i = 0; i < ARRAY_SIZE(must_burn); i++) {
209 bool secret;
210 len = strlen(must_burn[i]);
211 secret = strneq_cmdline_exact(p, must_burn[i], len);
212 if (secret) {
213 *ulen = len;
214 return true;
218 for (i = 0; i < ARRAY_SIZE(allowed); i++) {
219 bool safe;
220 len = strlen(allowed[i]);
221 safe = strneq_cmdline_exact(p, allowed[i], len);
222 if (safe) {
223 return false;
227 * We have found a suspicious option, and we need to work out where to
228 * burn it from. It could be
230 * --secret-password=cow -> password after '='
231 * --secret-password -> password is in next argument.
233 * but we also have the possibility of
235 * --cow=secret-password
237 * that is, the 'pass' in this option string is not in the option but
238 * the argument to it, which should not be burnt.
240 equals = strchr(p, '=');
241 if (equals == NULL) {
242 *ulen = strlen(p);
243 } else {
244 char *pass = (strstr(p, "pass"));
245 if (pass > equals) {
246 /* this is --foo=pass, not --pass=foo */
247 return false;
249 *ulen = equals - p;
252 * This message will be seen with Python tools when an option
253 * is misspelt, but not with C tools, because in C burning
254 * happens after the command line is parsed, while in Python
255 * it happens before (on a copy of argv).
257 * In either case it will appear for a newly added option, and
258 * we hope developers will notice it before pushing.
260 DBG_ERR("\nNote for developers: if '%*s' is not misspelt, it should be "
261 "added to the appropriate list in is_password_option().\n\n",
262 (int)(*ulen), p);
263 return true;
266 bool samba_cmdline_burn(int argc, char *argv[])
268 bool burnt = false;
269 int i;
271 for (i = 0; i < argc; i++) {
272 bool found = false;
273 bool is_user = false;
274 size_t ulen = 0;
275 char *p = NULL;
277 p = argv[i];
278 if (p == NULL) {
279 return burnt;
282 if (strncmp(p, "-U", 2) == 0) {
284 * Note: this won't catch combinations of
285 * short options like
286 * `samba-tool -NUAdministrator%...`, which is
287 * not possible in general outside of the
288 * actual parser (consider for example
289 * `-NHUroot%password`, which parses as
290 * `-N -H 'Uroot%password'`). We don't know
291 * here which short options might take
292 * arguments.
294 * This is an argument for embedding redaction
295 * inside the parser (e.g. by adding a flag to
296 * the option definitions), but we decided not
297 * to do that in order to share cmdline_burn().
299 ulen = 2;
300 found = true;
301 is_user = true;
302 } else if (strneq_cmdline_exact(p, "--user", 6)) {
303 ulen = 6;
304 found = true;
305 is_user = true;
306 } else if (strneq_cmdline_exact(p, "--username", 10)) {
307 ulen = 10;
308 found = true;
309 is_user = true;
310 } else if (strncmp(p, "--", 2) == 0 && strstr(p, "pass")) {
312 * We have many secret options like --password,
313 * --adminpass, --newpassword, and we could easily
314 * add more, so we will use an allowlist to let the
315 * safe ones through (of which there are also many).
317 found = is_password_option(p, &ulen);
320 if (found) {
321 if (strlen(p) == ulen) {
323 * The option string has no '=', so
324 * its argument will come in the NEXT
325 * argv member. If there is one, we
326 * can just step forward and take it,
327 * setting ulen to 0.
329 * {"--password=secret"} --> {"--password"}
330 * {"--password", "secret"} --> {"--password", ""}
331 * {"-Uadmin%secret"} --> {"-Uadmin"}
332 * {"-U", "admin%secret"} --> {"-U", "admin"}
334 i++;
335 if (i == argc) {
337 * this looks like an invalid
338 * command line, but that's
339 * for the caller to decide.
341 return burnt;
343 p = argv[i];
344 if (p == NULL) {
345 return burnt;
347 ulen = 0;
350 if (is_user) {
351 char *q = strchr_m(p, '%');
352 if (q == NULL) {
353 /* -U without '%' has no secret */
354 continue;
356 p = q;
357 } else {
358 p += ulen;
361 memset_s(p, strlen(p), '\0', strlen(p));
362 burnt = true;
365 return burnt;
368 static bool is_popt_table_end(const struct poptOption *o)
370 if (o->longName == NULL &&
371 o->shortName == 0 &&
372 o->argInfo == 0 &&
373 o->arg == NULL &&
374 o->val == 0 &&
375 o->descrip == NULL &&
376 o->argDescrip == NULL) {
377 return true;
380 return false;
383 static void find_duplicates(const struct poptOption *needle,
384 const struct poptOption *haystack,
385 size_t *count)
387 for(;
388 !is_popt_table_end(haystack);
389 haystack++) {
390 switch (haystack->argInfo) {
391 case POPT_ARG_INCLUDE_TABLE:
392 if (haystack->arg != NULL) {
393 find_duplicates(needle, haystack->arg, count);
396 break;
397 default:
398 if (needle->shortName != 0 &&
399 needle->shortName == haystack->shortName) {
400 (*count)++;
401 break;
404 if (needle->longName != NULL &&
405 haystack->longName != NULL &&
406 strequal(needle->longName, haystack->longName)) {
407 (*count)++;
408 break;
410 break;
413 if (*count > 1) {
414 return;
419 static bool cmdline_sanity_checker(const struct poptOption *current_opts,
420 const struct poptOption *full_opts)
422 const struct poptOption *o = current_opts;
424 for(;
425 !is_popt_table_end(o);
426 o++) {
427 bool ok;
429 switch (o->argInfo) {
430 case POPT_ARG_INCLUDE_TABLE:
431 if (o->arg != NULL) {
432 ok = cmdline_sanity_checker(o->arg, full_opts);
433 if (!ok) {
434 return false;
438 break;
439 default:
440 if (o->longName != NULL || o->shortName != 0) {
441 size_t count = 0;
443 find_duplicates(o, full_opts, &count);
444 if (count > 1) {
445 DBG_ERR("Duplicate option '--%s|-%c' "
446 "detected!\n",
447 o->longName,
448 o->shortName != 0 ?
449 o->shortName :
450 '-');
451 return false;
455 break;
459 return true;
462 bool samba_cmdline_sanity_check(const struct poptOption *opts)
464 return cmdline_sanity_checker(opts, opts);
467 poptContext samba_popt_get_context(const char * name,
468 int argc, const char ** argv,
469 const struct poptOption * options,
470 unsigned int flags)
472 #ifdef DEVELOPER
473 bool ok;
475 ok = samba_cmdline_sanity_check(options);
476 if (!ok) {
477 return NULL;
479 #endif
480 process_save_binary_name(name);
481 return poptGetContext(name, argc, argv, options, flags);
484 /**********************************************************
485 * COMMON SAMBA POPT
486 **********************************************************/
488 static bool log_to_file;
490 static bool set_logfile(TALLOC_CTX *mem_ctx,
491 struct loadparm_context *lp_ctx,
492 const char *log_basename,
493 const char *process_name,
494 bool from_cmdline)
496 bool ok = false;
497 char *new_logfile = talloc_asprintf(mem_ctx,
498 "%s/log.%s",
499 log_basename,
500 process_name);
501 if (new_logfile == NULL) {
502 return false;
505 if (from_cmdline) {
506 ok = lpcfg_set_cmdline(lp_ctx,
507 "log file",
508 new_logfile);
509 } else {
510 ok = lpcfg_do_global_parameter(lp_ctx,
511 "log file",
512 new_logfile);
514 if (!ok) {
515 fprintf(stderr,
516 "Failed to set log to %s\n",
517 new_logfile);
518 TALLOC_FREE(new_logfile);
519 return false;
521 debug_set_logfile(new_logfile);
522 TALLOC_FREE(new_logfile);
524 return true;
527 static void popt_samba_callback(poptContext popt_ctx,
528 enum poptCallbackReason reason,
529 const struct poptOption *opt,
530 const char *arg, const void *data)
532 TALLOC_CTX *mem_ctx = samba_cmdline_get_talloc_ctx();
533 struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
534 const char *pname = NULL;
535 bool ok;
537 /* Find out basename of current program */
538 pname = getprogname();
540 if (reason == POPT_CALLBACK_REASON_PRE) {
541 if (lp_ctx == NULL) {
542 fprintf(stderr,
543 "Command line parsing not initialized!\n");
544 exit(1);
546 ok = set_logfile(mem_ctx,
547 lp_ctx,
548 get_dyn_LOGFILEBASE(),
549 pname,
550 false);
551 if (!ok) {
552 fprintf(stderr,
553 "Failed to set log file for %s\n",
554 pname);
555 exit(1);
557 return;
560 if (reason == POPT_CALLBACK_REASON_POST) {
561 ok = cmdline_load_config_fn();
562 if (!ok) {
563 fprintf(stderr,
564 "%s - Failed to load config file!\n",
565 getprogname());
566 exit(1);
569 if (log_to_file) {
570 const struct loadparm_substitution *lp_sub =
571 lpcfg_noop_substitution();
572 char *logfile = NULL;
574 logfile = lpcfg_logfile(lp_ctx, lp_sub, mem_ctx);
575 if (logfile == NULL) {
576 fprintf(stderr,
577 "Failed to setup logging to file!");
578 exit(1);
580 debug_set_logfile(logfile);
581 setup_logging(logfile, DEBUG_FILE);
582 TALLOC_FREE(logfile);
585 return;
588 switch(opt->val) {
589 case OPT_LEAK_REPORT:
590 talloc_enable_leak_report();
591 break;
592 case OPT_LEAK_REPORT_FULL:
593 talloc_enable_leak_report_full();
594 break;
595 case OPT_OPTION:
596 if (arg != NULL) {
597 ok = lpcfg_set_option(lp_ctx, arg);
598 if (!ok) {
599 fprintf(stderr, "Error setting option '%s'\n", arg);
600 exit(1);
603 break;
604 case 'd':
605 if (arg != NULL) {
606 ok = lpcfg_set_cmdline(lp_ctx, "log level", arg);
607 if (!ok) {
608 fprintf(stderr,
609 "Failed to set debug level to: %s\n",
610 arg);
611 exit(1);
614 break;
615 case OPT_DEBUG_STDOUT:
616 setup_logging(pname, DEBUG_STDOUT);
617 break;
618 case OPT_CONFIGFILE:
619 if (arg != NULL) {
620 set_dyn_CONFIGFILE(arg);
622 break;
623 case 'l':
624 if (arg != NULL) {
625 ok = set_logfile(mem_ctx, lp_ctx, arg, pname, true);
626 if (!ok) {
627 fprintf(stderr,
628 "Failed to set log file for %s\n",
629 arg);
630 exit(1);
632 log_to_file = true;
634 set_dyn_LOGFILEBASE(arg);
636 break;
640 static struct poptOption popt_common_debug[] = {
642 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
643 .arg = (void *)popt_samba_callback,
646 .longName = "debuglevel",
647 .shortName = 'd',
648 .argInfo = POPT_ARG_STRING,
649 .val = 'd',
650 .descrip = "Set debug level",
651 .argDescrip = "DEBUGLEVEL",
654 .longName = "debug-stdout",
655 .argInfo = POPT_ARG_NONE,
656 .val = OPT_DEBUG_STDOUT,
657 .descrip = "Send debug output to standard output",
659 POPT_TABLEEND
662 static struct poptOption popt_common_option[] = {
664 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
665 .arg = (void *)popt_samba_callback,
668 .longName = "option",
669 .argInfo = POPT_ARG_STRING,
670 .val = OPT_OPTION,
671 .descrip = "Set smb.conf option from command line",
672 .argDescrip = "name=value",
674 POPT_TABLEEND
677 static struct poptOption popt_common_config[] = {
679 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
680 .arg = (void *)popt_samba_callback,
683 .longName = "configfile",
684 .argInfo = POPT_ARG_STRING,
685 .val = OPT_CONFIGFILE,
686 .descrip = "Use alternative configuration file",
687 .argDescrip = "CONFIGFILE",
689 POPT_TABLEEND
692 static struct poptOption popt_common_samba[] = {
694 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
695 .arg = (void *)popt_samba_callback,
698 .longName = "debuglevel",
699 .shortName = 'd',
700 .argInfo = POPT_ARG_STRING,
701 .val = 'd',
702 .descrip = "Set debug level",
703 .argDescrip = "DEBUGLEVEL",
706 .longName = "debug-stdout",
707 .argInfo = POPT_ARG_NONE,
708 .val = OPT_DEBUG_STDOUT,
709 .descrip = "Send debug output to standard output",
712 .longName = "configfile",
713 .shortName = 's',
714 .argInfo = POPT_ARG_STRING,
715 .val = OPT_CONFIGFILE,
716 .descrip = "Use alternative configuration file",
717 .argDescrip = "CONFIGFILE",
720 .longName = "option",
721 .argInfo = POPT_ARG_STRING,
722 .val = OPT_OPTION,
723 .descrip = "Set smb.conf option from command line",
724 .argDescrip = "name=value",
727 .longName = "log-basename",
728 .shortName = 'l',
729 .argInfo = POPT_ARG_STRING,
730 .val = 'l',
731 .descrip = "Basename for log/debug files",
732 .argDescrip = "LOGFILEBASE",
735 .longName = "leak-report",
736 .argInfo = POPT_ARG_NONE,
737 .val = OPT_LEAK_REPORT,
738 .descrip = "enable talloc leak reporting on exit",
741 .longName = "leak-report-full",
742 .argInfo = POPT_ARG_NONE,
743 .val = OPT_LEAK_REPORT_FULL,
744 .descrip = "enable full talloc leak reporting on exit",
746 POPT_TABLEEND
749 static struct poptOption popt_common_samba_ldb[] = {
751 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
752 .arg = (void *)popt_samba_callback,
755 .longName = "debuglevel",
756 .shortName = 'd',
757 .argInfo = POPT_ARG_STRING,
758 .val = 'd',
759 .descrip = "Set debug level",
760 .argDescrip = "DEBUGLEVEL",
763 .longName = "debug-stdout",
764 .argInfo = POPT_ARG_NONE,
765 .val = OPT_DEBUG_STDOUT,
766 .descrip = "Send debug output to standard output",
769 .longName = "configfile",
770 .argInfo = POPT_ARG_STRING,
771 .val = OPT_CONFIGFILE,
772 .descrip = "Use alternative configuration file",
773 .argDescrip = "CONFIGFILE",
776 .longName = "option",
777 .argInfo = POPT_ARG_STRING,
778 .val = OPT_OPTION,
779 .descrip = "Set smb.conf option from command line",
780 .argDescrip = "name=value",
783 .longName = "log-basename",
784 .shortName = 'l',
785 .argInfo = POPT_ARG_STRING,
786 .val = 'l',
787 .descrip = "Basename for log/debug files",
788 .argDescrip = "LOGFILEBASE",
791 .longName = "leak-report",
792 .argInfo = POPT_ARG_NONE,
793 .val = OPT_LEAK_REPORT,
794 .descrip = "enable talloc leak reporting on exit",
797 .longName = "leak-report-full",
798 .argInfo = POPT_ARG_NONE,
799 .val = OPT_LEAK_REPORT_FULL,
800 .descrip = "enable full talloc leak reporting on exit",
802 POPT_TABLEEND
805 /**********************************************************
806 * CONNECTION POPT
807 **********************************************************/
809 static void popt_connection_callback(poptContext popt_ctx,
810 enum poptCallbackReason reason,
811 const struct poptOption *opt,
812 const char *arg,
813 const void *data)
815 struct loadparm_context *lp_ctx = cmdline_lp_ctx;
817 if (reason == POPT_CALLBACK_REASON_PRE) {
818 if (lp_ctx == NULL) {
819 fprintf(stderr,
820 "Command line parsing not initialized!\n");
821 exit(1);
823 return;
826 switch(opt->val) {
827 case 'O':
828 if (arg != NULL) {
829 lpcfg_set_cmdline(lp_ctx, "socket options", arg);
831 break;
832 case 'R':
833 if (arg != NULL) {
834 lpcfg_set_cmdline(lp_ctx, "name resolve order", arg);
836 break;
837 case 'm':
838 if (arg != NULL) {
839 lpcfg_set_cmdline(lp_ctx, "client max protocol", arg);
841 break;
842 case OPT_NETBIOS_SCOPE:
843 if (arg != NULL) {
844 lpcfg_set_cmdline(lp_ctx, "netbios scope", arg);
846 break;
847 case 'n':
848 if (arg != NULL) {
849 lpcfg_set_cmdline(lp_ctx, "netbios name", arg);
851 break;
852 case 'W':
853 if (arg != NULL) {
854 lpcfg_set_cmdline(lp_ctx, "workgroup", arg);
856 break;
857 case 'r':
858 if (arg != NULL) {
859 lpcfg_set_cmdline(lp_ctx, "realm", arg);
861 break;
865 static struct poptOption popt_common_connection[] = {
867 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE,
868 .arg = (void *)popt_connection_callback,
871 .longName = "name-resolve",
872 .shortName = 'R',
873 .argInfo = POPT_ARG_STRING,
874 .val = 'R',
875 .descrip = "Use these name resolution services only",
876 .argDescrip = "NAME-RESOLVE-ORDER",
879 .longName = "socket-options",
880 .shortName = 'O',
881 .argInfo = POPT_ARG_STRING,
882 .val = 'O',
883 .descrip = "socket options to use",
884 .argDescrip = "SOCKETOPTIONS",
887 .longName = "max-protocol",
888 .shortName = 'm',
889 .argInfo = POPT_ARG_STRING,
890 .val = 'm',
891 .descrip = "Set max protocol level",
892 .argDescrip = "MAXPROTOCOL",
895 .longName = "netbiosname",
896 .shortName = 'n',
897 .argInfo = POPT_ARG_STRING,
898 .val = 'n',
899 .descrip = "Primary netbios name",
900 .argDescrip = "NETBIOSNAME",
903 .longName = "netbios-scope",
904 .argInfo = POPT_ARG_STRING,
905 .val = OPT_NETBIOS_SCOPE,
906 .descrip = "Use this Netbios scope",
907 .argDescrip = "SCOPE",
910 .longName = "workgroup",
911 .shortName = 'W',
912 .argInfo = POPT_ARG_STRING,
913 .val = 'W',
914 .descrip = "Set the workgroup name",
915 .argDescrip = "WORKGROUP",
918 .longName = "realm",
919 .argInfo = POPT_ARG_STRING,
920 .val = 'r',
921 .descrip = "Set the realm name",
922 .argDescrip = "REALM",
924 POPT_TABLEEND
927 /**********************************************************
928 * CREDENTIALS POPT
929 **********************************************************/
931 static bool skip_password_callback;
932 static bool machine_account_pending;
934 static void popt_common_credentials_callback(poptContext popt_ctx,
935 enum poptCallbackReason reason,
936 const struct poptOption *opt,
937 const char *arg,
938 const void *data)
940 struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
941 struct cli_credentials *creds = samba_cmdline_get_creds();
942 bool ok;
944 if (reason == POPT_CALLBACK_REASON_PRE) {
945 if (creds == NULL) {
946 fprintf(stderr,
947 "Command line parsing not initialized!\n");
948 exit(1);
950 return;
953 if (reason == POPT_CALLBACK_REASON_POST) {
954 const char *username = NULL;
955 enum credentials_obtained username_obtained =
956 CRED_UNINITIALISED;
957 enum credentials_obtained password_obtained =
958 CRED_UNINITIALISED;
961 * This calls cli_credentials_set_conf() to get the defaults
962 * form smb.conf and set the winbind separator.
964 * Just warn that we can't read the smb.conf. There might not be
965 * one available or we want to ignore it.
967 ok = cli_credentials_guess(creds, lp_ctx);
968 if (!ok) {
969 fprintf(stderr,
970 "Unable to read defaults from smb.conf\n");
973 if (machine_account_pending) {
974 NTSTATUS status;
976 status = cli_credentials_set_machine_account_fn(
977 creds, lp_ctx);
978 if (!NT_STATUS_IS_OK(status)) {
979 fprintf(stderr,
980 "Failed to set machine account: %s\n",
981 nt_errstr(status));
982 exit(1);
987 * When we set the username during the handling of the options
988 * passed to the binary we haven't loaded the config yet. This
989 * means that we didn't take the 'winbind separator' into
990 * account.
992 * The username might contain the domain name and thus it
993 * hasn't been correctly parsed yet. If we have a username we
994 * need to set it again to run the string parser for the
995 * username correctly.
997 username =
998 cli_credentials_get_username_and_obtained(
999 creds, &username_obtained);
1000 if (username_obtained == CRED_SPECIFIED &&
1001 username != NULL && username[0] != '\0') {
1002 cli_credentials_parse_string(creds,
1003 username,
1004 CRED_SPECIFIED);
1007 if (cli_credentials_get_kerberos_state(creds) ==
1008 CRED_USE_KERBEROS_REQUIRED)
1010 enum credentials_obtained ccache_obtained =
1011 CRED_UNINITIALISED;
1012 enum credentials_obtained principal_obtained =
1013 CRED_UNINITIALISED;
1014 bool ccache_valid;
1016 principal_obtained =
1017 cli_credentials_get_principal_obtained(creds);
1018 ccache_valid = cli_credentials_get_ccache_name_obtained(
1019 creds, NULL, NULL, &ccache_obtained);
1020 if (ccache_valid &&
1021 ccache_obtained == principal_obtained)
1023 skip_password_callback = true;
1026 if (!skip_password_callback) {
1027 (void)cli_credentials_get_password_and_obtained(creds,
1028 &password_obtained);
1030 if (!skip_password_callback &&
1031 password_obtained < CRED_CALLBACK) {
1032 ok = cli_credentials_set_cmdline_callbacks(creds);
1033 if (!ok) {
1034 fprintf(stderr,
1035 "Failed to set cmdline password "
1036 "callback\n");
1037 exit(1);
1041 return;
1044 switch(opt->val) {
1045 case 'U':
1046 if (arg != NULL) {
1047 cli_credentials_parse_string(creds,
1048 arg,
1049 CRED_SPECIFIED);
1051 break;
1052 case OPT_PASSWORD:
1053 if (arg != NULL) {
1054 ok = cli_credentials_set_password(creds,
1055 arg,
1056 CRED_SPECIFIED);
1057 if (!ok) {
1058 fprintf(stderr,
1059 "Failed to set password!\n");
1060 exit(1);
1063 skip_password_callback = true;
1065 break;
1066 case OPT_NT_HASH:
1067 cli_credentials_set_password_will_be_nt_hash(creds, true);
1068 break;
1069 case 'A':
1070 if (arg != NULL) {
1071 ok = cli_credentials_parse_file(creds,
1072 arg,
1073 CRED_SPECIFIED);
1074 if (!ok) {
1075 fprintf(stderr,
1076 "Failed to set parse authentication file!\n");
1077 exit(1);
1079 skip_password_callback = true;
1081 break;
1082 case 'N':
1083 ok = cli_credentials_set_password(creds,
1084 NULL,
1085 CRED_SPECIFIED);
1086 if (!ok) {
1087 fprintf(stderr,
1088 "Failed to set password!\n");
1089 exit(1);
1091 skip_password_callback = true;
1092 break;
1093 case 'P':
1095 * Later, after this is all over, get the machine account
1096 * details from the secrets.(l|t)db.
1098 machine_account_pending = true;
1099 break;
1100 case OPT_SIMPLE_BIND_DN:
1101 if (arg != NULL) {
1102 ok = cli_credentials_set_bind_dn(creds, arg);
1103 if (!ok) {
1104 fprintf(stderr,
1105 "Failed to set bind DN!\n");
1106 exit(1);
1109 break;
1110 case OPT_USE_KERBEROS: {
1111 int32_t use_kerberos = INT_MIN;
1112 if (arg == NULL) {
1113 fprintf(stderr,
1114 "Failed to parse "
1115 "--use-kerberos=desired|required|off: "
1116 "Missing argument\n");
1117 exit(1);
1120 use_kerberos = lpcfg_parse_enum_vals("client use kerberos",
1121 arg);
1122 if (use_kerberos == INT_MIN) {
1123 fprintf(stderr,
1124 "Failed to parse "
1125 "--use-kerberos=desired|required|off: "
1126 "Invalid argument\n");
1127 exit(1);
1130 ok = cli_credentials_set_kerberos_state(creds,
1131 use_kerberos,
1132 CRED_SPECIFIED);
1133 if (!ok) {
1134 fprintf(stderr,
1135 "Failed to set Kerberos state to %s!\n", arg);
1136 exit(1);
1138 break;
1140 case OPT_USE_KERBEROS_CCACHE: {
1141 const char *error_string = NULL;
1142 int rc;
1144 if (arg == NULL) {
1145 fprintf(stderr,
1146 "Failed to parse --use-krb5-ccache=CCACHE: "
1147 "Missing argument\n");
1148 exit(1);
1151 ok = cli_credentials_set_kerberos_state(creds,
1152 CRED_USE_KERBEROS_REQUIRED,
1153 CRED_SPECIFIED);
1154 if (!ok) {
1155 fprintf(stderr,
1156 "Failed to set Kerberos state to %s!\n", arg);
1157 exit(1);
1160 rc = cli_credentials_set_ccache(creds,
1161 lp_ctx,
1162 arg,
1163 CRED_SPECIFIED,
1164 &error_string);
1165 if (rc != 0) {
1166 fprintf(stderr,
1167 "Error reading krb5 credentials cache: '%s'"
1168 " - %s\n",
1169 arg,
1170 error_string);
1171 exit(1);
1174 skip_password_callback = true;
1175 break;
1177 case OPT_USE_WINBIND_CCACHE:
1179 ok = cli_credentials_add_gensec_features(
1180 creds, GENSEC_FEATURE_NTLM_CCACHE, CRED_SPECIFIED);
1181 if (!ok) {
1182 fprintf(stderr,
1183 "Failed to set gensec feature!\n");
1184 exit(1);
1187 skip_password_callback = true;
1188 break;
1190 case OPT_CLIENT_PROTECTION: {
1191 uint32_t gensec_features;
1192 enum smb_signing_setting signing_state =
1193 SMB_SIGNING_OFF;
1194 enum smb_encryption_setting encryption_state =
1195 SMB_ENCRYPTION_OFF;
1197 if (arg == NULL) {
1198 fprintf(stderr,
1199 "Failed to parse "
1200 "--client-protection=sign|encrypt|off: "
1201 "Missing argument\n");
1202 exit(1);
1205 gensec_features =
1206 cli_credentials_get_gensec_features(
1207 creds);
1209 if (strequal(arg, "off")) {
1210 gensec_features &=
1211 ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL);
1213 signing_state = SMB_SIGNING_OFF;
1214 encryption_state = SMB_ENCRYPTION_OFF;
1215 } else if (strequal(arg, "sign")) {
1216 gensec_features |= GENSEC_FEATURE_SIGN;
1218 signing_state = SMB_SIGNING_REQUIRED;
1219 encryption_state = SMB_ENCRYPTION_OFF;
1220 } else if (strequal(arg, "encrypt")) {
1221 gensec_features |= GENSEC_FEATURE_SEAL;
1223 signing_state = SMB_SIGNING_REQUIRED;
1224 encryption_state = SMB_ENCRYPTION_REQUIRED;
1225 } else {
1226 fprintf(stderr,
1227 "Failed to parse --client-protection\n");
1228 exit(1);
1231 ok = cli_credentials_set_gensec_features(creds,
1232 gensec_features,
1233 CRED_SPECIFIED);
1234 if (!ok) {
1235 fprintf(stderr,
1236 "Failed to set gensec feature!\n");
1237 exit(1);
1240 ok = cli_credentials_set_smb_signing(creds,
1241 signing_state,
1242 CRED_SPECIFIED);
1243 if (!ok) {
1244 fprintf(stderr,
1245 "Failed to set smb signing!\n");
1246 exit(1);
1249 ok = cli_credentials_set_smb_encryption(creds,
1250 encryption_state,
1251 CRED_SPECIFIED);
1252 if (!ok) {
1253 fprintf(stderr,
1254 "Failed to set smb encryption!\n");
1255 exit(1);
1257 break;
1259 } /* switch */
1262 static struct poptOption popt_common_credentials[] = {
1264 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
1265 .arg = (void *)popt_common_credentials_callback,
1268 .longName = "user",
1269 .shortName = 'U',
1270 .argInfo = POPT_ARG_STRING,
1271 .val = 'U',
1272 .descrip = "Set the network username",
1273 .argDescrip = "[DOMAIN/]USERNAME[%PASSWORD]",
1276 .longName = "no-pass",
1277 .shortName = 'N',
1278 .argInfo = POPT_ARG_NONE,
1279 .val = 'N',
1280 .descrip = "Don't ask for a password",
1283 .longName = "password",
1284 .argInfo = POPT_ARG_STRING,
1285 .val = OPT_PASSWORD,
1286 .descrip = "Password",
1289 .longName = "pw-nt-hash",
1290 .argInfo = POPT_ARG_NONE,
1291 .val = OPT_NT_HASH,
1292 .descrip = "The supplied password is the NT hash",
1295 .longName = "authentication-file",
1296 .shortName = 'A',
1297 .argInfo = POPT_ARG_STRING,
1298 .val = 'A',
1299 .descrip = "Get the credentials from a file",
1300 .argDescrip = "FILE",
1303 .longName = "machine-pass",
1304 .shortName = 'P',
1305 .argInfo = POPT_ARG_NONE,
1306 .val = 'P',
1307 .descrip = "Use stored machine account password",
1310 .longName = "simple-bind-dn",
1311 .argInfo = POPT_ARG_STRING,
1312 .val = OPT_SIMPLE_BIND_DN,
1313 .descrip = "DN to use for a simple bind",
1314 .argDescrip = "DN",
1317 .longName = "use-kerberos",
1318 .argInfo = POPT_ARG_STRING,
1319 .val = OPT_USE_KERBEROS,
1320 .descrip = "Use Kerberos authentication",
1321 .argDescrip = "desired|required|off",
1324 .longName = "use-krb5-ccache",
1325 .argInfo = POPT_ARG_STRING,
1326 .val = OPT_USE_KERBEROS_CCACHE,
1327 .descrip = "Credentials cache location for Kerberos",
1328 .argDescrip = "CCACHE",
1331 .longName = "use-winbind-ccache",
1332 .argInfo = POPT_ARG_NONE,
1333 .val = OPT_USE_WINBIND_CCACHE,
1334 .descrip = "Use the winbind ccache for authentication",
1337 .longName = "client-protection",
1338 .argInfo = POPT_ARG_STRING,
1339 .val = OPT_CLIENT_PROTECTION,
1340 .descrip = "Configure used protection for client connections",
1341 .argDescrip = "sign|encrypt|off",
1343 POPT_TABLEEND
1346 /**********************************************************
1347 * VERSION POPT
1348 **********************************************************/
1350 static void popt_version_callback(poptContext ctx,
1351 enum poptCallbackReason reason,
1352 const struct poptOption *opt,
1353 const char *arg,
1354 const void *data)
1356 switch(opt->val) {
1357 case 'V':
1358 printf("Version %s\n", SAMBA_VERSION_STRING);
1359 exit(0);
1363 static struct poptOption popt_common_version[] = {
1365 .argInfo = POPT_ARG_CALLBACK,
1366 .arg = (void *)popt_version_callback,
1369 .longName = "version",
1370 .shortName = 'V',
1371 .argInfo = POPT_ARG_NONE,
1372 .val = 'V',
1373 .descrip = "Print version",
1375 POPT_TABLEEND
1378 /**********************************************************
1379 * DAEMON POPT
1380 **********************************************************/
1382 static void popt_daemon_callback(poptContext ctx,
1383 enum poptCallbackReason reason,
1384 const struct poptOption *opt,
1385 const char *arg,
1386 const void *data)
1388 switch(opt->val) {
1389 case OPT_DAEMON:
1390 cmdline_daemon_cfg.daemon = true;
1391 break;
1392 case OPT_INTERACTIVE:
1393 cmdline_daemon_cfg.interactive = true;
1394 cmdline_daemon_cfg.fork = false;
1395 break;
1396 case OPT_FORK:
1397 cmdline_daemon_cfg.fork = false;
1398 break;
1399 case OPT_NO_PROCESS_GROUP:
1400 cmdline_daemon_cfg.no_process_group = true;
1401 break;
1405 static struct poptOption popt_common_daemon[] = {
1407 .argInfo = POPT_ARG_CALLBACK,
1408 .arg = (void *)popt_daemon_callback
1411 .longName = "daemon",
1412 .shortName = 'D',
1413 .argInfo = POPT_ARG_NONE,
1414 .arg = NULL,
1415 .val = OPT_DAEMON,
1416 .descrip = "Become a daemon (default)" ,
1419 .longName = "interactive",
1420 .shortName = 'i',
1421 .argInfo = POPT_ARG_NONE,
1422 .arg = NULL,
1423 .val = OPT_INTERACTIVE,
1424 .descrip = "Run interactive (not a daemon) and log to stdout",
1427 .longName = "foreground",
1428 .shortName = 'F',
1429 .argInfo = POPT_ARG_NONE,
1430 .arg = NULL,
1431 .val = OPT_FORK,
1432 .descrip = "Run daemon in foreground (for daemontools, etc.)",
1435 .longName = "no-process-group",
1436 .shortName = '\0',
1437 .argInfo = POPT_ARG_NONE,
1438 .arg = NULL,
1439 .val = OPT_NO_PROCESS_GROUP,
1440 .descrip = "Don't create a new process group" ,
1442 POPT_TABLEEND
1445 /**********************************************************
1446 * LEGACY S3 POPT
1447 **********************************************************/
1449 static void popt_legacy_s3_callback(poptContext ctx,
1450 enum poptCallbackReason reason,
1451 const struct poptOption *opt,
1452 const char *arg,
1453 const void *data)
1455 struct cli_credentials *creds = samba_cmdline_get_creds();
1456 bool ok;
1458 switch(opt->val) {
1459 case 'k':
1460 fprintf(stderr,
1461 "WARNING: The option -k|--kerberos is deprecated!\n");
1463 ok = cli_credentials_set_kerberos_state(creds,
1464 CRED_USE_KERBEROS_REQUIRED,
1465 CRED_SPECIFIED);
1466 if (!ok) {
1467 fprintf(stderr,
1468 "Failed to set Kerberos state to %s!\n", arg);
1469 exit(1);
1472 skip_password_callback = true;
1473 break;
1477 /* We allow '-k yes' too. */
1478 static struct poptOption popt_legacy_s3[] = {
1480 .argInfo = POPT_ARG_CALLBACK,
1481 .arg = (void *)popt_legacy_s3_callback,
1484 .longName = "kerberos",
1485 .shortName = 'k',
1486 .argInfo = POPT_ARG_NONE,
1487 .val = 'k',
1488 .descrip = "DEPRECATED: Migrate to --use-kerberos",
1490 POPT_TABLEEND
1493 /**********************************************************
1494 * LEGACY S4 POPT
1495 **********************************************************/
1497 static void popt_legacy_s4_callback(poptContext ctx,
1498 enum poptCallbackReason reason,
1499 const struct poptOption *opt,
1500 const char *arg,
1501 const void *data)
1503 struct cli_credentials *creds = samba_cmdline_get_creds();
1504 bool ok;
1506 switch(opt->val) {
1507 case 'k': {
1508 enum credentials_use_kerberos use_kerberos =
1509 CRED_USE_KERBEROS_REQUIRED;
1511 fprintf(stderr,
1512 "WARNING: The option -k|--kerberos is deprecated!\n");
1514 if (arg != NULL) {
1515 if (strcasecmp_m(arg, "yes") == 0) {
1516 use_kerberos = CRED_USE_KERBEROS_REQUIRED;
1517 } else if (strcasecmp_m(arg, "no") == 0) {
1518 use_kerberos = CRED_USE_KERBEROS_DISABLED;
1519 } else {
1520 fprintf(stderr,
1521 "Error parsing -k %s. Should be "
1522 "-k [yes|no]\n",
1523 arg);
1524 exit(1);
1528 ok = cli_credentials_set_kerberos_state(creds,
1529 use_kerberos,
1530 CRED_SPECIFIED);
1531 if (!ok) {
1532 fprintf(stderr,
1533 "Failed to set Kerberos state to %s!\n", arg);
1534 exit(1);
1537 break;
1542 static struct poptOption popt_legacy_s4[] = {
1544 .argInfo = POPT_ARG_CALLBACK,
1545 .arg = (void *)popt_legacy_s4_callback,
1548 .longName = "kerberos",
1549 .shortName = 'k',
1550 .argInfo = POPT_ARG_STRING,
1551 .val = 'k',
1552 .descrip = "DEPRECATED: Migrate to --use-kerberos",
1554 POPT_TABLEEND
1557 struct poptOption *samba_cmdline_get_popt(enum smb_cmdline_popt_options opt)
1559 switch (opt) {
1560 case SAMBA_CMDLINE_POPT_OPT_DEBUG_ONLY:
1561 return popt_common_debug;
1562 break;
1563 case SAMBA_CMDLINE_POPT_OPT_OPTION_ONLY:
1564 return popt_common_option;
1565 break;
1566 case SAMBA_CMDLINE_POPT_OPT_CONFIG_ONLY:
1567 return popt_common_config;
1568 break;
1569 case SAMBA_CMDLINE_POPT_OPT_SAMBA:
1570 return popt_common_samba;
1571 break;
1572 case SAMBA_CMDLINE_POPT_OPT_CONNECTION:
1573 return popt_common_connection;
1574 break;
1575 case SAMBA_CMDLINE_POPT_OPT_CREDENTIALS:
1576 return popt_common_credentials;
1577 break;
1578 case SAMBA_CMDLINE_POPT_OPT_VERSION:
1579 return popt_common_version;
1580 break;
1581 case SAMBA_CMDLINE_POPT_OPT_DAEMON:
1582 return popt_common_daemon;
1583 break;
1584 case SAMBA_CMDLINE_POPT_OPT_SAMBA_LDB:
1585 return popt_common_samba_ldb;
1586 break;
1587 case SAMBA_CMDLINE_POPT_OPT_LEGACY_S3:
1588 return popt_legacy_s3;
1589 break;
1590 case SAMBA_CMDLINE_POPT_OPT_LEGACY_S4:
1591 return popt_legacy_s4;
1592 break;
1595 /* Never reached */
1596 return NULL;