Example #1
0
errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx,
                                  struct sss_domain_info *domain,
                                  const char *name,
                                  struct ldb_result **res)
{
    int ret;
    struct ldb_result *orig_obj = NULL;
    struct ldb_result *override_obj = NULL;
    TALLOC_CTX *tmp_ctx;

    tmp_ctx = talloc_new(NULL);
    if (tmp_ctx == NULL) {
        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
        return ENOMEM;
    }

    /* If there are views we first have to search the overrides for matches */
    if (DOM_HAS_VIEWS(domain)) {
        ret = sysdb_search_user_override_by_name(tmp_ctx, domain, name,
                                                 &override_obj, &orig_obj);
        if (ret != EOK && ret != ENOENT) {
            DEBUG(SSSDBG_OP_FAILURE,
                  "sysdb_search_override_by_name failed.\n");
            goto done;
        }
    }

    /* If there are no views or nothing was found in the overrides the
     * original objects are searched. */
    if (orig_obj == NULL) {
        ret = sysdb_getpwnam(tmp_ctx, domain, name, &orig_obj);
        if (ret != EOK) {
            DEBUG(SSSDBG_OP_FAILURE, "sysdb_getpwnam failed.\n");
            goto done;
        }
    }

    /* If there are views we have to check if override values must be added to
     * the original object. */
    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
        ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
                          override_obj == NULL ? NULL : override_obj->msgs[0],
                          NULL);
        if (ret != EOK && ret != ENOENT) {
            DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n");
            goto done;
        }

        if (ret == ENOENT) {
            *res = talloc_zero(mem_ctx, struct ldb_result);
            if (*res == NULL) {
                DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
                ret = ENOMEM;
            } else {
                ret = EOK;
            }
            goto done;
        }
Example #2
0
static int pam_check_user_search(struct pam_auth_req *preq)
{
    struct sss_domain_info *dom = preq->domain;
    char *name = NULL;
    time_t cacheExpire;
    int ret;
    struct tevent_req *dpreq;
    struct dp_callback_ctx *cb_ctx;
    struct pam_ctx *pctx =
            talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);

    while (dom) {
       /* if it is a domainless search, skip domains that require fully
         * qualified names instead */
        while (dom && !preq->pd->domain && dom->fqnames) {
            dom = get_next_domain(dom, false);
        }

        if (!dom) break;

        if (dom != preq->domain) {
            /* make sure we reset the check_provider flag when we check
             * a new domain */
            preq->check_provider = NEED_CHECK_PROVIDER(dom->provider);
        }

        /* make sure to update the preq if we changed domain */
        preq->domain = dom;

        talloc_free(name);
        name = sss_get_cased_name(preq, preq->pd->user,
                                  dom->case_sensitive);
        if (!name) {
            return ENOMEM;
        }

        name = sss_reverse_replace_space(preq, name,
                                         pctx->rctx->override_space);
        if (name == NULL) {
            DEBUG(SSSDBG_CRIT_FAILURE,
                  "sss_reverse_replace_space failed\n");
            return ENOMEM;
        }

        /* Refresh the user's cache entry on any PAM query
         * We put a timeout in the client context so that we limit
         * the number of updates within a reasonable timeout
         */
        if (preq->check_provider) {
            ret = pam_initgr_check_timeout(pctx->id_table, name);
            if (ret != EOK
                    && ret != ENOENT) {
                DEBUG(SSSDBG_OP_FAILURE,
                      "Could not look up initgroup timout\n");
                return EIO;
            } else if (ret == ENOENT) {
                /* Call provider first */
                break;
            }
            /* Entry is still valid, get it from the sysdb */
        }

        DEBUG(SSSDBG_CONF_SETTINGS,
              "Requesting info for [%s@%s]\n", name, dom->name);

        if (dom->sysdb == NULL) {
            DEBUG(SSSDBG_FATAL_FAILURE,
                  "Fatal: Sysdb CTX not found for this domain!\n");
            preq->pd->pam_status = PAM_SYSTEM_ERR;
            return EFAULT;
        }

        ret = sysdb_getpwnam(preq, dom, name, &preq->res);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE,
                  "Failed to make request to our cache!\n");
            return EIO;
        }

        if (preq->res->count > 1) {
            DEBUG(SSSDBG_FATAL_FAILURE,
                  "getpwnam call returned more than one result !?!\n");
            return ENOENT;
        }

        if (preq->res->count == 0) {
            if (preq->check_provider == false) {
                /* set negative cache only if not result of cache check */
                ret = sss_ncache_set_user(pctx->ncache, false, dom, name);
                if (ret != EOK) {
                    /* Should not be fatal, just slower next time */
                    DEBUG(SSSDBG_MINOR_FAILURE,
                           "Cannot set ncache for [%s@%s]\n", name,
                            dom->name);
                }
            }

            /* if a multidomain search, try with next */
            if (!preq->pd->domain) {
                dom = get_next_domain(dom, false);
                continue;
            }

            DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n");

            /* TODO: store negative cache ? */

            return ENOENT;
        }

        /* One result found */

        /* if we need to check the remote account go on */
        if (preq->check_provider) {
            cacheExpire = ldb_msg_find_attr_as_uint64(preq->res->msgs[0],
                                                      SYSDB_CACHE_EXPIRE, 0);
            if (cacheExpire < time(NULL)) {
                break;
            }
        }

        DEBUG(SSSDBG_TRACE_FUNC,
              "Returning info for user [%s@%s]\n", name, dom->name);

        /* We might have searched by alias. Pass on the primary name */
        ret = pd_set_primary_name(preq->res->msgs[0], preq->pd);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "Could not canonicalize username\n");
            return ret;
        }

        return EOK;
    }

    if (!dom) {
        /* Ensure that we don't try to check a provider without a domain,
         * since this will cause a NULL-dereference below.
         */
        preq->check_provider = false;
    }

    if (preq->check_provider) {

        /* dont loop forever :-) */
        preq->check_provider = false;

        dpreq = sss_dp_get_account_send(preq, preq->cctx->rctx,
                                        dom, false, SSS_DP_INITGROUPS,
                                        name, 0, NULL);
        if (!dpreq) {
            DEBUG(SSSDBG_CRIT_FAILURE,
                  "Out of memory sending data provider request\n");
            return ENOMEM;
        }

        cb_ctx = talloc_zero(preq, struct dp_callback_ctx);
        if(!cb_ctx) {
            talloc_zfree(dpreq);
            return ENOMEM;
        }

        cb_ctx->callback = pam_check_user_dp_callback;
        cb_ctx->ptr = preq;
        cb_ctx->cctx = preq->cctx;
        cb_ctx->mem_ctx = preq;

        tevent_req_set_callback(dpreq, pam_dp_send_acct_req_done, cb_ctx);

        /* tell caller we are in an async call */
        return EAGAIN;
    }
