struct imessaging_context *winbind_imessaging_context(void) { static struct imessaging_context *msg = NULL; struct loadparm_context *lp_ctx; if (msg != NULL) { return msg; } lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers()); if (lp_ctx == NULL) { smb_panic("Could not load smb.conf to init winbindd's imessaging context.\n"); } /* * Note we MUST use the NULL context here, not the autofree context, * to avoid side effects in forked children exiting. */ msg = imessaging_init(NULL, lp_ctx, procid_self(), winbind_event_context(), false); talloc_unlink(NULL, lp_ctx); if (msg == NULL) { smb_panic("Could not init winbindd's messaging context.\n"); } return msg; }
static bool posix_eadb_init(int snum, struct tdb_wrap **p_db) { struct tdb_wrap *db; struct loadparm_context *lp_ctx; const char *eadb = lp_parm_const_string(snum, "posix", "eadb", NULL); if (!eadb) { DEBUG(0, ("Can not use vfs_posix_eadb without posix:eadb set\n")); return false; } lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers()); become_root(); db = tdb_wrap_open(NULL, eadb, 50000, TDB_DEFAULT, O_RDWR|O_CREAT, 0600, lp_ctx); unbecome_root(); talloc_unlink(NULL, lp_ctx); /* now we know dbname is not NULL */ if (db == NULL) { #if defined(ENOTSUP) errno = ENOTSUP; #else errno = ENOSYS; #endif return false; } *p_db = db; return true; }
/* * Hook to allow handling of NTLM authentication for AD operation * without directly linking the s4 auth stack * * This ensures we use the source4 authentication stack, as well as * the authorization stack to create the user's token. This ensures * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is * handled by the hook above. */ static NTSTATUS make_auth4_context_s4(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct imessaging_context *msg_ctx; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); status = auth_context_create(mem_ctx, event_ctx, msg_ctx, lp_ctx, auth4_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, *auth4_context, msg_ctx); talloc_reparent(frame, *auth4_context, event_ctx); talloc_reparent(frame, *auth4_context, lp_ctx); TALLOC_FREE(frame); return status; }
NTSTATUS rpccli_pre_open_netlogon_creds(void) { static bool already_open = false; TALLOC_CTX *frame; struct loadparm_context *lp_ctx; char *fname; struct db_context *global_db; NTSTATUS status; if (already_open) { return NT_STATUS_OK; } frame = talloc_stackframe(); lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } fname = lpcfg_private_db_path(frame, lp_ctx, "netlogon_creds_cli"); if (fname == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } global_db = db_open(frame, fname, 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_OPTIMIZE_READONLY_ACCESS); if (global_db == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } status = netlogon_creds_cli_set_global_db(&global_db); TALLOC_FREE(frame); if (!NT_STATUS_IS_OK(status)) { return status; } already_open = true; return NT_STATUS_OK; }
static NTSTATUS rpccli_create_netlogon_creds( const char *server_computer, const char *server_netbios_domain, const char *server_dns_domain, const char *client_account, enum netr_SchannelType sec_chan_type, struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context **netlogon_creds) { TALLOC_CTX *frame = talloc_stackframe(); struct loadparm_context *lp_ctx; NTSTATUS status; status = rpccli_pre_open_netlogon_creds(); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return status; } lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } status = netlogon_creds_cli_context_global(lp_ctx, msg_ctx, client_account, sec_chan_type, server_computer, server_netbios_domain, server_dns_domain, mem_ctx, netlogon_creds); TALLOC_FREE(frame); if (!NT_STATUS_IS_OK(status)) { return status; } return NT_STATUS_OK; }
NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address, struct gensec_security **gensec_security_out) { struct gensec_security *gensec_security; struct auth_context *auth_context; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); nt_status = make_auth_context_subsystem(tmp_ctx, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } if (auth_context->prepare_gensec) { nt_status = auth_context->prepare_gensec(auth_context, tmp_ctx, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } } else { const struct gensec_security_ops **backends = NULL; struct gensec_settings *gensec_settings; struct loadparm_context *lp_ctx; size_t idx = 0; struct cli_credentials *server_credentials; const char *dns_name; const char *dns_domain; struct auth4_context *auth4_context = make_auth4_context_s3(tmp_ctx, auth_context); if (auth4_context == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_INVALID_SERVER_STATE; } gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx); if (lp_ctx == NULL) { DEBUG(10, ("lpcfg_gensec_settings failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* * This should be a 'netbios domain -> DNS domain' * mapping, and can currently validly return NULL on * poorly configured systems. * * This is used for the NTLMSSP server * */ dns_name = get_mydnsfullname(); if (dns_name == NULL) { dns_name = ""; } dns_domain = get_mydnsdomname(tmp_ctx); if (dns_domain == NULL) { dns_domain = ""; } gensec_settings->server_dns_name = strlower_talloc(gensec_settings, dns_name); if (gensec_settings->server_dns_name == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->server_dns_domain = strlower_talloc(gensec_settings, dns_domain); if (gensec_settings->server_dns_domain == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } backends = talloc_zero_array(gensec_settings, const struct gensec_security_ops *, 6); if (backends == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->backends = backends; gensec_init(); /* These need to be in priority order, krb5 before NTLMSSP */ #if defined(HAVE_KRB5) backends[idx++] = &gensec_gse_krb5_security_ops; #endif backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP); backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_SCHANNEL); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM); /* * This is anonymous for now, because we just use it * to set the kerberos state at the moment */ server_credentials = cli_credentials_init_anon(tmp_ctx); if (!server_credentials) { DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n")); return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(server_credentials, lp_ctx); if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) { cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS); } else { cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS); } nt_status = gensec_server_start(tmp_ctx, gensec_settings, auth4_context, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } gensec_set_credentials(gensec_security, server_credentials); talloc_unlink(tmp_ctx, lp_ctx); talloc_unlink(tmp_ctx, server_credentials); talloc_unlink(tmp_ctx, gensec_settings); talloc_unlink(tmp_ctx, auth4_context); } nt_status = gensec_set_remote_address(gensec_security, remote_address); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } *gensec_security_out = talloc_steal(mem_ctx, gensec_security); TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; }
/** * open a database */ struct db_context *db_open(TALLOC_CTX *mem_ctx, const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode, enum dbwrap_lock_order lock_order, uint64_t dbwrap_flags) { struct db_context *result = NULL; const char *sockname; if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) { errno = EINVAL; return NULL; } if (tdb_flags & TDB_CLEAR_IF_FIRST) { const char *base; bool try_readonly = false; base = strrchr_m(name, '/'); if (base != NULL) { base += 1; } else { base = name; } if (dbwrap_flags & DBWRAP_FLAG_OPTIMIZE_READONLY_ACCESS) { try_readonly = true; } try_readonly = lp_parm_bool(-1, "dbwrap_optimize_readonly", "*", try_readonly); try_readonly = lp_parm_bool(-1, "dbwrap_optimize_readonly", base, try_readonly); if (try_readonly) { dbwrap_flags |= DBWRAP_FLAG_OPTIMIZE_READONLY_ACCESS; } else { dbwrap_flags &= ~DBWRAP_FLAG_OPTIMIZE_READONLY_ACCESS; } } if (tdb_flags & TDB_CLEAR_IF_FIRST) { const char *base; bool try_mutex = true; bool require_mutex = false; base = strrchr_m(name, '/'); if (base != NULL) { base += 1; } else { base = name; } try_mutex = lp_parm_bool(-1, "dbwrap_tdb_mutexes", "*", try_mutex); try_mutex = lp_parm_bool(-1, "dbwrap_tdb_mutexes", base, try_mutex); if (!lp_use_mmap()) { /* * Mutexes require mmap. "use mmap = no" can * be a debugging tool, so let it override the * mutex parameters */ try_mutex = false; } if (try_mutex && tdb_runtime_check_for_robust_mutexes()) { tdb_flags |= TDB_MUTEX_LOCKING; } require_mutex = lp_parm_bool(-1, "dbwrap_tdb_require_mutexes", "*", require_mutex); require_mutex = lp_parm_bool(-1, "dbwrap_tdb_require_mutexes", base, require_mutex); if (require_mutex) { tdb_flags |= TDB_MUTEX_LOCKING; } } sockname = lp_ctdbd_socket(); if (lp_clustering()) { const char *partname; if (!socket_exist(sockname)) { DEBUG(1, ("ctdb socket does not exist - is ctdb not " "running?\n")); return NULL; } /* ctdb only wants the file part of the name */ partname = strrchr(name, '/'); if (partname) { partname++; } else { partname = name; } /* allow ctdb for individual databases to be disabled */ if (lp_parm_bool(-1, "ctdb", partname, True)) { struct messaging_context *msg_ctx; struct ctdbd_connection *conn; conn = messaging_ctdb_connection(); if (conn == NULL) { DBG_WARNING("No ctdb connection\n"); errno = EIO; return NULL; } msg_ctx = server_messaging_context(); result = db_open_ctdb(mem_ctx, msg_ctx, partname, hash_size, tdb_flags, open_flags, mode, lock_order, dbwrap_flags); if (result == NULL) { DEBUG(0,("failed to attach to ctdb %s\n", partname)); if (errno == 0) { errno = EIO; } return NULL; } } } if (result == NULL) { struct loadparm_context *lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); if (hash_size == 0) { hash_size = lpcfg_tdb_hash_size(lp_ctx, name); } tdb_flags = lpcfg_tdb_flags(lp_ctx, tdb_flags); result = dbwrap_local_open( mem_ctx, name, hash_size, tdb_flags, open_flags, mode, lock_order, dbwrap_flags); talloc_unlink(mem_ctx, lp_ctx); } return result; }
int main(int argc,const char *argv[]) { /* shall I run as a daemon */ bool is_daemon = false; bool interactive = false; bool Fork = true; bool no_process_group = false; bool log_stdout = false; char *ports = NULL; char *profile_level = NULL; int opt; poptContext pc; bool print_build_options = False; enum { OPT_DAEMON = 1000, OPT_INTERACTIVE, OPT_FORK, OPT_NO_PROCESS_GROUP, OPT_LOG_STDOUT }; struct poptOption long_options[] = { POPT_AUTOHELP {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)" }, {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon)"}, {"foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Run daemon in foreground (for daemontools, etc.)" }, {"no-process-group", '\0', POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" }, {"log-stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" }, {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" }, {"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"}, {"profiling-level", 'P', POPT_ARG_STRING, &profile_level, 0, "Set profiling level","PROFILE_LEVEL"}, POPT_COMMON_SAMBA POPT_TABLEEND }; struct smbd_parent_context *parent = NULL; TALLOC_CTX *frame; NTSTATUS status; struct tevent_context *ev_ctx; struct messaging_context *msg_ctx; struct server_id server_id; struct tevent_signal *se; int profiling_level; char *np_dir = NULL; static const struct smbd_shim smbd_shim_fns = { .cancel_pending_lock_requests_by_fid = smbd_cancel_pending_lock_requests_by_fid, .send_stat_cache_delete_message = smbd_send_stat_cache_delete_message, .change_to_root_user = smbd_change_to_root_user, .become_authenticated_pipe_user = smbd_become_authenticated_pipe_user, .unbecome_authenticated_pipe_user = smbd_unbecome_authenticated_pipe_user, .contend_level2_oplocks_begin = smbd_contend_level2_oplocks_begin, .contend_level2_oplocks_end = smbd_contend_level2_oplocks_end, .become_root = smbd_become_root, .unbecome_root = smbd_unbecome_root, .exit_server = smbd_exit_server, .exit_server_cleanly = smbd_exit_server_cleanly, }; /* * Do this before any other talloc operation */ talloc_enable_null_tracking(); frame = talloc_stackframe(); setup_logging(argv[0], DEBUG_DEFAULT_STDOUT); smb_init_locale(); set_smbd_shim(&smbd_shim_fns); smbd_init_globals(); TimeInit(); #ifdef HAVE_SET_AUTH_PARAMETERS set_auth_parameters(argc,argv); #endif pc = poptGetContext("smbd", argc, argv, long_options, 0); while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_DAEMON: is_daemon = true; break; case OPT_INTERACTIVE: interactive = true; break; case OPT_FORK: Fork = false; break; case OPT_NO_PROCESS_GROUP: no_process_group = true; break; case OPT_LOG_STDOUT: log_stdout = true; break; case 'b': print_build_options = True; break; default: d_fprintf(stderr, "\nInvalid option %s: %s\n\n", poptBadOption(pc, 0), poptStrerror(opt)); poptPrintUsage(pc, stderr, 0); exit(1); } } poptFreeContext(pc); if (interactive) { Fork = False; log_stdout = True; } if (log_stdout) { setup_logging(argv[0], DEBUG_STDOUT); } else { setup_logging(argv[0], DEBUG_FILE); } if (print_build_options) { build_options(True); /* Display output to screen as well as debug */ exit(0); } #ifdef HAVE_SETLUID /* needed for SecureWare on SCO */ setluid(0); #endif set_remote_machine_name("smbd", False); if (interactive && (DEBUGLEVEL >= 9)) { talloc_enable_leak_report(); } if (log_stdout && Fork) { DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n")); exit(1); } /* we want to re-seed early to prevent time delays causing client problems at a later date. (tridge) */ generate_random_buffer(NULL, 0); /* get initial effective uid and gid */ sec_init(); /* make absolutely sure we run as root - to handle cases where people are crazy enough to have it setuid */ gain_root_privilege(); gain_root_group_privilege(); fault_setup(); dump_core_setup("smbd", lp_logfile(talloc_tos())); /* we are never interested in SIGPIPE */ BlockSignals(True,SIGPIPE); #if defined(SIGFPE) /* we are never interested in SIGFPE */ BlockSignals(True,SIGFPE); #endif #if defined(SIGUSR2) /* We are no longer interested in USR2 */ BlockSignals(True,SIGUSR2); #endif /* POSIX demands that signals are inherited. If the invoking process has * these signals masked, we will have problems, as we won't recieve them. */ BlockSignals(False, SIGHUP); BlockSignals(False, SIGUSR1); BlockSignals(False, SIGTERM); /* Ensure we leave no zombies until we * correctly set up child handling below. */ CatchChild(); /* we want total control over the permissions on created files, so set our umask to 0 */ umask(0); reopen_logs(); DEBUG(0,("smbd version %s started.\n", samba_version_string())); DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE)); DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n", (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid())); /* Output the build options to the debug log */ build_options(False); if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4) { DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); exit(1); } if (!lp_load_initial_only(get_dyn_CONFIGFILE())) { DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE())); exit(1); } if (!cluster_probe_ok()) { exit(1); } /* Init the security context and global current_user */ init_sec_ctx(); /* * Initialize the event context. The event context needs to be * initialized before the messaging context, cause the messaging * context holds an event context. * FIXME: This should be s3_tevent_context_init() */ ev_ctx = server_event_context(); if (ev_ctx == NULL) { exit(1); } /* * Init the messaging context * FIXME: This should only call messaging_init() */ msg_ctx = server_messaging_context(); if (msg_ctx == NULL) { exit(1); } /* * Reloading of the printers will not work here as we don't have a * server info and rpc services set up. It will be called later. */ if (!reload_services(NULL, NULL, false)) { exit(1); } if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC && !lp_parm_bool(-1, "server role check", "inhibit", false)) { DEBUG(0, ("server role = 'active directory domain controller' not compatible with running smbd standalone. \n")); DEBUGADD(0, ("You should start 'samba' instead, and it will control starting smbd if required\n")); exit(1); } /* ...NOTE... Log files are working from this point! */ DEBUG(3,("loaded services\n")); init_structs(); if (!profile_setup(msg_ctx, False)) { DEBUG(0,("ERROR: failed to setup profiling\n")); return -1; } if (profile_level != NULL) { profiling_level = atoi(profile_level); } else { profiling_level = lp_smbd_profiling_level(); } set_profile_level(profiling_level, messaging_server_id(msg_ctx)); if (!is_daemon && !is_a_socket(0)) { if (!interactive) { DEBUG(3, ("Standard input is not a socket, " "assuming -D option\n")); } /* * Setting is_daemon here prevents us from eventually calling * the open_sockets_inetd() */ is_daemon = True; } if (is_daemon && !interactive) { DEBUG(3, ("Becoming a daemon.\n")); become_daemon(Fork, no_process_group, log_stdout); } #if HAVE_SETPGID /* * If we're interactive we want to set our own process group for * signal management. */ if (interactive && !no_process_group) setpgid( (pid_t)0, (pid_t)0); #endif if (!directory_exist(lp_lock_directory())) mkdir(lp_lock_directory(), 0755); if (!directory_exist(lp_pid_directory())) mkdir(lp_pid_directory(), 0755); if (is_daemon) pidfile_create(lp_pid_directory(), "smbd"); status = reinit_after_fork(msg_ctx, ev_ctx, false, NULL); if (!NT_STATUS_IS_OK(status)) { exit_daemon("reinit_after_fork() failed", map_errno_from_nt_status(status)); } if (!interactive) { /* * Do not initialize the parent-child-pipe before becoming a * daemon: this is used to detect a died parent in the child * process. */ status = init_before_fork(); if (!NT_STATUS_IS_OK(status)) { exit_daemon(nt_errstr(status), map_errno_from_nt_status(status)); } } parent = talloc_zero(ev_ctx, struct smbd_parent_context); if (!parent) { exit_server("talloc(struct smbd_parent_context) failed"); } parent->interactive = interactive; parent->ev_ctx = ev_ctx; parent->msg_ctx = msg_ctx; am_parent = parent; se = tevent_add_signal(parent->ev_ctx, parent, SIGTERM, 0, smbd_parent_sig_term_handler, parent); if (!se) { exit_server("failed to setup SIGTERM handler"); } se = tevent_add_signal(parent->ev_ctx, parent, SIGHUP, 0, smbd_parent_sig_hup_handler, parent); if (!se) { exit_server("failed to setup SIGHUP handler"); } /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */ if (smbd_memcache() == NULL) { exit_daemon("no memcache available", EACCES); } memcache_set_global(smbd_memcache()); /* Initialise the password backed before the global_sam_sid to ensure that we fetch from ldap before we make a domain sid up */ if(!initialize_password_db(false, ev_ctx)) exit(1); if (!secrets_init()) { exit_daemon("smbd can not open secrets.tdb", EACCES); } if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) { struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers()); if (!open_schannel_session_store(NULL, lp_ctx)) { exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES); } TALLOC_FREE(lp_ctx); } if(!get_global_sam_sid()) { exit_daemon("Samba cannot create a SAM SID", EACCES); } server_id = messaging_server_id(msg_ctx); status = smbXsrv_version_global_init(&server_id); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba cannot init server context", EACCES); } status = smbXsrv_session_global_init(); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba cannot init session context", EACCES); } status = smbXsrv_tcon_global_init(); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba cannot init tcon context", EACCES); } if (!locking_init()) exit_daemon("Samba cannot init locking", EACCES); if (!leases_db_init(false)) { exit_daemon("Samba cannot init leases", EACCES); } if (!smbd_notifyd_init(msg_ctx, interactive)) { exit_daemon("Samba cannot init notification", EACCES); } if (!messaging_parent_dgm_cleanup_init(msg_ctx)) { exit(1); } if (!smbd_scavenger_init(NULL, msg_ctx, ev_ctx)) { exit_daemon("Samba cannot init scavenging", EACCES); } if (!serverid_parent_init(ev_ctx)) { exit_daemon("Samba cannot init server id", EACCES); } if (!W_ERROR_IS_OK(registry_init_full())) exit_daemon("Samba cannot init registry", EACCES); /* Open the share_info.tdb here, so we don't have to open after the fork on every single connection. This is a small performance improvment and reduces the total number of system fds used. */ if (!share_info_db_init()) { exit_daemon("ERROR: failed to load share info db.", EACCES); } status = init_system_session_info(); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("ERROR: failed to setup system user info: %s.\n", nt_errstr(status))); return -1; } if (!init_guest_info()) { DEBUG(0,("ERROR: failed to setup guest info.\n")); return -1; } if (!file_init_global()) { DEBUG(0, ("ERROR: file_init_global() failed\n")); return -1; } status = smbXsrv_open_global_init(); if (!NT_STATUS_IS_OK(status)) { exit_daemon("Samba cannot init global open", map_errno_from_nt_status(status)); } /* This MUST be done before start_epmd() because otherwise * start_epmd() forks and races against dcesrv_ep_setup() to * call directory_create_or_exist() */ if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) { DEBUG(0, ("Failed to create pipe directory %s - %s\n", lp_ncalrpc_dir(), strerror(errno))); return -1; } np_dir = talloc_asprintf(talloc_tos(), "%s/np", lp_ncalrpc_dir()); if (!np_dir) { DEBUG(0, ("%s: Out of memory\n", __location__)); return -1; } if (!directory_create_or_exist_strict(np_dir, geteuid(), 0700)) { DEBUG(0, ("Failed to create pipe directory %s - %s\n", np_dir, strerror(errno))); return -1; } if (is_daemon && !interactive) { if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) { start_epmd(ev_ctx, msg_ctx); } } if (!dcesrv_ep_setup(ev_ctx, msg_ctx)) { exit_daemon("Samba cannot setup ep pipe", EACCES); } if (is_daemon && !interactive) { daemon_ready("smbd"); } /* only start other daemons if we are running as a daemon * -- bad things will happen if smbd is launched via inetd * and we fork a copy of ourselves here */ if (is_daemon && !interactive) { if (rpc_lsasd_daemon() == RPC_DAEMON_FORK) { start_lsasd(ev_ctx, msg_ctx); } if (rpc_fss_daemon() == RPC_DAEMON_FORK) { start_fssd(ev_ctx, msg_ctx); } if (!lp__disable_spoolss() && (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) { bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true); if (!printing_subsystem_init(ev_ctx, msg_ctx, true, bgq)) { exit_daemon("Samba failed to init printing subsystem", EACCES); } } #ifdef WITH_SPOTLIGHT if ((rpc_mdssvc_mode() == RPC_SERVICE_MODE_EXTERNAL) && (rpc_mdssd_daemon() == RPC_DAEMON_FORK)) { start_mdssd(ev_ctx, msg_ctx); } #endif } else if (!lp__disable_spoolss() && (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) { if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) { exit(1); } } if (!is_daemon) { int sock; /* inetd mode */ TALLOC_FREE(frame); /* Started from inetd. fd 0 is the socket. */ /* We will abort gracefully when the client or remote system goes away */ sock = dup(0); /* close stdin, stdout (if not logging to it), but not stderr */ close_low_fds(true, !debug_get_output_is_stdout(), false); #ifdef HAVE_ATEXIT atexit(killkids); #endif /* Stop zombies */ smbd_setup_sig_chld_handler(parent); smbd_process(ev_ctx, msg_ctx, sock, true); exit_server_cleanly(NULL); return(0); } if (!open_sockets_smbd(parent, ev_ctx, msg_ctx, ports)) exit_server("open_sockets_smbd() failed"); /* do a printer update now that all messaging has been set up, * before we allow clients to start connecting */ if (!lp__disable_spoolss() && (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) { printing_subsystem_update(ev_ctx, msg_ctx, false); } TALLOC_FREE(frame); /* make sure we always have a valid stackframe */ frame = talloc_stackframe(); if (!Fork) { /* if we are running in the foreground then look for EOF on stdin, and exit if it happens. This allows us to die if the parent process dies Only do this on a pipe or socket, no other device. */ struct stat st; if (fstat(0, &st) != 0) { return false; } if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { tevent_add_fd(ev_ctx, parent, 0, TEVENT_FD_READ, smbd_stdin_handler, NULL); } } smbd_parent_loop(ev_ctx, parent); exit_server_cleanly(NULL); TALLOC_FREE(frame); return(0); }
NTSTATUS auth_generic_client_prepare(TALLOC_CTX *mem_ctx, struct auth_generic_state **auth_generic_state) { struct auth_generic_state *ans; NTSTATUS nt_status; size_t idx = 0; struct gensec_settings *gensec_settings; const struct gensec_security_ops **backends = NULL; struct loadparm_context *lp_ctx; ans = talloc_zero(mem_ctx, struct auth_generic_state); if (!ans) { DEBUG(0,("auth_generic_start: talloc failed!\n")); return NT_STATUS_NO_MEMORY; } lp_ctx = loadparm_init_s3(ans, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); TALLOC_FREE(ans); return NT_STATUS_INVALID_SERVER_STATE; } gensec_settings = lpcfg_gensec_settings(ans, lp_ctx); if (lp_ctx == NULL) { DEBUG(10, ("lpcfg_gensec_settings failed\n")); TALLOC_FREE(ans); return NT_STATUS_NO_MEMORY; } backends = talloc_zero_array(gensec_settings, const struct gensec_security_ops *, 6); if (backends == NULL) { TALLOC_FREE(ans); return NT_STATUS_NO_MEMORY; } gensec_settings->backends = backends; gensec_init(); /* These need to be in priority order, krb5 before NTLMSSP */ #if defined(HAVE_KRB5) backends[idx++] = &gensec_gse_krb5_security_ops; #endif backends[idx++] = &gensec_ntlmssp3_client_ops; backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_SCHANNEL); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM); nt_status = gensec_client_start(ans, &ans->gensec_security, gensec_settings); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(ans); return nt_status; } ans->credentials = cli_credentials_init(ans); if (!ans->credentials) { TALLOC_FREE(ans); return NT_STATUS_NO_MEMORY; } cli_credentials_guess(ans->credentials, lp_ctx); talloc_unlink(ans, lp_ctx); talloc_unlink(ans, gensec_settings); *auth_generic_state = ans; return NT_STATUS_OK; }
static void popt_common_callback(poptContext con, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { if (reason == POPT_CALLBACK_REASON_PRE) { set_logfile(con, get_dyn_LOGFILEBASE()); talloc_set_log_fn(popt_s3_talloc_log_fn); talloc_set_abort_fn(smb_panic); return; } if (reason == POPT_CALLBACK_REASON_POST) { if (PrintSambaVersionString) { printf( "Version %s\n", samba_version_string()); exit(0); } if (is_default_dyn_CONFIGFILE()) { if(getenv("SMB_CONF_PATH")) { set_dyn_CONFIGFILE(getenv("SMB_CONF_PATH")); } } /* Further 'every Samba program must do this' hooks here. */ return; } switch(opt->val) { case OPT_OPTION: { struct loadparm_context *lp_ctx; lp_ctx = loadparm_init_s3(talloc_tos(), loadparm_s3_helpers()); if (lp_ctx == NULL) { fprintf(stderr, "loadparm_init_s3() failed!\n"); exit(1); } if (!lpcfg_set_option(lp_ctx, arg)) { fprintf(stderr, "Error setting option '%s'\n", arg); exit(1); } TALLOC_FREE(lp_ctx); break; } case 'd': if (arg) { lp_set_cmdline("log level", arg); } break; case 'V': PrintSambaVersionString = True; break; case 'O': if (arg) { lp_set_cmdline("socket options", arg); } break; case 's': if (arg) { set_dyn_CONFIGFILE(arg); } break; case 'n': if (arg) { lp_set_cmdline("netbios name", arg); } break; case 'l': if (arg) { set_logfile(con, arg); override_logfile = True; set_dyn_LOGFILEBASE(arg); } break; case 'i': if (arg) { lp_set_cmdline("netbios scope", arg); } break; case 'W': if (arg) { lp_set_cmdline("workgroup", arg); } break; } }
/* * Hook to allow handling of NTLM authentication for AD operation * without directly linking the s4 auth stack * * This ensures we use the source4 authentication stack, as well as * the authorization stack to create the user's token. This ensures * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is * handled by the hook above. */ static NTSTATUS make_auth4_context_s4(const struct auth_context *auth_context, TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct imessaging_context *msg_ctx; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); /* Allow forcing a specific auth4 module */ if (!auth_context->forced_samba4_methods) { status = auth_context_create(mem_ctx, event_ctx, msg_ctx, lp_ctx, auth4_context); } else { const char * const *forced_auth_methods = (const char * const *)str_list_make(mem_ctx, auth_context->forced_samba4_methods, NULL); status = auth_context_create_methods(mem_ctx, forced_auth_methods, event_ctx, msg_ctx, lp_ctx, NULL, auth4_context); } if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, *auth4_context, msg_ctx); talloc_reparent(frame, *auth4_context, event_ctx); talloc_reparent(frame, *auth4_context, lp_ctx); TALLOC_FREE(frame); return status; }
/* * Hook to allow the source4 set of GENSEC modules to handle * blob-based authentication mechanisms, without directly linking the * mechanism code. * * This may eventually go away, when the GSSAPI acceptors are merged, * when we will just rely on the make_auth4_context_s4 hook instead. * * Even for NTLMSSP, which has a common module, significant parts of * the behaviour are overridden here, because it uses the source4 NTLM * stack and the source4 mapping between the PAC/SamLogon response and * the local token. * * It is important to override all this to ensure that the exact same * token is generated and used in the SMB and LDAP servers, for NTLM * and for Kerberos. */ static NTSTATUS prepare_gensec(const struct auth_context *auth_context, TALLOC_CTX *mem_ctx, struct gensec_security **gensec_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct gensec_security *gensec_ctx; struct imessaging_context *msg_ctx; struct cli_credentials *server_credentials; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); server_credentials = cli_credentials_init(frame); if (!server_credentials) { DEBUG(1, ("Failed to init server credentials")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } cli_credentials_set_conf(server_credentials, lp_ctx); status = cli_credentials_set_machine_account(server_credentials, lp_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } status = samba_server_gensec_start(mem_ctx, event_ctx, msg_ctx, lp_ctx, server_credentials, "cifs", &gensec_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, gensec_ctx, msg_ctx); talloc_reparent(frame, gensec_ctx, event_ctx); talloc_reparent(frame, gensec_ctx, lp_ctx); talloc_reparent(frame, gensec_ctx, server_credentials); gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(gensec_ctx, GENSEC_FEATURE_UNIX_TOKEN); *gensec_context = gensec_ctx; TALLOC_FREE(frame); return status; }
/* * Given the username/password, do a kinit, store the ticket in * cache_name if specified, and return the PAC_LOGON_INFO (the * structure containing the important user information such as * groups). */ NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx, const char *name, const char *pass, time_t time_offset, time_t *expire_time, time_t *renew_till_time, const char *cache_name, bool request_pac, bool add_netbios_addr, time_t renewable_time, const char *impersonate_princ_s, const char *local_service, struct PAC_DATA_CTR **_pac_data_ctr) { krb5_error_code ret; NTSTATUS status = NT_STATUS_INVALID_PARAMETER; DATA_BLOB tkt, tkt_wrapped, ap_rep, sesskey1; const char *auth_princ = NULL; const char *cc = "MEMORY:kerberos_return_pac"; struct auth_session_info *session_info; struct gensec_security *gensec_server_context; const struct gensec_security_ops **backends; struct gensec_settings *gensec_settings; size_t idx = 0; struct auth4_context *auth_context; struct loadparm_context *lp_ctx; struct PAC_DATA_CTR *pac_data_ctr = NULL; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); ZERO_STRUCT(tkt); ZERO_STRUCT(ap_rep); ZERO_STRUCT(sesskey1); if (!name || !pass) { return NT_STATUS_INVALID_PARAMETER; } if (cache_name) { cc = cache_name; } if (!strchr_m(name, '@')) { auth_princ = talloc_asprintf(mem_ctx, "%s@%s", name, lp_realm()); } else { auth_princ = name; } NT_STATUS_HAVE_NO_MEMORY(auth_princ); ret = kerberos_kinit_password_ext(auth_princ, pass, time_offset, expire_time, renew_till_time, cc, request_pac, add_netbios_addr, renewable_time, &status); if (ret) { DEBUG(1,("kinit failed for '%s' with: %s (%d)\n", auth_princ, error_message(ret), ret)); /* status already set */ goto out; } DEBUG(10,("got TGT for %s in %s\n", auth_princ, cc)); if (expire_time) { DEBUGADD(10,("\tvalid until: %s (%d)\n", http_timestring(talloc_tos(), *expire_time), (int)*expire_time)); } if (renew_till_time) { DEBUGADD(10,("\trenewable till: %s (%d)\n", http_timestring(talloc_tos(), *renew_till_time), (int)*renew_till_time)); } /* we cannot continue with krb5 when UF_DONT_REQUIRE_PREAUTH is set, * in that case fallback to NTLM - gd */ if (expire_time && renew_till_time && (*expire_time == 0) && (*renew_till_time == 0)) { return NT_STATUS_INVALID_LOGON_TYPE; } ret = cli_krb5_get_ticket(mem_ctx, local_service, time_offset, &tkt, &sesskey1, 0, cc, NULL, impersonate_princ_s); if (ret) { DEBUG(1,("failed to get ticket for %s: %s\n", local_service, error_message(ret))); if (impersonate_princ_s) { DEBUGADD(1,("tried S4U2SELF impersonation as: %s\n", impersonate_princ_s)); } status = krb5_to_nt_status(ret); goto out; } /* wrap that up in a nice GSS-API wrapping */ tkt_wrapped = spnego_gen_krb5_wrap(tmp_ctx, tkt, TOK_ID_KRB_AP_REQ); if (tkt_wrapped.data == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } auth_context = talloc_zero(tmp_ctx, struct auth4_context); if (auth_context == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } auth_context->generate_session_info_pac = kerberos_fetch_pac; lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { status = NT_STATUS_INVALID_SERVER_STATE; DEBUG(10, ("loadparm_init_s3 failed\n")); goto out; } gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx); if (lp_ctx == NULL) { status = NT_STATUS_NO_MEMORY; DEBUG(10, ("lpcfg_gensec_settings failed\n")); goto out; } backends = talloc_zero_array(gensec_settings, const struct gensec_security_ops *, 2); if (backends == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } gensec_settings->backends = backends; gensec_init(); backends[idx++] = &gensec_gse_krb5_security_ops; status = gensec_server_start(tmp_ctx, gensec_settings, auth_context, &gensec_server_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, (__location__ "Failed to start server-side GENSEC to validate a Kerberos ticket: %s\n", nt_errstr(status))); goto out; } talloc_unlink(tmp_ctx, lp_ctx); talloc_unlink(tmp_ctx, gensec_settings); talloc_unlink(tmp_ctx, auth_context); status = gensec_start_mech_by_oid(gensec_server_context, GENSEC_OID_KERBEROS5); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, (__location__ "Failed to start server-side GENSEC krb5 to validate a Kerberos ticket: %s\n", nt_errstr(status))); goto out; } /* Do a client-server update dance */ status = gensec_update(gensec_server_context, tmp_ctx, tkt_wrapped, &ap_rep); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("gensec_update() failed: %s\n", nt_errstr(status))); goto out; } /* Now return the PAC information to the callers. We ingore * the session_info and instead pick out the PAC via the * private_data on the auth_context */ status = gensec_session_info(gensec_server_context, tmp_ctx, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Unable to obtain PAC via gensec_session_info\n")); goto out; } pac_data_ctr = talloc_get_type_abort(gensec_server_context->auth_context->private_data, struct PAC_DATA_CTR); if (pac_data_ctr == NULL) { DEBUG(1,("no PAC\n")); status = NT_STATUS_INVALID_PARAMETER; goto out; } *_pac_data_ctr = talloc_move(mem_ctx, &pac_data_ctr); out: talloc_free(tmp_ctx); if (cc != cache_name) { ads_kdestroy(cc); } data_blob_free(&tkt); data_blob_free(&ap_rep); data_blob_free(&sesskey1); return status; }
static NTSTATUS check_samba4_security(const struct auth_context *auth_context, void *my_private_data, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { TALLOC_CTX *frame = talloc_stackframe(); struct netr_SamInfo3 *info3 = NULL; NTSTATUS nt_status; struct auth_user_info_dc *user_info_dc; struct auth4_context *auth4_context; struct loadparm_context *lp_ctx; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); talloc_free(frame); return NT_STATUS_INVALID_SERVER_STATE; } /* We create a private tevent context here to avoid nested loops in * the s3 one, as that may not be expected */ nt_status = auth_context_create(mem_ctx, s4_event_context_init(frame), NULL, lp_ctx, &auth4_context); NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = auth_context_set_challenge(auth4_context, auth_context->challenge.data, "auth_samba4"); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(auth4_context); return nt_status; } nt_status = auth_check_password(auth4_context, auth4_context, user_info, &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(auth4_context); return nt_status; } nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, user_info_dc, &info3); if (NT_STATUS_IS_OK(nt_status)) { /* We need the strings from the server_info to be valid as long as the info3 is around */ talloc_steal(info3, user_info_dc); } talloc_free(auth4_context); if (!NT_STATUS_IS_OK(nt_status)) { goto done; } nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name, user_info->mapped.domain_name, server_info, info3); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("make_server_info_info3 failed: %s\n", nt_errstr(nt_status))); TALLOC_FREE(frame); return nt_status; } nt_status = NT_STATUS_OK; done: TALLOC_FREE(frame); return nt_status; }