Пример #1
0
static void assert_defaults(struct dp_option *opts)
{
    char *s;
    struct dp_opt_blob b;
    int i;
    bool bo;

    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
    assert_null(s);

    s = dp_opt_get_string(opts, OPT_STRING_DEFAULT);
    assert_non_null(s);
    assert_string_equal(s, STRING_DEFAULT);

    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
    assert_null(b.data);
    assert_int_equal(b.length, 0);

    b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT);
    assert_non_null(b.data);
    assert_int_equal(b.length, strlen(BLOB_DEFAULT));
    assert_memory_equal(b.data, BLOB_DEFAULT, strlen(BLOB_DEFAULT));

    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
    assert_int_equal(i, 0);

    i = dp_opt_get_int(opts, OPT_INT_DEFAULT);
    assert_int_equal(i, INT_DEFAULT);

    bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
    assert_true(bo == true);

    bo = dp_opt_get_bool(opts, OPT_BOOL_FALSE);
    assert_true(bo == false);
}
Пример #2
0
static void ldap_id_enumerate_timer(struct tevent_context *ev,
                                    struct tevent_timer *tt,
                                    struct timeval tv, void *pvt)
{
    struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
    struct tevent_timer *timeout;
    struct tevent_req *req;
    int delay;
    errno_t ret;

    if (be_is_offline(ctx->be)) {
        DEBUG(4, ("Backend is marked offline, retry later!\n"));
        /* schedule starting from now, not the last run */
        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
        tv = tevent_timeval_current_ofs(delay, 0);
        ldap_id_enumerate_set_timer(ctx, tv);
        return;
    }

    req = ldap_id_enumerate_send(ev, ctx);
    if (!req) {
        DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
        /* schedule starting from now, not the last run */
        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
        tv = tevent_timeval_current_ofs(delay, 0);
        ret = ldap_id_enumerate_set_timer(ctx, tv);
        if (ret != EOK) {
            DEBUG(1, ("Error setting up enumerate timer\n"));
        }
        return;
    }
    tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx);

    /* if enumeration takes so long, either we try to enumerate too
     * frequently, or something went seriously wrong */
    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
    tv = tevent_timeval_current_ofs(delay, 0);
    timeout = tevent_add_timer(ctx->be->ev, req, tv,
                               ldap_id_enumerate_timeout, req);
    if (timeout == NULL) {
        /* If we can't guarantee a timeout, we
         * need to cancel the request, to avoid
         * the possibility of starting another
         * concurrently
         */
        talloc_zfree(req);

        DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
        /* schedule starting from now, not the last run */
        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
        tv = tevent_timeval_current_ofs(delay, 0);
        ret = ldap_id_enumerate_set_timer(ctx, tv);
        if (ret != EOK) {
            DEBUG(1, ("Error setting up enumerate timer\n"));
        }
        return;
    }
    return;
}
Пример #3
0
void opt_test_get(void **state)
{
    int ret;
    struct sss_test_ctx *tctx;
    struct dp_option *opts;
    struct sss_test_conf_param params[] = {
        { "string_nodefault", "stringval2" },
        { "blob_nodefault", "blobval2" },
        { "int_nodefault", "456" },
        { "bool_true", "false" },
        { NULL, NULL },             /* Sentinel */
    };
    char *s;
    struct dp_opt_blob b;
    int i;
    bool bo;

    tctx = create_dom_test_ctx(global_talloc_context, TESTS_PATH, TEST_CONF_DB,
                               TEST_DOM_NAME, TEST_ID_PROVIDER, params);
    assert_non_null(tctx);

    ret = dp_get_options(global_talloc_context, tctx->confdb, tctx->conf_dom_path,
                         test_def_opts, OPT_NUM_OPTS, &opts);
    assert_int_equal(ret, EOK);

    /* Options that were not specified explicitly should only have the default
     * value, those that have been specified explicitly should carry that
     * value
     */
    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
    assert_non_null(s);
    assert_string_equal(s, "stringval2");

    s = dp_opt_get_string(opts, OPT_STRING_DEFAULT);
    assert_non_null(s);
    assert_string_equal(s, STRING_DEFAULT);

    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
    assert_non_null(b.data);
    assert_int_equal(b.length, strlen("blobval2"));
    assert_memory_equal(b.data, "blobval2", strlen("blobval2"));

    b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT);
    assert_non_null(b.data);
    assert_int_equal(b.length, strlen(BLOB_DEFAULT));
    assert_memory_equal(b.data, BLOB_DEFAULT, strlen(BLOB_DEFAULT));

    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
    assert_int_equal(i, 456);

    i = dp_opt_get_int(opts, OPT_INT_DEFAULT);
    assert_int_equal(i, INT_DEFAULT);

    bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
    assert_true(bo == false);

    bo = dp_opt_get_bool(opts, OPT_BOOL_FALSE);
    assert_true(bo == false);
}
Пример #4
0
static void sdap_sudo_periodical_first_refresh_done(struct tevent_req *req)
{
    struct tevent_req *subreq = NULL; /* req from sdap_sudo_full_refresh_send() */
    struct sdap_sudo_ctx *sudo_ctx = NULL;
    time_t delay;
    int dp_error = DP_ERR_OK;
    int error = EOK;
    int ret;

    ret = sdap_sudo_timer_recv(req, req, &subreq);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE,
              ("Sudo timer failed [%d]: %s\n", ret, strerror(ret)));
        goto schedule;
    }

    ret = sdap_sudo_full_refresh_recv(subreq, &dp_error, &error);
    if (dp_error != DP_ERR_OK || error != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, ("Periodical full refresh of sudo rules "
              "failed [dp_error: %d] ([%d]: %s)\n",
              dp_error, error, strerror(error)));
        goto schedule;
    }

