static int seed_interactive_input(TALLOC_CTX *mem_ctx, struct user_ctx *uctx, struct user_ctx **_uctx) { struct user_ctx *input_uctx = NULL; int ret = EOK; input_uctx = talloc_zero(NULL, struct user_ctx); if (input_uctx == NULL) { ret = ENOMEM; goto done; } if (uctx->name == NULL) { ret = seed_str_input(input_uctx, _("username"), &input_uctx->name); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Username interactive input failed.\n")); goto done; } } else { input_uctx->name = talloc_strdup(input_uctx, uctx->name); if (input_uctx->name == NULL) { ret = ENOMEM; goto done; } } if (uctx->uid == 0) { ret = seed_id_input(_("UID"), &input_uctx->uid); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("UID interactive input failed.\n")); goto done; } } else { input_uctx->uid = uctx->uid; } if (uctx->gid == 0) { ret = seed_id_input(_("GID"), &input_uctx->gid); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("GID interactive input failed.\n")); goto done; } } else { input_uctx->gid = uctx->gid; } if (uctx->gecos == NULL) { ret = seed_str_input(input_uctx, _("user comment (gecos)"), &input_uctx->gecos); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Gecos interactive input failed.\n")); goto done; } } else { input_uctx->gecos = talloc_strdup(input_uctx, uctx->gecos); if (input_uctx->gecos == NULL) { ret = ENOMEM; goto done; } } if (uctx->home == NULL) { ret = seed_str_input(input_uctx, _("home directory"), &input_uctx->home); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Home directory interactive input fialed.\n")); goto done; } } else { input_uctx->home = talloc_strdup(input_uctx, uctx->home); if (input_uctx->home == NULL) { ret = ENOMEM; goto done; } } if (uctx->shell == NULL) { ret = seed_str_input(input_uctx, _("user login shell"), &input_uctx->shell); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Shell interactive input failed\n")); goto done; } } else { input_uctx->shell = talloc_strdup(input_uctx, uctx->shell); if (input_uctx->shell == NULL) { ret = ENOMEM; goto done; } } done: if (ret == EOK) { *_uctx = talloc_steal(mem_ctx, input_uctx); } else { ERROR("Interactive input failed.\n"); talloc_zfree(input_uctx); } return ret; }
static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx) { TALLOC_CTX *tmp_ctx = NULL; struct sss_domain_info *dom = dctx->domain; struct sudo_cmd_ctx *cmd_ctx = dctx->cmd_ctx; struct cli_ctx *cli_ctx = dctx->cmd_ctx->cli_ctx; struct ldb_result *user; time_t cache_expire = 0; struct tevent_req *dpreq; struct dp_callback_ctx *cb_ctx; const char *original_name = NULL; char *name = NULL; uid_t uid = 0; errno_t ret; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); return ENOMEM; } while (dom) { /* if it is a domainless search, skip domains that require fully * qualified names instead */ while (dom && cmd_ctx->check_next && dom->fqnames) { dom = get_next_domain(dom, false); } if (!dom) break; /* make sure to update the dctx if we changed domain */ dctx->domain = dom; talloc_free(name); name = sss_get_cased_name(tmp_ctx, cmd_ctx->username, dom->case_sensitive); if (name == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n")); ret = ENOMEM; goto done; } DEBUG(SSSDBG_FUNC_DATA, ("Requesting info about [%s@%s]\n", name, dom->name)); ret = sysdb_getpwnam(dctx, dctx->domain->sysdb, dctx->domain, name, &user); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to make request to our cache!\n")); ret = EIO; goto done; } if (user->count > 1) { DEBUG(SSSDBG_CRIT_FAILURE, ("getpwnam call returned more than one result !?!\n")); ret = EIO; goto done; } if (user->count == 0 && !dctx->check_provider) { /* if a multidomain search, try with next */ if (cmd_ctx->check_next) { dctx->check_provider = true; dom = get_next_domain(dom, false); if (dom) continue; } DEBUG(SSSDBG_MINOR_FAILURE, ("No results for getpwnam call\n")); ret = ENOENT; goto done; } /* One result found, check cache expiry */ if (user->count == 1) { cache_expire = ldb_msg_find_attr_as_uint64(user->msgs[0], SYSDB_CACHE_EXPIRE, 0); } /* If cache miss and we haven't checked DP yet OR the entry is * outdated, go to DP */ if ((user->count == 0 || cache_expire < time(NULL)) && dctx->check_provider) { dpreq = sss_dp_get_account_send(cli_ctx, cli_ctx->rctx, dom, false, SSS_DP_INITGROUPS, cmd_ctx->username, 0, NULL); if (!dpreq) { DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory sending data provider request\n")); ret = ENOMEM; goto done; } cb_ctx = talloc_zero(cli_ctx, struct dp_callback_ctx); if(!cb_ctx) { talloc_zfree(dpreq); ret = ENOMEM; goto done; } cb_ctx->callback = sudosrv_check_user_dp_callback; cb_ctx->ptr = dctx; cb_ctx->cctx = cli_ctx; cb_ctx->mem_ctx = cli_ctx; tevent_req_set_callback(dpreq, sudosrv_dp_send_acct_req_done, cb_ctx); /* tell caller we are in an async call */ ret = EAGAIN; goto done; } /* check uid */ uid = ldb_msg_find_attr_as_int(user->msgs[0], SYSDB_UIDNUM, 0); if (uid != cmd_ctx->uid) { /* if a multidomain search, try with next */ if (cmd_ctx->check_next) { dctx->check_provider = true; dom = get_next_domain(dom, false); if (dom) continue; } DEBUG(SSSDBG_MINOR_FAILURE, ("UID does not match\n")); ret = ENOENT; goto done; } /* user is stored in cache, remember cased and original name */ original_name = ldb_msg_find_attr_as_string(user->msgs[0], SYSDB_NAME, NULL); if (original_name == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("A user with no name?\n")); ret = EFAULT; goto done; } cmd_ctx->cased_username = talloc_move(cmd_ctx, &name); cmd_ctx->orig_username = talloc_strdup(cmd_ctx, original_name); if (cmd_ctx->orig_username == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n")); ret = ENOMEM; goto done; } /* and set domain */ cmd_ctx->domain = dom; DEBUG(SSSDBG_TRACE_FUNC, ("Returning info for user [%s@%s]\n", cmd_ctx->username, dctx->domain->name)); ret = EOK; goto done; }
errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, struct confdb_ctx *cdb, struct resp_ctx *rctx) { errno_t ret; bool filter_set = false; char **filter_list = NULL; char *name = NULL; struct sss_domain_info *dom = NULL; struct sss_domain_info *domain_list = rctx->domains; char *domainname = NULL; char *conf_path = NULL; TALLOC_CTX *tmpctx = talloc_new(NULL); int i; /* Populate domain-specific negative cache entries */ for (dom = domain_list; dom; dom = get_next_domain(dom, 0)) { conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, dom->name); if (!conf_path) { ret = ENOMEM; goto done; } talloc_zfree(filter_list); ret = confdb_get_string_as_list(cdb, tmpctx, conf_path, CONFDB_NSS_FILTER_USERS, &filter_list); if (ret == ENOENT) continue; if (ret != EOK) goto done; filter_set = true; for (i = 0; (filter_list && filter_list[i]); i++) { ret = sss_parse_name_for_domains(tmpctx, domain_list, rctx->default_domain, filter_list[i], &domainname, &name); if (ret == EAGAIN) { DEBUG(SSSDBG_MINOR_FAILURE, "cannot add [%s] to negcache because the required or " "default domain are not known yet\n", filter_list[i]); } else if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Invalid name in filterUsers list: [%s] (%d)\n", filter_list[i], ret); continue; } if (domainname && strcmp(domainname, dom->name)) { DEBUG(SSSDBG_CRIT_FAILURE, "Mismatch between domain name (%s) and name " "set in FQN (%s), skipping user %s\n", dom->name, domainname, name); continue; } ret = sss_ncache_set_user(ncache, true, dom, name); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to store permanent user filter for [%s]" " (%d [%s])\n", filter_list[i], ret, strerror(ret)); continue; } } } ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, CONFDB_NSS_FILTER_USERS, &filter_list); if (ret == ENOENT) { if (!filter_set) { filter_list = talloc_array(tmpctx, char *, 2); if (!filter_list) { ret = ENOMEM; goto done; } filter_list[0] = talloc_strdup(tmpctx, "root"); if (!filter_list[0]) { ret = ENOMEM; goto done; } filter_list[1] = NULL; } }
/* * Functions to convert sysdb_attrs to the hbac_rule format */ static errno_t hbac_host_attrs_to_rule(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *rule_name, struct sysdb_attrs *rule_attrs, const char *category_attr, const char *member_attr, size_t *host_count, struct hbac_rule_element **hosts) { errno_t ret; TALLOC_CTX *tmp_ctx; struct hbac_rule_element *new_hosts; const char *attrs[] = { SYSDB_FQDN, SYSDB_NAME, NULL }; struct ldb_message_element *el; size_t num_hosts = 0; size_t num_hostgroups = 0; size_t i; char *member_dn; char *filter; size_t count; struct ldb_message **msgs; const char *name; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) return ENOMEM; new_hosts = talloc_zero(tmp_ctx, struct hbac_rule_element); if (new_hosts == NULL) { ret = ENOMEM; goto done; } /* First check for host category */ ret = hbac_get_category(rule_attrs, category_attr, &new_hosts->category); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify host categories\n"); goto done; } if (new_hosts->category & HBAC_CATEGORY_ALL) { /* Short-cut to the exit */ ret = EOK; goto done; } /* Get the list of DNs from the member_attr */ ret = sysdb_attrs_get_el(rule_attrs, member_attr, &el); if (ret != EOK && ret != ENOENT) { DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n"); goto done; } if (ret == ENOENT || el->num_values == 0) { el->num_values = 0; DEBUG(SSSDBG_CONF_SETTINGS, "No host specified, rule will never apply.\n"); } /* Assume maximum size; We'll trim it later */ new_hosts->names = talloc_array(new_hosts, const char *, el->num_values +1); if (new_hosts->names == NULL) { ret = ENOMEM; goto done; } new_hosts->groups = talloc_array(new_hosts, const char *, el->num_values + 1); if (new_hosts->groups == NULL) { ret = ENOMEM; goto done; } for (i = 0; i < el->num_values; i++) { ret = sss_filter_sanitize(tmp_ctx, (const char *)el->values[i].data, &member_dn); if (ret != EOK) goto done; filter = talloc_asprintf(member_dn, "(%s=%s)", SYSDB_ORIG_DN, member_dn); if (filter == NULL) { ret = ENOMEM; goto done; } /* First check if this is a specific host */ ret = sysdb_search_custom(tmp_ctx, domain, filter, HBAC_HOSTS_SUBDIR, attrs, &count, &msgs); if (ret != EOK && ret != ENOENT) goto done; if (ret == EOK && count == 0) { ret = ENOENT; } if (ret == EOK) { if (count > 1) { DEBUG(SSSDBG_CRIT_FAILURE, "Original DN matched multiple hosts. Skipping \n"); talloc_zfree(member_dn); continue; } /* Original DN matched a single host. Get the hostname */ name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_FQDN, NULL); if (name == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "FQDN is missing!\n"); ret = EFAULT; goto done; } new_hosts->names[num_hosts] = talloc_strdup(new_hosts->names, name); if (new_hosts->names[num_hosts] == NULL) { ret = ENOMEM; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "Added host [%s] to rule [%s]\n", name, rule_name); num_hosts++; } else { /* ret == ENOENT */ /* Check if this is a hostgroup */ ret = sysdb_search_custom(tmp_ctx, domain, filter, HBAC_HOSTGROUPS_SUBDIR, attrs, &count, &msgs); if (ret != EOK && ret != ENOENT) goto done; if (ret == EOK && count == 0) { ret = ENOENT; } if (ret == EOK) { if (count > 1) { DEBUG(SSSDBG_CRIT_FAILURE, "Original DN matched multiple hostgroups. " "Skipping\n"); talloc_zfree(member_dn); continue; } /* Original DN matched a single group. Get the groupname */ name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL); if (name == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Hostgroup name is missing!\n"); ret = EFAULT; goto done; } new_hosts->groups[num_hostgroups] = talloc_strdup(new_hosts->groups, name); if (new_hosts->groups[num_hostgroups] == NULL) { ret = ENOMEM; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "Added hostgroup [%s] to rule [%s]\n", name, rule_name); num_hostgroups++; } else { /* ret == ENOENT */ /* Neither a host nor a hostgroup? Skip it */ DEBUG(SSSDBG_TRACE_LIBS, "[%s] does not map to either a host or hostgroup. " "Skipping\n", member_dn); } } talloc_zfree(member_dn); } new_hosts->names[num_hosts] = NULL; new_hosts->groups[num_hostgroups] = NULL; /* Shrink the arrays down to their real sizes */ new_hosts->names = talloc_realloc(new_hosts, new_hosts->names, const char *, num_hosts + 1); if (new_hosts->names == NULL) { ret = ENOMEM; goto done; } new_hosts->groups = talloc_realloc(new_hosts, new_hosts->groups, const char *, num_hostgroups + 1); if (new_hosts->groups == NULL) { ret = ENOMEM; goto done; } ret = EOK; done: if (ret == EOK) { *hosts = talloc_steal(mem_ctx, new_hosts); if (host_count) *host_count = num_hosts; } talloc_free(tmp_ctx); return ret; }
int sdap_save_users(TALLOC_CTX *memctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom, struct sdap_options *opts, struct sysdb_attrs **users, int num_users, char **_usn_value) { TALLOC_CTX *tmpctx; char *higher_usn = NULL; char *usn_value; int ret; errno_t sret; int i; time_t now; bool in_transaction = false; if (num_users == 0) { /* Nothing to do if there are no users */ return EOK; } tmpctx = talloc_new(memctx); if (!tmpctx) { return ENOMEM; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; now = time(NULL); for (i = 0; i < num_users; i++) { usn_value = NULL; ret = sdap_save_user(tmpctx, sysdb, opts, dom, users[i], false, &usn_value, now); /* Do not fail completely on errors. * Just report the failure to save and go on */ if (ret) { DEBUG(2, ("Failed to store user %d. Ignoring.\n", i)); } else { DEBUG(9, ("User %d processed!\n", i)); } if (usn_value) { if (higher_usn) { if ((strlen(usn_value) > strlen(higher_usn)) || (strcmp(usn_value, higher_usn) > 0)) { talloc_zfree(higher_usn); higher_usn = usn_value; } else { talloc_zfree(usn_value); } } else { higher_usn = usn_value; } } } ret = sysdb_transaction_commit(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction!\n")); goto done; } in_transaction = false; if (_usn_value) { *_usn_value = talloc_steal(memctx, higher_usn); } done: if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n")); } } talloc_zfree(tmpctx); return ret; }
static void nested_groups_test_one_group_unique_group_members(void **state) { struct nested_groups_test_ctx *test_ctx = NULL; struct sysdb_attrs *rootgroup = NULL; struct tevent_req *req = NULL; TALLOC_CTX *req_mem_ctx = NULL; errno_t ret; const char *groups[] = { "cn=emptygroup1,"GROUP_BASE_DN, "cn=emptygroup2,"GROUP_BASE_DN, NULL }; const struct sysdb_attrs *group1_reply[2] = { NULL }; const struct sysdb_attrs *group2_reply[2] = { NULL }; const char * expected[] = { "rootgroup", "emptygroup1", "emptygroup2" }; test_ctx = talloc_get_type_abort(*state, struct nested_groups_test_ctx); /* mock return values */ rootgroup = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, 1000, "rootgroup", groups); group1_reply[0] = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, 1001, "emptygroup1", NULL); assert_non_null(group1_reply[0]); will_return(sdap_get_generic_recv, 1); will_return(sdap_get_generic_recv, group1_reply); group2_reply[0] = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, 1002, "emptygroup2", NULL); assert_non_null(group2_reply[0]); will_return(sdap_get_generic_recv, 1); will_return(sdap_get_generic_recv, group2_reply); sss_will_return_always(sdap_has_deref_support, false); /* run test, check for memory leaks */ req_mem_ctx = talloc_new(global_talloc_context); assert_non_null(req_mem_ctx); check_leaks_push(req_mem_ctx); req = sdap_nested_group_send(req_mem_ctx, test_ctx->tctx->ev, test_ctx->sdap_domain, test_ctx->sdap_opts, test_ctx->sdap_handle, rootgroup); assert_non_null(req); tevent_req_set_callback(req, nested_groups_test_done, test_ctx); ret = test_ev_loop(test_ctx->tctx); assert_true(check_leaks_pop(req_mem_ctx) == true); talloc_zfree(req_mem_ctx); /* check return code */ assert_int_equal(ret, ERR_OK); /* Check the users */ assert_int_equal(test_ctx->num_users, 0); assert_int_equal(test_ctx->num_groups, N_ELEMENTS(expected)); compare_sysdb_string_array_noorder(test_ctx->groups, expected, N_ELEMENTS(expected)); }
int sssm_ipa_id_init(struct be_ctx *bectx, struct bet_ops **ops, void **pvt_data) { struct ipa_id_ctx *ipa_ctx; struct sdap_id_ctx *sdap_ctx; const char *hostname; const char *ipa_domain; const char *ipa_servers; struct ipa_srv_plugin_ctx *srv_ctx; bool server_mode; int ret; if (!ipa_options) { ret = common_ipa_init(bectx); if (ret != EOK) { return ret; } } if (ipa_options->id_ctx) { /* already initialized */ *ops = &ipa_id_ops; *pvt_data = ipa_options->id_ctx; return EOK; } ipa_ctx = talloc_zero(ipa_options, struct ipa_id_ctx); if (!ipa_ctx) { return ENOMEM; } ipa_options->id_ctx = ipa_ctx; ipa_ctx->ipa_options = ipa_options; sdap_ctx = sdap_id_ctx_new(ipa_options, bectx, ipa_options->service->sdap); if (sdap_ctx == NULL) { return ENOMEM; } ipa_ctx->sdap_id_ctx = sdap_ctx; ret = ipa_get_id_options(ipa_options, bectx->cdb, bectx->conf_path, &sdap_ctx->opts); if (ret != EOK) { goto done; } ret = ipa_get_dyndns_options(bectx, ipa_options); if (ret != EOK) { goto done; } if (dp_opt_get_bool(ipa_options->dyndns_ctx->opts, DP_OPT_DYNDNS_UPDATE)) { /* Perform automatic DNS updates when the * IP address changes. * Register a callback for successful LDAP * reconnections. This is the easiest way to * identify that we have gone online. */ DEBUG(SSSDBG_CONF_SETTINGS, "Dynamic DNS updates are on. Checking for nsupdate..\n"); ret = be_nsupdate_check(); if (ret == EOK) { /* nsupdate is available. Dynamic updates * are supported */ ret = ipa_dyndns_init(sdap_ctx->be, ipa_options); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failure setting up automatic DNS update\n"); /* We will continue without DNS updating */ } } } ret = setup_tls_config(sdap_ctx->opts->basic); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "setup_tls_config failed [%d][%s].\n", ret, strerror(ret)); goto done; } /* Set up the ID mapping object */ ret = ipa_idmap_init(sdap_ctx, sdap_ctx, &sdap_ctx->opts->idmap_ctx); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize ID mapping. In case ID mapping properties " "changed on the server, please remove the SSSD database\n"); goto done; } ret = ldap_id_setup_tasks(sdap_ctx); if (ret != EOK) { goto done; } ret = sdap_setup_child(); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "setup_child failed [%d][%s].\n", ret, strerror(ret)); goto done; } /* setup SRV lookup plugin */ hostname = dp_opt_get_string(ipa_options->basic, IPA_HOSTNAME); server_mode = dp_opt_get_bool(ipa_options->basic, IPA_SERVER_MODE); if (server_mode == true) { ipa_ctx->view_name = talloc_strdup(ipa_ctx, SYSDB_DEFAULT_VIEW_NAME); if (ipa_ctx->view_name == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ret = ENOMEM; goto done; } ret = sysdb_update_view_name(bectx->domain->sysdb, ipa_ctx->view_name); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add/update view name to sysdb.\n"); goto done; } ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER); if (srv_in_server_list(ipa_servers) == true || dp_opt_get_bool(ipa_options->basic, IPA_ENABLE_DNS_SITES) == true) { DEBUG(SSSDBG_MINOR_FAILURE, "SRV resolution or IPA sites enabled " "on the IPA server. Site discovery of trusted AD servers " "might not work\n"); /* If SRV discovery is enabled on the server and * dns_discovery_domain is set explicitly, then * the current failover code would use the dns_discovery * domain to try to find AD servers and fail */ if (dp_opt_get_string(bectx->be_res->opts, DP_RES_OPT_DNS_DOMAIN)) { sss_log(SSS_LOG_ERR, ("SRV discovery is enabled on the IPA " "server while using custom dns_discovery_domain. " "DNS discovery of trusted AD domain will likely fail. " "It is recommended not to use SRV discovery or the " "dns_discovery_domain option for the IPA domain while " "running on the server itself\n")); DEBUG(SSSDBG_CRIT_FAILURE, "SRV discovery is enabled on IPA " "server while using custom dns_discovery_domain. " "DNS discovery of trusted AD domain will likely fail. " "It is recommended not to use SRV discovery or the " "dns_discovery_domain option for the IPA domain while " "running on the server itself\n"); } ret = be_fo_set_dns_srv_lookup_plugin(bectx, hostname); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin " "[%d]: %s\n", ret, strerror(ret)); goto done; } } else { /* In server mode we need to ignore the dns_discovery_domain if set * and only discover servers based on AD domains */ ret = dp_opt_set_string(bectx->be_res->opts, DP_RES_OPT_DNS_DOMAIN, NULL); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not reset the " "dns_discovery_domain, trusted AD domains discovery " "might fail. Please remove dns_discovery_domain " "from the config file and restart the SSSD\n"); } else { DEBUG(SSSDBG_CONF_SETTINGS, "The value of dns_discovery_domain " "will be ignored in ipa_server_mode\n"); } } } else { ret = sysdb_get_view_name(ipa_ctx, bectx->domain->sysdb, &ipa_ctx->view_name); if (ret != EOK) { if (ret == ENOENT) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find view name in the cache. " \ "Will do online lookup later.\n"); } else { DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n"); goto done; } } if (dp_opt_get_bool(ipa_options->basic, IPA_ENABLE_DNS_SITES)) { /* use IPA plugin */ ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN); srv_ctx = ipa_srv_plugin_ctx_init(bectx, bectx->be_res->resolv, hostname, ipa_domain); if (srv_ctx == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n"); ret = ENOMEM; goto done; } be_fo_set_srv_lookup_plugin(bectx, ipa_srv_plugin_send, ipa_srv_plugin_recv, srv_ctx, "IPA"); } else { /* fall back to standard plugin on clients. */ ret = be_fo_set_dns_srv_lookup_plugin(bectx, hostname); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin " "[%d]: %s\n", ret, strerror(ret)); goto done; } } } /* setup periodical refresh of expired records */ ret = sdap_refresh_init(bectx->refresh_ctx, sdap_ctx); if (ret != EOK && ret != EEXIST) { DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh " "will not work [%d]: %s\n", ret, strerror(ret)); } ipa_ctx->sdap_id_ctx->opts->ext_ctx = ipa_create_ext_members_ctx( ipa_ctx->sdap_id_ctx->opts, ipa_ctx); if (ipa_ctx->sdap_id_ctx->opts->ext_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV the extrernal group ctx\n"); ret = ENOMEM; goto done; } *ops = &ipa_id_ops; *pvt_data = ipa_ctx; ret = EOK; done: if (ret != EOK) { talloc_zfree(ipa_options->id_ctx); } return ret; }
int confdb_init_db(const char *config_file, struct confdb_ctx *cdb) { TALLOC_CTX *tmp_ctx; int ret; int sret = EOK; int version; char timestr[21]; char *lasttimestr; bool in_transaction = false; const char *config_ldif; const char *vals[2] = { timestr, NULL }; struct ldb_ldif *ldif; struct sss_ini_initdata *init_data; tmp_ctx = talloc_new(cdb); if (tmp_ctx == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory.\n"); return ENOMEM; } init_data = sss_ini_initdata_init(tmp_ctx); if (!init_data) { DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory.\n"); ret = ENOMEM; goto done; } /* Open config file */ ret = sss_ini_config_file_open(init_data, config_file); if (ret != EOK) { DEBUG(SSSDBG_TRACE_FUNC, "sss_ini_config_file_open failed: %s [%d]\n", strerror(ret), ret); if (ret == ENOENT) { /* sss specific error denoting missing configuration file */ ret = ERR_MISSING_CONF; } goto done; } ret = sss_ini_config_access_check(init_data); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Permission check on config file failed.\n"); ret = EPERM; goto done; } /* Determine if the conf file has changed since we last updated * the confdb */ ret = sss_ini_get_stat(init_data); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Status check on config file failed.\n"); ret = errno; goto done; } errno = 0; ret = sss_ini_get_mtime(init_data, sizeof(timestr), timestr); if (ret <= 0 || ret >= sizeof(timestr)) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to convert time_t to string ??\n"); ret = errno ? errno : EFAULT; } ret = confdb_get_string(cdb, tmp_ctx, "config", "lastUpdate", NULL, &lasttimestr); if (ret == EOK) { /* check if we lastUpdate and last file modification change differ*/ if ((lasttimestr != NULL) && (strcmp(lasttimestr, timestr) == 0)) { /* not changed, get out, nothing more to do */ ret = EOK; goto done; } } else { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get lastUpdate attribute.\n"); goto done; } ret = sss_ini_get_config(init_data, config_file); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load configuration\n"); goto done; } /* Make sure that the config file version matches the confdb version */ ret = sss_ini_get_cfgobj(init_data, "sssd", "config_file_version"); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Internal error determining config_file_version\n"); goto done; } ret = sss_ini_check_config_obj(init_data); if (ret != EOK) { /* No known version. Use default. */ DEBUG(SSSDBG_CONF_SETTINGS, "Value of config_file_version option not found. " "Assumed to be version %d.\n", CONFDB_DEFAULT_CFG_FILE_VER); } else { version = sss_ini_get_int_config_value(init_data, CONFDB_DEFAULT_CFG_FILE_VER, -1, &ret); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Config file version could not be determined\n"); goto done; } else if (version < CONFDB_VERSION_INT) { DEBUG(SSSDBG_FATAL_FAILURE, "Config file is an old version. " "Please run configuration upgrade script.\n"); ret = EINVAL; goto done; } else if (version > CONFDB_VERSION_INT) { DEBUG(SSSDBG_FATAL_FAILURE, "Config file version is newer than confdb\n"); ret = EINVAL; goto done; } } /* Set up a transaction to replace the configuration */ ret = ldb_transaction_start(cdb->ldb); if (ret != LDB_SUCCESS) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to start a transaction for " "updating the configuration\n"); ret = sysdb_error_to_errno(ret); goto done; } in_transaction = true; /* Purge existing database */ ret = confdb_purge(cdb); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Could not purge existing configuration\n"); goto done; } ret = sss_confdb_create_ldif(tmp_ctx, init_data, &config_ldif); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Could not create LDIF for confdb\n"); goto done; } DEBUG(SSSDBG_TRACE_LIBS, "LDIF file to import: \n%s\n", config_ldif); while ((ldif = ldb_ldif_read_string(cdb->ldb, &config_ldif))) { ret = ldb_add(cdb->ldb, ldif->msg); if (ret != LDB_SUCCESS) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize DB (%d,[%s]), aborting!\n", ret, ldb_errstring(cdb->ldb)); ret = EIO; goto done; } ldb_ldif_read_free(cdb->ldb, ldif); } /* now store the lastUpdate time so that we do not re-init if nothing * changed on restart */ ret = confdb_add_param(cdb, true, "config", "lastUpdate", vals); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set last update time on db!\n"); goto done; } ret = ldb_transaction_commit(cdb->ldb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; ret = EOK; done: if (in_transaction) { sret = ldb_transaction_cancel(cdb->ldb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } sss_ini_config_destroy(init_data); sss_ini_close_file(init_data); talloc_zfree(tmp_ctx); return ret; }
/* This is a reversible version of become_user, and returns the saved * credentials so that creds can be switched back calling restore_creds */ errno_t switch_creds(TALLOC_CTX *mem_ctx, uid_t uid, gid_t gid, int num_gids, gid_t *gids, struct sss_creds **saved_creds) { struct sss_creds *ssc = NULL; int size; int ret; DEBUG(SSSDBG_FUNC_DATA, "Switch user to [%d][%d].\n", uid, gid); if (saved_creds) { /* save current user credentials */ size = getgroups(0, NULL); if (size == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n", ret, strerror(ret)); goto done; } ssc = talloc_size(mem_ctx, (sizeof(struct sss_creds) + size * sizeof(gid_t))); if (!ssc) { DEBUG(SSSDBG_CRIT_FAILURE, "Allocation failed!\n"); ret = ENOMEM; goto done; } ssc->num_gids = size; size = getgroups(ssc->num_gids, ssc->gids); if (size == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n", ret, strerror(ret)); /* free ssc immediately otherwise the code will try to restore * wrong creds */ talloc_zfree(ssc); goto done; } /* we care only about effective ids */ ssc->uid = geteuid(); ssc->gid = getegid(); } /* if we are regaining root set euid first so that we have CAP_SETUID back, * ane the other calls work too, otherwise call it last so that we can * change groups before we loose CAP_SETUID */ if (uid == 0) { ret = setresuid(0, 0, 0); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "setresuid failed [%d][%s].\n", ret, strerror(ret)); goto done; } } /* TODO: use prctl to get/set capabilities too ? */ /* try to setgroups first should always work if CAP_SETUID is set, * otherwise it will always fail, failure is not critical though as * generally we only really care about uid and at mot primary gid */ ret = setgroups(num_gids, gids); if (ret == -1) { ret = errno; DEBUG(SSSDBG_TRACE_FUNC, "setgroups failed [%d][%s].\n", ret, strerror(ret)); } /* change gid now, (leaves saved gid to current, so we can restore) */ ret = setresgid(-1, gid, -1); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "setresgid failed [%d][%s].\n", ret, strerror(ret)); goto done; } if (uid != 0) { /* change uid, (leaves saved uid to current, so we can restore) */ ret = setresuid(-1, uid, -1); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "setresuid failed [%d][%s].\n", ret, strerror(ret)); goto done; } } ret = 0; done: if (ret) { if (ssc) { /* attempt to restore creds first */ restore_creds(ssc); talloc_free(ssc); } } else if (saved_creds) { *saved_creds = ssc; } return ret; }
static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, struct group *grp, const char *real_name, const char *alias, uint64_t cache_timeout) { errno_t ret, sret; struct sysdb_attrs *attrs = NULL; char *lower; const char *cased_alias; TALLOC_CTX *tmp_ctx; time_t now = time(NULL); bool in_transaction = false; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } DEBUG_GR_MEM(7, grp); ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; if (grp->gr_mem && grp->gr_mem[0]) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation error ?!\n")); ret = ENOMEM; goto done; } ret = sysdb_attrs_users_from_str_list( attrs, SYSDB_MEMBER, dom->name, (const char *const *)grp->gr_mem); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add group members\n")); goto done; } /* Create ghost users */ ret = proxy_process_missing_users(sysdb, dom, attrs, grp, now); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add missing members\n")); goto done; } } if (dom->case_sensitive == false || alias) { if (!attrs) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation error ?!\n")); ret = ENOMEM; goto done; } } if (dom->case_sensitive == false) { lower = sss_tc_utf8_str_tolower(attrs, grp->gr_name); if (!lower) { DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); ret = ENOMEM; goto done; } } if (alias) { cased_alias = sss_get_cased_name(attrs, alias, dom->case_sensitive); if (!cased_alias) { talloc_zfree(attrs); return ENOMEM; } ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); ret = ENOMEM; goto done; } } } ret = sysdb_store_group(sysdb, dom, real_name, grp->gr_gid, attrs, cache_timeout, now); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add group to cache\n")); goto done; } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Could not commit transaction: [%s]\n", strerror(ret))); goto done; } in_transaction = false; done: if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n")); } } talloc_free(tmp_ctx); return ret; }
static int enum_groups(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct group *grp; enum nss_status status; size_t buflen; char *buffer; char *newbuf; int ret; errno_t sret; bool again; DEBUG(SSSDBG_TRACE_LIBS, ("Enumerating groups\n")); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } grp = talloc(tmpctx, struct group); if (!grp) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; status = ctx->ops.setgrent(); if (status != NSS_STATUS_SUCCESS) { ret = EIO; goto done; } do { again = false; /* always zero out the grp structure */ memset(grp, 0, sizeof(struct group)); /* get entry */ status = ctx->ops.getgrent_r(grp, buffer, buflen, &ret); switch (status) { case NSS_STATUS_TRYAGAIN: /* buffer too small ? */ if (buflen < MAX_BUF_SIZE) { buflen *= 2; } if (buflen > MAX_BUF_SIZE) { buflen = MAX_BUF_SIZE; } newbuf = talloc_realloc_size(tmpctx, buffer, buflen); if (!newbuf) { ret = ENOMEM; goto done; } buffer = newbuf; again = true; break; case NSS_STATUS_NOTFOUND: /* we are done here */ DEBUG(SSSDBG_TRACE_LIBS, ("Enumeration completed.\n")); ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); goto done; } in_transaction = false; break; case NSS_STATUS_SUCCESS: DEBUG(SSSDBG_OP_FAILURE, ("Group found (%s, %d)\n", grp->gr_name, grp->gr_gid)); /* gid=0 is an invalid value */ /* also check that the id is in the valid range for this domain */ if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) { DEBUG(SSSDBG_OP_FAILURE, ("Group [%s] filtered out! (id" "out of range)\n", grp->gr_name)); again = true; break; } ret = save_group(sysdb, dom, grp, grp->gr_name, NULL, dom->group_timeout); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ DEBUG(SSSDBG_OP_FAILURE, ("Failed to store group." "Ignoring\n")); } again = true; break; case NSS_STATUS_UNAVAIL: /* "remote" backend unavailable. Enter offline mode */ ret = ENXIO; break; default: ret = EIO; DEBUG(SSSDBG_OP_FAILURE, ("proxy -> getgrent_r failed (%d)[%s]" "\n", ret, strerror(ret))); break; } } while (again); done: talloc_zfree(tmpctx); if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n")); } } ctx->ops.endgrent(); return ret; }
static int save_user(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, bool lowercase, struct passwd *pwd, const char *real_name, const char *alias, uint64_t cache_timeout) { const char *shell; char *lower; struct sysdb_attrs *attrs = NULL; errno_t ret; const char *cased_alias; if (pwd->pw_shell && pwd->pw_shell[0] != '\0') { shell = pwd->pw_shell; } else { shell = NULL; } if (lowercase || alias) { attrs = sysdb_new_attrs(NULL); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation error ?!\n")); return ENOMEM; } } if (lowercase) { lower = sss_tc_utf8_str_tolower(attrs, pwd->pw_name); if (!lower) { DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); talloc_zfree(attrs); return ENOMEM; } ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); talloc_zfree(attrs); return ret; } } if (alias) { cased_alias = sss_get_cased_name(attrs, alias, !lowercase); if (!cased_alias) { talloc_zfree(attrs); return ENOMEM; } ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); talloc_zfree(attrs); return ret; } } ret = sysdb_store_user(sysdb, domain, real_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir, shell, NULL, attrs, NULL, cache_timeout, 0); talloc_zfree(attrs); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add user to cache\n")); return ret; } return EOK; }
int main(int argc, const char **argv) { struct seed_ctx *sctx = NULL; struct user_ctx *input_uctx = NULL; int ret = EOK; /* initialize seed context and parse options */ ret = seed_init(sctx, argc, argv, &sctx); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE,("Seed init failed [%d][%s]\n", ret, strerror(ret))); goto done; } /* set up confdb,sysdb and domain */ ret = seed_init_db(sctx, sctx->uctx->domain_name, &sctx->confdb, &sctx->domain, &sctx->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to initialize db and domain\n")); goto done; } /* get user info from domain */ ret = seed_domain_user_info(sctx->uctx->name, sctx->uctx->domain_name, sctx->sysdb, sctx->domain, &sctx->user_cached); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Failed lookup of user [%s] in domain [%s]\n", sctx->uctx->name, sctx->uctx->domain_name)); } /* interactive mode to fill in user information */ if (sctx->interact == true) { if (sctx->user_cached == true) { ERROR(_("User entry already exists in the cache.\n")); ret = EEXIST; goto done; } else { ret = seed_interactive_input(sctx, sctx->uctx, &input_uctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to get seed input.\n")); ret = EINVAL; goto done; } talloc_zfree(sctx->uctx); sctx->uctx = input_uctx; } } if (sctx->user_cached == false) { if (sctx->uctx->uid == 0 || sctx->uctx->gid == 0) { /* require username, UID, and GID to continue */ DEBUG(SSSDBG_MINOR_FAILURE, ("Not enough information provided\n")); ERROR("UID and primary GID not provided.\n"); ret = EINVAL; goto done; } } /* password input */ if (sctx->password_method == PASS_FILE) { ret = seed_password_input_file(sctx->uctx, sctx->password_file, &sctx->uctx->password); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Password input failure\n")); goto done; } } else { ret = seed_password_input_prompt(sctx->uctx, &sctx->uctx->password); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Password input failure\n")); goto done; } } /* Add user info and password to sysdb cache */ ret = seed_cache_user(sctx); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to modify cache.\n")); goto done; } else { if (sctx->user_cached == false) { printf(_("User cache entry created for %1$s\n"), sctx->uctx->name); } printf(_("Temporary password added to cache entry for %1$s\n"), sctx->uctx->name); } done: talloc_zfree(sctx); if (ret != EOK) { DEBUG(SSSDBG_TRACE_INTERNAL, ("Exit error: [%d] [%s]\n", ret, strerror(ret))); ret = EXIT_FAILURE; } else { ret = EXIT_SUCCESS; } exit(ret); }
static int seed_domain_user_info(const char *name, const char *domain_name, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, bool *is_cached) { TALLOC_CTX *tmp_ctx = NULL; char *fq_name = NULL; struct passwd *passwd = NULL; struct ldb_result *res = NULL; int ret = EOK; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { ret = ENOMEM; goto done; } fq_name = talloc_asprintf(tmp_ctx, "%s@%s", name, domain_name); if (fq_name == NULL) { ret = ENOMEM; goto done; } errno = 0; passwd = getpwnam(fq_name); if (passwd == NULL) { ret = errno; DEBUG(SSSDBG_MINOR_FAILURE, ("getpwnam failed [%d] [%s]\n", ret, strerror(ret))); goto done; } /* look for user in cache */ ret = sysdb_getpwnam(tmp_ctx, sysdb, domain, name, &res); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Couldn't lookup user (%s) in the cache\n", name)); goto done; } if (res->count == 0) { DEBUG(SSSDBG_TRACE_INTERNAL, ("User (%s) wasn't found in the cache\n", name)); *is_cached = false; ret = ENOENT; goto done; } else if (res->count > 1) { DEBUG(SSSDBG_CRIT_FAILURE, ("Multiple user (%s) entries were found in the cache\n", name)); ret = EINVAL; goto done; } else { DEBUG(SSSDBG_TRACE_INTERNAL, ("User found in cache\n")); *is_cached = true; errno = 0; ret = initgroups(fq_name, passwd->pw_gid); if (ret != EOK) { ret = errno; DEBUG(SSSDBG_MINOR_FAILURE, ("initgroups failed [%d] [%s]\n", ret, strerror(ret))); goto done; } } done: if (ret == ENOMEM) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to allocate user information\n")); } talloc_zfree(tmp_ctx); return ret; }
static void be_ptask_schedule(struct be_ptask *task, enum be_ptask_delay delay_type, enum be_ptask_schedule from) { struct timeval tv; time_t delay = 0; if (!task->enabled) { DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: disabled\n", task->name); return; } switch (delay_type) { case BE_PTASK_FIRST_DELAY: delay = task->first_delay; break; case BE_PTASK_ENABLED_DELAY: delay = task->enabled_delay; break; case BE_PTASK_PERIOD: delay = task->period; if (backoff_allowed(task) && task->period * 2 <= task->max_backoff) { /* double the period for the next execution */ task->period *= 2; } break; } /* add random offset */ if (task->random_offset != 0) { delay = delay + (rand_r(&task->ro_seed) % task->random_offset); } switch (from) { case BE_PTASK_SCHEDULE_FROM_NOW: tv = tevent_timeval_current_ofs(delay, 0); DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds " "from now [%lu]\n", task->name, delay, tv.tv_sec); break; case BE_PTASK_SCHEDULE_FROM_LAST: tv = tevent_timeval_set(task->last_execution + delay, 0); DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds " "from last execution time [%lu]\n", task->name, delay, tv.tv_sec); break; } if (task->timer != NULL) { DEBUG(SSSDBG_MINOR_FAILURE, "Task [%s]: another timer is already " "active?\n", task->name); talloc_zfree(task->timer); } task->timer = tevent_add_timer(task->ev, task, tv, be_ptask_execute, task); if (task->timer == NULL) { /* nothing we can do about it */ DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Unable to schedule task [%s]\n", task->name); be_ptask_disable(task); } task->next_execution = tv.tv_sec; }
static int save_user(struct sss_domain_info *domain, bool lowercase, struct passwd *pwd, const char *real_name, const char *alias, uint64_t cache_timeout) { const char *shell; const char *gecos; struct sysdb_attrs *attrs = NULL; errno_t ret; const char *cased_alias; const char *lc_pw_name = NULL; if (pwd->pw_shell && pwd->pw_shell[0] != '\0') { shell = pwd->pw_shell; } else { shell = NULL; } if (pwd->pw_gecos && pwd->pw_gecos[0] != '\0') { gecos = pwd->pw_gecos; } else { gecos = NULL; } if (lowercase || alias) { attrs = sysdb_new_attrs(NULL); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n"); ret = ENOMEM; goto done; } } if (lowercase) { lc_pw_name = sss_tc_utf8_str_tolower(attrs, pwd->pw_name); if (lc_pw_name == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n"); ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_pw_name); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n"); ret = ENOMEM; goto done; } } if (alias) { cased_alias = sss_get_cased_name(attrs, alias, !lowercase); if (!cased_alias) { ret = ENOMEM; goto done; } /* Add the alias only if it differs from lowercased pw_name */ if (lc_pw_name == NULL || strcmp(cased_alias, lc_pw_name) != 0) { ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n"); goto done; } } } ret = sysdb_store_user(domain, real_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid, gecos, pwd->pw_dir, shell, NULL, attrs, NULL, cache_timeout, 0); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add user to cache\n"); goto done; } done: talloc_zfree(attrs); return ret; }
void be_ptask_destroy(struct be_ptask **task) { talloc_zfree(*task); }
static int get_pw_uid(struct proxy_id_ctx *ctx, struct sss_domain_info *dom, uid_t uid) { TALLOC_CTX *tmpctx; struct passwd *pwd; enum nss_status status; char *buffer; size_t buflen; bool del_user = false; int ret; char *name; DEBUG(SSSDBG_TRACE_FUNC, "Searching user by uid (%"SPRIuid")\n", uid); tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); ret = handle_getpw_result(status, pwd, dom, &del_user); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "getpwuid failed [%d]: %s\n", ret, strerror(ret)); goto done; } if (del_user) { ret = delete_user(dom, NULL, uid); goto done; } name = sss_create_internal_fqname(tmpctx, pwd->pw_name, dom->name); if (name == NULL) { DEBUG(SSSDBG_OP_FAILURE, "failed to qualify name '%s'\n", pwd->pw_name); goto done; } ret = save_user(dom, !dom->case_sensitive, pwd, name, NULL, dom->user_timeout); done: talloc_zfree(tmpctx); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "proxy -> getpwuid_r failed for '%"SPRIuid"' <%d>: %s\n", uid, ret, strerror(ret)); } return ret; }
void nested_groups_test_teardown(void **state) { talloc_zfree(*state); }
static int enum_users(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct passwd *pwd; enum nss_status status; size_t buflen; char *buffer; char *newbuf; int ret; errno_t sret; bool again; char *name; DEBUG(SSSDBG_TRACE_LIBS, "Enumerating users\n"); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; status = ctx->ops.setpwent(); if (status != NSS_STATUS_SUCCESS) { ret = EIO; goto done; } do { again = false; /* always zero out the pwd structure */ memset(pwd, 0, sizeof(struct passwd)); /* get entry */ status = ctx->ops.getpwent_r(pwd, buffer, buflen, &ret); switch (status) { case NSS_STATUS_TRYAGAIN: /* buffer too small ? */ if (buflen < MAX_BUF_SIZE) { buflen *= 2; } if (buflen > MAX_BUF_SIZE) { buflen = MAX_BUF_SIZE; } newbuf = talloc_realloc_size(tmpctx, buffer, buflen); if (!newbuf) { ret = ENOMEM; goto done; } buffer = newbuf; again = true; break; case NSS_STATUS_NOTFOUND: /* we are done here */ DEBUG(SSSDBG_TRACE_LIBS, "Enumeration completed.\n"); ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; break; case NSS_STATUS_SUCCESS: DEBUG(SSSDBG_TRACE_LIBS, "User found (%s, %"SPRIuid", %"SPRIgid")\n", pwd->pw_name, pwd->pw_uid, pwd->pw_gid); /* uid=0 or gid=0 are invalid values */ /* also check that the id is in the valid range for this domain */ if (OUT_OF_ID_RANGE(pwd->pw_uid, dom->id_min, dom->id_max) || OUT_OF_ID_RANGE(pwd->pw_gid, dom->id_min, dom->id_max)) { DEBUG(SSSDBG_OP_FAILURE, "User [%s] filtered out! (id out" " of range)\n", pwd->pw_name); again = true; break; } name = sss_create_internal_fqname(tmpctx, pwd->pw_name, dom->name); if (name == NULL) { DEBUG(SSSDBG_OP_FAILURE, "failed to create internal name '%s'\n", pwd->pw_name); goto done; } ret = save_user(dom, !dom->case_sensitive, pwd, name, NULL, dom->user_timeout); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ DEBUG(SSSDBG_OP_FAILURE, "Failed to store user %s." " Ignoring.\n", pwd->pw_name); } again = true; break; case NSS_STATUS_UNAVAIL: /* "remote" backend unavailable. Enter offline mode */ ret = ENXIO; break; default: ret = EIO; DEBUG(SSSDBG_OP_FAILURE, "proxy -> getpwent_r failed (%d)[%s]" "\n", ret, strerror(ret)); break; } } while (again); done: talloc_zfree(tmpctx); if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } ctx->ops.endpwent(); return ret; }
int sssm_ipa_auth_init(struct be_ctx *bectx, struct bet_ops **ops, void **pvt_data) { struct ipa_auth_ctx *ipa_auth_ctx; struct ipa_id_ctx *id_ctx; struct krb5_ctx *krb5_auth_ctx; struct sdap_auth_ctx *sdap_auth_ctx; struct bet_ops *id_ops; int ret; if (!ipa_options) { ret = common_ipa_init(bectx); if (ret != EOK) { return ret; } } if (ipa_options->auth_ctx) { /* already initialized */ *ops = &ipa_auth_ops; *pvt_data = ipa_options->auth_ctx; return EOK; } ipa_auth_ctx = talloc_zero(ipa_options, struct ipa_auth_ctx); if (!ipa_auth_ctx) { return ENOMEM; } ipa_options->auth_ctx = ipa_auth_ctx; ret = sssm_ipa_id_init(bectx, &id_ops, (void **) &id_ctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n"); goto done; } ipa_auth_ctx->sdap_id_ctx = id_ctx->sdap_id_ctx; ret = dp_copy_options(ipa_auth_ctx, ipa_options->basic, IPA_OPTS_BASIC, &ipa_auth_ctx->ipa_options); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "dp_copy_options failed.\n"); goto done; } krb5_auth_ctx = talloc_zero(ipa_auth_ctx, struct krb5_ctx); if (!krb5_auth_ctx) { ret = ENOMEM; goto done; } krb5_auth_ctx->service = ipa_options->service->krb5_service; if (dp_opt_get_bool(id_ctx->ipa_options->basic, IPA_SERVER_MODE) == true) { krb5_auth_ctx->config_type = K5C_IPA_SERVER; } else { krb5_auth_ctx->config_type = K5C_IPA_CLIENT; } ipa_options->auth_ctx->krb5_auth_ctx = krb5_auth_ctx; ret = ipa_get_auth_options(ipa_options, bectx->cdb, bectx->conf_path, &krb5_auth_ctx->opts); if (ret != EOK) { goto done; } sdap_auth_ctx = talloc_zero(ipa_auth_ctx, struct sdap_auth_ctx); if (!sdap_auth_ctx) { ret = ENOMEM; goto done; } sdap_auth_ctx->be = bectx; sdap_auth_ctx->service = ipa_options->service->sdap; if (ipa_options->id == NULL) { ret = EINVAL; goto done; } sdap_auth_ctx->opts = ipa_options->id; ipa_options->auth_ctx->sdap_auth_ctx = sdap_auth_ctx; ret = setup_tls_config(sdap_auth_ctx->opts->basic); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "setup_tls_config failed [%d][%s].\n", ret, strerror(ret)); goto done; } /* Initialize features needed by the krb5_child */ ret = krb5_child_init(krb5_auth_ctx, bectx); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize krb5_child settings: [%s]\n", strerror(ret)); goto done; } ret = create_ipa_preauth_indicator(); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create preauth indicator file, special password " "prompting might not be available.\n"); sss_log(SSSDBG_CRIT_FAILURE, "Failed to create preauth indicator file, special password " "prompting might not be available.\n"); } *ops = &ipa_auth_ops; *pvt_data = ipa_auth_ctx; ret = EOK; done: if (ret != EOK) { talloc_zfree(ipa_options->auth_ctx); } return ret; }
static int get_pw_name(struct proxy_id_ctx *ctx, struct sss_domain_info *dom, const char *i_name) { TALLOC_CTX *tmpctx; struct passwd *pwd; enum nss_status status; char *buffer; size_t buflen; int ret; uid_t uid; bool del_user; struct ldb_result *cached_pwd = NULL; const char *real_name = NULL; char *shortname_or_alias; DEBUG(SSSDBG_TRACE_FUNC, "Searching user by name (%s)\n", i_name); tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } ret = sss_parse_internal_fqname(tmpctx, i_name, &shortname_or_alias, NULL); if (ret != EOK) { goto done; } pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } /* FIXME: should we move this call outside the transaction to keep the * transaction as short as possible ? */ status = ctx->ops.getpwnam_r(shortname_or_alias, pwd, buffer, buflen, &ret); ret = handle_getpw_result(status, pwd, dom, &del_user); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "getpwnam failed [%d]: %s\n", ret, strerror(ret)); goto done; } if (del_user) { ret = delete_user(dom, i_name, 0); goto done; } uid = pwd->pw_uid; /* Canonicalize the username in case it was actually an alias */ if (ctx->fast_alias == true) { ret = sysdb_getpwuid(tmpctx, dom, uid, &cached_pwd); if (ret != EOK) { /* Non-fatal, attempt to canonicalize online */ DEBUG(SSSDBG_TRACE_FUNC, "Request to cache failed [%d]: %s\n", ret, strerror(ret)); } if (ret == EOK && cached_pwd->count == 1) { real_name = ldb_msg_find_attr_as_string(cached_pwd->msgs[0], SYSDB_NAME, NULL); if (!real_name) { DEBUG(SSSDBG_MINOR_FAILURE, "Cached user has no name?\n"); } } } if (real_name == NULL) { memset(buffer, 0, buflen); status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); ret = handle_getpw_result(status, pwd, dom, &del_user); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "getpwuid failed [%d]: %s\n", ret, strerror(ret)); goto done; } real_name = sss_create_internal_fqname(tmpctx, pwd->pw_name, dom->name); if (real_name == NULL) { ret = ENOMEM; goto done; } } if (del_user) { ret = delete_user(dom, i_name, uid); goto done; } /* Both lookups went fine, we can save the user now */ ret = save_user(dom, !dom->case_sensitive, pwd, real_name, i_name, dom->user_timeout); done: talloc_zfree(tmpctx); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "proxy -> getpwnam_r failed for '%s' <%d>: %s\n", i_name, ret, strerror(ret)); } return ret; }
static int krb5_mod_ccname(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, const char *name, const char *ccname, int mod_op) { TALLOC_CTX *tmpctx; struct sysdb_attrs *attrs; int ret; errno_t sret; bool in_transaction = false; if (name == NULL || ccname == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing user or ccache name.\n"); return EINVAL; } if (mod_op != SYSDB_MOD_REP && mod_op != SYSDB_MOD_DEL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported operation [%d].\n", mod_op); return EINVAL; } DEBUG(SSSDBG_TRACE_ALL, "%s ccname [%s] for user [%s].\n", mod_op == SYSDB_MOD_REP ? "Save" : "Delete", ccname, name); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } attrs = sysdb_new_attrs(tmpctx); if (!attrs) { ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, ccname); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_add_string failed.\n"); goto done; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Error %d starting transaction (%s)\n", ret, strerror(ret)); goto done; } in_transaction = true; ret = sysdb_set_user_attr(domain, name, attrs, mod_op); if (ret != EOK) { DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret)); goto done; } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n"); goto done; } in_transaction = false; done: if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } talloc_zfree(tmpctx); return ret; }
static int get_gr_name(struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom, const char *i_name) { TALLOC_CTX *tmpctx; struct group *grp; enum nss_status status; char *buffer = 0; size_t buflen = 0; bool delete_group = false; int ret; gid_t gid; struct ldb_result *cached_grp = NULL; const char *real_name = NULL; char *shortname_or_alias; DEBUG(SSSDBG_FUNC_DATA, "Searching group by name (%s)\n", i_name); tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } ret = sss_parse_internal_fqname(tmpctx, i_name, &shortname_or_alias, NULL); if (ret != EOK) { goto done; } grp = talloc(tmpctx, struct group); if (!grp) { ret = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "proxy -> getgrnam_r failed for '%s': [%d] %s\n", i_name, ret, strerror(ret)); goto done; } do { /* always zero out the grp structure */ memset(grp, 0, sizeof(struct group)); buffer = grow_group_buffer(tmpctx, &buffer, &buflen); if (!buffer) { ret = ENOMEM; goto done; } status = ctx->ops.getgrnam_r(shortname_or_alias, grp, buffer, buflen, &ret); ret = handle_getgr_result(status, grp, dom, &delete_group); } while (ret == EAGAIN); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "getgrnam failed [%d]: %s\n", ret, strerror(ret)); goto done; } if (delete_group) { DEBUG(SSSDBG_TRACE_FUNC, "Group %s does not exist (or is invalid) on remote server," " deleting!\n", i_name); ret = sysdb_delete_group(dom, i_name, 0); if (ret == ENOENT) { ret = EOK; } goto done; } gid = grp->gr_gid; /* Canonicalize the group name in case it was actually an alias */ if (ctx->fast_alias == true) { ret = sysdb_getgrgid(tmpctx, dom, gid, &cached_grp); if (ret != EOK) { /* Non-fatal, attempt to canonicalize online */ DEBUG(SSSDBG_TRACE_FUNC, "Request to cache failed [%d]: %s\n", ret, strerror(ret)); } if (ret == EOK && cached_grp->count == 1) { real_name = ldb_msg_find_attr_as_string(cached_grp->msgs[0], SYSDB_NAME, NULL); if (!real_name) { DEBUG(SSSDBG_MINOR_FAILURE, "Cached group has no name?\n"); } } } if (real_name == NULL) { talloc_zfree(buffer); buflen = 0; do { memset(grp, 0, sizeof(struct group)); buffer = grow_group_buffer(tmpctx, &buffer, &buflen); if (!buffer) { ret = ENOMEM; goto done; } status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret); ret = handle_getgr_result(status, grp, dom, &delete_group); } while (ret == EAGAIN); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "getgrgid failed [%d]: %s\n", ret, strerror(ret)); goto done; } real_name = sss_create_internal_fqname(tmpctx, grp->gr_name, dom->name); if (real_name == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Failed to create fqdn '%s'\n", grp->gr_name); ret = ENOMEM; goto done; } } if (delete_group) { DEBUG(SSSDBG_TRACE_FUNC, "Group %s does not exist (or is invalid) on remote server," " deleting!\n", i_name); ret = sysdb_delete_group(dom, i_name, gid); if (ret == ENOENT) { ret = EOK; } goto done; } ret = save_group(sysdb, dom, grp, real_name, i_name, dom->group_timeout); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Cannot save group [%d]: %s\n", ret, strerror(ret)); goto done; } done: talloc_zfree(tmpctx); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "proxy -> getgrnam_r failed for '%s' <%d>: %s\n", i_name, ret, strerror(ret)); } return ret; }
errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx) { TALLOC_CTX *tmp_ctx = NULL; struct tevent_req *dpreq = NULL; struct dp_callback_ctx *cb_ctx = NULL; char **groupnames = NULL; uint32_t expired_rules_num = 0; struct sysdb_attrs **expired_rules = NULL; errno_t ret; unsigned int flags = SYSDB_SUDO_FILTER_NONE; const char *attrs[] = { SYSDB_NAME, NULL }; if (cmd_ctx->domain == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("Domain is not set!\n")); return EFAULT; } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); return ENOMEM; } switch (cmd_ctx->type) { case SSS_SUDO_DEFAULTS: DEBUG(SSSDBG_TRACE_FUNC, ("Retrieving default options " "for [%s] from [%s]\n", cmd_ctx->orig_username, cmd_ctx->domain->name)); break; case SSS_SUDO_USER: DEBUG(SSSDBG_TRACE_FUNC, ("Retrieving rules " "for [%s] from [%s]\n", cmd_ctx->orig_username, cmd_ctx->domain->name)); break; } /* Fetch all expired rules: * sudo asks sssd twice - for defaults and for rules. If we refresh all * expired rules for this user and defaults at once we will save one * provider call */ ret = sysdb_get_sudo_user_info(tmp_ctx, cmd_ctx->domain->sysdb, cmd_ctx->domain, cmd_ctx->orig_username, NULL, &groupnames); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to retrieve user info [%d]: %s\n", ret, strerror(ret))); goto done; } flags = SYSDB_SUDO_FILTER_INCLUDE_ALL | SYSDB_SUDO_FILTER_INCLUDE_DFL | SYSDB_SUDO_FILTER_ONLY_EXPIRED | SYSDB_SUDO_FILTER_USERINFO; ret = sudosrv_get_sudorules_query_cache(tmp_ctx, cmd_ctx->domain->sysdb, cmd_ctx->domain, attrs, flags, cmd_ctx->orig_username, cmd_ctx->uid, groupnames, &expired_rules, &expired_rules_num); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to retrieve expired sudo rules " "[%d]: %s\n", ret, strerror(ret))); goto done; } cmd_ctx->expired_rules_num = expired_rules_num; if (expired_rules_num > 0) { /* refresh expired rules then continue */ DEBUG(SSSDBG_TRACE_INTERNAL, ("Refreshing %d expired rules\n", expired_rules_num)); dpreq = sss_dp_get_sudoers_send(tmp_ctx, cmd_ctx->cli_ctx->rctx, cmd_ctx->domain, false, SSS_DP_SUDO_REFRESH_RULES, cmd_ctx->orig_username, expired_rules_num, expired_rules); if (dpreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot issue DP request.\n")); ret = EIO; goto done; } cb_ctx = talloc_zero(tmp_ctx, struct dp_callback_ctx); if (!cb_ctx) { talloc_zfree(dpreq); ret = ENOMEM; goto done; } cb_ctx->callback = sudosrv_get_sudorules_dp_callback; cb_ctx->ptr = cmd_ctx; cb_ctx->cctx = cmd_ctx->cli_ctx; cb_ctx->mem_ctx = cmd_ctx; tevent_req_set_callback(dpreq, sudosrv_dp_req_done, cb_ctx); ret = EAGAIN; } else {
/* =Getgrgid-wrapper======================================================*/ static int get_gr_gid(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom, gid_t gid, time_t now) { TALLOC_CTX *tmpctx; struct group *grp; enum nss_status status; char *buffer = NULL; size_t buflen = 0; bool delete_group = false; int ret; char *name; DEBUG(SSSDBG_TRACE_FUNC, "Searching group by gid (%"SPRIgid")\n", gid); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } grp = talloc(tmpctx, struct group); if (!grp) { ret = ENOMEM; goto done; } do { /* always zero out the grp structure */ memset(grp, 0, sizeof(struct group)); buffer = grow_group_buffer(tmpctx, &buffer, &buflen); if (!buffer) { ret = ENOMEM; goto done; } status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret); ret = handle_getgr_result(status, grp, dom, &delete_group); } while (ret == EAGAIN); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "getgrgid failed [%d]: %s\n", ret, strerror(ret)); goto done; } if (delete_group) { DEBUG(SSSDBG_TRACE_FUNC, "Group %"SPRIgid" does not exist (or is invalid) on remote " "server, deleting!\n", gid); ret = sysdb_delete_group(dom, NULL, gid); if (ret == ENOENT) { ret = EOK; } goto done; } name = sss_create_internal_fqname(tmpctx, grp->gr_name, dom->name); if (name == NULL) { ret = ENOMEM; goto done; } ret = save_group(sysdb, dom, grp, name, NULL, dom->group_timeout); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Cannot save user [%d]: %s\n", ret, strerror(ret)); goto done; } done: talloc_zfree(tmpctx); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "proxy -> getgrgid_r failed for '%"SPRIgid"' <%d>: %s\n", gid, ret, strerror(ret)); } return ret; }
errno_t enum_services(struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct servent *svc; enum nss_status status; size_t buflen; char *buffer; char *newbuf; errno_t ret, sret; time_t now = time(NULL); const char *protocols[2] = { NULL, NULL }; const char **cased_aliases; DEBUG(SSSDBG_TRACE_FUNC, ("Enumerating services\n")); tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } svc = talloc(tmpctx, struct servent); if (!svc) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } ret = sysdb_transaction_start(sysdb); if (ret) { goto done; } in_transaction = true; status = ctx->ops.setservent(); if (status != NSS_STATUS_SUCCESS) { ret = EIO; goto done; } again: /* always zero out the svc structure */ memset(svc, 0, sizeof(struct servent)); /* get entry */ status = ctx->ops.getservent_r(svc, buffer, buflen, &ret); switch (status) { case NSS_STATUS_TRYAGAIN: /* buffer too small ? */ if (buflen < MAX_BUF_SIZE) { buflen *= 2; } if (buflen > MAX_BUF_SIZE) { buflen = MAX_BUF_SIZE; } newbuf = talloc_realloc_size(tmpctx, buffer, buflen); if (!newbuf) { ret = ENOMEM; goto done; } buffer = newbuf; goto again; case NSS_STATUS_NOTFOUND: /* we are done here */ DEBUG(SSSDBG_TRACE_FUNC, ("Enumeration completed.\n")); ret = sysdb_transaction_commit(sysdb); if (ret != EOK) goto done; in_transaction = false; break; case NSS_STATUS_SUCCESS: DEBUG(SSSDBG_TRACE_INTERNAL, ("Service found (%s, %d/%s)\n", svc->s_name, svc->s_port, svc->s_proto)); protocols[0] = sss_get_cased_name(protocols, svc->s_proto, dom->case_sensitive); if (!protocols[0]) { ret = ENOMEM; goto done; } protocols[1] = NULL; ret = sss_get_cased_name_list(tmpctx, (const char * const *) svc->s_aliases, dom->case_sensitive, &cased_aliases); if (ret != EOK) { /* Do not fail completely on errors. * Just report the failure to save and go on */ DEBUG(SSSDBG_OP_FAILURE, ("Failed to store service [%s]. Ignoring.\n", strerror(ret))); goto again; /* next */ } ret = sysdb_store_service(sysdb, svc->s_name, svc->s_port, cased_aliases, protocols, NULL, NULL, dom->service_timeout, now); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ DEBUG(SSSDBG_OP_FAILURE, ("Failed to store service [%s]. Ignoring.\n", strerror(ret))); } goto again; /* next */ case NSS_STATUS_UNAVAIL: /* "remote" backend unavailable. Enter offline mode */ ret = ENXIO; break; default: ret = EIO; DEBUG(SSSDBG_CRIT_FAILURE, ("proxy -> getservent_r failed (%d)[%s]\n", ret, strerror(ret))); break; } done: talloc_zfree(tmpctx); if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction! [%s]\n", strerror(sret))); } } ctx->ops.endservent(); return ret; }
static void be_ptask_execute(struct tevent_context *ev, struct tevent_timer *tt, struct timeval tv, void *pvt) { struct be_ptask *task = NULL; struct tevent_timer *timeout = NULL; task = talloc_get_type(pvt, struct be_ptask); task->timer = NULL; /* timer is freed by tevent */ if (be_is_offline(task->be_ctx)) { DEBUG(SSSDBG_TRACE_FUNC, "Back end is offline\n"); switch (task->offline) { case BE_PTASK_OFFLINE_SKIP: be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); return; case BE_PTASK_OFFLINE_DISABLE: /* This case is normally handled by offline callback but we * should handle it here as well since we can get here in some * special cases for example unit tests or tevent events order. */ be_ptask_disable(task); return; case BE_PTASK_OFFLINE_EXECUTE: /* continue */ break; } } DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: executing task, timeout %lu " "seconds\n", task->name, task->timeout); task->last_execution = tv.tv_sec; task->req = task->send_fn(task, task->ev, task->be_ctx, task, task->pvt); if (task->req == NULL) { /* skip this iteration and try again later */ DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed to execute task, " "will try again later\n", task->name); be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); return; } tevent_req_set_callback(task->req, be_ptask_done, task); /* schedule timeout */ if (task->timeout > 0) { tv = tevent_timeval_current_ofs(task->timeout, 0); timeout = tevent_add_timer(task->ev, task->req, tv, be_ptask_timeout, task); if (timeout == NULL) { /* If we can't guarantee a timeout, * we need to cancel the request. */ talloc_zfree(task->req); DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed to set timeout, " "the task will be rescheduled\n", task->name); be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); } } return; }
static int get_initgr(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom, const char *name) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct passwd *pwd; enum nss_status status; char *buffer; size_t buflen; int ret; bool del_user; uid_t uid; struct ldb_result *cached_pwd = NULL; const char *real_name = NULL; tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; goto fail; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto fail; } ret = sysdb_transaction_start(sysdb); if (ret) { goto fail; } in_transaction = true; /* FIXME: should we move this call outside the transaction to keep the * transaction as short as possible ? */ status = ctx->ops.getpwnam_r(name, pwd, buffer, buflen, &ret); ret = handle_getpw_result(status, pwd, dom, &del_user); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("getpwnam failed [%d]: %s\n", ret, strerror(ret))); goto fail; } if (del_user) { DEBUG(SSSDBG_TRACE_FUNC, ("User %s does not exist (or is invalid) on remote server," " deleting!\n", name)); ret = sysdb_delete_user(sysdb, name, 0); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not delete user\n")); goto fail; } goto done; } uid = pwd->pw_uid; memset(buffer, 0, buflen); /* Canonicalize the username in case it was actually an alias */ if (ctx->fast_alias == true) { ret = sysdb_getpwuid(tmpctx, sysdb, uid, &cached_pwd); if (ret != EOK) { /* Non-fatal, attempt to canonicalize online */ DEBUG(SSSDBG_TRACE_FUNC, ("Request to cache failed [%d]: %s\n", ret, strerror(ret))); } if (ret == EOK && cached_pwd->count == 1) { real_name = ldb_msg_find_attr_as_string(cached_pwd->msgs[0], SYSDB_NAME, NULL); if (!real_name) { DEBUG(SSSDBG_MINOR_FAILURE, ("Cached user has no name?\n")); } } } if (real_name == NULL) { memset(buffer, 0, buflen); status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); ret = handle_getpw_result(status, pwd, dom, &del_user); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); goto done; } real_name = pwd->pw_name; } if (del_user) { DEBUG(SSSDBG_TRACE_FUNC, ("User %s does not exist (or is invalid) on remote server," " deleting!\n", name)); ret = sysdb_delete_user(sysdb, name, uid); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not delete user\n")); goto fail; } goto done; } ret = save_user(sysdb, !dom->case_sensitive, pwd, real_name, name, dom->user_timeout); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not save user\n")); goto fail; } ret = get_initgr_groups_process(tmpctx, ctx, sysdb, dom, pwd); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not process initgroups\n")); goto fail; } done: ret = sysdb_transaction_commit(sysdb); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to commit transaction\n")); goto fail; } in_transaction = false; fail: talloc_zfree(tmpctx); if (in_transaction) { sysdb_transaction_cancel(sysdb); } return ret; }
static int parse_members(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct sss_domain_info *domain, struct ldb_message_element *el, const char *parent_name, const char ***user_members, const char ***group_members, int *num_group_members) { struct ldb_dn *user_basedn = NULL, *group_basedn = NULL; struct ldb_dn *parent_dn = NULL; struct ldb_dn *dn = NULL; const char **um = NULL, **gm = NULL; unsigned int um_index = 0, gm_index = 0; TALLOC_CTX *tmp_ctx = NULL; int ret; int i; tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { ret = ENOMEM; goto fail; } user_basedn = sysdb_user_base_dn(tmp_ctx, domain); group_basedn = sysdb_group_base_dn(tmp_ctx, domain); if (!user_basedn || !group_basedn) { ret = ENOMEM; goto fail; } um = talloc_array(mem_ctx, const char *, el->num_values+1); gm = talloc_array(mem_ctx, const char *, el->num_values+1); if (!um || !gm) { ret = ENOMEM; goto fail; } for (i = 0; i< el->num_values; ++i) { dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &(el->values[i])); /* user member or group member? */ parent_dn = ldb_dn_get_parent(tmp_ctx, dn); if (ldb_dn_compare_base(parent_dn, user_basedn) == 0) { um[um_index] = rdn_as_string(mem_ctx, dn); if (um[um_index] == NULL) { ret = ENOMEM; goto fail; } DEBUG(SSSDBG_TRACE_FUNC, "User member %s\n", um[um_index]); um_index++; } else if (ldb_dn_compare_base(parent_dn, group_basedn) == 0) { gm[gm_index] = rdn_as_string(mem_ctx, dn); if (gm[gm_index] == NULL) { ret = ENOMEM; goto fail; } if (parent_name && strcmp(gm[gm_index], parent_name) == 0) { DEBUG(SSSDBG_TRACE_FUNC, "Skipping circular nesting for group %s\n", gm[gm_index]); continue; } DEBUG(SSSDBG_TRACE_FUNC, "Group member %s\n", gm[gm_index]); gm_index++; } else { DEBUG(SSSDBG_OP_FAILURE, "Group member not a user nor group: %s\n", ldb_dn_get_linearized(dn)); ret = EIO; goto fail; } talloc_zfree(dn); talloc_zfree(parent_dn); } um[um_index] = NULL; gm[gm_index] = NULL; if (um_index > 0) { um = talloc_realloc(mem_ctx, um, const char *, um_index+1); if (!um) { ret = ENOMEM; goto fail; } } else {