LCOV - code coverage report
Current view: top level - providers/simple - simple_access_check.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 170 365 46.6 %
Date: 2016-06-29 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/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 = dp_req_send(state, ctx->be_ctx->provider, NULL, ar->domain,
     272             :                          "Simple Resolve Group", DPT_ID, DPM_ACCOUNT_HANDLER,
     273             :                          0, ar, NULL);
     274           0 :     if (!subreq) {
     275           0 :         ret = ENOMEM;
     276           0 :         goto done;
     277             :     }
     278           0 :     tevent_req_set_callback(subreq, simple_resolve_group_done, req);
     279             : 
     280           0 :     return req;
     281             : 
     282             : done:
     283           0 :     if (ret == EOK) {
     284           0 :         tevent_req_done(req);
     285             :     } else {
     286           0 :         tevent_req_error(req, ret);
     287             :     }
     288           0 :     tevent_req_post(req, ev);
     289           0 :     return req;
     290             : }
     291             : 
     292             : static errno_t
     293           0 : simple_resolve_group_check(struct simple_resolve_group_state *state)
     294             : {
     295             :     errno_t ret;
     296             :     struct ldb_message *group;
     297           0 :     const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
     298             :                                   SYSDB_GIDNUM, NULL };
     299             : 
     300             :     /* Check the cache by GID again and fetch the name */
     301           0 :     ret = sysdb_search_group_by_gid(state, state->domain, state->gid,
     302             :                                     group_attrs, &group);
     303           0 :     if (ret == ENOENT) {
     304             :         /* The group is missing, we will try to update it. */
     305           0 :         return EAGAIN;
     306           0 :     } else if (ret != EOK) {
     307           0 :         DEBUG(SSSDBG_OP_FAILURE,
     308             :                "Could not look up group by gid [%"SPRIgid"]: [%d][%s]\n",
     309             :                state->gid, ret, sss_strerror(ret));
     310           0 :         return ret;
     311             :     }
     312             : 
     313           0 :     state->name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
     314           0 :     if (!state->name) {
     315           0 :         DEBUG(SSSDBG_OP_FAILURE, "No group name\n");
     316           0 :         return ERR_ACCOUNT_UNKNOWN;
     317             :     }
     318             : 
     319           0 :     if (is_posix(group) == false) {
     320           0 :         DEBUG(SSSDBG_TRACE_LIBS,
     321             :               "The group is still non-POSIX\n");
     322           0 :         return EAGAIN;
     323             :     }
     324             : 
     325           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Got POSIX group\n");
     326           0 :     return EOK;
     327             : }
     328             : 
     329           0 : static void simple_resolve_group_done(struct tevent_req *subreq)
     330             : {
     331             :     struct tevent_req *req;
     332             :     struct simple_resolve_group_state *state;
     333             :     struct dp_reply_std *reply;
     334             :     errno_t ret;
     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 = dp_req_recv_ptr(state, subreq, struct dp_reply_std, &reply);
     340           0 :     talloc_zfree(subreq);
     341           0 :     if (ret) {
     342           0 :         DEBUG(SSSDBG_OP_FAILURE, "dp_req_recv failed\n");
     343           0 :         tevent_req_error(req, ret);
     344           0 :         return;
     345             :     }
     346             : 
     347           0 :     if (reply->dp_error != DP_ERR_OK) {
     348           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     349             :               "Cannot refresh data from DP: %u,%u: %s\n",
     350             :               reply->dp_error, reply->error, reply->message);
     351           0 :         tevent_req_error(req, EIO);
     352           0 :         return;
     353             :     }
     354             : 
     355             :     /* Check the cache by GID again and fetch the name */
     356           0 :     ret = simple_resolve_group_check(state);
     357           0 :     if (ret != EOK) {
     358           0 :         DEBUG(SSSDBG_OP_FAILURE, "Refresh failed\n");
     359           0 :         tevent_req_error(req, ret);
     360           0 :         return;
     361             :     }
     362             : 
     363           0 :     tevent_req_done(req);
     364             : }
     365             : 
     366             : static errno_t
     367           0 : simple_resolve_group_recv(struct tevent_req *req,
     368             :                           TALLOC_CTX *mem_ctx,
     369             :                           const char **name)
     370             : {
     371             :     struct simple_resolve_group_state *state;
     372             : 
     373           0 :     state = tevent_req_data(req, struct simple_resolve_group_state);
     374             : 
     375           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     376             : 
     377           0 :     *name = talloc_strdup(mem_ctx, state->name);
     378           0 :     return EOK;
     379             : }
     380             : 
     381             : struct simple_group {
     382             :     struct sss_domain_info *domain;
     383             :     gid_t gid;
     384             : };
     385             : 
     386             : struct simple_check_groups_state {
     387             :     struct tevent_context *ev;
     388             :     struct simple_ctx *ctx;
     389             :     struct sss_domain_info *domain;
     390             : 
     391             :     struct simple_group *lookup_groups;
     392             :     size_t num_groups;
     393             :     size_t giter;
     394             : 
     395             :     const char **group_names;
     396             :     size_t num_names;
     397             : 
     398             :     bool failed_to_resolve_groups;
     399             : };
     400             : 
     401             : static void simple_check_get_groups_next(struct tevent_req *subreq);
     402             : 
     403             : static errno_t
     404             : simple_check_get_groups_primary(struct simple_check_groups_state *state,
     405             :                                 gid_t gid);
     406             : static errno_t
     407             : simple_check_process_group(struct simple_check_groups_state *state,
     408             :                            struct ldb_message *group);
     409             : 
     410             : static struct tevent_req *
     411           8 : simple_check_get_groups_send(TALLOC_CTX *mem_ctx,
     412             :                              struct tevent_context *ev,
     413             :                              struct simple_ctx *ctx,
     414             :                              const char *username)
     415             : {
     416             :     errno_t ret;
     417             :     struct tevent_req *req;
     418             :     struct tevent_req *subreq;
     419             :     struct simple_check_groups_state *state;
     420           8 :     const char *attrs[] = { SYSDB_NAME, SYSDB_POSIX, SYSDB_GIDNUM,
     421             :                             SYSDB_SID_STR, NULL };
     422             :     size_t group_count;
     423             :     struct ldb_message *user;
     424             :     struct ldb_message **groups;
     425             :     int i;
     426             :     gid_t gid;
     427             : 
     428           8 :     req = tevent_req_create(mem_ctx, &state,
     429             :                             struct simple_check_groups_state);
     430           8 :     if (!req) return NULL;
     431             : 
     432           8 :     state->ev = ev;
     433           8 :     state->ctx = ctx;
     434           8 :     state->failed_to_resolve_groups = false;
     435             : 
     436           8 :     DEBUG(SSSDBG_TRACE_LIBS, "Looking up groups for user %s\n", username);
     437             : 
     438             :     /* get domain from username */
     439           8 :     state->domain = find_domain_by_object_name(ctx->domain, username);
     440           8 :     if (state->domain == NULL) {
     441           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid user %s!\n", username);
     442           0 :         ret = EINVAL;
     443           0 :         goto done;
     444             :     }
     445             : 
     446           8 :     ret = sysdb_search_user_by_name(state, state->domain, username, attrs,
     447             :                                     &user);
     448           8 :     if (ret == ENOENT) {
     449           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "No such user %s\n", username);
     450           0 :         ret = ERR_ACCOUNT_UNKNOWN;
     451           0 :         goto done;
     452           8 :     } else if (ret != EOK) {
     453           0 :         DEBUG(SSSDBG_OP_FAILURE,
     454             :               "Could not look up username [%s]: [%d][%s]\n",
     455             :               username, ret, sss_strerror(ret));
     456           0 :         goto done;
     457             :     }
     458             : 
     459           8 :     ret = sysdb_asq_search(state, state->domain,
     460           8 :                            user->dn, NULL, SYSDB_MEMBEROF,
     461             :                            attrs, &group_count, &groups);
     462           8 :     if (ret != EOK) {
     463           0 :         goto done;
     464             :     }
     465             : 
     466           8 :     DEBUG(SSSDBG_TRACE_FUNC,
     467             :           "User %s is a member of %zu supplemental groups\n",
     468             :            username, group_count);
     469             : 
     470             :     /* One extra space for terminator, one extra space for private group */
     471           8 :     state->group_names = talloc_zero_array(state, const char *, group_count + 2);
     472           8 :     state->lookup_groups = talloc_zero_array(state, struct simple_group,
     473             :                                              group_count + 2);
     474           8 :     if (!state->group_names || !state->lookup_groups) {
     475           0 :         ret = ENOMEM;
     476           0 :         goto done;
     477             :     }
     478             : 
     479          13 :     for (i=0; i < group_count; i++) {
     480             :         /* Some providers (like the AD provider) might perform initgroups
     481             :          * without resolving the group names. In order for the simple access
     482             :          * provider to work correctly, we need to resolve the groups before
     483             :          * performing the access check. In AD provider, the situation is
     484             :          * even more tricky b/c the groups HAVE name, but their name
     485             :          * attribute is set to SID and they are set as non-POSIX
     486             :          */
     487           5 :         ret = simple_check_process_group(state, groups[i]);
     488           5 :         if (ret != EOK) {
     489           0 :             goto done;
     490             :         }
     491             :     }
     492             : 
     493           8 :     gid = ldb_msg_find_attr_as_uint64(user, SYSDB_GIDNUM, 0);
     494           8 :     if (!gid) {
     495           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "User %s has no gid?\n", username);
     496           0 :         ret = EINVAL;
     497           0 :         goto done;
     498             :     }
     499             : 
     500           8 :     ret = simple_check_get_groups_primary(state, gid);
     501           8 :     if (ret != EOK) {
     502           0 :         goto done;
     503             :     }
     504             : 
     505           8 :     if (state->num_groups == 0) {
     506             :         /* If all groups could have been resolved by name, we are
     507             :          * done
     508             :          */
     509           8 :         DEBUG(SSSDBG_TRACE_FUNC, "All groups had name attribute\n");
     510           8 :         ret = EOK;
     511           8 :         goto done;
     512             :     }
     513             : 
     514           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Need to resolve %zu groups\n",
     515             :                               state->num_groups);
     516           0 :     state->giter = 0;
     517           0 :     subreq = simple_resolve_group_send(req, state->ev, state->ctx,
     518           0 :                                        state->lookup_groups[state->giter].domain,
     519           0 :                                        state->lookup_groups[state->giter].gid);
     520           0 :     if (!subreq) {
     521           0 :         ret = ENOMEM;
     522           0 :         goto done;
     523             :     }
     524           0 :     tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
     525             : 
     526           0 :     return req;
     527             : 
     528             : done:
     529           8 :     if (ret == EOK) {
     530           8 :         tevent_req_done(req);
     531             :     } else {
     532           0 :         tevent_req_error(req, ret);
     533             :     }
     534           8 :     tevent_req_post(req, ev);
     535           8 :     return req;
     536             : }
     537             : 
     538           0 : static void simple_check_get_groups_next(struct tevent_req *subreq)
     539             : {
     540           0 :     struct tevent_req *req =
     541           0 :                         tevent_req_callback_data(subreq, struct tevent_req);
     542           0 :     struct simple_check_groups_state *state =
     543           0 :                         tevent_req_data(req, struct simple_check_groups_state);
     544             :     errno_t ret;
     545             : 
     546           0 :     ret = simple_resolve_group_recv(subreq, state->group_names,
     547           0 :                                     &state->group_names[state->num_names]);
     548           0 :     talloc_zfree(subreq);
     549           0 :     if (ret != EOK) {
     550           0 :         DEBUG(SSSDBG_OP_FAILURE,
     551             :               "Could not resolve name of group with GID %"SPRIgid"\n",
     552             :               state->lookup_groups[state->giter].gid);
     553           0 :         state->failed_to_resolve_groups = true;
     554             :     } else {
     555           0 :         state->num_names++;
     556             :     }
     557           0 :     state->giter++;
     558             : 
     559           0 :     if (state->giter < state->num_groups) {
     560           0 :         subreq = simple_resolve_group_send(req, state->ev, state->ctx,
     561           0 :                                    state->lookup_groups[state->giter].domain,
     562           0 :                                    state->lookup_groups[state->giter].gid);
     563           0 :         if (!subreq) {
     564           0 :             tevent_req_error(req, ENOMEM);
     565           0 :             return;
     566             :         }
     567           0 :         tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
     568           0 :         return;
     569             :     }
     570             : 
     571           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "All groups resolved. Done.\n");
     572           0 :     tevent_req_done(req);
     573             : }
     574             : 
     575             : static errno_t
     576          13 : simple_check_process_group(struct simple_check_groups_state *state,
     577             :                            struct ldb_message *group)
     578             : {
     579             :     const char *name;
     580             :     const char *group_sid;
     581             :     struct sss_domain_info *domain;
     582             :     gid_t gid;
     583             :     bool posix;
     584             : 
     585          13 :     posix = is_posix(group);
     586          13 :     name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
     587          13 :     gid = ldb_msg_find_attr_as_uint64(group, SYSDB_GIDNUM, 0);
     588             : 
     589             :     /* With the current sysdb layout, every group has a name */
     590          13 :     if (name == NULL) {
     591           0 :         return EINVAL;
     592             :     }
     593             : 
     594          13 :     if (gid == 0) {
     595           0 :         if (posix == true) {
     596           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "POSIX group without GID\n");
     597           0 :             return EINVAL;
     598             :         }
     599             : 
     600             :         /* Non-posix group with a name. Still can be used for access
     601             :          * control as the name should point to the real name, no SID
     602             :          */
     603           0 :         state->group_names[state->num_names] = talloc_strdup(state->group_names,
     604             :                                                              name);
     605           0 :         if (!state->group_names[state->num_names]) {
     606           0 :             return ENOMEM;
     607             :         }
     608           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
     609           0 :         state->num_names++;
     610           0 :         return EOK;
     611             :     }
     612             : 
     613             :     /* Here are only groups with a name and gid. POSIX group can already
     614             :      * be used, non-POSIX groups can be resolved */
     615          13 :     if (posix) {
     616          13 :         state->group_names[state->num_names] = talloc_strdup(state->group_names,
     617             :                                                              name);
     618          13 :         if (!state->group_names[state->num_names]) {
     619           0 :             return ENOMEM;
     620             :         }
     621          13 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
     622          13 :         state->num_names++;
     623          13 :         return EOK;
     624             :     }
     625             : 
     626             :     /* Try to get group SID and assign it a domain */
     627           0 :     group_sid = ldb_msg_find_attr_as_string(group, SYSDB_SID_STR, NULL);
     628           0 :     if (group_sid == NULL) {
     629             :         /* We will look it up in main domain. */
     630           0 :         domain = state->ctx->domain;
     631             :     } else {
     632           0 :         domain = find_domain_by_sid(state->ctx->domain, group_sid);
     633           0 :         if (domain == NULL) {
     634           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "There is no domain information for "
     635             :                                         "SID %s\n", group_sid);
     636           0 :             return ENOENT;
     637             :         }
     638             :     }
     639             : 
     640             :     /* It is a non-posix group with a GID. Needs resolving */
     641           0 :     state->lookup_groups[state->num_groups].domain = domain;
     642           0 :     state->lookup_groups[state->num_groups].gid = gid;
     643           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Adding GID %"SPRIgid"\n", gid);
     644           0 :     state->num_groups++;
     645           0 :     return EOK;
     646             : }
     647             : 
     648             : static errno_t
     649           8 : simple_check_get_groups_primary(struct simple_check_groups_state *state,
     650             :                                 gid_t gid)
     651             : {
     652             :     errno_t ret;
     653           8 :     const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
     654             :                                   SYSDB_GIDNUM, SYSDB_SID_STR, NULL };
     655             :     struct ldb_message *msg;
     656             : 
     657           8 :     ret = sysdb_search_group_by_gid(state, state->domain, gid, group_attrs,
     658             :                                     &msg);
     659           8 :     if (ret != EOK) {
     660           0 :         DEBUG(SSSDBG_OP_FAILURE,
     661             :               "Could not look up primary group [%"SPRIgid"]: [%d][%s]\n",
     662             :                gid, ret, sss_strerror(ret));
     663             :         /* We have to treat this as non-fatal, because the primary
     664             :          * group may be local to the machine and not available in
     665             :          * our ID provider.
     666             :          */
     667             :     } else {
     668           8 :         ret = simple_check_process_group(state, msg);
     669           8 :         if (ret != EOK) {
     670           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot process primary group\n");
     671           0 :             return ret;
     672             :         }
     673             :     }
     674             : 
     675           8 :     return EOK;
     676             : }
     677             : 
     678             : static errno_t
     679           8 : simple_check_get_groups_recv(struct tevent_req *req,
     680             :                              TALLOC_CTX *mem_ctx,
     681             :                              const char ***_group_names)
     682             : {
     683             :     struct simple_check_groups_state *state;
     684             : 
     685           8 :     state = tevent_req_data(req, struct simple_check_groups_state);
     686             : 
     687           8 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     688             : 
     689           8 :     *_group_names = talloc_steal(mem_ctx, state->group_names);
     690           8 :     if (state->failed_to_resolve_groups) {
     691           0 :         return ERR_SIMPLE_GROUPS_MISSING;
     692             :     }
     693           8 :     return EOK;
     694             : }
     695             : 
     696             : struct simple_access_check_state {
     697             :     bool access_granted;
     698             :     struct simple_ctx *ctx;
     699             :     const char *username;
     700             : 
     701             :     const char **group_names;
     702             : };
     703             : 
     704             : static void simple_access_check_done(struct tevent_req *subreq);
     705             : 
     706          18 : struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
     707             :                                             struct tevent_context *ev,
     708             :                                             struct simple_ctx *ctx,
     709             :                                             const char *username)
     710             : {
     711             :     errno_t ret;
     712             :     struct tevent_req *req;
     713             :     struct tevent_req *subreq;
     714             :     struct simple_access_check_state *state;
     715             : 
     716          18 :     req = tevent_req_create(mem_ctx, &state,
     717             :                             struct simple_access_check_state);
     718          18 :     if (!req) return NULL;
     719             : 
     720          18 :     state->access_granted = false;
     721          18 :     state->ctx = ctx;
     722          18 :     state->username = talloc_strdup(state, username);
     723          18 :     if (!state->username) {
     724           0 :         ret = ENOMEM;
     725           0 :         goto immediate;
     726             :     }
     727             : 
     728          18 :     DEBUG(SSSDBG_FUNC_DATA, "Simple access check for %s\n", username);
     729             : 
     730          18 :     ret = simple_check_users(ctx, username, &state->access_granted);
     731          18 :     if (ret == EOK) {
     732           2 :         goto immediate;
     733          16 :     } else if (ret != EAGAIN) {
     734           0 :         ret = ERR_INTERNAL;
     735           0 :         goto immediate;
     736             :     }
     737             : 
     738             :     /* EAGAIN -- check groups */
     739             : 
     740          16 :     if (!ctx->allow_groups && !ctx->deny_groups) {
     741             :         /* There are no group restrictions, so just return
     742             :          * here with whatever we've decided.
     743             :          */
     744           8 :         DEBUG(SSSDBG_TRACE_LIBS, "No group restrictions, end request\n");
     745           8 :         ret = EOK;
     746           8 :         goto immediate;
     747             :     }
     748             : 
     749             :     /* The group names might not be available. Fire a request to
     750             :      * gather them. In most cases, the request will just shortcut
     751             :      */
     752           8 :     subreq = simple_check_get_groups_send(state, ev, ctx, username);
     753           8 :     if (!subreq) {
     754           0 :         ret = ENOMEM;
     755           0 :         goto immediate;
     756             :     }
     757           8 :     tevent_req_set_callback(subreq, simple_access_check_done, req);
     758             : 
     759           8 :     return req;
     760             : 
     761             : immediate:
     762          10 :     if (ret == EOK) {
     763          10 :         tevent_req_done(req);
     764             :     } else {
     765           0 :         tevent_req_error(req, ret);
     766             :     }
     767          10 :     tevent_req_post(req, ev);
     768          10 :     return req;
     769             : }
     770             : 
     771             : 
     772           8 : static void simple_access_check_done(struct tevent_req *subreq)
     773             : {
     774           8 :     struct tevent_req *req =
     775           8 :                         tevent_req_callback_data(subreq, struct tevent_req);
     776           8 :     struct simple_access_check_state *state =
     777           8 :                         tevent_req_data(req, struct simple_access_check_state);
     778             :     errno_t ret;
     779             : 
     780             :     /* We know the names now. Run the check. */
     781           8 :     ret = simple_check_get_groups_recv(subreq, state, &state->group_names);
     782             : 
     783           8 :     talloc_zfree(subreq);
     784           8 :     if (ret == ENOENT) {
     785             :         /* If the user wasn't found, just shortcut */
     786           0 :         state->access_granted = false;
     787           0 :         tevent_req_done(req);
     788           0 :         return;
     789           8 :     } else if (ret == ERR_SIMPLE_GROUPS_MISSING) {
     790           0 :         DEBUG(SSSDBG_OP_FAILURE,
     791             :               "Could not collect groups of user %s\n", state->username);
     792           0 :         if (state->ctx->deny_groups == NULL) {
     793           0 :             DEBUG(SSSDBG_TRACE_FUNC,
     794             :                   "But no deny groups were defined so we can continue.\n");
     795             :         } else {
     796           0 :             DEBUG(SSSDBG_OP_FAILURE,
     797             :                   "Some deny groups were defined, we can't continue\n");
     798           0 :             tevent_req_error(req, ret);
     799           0 :             return;
     800             :         }
     801           8 :     } else if (ret != EOK) {
     802           0 :         DEBUG(SSSDBG_OP_FAILURE,
     803             :               "Could not collect groups of user %s\n", state->username);
     804           0 :         tevent_req_error(req, ret);
     805           0 :         return;
     806             :     }
     807             : 
     808           8 :     ret = simple_check_groups(state->ctx, state->group_names,
     809             :                               &state->access_granted);
     810           8 :     if (ret != EOK) {
     811           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not check group access [%d]: %s\n",
     812             :               ret, sss_strerror(ret));
     813           0 :         tevent_req_error(req, ERR_INTERNAL);
     814           0 :         return;
     815             :     }
     816             : 
     817             :     /* Now just return whatever we decided */
     818           8 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Group check done\n");
     819           8 :     tevent_req_done(req);
     820             : }
     821             : 
     822          18 : errno_t simple_access_check_recv(struct tevent_req *req, bool *access_granted)
     823             : {
     824          18 :     struct simple_access_check_state *state =
     825          18 :                         tevent_req_data(req, struct simple_access_check_state);
     826             : 
     827          18 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     828             : 
     829          36 :     DEBUG(SSSDBG_TRACE_LIBS,
     830             :           "Access %sgranted\n", state->access_granted ? "" : "not ");
     831          18 :     if (access_granted) {
     832          18 :         *access_granted = state->access_granted;
     833             :     }
     834             : 
     835          18 :     return EOK;
     836             : }

Generated by: LCOV version 1.10