schedule:
    sudo_ctx = tevent_req_callback_data(req, struct sdap_sudo_ctx);
    talloc_zfree(req);

    /* full refresh */
    delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic,
                           SDAP_SUDO_FULL_REFRESH_INTERVAL);
    if (delay == 0) {
        /* runtime configuration change? */
        DEBUG(SSSDBG_TRACE_FUNC, ("Periodical full refresh of sudo rules "
                                  "is disabled\n"));
        return;
    }

    ret = sdap_sudo_schedule_full_refresh(sudo_ctx, delay);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, ("Full periodical refresh will not work.\n"));
    }

    /* smart refresh */
    delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic,
                           SDAP_SUDO_SMART_REFRESH_INTERVAL);
    if (delay == 0) {
        /* runtime configuration change? */
        DEBUG(SSSDBG_TRACE_FUNC, ("Periodical smart refresh of sudo rules "
                                  "is disabled\n"));
        return;
    }

    ret = sdap_sudo_schedule_smart_refresh(sudo_ctx, delay);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, ("Smart periodical refresh will not work.\n"));
    }
}
Пример #5
0
void opt_test_copy_options(void **state)
{
    int ret;
    TALLOC_CTX *mem_ctx;
    struct dp_option *opts;
    char *s;
    struct dp_opt_blob b;
    int i;
    bool bo;

    mem_ctx = talloc_new(global_talloc_context);
    assert_non_null(mem_ctx);

    ret = dp_copy_options(mem_ctx, test_def_opts, OPT_NUM_OPTS, &opts);
    assert_int_equal(ret, EOK);
    assert_int_equal(ret, EOK);

    ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1");
    assert_int_equal(ret, EOK);

    b.data = discard_const_p(uint8_t, "blob1");
    b.length = strlen("blob1");
    ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b);
    assert_int_equal(ret, EOK);

    ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456);
    assert_int_equal(ret, EOK);

    ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false);
    assert_int_equal(ret, EOK);

    /* Test that options set to an explicit value retain
     * the value and even options with default value
     * do not return the default unless explicitly set
     */
    s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT);
    assert_string_equal(s, "str1");
    s = dp_opt_get_string(opts, OPT_STRING_DEFAULT);
    assert_null(s);

    b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT);
    assert_non_null(b.data);
    assert_int_equal(b.length, strlen("blob1"));
    assert_memory_equal(b.data, "blob1", strlen("blob1"));
    b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT);
    assert_null(b.data);
    assert_int_equal(b.length, 0);

    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
    assert_int_equal(i, 456);
    i = dp_opt_get_int(opts, OPT_INT_DEFAULT);
    assert_int_equal(i, 0);

    bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE);
    assert_false(bo == true);
}
Пример #6
0
static errno_t
sdap_idmap_get_configured_external_range(struct sdap_idmap_ctx *idmap_ctx,
                                         struct sss_idmap_range *range)
{
    int int_id;
    struct sdap_id_ctx *id_ctx;
    uint32_t min;
    uint32_t max;

    if (idmap_ctx == NULL) {
        return EINVAL;
    }

    id_ctx = idmap_ctx->id_ctx;

    int_id = dp_opt_get_int(id_ctx->opts->basic, SDAP_MIN_ID);
    if (int_id < 0) {
        DEBUG(SSSDBG_CONF_SETTINGS, "ldap_min_id must be greater than 0.\n");
        return EINVAL;
    }
    min = int_id;

    int_id = dp_opt_get_int(id_ctx->opts->basic, SDAP_MAX_ID);
    if (int_id < 0) {
        DEBUG(SSSDBG_CONF_SETTINGS, "ldap_max_id must be greater than 0.\n");
        return EINVAL;
    }
    max = int_id;

    if ((min == 0 && max != 0) || (min != 0 && max == 0)) {
        DEBUG(SSSDBG_CONF_SETTINGS, "Both ldap_min_id and ldap_max_id " \
                                     "either must be 0 (not set) " \
                                     "or positive integers.\n");
        return EINVAL;
    }

    if (min == 0 && max == 0) {
        /* ldap_min_id and ldap_max_id not set, using min_id and max_id */
        min = id_ctx->be->domain->id_min;
        max = id_ctx->be->domain->id_max;
        if (max == 0) {
            max = UINT32_MAX;
        }
    }

    range->min = min;
    range->max =max;

