static int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt) { int retval; bool winbind_env; DEBUG(10,("sys_getgrouplist: user [%s]\n", user)); /* This is only ever called for Unix users, remote memberships are * always determined by the info3 coming back from auth3 or the * PAC. */ winbind_env = winbind_env_set(); (void)winbind_off(); #ifdef HAVE_GETGROUPLIST retval = getgrouplist(user, gid, groups, grpcnt); #else #ifdef HAVE_GETGRSET retval = getgrouplist_getgrset(user, gid, groups, grpcnt); #else become_root(); retval = getgrouplist_internals(user, gid, groups, grpcnt); unbecome_root(); #endif /* HAVE_GETGRSET */ #endif /* HAVE_GETGROUPLIST */ /* allow winbindd lookups, but only if they were not already disabled */ if (!winbind_env) { (void)winbind_on(); } return retval; }
int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt) { char *p; int retval; DEBUG(10,("sys_getgrouplist: user [%s]\n", user)); /* see if we should disable winbindd lookups for local users */ if ( (p = strchr(user, *lp_winbind_separator())) == NULL ) { if ( !winbind_off() ) DEBUG(0,("sys_getgroup_list: Insufficient environment space for %s\n", WINBINDD_DONT_ENV)); else DEBUG(10,("sys_getgrouplist(): disabled winbindd for group lookup [user == %s]\n", user)); } #ifdef HAVE_GETGROUPLIST retval = getgrouplist(user, gid, groups, grpcnt); #else become_root(); retval = getgrouplist_internals(user, gid, groups, grpcnt); unbecome_root(); #endif /* allow winbindd lookups */ winbind_on(); return retval; }
NTSTATUS make_server_info_sam(struct auth_serversupplied_info **server_info, struct samu *sampass) { struct passwd *pwd; struct auth_serversupplied_info *result; const char *username = pdb_get_username(sampass); NTSTATUS status; if ( !(result = make_server_info(NULL)) ) { return NT_STATUS_NO_MEMORY; } if ( !(pwd = Get_Pwnam_alloc(result, username)) ) { DEBUG(1, ("User %s in passdb, but getpwnam() fails!\n", pdb_get_username(sampass))); TALLOC_FREE(result); return NT_STATUS_NO_SUCH_USER; } status = samu_to_SamInfo3(result, sampass, lp_netbios_name(), &result->info3, &result->extra); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(result); return status; } result->unix_name = pwd->pw_name; /* Ensure that we keep pwd->pw_name, because we will free pwd below */ talloc_steal(result, pwd->pw_name); result->utok.gid = pwd->pw_gid; result->utok.uid = pwd->pw_uid; TALLOC_FREE(pwd); if (IS_DC && is_our_machine_account(username)) { /* * This is a hack of monstrous proportions. * If we know it's winbindd talking to us, * we know we must never recurse into it, * so turn off contacting winbindd for this * entire process. This will get fixed when * winbindd doesn't need to talk to smbd on * a PDC. JRA. */ (void)winbind_off(); DEBUG(10, ("make_server_info_sam: our machine account %s " "turning off winbindd requests.\n", username)); } DEBUG(5,("make_server_info_sam: made server info for user %s -> %s\n", pdb_get_username(sampass), result->unix_name)); *server_info = result; return NT_STATUS_OK; }
/* startup a copy of smbd as a child daemon */ static void s3fs_task_init(struct task_server *task) { struct tevent_req *subreq; const char *smbd_path; const char *smbd_cmd[2] = { NULL, NULL }; task_server_set_title(task, "task[s3fs_parent]"); smbd_path = talloc_asprintf(task, "%s/smbd", dyn_SBINDIR); smbd_cmd[0] = smbd_path; /* the child should be able to call through nss_winbind */ (void)winbind_on(); /* start it as a child process */ subreq = samba_runcmd_send(task, task->event_ctx, timeval_zero(), 1, 0, smbd_cmd, "--option=server role check:inhibit=yes", "--foreground", debug_get_output_is_stdout()?"--log-stdout":NULL, NULL); /* the parent should not be able to call through nss_winbind */ if (!winbind_off()) { DEBUG(0,("Failed to re-disable recursive winbindd calls after forking smbd\n")); task_server_terminate(task, "Failed to re-disable recursive winbindd calls", true); return; } if (subreq == NULL) { DEBUG(0, ("Failed to start smbd as child daemon\n")); task_server_terminate(task, "Failed to startup s3fs smb task", true); return; } tevent_req_set_callback(subreq, file_server_smbd_done, task); DEBUG(5,("Started file server child smbd\n")); }
static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) { int i; /* initialize the status to avoid suprise */ for (i = 0; ids[i]; i++) { ids[i]->status = ID_UNKNOWN; } for (i = 0; ids[i]; i++) { struct passwd *pw; struct group *gr; const char *name; enum lsa_SidType type; bool ret; switch (ids[i]->xid.type) { case ID_TYPE_UID: pw = getpwuid((uid_t)ids[i]->xid.id); if (!pw) { ids[i]->status = ID_UNMAPPED; continue; } name = pw->pw_name; break; case ID_TYPE_GID: gr = getgrgid((gid_t)ids[i]->xid.id); if (!gr) { ids[i]->status = ID_UNMAPPED; continue; } name = gr->gr_name; break; default: /* ?? */ ids[i]->status = ID_UNKNOWN; continue; } /* by default calls to winbindd are disabled the following call will not recurse so this is safe */ (void)winbind_on(); /* Lookup name from PDC using lsa_lookup_names() */ ret = winbind_lookup_name(dom->name, name, ids[i]->sid, &type); (void)winbind_off(); if (!ret) { /* TODO: how do we know if the name is really not mapped, * or something just failed ? */ ids[i]->status = ID_UNMAPPED; continue; } switch (type) { case SID_NAME_USER: if (ids[i]->xid.type == ID_TYPE_UID) { ids[i]->status = ID_MAPPED; } break; case SID_NAME_DOM_GRP: case SID_NAME_ALIAS: case SID_NAME_WKN_GRP: if (ids[i]->xid.type == ID_TYPE_GID) { ids[i]->status = ID_MAPPED; } break; default: ids[i]->status = ID_UNKNOWN; break; } } return NT_STATUS_OK; }
static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids) { int i; /* initialize the status to avoid suprise */ for (i = 0; ids[i]; i++) { ids[i]->status = ID_UNKNOWN; } for (i = 0; ids[i]; i++) { struct group *gr; enum lsa_SidType type; char *name = NULL; bool ret; /* by default calls to winbindd are disabled the following call will not recurse so this is safe */ (void)winbind_on(); ret = winbind_lookup_sid(talloc_tos(), ids[i]->sid, NULL, (const char **)&name, &type); (void)winbind_off(); if (!ret) { /* TODO: how do we know if the name is really not mapped, * or something just failed ? */ ids[i]->status = ID_UNMAPPED; continue; } switch (type) { case SID_NAME_USER: { struct passwd *pw; /* this will find also all lower case name and use username level */ pw = Get_Pwnam_alloc(talloc_tos(), name); if (pw) { ids[i]->xid.id = pw->pw_uid; ids[i]->xid.type = ID_TYPE_UID; ids[i]->status = ID_MAPPED; } TALLOC_FREE(pw); break; } case SID_NAME_DOM_GRP: case SID_NAME_ALIAS: case SID_NAME_WKN_GRP: gr = getgrnam(name); if (gr) { ids[i]->xid.id = gr->gr_gid; ids[i]->xid.type = ID_TYPE_GID; ids[i]->status = ID_MAPPED; } break; default: ids[i]->status = ID_UNKNOWN; break; } TALLOC_FREE(name); } return NT_STATUS_OK; }
static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) { TALLOC_CTX *ctx; int i; if (! dom->initialized) { return NT_STATUS_UNSUCCESSFUL; } ctx = talloc_new(dom); if ( ! ctx) { DEBUG(0, ("Out of memory!\n")); return NT_STATUS_NO_MEMORY; } for (i = 0; ids[i]; i++) { struct passwd *pw; struct group *gr; const char *name; enum lsa_SidType type; BOOL ret; switch (ids[i]->xid.type) { case ID_TYPE_UID: pw = getpwuid((uid_t)ids[i]->xid.id); if (!pw) { ids[i]->status = ID_UNMAPPED; continue; } name = pw->pw_name; break; case ID_TYPE_GID: gr = getgrgid((gid_t)ids[i]->xid.id); if (!gr) { ids[i]->status = ID_UNMAPPED; continue; } name = gr->gr_name; break; default: /* ?? */ ids[i]->status = ID_UNKNOWN; continue; } /* by default calls to winbindd are disabled the following call will not recurse so this is safe */ winbind_on(); /* Lookup name from PDC using lsa_lookup_names() */ ret = winbind_lookup_name(dom->name, name, ids[i]->sid, &type); winbind_off(); if (!ret) { /* TODO: how do we know if the name is really not mapped, * or something just failed ? */ ids[i]->status = ID_UNMAPPED; continue; } switch (type) { case SID_NAME_USER: if (ids[i]->xid.type == ID_TYPE_UID) { ids[i]->status = ID_MAPPED; } break; case SID_NAME_DOM_GRP: case SID_NAME_ALIAS: case SID_NAME_WKN_GRP: if (ids[i]->xid.type == ID_TYPE_GID) { ids[i]->status = ID_MAPPED; } break; default: ids[i]->status = ID_UNKNOWN; break; } } talloc_free(ctx); return NT_STATUS_OK; }
static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids) { TALLOC_CTX *ctx; int i; if (! dom->initialized) { return NT_STATUS_UNSUCCESSFUL; } ctx = talloc_new(dom); if ( ! ctx) { DEBUG(0, ("Out of memory!\n")); return NT_STATUS_NO_MEMORY; } for (i = 0; ids[i]; i++) { struct passwd *pw; struct group *gr; enum lsa_SidType type; const char *dom_name = NULL; const char *name = NULL; BOOL ret; /* by default calls to winbindd are disabled the following call will not recurse so this is safe */ winbind_on(); ret = winbind_lookup_sid(ctx, ids[i]->sid, &dom_name, &name, &type); winbind_off(); if (!ret) { /* TODO: how do we know if the name is really not mapped, * or something just failed ? */ ids[i]->status = ID_UNMAPPED; continue; } switch (type) { case SID_NAME_USER: /* this will find also all lower case name and use username level */ pw = Get_Pwnam(name); if (pw) { ids[i]->xid.id = pw->pw_uid; ids[i]->xid.type = ID_TYPE_UID; ids[i]->status = ID_MAPPED; } break; case SID_NAME_DOM_GRP: case SID_NAME_ALIAS: case SID_NAME_WKN_GRP: gr = getgrnam(name); if (gr) { ids[i]->xid.id = gr->gr_gid; ids[i]->xid.type = ID_TYPE_GID; ids[i]->status = ID_MAPPED; } break; default: ids[i]->status = ID_UNKNOWN; break; } } talloc_free(ctx); return NT_STATUS_OK; }
/* 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); talloc_enable_null_tracking(); 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-2016\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); 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; }