Esempio n. 1
0
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;
    }
Esempio n. 3
0
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;
        }
    }
Esempio n. 4
0
/*
 * 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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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));
}
Esempio n. 7
0
File: ipa_init.c Progetto: 3van/sssd
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
/* 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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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);
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
void be_ptask_destroy(struct be_ptask **task)
{
    talloc_zfree(*task);
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
void nested_groups_test_teardown(void **state)
{
    talloc_zfree(*state);
}
Esempio n. 20
0
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;
}
Esempio n. 21
0
File: ipa_init.c Progetto: 3van/sssd
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;
}
Esempio n. 22
0
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;
}
Esempio n. 23
0
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;
}
Esempio n. 24
0
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 {
Esempio n. 26
0
/* =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;
}
Esempio n. 27
0
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;
}
Esempio n. 28
0
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;
}
Esempio n. 29
0
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;
}
Esempio n. 30
0
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 {