    return EOK;
}
Пример #7
0
static void ldap_id_enumerate_reschedule(struct tevent_req *req)
{
    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
                                                       struct sdap_id_ctx);
    enum tevent_req_state tstate;
    uint64_t err;
    struct timeval tv;
    int delay;
    errno_t ret;

    if (tevent_req_is_error(req, &tstate, &err)) {
        /* On error schedule starting from now, not the last run */
        tv = tevent_timeval_current();
    } else {
        tv = ctx->last_enum;

        /* Ok, we've completed an enumeration. Save this to the
         * sysdb so we can postpone starting up the enumeration
         * process on the next SSSD service restart (to avoid
         * slowing down system boot-up
         */
        ret = sysdb_set_enumerated(ctx->be->sysdb, true);
        if (ret != EOK) {
            DEBUG(1, ("Could not mark domain as having enumerated.\n"));
            /* This error is non-fatal, so continue */
        }
    }
    talloc_zfree(req);

    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
    tv = tevent_timeval_add(&tv, delay, 0);
    ldap_id_enumerate_set_timer(ctx, tv);
}
Пример #8
0
static int hbac_retry(struct hbac_ctx *hbac_ctx)
{
    struct tevent_req *subreq;
    int ret;
    bool offline;
    time_t now, refresh_interval;
    struct ipa_access_ctx *access_ctx = hbac_ctx->access_ctx;
    struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);

    offline = be_is_offline(be_ctx);
    DEBUG(9, ("Connection status is [%s].\n", offline ? "offline" : "online"));

    refresh_interval = dp_opt_get_int(hbac_ctx->ipa_options,
                                      IPA_HBAC_REFRESH);

    now = time(NULL);
    if (now < access_ctx->last_update + refresh_interval) {
        /* Simulate offline mode and just go to the cache */
        DEBUG(6, ("Performing cached HBAC evaluation\n"));
        offline = true;
    }

    if (!offline) {
        if (hbac_ctx->sdap_op == NULL) {
            hbac_ctx->sdap_op = sdap_id_op_create(hbac_ctx,
                                          hbac_ctx->sdap_ctx->conn->conn_cache);
            if (hbac_ctx->sdap_op == NULL) {
                DEBUG(1, ("sdap_id_op_create failed.\n"));
                return EIO;
            }
        }

        subreq = sdap_id_op_connect_send(hbac_ctx->sdap_op, hbac_ctx, &ret);
        if (!subreq) {
            DEBUG(1, ("sdap_id_op_connect_send failed: %d(%s).\n", ret, strerror(ret)));
            talloc_zfree(hbac_ctx->sdap_op);
            return ret;
        }

        tevent_req_set_callback(subreq, hbac_connect_done, hbac_ctx);
    } else {
        /* Evaluate the rules based on what we have in the
         * sysdb
         */
        ipa_hbac_evaluate_rules(hbac_ctx);
        return EOK;
    }
    return EOK;
}
Пример #9
0
static void ldap_id_enumerate_timeout(struct tevent_context *ev,
                                      struct tevent_timer *te,
                                      struct timeval tv, void *pvt)
{
    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
                                                       struct sdap_id_ctx);
    int delay;

    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
    DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", delay));

    tv = tevent_timeval_current_ofs(delay, 0);
    ldap_id_enumerate_set_timer(ctx, tv);

    talloc_zfree(req);
}
Пример #10
0
static void sdap_sudo_full_refresh_online_cb(void *pvt)
{
    struct sdap_sudo_ctx *sudo_ctx = NULL;
    time_t timeout;
    int ret;

    sudo_ctx = talloc_get_type(pvt, struct sdap_sudo_ctx);

    /* remove online callback */
    talloc_zfree(sudo_ctx->first_refresh_online_cb);

    /* schedule new first refresh only if this callback wasn't triggered
     * by ongoing full refresh */
    if (sudo_ctx->full_refresh_in_progress) {
        return;
    }

    /* otherwise cancel the concurrent timer for full refresh */
    talloc_zfree(sudo_ctx->first_refresh_timer);

    /* and fire full refresh immediately */
    timeout = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic,
                             SDAP_SUDO_FULL_REFRESH_INTERVAL);
    if (timeout == 0) {
        /* runtime configuration change? */
        DEBUG(SSSDBG_TRACE_FUNC, "Periodical full refresh of sudo rules "
                                  "is disabled\n");
        return;
    }

    ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx,
                                     SDAP_SUDO_REFRESH_FULL,
                                     sdap_sudo_periodical_first_refresh_done,
                                     0, timeout, NULL);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule full refresh of sudo "
              "rules! Periodical updates will not work!\n");
    }
}
Пример #11
0
static int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx)
{
    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
    struct tevent_req *req;
    time_t smart_default;
    time_t smart_interval;
    time_t full_interval;
    time_t last_full;
    struct timeval tv;
    int ret;

    smart_interval = dp_opt_get_int(id_ctx->opts->basic,
                                    SDAP_SUDO_SMART_REFRESH_INTERVAL);

    full_interval = dp_opt_get_int(id_ctx->opts->basic,
                                   SDAP_SUDO_FULL_REFRESH_INTERVAL);

    if (smart_interval == 0 && full_interval == 0) {
        smart_default = id_ctx->opts->basic[SDAP_SUDO_SMART_REFRESH_INTERVAL].def_val.number;

        DEBUG(SSSDBG_MINOR_FAILURE, ("At least one periodical update has to be "
              "enabled. Setting smart refresh interval to default value (%d).\n",
              smart_default));

        ret = dp_opt_set_int(id_ctx->opts->basic,
                             SDAP_SUDO_SMART_REFRESH_INTERVAL,
                             smart_default);
        if (ret != EOK) {
            return ret;
        }
    }

    if (full_interval <= smart_interval) {
        DEBUG(SSSDBG_MINOR_FAILURE, ("Full refresh interval has to be greater"
              "than smart refresh interval. Periodical full refresh will be "
              "disabled.\n"));
        ret = dp_opt_set_int(id_ctx->opts->basic,
                             SDAP_SUDO_FULL_REFRESH_INTERVAL,
                             0);
        if (ret != EOK) {
            return ret;
        }
    }

    ret = sysdb_sudo_get_last_full_refresh(id_ctx->be->sysdb, &last_full);
    if (ret != EOK) {
        return ret;
    }

    if (last_full == 0) {
        /* If this is the first startup, we need to kick off
         * an refresh immediately, to close a window where
         * clients requesting sudo information won't get an
         * immediate reply with no entries
         */
        tv = tevent_timeval_current();
    } else {
        /* At least one update has previously run,
         * so clients will get cached data.
         * We will delay the refresh so we don't slow
         * down the startup process if this is happening
         * during system boot.
         */

        /* delay at least by 10s */
        tv = tevent_timeval_current_ofs(10, 0);
    }

    req = sdap_sudo_timer_send(sudo_ctx, id_ctx->be->ev, sudo_ctx,
                               tv, full_interval,
                               sdap_sudo_full_refresh_send);
    if (req == NULL) {
        DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo "
              "rules! Periodical updates will not work!\n"));
        return ENOMEM;
    }

    tevent_req_set_callback(req, sdap_sudo_periodical_first_refresh_done,
                            sudo_ctx);

    DEBUG(SSSDBG_TRACE_FUNC, ("Full refresh scheduled at: %lld\n",
                              (long long)tv.tv_sec));

    return EOK;
}
Пример #12
0
errno_t
sdap_idmap_init(TALLOC_CTX *mem_ctx,
                struct sdap_id_ctx *id_ctx,
                struct sdap_idmap_ctx **_idmap_ctx)
{
    errno_t ret;
    TALLOC_CTX *tmp_ctx;
    enum idmap_error_code err;
    size_t i;
    struct ldb_result *res;
    const char *dom_name;
    const char *sid_str;
    id_t slice_num;
    id_t idmap_lower;
    id_t idmap_upper;
    id_t rangesize;
    bool autorid_mode;
    struct sdap_idmap_ctx *idmap_ctx = NULL;

    tmp_ctx = talloc_new(NULL);
    if (!tmp_ctx) return ENOMEM;

    idmap_ctx = talloc_zero(tmp_ctx, struct sdap_idmap_ctx);
    if (!idmap_ctx) {
        ret = ENOMEM;
        goto done;
    }
    idmap_ctx->id_ctx = id_ctx;
    idmap_ctx->find_new_domain = sdap_idmap_find_new_domain;

    idmap_lower = dp_opt_get_int(idmap_ctx->id_ctx->opts->basic,
                                 SDAP_IDMAP_LOWER);
    idmap_upper = dp_opt_get_int(idmap_ctx->id_ctx->opts->basic,
                                 SDAP_IDMAP_UPPER);
    rangesize = dp_opt_get_int(idmap_ctx->id_ctx->opts->basic,
                               SDAP_IDMAP_RANGESIZE);
    autorid_mode = dp_opt_get_bool(idmap_ctx->id_ctx->opts->basic,
                                   SDAP_IDMAP_AUTORID_COMPAT);

