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/>.
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"
25 #include <samba/version.h>
27 static TALLOC_CTX *cmdline_mem_ctx;
28 static struct loadparm_context *cmdline_lp_ctx;
29 static struct cli_credentials *cmdline_creds;
30 static samba_cmdline_load_config cmdline_load_config_fn;
33 bool samba_cmdline_set_talloc_ctx(TALLOC_CTX *mem_ctx)
35 if (cmdline_mem_ctx != NULL) {
39 cmdline_mem_ctx = mem_ctx;
43 TALLOC_CTX *samba_cmdline_get_talloc_ctx(void)
45 return cmdline_mem_ctx;
48 static void _samba_cmdline_talloc_log(const char *message)
50 DBG_ERR("%s", message);
53 bool samba_cmdline_init_common(TALLOC_CTX *mem_ctx)
57 ok = samba_cmdline_set_talloc_ctx(mem_ctx);
65 * Log to stdout by default.
66 * This can be changed to stderr using the option: --debug-stdout
68 setup_logging(getprogname(), DEBUG_DEFAULT_STDERR);
70 talloc_set_log_fn(_samba_cmdline_talloc_log);
71 talloc_set_abort_fn(smb_panic);
76 bool samba_cmdline_set_load_config_fn(samba_cmdline_load_config fn)
78 cmdline_load_config_fn = fn;
83 bool samba_cmdline_set_lp_ctx(struct loadparm_context *lp_ctx)
88 cmdline_lp_ctx = lp_ctx;
93 struct loadparm_context *samba_cmdline_get_lp_ctx(void)
95 return cmdline_lp_ctx;
98 bool samba_cmdline_set_creds(struct cli_credentials *creds)
104 TALLOC_FREE(cmdline_creds);
105 cmdline_creds = creds;
110 struct cli_credentials *samba_cmdline_get_creds(void)
112 return cmdline_creds;
115 void samba_cmdline_burn(int argc, char *argv[])
118 bool is_user = false;
122 for (i = 0; i < argc; i++) {
128 if (strncmp(p, "-U", 2) == 0) {
132 } else if (strncmp(p, "--user", 6) == 0) {
136 } else if (strncmp(p, "--password", 10) == 0) {
144 if (strlen(p) == ulen) {
149 q = strchr_m(p, '%');
157 memset_s(p, strlen(p), '\0', strlen(p));
164 static bool is_popt_table_end(const struct poptOption *o)
166 if (o->longName == NULL &&
171 o->descrip == NULL &&
172 o->argDescrip == NULL) {
179 static void find_duplicates(const struct poptOption *needle,
180 const struct poptOption *haystack,
184 !is_popt_table_end(haystack);
186 switch (haystack->argInfo) {
187 case POPT_ARG_INCLUDE_TABLE:
188 if (haystack->arg != NULL) {
189 find_duplicates(needle, haystack->arg, count);
194 if (needle->shortName != 0 &&
195 needle->shortName == haystack->shortName) {
200 if (needle->longName != NULL &&
201 haystack->longName != NULL &&
202 strequal(needle->longName, haystack->longName)) {
215 static bool cmdline_sanity_checker(const struct poptOption *current_opts,
216 const struct poptOption *full_opts)
218 const struct poptOption *o = current_opts;
221 !is_popt_table_end(o);
225 switch (o->argInfo) {
226 case POPT_ARG_INCLUDE_TABLE:
227 if (o->arg != NULL) {
228 ok = cmdline_sanity_checker(o->arg, full_opts);
236 if (o->longName != NULL || o->shortName != 0) {
239 find_duplicates(o, full_opts, &count);
241 DBG_ERR("Duplicate option '--%s|-%c' "
258 bool samba_cmdline_sanity_check(const struct poptOption *opts)
260 return cmdline_sanity_checker(opts, opts);
263 poptContext samba_popt_get_context(const char * name,
264 int argc, const char ** argv,
265 const struct poptOption * options,
271 ok = samba_cmdline_sanity_check(options);
276 return poptGetContext(name, argc, argv, options, flags);
279 /**********************************************************
281 **********************************************************/
283 static bool log_to_file;
285 static void popt_samba_callback(poptContext popt_ctx,
286 enum poptCallbackReason reason,
287 const struct poptOption *opt,
288 const char *arg, const void *data)
290 TALLOC_CTX *mem_ctx = samba_cmdline_get_talloc_ctx();
291 struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
292 const char *pname = NULL;
295 if (reason == POPT_CALLBACK_REASON_PRE) {
296 if (lp_ctx == NULL) {
298 "Command line parsing not initialized!\n");
304 if (reason == POPT_CALLBACK_REASON_POST) {
305 ok = cmdline_load_config_fn();
308 "%s - Failed to load config file!\n",
314 const struct loadparm_substitution *lp_sub =
315 lpcfg_noop_substitution();
316 char *logfile = NULL;
318 logfile = lpcfg_logfile(lp_ctx, lp_sub, mem_ctx);
319 if (logfile == NULL) {
321 "Failed to setup logging to file!");
324 debug_set_logfile(logfile);
325 setup_logging(logfile, DEBUG_FILE);
326 TALLOC_FREE(logfile);
332 /* Find out basename of current program */
333 pname = strrchr_m(poptGetInvocationName(popt_ctx), '/');
335 pname = poptGetInvocationName(popt_ctx);
341 case OPT_LEAK_REPORT:
342 talloc_enable_leak_report();
344 case OPT_LEAK_REPORT_FULL:
345 talloc_enable_leak_report_full();
349 ok = lpcfg_set_option(lp_ctx, arg);
351 fprintf(stderr, "Error setting option '%s'\n", arg);
358 ok = lpcfg_set_cmdline(lp_ctx, "log level", arg);
361 "Failed to set debug level to: %s\n",
367 case OPT_DEBUG_STDOUT:
368 setup_logging(pname, DEBUG_STDOUT);
372 set_dyn_CONFIGFILE(arg);
377 char *new_logfile = talloc_asprintf(mem_ctx,
381 if (new_logfile == NULL) {
383 "Failed to allocate memory\n");
387 ok = lpcfg_set_cmdline(lp_ctx,
392 "Failed to set log file: %s\n",
394 TALLOC_FREE(new_logfile);
399 set_dyn_LOGFILEBASE(arg);
401 TALLOC_FREE(new_logfile);
407 static struct poptOption popt_common_samba[] = {
409 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
410 .arg = (void *)popt_samba_callback,
413 .longName = "debuglevel",
415 .argInfo = POPT_ARG_STRING,
417 .descrip = "Set debug level",
418 .argDescrip = "DEBUGLEVEL",
421 .longName = "debug-stdout",
422 .argInfo = POPT_ARG_NONE,
423 .val = OPT_DEBUG_STDOUT,
424 .descrip = "Send debug output to standard output",
427 .longName = "configfile",
429 .argInfo = POPT_ARG_STRING,
430 .val = OPT_CONFIGFILE,
431 .descrip = "Use alternative configuration file",
432 .argDescrip = "CONFIGFILE",
435 .longName = "option",
436 .argInfo = POPT_ARG_STRING,
438 .descrip = "Set smb.conf option from command line",
439 .argDescrip = "name=value",
442 .longName = "log-basename",
444 .argInfo = POPT_ARG_STRING,
446 .descrip = "Basename for log/debug files",
447 .argDescrip = "LOGFILEBASE",
450 .longName = "leak-report",
451 .argInfo = POPT_ARG_NONE,
452 .val = OPT_LEAK_REPORT,
453 .descrip = "enable talloc leak reporting on exit",
456 .longName = "leak-report-full",
457 .argInfo = POPT_ARG_NONE,
458 .val = OPT_LEAK_REPORT_FULL,
459 .descrip = "enable full talloc leak reporting on exit",
464 static struct poptOption popt_common_samba_ldb[] = {
466 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
467 .arg = (void *)popt_samba_callback,
470 .longName = "debuglevel",
472 .argInfo = POPT_ARG_STRING,
474 .descrip = "Set debug level",
475 .argDescrip = "DEBUGLEVEL",
478 .longName = "debug-stdout",
479 .argInfo = POPT_ARG_NONE,
480 .val = OPT_DEBUG_STDOUT,
481 .descrip = "Send debug output to standard output",
484 .longName = "configfile",
485 .argInfo = POPT_ARG_STRING,
486 .val = OPT_CONFIGFILE,
487 .descrip = "Use alternative configuration file",
488 .argDescrip = "CONFIGFILE",
491 .longName = "option",
492 .argInfo = POPT_ARG_STRING,
494 .descrip = "Set smb.conf option from command line",
495 .argDescrip = "name=value",
498 .longName = "log-basename",
500 .argInfo = POPT_ARG_STRING,
502 .descrip = "Basename for log/debug files",
503 .argDescrip = "LOGFILEBASE",
506 .longName = "leak-report",
507 .argInfo = POPT_ARG_NONE,
508 .val = OPT_LEAK_REPORT,
509 .descrip = "enable talloc leak reporting on exit",
512 .longName = "leak-report-full",
513 .argInfo = POPT_ARG_NONE,
514 .val = OPT_LEAK_REPORT_FULL,
515 .descrip = "enable full talloc leak reporting on exit",
520 /**********************************************************
522 **********************************************************/
524 static void popt_connection_callback(poptContext popt_ctx,
525 enum poptCallbackReason reason,
526 const struct poptOption *opt,
530 struct loadparm_context *lp_ctx = cmdline_lp_ctx;
532 if (reason == POPT_CALLBACK_REASON_PRE) {
533 if (lp_ctx == NULL) {
535 "Command line parsing not initialized!\n");
544 lpcfg_set_cmdline(lp_ctx, "socket options", arg);
549 lpcfg_set_cmdline(lp_ctx, "name resolve order", arg);
554 lpcfg_set_cmdline(lp_ctx, "client max protocol", arg);
557 case OPT_NETBIOS_SCOPE:
559 lpcfg_set_cmdline(lp_ctx, "netbios scope", arg);
564 lpcfg_set_cmdline(lp_ctx, "netbios name", arg);
569 lpcfg_set_cmdline(lp_ctx, "workgroup", arg);
574 lpcfg_set_cmdline(lp_ctx, "realm", arg);
580 static struct poptOption popt_common_connection[] = {
582 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE,
583 .arg = (void *)popt_connection_callback,
586 .longName = "name-resolve",
588 .argInfo = POPT_ARG_STRING,
590 .descrip = "Use these name resolution services only",
591 .argDescrip = "NAME-RESOLVE-ORDER",
594 .longName = "socket-options",
596 .argInfo = POPT_ARG_STRING,
598 .descrip = "socket options to use",
599 .argDescrip = "SOCKETOPTIONS",
602 .longName = "maxprotocol",
604 .argInfo = POPT_ARG_STRING,
606 .descrip = "Set max protocol level",
607 .argDescrip = "MAXPROTOCOL",
610 .longName = "netbiosname",
612 .argInfo = POPT_ARG_STRING,
614 .descrip = "Primary netbios name",
615 .argDescrip = "NETBIOSNAME",
618 .longName = "netbios-scope",
619 .argInfo = POPT_ARG_STRING,
620 .val = OPT_NETBIOS_SCOPE,
621 .descrip = "Use this Netbios scope",
622 .argDescrip = "SCOPE",
625 .longName = "workgroup",
627 .argInfo = POPT_ARG_STRING,
629 .descrip = "Set the workgroup name",
630 .argDescrip = "WORKGROUP",
634 .argInfo = POPT_ARG_STRING,
636 .descrip = "Set the realm name",
637 .argDescrip = "REALM",
642 /**********************************************************
644 **********************************************************/
646 static bool skip_password_callback;
647 static bool machine_account_pending;
649 static void popt_common_credentials_callback(poptContext popt_ctx,
650 enum poptCallbackReason reason,
651 const struct poptOption *opt,
655 struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
656 struct cli_credentials *creds = samba_cmdline_get_creds();
659 if (reason == POPT_CALLBACK_REASON_PRE) {
662 "Command line parsing not initialized!\n");
668 if (reason == POPT_CALLBACK_REASON_POST) {
669 const char *username = NULL;
670 enum credentials_obtained username_obtained =
672 enum credentials_obtained password_obtained =
676 * This calls cli_credentials_set_conf() to get the defaults
677 * form smb.conf and set the winbind separator.
679 cli_credentials_guess(creds, lp_ctx);
681 (void)cli_credentials_get_password_and_obtained(creds,
683 if (!skip_password_callback &&
684 password_obtained < CRED_CALLBACK) {
685 ok = cli_credentials_set_cmdline_callbacks(creds);
688 "Failed to set cmdline password "
694 if (machine_account_pending) {
697 status = cli_credentials_set_machine_account(creds,
699 if (!NT_STATUS_IS_OK(status)) {
701 "Failed to set machine account: %s\n",
708 * When we set the username during the handling of the options
709 * passed to the binary we haven't loaded the config yet. This
710 * means that we didn't take the 'winbind separator' into
713 * The username might contain the domain name and thus it
714 * hasn't been correctly parsed yet. If we have a username we
715 * need to set it again to run the string parser for the
716 * username correctly.
719 cli_credentials_get_username_and_obtained(
720 creds, &username_obtained);
721 if (username_obtained == CRED_SPECIFIED &&
722 username != NULL && username[0] != '\0') {
723 cli_credentials_parse_string(creds,
734 cli_credentials_parse_string(creds,
741 ok = cli_credentials_set_password(creds,
746 "Failed to set password!\n");
750 skip_password_callback = true;
754 cli_credentials_set_password_will_be_nt_hash(creds, true);
758 ok = cli_credentials_parse_file(creds,
763 "Failed to set parse authentication file!\n");
766 skip_password_callback = true;
770 ok = cli_credentials_set_password(creds,
775 "Failed to set password!\n");
778 skip_password_callback = true;
782 * Later, after this is all over, get the machine account
783 * details from the secrets.(l|t)db.
785 machine_account_pending = true;
787 case OPT_SIMPLE_BIND_DN:
789 ok = cli_credentials_set_bind_dn(creds, arg);
792 "Failed to set bind DN!\n");
797 case OPT_USE_KERBEROS:
799 int32_t use_kerberos =
800 lpcfg_parse_enum_vals("client use kerberos", arg);
802 if (use_kerberos == INT_MIN) {
803 fprintf(stderr, "Failed to parse --use-kerberos\n");
807 ok = cli_credentials_set_kerberos_state(creds,
812 "Failed to set Kerberos state to %s!\n", arg);
817 case OPT_USE_KERBEROS_CCACHE:
819 const char *error_string = NULL;
822 ok = cli_credentials_set_kerberos_state(creds,
823 CRED_USE_KERBEROS_REQUIRED,
827 "Failed to set Kerberos state to %s!\n", arg);
831 rc = cli_credentials_set_ccache(creds,
838 "Error reading krb5 credentials cache: '%s'"
845 skip_password_callback = true;
848 case OPT_USE_WINBIND_CCACHE:
850 uint32_t gensec_features;
852 gensec_features = cli_credentials_get_gensec_features(creds);
853 gensec_features |= GENSEC_FEATURE_NTLM_CCACHE;
855 ok = cli_credentials_set_gensec_features(creds,
860 "Failed to set gensec feature!\n");
864 skip_password_callback = true;
867 case OPT_CLIENT_PROTECTION:
869 uint32_t gensec_features;
870 enum smb_signing_setting signing_state =
872 enum smb_encryption_setting encryption_state =
876 cli_credentials_get_gensec_features(
879 if (strequal(arg, "off")) {
881 ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL);
883 signing_state = SMB_SIGNING_OFF;
884 encryption_state = SMB_ENCRYPTION_OFF;
885 } else if (strequal(arg, "sign")) {
886 gensec_features |= GENSEC_FEATURE_SIGN;
888 signing_state = SMB_SIGNING_REQUIRED;
889 encryption_state = SMB_ENCRYPTION_OFF;
890 } else if (strequal(arg, "encrypt")) {
891 gensec_features |= GENSEC_FEATURE_SEAL;
893 signing_state = SMB_SIGNING_REQUIRED;
894 encryption_state = SMB_ENCRYPTION_REQUIRED;
897 "Failed to parse --client-protection\n");
901 ok = cli_credentials_set_gensec_features(creds,
906 "Failed to set gensec feature!\n");
910 ok = cli_credentials_set_smb_signing(creds,
915 "Failed to set smb signing!\n");
919 ok = cli_credentials_set_smb_encryption(creds,
924 "Failed to set smb encryption!\n");
932 static struct poptOption popt_common_credentials[] = {
934 .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
935 .arg = (void *)popt_common_credentials_callback,
940 .argInfo = POPT_ARG_STRING,
942 .descrip = "Set the network username",
943 .argDescrip = "[DOMAIN/]USERNAME[%PASSWORD]",
946 .longName = "no-pass",
948 .argInfo = POPT_ARG_NONE,
950 .descrip = "Don't ask for a password",
953 .longName = "password",
954 .argInfo = POPT_ARG_STRING,
956 .descrip = "Password",
959 .longName = "pw-nt-hash",
960 .argInfo = POPT_ARG_NONE,
962 .descrip = "The supplied password is the NT hash",
965 .longName = "authentication-file",
967 .argInfo = POPT_ARG_STRING,
969 .descrip = "Get the credentials from a file",
970 .argDescrip = "FILE",
973 .longName = "machine-pass",
975 .argInfo = POPT_ARG_NONE,
977 .descrip = "Use stored machine account password",
980 .longName = "simple-bind-dn",
981 .argInfo = POPT_ARG_STRING,
982 .val = OPT_SIMPLE_BIND_DN,
983 .descrip = "DN to use for a simple bind",
987 .longName = "use-kerberos",
988 .argInfo = POPT_ARG_STRING,
989 .val = OPT_USE_KERBEROS,
990 .descrip = "Use Kerberos authentication",
991 .argDescrip = "desired|required|off",
994 .longName = "use-krb5-ccache",
995 .argInfo = POPT_ARG_STRING,
996 .val = OPT_USE_KERBEROS_CCACHE,
997 .descrip = "Credentials cache location for Kerberos",
998 .argDescrip = "CCACHE",
1001 .longName = "use-winbind-ccache",
1002 .argInfo = POPT_ARG_NONE,
1003 .val = OPT_USE_WINBIND_CCACHE,
1004 .descrip = "Use the winbind ccache for authentication",
1007 .longName = "client-protection",
1008 .argInfo = POPT_ARG_STRING,
1009 .val = OPT_CLIENT_PROTECTION,
1010 .descrip = "Configure used protection for client connections",
1011 .argDescrip = "sign|encrypt|off",
1016 /**********************************************************
1018 **********************************************************/
1020 static void popt_version_callback(poptContext ctx,
1021 enum poptCallbackReason reason,
1022 const struct poptOption *opt,
1028 printf("Version %s\n", SAMBA_VERSION_STRING);
1033 static struct poptOption popt_common_version[] = {
1035 .argInfo = POPT_ARG_CALLBACK,
1036 .arg = (void *)popt_version_callback,
1039 .longName = "version",
1041 .argInfo = POPT_ARG_NONE,
1043 .descrip = "Print version",
1048 /**********************************************************
1050 **********************************************************/
1052 static void popt_legacy_s3_callback(poptContext ctx,
1053 enum poptCallbackReason reason,
1054 const struct poptOption *opt,
1058 struct cli_credentials *creds = samba_cmdline_get_creds();
1064 "WARNING: The option -k|--kerberos is deprecated!\n");
1066 ok = cli_credentials_set_kerberos_state(creds,
1067 CRED_USE_KERBEROS_REQUIRED,
1071 "Failed to set Kerberos state to %s!\n", arg);
1075 skip_password_callback = true;
1080 /* We allow '-k yes' too. */
1081 static struct poptOption popt_legacy_s3[] = {
1083 .argInfo = POPT_ARG_CALLBACK,
1084 .arg = (void *)popt_legacy_s3_callback,
1087 .longName = "kerberos",
1089 .argInfo = POPT_ARG_STRING,
1091 .descrip = "DEPRECATED: Migrate to --use-kerberos",
1096 /**********************************************************
1098 **********************************************************/
1100 static void popt_legacy_s4_callback(poptContext ctx,
1101 enum poptCallbackReason reason,
1102 const struct poptOption *opt,
1106 struct cli_credentials *creds = samba_cmdline_get_creds();
1111 enum credentials_use_kerberos use_kerberos =
1112 CRED_USE_KERBEROS_REQUIRED;
1115 "WARNING: The option -k|--kerberos is deprecated!\n");
1118 if (strcasecmp_m(arg, "yes") == 0) {
1119 use_kerberos = CRED_USE_KERBEROS_REQUIRED;
1120 } else if (strcasecmp_m(arg, "no") == 0) {
1121 use_kerberos = CRED_USE_KERBEROS_DISABLED;
1124 "Error parsing -k %s. Should be "
1131 ok = cli_credentials_set_kerberos_state(creds,
1136 "Failed to set Kerberos state to %s!\n", arg);
1145 static struct poptOption popt_legacy_s4[] = {
1147 .argInfo = POPT_ARG_CALLBACK,
1148 .arg = (void *)popt_legacy_s4_callback,
1151 .longName = "kerberos",
1153 .argInfo = POPT_ARG_STRING,
1155 .descrip = "DEPRECATED: Migrate to --use-kerberos",
1160 struct poptOption *samba_cmdline_get_popt(enum smb_cmdline_popt_options opt)
1163 case SAMBA_CMDLINE_POPT_OPT_SAMBA:
1164 return popt_common_samba;
1166 case SAMBA_CMDLINE_POPT_OPT_CONNECTION:
1167 return popt_common_connection;
1169 case SAMBA_CMDLINE_POPT_OPT_CREDENTIALS:
1170 return popt_common_credentials;
1172 case SAMBA_CMDLINE_POPT_OPT_VERSION:
1173 return popt_common_version;
1175 case SAMBA_CMDLINE_POPT_OPT_SAMBA_LDB:
1176 return popt_common_samba_ldb;
1178 case SAMBA_CMDLINE_POPT_OPT_LEGACY_S3:
1179 return popt_legacy_s3;
1181 case SAMBA_CMDLINE_POPT_OPT_LEGACY_S4:
1182 return popt_legacy_s4;