LCOV - code coverage report
Current view: top level - providers/simple - simple_access_check.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 170 365 46.6 %
Date: 2015-10-19 Functions: 10 15 66.7 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    Simple access control
       5             : 
       6             :    Copyright (C) Sumit Bose <sbose@redhat.com> 2010
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "providers/dp_backend.h"
      23             : #include "providers/simple/simple_access.h"
      24             : #include "util/sss_utf8.h"
      25             : #include "db/sysdb.h"
      26             : 
      27             : #define NON_EXIST_USR_ALLOW "The user %s does not exist. Possible typo in simple_allow_users.\n"
      28             : #define NON_EXIST_USR_DENY  "The user %s does not exist. Possible typo in simple_deny_users.\n"
      29             : #define NON_EXIST_GRP_ALLOW "The group %s does not exist. Possible typo in simple_allow_groups.\n"
      30             : #define NON_EXIST_GRP_DENY  "The group %s does not exist. Possible typo in simple_deny_groups.\n"
      31             : 
      32             : static bool
      33          13 : is_posix(const struct ldb_message *group)
      34             : {
      35             :     const char *val;
      36             : 
      37          13 :     val = ldb_msg_find_attr_as_string(group, SYSDB_POSIX, NULL);
      38          26 :     if (!val || /* Groups are posix by default */
      39          13 :         strcasecmp(val, "TRUE") == 0) {
      40          13 :         return true;
      41             :     }
      42             : 
      43           0 :     return false;
      44             : }
      45             : 
      46             : /* Returns EOK if the result is definitive, EAGAIN if only partial result
      47             :  */
      48             : static errno_t
      49          18 : simple_check_users(struct simple_ctx *ctx, const char *username,
      50             :                    bool *access_granted)
      51             : {
      52          18 :     struct sss_domain_info *domain = NULL;
      53             :     int i;
      54             : 
      55             :     /* First, check whether the user is in the allowed users list */
      56          18 :     if (ctx->allow_users != NULL) {
      57          15 :         for(i = 0; ctx->allow_users[i] != NULL; i++) {
      58          11 :             domain = find_domain_by_object_name(ctx->domain,
      59          11 :                                                 ctx->allow_users[i]);
      60          11 :             if (domain == NULL) {
      61           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_USR_ALLOW,
      62             :                       ctx->allow_users[i]);
      63           0 :                 sss_log(SSS_LOG_CRIT, NON_EXIST_USR_ALLOW,
      64           0 :                         ctx->allow_users[i]);
      65           0 :                 continue;
      66             :             }
      67             : 
      68          11 :             if (sss_string_equal(domain->case_sensitive, username,
      69          11 :                                  ctx->allow_users[i])) {
      70           3 :                 DEBUG(SSSDBG_TRACE_LIBS,
      71             :                       "User [%s] found in allow list, access granted.\n",
      72             :                       username);
      73             : 
      74             :                 /* Do not return immediately on explicit allow
      75             :                  * We need to make sure none of the user's groups
      76             :                  * are denied. But there's no need to check username
      77             :                  * matches any more.
      78             :                  */
      79           3 :                 *access_granted = true;
      80           3 :                 break;
      81             :             }
      82             :         }
      83          11 :     } else if (!ctx->allow_groups) {
      84             :         /* If neither allow rule is in place, we'll assume allowed
      85             :          * unless a deny rule disables us below.
      86             :          */
      87           5 :         DEBUG(SSSDBG_TRACE_LIBS,
      88             :               "No allow rule, assumuing allow unless explicitly denied\n");
      89           5 :         *access_granted = true;
      90             :     }
      91             : 
      92             :     /* Next check whether this user has been specifically denied */
      93          18 :     if (ctx->deny_users != NULL) {
      94           8 :         for(i = 0; ctx->deny_users[i] != NULL; i++) {
      95           6 :             domain = find_domain_by_object_name(ctx->domain,
      96           6 :                                                 ctx->deny_users[i]);
      97           6 :             if (domain == NULL) {
      98           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_USR_DENY,
      99             :                       ctx->deny_users[i]);
     100           0 :                 sss_log(SSS_LOG_CRIT, NON_EXIST_USR_DENY,
     101           0 :                         ctx->deny_users[i]);
     102           0 :                 return EINVAL;
     103             :             }
     104             : 
     105           6 :             if (sss_string_equal(domain->case_sensitive, username,
     106           6 :                                  ctx->deny_users[i])) {
     107           2 :                 DEBUG(SSSDBG_TRACE_LIBS,
     108             :                       "User [%s] found in deny list, access denied.\n",
     109             :                         ctx->deny_users[i]);
     110             : 
     111             :                 /* Return immediately on explicit denial */
     112           2 :                 *access_granted = false;
     113           2 :                 return EOK;
     114             :             }
     115             :         }
     116             :     }
     117             : 
     118          16 :     return EAGAIN;
     119             : }
     120             : 
     121             : static errno_t
     122           8 : simple_check_groups(struct simple_ctx *ctx, const char **group_names,
     123             :                     bool *access_granted)
     124             : {
     125           8 :     struct sss_domain_info *domain = NULL;
     126             :     bool matched;
     127             :     int i, j;
     128             : 
     129             :     /* Now process allow and deny group rules
     130             :      * If access was already granted above, we'll skip
     131             :      * this redundant rule check
     132             :      */
     133           8 :     if (ctx->allow_groups && !*access_granted) {
     134           6 :         matched = false;
     135          14 :         for (i = 0; ctx->allow_groups[i]; i++) {
     136          10 :             domain = find_domain_by_object_name(ctx->domain,
     137          10 :                                                 ctx->allow_groups[i]);
     138          10 :             if (domain == NULL) {
     139           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_GRP_ALLOW,
     140             :                       ctx->allow_groups[i]);
     141           0 :                 sss_log(SSS_LOG_CRIT, NON_EXIST_GRP_ALLOW,
     142           0 :                         ctx->allow_groups[i]);
     143             : 
     144           0 :                 continue;
     145             :             }
     146             : 
     147          22 :             for(j = 0; group_names[j]; j++) {
     148          28 :                 if (sss_string_equal(domain->case_sensitive,
     149          28 :                                      group_names[j], ctx->allow_groups[i])) {
     150           2 :                     matched = true;
     151           2 :                     break;
     152             :                 }
     153             :             }
     154             : 
     155             :             /* If any group has matched, we can skip out on the
     156             :              * processing early
     157             :              */
     158          10 :             if (matched) {
     159           2 :                 DEBUG(SSSDBG_TRACE_LIBS,
     160             :                       "Group [%s] found in allow list, access granted.\n",
     161             :                       group_names[j]);
     162           2 :                 *access_granted = true;
     163           2 :                 break;
     164             :             }
     165             :         }
     166             :     }
     167             : 
     168             :     /* Finally, process the deny group rules */
     169           8 :     if (ctx->deny_groups) {
     170           4 :         matched = false;
     171          10 :         for (i = 0; ctx->deny_groups[i]; i++) {
     172           7 :             domain = find_domain_by_object_name(ctx->domain,
     173           7 :                                                 ctx->deny_groups[i]);
     174           7 :             if (domain == NULL) {
     175           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_GRP_DENY,
     176             :                       ctx->deny_groups[i]);
     177           0 :                 sss_log(SSS_LOG_CRIT, NON_EXIST_GRP_DENY,
     178           0 :                         ctx->deny_groups[i]);
     179             : 
     180           0 :                 return EINVAL;
     181             :             }
     182             : 
     183          15 :             for(j = 0; group_names[j]; j++) {
     184          18 :                 if (sss_string_equal(domain->case_sensitive,
     185          18 :                                      group_names[j], ctx->deny_groups[i])) {
     186           1 :                     matched = true;
     187           1 :                     break;
     188             :                 }
     189             :             }
     190             : 
     191             :             /* If any group has matched, we can skip out on the
     192             :              * processing early
     193             :              */
     194           7 :             if (matched) {
     195           1 :                 DEBUG(SSSDBG_TRACE_LIBS,
     196             :                       "Group [%s] found in deny list, access denied.\n",
     197             :                       group_names[j]);
     198           1 :                 *access_granted = false;
     199           1 :                 break;
     200             :             }
     201             :         }
     202             :     }
     203             : 
     204           8 :     return EOK;
     205             : }
     206             : 
     207             : struct simple_resolve_group_state {
     208             :     struct sss_domain_info *domain;
     209             :     gid_t gid;
     210             :     struct simple_ctx *ctx;
     211             : 
     212             :     const char *name;
     213             : };
     214             : 
     215             : static errno_t
     216             : simple_resolve_group_check(struct simple_resolve_group_state *state);
     217             : static void simple_resolve_group_done(struct tevent_req *subreq);
     218             : 
     219             : static struct tevent_req *
     220           0 : simple_resolve_group_send(TALLOC_CTX *mem_ctx,
     221             :                           struct tevent_context *ev,
     222             :                           struct simple_ctx *ctx,
     223             :                           struct sss_domain_info *domain,
     224             :                           gid_t gid)
     225             : {
     226             :     errno_t ret;
     227             :     struct tevent_req *req;
     228             :     struct tevent_req *subreq;
     229             :     struct simple_resolve_group_state *state;
     230             :     struct be_acct_req *ar;
     231             : 
     232           0 :     req = tevent_req_create(mem_ctx, &state,
     233             :                             struct simple_resolve_group_state);
     234           0 :     if (!req) return NULL;
     235             : 
     236           0 :     state->domain = domain;
     237           0 :     state->gid = gid;
     238           0 :     state->ctx = ctx;
     239             : 
     240             :     /* First check if the group was updated already. If it was (maybe its
     241             :      * parent was updated first), then just shortcut */
     242           0 :     ret = simple_resolve_group_check(state);
     243           0 :     if (ret == EOK) {
     244           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Group already updated\n");
     245           0 :         ret = EOK;
     246           0 :         goto done;
     247           0 :     } else if (ret != EAGAIN) {
     248           0 :         DEBUG(SSSDBG_OP_FAILURE,
     249             :               "Cannot check if group was already updated [%d]: %s\n",
     250             :                ret, sss_strerror(ret));
     251           0 :         goto done;
     252             :     }
     253             :     /* EAGAIN - still needs update */
     254             : 
     255           0 :     ar = talloc(state, struct be_acct_req);
     256           0 :     if (!ar) {
     257           0 :         ret = ENOMEM;
     258           0 :         goto done;
     259             :     }
     260             : 
     261           0 :     ar->entry_type = BE_REQ_GROUP;
     262           0 :     ar->attr_type = BE_ATTR_CORE;
     263           0 :     ar->filter_type = BE_FILTER_IDNUM;
     264           0 :     ar->filter_value = talloc_asprintf(ar, "%llu", (unsigned long long) gid);
     265           0 :     ar->domain = talloc_strdup(ar, state->domain->name);
     266           0 :     if (!ar->domain || !ar->filter_value) {
     267           0 :         ret = ENOMEM;
     268           0 :         goto done;
     269             :     }
     270             : 
     271           0 :     subreq = be_get_account_info_send(state, ev, NULL, ctx->be_ctx, ar);
     272           0 :     if (!subreq) {
     273           0 :         ret = ENOMEM;
     274           0 :         goto done;
     275             :     }
     276           0 :     tevent_req_set_callback(subreq, simple_resolve_group_done, req);
     277             : 
     278           0 :     return req;
     279             : 
     280             : done:
     281           0 :     if (ret == EOK) {
     282           0 :         tevent_req_done(req);
     283             :     } else {
     284           0 :         tevent_req_error(req, ret);
     285             :     }
     286           0 :     tevent_req_post(req, ev);
     287           0 :     return req;
     288             : }
     289             : 
     290             : static errno_t
     291           0 : simple_resolve_group_check(struct simple_resolve_group_state *state)
     292             : {
     293             :     errno_t ret;
     294             :     struct ldb_message *group;
     295           0 :     const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
     296             :                                   SYSDB_GIDNUM, NULL };
     297             : 
     298             :     /* Check the cache by GID again and fetch the name */
     299           0 :     ret = sysdb_search_group_by_gid(state, state->domain, state->gid,
     300             :                                     group_attrs, &group);
     301           0 :     if (ret == ENOENT) {
     302             :         /* The group is missing, we will try to update it. */
     303           0 :         return EAGAIN;
     304           0 :     } else if (ret != EOK) {
     305           0 :         DEBUG(SSSDBG_OP_FAILURE,
     306             :                "Could not look up group by gid [%"SPRIgid"]: [%d][%s]\n",
     307             :                state->gid, ret, sss_strerror(ret));
     308           0 :         return ret;
     309             :     }
     310             : 
     311           0 :     state->name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
     312           0 :     if (!state->name) {
     313           0 :         DEBUG(SSSDBG_OP_FAILURE, "No group name\n");
     314           0 :         return ERR_ACCOUNT_UNKNOWN;
     315             :     }
     316             : 
     317           0 :     if (is_posix(group) == false) {
     318           0 :         DEBUG(SSSDBG_TRACE_LIBS,
     319             :               "The group is still non-POSIX\n");
     320           0 :         return EAGAIN;
     321             :     }
     322             : 
     323           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Got POSIX group\n");
     324           0 :     return EOK;
     325             : }
     326             : 
     327           0 : static void simple_resolve_group_done(struct tevent_req *subreq)
     328             : {
     329             :     struct tevent_req *req;
     330             :     struct simple_resolve_group_state *state;
     331             :     int err_maj;
     332             :     int err_min;
     333             :     errno_t ret;
     334             :     const char *err_msg;
     335             : 
     336           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
     337           0 :     state = tevent_req_data(req, struct simple_resolve_group_state);
     338             : 
     339           0 :     ret = be_get_account_info_recv(subreq, state,
     340             :                                    &err_maj, &err_min, &err_msg);
     341           0 :     talloc_zfree(subreq);
     342           0 :     if (ret) {
     343           0 :         DEBUG(SSSDBG_OP_FAILURE, "be_get_account_info_recv failed\n");
     344           0 :         tevent_req_error(req, ret);
     345           0 :         return;
     346             :     }
     347             : 
     348           0 :     if (err_maj) {
     349           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     350             :               "Cannot refresh data from DP: %u,%u: %s\n",
     351             :               err_maj, err_min, err_msg);
     352           0 :         tevent_req_error(req, EIO);
     353           0 :         return;
     354             :     }
     355             : 
     356             :     /* Check the cache by GID again and fetch the name */
     357           0 :     ret = simple_resolve_group_check(state);
     358           0 :     if (ret != EOK) {
     359           0 :         DEBUG(SSSDBG_OP_FAILURE, "Refresh failed\n");
     360           0 :         tevent_req_error(req, ret);
     361           0 :         return;
     362             :     }
     363             : 
     364           0 :     tevent_req_done(req);
     365             : }
     366             : 
     367             : static errno_t
     368           0 : simple_resolve_group_recv(struct tevent_req *req,
     369             :                           TALLOC_CTX *mem_ctx,
     370             :                           const char **name)
     371             : {
     372             :     struct simple_resolve_group_state *state;
     373             : 
     374           0 :     state = tevent_req_data(req, struct simple_resolve_group_state);
     375             : 
     376           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     377             : 
     378           0 :     *name = talloc_strdup(mem_ctx, state->name);
     379           0 :     return EOK;
     380             : }
     381             : 
     382             : struct simple_group {
     383             :     struct sss_domain_info *domain;
     384             :     gid_t gid;
     385             : };
     386             : 
     387             : struct simple_check_groups_state {
     388             :     struct tevent_context *ev;
     389             :     struct simple_ctx *ctx;
     390             :     struct sss_domain_info *domain;
     391             : 
     392             :     struct simple_group *lookup_groups;
     393             :     size_t num_groups;
     394             :     size_t giter;
     395             : 
     396             :     const char **group_names;
     397             :     size_t num_names;
     398             : 
     399             :     bool failed_to_resolve_groups;
     400             : };
     401             : 
     402             : static void simple_check_get_groups_next(struct tevent_req *subreq);
     403             : 
     404             : static errno_t
     405             : simple_check_get_groups_primary(struct simple_check_groups_state *state,
     406             :                                 gid_t gid);
     407             : static errno_t
     408             : simple_check_process_group(struct simple_check_groups_state *state,
     409             :                            struct ldb_message *group);
     410             : 
     411             : static struct tevent_req *
     412           8 : simple_check_get_groups_send(TALLOC_CTX *mem_ctx,
     413             :                              struct tevent_context *ev,
     414             :                              struct simple_ctx *ctx,
     415             :                              const char *username)
     416             : {
     417             :     errno_t ret;
     418             :     struct tevent_req *req;
     419             :     struct tevent_req *subreq;
     420             :     struct simple_check_groups_state *state;
     421           8 :     const char *attrs[] = { SYSDB_NAME, SYSDB_POSIX, SYSDB_GIDNUM,
     422             :                             SYSDB_SID_STR, NULL };
     423             :     size_t group_count;
     424             :     struct ldb_message *user;
     425             :     struct ldb_message **groups;
     426             :     int i;
     427             :     gid_t gid;
     428             : 
     429           8 :     req = tevent_req_create(mem_ctx, &state,
     430             :                             struct simple_check_groups_state);
     431           8 :     if (!req) return NULL;
     432             : 
     433           8 :     state->ev = ev;
     434           8 :     state->ctx = ctx;
     435           8 :     state->failed_to_resolve_groups = false;
     436             : 
     437           8 :     DEBUG(SSSDBG_TRACE_LIBS, "Looking up groups for user %s\n", username);
     438             : 
     439             :     /* get domain from username */
     440           8 :     state->domain = find_domain_by_object_name(ctx->domain, username);
     441           8 :     if (state->domain == NULL) {
     442           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid user %s!\n", username);
     443           0 :         ret = EINVAL;
     444           0 :         goto done;
     445             :     }
     446             : 
     447           8 :     ret = sysdb_search_user_by_name(state, state->domain, username, attrs,
     448             :                                     &user);
     449           8 :     if (ret == ENOENT) {
     450           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "No such user %s\n", username);
     451           0 :         ret = ERR_ACCOUNT_UNKNOWN;
     452           0 :         goto done;
     453           8 :     } else if (ret != EOK) {
     454           0 :         DEBUG(SSSDBG_OP_FAILURE,
     455             :               "Could not look up username [%s]: [%d][%s]\n",
     456             :               username, ret, sss_strerror(ret));
     457           0 :         goto done;
     458             :     }
     459             : 
     460           8 :     ret = sysdb_asq_search(state, state->domain,
     461           8 :                            user->dn, NULL, SYSDB_MEMBEROF,
     462             :                            attrs, &group_count, &groups);
     463           8 :     if (ret != EOK) {
     464           0 :         goto done;
     465             :     }
     466             : 
     467           8 :     DEBUG(SSSDBG_TRACE_FUNC,
     468             :           "User %s is a member of %zu supplemental groups\n",
     469             :            username, group_count);
     470             : 
     471             :     /* One extra space for terminator, one extra space for private group */
     472           8 :     state->group_names = talloc_zero_array(state, const char *, group_count + 2);
     473           8 :     state->lookup_groups = talloc_zero_array(state, struct simple_group,
     474             :                                              group_count + 2);
     475           8 :     if (!state->group_names || !state->lookup_groups) {
     476           0 :         ret = ENOMEM;
     477           0 :         goto done;
     478             :     }
     479             : 
     480          13 :     for (i=0; i < group_count; i++) {
     481             :         /* Some providers (like the AD provider) might perform initgroups
     482             :          * without resolving the group names. In order for the simple access
     483             :          * provider to work correctly, we need to resolve the groups before
     484             :          * performing the access check. In AD provider, the situation is
     485             :          * even more tricky b/c the groups HAVE name, but their name
     486             :          * attribute is set to SID and they are set as non-POSIX
     487             :          */
     488           5 :         ret = simple_check_process_group(state, groups[i]);
     489           5 :         if (ret != EOK) {
     490           0 :             goto done;
     491             :         }
     492             :     }
     493             : 
     494           8 :     gid = ldb_msg_find_attr_as_uint64(user, SYSDB_GIDNUM, 0);
     495           8 :     if (!gid) {
     496           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "User %s has no gid?\n", username);
     497           0 :         ret = EINVAL;
     498           0 :         goto done;
     499             :     }
     500             : 
     501           8 :     ret = simple_check_get_groups_primary(state, gid);
     502           8 :     if (ret != EOK) {
     503           0 :         goto done;
     504             :     }
     505             : 
     506           8 :     if (state->num_groups == 0) {
     507             :         /* If all groups could have been resolved by name, we are
     508             :          * done
     509             :          */
     510           8 :         DEBUG(SSSDBG_TRACE_FUNC, "All groups had name attribute\n");
     511           8 :         ret = EOK;
     512           8 :         goto done;
     513             :     }
     514             : 
     515           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Need to resolve %zu groups\n",
     516             :                               state->num_groups);
     517           0 :     state->giter = 0;
     518           0 :     subreq = simple_resolve_group_send(req, state->ev, state->ctx,
     519           0 :                                        state->lookup_groups[state->giter].domain,
     520           0 :                                        state->lookup_groups[state->giter].gid);
     521           0 :     if (!subreq) {
     522           0 :         ret = ENOMEM;
     523           0 :         goto done;
     524             :     }
     525           0 :     tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
     526             : 
     527           0 :     return req;
     528             : 
     529             : done:
     530           8 :     if (ret == EOK) {
     531           8 :         tevent_req_done(req);
     532             :     } else {
     533           0 :         tevent_req_error(req, ret);
     534             :     }
     535           8 :     tevent_req_post(req, ev);
     536           8 :     return req;
     537             : }
     538             : 
     539           0 : static void simple_check_get_groups_next(struct tevent_req *subreq)
     540             : {
     541           0 :     struct tevent_req *req =
     542           0 :                         tevent_req_callback_data(subreq, struct tevent_req);
     543           0 :     struct simple_check_groups_state *state =
     544           0 :                         tevent_req_data(req, struct simple_check_groups_state);
     545             :     errno_t ret;
     546             : 
     547           0 :     ret = simple_resolve_group_recv(subreq, state->group_names,
     548           0 :                                     &state->group_names[state->num_names]);
     549           0 :     talloc_zfree(subreq);
     550           0 :     if (ret != EOK) {
     551           0 :         DEBUG(SSSDBG_OP_FAILURE,
     552             :               "Could not resolve name of group with GID %"SPRIgid"\n",
     553             :               state->lookup_groups[state->giter].gid);
     554           0 :         state->failed_to_resolve_groups = true;
     555             :     } else {
     556           0 :         state->num_names++;
     557             :     }
     558           0 :     state->giter++;
     559             : 
     560           0 :     if (state->giter < state->num_groups) {
     561           0 :         subreq = simple_resolve_group_send(req, state->ev, state->ctx,
     562           0 :                                    state->lookup_groups[state->giter].domain,
     563           0 :                                    state->lookup_groups[state->giter].gid);
     564           0 :         if (!subreq) {
     565           0 :             tevent_req_error(req, ENOMEM);
     566           0 :             return;
     567             :         }
     568           0 :         tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
     569           0 :         return;
     570             :     }
     571             : 
     572           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "All groups resolved. Done.\n");
     573           0 :     tevent_req_done(req);
     574             : }
     575             : 
     576             : static errno_t
     577          13 : simple_check_process_group(struct simple_check_groups_state *state,
     578             :                            struct ldb_message *group)
     579             : {
     580             :     const char *name;
     581             :     const char *group_sid;
     582             :     struct sss_domain_info *domain;
     583             :     gid_t gid;
     584             :     bool posix;
     585             : 
     586          13 :     posix = is_posix(group);
     587          13 :     name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
     588          13 :     gid = ldb_msg_find_attr_as_uint64(group, SYSDB_GIDNUM, 0);
     589             : 
     590             :     /* With the current sysdb layout, every group has a name */
     591          13 :     if (name == NULL) {
     592           0 :         return EINVAL;
     593             :     }
     594             : 
     595          13 :     if (gid == 0) {
     596           0 :         if (posix == true) {
     597           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "POSIX group without GID\n");
     598           0 :             return EINVAL;
     599             :         }
     600             : 
     601             :         /* Non-posix group with a name. Still can be used for access
     602             :          * control as the name should point to the real name, no SID
     603             :          */
     604           0 :         state->group_names[state->num_names] = talloc_strdup(state->group_names,
     605             :                                                              name);
     606           0 :         if (!state->group_names[state->num_names]) {
     607           0 :             return ENOMEM;
     608             :         }
     609           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
     610           0 :         state->num_names++;
     611           0 :         return EOK;
     612             :     }
     613             : 
     614             :     /* Here are only groups with a name and gid. POSIX group can already
     615             :      * be used, non-POSIX groups can be resolved */
     616          13 :     if (posix) {
     617          13 :         state->group_names[state->num_names] = talloc_strdup(state->group_names,
     618             :                                                              name);
     619          13 :         if (!state->group_names[state->num_names]) {
     620           0 :             return ENOMEM;
     621             :         }
     622          13 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
     623          13 :         state->num_names++;
     624          13 :         return EOK;
     625             :     }
     626             : 
     627             :     /* Try to get group SID and assign it a domain */
     628           0 :     group_sid = ldb_msg_find_attr_as_string(group, SYSDB_SID_STR, NULL);
     629           0 :     if (group_sid == NULL) {
     630             :         /* We will look it up in main domain. */
     631           0 :         domain = state->ctx->domain;
     632             :     } else {
     633           0 :         domain = find_domain_by_sid(state->ctx->domain, group_sid);
     634           0 :         if (domain == NULL) {
     635           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "There is no domain information for "
     636             :                                         "SID %s\n", group_sid);
     637           0 :             return ENOENT;
     638             :         }
     639             :     }
     640             : 
     641             :     /* It is a non-posix group with a GID. Needs resolving */
     642           0 :     state->lookup_groups[state->num_groups].domain = domain;
     643           0 :     state->lookup_groups[state->num_groups].gid = gid;
     644           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Adding GID %"SPRIgid"\n", gid);
     645           0 :     state->num_groups++;
     646           0 :     return EOK;
     647             : }
     648             : 
     649             : static errno_t
     650           8 : simple_check_get_groups_primary(struct simple_check_groups_state *state,
     651             :                                 gid_t gid)
     652             : {
     653             :     errno_t ret;
     654           8 :     const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
     655             :                                   SYSDB_GIDNUM, SYSDB_SID_STR, NULL };
     656             :     struct ldb_message *msg;
     657             : 
     658           8 :     ret = sysdb_search_group_by_gid(state, state->domain, gid, group_attrs,
     659             :                                     &msg);
     660           8 :     if (ret != EOK) {
     661           0 :         DEBUG(SSSDBG_OP_FAILURE,
     662             :               "Could not look up primary group [%"SPRIgid"]: [%d][%s]\n",
     663             :                gid, ret, sss_strerror(ret));
     664             :         /* We have to treat this as non-fatal, because the primary
     665             :          * group may be local to the machine and not available in
     666             :          * our ID provider.
     667             :          */
     668             :     } else {
     669           8 :         ret = simple_check_process_group(state, msg);
     670           8 :         if (ret != EOK) {
     671           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot process primary group\n");
     672           0 :             return ret;
     673             :         }
     674             :     }
     675             : 
     676           8 :     return EOK;
     677             : }
     678             : 
     679             : static errno_t
     680           8 : simple_check_get_groups_recv(struct tevent_req *req,
     681             :                              TALLOC_CTX *mem_ctx,
     682             :                              const char ***_group_names)
     683             : {
     684             :     struct simple_check_groups_state *state;
     685             : 
     686           8 :     state = tevent_req_data(req, struct simple_check_groups_state);
     687             : 
     688           8 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     689             : 
     690           8 :     *_group_names = talloc_steal(mem_ctx, state->group_names);
     691           8 :     if (state->failed_to_resolve_groups) {
     692           0 :         return ERR_SIMPLE_GROUPS_MISSING;
     693             :     }
     694           8 :     return EOK;
     695             : }
     696             : 
     697             : struct simple_access_check_state {
     698             :     bool access_granted;
     699             :     struct simple_ctx *ctx;
     700             :     const char *username;
     701             : 
     702             :     const char **group_names;
     703             : };
     704             : 
     705             : static void simple_access_check_done(struct tevent_req *subreq);
     706             : 
     707          18 : struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
     708             :                                             struct tevent_context *ev,
     709             :                                             struct simple_ctx *ctx,
     710             :                                             const char *username)
     711             : {
     712             :     errno_t ret;
     713             :     struct tevent_req *req;
     714             :     struct tevent_req *subreq;
     715             :     struct simple_access_check_state *state;
     716             : 
     717          18 :     req = tevent_req_create(mem_ctx, &state,
     718             :                             struct simple_access_check_state);
     719          18 :     if (!req) return NULL;
     720             : 
     721          18 :     state->access_granted = false;
     722          18 :     state->ctx = ctx;
     723          18 :     state->username = talloc_strdup(state, username);
     724          18 :     if (!state->username) {
     725           0 :         ret = ENOMEM;
     726           0 :         goto immediate;
     727             :     }
     728             : 
     729          18 :     DEBUG(SSSDBG_FUNC_DATA, "Simple access check for %s\n", username);
     730             : 
     731          18 :     ret = simple_check_users(ctx, username, &state->access_granted);
     732          18 :     if (ret == EOK) {
     733           2 :         goto immediate;
     734          16 :     } else if (ret != EAGAIN) {
     735           0 :         ret = ERR_INTERNAL;
     736           0 :         goto immediate;
     737             :     }
     738             : 
     739             :     /* EAGAIN -- check groups */
     740             : 
     741          16 :     if (!ctx->allow_groups && !ctx->deny_groups) {
     742             :         /* There are no group restrictions, so just return
     743             :          * here with whatever we've decided.
     744             :          */
     745           8 :         DEBUG(SSSDBG_TRACE_LIBS, "No group restrictions, end request\n");
     746           8 :         ret = EOK;
     747           8 :         goto immediate;
     748             :     }
     749             : 
     750             :     /* The group names might not be available. Fire a request to
     751             :      * gather them. In most cases, the request will just shortcut
     752             :      */
     753           8 :     subreq = simple_check_get_groups_send(state, ev, ctx, username);
     754           8 :     if (!subreq) {
     755           0 :         ret = ENOMEM;
     756           0 :         goto immediate;
     757             :     }
     758           8 :     tevent_req_set_callback(subreq, simple_access_check_done, req);
     759             : 
     760           8 :     return req;
     761             : 
     762             : immediate:
     763          10 :     if (ret == EOK) {
     764          10 :         tevent_req_done(req);
     765             :     } else {
     766           0 :         tevent_req_error(req, ret);
     767             :     }
     768          10 :     tevent_req_post(req, ev);
     769          10 :     return req;
     770             : }
     771             : 
     772             : 
     773           8 : static void simple_access_check_done(struct tevent_req *subreq)
     774             : {
     775           8 :     struct tevent_req *req =
     776           8 :                         tevent_req_callback_data(subreq, struct tevent_req);
     777           8 :     struct simple_access_check_state *state =
     778           8 :                         tevent_req_data(req, struct simple_access_check_state);
     779             :     errno_t ret;
     780             : 
     781             :     /* We know the names now. Run the check. */
     782           8 :     ret = simple_check_get_groups_recv(subreq, state, &state->group_names);
     783             : 
     784           8 :     talloc_zfree(subreq);
     785           8 :     if (ret == ENOENT) {
     786             :         /* If the user wasn't found, just shortcut */
     787           0 :         state->access_granted = false;
     788           0 :         tevent_req_done(req);
     789           0 :         return;
     790           8 :     } else if (ret == ERR_SIMPLE_GROUPS_MISSING) {
     791           0 :         DEBUG(SSSDBG_OP_FAILURE,
     792             :               "Could not collect groups of user %s\n", state->username);
     793           0 :         if (state->ctx->deny_groups == NULL) {
     794           0 :             DEBUG(SSSDBG_TRACE_FUNC,
     795             :                   "But no deny groups were defined so we can continue.\n");
     796             :         } else {
     797           0 :             DEBUG(SSSDBG_OP_FAILURE,
     798             :                   "Some deny groups were defined, we can't continue\n");
     799           0 :             tevent_req_error(req, ret);
     800           0 :             return;
     801             :         }
     802           8 :     } else if (ret != EOK) {
     803           0 :         DEBUG(SSSDBG_OP_FAILURE,
     804             :               "Could not collect groups of user %s\n", state->username);
     805           0 :         tevent_req_error(req, ret);
     806           0 :         return;
     807             :     }
     808             : 
     809           8 :     ret = simple_check_groups(state->ctx, state->group_names,
     810             :                               &state->access_granted);
     811           8 :     if (ret != EOK) {
     812           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not check group access [%d]: %s\n",
     813             :               ret, sss_strerror(ret));
     814           0 :         tevent_req_error(req, ERR_INTERNAL);
     815           0 :         return;
     816             :     }
     817             : 
     818             :     /* Now just return whatever we decided */
     819           8 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Group check done\n");
     820           8 :     tevent_req_done(req);
     821             : }
     822             : 
     823          18 : errno_t simple_access_check_recv(struct tevent_req *req, bool *access_granted)
     824             : {
     825          18 :     struct simple_access_check_state *state =
     826          18 :                         tevent_req_data(req, struct simple_access_check_state);
     827             : 
     828          18 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     829             : 
     830          36 :     DEBUG(SSSDBG_TRACE_LIBS,
     831             :           "Access %sgranted\n", state->access_granted ? "" : "not ");
     832          18 :     if (access_granted) {
     833          18 :         *access_granted = state->access_granted;
     834             :     }
     835             : 
     836          18 :     return EOK;
     837             : }

Generated by: LCOV version 1.10