    /* Validate that the values make sense */
    if (rangesize <= 0
            || idmap_upper <= idmap_lower
            || (idmap_upper-idmap_lower) < rangesize)
    {
        DEBUG(SSSDBG_FATAL_FAILURE,
              "Invalid settings for range selection: "
               "[%"SPRIid"][%"SPRIid"][%"SPRIid"]\n",
               idmap_lower, idmap_upper, rangesize);
        ret = EINVAL;
        goto done;
    }

    if (((idmap_upper - idmap_lower) % rangesize) != 0) {
        DEBUG(SSSDBG_CONF_SETTINGS,
              "Range size does not divide evenly. Uppermost range will "
               "not be used\n");
    }

    /* Initialize the map */
    err = sss_idmap_init(sss_idmap_talloc, idmap_ctx,
                         sss_idmap_talloc_free,
                         &idmap_ctx->map);
    if (err != IDMAP_SUCCESS) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Could not initialize the ID map: [%s]\n",
               idmap_error_string(err));
        if (err == IDMAP_OUT_OF_MEMORY) {
            ret = ENOMEM;
        } else {
            ret = EINVAL;
        }
        goto done;
    }

    err = sss_idmap_ctx_set_autorid(idmap_ctx->map, autorid_mode);
    err |= sss_idmap_ctx_set_lower(idmap_ctx->map, idmap_lower);
    err |= sss_idmap_ctx_set_upper(idmap_ctx->map, idmap_upper);
    err |= sss_idmap_ctx_set_rangesize(idmap_ctx->map, rangesize);
    if (err != IDMAP_SUCCESS) {
        /* This should never happen */
        DEBUG(SSSDBG_CRIT_FAILURE, "sss_idmap_ctx corrupted\n");
        return EIO;
    }


    /* Setup range for externally managed IDs, i.e. IDs are read from the
     * ldap_user_uid_number and ldap_group_gid_number attributes. */
    if (!dp_opt_get_bool(idmap_ctx->id_ctx->opts->basic, SDAP_ID_MAPPING)) {
        ret = sdap_idmap_add_configured_external_range(idmap_ctx);
        if (ret != EOK) {
            DEBUG(SSSDBG_OP_FAILURE,
                  "sdap_idmap_add_configured_external_range failed.\n");
            goto done;
        }
    }

    /* Read in any existing mappings from the cache */
    ret = sysdb_idmap_get_mappings(tmp_ctx, id_ctx->be->domain, &res);
    if (ret != EOK && ret != ENOENT) {
        DEBUG(SSSDBG_FATAL_FAILURE,
              "Could not read ID mappings from the cache: [%s]\n",
               strerror(ret));
        goto done;
    }

    if (ret == EOK && res->count > 0) {
        DEBUG(SSSDBG_CONF_SETTINGS,
              "Initializing [%d] domains for ID-mapping\n", res->count);

        for (i = 0; i < res->count; i++) {
            dom_name = ldb_msg_find_attr_as_string(res->msgs[i],
                                                   SYSDB_NAME,
                                                   NULL);
            if (!dom_name) {
                /* This should never happen */
                ret = EINVAL;
                goto done;
            }

            sid_str = ldb_msg_find_attr_as_string(res->msgs[i],
                                                  SYSDB_IDMAP_SID_ATTR,
                                                  NULL);
            if (!sid_str) {
                /* This should never happen */
                ret = EINVAL;
                goto done;
            }

            slice_num = ldb_msg_find_attr_as_int(res->msgs[i],
                                                 SYSDB_IDMAP_SLICE_ATTR,
                                                 -1);
            if (slice_num == -1) {
                /* This should never happen */
                ret = EINVAL;
                goto done;
            }

            ret = sdap_idmap_add_domain(idmap_ctx, dom_name,
                                        sid_str, slice_num);
            if (ret != EOK) {
                DEBUG(SSSDBG_CRIT_FAILURE,
                      "Could not add domain [%s][%s][%"SPRIid"] "
                       "to ID map: [%s]\n",
                       dom_name, sid_str, slice_num, strerror(ret));
                goto done;
            }
        }
    } else {
        /* This is the first time we're setting up id-mapping
         * Store the default domain as slice 0
         */
        dom_name = dp_opt_get_string(idmap_ctx->id_ctx->opts->basic, SDAP_IDMAP_DEFAULT_DOMAIN);
        if (!dom_name) {
            /* If it's not explicitly specified, use the SSSD domain name */
            dom_name = idmap_ctx->id_ctx->be->domain->name;
            ret = dp_opt_set_string(idmap_ctx->id_ctx->opts->basic,
                                    SDAP_IDMAP_DEFAULT_DOMAIN,
                                    dom_name);
            if (ret != EOK) goto done;
        }

        sid_str = dp_opt_get_string(idmap_ctx->id_ctx->opts->basic, SDAP_IDMAP_DEFAULT_DOMAIN_SID);
        if (sid_str) {
            /* Set the default domain as slice 0 */
            ret = sdap_idmap_add_domain(idmap_ctx, dom_name,
                                        sid_str, 0);
            if (ret != EOK) {
                DEBUG(SSSDBG_CRIT_FAILURE,
                      "Could not add domain [%s][%s][%u] to ID map: [%s]\n",
                       dom_name, sid_str, 0, strerror(ret));
                goto done;
            }
        } else {
            if (dp_opt_get_bool(idmap_ctx->id_ctx->opts->basic, SDAP_IDMAP_AUTORID_COMPAT)) {
                /* In autorid compatibility mode, we MUST have a slice 0 */
                DEBUG(SSSDBG_CRIT_FAILURE,
                      "WARNING: Autorid compatibility mode selected, "
                       "but %s is not set. UID/GID values may differ "
                       "between clients.\n",
                       idmap_ctx->id_ctx->opts->basic[SDAP_IDMAP_DEFAULT_DOMAIN_SID].opt_name);
            }
            /* Otherwise, we'll just fall back to hash values as they are seen */
        }
    }

    *_idmap_ctx = talloc_steal(mem_ctx, idmap_ctx);
    ret = EOK;