Example #3
0
/*
 * getpwnam, getgrnam and friends
 */
int sysdb_getpwnam_sync(TALLOC_CTX *mem_ctx,
                        struct sysdb_ctx *sysdb,
                        const char *name,
                        struct ops_ctx *out)
{
    struct ldb_result *res;
    const char *str;
    int ret;

    ret = sysdb_getpwnam(mem_ctx, sysdb, name, &res);
    if (ret) {
        return ret;
    }

    switch (res->count) {
    case 0:
        DEBUG(1, ("No result for sysdb_getpwnam call\n"));
        return ENOENT;

    case 1:
        /* fill ops_ctx */
        out->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);

        out->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0);

        str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
        out->name = talloc_strdup(out, str);
        if (out->name == NULL) {
            return ENOMEM;
        }

        str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_GECOS, NULL);
        out->gecos = talloc_strdup(out, str);
        if (out->gecos == NULL) {
            return ENOMEM;
        }

        str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR, NULL);
        out->home = talloc_strdup(out, str);
        if (out->home == NULL) {
            return ENOMEM;
        }

        str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SHELL, NULL);
        out->shell = talloc_strdup(out, str);
        if (out->shell == NULL) {
            return ENOMEM;
        }

        str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_DISABLED, NULL);
        if (str == NULL) {
            out->lock = DO_UNLOCK;
        } else {
            if (strcasecmp(str, "true") == 0) {
                out->lock = DO_LOCK;
            } else if (strcasecmp(str, "false") == 0) {
                out->lock = DO_UNLOCK;
            } else { /* Invalid value */
                DEBUG(2, ("Invalid value for %s attribute: %s\n",
                          SYSDB_DISABLED, str ? str : "NULL"));
                return EIO;
            }
        }
        break;

    default:
        DEBUG(1, ("More than one result for sysdb_getpwnam call\n"));
        return EIO;
    }

    return EOK;
}
Example #4
0
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;
    }
Example #5
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;
}