/* * Copyright (c) 2020 Andreas Schneider * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "includes.h" #include "lib/param/param.h" #include "dynconfig/dynconfig.h" #include "auth/gensec/gensec.h" #include "libcli/smb/smb_util.h" #include "cmdline_private.h" #include static TALLOC_CTX *cmdline_mem_ctx; static struct loadparm_context *cmdline_lp_ctx; static struct cli_credentials *cmdline_creds; static samba_cmdline_load_config cmdline_load_config_fn; static struct samba_cmdline_daemon_cfg cmdline_daemon_cfg; /* PRIVATE */ bool samba_cmdline_set_talloc_ctx(TALLOC_CTX *mem_ctx) { if (cmdline_mem_ctx != NULL) { return false; } cmdline_mem_ctx = mem_ctx; return true; } TALLOC_CTX *samba_cmdline_get_talloc_ctx(void) { return cmdline_mem_ctx; } static void _samba_cmdline_talloc_log(const char *message) { D_ERR("%s", message); } bool samba_cmdline_init_common(TALLOC_CTX *mem_ctx) { bool ok; ok = samba_cmdline_set_talloc_ctx(mem_ctx); if (!ok) { return false; } cmdline_daemon_cfg = (struct samba_cmdline_daemon_cfg) { .fork = true, }; fault_setup(); /* * Log to stderr by default. * This can be changed to stdout using the option: --debug-stdout */ setup_logging(getprogname(), DEBUG_DEFAULT_STDERR); talloc_set_log_fn(_samba_cmdline_talloc_log); talloc_set_abort_fn(smb_panic); return true; } bool samba_cmdline_set_load_config_fn(samba_cmdline_load_config fn) { cmdline_load_config_fn = fn; return true; } /* PUBLIC */ bool samba_cmdline_set_lp_ctx(struct loadparm_context *lp_ctx) { if (lp_ctx == NULL) { return false; } cmdline_lp_ctx = lp_ctx; return true; } struct loadparm_context *samba_cmdline_get_lp_ctx(void) { return cmdline_lp_ctx; } bool samba_cmdline_set_creds(struct cli_credentials *creds) { if (creds == NULL) { return false; } TALLOC_FREE(cmdline_creds); cmdline_creds = creds; return true; } struct cli_credentials *samba_cmdline_get_creds(void) { return cmdline_creds; } struct samba_cmdline_daemon_cfg *samba_cmdline_get_daemon_cfg(void) { return &cmdline_daemon_cfg; } void samba_cmdline_burn(int argc, char *argv[]) { bool found = false; bool is_user = false; char *p = NULL; int i; size_t ulen = 0; for (i = 0; i < argc; i++) { p = argv[i]; if (p == NULL) { return; } if (strncmp(p, "-U", 2) == 0) { ulen = 2; found = true; is_user = true; } else if (strncmp(p, "--user", 6) == 0) { ulen = 6; found = true; is_user = true; } else if (strncmp(p, "--password", 10) == 0) { ulen = 10; found = true; } if (found) { char *q = NULL; if (strlen(p) == ulen) { continue; } if (is_user) { q = strchr_m(p, '%'); if (q != NULL) { p = q; } } else { p += ulen; } memset_s(p, strlen(p), '\0', strlen(p)); found = false; is_user = false; } } } static bool is_popt_table_end(const struct poptOption *o) { if (o->longName == NULL && o->shortName == 0 && o->argInfo == 0 && o->arg == NULL && o->val == 0 && o->descrip == NULL && o->argDescrip == NULL) { return true; } return false; } static void find_duplicates(const struct poptOption *needle, const struct poptOption *haystack, size_t *count) { for(; !is_popt_table_end(haystack); haystack++) { switch (haystack->argInfo) { case POPT_ARG_INCLUDE_TABLE: if (haystack->arg != NULL) { find_duplicates(needle, haystack->arg, count); } break; default: if (needle->shortName != 0 && needle->shortName == haystack->shortName) { (*count)++; break; } if (needle->longName != NULL && haystack->longName != NULL && strequal(needle->longName, haystack->longName)) { (*count)++; break; } break; } if (*count > 1) { return; } } } static bool cmdline_sanity_checker(const struct poptOption *current_opts, const struct poptOption *full_opts) { const struct poptOption *o = current_opts; for(; !is_popt_table_end(o); o++) { bool ok; switch (o->argInfo) { case POPT_ARG_INCLUDE_TABLE: if (o->arg != NULL) { ok = cmdline_sanity_checker(o->arg, full_opts); if (!ok) { return false; } } break; default: if (o->longName != NULL || o->shortName != 0) { size_t count = 0; find_duplicates(o, full_opts, &count); if (count > 1) { DBG_ERR("Duplicate option '--%s|-%c' " "detected!\n", o->longName, o->shortName != 0 ? o->shortName : '-'); return false; } } break; } } return true; } bool samba_cmdline_sanity_check(const struct poptOption *opts) { return cmdline_sanity_checker(opts, opts); } poptContext samba_popt_get_context(const char * name, int argc, const char ** argv, const struct poptOption * options, unsigned int flags) { #ifdef DEVELOPER bool ok; ok = samba_cmdline_sanity_check(options); if (!ok) { return NULL; } #endif return poptGetContext(name, argc, argv, options, flags); } /********************************************************** * COMMON SAMBA POPT **********************************************************/ static bool log_to_file; static bool set_logfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, const char *log_basename, const char *process_name, bool from_cmdline) { bool ok = false; char *new_logfile = talloc_asprintf(mem_ctx, "%s/log.%s", log_basename, process_name); if (new_logfile == NULL) { return false; } if (from_cmdline) { ok = lpcfg_set_cmdline(lp_ctx, "log file", new_logfile); } else { ok = lpcfg_do_global_parameter(lp_ctx, "log file", new_logfile); } if (!ok) { fprintf(stderr, "Failed to set log to %s\n", new_logfile); TALLOC_FREE(new_logfile); return false; } debug_set_logfile(new_logfile); TALLOC_FREE(new_logfile); return true; } static void popt_samba_callback(poptContext popt_ctx, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { TALLOC_CTX *mem_ctx = samba_cmdline_get_talloc_ctx(); struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx(); const char *pname = NULL; bool ok; /* Find out basename of current program */ pname = getprogname(); if (reason == POPT_CALLBACK_REASON_PRE) { if (lp_ctx == NULL) { fprintf(stderr, "Command line parsing not initialized!\n"); exit(1); } ok = set_logfile(mem_ctx, lp_ctx, get_dyn_LOGFILEBASE(), pname, false); if (!ok) { fprintf(stderr, "Failed to set log file for %s\n", pname); exit(1); } return; } if (reason == POPT_CALLBACK_REASON_POST) { ok = cmdline_load_config_fn(); if (!ok) { fprintf(stderr, "%s - Failed to load config file!\n", getprogname()); exit(1); } if (log_to_file) { const struct loadparm_substitution *lp_sub = lpcfg_noop_substitution(); char *logfile = NULL; logfile = lpcfg_logfile(lp_ctx, lp_sub, mem_ctx); if (logfile == NULL) { fprintf(stderr, "Failed to setup logging to file!"); exit(1); } debug_set_logfile(logfile); setup_logging(logfile, DEBUG_FILE); TALLOC_FREE(logfile); } return; } switch(opt->val) { case OPT_LEAK_REPORT: talloc_enable_leak_report(); break; case OPT_LEAK_REPORT_FULL: talloc_enable_leak_report_full(); break; case OPT_OPTION: if (arg != NULL) { ok = lpcfg_set_option(lp_ctx, arg); if (!ok) { fprintf(stderr, "Error setting option '%s'\n", arg); exit(1); } } break; case 'd': if (arg != NULL) { ok = lpcfg_set_cmdline(lp_ctx, "log level", arg); if (!ok) { fprintf(stderr, "Failed to set debug level to: %s\n", arg); exit(1); } } break; case OPT_DEBUG_STDOUT: setup_logging(pname, DEBUG_STDOUT); break; case OPT_CONFIGFILE: if (arg != NULL) { set_dyn_CONFIGFILE(arg); } break; case 'l': if (arg != NULL) { ok = set_logfile(mem_ctx, lp_ctx, arg, pname, true); if (!ok) { fprintf(stderr, "Failed to set log file for %s\n", arg); exit(1); } log_to_file = true; set_dyn_LOGFILEBASE(arg); } break; } } static struct poptOption popt_common_debug[] = { { .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, .arg = (void *)popt_samba_callback, }, { .longName = "debuglevel", .shortName = 'd', .argInfo = POPT_ARG_STRING, .val = 'd', .descrip = "Set debug level", .argDescrip = "DEBUGLEVEL", }, { .longName = "debug-stdout", .argInfo = POPT_ARG_NONE, .val = OPT_DEBUG_STDOUT, .descrip = "Send debug output to standard output", }, POPT_TABLEEND }; static struct poptOption popt_common_option[] = { { .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, .arg = (void *)popt_samba_callback, }, { .longName = "option", .argInfo = POPT_ARG_STRING, .val = OPT_OPTION, .descrip = "Set smb.conf option from command line", .argDescrip = "name=value", }, POPT_TABLEEND }; static struct poptOption popt_common_config[] = { { .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, .arg = (void *)popt_samba_callback, }, { .longName = "configfile", .argInfo = POPT_ARG_STRING, .val = OPT_CONFIGFILE, .descrip = "Use alternative configuration file", .argDescrip = "CONFIGFILE", }, POPT_TABLEEND }; static struct poptOption popt_common_samba[] = { { .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, .arg = (void *)popt_samba_callback, }, { .longName = "debuglevel", .shortName = 'd', .argInfo = POPT_ARG_STRING, .val = 'd', .descrip = "Set debug level", .argDescrip = "DEBUGLEVEL", }, { .longName = "debug-stdout", .argInfo = POPT_ARG_NONE, .val = OPT_DEBUG_STDOUT, .descrip = "Send debug output to standard output", }, { .longName = "configfile", .shortName = 's', .argInfo = POPT_ARG_STRING, .val = OPT_CONFIGFILE, .descrip = "Use alternative configuration file", .argDescrip = "CONFIGFILE", }, { .longName = "option", .argInfo = POPT_ARG_STRING, .val = OPT_OPTION, .descrip = "Set smb.conf option from command line", .argDescrip = "name=value", }, { .longName = "log-basename", .shortName = 'l', .argInfo = POPT_ARG_STRING, .val = 'l', .descrip = "Basename for log/debug files", .argDescrip = "LOGFILEBASE", }, { .longName = "leak-report", .argInfo = POPT_ARG_NONE, .val = OPT_LEAK_REPORT, .descrip = "enable talloc leak reporting on exit", }, { .longName = "leak-report-full", .argInfo = POPT_ARG_NONE, .val = OPT_LEAK_REPORT_FULL, .descrip = "enable full talloc leak reporting on exit", }, POPT_TABLEEND }; static struct poptOption popt_common_samba_ldb[] = { { .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, .arg = (void *)popt_samba_callback, }, { .longName = "debuglevel", .shortName = 'd', .argInfo = POPT_ARG_STRING, .val = 'd', .descrip = "Set debug level", .argDescrip = "DEBUGLEVEL", }, { .longName = "debug-stdout", .argInfo = POPT_ARG_NONE, .val = OPT_DEBUG_STDOUT, .descrip = "Send debug output to standard output", }, { .longName = "configfile", .argInfo = POPT_ARG_STRING, .val = OPT_CONFIGFILE, .descrip = "Use alternative configuration file", .argDescrip = "CONFIGFILE", }, { .longName = "option", .argInfo = POPT_ARG_STRING, .val = OPT_OPTION, .descrip = "Set smb.conf option from command line", .argDescrip = "name=value", }, { .longName = "log-basename", .shortName = 'l', .argInfo = POPT_ARG_STRING, .val = 'l', .descrip = "Basename for log/debug files", .argDescrip = "LOGFILEBASE", }, { .longName = "leak-report", .argInfo = POPT_ARG_NONE, .val = OPT_LEAK_REPORT, .descrip = "enable talloc leak reporting on exit", }, { .longName = "leak-report-full", .argInfo = POPT_ARG_NONE, .val = OPT_LEAK_REPORT_FULL, .descrip = "enable full talloc leak reporting on exit", }, POPT_TABLEEND }; /********************************************************** * CONNECTION POPT **********************************************************/ static void popt_connection_callback(poptContext popt_ctx, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { struct loadparm_context *lp_ctx = cmdline_lp_ctx; if (reason == POPT_CALLBACK_REASON_PRE) { if (lp_ctx == NULL) { fprintf(stderr, "Command line parsing not initialized!\n"); exit(1); } return; } switch(opt->val) { case 'O': if (arg != NULL) { lpcfg_set_cmdline(lp_ctx, "socket options", arg); } break; case 'R': if (arg != NULL) { lpcfg_set_cmdline(lp_ctx, "name resolve order", arg); } break; case 'm': if (arg != NULL) { lpcfg_set_cmdline(lp_ctx, "client max protocol", arg); } break; case OPT_NETBIOS_SCOPE: if (arg != NULL) { lpcfg_set_cmdline(lp_ctx, "netbios scope", arg); } break; case 'n': if (arg != NULL) { lpcfg_set_cmdline(lp_ctx, "netbios name", arg); } break; case 'W': if (arg != NULL) { lpcfg_set_cmdline(lp_ctx, "workgroup", arg); } break; case 'r': if (arg != NULL) { lpcfg_set_cmdline(lp_ctx, "realm", arg); } break; } } static struct poptOption popt_common_connection[] = { { .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, .arg = (void *)popt_connection_callback, }, { .longName = "name-resolve", .shortName = 'R', .argInfo = POPT_ARG_STRING, .val = 'R', .descrip = "Use these name resolution services only", .argDescrip = "NAME-RESOLVE-ORDER", }, { .longName = "socket-options", .shortName = 'O', .argInfo = POPT_ARG_STRING, .val = 'O', .descrip = "socket options to use", .argDescrip = "SOCKETOPTIONS", }, { .longName = "max-protocol", .shortName = 'm', .argInfo = POPT_ARG_STRING, .val = 'm', .descrip = "Set max protocol level", .argDescrip = "MAXPROTOCOL", }, { .longName = "netbiosname", .shortName = 'n', .argInfo = POPT_ARG_STRING, .val = 'n', .descrip = "Primary netbios name", .argDescrip = "NETBIOSNAME", }, { .longName = "netbios-scope", .argInfo = POPT_ARG_STRING, .val = OPT_NETBIOS_SCOPE, .descrip = "Use this Netbios scope", .argDescrip = "SCOPE", }, { .longName = "workgroup", .shortName = 'W', .argInfo = POPT_ARG_STRING, .val = 'W', .descrip = "Set the workgroup name", .argDescrip = "WORKGROUP", }, { .longName = "realm", .argInfo = POPT_ARG_STRING, .val = 'r', .descrip = "Set the realm name", .argDescrip = "REALM", }, POPT_TABLEEND }; /********************************************************** * CREDENTIALS POPT **********************************************************/ static bool skip_password_callback; static bool machine_account_pending; static void popt_common_credentials_callback(poptContext popt_ctx, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx(); struct cli_credentials *creds = samba_cmdline_get_creds(); bool ok; if (reason == POPT_CALLBACK_REASON_PRE) { if (creds == NULL) { fprintf(stderr, "Command line parsing not initialized!\n"); exit(1); } return; } if (reason == POPT_CALLBACK_REASON_POST) { const char *username = NULL; enum credentials_obtained username_obtained = CRED_UNINITIALISED; enum credentials_obtained password_obtained = CRED_UNINITIALISED; /* * This calls cli_credentials_set_conf() to get the defaults * form smb.conf and set the winbind separator. * * Just warn that we can't read the smb.conf. The might not be * one available or we want to ignore it. */ ok = cli_credentials_guess(creds, lp_ctx); if (!ok) { fprintf(stderr, "Unable to read defaults from smb.conf\n"); } (void)cli_credentials_get_password_and_obtained(creds, &password_obtained); if (!skip_password_callback && password_obtained < CRED_CALLBACK) { ok = cli_credentials_set_cmdline_callbacks(creds); if (!ok) { fprintf(stderr, "Failed to set cmdline password " "callback\n"); exit(1); } } if (machine_account_pending) { NTSTATUS status; status = cli_credentials_set_machine_account(creds, lp_ctx); if (!NT_STATUS_IS_OK(status)) { fprintf(stderr, "Failed to set machine account: %s\n", nt_errstr(status)); exit(1); } } /* * When we set the username during the handling of the options * passed to the binary we haven't loaded the config yet. This * means that we didn't take the 'winbind separator' into * account. * * The username might contain the domain name and thus it * hasn't been correctly parsed yet. If we have a username we * need to set it again to run the string parser for the * username correctly. */ username = cli_credentials_get_username_and_obtained( creds, &username_obtained); if (username_obtained == CRED_SPECIFIED && username != NULL && username[0] != '\0') { cli_credentials_parse_string(creds, username, CRED_SPECIFIED); } return; } switch(opt->val) { case 'U': if (arg != NULL) { cli_credentials_parse_string(creds, arg, CRED_SPECIFIED); } break; case OPT_PASSWORD: if (arg != NULL) { ok = cli_credentials_set_password(creds, arg, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set password!\n"); exit(1); } skip_password_callback = true; } break; case OPT_NT_HASH: cli_credentials_set_password_will_be_nt_hash(creds, true); break; case 'A': if (arg != NULL) { ok = cli_credentials_parse_file(creds, arg, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set parse authentication file!\n"); exit(1); } skip_password_callback = true; } break; case 'N': ok = cli_credentials_set_password(creds, NULL, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set password!\n"); exit(1); } skip_password_callback = true; break; case 'P': /* * Later, after this is all over, get the machine account * details from the secrets.(l|t)db. */ machine_account_pending = true; break; case OPT_SIMPLE_BIND_DN: if (arg != NULL) { ok = cli_credentials_set_bind_dn(creds, arg); if (!ok) { fprintf(stderr, "Failed to set bind DN!\n"); exit(1); } } break; case OPT_USE_KERBEROS: if (arg != NULL) { int32_t use_kerberos = lpcfg_parse_enum_vals("client use kerberos", arg); if (use_kerberos == INT_MIN) { fprintf(stderr, "Failed to parse --use-kerberos\n"); exit(1); } ok = cli_credentials_set_kerberos_state(creds, use_kerberos, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set Kerberos state to %s!\n", arg); exit(1); } } break; case OPT_USE_KERBEROS_CCACHE: if (arg != NULL) { const char *error_string = NULL; int rc; ok = cli_credentials_set_kerberos_state(creds, CRED_USE_KERBEROS_REQUIRED, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set Kerberos state to %s!\n", arg); exit(1); } rc = cli_credentials_set_ccache(creds, lp_ctx, arg, CRED_SPECIFIED, &error_string); if (rc != 0) { fprintf(stderr, "Error reading krb5 credentials cache: '%s'" " - %s\n", arg, error_string); exit(1); } skip_password_callback = true; } break; case OPT_USE_WINBIND_CCACHE: { uint32_t gensec_features; gensec_features = cli_credentials_get_gensec_features(creds); gensec_features |= GENSEC_FEATURE_NTLM_CCACHE; ok = cli_credentials_set_gensec_features(creds, gensec_features, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set gensec feature!\n"); exit(1); } skip_password_callback = true; break; } case OPT_CLIENT_PROTECTION: if (arg != NULL) { uint32_t gensec_features; enum smb_signing_setting signing_state = SMB_SIGNING_OFF; enum smb_encryption_setting encryption_state = SMB_ENCRYPTION_OFF; gensec_features = cli_credentials_get_gensec_features( creds); if (strequal(arg, "off")) { gensec_features &= ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL); signing_state = SMB_SIGNING_OFF; encryption_state = SMB_ENCRYPTION_OFF; } else if (strequal(arg, "sign")) { gensec_features |= GENSEC_FEATURE_SIGN; signing_state = SMB_SIGNING_REQUIRED; encryption_state = SMB_ENCRYPTION_OFF; } else if (strequal(arg, "encrypt")) { gensec_features |= GENSEC_FEATURE_SEAL; signing_state = SMB_SIGNING_REQUIRED; encryption_state = SMB_ENCRYPTION_REQUIRED; } else { fprintf(stderr, "Failed to parse --client-protection\n"); exit(1); } ok = cli_credentials_set_gensec_features(creds, gensec_features, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set gensec feature!\n"); exit(1); } ok = cli_credentials_set_smb_signing(creds, signing_state, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set smb signing!\n"); exit(1); } ok = cli_credentials_set_smb_encryption(creds, encryption_state, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set smb encryption!\n"); exit(1); } } break; } /* switch */ } static struct poptOption popt_common_credentials[] = { { .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, .arg = (void *)popt_common_credentials_callback, }, { .longName = "user", .shortName = 'U', .argInfo = POPT_ARG_STRING, .val = 'U', .descrip = "Set the network username", .argDescrip = "[DOMAIN/]USERNAME[%PASSWORD]", }, { .longName = "no-pass", .shortName = 'N', .argInfo = POPT_ARG_NONE, .val = 'N', .descrip = "Don't ask for a password", }, { .longName = "password", .argInfo = POPT_ARG_STRING, .val = OPT_PASSWORD, .descrip = "Password", }, { .longName = "pw-nt-hash", .argInfo = POPT_ARG_NONE, .val = OPT_NT_HASH, .descrip = "The supplied password is the NT hash", }, { .longName = "authentication-file", .shortName = 'A', .argInfo = POPT_ARG_STRING, .val = 'A', .descrip = "Get the credentials from a file", .argDescrip = "FILE", }, { .longName = "machine-pass", .shortName = 'P', .argInfo = POPT_ARG_NONE, .val = 'P', .descrip = "Use stored machine account password", }, { .longName = "simple-bind-dn", .argInfo = POPT_ARG_STRING, .val = OPT_SIMPLE_BIND_DN, .descrip = "DN to use for a simple bind", .argDescrip = "DN", }, { .longName = "use-kerberos", .argInfo = POPT_ARG_STRING, .val = OPT_USE_KERBEROS, .descrip = "Use Kerberos authentication", .argDescrip = "desired|required|off", }, { .longName = "use-krb5-ccache", .argInfo = POPT_ARG_STRING, .val = OPT_USE_KERBEROS_CCACHE, .descrip = "Credentials cache location for Kerberos", .argDescrip = "CCACHE", }, { .longName = "use-winbind-ccache", .argInfo = POPT_ARG_NONE, .val = OPT_USE_WINBIND_CCACHE, .descrip = "Use the winbind ccache for authentication", }, { .longName = "client-protection", .argInfo = POPT_ARG_STRING, .val = OPT_CLIENT_PROTECTION, .descrip = "Configure used protection for client connections", .argDescrip = "sign|encrypt|off", }, POPT_TABLEEND }; /********************************************************** * VERSION POPT **********************************************************/ static void popt_version_callback(poptContext ctx, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { switch(opt->val) { case 'V': printf("Version %s\n", SAMBA_VERSION_STRING); exit(0); } } static struct poptOption popt_common_version[] = { { .argInfo = POPT_ARG_CALLBACK, .arg = (void *)popt_version_callback, }, { .longName = "version", .shortName = 'V', .argInfo = POPT_ARG_NONE, .val = 'V', .descrip = "Print version", }, POPT_TABLEEND }; /********************************************************** * DAEMON POPT **********************************************************/ static void popt_daemon_callback(poptContext ctx, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { switch(opt->val) { case OPT_DAEMON: cmdline_daemon_cfg.daemon = true; break; case OPT_INTERACTIVE: cmdline_daemon_cfg.interactive = true; cmdline_daemon_cfg.fork = false; break; case OPT_FORK: cmdline_daemon_cfg.fork = false; break; case OPT_NO_PROCESS_GROUP: cmdline_daemon_cfg.no_process_group = true; break; } } static struct poptOption popt_common_daemon[] = { { .argInfo = POPT_ARG_CALLBACK, .arg = (void *)popt_daemon_callback }, { .longName = "daemon", .shortName = 'D', .argInfo = POPT_ARG_NONE, .arg = NULL, .val = OPT_DAEMON, .descrip = "Become a daemon (default)" , }, { .longName = "interactive", .shortName = 'i', .argInfo = POPT_ARG_NONE, .arg = NULL, .val = OPT_INTERACTIVE, .descrip = "Run interactive (not a daemon) and log to stdout", }, { .longName = "foreground", .shortName = 'F', .argInfo = POPT_ARG_NONE, .arg = NULL, .val = OPT_FORK, .descrip = "Run daemon in foreground (for daemontools, etc.)", }, { .longName = "no-process-group", .shortName = '\0', .argInfo = POPT_ARG_NONE, .arg = NULL, .val = OPT_NO_PROCESS_GROUP, .descrip = "Don't create a new process group" , }, POPT_TABLEEND }; /********************************************************** * LEGACY S3 POPT **********************************************************/ static void popt_legacy_s3_callback(poptContext ctx, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { struct cli_credentials *creds = samba_cmdline_get_creds(); bool ok; switch(opt->val) { case 'k': fprintf(stderr, "WARNING: The option -k|--kerberos is deprecated!\n"); ok = cli_credentials_set_kerberos_state(creds, CRED_USE_KERBEROS_REQUIRED, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set Kerberos state to %s!\n", arg); exit(1); } skip_password_callback = true; break; } } /* We allow '-k yes' too. */ static struct poptOption popt_legacy_s3[] = { { .argInfo = POPT_ARG_CALLBACK, .arg = (void *)popt_legacy_s3_callback, }, { .longName = "kerberos", .shortName = 'k', .argInfo = POPT_ARG_NONE, .val = 'k', .descrip = "DEPRECATED: Migrate to --use-kerberos", }, POPT_TABLEEND }; /********************************************************** * LEGACY S4 POPT **********************************************************/ static void popt_legacy_s4_callback(poptContext ctx, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { struct cli_credentials *creds = samba_cmdline_get_creds(); bool ok; switch(opt->val) { case 'k': { enum credentials_use_kerberos use_kerberos = CRED_USE_KERBEROS_REQUIRED; fprintf(stderr, "WARNING: The option -k|--kerberos is deprecated!\n"); if (arg != NULL) { if (strcasecmp_m(arg, "yes") == 0) { use_kerberos = CRED_USE_KERBEROS_REQUIRED; } else if (strcasecmp_m(arg, "no") == 0) { use_kerberos = CRED_USE_KERBEROS_DISABLED; } else { fprintf(stderr, "Error parsing -k %s. Should be " "-k [yes|no]\n", arg); exit(1); } } ok = cli_credentials_set_kerberos_state(creds, use_kerberos, CRED_SPECIFIED); if (!ok) { fprintf(stderr, "Failed to set Kerberos state to %s!\n", arg); exit(1); } break; } } } static struct poptOption popt_legacy_s4[] = { { .argInfo = POPT_ARG_CALLBACK, .arg = (void *)popt_legacy_s4_callback, }, { .longName = "kerberos", .shortName = 'k', .argInfo = POPT_ARG_STRING, .val = 'k', .descrip = "DEPRECATED: Migrate to --use-kerberos", }, POPT_TABLEEND }; struct poptOption *samba_cmdline_get_popt(enum smb_cmdline_popt_options opt) { switch (opt) { case SAMBA_CMDLINE_POPT_OPT_DEBUG_ONLY: return popt_common_debug; break; case SAMBA_CMDLINE_POPT_OPT_OPTION_ONLY: return popt_common_option; break; case SAMBA_CMDLINE_POPT_OPT_CONFIG_ONLY: return popt_common_config; break; case SAMBA_CMDLINE_POPT_OPT_SAMBA: return popt_common_samba; break; case SAMBA_CMDLINE_POPT_OPT_CONNECTION: return popt_common_connection; break; case SAMBA_CMDLINE_POPT_OPT_CREDENTIALS: return popt_common_credentials; break; case SAMBA_CMDLINE_POPT_OPT_VERSION: return popt_common_version; break; case SAMBA_CMDLINE_POPT_OPT_DAEMON: return popt_common_daemon; break; case SAMBA_CMDLINE_POPT_OPT_SAMBA_LDB: return popt_common_samba_ldb; break; case SAMBA_CMDLINE_POPT_OPT_LEGACY_S3: return popt_legacy_s3; break; case SAMBA_CMDLINE_POPT_OPT_LEGACY_S4: return popt_legacy_s4; break; } /* Never reached */ return NULL; }