done:
    talloc_free(tmp_ctx);
    return ret;
}
Пример #13
0
static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
                                  struct sysdb_ctx *ctx,
                                  struct sdap_options *opts,
                                  struct sss_domain_info *dom,
                                  struct sysdb_attrs *attrs,
                                  char **_timestamp)
{
    struct ldb_message_element *el;
    struct sysdb_attrs *netgroup_attrs;
    const char *name = NULL;
    int ret;
    char *timestamp = NULL;
    size_t c;

    ret = sysdb_attrs_get_el(attrs,
                             opts->netgroup_map[SDAP_AT_NETGROUP_NAME].sys_name,
                             &el);
    if (ret) goto fail;
    if (el->num_values == 0) {
        ret = EINVAL;
        goto fail;
    }
    name = (const char *)el->values[0].data;

    netgroup_attrs = sysdb_new_attrs(memctx);
    if (!netgroup_attrs) {
        ret = ENOMEM;
        goto fail;
    }

    ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
    if (ret) {
        goto fail;
    }
    if (el->num_values == 0) {
        DEBUG(7, ("Original DN is not available for [%s].\n", name));
    } else {
        DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
                  el->values[0].data, name));
        ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_ORIG_DN,
                                     (const char *)el->values[0].data);
        if (ret) {
            goto fail;
        }
    }

    ret = sysdb_attrs_get_el(attrs,
                         opts->netgroup_map[SDAP_AT_NETGROUP_MODSTAMP].sys_name,
                         &el);
    if (ret) {
        goto fail;
    }
    if (el->num_values == 0) {
        DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
                  name));
    } else {
        ret = sysdb_attrs_add_string(netgroup_attrs,
                         opts->netgroup_map[SDAP_AT_NETGROUP_MODSTAMP].sys_name,
                         (const char*)el->values[0].data);
        if (ret) {
            goto fail;
        }
        timestamp = talloc_strdup(memctx, (const char*)el->values[0].data);
        if (!timestamp) {
            ret = ENOMEM;
            goto fail;
        }
    }

    ret = sysdb_attrs_get_el(attrs,
                           opts->netgroup_map[SDAP_AT_NETGROUP_TRIPLE].sys_name,
                           &el);
    if (ret) {
        goto fail;
    }
    if (el->num_values == 0) {
        DEBUG(7, ("No netgroup triples for netgroup [%s].\n", name));
    } else {
        for(c = 0; c < el->num_values; c++) {
            ret = sysdb_attrs_add_string(netgroup_attrs,
                           opts->netgroup_map[SDAP_AT_NETGROUP_TRIPLE].sys_name,
                            (const char*)el->values[c].data);
            if (ret) {
                goto fail;
            }
        }
    }

    ret = sysdb_attrs_get_el(attrs,
                       opts->netgroup_map[SDAP_AT_NETGROUP_MEMBER].sys_name,
                       &el);
    if (ret != EOK) {
        goto fail;
    }
    if (el->num_values == 0) {
        DEBUG(7, ("No original members for netgroup [%s]\n", name));

    } else {
        DEBUG(7, ("Adding original members to netgroup [%s]\n", name));
        for(c = 0; c < el->num_values; c++) {
            ret = sysdb_attrs_add_string(netgroup_attrs,
                       opts->netgroup_map[SDAP_AT_NETGROUP_MEMBER].sys_name,
                       (const char*)el->values[c].data);
            if (ret) {
                goto fail;
            }
        }
    }


    ret = sysdb_attrs_get_el(attrs, SYSDB_NETGROUP_MEMBER, &el);
    if (ret != EOK) {
        goto fail;
    }
    if (el->num_values == 0) {
        DEBUG(7, ("No members for netgroup [%s]\n", name));

    } else {
        DEBUG(7, ("Adding members to netgroup [%s]\n", name));
        for(c = 0; c < el->num_values; c++) {
            ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_NETGROUP_MEMBER,
                                         (const char*)el->values[c].data);
            if (ret) {
                goto fail;
            }
        }
    }

    DEBUG(6, ("Storing info for netgroup %s\n", name));

    ret = sysdb_add_netgroup(ctx, name, NULL, netgroup_attrs,
                             dp_opt_get_int(opts->basic,
                                            SDAP_ENTRY_CACHE_TIMEOUT));
    if (ret) goto fail;

    if (_timestamp) {
        *_timestamp = timestamp;
    }

    return EOK;

fail:
    DEBUG(2, ("Failed to save netgroup %s\n", name));
    return ret;
}
Пример #14
0
static void sdap_sudo_periodical_first_refresh_done(struct tevent_req *req)
{
    struct tevent_req *subreq = NULL; /* req from sdap_sudo_full_refresh_send() */
    struct sdap_sudo_ctx *sudo_ctx = NULL;
    time_t delay;
    time_t timeout;
    int dp_error = DP_ERR_OK;
    int error = EOK;
    int ret;

    ret = sdap_sudo_timer_recv(req, req, &subreq);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE,
              "Sudo timer failed [%d]: %s\n", ret, strerror(ret));
        goto schedule;
    }

    ret = sdap_sudo_full_refresh_recv(subreq, &dp_error, &error);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, "Periodical full refresh of sudo rules "
                                  "failed [%d]: %s)\n", ret, strerror(ret));
        goto schedule;
    }

    if (dp_error != DP_ERR_OK || error != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, "Periodical full refresh of sudo rules "
                                  "failed [dp_error: %d] ([%d]: %s)\n",
                                  dp_error, error, strerror(error));
        goto schedule;
    }

