1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-07 17:18:11 +03:00
samba-mirror/lib/cmdline/cmdline.c
Andrew Bartlett 3109899299 lib/fault: During smb_panic() print process comment and setprocname() title
The purpose of this is to make it clear which part of the AD DC (in particular)
has faulted without having to deduce it from the stacktrace.

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
2023-07-21 01:25:37 +00:00

1403 lines
31 KiB
C

/*
* Copyright (c) 2020 Andreas Schneider <asn@samba.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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 "lib/util/util_process.h"
#include <samba/version.h>
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;
static NTSTATUS (*cli_credentials_set_machine_account_fn)(
struct cli_credentials *cred,
struct loadparm_context *lp_ctx) =
cli_credentials_set_machine_account;
/* 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_set_machine_account_fn(
NTSTATUS (*fn) (struct cli_credentials *cred,
struct loadparm_context *lp_ctx))
{
cli_credentials_set_machine_account_fn = fn;
}
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
process_save_binary_name(name);
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. There 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_fn(
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: {
int32_t use_kerberos = INT_MIN;
if (arg == NULL) {
fprintf(stderr,
"Failed to parse "
"--use-kerberos=desired|required|off: "
"Missing argument\n");
exit(1);
}
use_kerberos = lpcfg_parse_enum_vals("client use kerberos",
arg);
if (use_kerberos == INT_MIN) {
fprintf(stderr,
"Failed to parse "
"--use-kerberos=desired|required|off: "
"Invalid argument\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: {
const char *error_string = NULL;
int rc;
if (arg == NULL) {
fprintf(stderr,
"Failed to parse --use-krb5-ccache=CCACHE: "
"Missing argument\n");
exit(1);
}
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: {
uint32_t gensec_features;
enum smb_signing_setting signing_state =
SMB_SIGNING_OFF;
enum smb_encryption_setting encryption_state =
SMB_ENCRYPTION_OFF;
if (arg == NULL) {
fprintf(stderr,
"Failed to parse "
"--client-protection=sign|encrypt|off: "
"Missing argument\n");
exit(1);
}
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;
}