/* main server. */ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[]) { bool opt_daemon = false; bool opt_interactive = false; int opt; poptContext pc; #define _MODULE_PROTO(init) extern NTSTATUS init(void); STATIC_service_MODULES_PROTO; init_module_fn static_init[] = { STATIC_service_MODULES }; init_module_fn *shared_init; struct tevent_context *event_ctx; uint16_t stdin_event_flags; NTSTATUS status; const char *model = "standard"; int max_runtime = 0; struct stat st; enum { OPT_DAEMON = 1000, OPT_INTERACTIVE, OPT_PROCESS_MODEL, OPT_SHOW_BUILD }; struct poptOption long_options[] = { POPT_AUTOHELP {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)", NULL }, {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon)", NULL}, {"model", 'M', POPT_ARG_STRING, NULL, OPT_PROCESS_MODEL, "Select process model", "MODEL"}, {"maximum-runtime",0, POPT_ARG_INT, &max_runtime, 0, "set maximum runtime of the server process, till autotermination", "seconds"}, {"show-build", 'b', POPT_ARG_NONE, NULL, OPT_SHOW_BUILD, "show build info", NULL }, POPT_COMMON_SAMBA POPT_COMMON_VERSION { NULL } }; pc = poptGetContext(binary_name, argc, argv, long_options, 0); while((opt = poptGetNextOpt(pc)) != -1) { switch(opt) { case OPT_DAEMON: opt_daemon = true; break; case OPT_INTERACTIVE: opt_interactive = true; break; case OPT_PROCESS_MODEL: model = poptGetOptArg(pc); break; case OPT_SHOW_BUILD: show_build(); break; default: fprintf(stderr, "\nInvalid option %s: %s\n\n", poptBadOption(pc, 0), poptStrerror(opt)); poptPrintUsage(pc, stderr, 0); return 1; } } if (opt_daemon && opt_interactive) { fprintf(stderr,"\nERROR: " "Option -i|--interactive is not allowed together with -D|--daemon\n\n"); poptPrintUsage(pc, stderr, 0); return 1; } else if (!opt_interactive) { /* default is --daemon */ opt_daemon = true; } poptFreeContext(pc); setup_logging(binary_name, opt_interactive?DEBUG_STDOUT:DEBUG_FILE); setup_signals(); /* we want total control over the permissions on created files, so set our umask to 0 */ umask(0); DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING)); DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2015\n")); if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) { DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); DEBUGADD(0,("sizeof(uint16_t) = %u, sizeof(uint32_t) %u, sizeof(uint64_t) = %u\n", (unsigned int)sizeof(uint16_t), (unsigned int)sizeof(uint32_t), (unsigned int)sizeof(uint64_t))); return 1; } if (opt_daemon) { DEBUG(3,("Becoming a daemon.\n")); become_daemon(true, false, false); } cleanup_tmp_files(cmdline_lp_ctx); if (!directory_exist(lpcfg_lock_directory(cmdline_lp_ctx))) { mkdir(lpcfg_lock_directory(cmdline_lp_ctx), 0755); } pidfile_create(lpcfg_pid_directory(cmdline_lp_ctx), binary_name); /* Set up a database to hold a random seed, in case we don't * have /dev/urandom */ if (!randseed_init(talloc_autofree_context(), cmdline_lp_ctx)) { return 1; } if (lpcfg_server_role(cmdline_lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC) { if (!open_schannel_session_store(talloc_autofree_context(), cmdline_lp_ctx)) { exit_daemon("Samba cannot open schannel store for secured NETLOGON operations.", EACCES); } } /* make sure we won't go through nss_winbind */ if (!winbind_off()) { exit_daemon("Samba failed to disable recusive winbindd calls.", EACCES); } gensec_init(); /* FIXME: */ ntptr_init(); /* FIXME: maybe run this in the initialization function of the spoolss RPC server instead? */ ntvfs_init(cmdline_lp_ctx); /* FIXME: maybe run this in the initialization functions of the SMB[,2] server instead? */ process_model_init(cmdline_lp_ctx); shared_init = load_samba_modules(NULL, "service"); run_init_functions(static_init); run_init_functions(shared_init); talloc_free(shared_init); /* the event context is the top level structure in smbd. Everything else should hang off that */ event_ctx = s4_event_context_init(talloc_autofree_context()); if (event_ctx == NULL) { exit_daemon("Initializing event context failed", EACCES); } if (opt_interactive) { /* terminate when stdin goes away */ stdin_event_flags = TEVENT_FD_READ; } else { /* stay alive forever */ stdin_event_flags = 0; } /* catch EOF on stdin */ #ifdef SIGTTIN signal(SIGTTIN, SIG_IGN); #endif if (fstat(0, &st) != 0) { exit_daemon("Samba failed to set standard input handler", ENOTTY); } if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { tevent_add_fd(event_ctx, event_ctx, 0, stdin_event_flags, server_stdin_handler, discard_const(binary_name)); } if (max_runtime) { DEBUG(0,("Called with maxruntime %d - current ts %llu\n", max_runtime, (unsigned long long) time(NULL))); tevent_add_timer(event_ctx, event_ctx, timeval_current_ofs(max_runtime, 0), max_runtime_handler, discard_const(binary_name)); } if (lpcfg_server_role(cmdline_lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC && !lpcfg_parm_bool(cmdline_lp_ctx, NULL, "server role check", "inhibit", false) && !str_list_check_ci(lpcfg_server_services(cmdline_lp_ctx), "smb") && !str_list_check_ci(lpcfg_dcerpc_endpoint_servers(cmdline_lp_ctx), "remote") && !str_list_check_ci(lpcfg_dcerpc_endpoint_servers(cmdline_lp_ctx), "mapiproxy")) { DEBUG(0, ("At this time the 'samba' binary should only be used for either:\n")); DEBUGADD(0, ("'server role = active directory domain controller' or to access the ntvfs file server with 'server services = +smb' or the rpc proxy with 'dcerpc endpoint servers = remote'\n")); DEBUGADD(0, ("You should start smbd/nmbd/winbindd instead for domain member and standalone file server tasks\n")); exit_daemon("Samba detected misconfigured 'server role' and exited. Check logs for details", EINVAL); }; prime_ldb_databases(event_ctx); status = setup_parent_messaging(event_ctx, cmdline_lp_ctx); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba failed to setup parent messaging", NT_STATUS_V(status)); } DEBUG(0,("%s: using '%s' process model\n", binary_name, model)); status = server_service_startup(event_ctx, cmdline_lp_ctx, model, lpcfg_server_services(cmdline_lp_ctx)); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba failed to start services", NT_STATUS_V(status)); } if (opt_daemon) { daemon_ready("samba"); } /* wait for events - this is where smbd sits for most of its life */ tevent_loop_wait(event_ctx); /* as everything hangs off this event context, freeing it should initiate a clean shutdown of all services */ talloc_free(event_ctx); return 0; }
/** * Fill in credentials for the machine trust account, from the * secrets.ldb or passed in handle to secrets.tdb (perhaps in CTDB). * * This version is used in parts of the code that can link in the * CTDB dbwrap backend, by passing down the already open handle. * * @param cred Credentials structure to fill in * @param db_ctx dbwrap context for secrets.tdb * @retval NTSTATUS error detailing any failure */ _PUBLIC_ NTSTATUS cli_credentials_set_machine_account_db_ctx(struct cli_credentials *cred, struct loadparm_context *lp_ctx, struct db_context *db_ctx) { NTSTATUS status; char *filter; char *error_string = NULL; const char *domain; bool secrets_tdb_password_more_recent; time_t secrets_tdb_lct = 0; char *secrets_tdb_password = NULL; char *secrets_tdb_old_password = NULL; uint32_t secrets_tdb_secure_channel_type = SEC_CHAN_NULL; int server_role = lpcfg_server_role(lp_ctx); int security = lpcfg_security(lp_ctx); char *keystr; char *keystr_upper = NULL; TALLOC_CTX *tmp_ctx = talloc_named(cred, 0, "cli_credentials_set_secrets from ldb"); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } /* Bleh, nasty recursion issues: We are setting a machine * account here, so we don't want the 'pending' flag around * any more */ cred->machine_account_pending = false; /* We have to do this, as the fallback in * cli_credentials_set_secrets is to run as anonymous, so the domain is wiped */ domain = cli_credentials_get_domain(cred); if (db_ctx) { TDB_DATA dbuf; keystr = talloc_asprintf(tmp_ctx, "%s/%s", SECRETS_MACHINE_LAST_CHANGE_TIME, domain); keystr_upper = strupper_talloc(tmp_ctx, keystr); status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper), &dbuf); if (NT_STATUS_IS_OK(status) && dbuf.dsize == 4) { secrets_tdb_lct = IVAL(dbuf.dptr,0); } keystr = talloc_asprintf(tmp_ctx, "%s/%s", SECRETS_MACHINE_PASSWORD, domain); keystr_upper = strupper_talloc(tmp_ctx, keystr); status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper), &dbuf); if (NT_STATUS_IS_OK(status)) { secrets_tdb_password = (char *)dbuf.dptr; } keystr = talloc_asprintf(tmp_ctx, "%s/%s", SECRETS_MACHINE_PASSWORD_PREV, domain); keystr_upper = strupper_talloc(tmp_ctx, keystr); status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper), &dbuf); if (NT_STATUS_IS_OK(status)) { secrets_tdb_old_password = (char *)dbuf.dptr; } keystr = talloc_asprintf(tmp_ctx, "%s/%s", SECRETS_MACHINE_SEC_CHANNEL_TYPE, domain); keystr_upper = strupper_talloc(tmp_ctx, keystr); status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper), &dbuf); if (NT_STATUS_IS_OK(status) && dbuf.dsize == 4) { secrets_tdb_secure_channel_type = IVAL(dbuf.dptr,0); } } filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER, domain); status = cli_credentials_set_secrets_lct(cred, lp_ctx, NULL, SECRETS_PRIMARY_DOMAIN_DN, filter, secrets_tdb_lct, secrets_tdb_password, &error_string); if (secrets_tdb_password == NULL) { secrets_tdb_password_more_recent = false; } else if (NT_STATUS_EQUAL(NT_STATUS_CANT_ACCESS_DOMAIN_INFO, status) || NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, status)) { secrets_tdb_password_more_recent = true; } else if (secrets_tdb_lct > cli_credentials_get_password_last_changed_time(cred)) { secrets_tdb_password_more_recent = true; } else if (secrets_tdb_lct == cli_credentials_get_password_last_changed_time(cred)) { secrets_tdb_password_more_recent = strcmp(secrets_tdb_password, cli_credentials_get_password(cred)) != 0; } else { secrets_tdb_password_more_recent = false; } if (secrets_tdb_password_more_recent) { enum credentials_use_kerberos use_kerberos = CRED_DONT_USE_KERBEROS; char *machine_account = talloc_asprintf(tmp_ctx, "%s$", lpcfg_netbios_name(lp_ctx)); cli_credentials_set_password(cred, secrets_tdb_password, CRED_SPECIFIED); cli_credentials_set_old_password(cred, secrets_tdb_old_password, CRED_SPECIFIED); cli_credentials_set_domain(cred, domain, CRED_SPECIFIED); if (strequal(domain, lpcfg_workgroup(lp_ctx))) { cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_SPECIFIED); switch (server_role) { case ROLE_DOMAIN_MEMBER: if (security != SEC_ADS) { break; } FALL_THROUGH; case ROLE_ACTIVE_DIRECTORY_DC: use_kerberos = CRED_AUTO_USE_KERBEROS; break; } } cli_credentials_set_kerberos_state(cred, use_kerberos); cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED); cli_credentials_set_password_last_changed_time(cred, secrets_tdb_lct); cli_credentials_set_secure_channel_type(cred, secrets_tdb_secure_channel_type); status = NT_STATUS_OK; } else if (!NT_STATUS_IS_OK(status)) { if (db_ctx) { error_string = talloc_asprintf(cred, "Failed to fetch machine account password for %s from both " "secrets.ldb (%s) and from %s", domain, error_string == NULL ? "error" : error_string, dbwrap_name(db_ctx)); } else { char *secrets_tdb_path; secrets_tdb_path = lpcfg_private_db_path(tmp_ctx, lp_ctx, "secrets"); if (secrets_tdb_path == NULL) { return NT_STATUS_NO_MEMORY; } error_string = talloc_asprintf(cred, "Failed to fetch machine account password from " "secrets.ldb: %s and failed to open %s", error_string == NULL ? "error" : error_string, secrets_tdb_path); } DEBUG(1, ("Could not find machine account in secrets database: %s: %s\n", error_string == NULL ? "error" : error_string, nt_errstr(status))); /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); } TALLOC_FREE(tmp_ctx); return status; }
/** * Start NTLMSSP on the server side * */ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; struct ntlmssp_state *ntlmssp_state; struct gensec_ntlmssp_context *gensec_ntlmssp; nt_status = gensec_ntlmssp_start(gensec_security); NT_STATUS_NOT_OK_RETURN(nt_status); gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); ntlmssp_state = gensec_ntlmssp->ntlmssp_state; ntlmssp_state->role = NTLMSSP_SERVER; ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE; ntlmssp_state->allow_lm_key = (lpcfg_lanman_auth(gensec_security->settings->lp_ctx) && gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "allow_lm_key", false)); ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION; ntlmssp_state->lm_resp = data_blob(NULL, 0); ntlmssp_state->nt_resp = data_blob(NULL, 0); if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "128bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "56bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "keyexchange", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "alwayssign", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "ntlm2", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } gensec_ntlmssp->auth_context = gensec_security->auth_context; ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; ntlmssp_state->check_password = auth_ntlmssp_check_password; if (lpcfg_server_role(gensec_security->settings->lp_ctx) == ROLE_STANDALONE) { ntlmssp_state->server.is_standalone = true; } else { ntlmssp_state->server.is_standalone = false; } ntlmssp_state->server.netbios_name = lpcfg_netbios_name(gensec_security->settings->lp_ctx); ntlmssp_state->server.netbios_domain = lpcfg_workgroup(gensec_security->settings->lp_ctx); { const char *dnsdomain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); char *dnsname, *lower_netbiosname; lower_netbiosname = strlower_talloc(ntlmssp_state, ntlmssp_state->server.netbios_name); /* Find out the DNS host name */ if (dnsdomain && dnsdomain[0] != '\0') { dnsname = talloc_asprintf(ntlmssp_state, "%s.%s", lower_netbiosname, dnsdomain); talloc_free(lower_netbiosname); ntlmssp_state->server.dns_name = dnsname; } else { ntlmssp_state->server.dns_name = lower_netbiosname; } NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_name); ntlmssp_state->server.dns_domain = talloc_strdup(ntlmssp_state, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_domain); } return NT_STATUS_OK; }