schedule:
    sudo_ctx = tevent_req_callback_data(req, struct sdap_sudo_ctx);
    if (sudo_ctx->first_refresh_timer == req) {
        sudo_ctx->first_refresh_timer = NULL;
    }
    talloc_zfree(req);

    /* full refresh */
    delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic,
                           SDAP_SUDO_FULL_REFRESH_INTERVAL);
    if (delay == 0) {
        /* runtime configuration change? */
        DEBUG(SSSDBG_TRACE_FUNC, "Periodical full refresh of sudo rules "
                                  "is disabled\n");
        return;
    }

    /* if we are offline, we will try to perform another full refresh */
    if (dp_error == DP_ERR_OFFLINE) {
        sudo_ctx->full_refresh_attempts++;
        timeout = delay;
        delay = sudo_ctx->full_refresh_attempts << 1;
        if (delay > SUDO_MAX_FIRST_REFRESH_DELAY) {
            delay = SUDO_MAX_FIRST_REFRESH_DELAY;
        }

        DEBUG(SSSDBG_TRACE_FUNC, "Data provider is offline. "
              "Scheduling another full refresh in %ld minutes.\n", delay);

        ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx,
                                         SDAP_SUDO_REFRESH_FULL,
                                         sdap_sudo_periodical_first_refresh_done,
                                         delay * 60, timeout,
                                         &sudo_ctx->first_refresh_timer);
        if (ret != EOK) {
            DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule full refresh of sudo "
                  "rules! Periodical updates will not work!\n");
        }

        /* also setup online callback to make sure the refresh is fired as soon
         * as possible */
        ret = be_add_online_cb(sudo_ctx->id_ctx->be, sudo_ctx->id_ctx->be,
                               sdap_sudo_full_refresh_online_cb,
                               sudo_ctx, &sudo_ctx->first_refresh_online_cb);
        if (ret != EOK) {
            DEBUG(SSSDBG_OP_FAILURE, "Could not set up online callback\n");
        }

        return;
    }

    ret = sdap_sudo_schedule_full_refresh(sudo_ctx, delay);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, "Full periodical refresh will not work.\n");
    }

    /* smart refresh */
    delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic,
                           SDAP_SUDO_SMART_REFRESH_INTERVAL);
    if (delay == 0) {
        /* runtime configuration change? */
        DEBUG(SSSDBG_TRACE_FUNC, "Periodical smart refresh of sudo rules "
                                  "is disabled\n");
        return;
    }

    ret = sdap_sudo_schedule_smart_refresh(sudo_ctx, delay);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, "Smart periodical refresh will not work.\n");
    }
}
Пример #15
0
static void assert_nondefault_int_set(struct dp_option *opts)
{
    int i;
    i = dp_opt_get_int(opts, OPT_INT_NODEFAULT);
    assert_int_equal(i, 456);
}
Пример #16
0
static int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx)
{
    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
    time_t smart_default;
    time_t smart_interval;
    time_t full_interval;
    time_t last_full;
    time_t delay;
    int ret;

    smart_interval = dp_opt_get_int(id_ctx->opts->basic,
                                    SDAP_SUDO_SMART_REFRESH_INTERVAL);

    full_interval = dp_opt_get_int(id_ctx->opts->basic,
                                   SDAP_SUDO_FULL_REFRESH_INTERVAL);

    if (smart_interval == 0 && full_interval == 0) {
        smart_default = id_ctx->opts->basic[SDAP_SUDO_SMART_REFRESH_INTERVAL].def_val.number;

        DEBUG(SSSDBG_MINOR_FAILURE, "At least one periodical update has to be "
              "enabled. Setting smart refresh interval to default value (%ld).\n",
              smart_default);

        ret = dp_opt_set_int(id_ctx->opts->basic,
                             SDAP_SUDO_SMART_REFRESH_INTERVAL,
                             smart_default);
        if (ret != EOK) {
            return ret;
        }
    }

    if (full_interval <= smart_interval) {
        DEBUG(SSSDBG_MINOR_FAILURE, "Full refresh interval has to be greater"
              "than smart refresh interval. Periodical full refresh will be "
              "disabled.\n");
        ret = dp_opt_set_int(id_ctx->opts->basic,
                             SDAP_SUDO_FULL_REFRESH_INTERVAL,
                             0);
        if (ret != EOK) {
            return ret;
        }
    }

    ret = sysdb_sudo_get_last_full_refresh(id_ctx->be->domain,
                                           &last_full);
    if (ret != EOK) {
        return ret;
    }

    if (last_full == 0) {
        /* If this is the first startup, we need to kick off
         * an refresh immediately, to close a window where
         * clients requesting sudo information won't get an
         * immediate reply with no entries
         */
        delay = 0;
    } else {
        /* At least one update has previously run,
         * so clients will get cached data.
         * We will delay the refresh so we don't slow
         * down the startup process if this is happening
         * during system boot.
         */

        /* delay at least by 10s */
        delay = 10;
    }

    ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx,
                                     SDAP_SUDO_REFRESH_FULL,
                                     sdap_sudo_periodical_first_refresh_done,
                                     delay, full_interval, NULL);
    if (ret != EOK) {
        DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule full refresh of sudo "
              "rules! Periodical updates will not work!\n");
        return ret;
    }

    return EOK;
}
Пример #17
0
errno_t
sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx,
                              struct dp_option *opts,
                              be_ptask_send_t full_send_fn,
                              be_ptask_recv_t full_recv_fn,
                              be_ptask_send_t smart_send_fn,
                              be_ptask_recv_t smart_recv_fn,
                              void *pvt)
{
    time_t smart;
    time_t full;
    time_t delay;
    time_t last_refresh;
    errno_t ret;

    smart = dp_opt_get_int(opts, SDAP_SUDO_SMART_REFRESH_INTERVAL);
    full = dp_opt_get_int(opts, SDAP_SUDO_FULL_REFRESH_INTERVAL);

    if (smart == 0 && full == 0) {
        /* We don't allow both types to be disabled. At least smart refresh
         * needs to be enabled. In this case smart refresh will catch up new
         * and modified rules and deleted rules are caught when expired. */
        smart = opts[SDAP_SUDO_SMART_REFRESH_INTERVAL].def_val.number;

        DEBUG(SSSDBG_CONF_SETTINGS, "At least smart refresh needs to be "
              "enabled. Setting smart refresh interval to default value "
              "(%ld) seconds.\n", smart);
    } else if (full > 0 && full <= smart) {
        /* In this case it does not make any sense to run smart refresh. */
        smart = 0;

        DEBUG(SSSDBG_CONF_SETTINGS, "Smart refresh interval has to be lower "
              "than full refresh interval. Periodical smart refresh will be "
              "disabled.\n");
    }

    ret = sysdb_sudo_get_last_full_refresh(be_ctx->domain, &last_refresh);
    if (ret != EOK) {
        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to obtain time of last full "
              "refresh. Assuming none was performed so far.\n");
        last_refresh = 0;
    }

    if (last_refresh == 0) {
        /* If this is the first startup, we need to kick off an refresh
         * immediately, to close a window where clients requesting sudo
         * information won't get an immediate reply with no entries */
        delay = 0;
    } else {
        /* At least one update has previously run, so clients will get cached
         * data. We will delay the refresh so we don't slow down the startup
         * process if this is happening during system boot. */
        delay = 10;
    }

    /* Full refresh.
     *
     * Disable when offline and run immediately when SSSD goes back online.
     * Since we have periodical online check we don't have to run this task
     * when offline. */
    if (full > 0) {
        ret = be_ptask_create(be_ctx, be_ctx, full, delay, 0, 0, full,
                              BE_PTASK_OFFLINE_DISABLE, 0,
                              full_send_fn, full_recv_fn, pvt,
                              "SUDO Full Refresh", NULL);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask "
                  "[%d]: %s\n", ret, sss_strerror(ret));
            return ret;
        }
    }

    /* Smart refresh.
     *
     * Disable when offline and reschedule normally when SSSD goes back online.
     * Since we have periodical online check we don't have to run this task
     * when offline. */
    if (smart > 0) {
        ret = be_ptask_create(be_ctx, be_ctx, smart, delay + smart, smart, 0,
                              smart, BE_PTASK_OFFLINE_DISABLE, 0,
                              smart_send_fn, smart_recv_fn, pvt,
                              "SUDO Smart Refresh", NULL);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask "
                  "[%d]: %s\n", ret, sss_strerror(ret));
            return ret;
        }
    }

    return EOK;
}
Пример #18
0
int ldap_get_options(TALLOC_CTX *memctx,
                     struct sss_domain_info *dom,
                     struct confdb_ctx *cdb,
                     const char *conf_path,
                     struct data_provider *dp,
                     struct sdap_options **_opts)
{
    struct sdap_attr_map *default_attr_map;
    struct sdap_attr_map *default_user_map;
    struct sdap_attr_map *default_group_map;
    struct sdap_attr_map *default_netgroup_map;
    struct sdap_attr_map *default_host_map;
    struct sdap_attr_map *default_service_map;
    struct sdap_options *opts;
    char *schema;
    char *pwmodify;
    const char *search_base;
    const char *pwd_policy;
    int ret;
    int account_cache_expiration;
    int offline_credentials_expiration;
    const char *ldap_deref;
    int ldap_deref_val;
    int o;
    const char *authtok_type;
    struct dp_opt_blob authtok_blob;
    char *cleartext;
    const int search_base_options[] = { SDAP_USER_SEARCH_BASE,
                                        SDAP_GROUP_SEARCH_BASE,
                                        SDAP_NETGROUP_SEARCH_BASE,
                                        SDAP_HOST_SEARCH_BASE,
                                        SDAP_SERVICE_SEARCH_BASE,
                                        -1 };

    opts = talloc_zero(memctx, struct sdap_options);
    if (!opts) return ENOMEM;
    opts->dp = dp;

    ret = sdap_domain_add(opts, dom, NULL);
    if (ret != EOK) {
        goto done;
    }

    ret = dp_get_options(opts, cdb, conf_path,
                         default_basic_opts,
                         SDAP_OPTS_BASIC,
                         &opts->basic);
    if (ret != EOK) {
        goto done;
    }

    /* Handle search bases */
    search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
    if (search_base != NULL) {
        /* set user/group/netgroup search bases if they are not */
        for (o = 0; search_base_options[o] != -1; o++) {
            if (NULL == dp_opt_get_string(opts->basic, search_base_options[o])) {
                ret = dp_opt_set_string(opts->basic, search_base_options[o],
                                        search_base);
                if (ret != EOK) {
                    goto done;
                }
                DEBUG(SSSDBG_TRACE_FUNC, "Option %s set to %s\n",
                          opts->basic[search_base_options[o]].opt_name,
                          dp_opt_get_string(opts->basic,
                                            search_base_options[o]));
            }
        }
    } else {
        DEBUG(SSSDBG_FUNC_DATA,
              "Search base not set, trying to discover it later when "
                  "connecting to the LDAP server.\n");
    }

    /* Default search */
    ret = sdap_parse_search_base(opts, opts->basic,
                                 SDAP_SEARCH_BASE,
                                 &opts->sdom->search_bases);
    if (ret != EOK && ret != ENOENT) goto done;

    /* User search */
    ret = sdap_parse_search_base(opts, opts->basic,
                                 SDAP_USER_SEARCH_BASE,
                                 &opts->sdom->user_search_bases);
    if (ret != EOK && ret != ENOENT) goto done;

    /* Group search base */
    ret = sdap_parse_search_base(opts, opts->basic,
                                 SDAP_GROUP_SEARCH_BASE,
                                 &opts->sdom->group_search_bases);
    if (ret != EOK && ret != ENOENT) goto done;

    /* Netgroup search */
    ret = sdap_parse_search_base(opts, opts->basic,
                                 SDAP_NETGROUP_SEARCH_BASE,
                                 &opts->sdom->netgroup_search_bases);
    if (ret != EOK && ret != ENOENT) goto done;

    /* Netgroup search */
    ret = sdap_parse_search_base(opts, opts->basic,
                                 SDAP_HOST_SEARCH_BASE,
                                 &opts->sdom->host_search_bases);
    if (ret != EOK && ret != ENOENT) goto done;

    /* Service search */
    ret = sdap_parse_search_base(opts, opts->basic,
                                 SDAP_SERVICE_SEARCH_BASE,
                                 &opts->sdom->service_search_bases);
    if (ret != EOK && ret != ENOENT) goto done;

    pwd_policy = dp_opt_get_string(opts->basic, SDAP_PWD_POLICY);
    if (pwd_policy == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Missing password policy, this may not happen.\n");
        ret = EINVAL;
        goto done;
    }
    if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) != 0 &&
        strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) != 0 &&
        strcasecmp(pwd_policy, PWD_POL_OPT_MIT) != 0) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Unsupported password policy [%s].\n", pwd_policy);
        ret = EINVAL;
        goto done;
    }

    /* account_cache_expiration must be >= than offline_credentials_expiration */
    ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
                         CONFDB_PAM_CRED_TIMEOUT, 0,
                         &offline_credentials_expiration);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get value of %s from confdb \n",
                  CONFDB_PAM_CRED_TIMEOUT);
        goto done;
    }

    account_cache_expiration = dp_opt_get_int(opts->basic,
                                              SDAP_ACCOUNT_CACHE_EXPIRATION);

    /* account cache_expiration must not be smaller than
     * offline_credentials_expiration to prevent deleting entries that
     * still contain credentials valid for offline login.
     *
     * offline_credentials_expiration == 0 is a special case that says
     * that the cached credentials are valid forever. Therefore, the cached
     * entries must not be purged from cache.
     */
    if (!offline_credentials_expiration && account_cache_expiration) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "Conflicting values for options %s (unlimited) "
                  "and %s (%d)\n",
                  opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
                  CONFDB_PAM_CRED_TIMEOUT,
                  offline_credentials_expiration);
        ret = EINVAL;
        goto done;
    }
    if (offline_credentials_expiration && account_cache_expiration &&
        offline_credentials_expiration > account_cache_expiration) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Value of %s (now %d) must be larger "
                  "than value of %s (now %d)\n",
                  opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
                  account_cache_expiration,
                  CONFDB_PAM_CRED_TIMEOUT,
                  offline_credentials_expiration);
        ret = EINVAL;
        goto done;
    }

    ldap_deref = dp_opt_get_string(opts->basic, SDAP_DEREF);
    if (ldap_deref != NULL) {
        ret = deref_string_to_val(ldap_deref, &ldap_deref_val);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to verify ldap_deref option.\n");
            goto done;
        }
    }

#ifndef HAVE_LDAP_CONNCB
    bool ldap_referrals;

    ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS);
    if (ldap_referrals) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "LDAP referrals are not supported, because the LDAP library "
                  "is too old, see sssd-ldap(5) for details.\n");
        ret = dp_opt_set_bool(opts->basic, SDAP_REFERRALS, false);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n");
            goto done;
        }
    }
#endif

    /* schema type */
    schema = dp_opt_get_string(opts->basic, SDAP_SCHEMA);
    if (strcasecmp(schema, "rfc2307") == 0) {
        opts->schema_type = SDAP_SCHEMA_RFC2307;
        default_attr_map = generic_attr_map;
        default_user_map = rfc2307_user_map;
        default_group_map = rfc2307_group_map;
        default_netgroup_map = netgroup_map;
        default_host_map = host_map;
        default_service_map = service_map;
    } else
    if (strcasecmp(schema, "rfc2307bis") == 0) {
        opts->schema_type = SDAP_SCHEMA_RFC2307BIS;
        default_attr_map = generic_attr_map;
        default_user_map = rfc2307bis_user_map;
        default_group_map = rfc2307bis_group_map;
        default_netgroup_map = netgroup_map;
        default_host_map = host_map;
        default_service_map = service_map;
    } else
    if (strcasecmp(schema, "IPA") == 0) {
        opts->schema_type = SDAP_SCHEMA_IPA_V1;
        default_attr_map = gen_ipa_attr_map;
        default_user_map = rfc2307bis_user_map;
        default_group_map = rfc2307bis_group_map;
        default_netgroup_map = netgroup_map;
        default_host_map = host_map;
        default_service_map = service_map;
    } else
    if (strcasecmp(schema, "AD") == 0) {
        opts->schema_type = SDAP_SCHEMA_AD;
        default_attr_map = gen_ad_attr_map;
        default_user_map = gen_ad2008r2_user_map;
        default_group_map = gen_ad2008r2_group_map;
        default_netgroup_map = netgroup_map;
        default_host_map = host_map;
        default_service_map = service_map;
    } else {
        DEBUG(SSSDBG_FATAL_FAILURE, "Unrecognized schema type: %s\n", schema);
        ret = EINVAL;
        goto done;
    }

    /* pwmodify mode */
    pwmodify = dp_opt_get_string(opts->basic, SDAP_PWMODIFY_MODE);
    if (strcasecmp(pwmodify, "exop") == 0) {
        opts->pwmodify_mode = SDAP_PWMODIFY_EXOP;
    } else if (strcasecmp(pwmodify, "ldap_modify") == 0) {
        opts->pwmodify_mode = SDAP_PWMODIFY_LDAP;
    } else {
        DEBUG(SSSDBG_FATAL_FAILURE, "Unrecognized pwmodify mode: %s\n", pwmodify);
        ret = EINVAL;
        goto done;
    }

    ret = sdap_get_map(opts, cdb, conf_path,
                       default_attr_map,
                       SDAP_AT_GENERAL,
                       &opts->gen_map);
    if (ret != EOK) {
        goto done;
    }

    ret = sdap_get_map(opts, cdb, conf_path,
                       default_user_map,
                       SDAP_OPTS_USER,
                       &opts->user_map);
    if (ret != EOK) {
        goto done;
    }

    ret = sdap_extend_map_with_list(opts, opts, SDAP_USER_EXTRA_ATTRS,
                                    opts->user_map, SDAP_OPTS_USER,
                                    &opts->user_map, &opts->user_map_cnt);
    if (ret != EOK) {
        goto done;
    }

    ret = sdap_get_map(opts, cdb, conf_path,
                       default_group_map,
                       SDAP_OPTS_GROUP,
                       &opts->group_map);
    if (ret != EOK) {
        goto done;
    }

    ret = sdap_get_map(opts, cdb, conf_path,
                       default_netgroup_map,
                       SDAP_OPTS_NETGROUP,
                       &opts->netgroup_map);
    if (ret != EOK) {
        goto done;
    }

    ret = sdap_get_map(opts, cdb, conf_path,
                       default_host_map,
                       SDAP_OPTS_HOST,
                       &opts->host_map);
    if (ret != EOK) {
        goto done;
    }

    ret = sdap_get_map(opts, cdb, conf_path,
                       default_service_map,
                       SDAP_OPTS_SERVICES,
                       &opts->service_map);
    if (ret != EOK) {
        goto done;
    }

    /* If there is no KDC, try the deprecated krb5_kdcip option, too */
    /* FIXME - this can be removed in a future version */
    ret = krb5_try_kdcip(cdb, conf_path, opts->basic, SDAP_KRB5_KDC);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "sss_krb5_try_kdcip failed.\n");
        goto done;
    }

    authtok_type = dp_opt_get_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE);
    if (authtok_type != NULL &&
        strcasecmp(authtok_type,"obfuscated_password") == 0) {
        DEBUG(SSSDBG_TRACE_ALL, "Found obfuscated password, "
                  "trying to convert to cleartext.\n");

        authtok_blob = dp_opt_get_blob(opts->basic, SDAP_DEFAULT_AUTHTOK);
        if (authtok_blob.data == NULL || authtok_blob.length == 0) {
            DEBUG(SSSDBG_CRIT_FAILURE, "Missing obfuscated password string.\n");
            ret = EINVAL;
            goto done;
        }

        ret = sss_password_decrypt(memctx, (char *) authtok_blob.data,
                                   &cleartext);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot convert the obfuscated "
                      "password back to cleartext\n");
            goto done;
        }

        authtok_blob.data = (uint8_t *) cleartext;
        authtok_blob.length = strlen(cleartext);
        ret = dp_opt_set_blob(opts->basic, SDAP_DEFAULT_AUTHTOK, authtok_blob);
        talloc_free(cleartext);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n");
            goto done;
        }

        ret = dp_opt_set_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE,
                                "password");
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n");
            goto done;
        }
    }

    ret = EOK;
    *_opts = opts;

done:
    if (ret != EOK) {
        talloc_zfree(opts);
    }
    return ret;
}