LCOV - code coverage report
Current view: top level - responder/sudo - sudosrv_get_sudorules.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 359 0.0 %
Date: 2015-10-19 Functions: 0 14 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Pavel Březina <pbrezina@redhat.com>
       4             :         Jakub Hrozek <jhrozek@redhat.com>
       5             : 
       6             :     Copyright (C) 2011 Red Hat
       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 "config.h"
      23             : 
      24             : #include <stdint.h>
      25             : #include <string.h>
      26             : #include <talloc.h>
      27             : 
      28             : #include "util/util.h"
      29             : #include "db/sysdb_sudo.h"
      30             : #include "responder/sudo/sudosrv_private.h"
      31             : #include "providers/data_provider.h"
      32             : 
      33             : static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx);
      34             : 
      35           0 : errno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx)
      36             : {
      37             :     errno_t ret;
      38             : 
      39           0 :     dctx->check_provider = true;
      40           0 :     ret = sudosrv_get_user(dctx);
      41           0 :     if (ret == EAGAIN) {
      42           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
      43             :               "Looking up the user info from Data Provider\n");
      44           0 :         return EAGAIN;
      45           0 :     } else if (ret != EOK) {
      46           0 :         DEBUG(SSSDBG_OP_FAILURE,
      47             :               "Error looking up user information [%d]: %s\n", ret, strerror(ret));
      48           0 :         return ret;
      49             :     }
      50             : 
      51             :     /* OK, got the user from cache. Try to get the rules. */
      52           0 :     ret = sudosrv_get_rules(dctx->cmd_ctx);
      53           0 :     if (ret == EAGAIN) {
      54           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
      55             :               "Looking up the sudo rules from Data Provider\n");
      56           0 :         return EAGAIN;
      57           0 :     } else if (ret != EOK) {
      58           0 :         DEBUG(SSSDBG_OP_FAILURE,
      59             :               "Error looking up sudo rules [%d]: %s\n", ret, strerror(ret));
      60           0 :         return ret;
      61             :     }
      62             : 
      63           0 :     return EOK;
      64             : }
      65             : 
      66             : static void sudosrv_dp_send_acct_req_done(struct tevent_req *req);
      67             : static void sudosrv_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
      68             :                                            const char *err_msg, void *ptr);
      69             : 
      70           0 : static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
      71             : {
      72           0 :     TALLOC_CTX *tmp_ctx = NULL;
      73           0 :     struct sss_domain_info *dom = dctx->domain;
      74           0 :     struct sudo_cmd_ctx *cmd_ctx = dctx->cmd_ctx;
      75           0 :     struct cli_ctx *cli_ctx = dctx->cmd_ctx->cli_ctx;
      76             :     struct ldb_result *user;
      77           0 :     time_t cache_expire = 0;
      78             :     struct tevent_req *dpreq;
      79             :     struct dp_callback_ctx *cb_ctx;
      80           0 :     const char *original_name = NULL;
      81           0 :     const char *extra_flag = NULL;
      82           0 :     const char *search_name = NULL;
      83           0 :     char *name = NULL;
      84           0 :     uid_t uid = 0;
      85             :     errno_t ret;
      86             : 
      87           0 :     tmp_ctx = talloc_new(NULL);
      88           0 :     if (tmp_ctx == NULL) {
      89           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
      90           0 :         return ENOMEM;
      91             :     }
      92             : 
      93           0 :     while (dom) {
      94             :        /* if it is a domainless search, skip domains that require fully
      95             :         * qualified names instead */
      96           0 :         while (dom && cmd_ctx->check_next && dom->fqnames) {
      97           0 :             dom = get_next_domain(dom, false);
      98             :         }
      99             : 
     100           0 :         if (!dom) break;
     101             : 
     102             :         /* make sure to update the dctx if we changed domain */
     103           0 :         dctx->domain = dom;
     104             : 
     105           0 :         talloc_free(name);
     106           0 :         name = sss_get_cased_name(tmp_ctx, cmd_ctx->username,
     107           0 :                                   dom->case_sensitive);
     108           0 :         if (name == NULL) {
     109           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
     110           0 :             ret = ENOMEM;
     111           0 :             goto done;
     112             :         }
     113             : 
     114           0 :         name = sss_reverse_replace_space(tmp_ctx, name,
     115           0 :                                          cmd_ctx->sudo_ctx->rctx->override_space);
     116           0 :         if (name == NULL) {
     117           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     118             :                   "sss_reverse_replace_whitespaces failed\n");
     119           0 :             return ENOMEM;
     120             :         }
     121             : 
     122           0 :         DEBUG(SSSDBG_FUNC_DATA, "Requesting info about [%s@%s]\n",
     123             :               name, dom->name);
     124             : 
     125           0 :         ret = sysdb_getpwnam_with_views(dctx, dctx->domain, name, &user);
     126           0 :         if (ret != EOK) {
     127           0 :             DEBUG(SSSDBG_OP_FAILURE,
     128             :                   "Failed to make request to our cache!\n");
     129           0 :             ret = EIO;
     130           0 :             goto done;
     131             :         }
     132             : 
     133           0 :         if (user->count > 1) {
     134           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     135             :                   "getpwnam call returned more than one result !?!\n");
     136           0 :             ret = EIO;
     137           0 :             goto done;
     138             :         }
     139             : 
     140           0 :         if (user->count == 0 && !dctx->check_provider) {
     141             :             /* if a multidomain search, try with next */
     142           0 :             if (cmd_ctx->check_next) {
     143           0 :                 dctx->check_provider = true;
     144           0 :                 dom = get_next_domain(dom, false);
     145           0 :                 if (dom) continue;
     146             :             }
     147             : 
     148           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "No results for getpwnam call\n");
     149           0 :             ret = ENOENT;
     150           0 :             goto done;
     151             :         }
     152             : 
     153             :         /* One result found, check cache expiry */
     154           0 :         if (user->count == 1) {
     155           0 :             cache_expire = ldb_msg_find_attr_as_uint64(user->msgs[0],
     156             :                                                        SYSDB_CACHE_EXPIRE, 0);
     157             :         }
     158             : 
     159             :         /* If cache miss and we haven't checked DP yet OR the entry is
     160             :          * outdated, go to DP */
     161           0 :         if ((user->count == 0 || cache_expire < time(NULL))
     162           0 :             && dctx->check_provider) {
     163             : 
     164           0 :             search_name = cmd_ctx->username;
     165           0 :             if (is_local_view(dom->view_name)) {
     166             :                 /* Search with original name in case of local view. */
     167           0 :                 if (user->count != 0) {
     168           0 :                     search_name = ldb_msg_find_attr_as_string(user->msgs[0],
     169             :                                                               SYSDB_NAME, NULL);
     170             :                 }
     171           0 :             } else if (DOM_HAS_VIEWS(dom) && (user->count == 0
     172           0 :                 || ldb_msg_find_attr_as_string(user->msgs[0],
     173             :                                                OVERRIDE_PREFIX SYSDB_NAME,
     174             :                                                NULL) != NULL)) {
     175           0 :                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
     176             :             }
     177             : 
     178           0 :             dpreq = sss_dp_get_account_send(cli_ctx, cli_ctx->rctx,
     179             :                                             dom, false, SSS_DP_INITGROUPS,
     180             :                                             search_name, 0, extra_flag);
     181           0 :             if (!dpreq) {
     182           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     183             :                       "Out of memory sending data provider request\n");
     184           0 :                 ret = ENOMEM;
     185           0 :                 goto done;
     186             :             }
     187             : 
     188           0 :             cb_ctx = talloc_zero(cli_ctx, struct dp_callback_ctx);
     189           0 :             if(!cb_ctx) {
     190           0 :                 talloc_zfree(dpreq);
     191           0 :                 ret = ENOMEM;
     192           0 :                 goto done;
     193             :             }
     194             : 
     195           0 :             cb_ctx->callback = sudosrv_check_user_dp_callback;
     196           0 :             cb_ctx->ptr = dctx;
     197           0 :             cb_ctx->cctx = cli_ctx;
     198           0 :             cb_ctx->mem_ctx = cli_ctx;
     199             : 
     200           0 :             tevent_req_set_callback(dpreq, sudosrv_dp_send_acct_req_done, cb_ctx);
     201             : 
     202             :             /* tell caller we are in an async call */
     203           0 :             ret = EAGAIN;
     204           0 :             goto done;
     205             :         }
     206             : 
     207             :         /* check uid */
     208           0 :         uid = sss_view_ldb_msg_find_attr_as_uint64(dom, user->msgs[0],
     209             :                                                    SYSDB_UIDNUM, 0);
     210           0 :         if (uid != cmd_ctx->uid) {
     211             :             /* if a multidomain search, try with next */
     212           0 :             if (cmd_ctx->check_next) {
     213           0 :                 dctx->check_provider = true;
     214           0 :                 dom = get_next_domain(dom, false);
     215           0 :                 if (dom) continue;
     216             :             }
     217             : 
     218           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "UID does not match\n");
     219           0 :             ret = ENOENT;
     220           0 :             goto done;
     221             :         }
     222             : 
     223             :         /* user is stored in cache, remember cased and original name */
     224           0 :         original_name = ldb_msg_find_attr_as_string(user->msgs[0],
     225             :                                                     SYSDB_NAME, NULL);
     226           0 :         if (original_name == NULL) {
     227           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n");
     228           0 :             ret = EFAULT;
     229           0 :             goto done;
     230             :         }
     231             : 
     232           0 :         cmd_ctx->cased_username = talloc_move(cmd_ctx, &name);
     233           0 :         cmd_ctx->orig_username = talloc_strdup(cmd_ctx, original_name);
     234           0 :         if (cmd_ctx->orig_username == NULL) {
     235           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
     236           0 :             ret = ENOMEM;
     237           0 :             goto done;
     238             :         }
     239             : 
     240             :         /* and set domain */
     241           0 :         cmd_ctx->domain = dom;
     242             : 
     243           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Returning info for user [%s@%s]\n",
     244             :               cmd_ctx->username, dctx->domain->name);
     245           0 :         ret = EOK;
     246           0 :         goto done;
     247             :     }
     248             : 
     249           0 :     ret = ENOENT;
     250             : done:
     251           0 :     talloc_free(tmp_ctx);
     252           0 :     return ret;
     253             : }
     254             : 
     255           0 : static void sudosrv_dp_send_acct_req_done(struct tevent_req *req)
     256             : {
     257           0 :     struct dp_callback_ctx *cb_ctx =
     258           0 :             tevent_req_callback_data(req, struct dp_callback_ctx);
     259             : 
     260             :     errno_t ret;
     261             :     dbus_uint16_t err_maj;
     262             :     dbus_uint32_t err_min;
     263             :     char *err_msg;
     264             : 
     265           0 :     ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
     266             :                                   &err_maj, &err_min,
     267             :                                   &err_msg);
     268           0 :     talloc_zfree(req);
     269           0 :     if (ret != EOK) {
     270           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     271             :               "Fatal error, killing connection!\n");
     272           0 :         talloc_free(cb_ctx->cctx);
     273           0 :         return;
     274             :     }
     275             : 
     276           0 :     cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
     277             : }
     278             : 
     279           0 : static void sudosrv_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
     280             :                                            const char *err_msg, void *ptr)
     281             : {
     282             :     errno_t ret;
     283           0 :     struct sudo_dom_ctx *dctx = talloc_get_type(ptr, struct sudo_dom_ctx);
     284             : 
     285           0 :     if (err_maj) {
     286           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     287             :              "Unable to get information from Data Provider\n"
     288             :               "Error: %u, %u, %s\n",
     289             :               (unsigned int)err_maj, (unsigned int)err_min, err_msg);
     290             :     }
     291             : 
     292           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     293             :           "Data Provider returned, check the cache again\n");
     294           0 :     dctx->check_provider = false;
     295           0 :     ret = sudosrv_get_user(dctx);
     296           0 :     if (ret == EAGAIN) {
     297           0 :         goto done;
     298           0 :     } else if (ret != EOK) {
     299           0 :         DEBUG(SSSDBG_OP_FAILURE,
     300             :               "Could not look up the user [%d]: %s\n",
     301             :               ret, strerror(ret));
     302           0 :         sudosrv_cmd_done(dctx->cmd_ctx, ret);
     303           0 :         return;
     304             :     }
     305             : 
     306           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Looking up sudo rules..\n");
     307           0 :     ret = sudosrv_get_rules(dctx->cmd_ctx);
     308           0 :     if (ret == EAGAIN) {
     309           0 :         goto done;
     310           0 :     } else if (ret != EOK) {
     311           0 :         DEBUG(SSSDBG_OP_FAILURE,
     312             :               "Error getting sudo rules [%d]: %s\n",
     313             :               ret, strerror(ret));
     314           0 :         sudosrv_cmd_done(dctx->cmd_ctx, EIO);
     315           0 :         return;
     316             :     }
     317             : 
     318             : done:
     319           0 :     sudosrv_cmd_done(dctx->cmd_ctx, ret);
     320             : }
     321             : 
     322             : static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
     323             :                                                 struct sudo_cmd_ctx *cmd_ctx,
     324             :                                                 struct sysdb_attrs ***_rules,
     325             :                                                 uint32_t *_num_rules);
     326             : static void
     327             : sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min,
     328             :                                   const char *err_msg, void *ptr);
     329             : static void
     330             : sudosrv_dp_req_done(struct tevent_req *req);
     331             : 
     332             : static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
     333             :                                                  struct sss_domain_info *domain,
     334             :                                                  const char **attrs,
     335             :                                                  unsigned int flags,
     336             :                                                  const char *username,
     337             :                                                  uid_t uid,
     338             :                                                  char **groupnames,
     339             :                                                  bool inverse_order,
     340             :                                                  struct sysdb_attrs ***_rules,
     341             :                                                  uint32_t *_count);
     342             : 
     343           0 : errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx)
     344             : {
     345           0 :     TALLOC_CTX *tmp_ctx = NULL;
     346           0 :     struct tevent_req *dpreq = NULL;
     347           0 :     struct dp_callback_ctx *cb_ctx = NULL;
     348           0 :     char **groupnames = NULL;
     349           0 :     uint32_t expired_rules_num = 0;
     350           0 :     struct sysdb_attrs **expired_rules = NULL;
     351             :     errno_t ret;
     352           0 :     unsigned int flags = SYSDB_SUDO_FILTER_NONE;
     353           0 :     const char *attrs[] = { SYSDB_NAME,
     354             :                             NULL };
     355             : 
     356           0 :     if (cmd_ctx->domain == NULL) {
     357           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Domain is not set!\n");
     358           0 :         return EFAULT;
     359             :     }
     360             : 
     361           0 :     tmp_ctx = talloc_new(NULL);
     362           0 :     if (tmp_ctx == NULL) {
     363           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
     364           0 :         return ENOMEM;
     365             :     }
     366             : 
     367           0 :     switch (cmd_ctx->type) {
     368             :         case SSS_SUDO_DEFAULTS:
     369           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Retrieving default options "
     370             :                   "for [%s] from [%s]\n", cmd_ctx->orig_username,
     371             :                   cmd_ctx->domain->name);
     372           0 :             break;
     373             :         case SSS_SUDO_USER:
     374           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Retrieving rules "
     375             :                   "for [%s] from [%s]\n", cmd_ctx->orig_username,
     376             :                   cmd_ctx->domain->name);
     377           0 :             break;
     378             :     }
     379             : 
     380             :     /* Fetch all expired rules:
     381             :      * sudo asks sssd twice - for defaults and for rules. If we refresh all
     382             :      * expired rules for this user and defaults at once we will save one
     383             :      * provider call
     384             :      */
     385           0 :     ret = sysdb_get_sudo_user_info(tmp_ctx, cmd_ctx->domain,
     386             :                                    cmd_ctx->orig_username, NULL, &groupnames);
     387           0 :     if (ret != EOK) {
     388           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     389             :              "Unable to retrieve user info [%d]: %s\n", ret, strerror(ret));
     390           0 :         goto done;
     391             :     }
     392             : 
     393           0 :     flags =   SYSDB_SUDO_FILTER_INCLUDE_ALL
     394             :             | SYSDB_SUDO_FILTER_INCLUDE_DFL
     395             :             | SYSDB_SUDO_FILTER_ONLY_EXPIRED
     396             :             | SYSDB_SUDO_FILTER_USERINFO;
     397           0 :     ret = sudosrv_get_sudorules_query_cache(tmp_ctx,
     398             :                                             cmd_ctx->domain, attrs, flags,
     399             :                                             cmd_ctx->orig_username,
     400             :                                             cmd_ctx->uid, groupnames,
     401           0 :                                             cmd_ctx->sudo_ctx->inverse_order,
     402             :                                             &expired_rules, &expired_rules_num);
     403           0 :     if (ret != EOK) {
     404           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve expired sudo rules "
     405             :                                     "[%d]: %s\n", ret, strerror(ret));
     406           0 :         goto done;
     407             :     }
     408             : 
     409           0 :     cmd_ctx->expired_rules_num = expired_rules_num;
     410           0 :     if (expired_rules_num > 0) {
     411             :         /* refresh expired rules then continue */
     412           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Refreshing %d expired rules\n",
     413             :                                       expired_rules_num);
     414           0 :         dpreq = sss_dp_get_sudoers_send(tmp_ctx, cmd_ctx->cli_ctx->rctx,
     415             :                                         cmd_ctx->domain, false,
     416             :                                         SSS_DP_SUDO_REFRESH_RULES,
     417             :                                         cmd_ctx->orig_username,
     418             :                                         expired_rules_num, expired_rules);
     419           0 :         if (dpreq == NULL) {
     420           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     421             :                   "Cannot issue DP request.\n");
     422           0 :             ret = EIO;
     423           0 :             goto done;
     424             :         }
     425             : 
     426           0 :         cb_ctx = talloc_zero(tmp_ctx, struct dp_callback_ctx);
     427           0 :         if (!cb_ctx) {
     428           0 :             talloc_zfree(dpreq);
     429           0 :             ret = ENOMEM;
     430           0 :             goto done;
     431             :         }
     432             : 
     433           0 :         cb_ctx->callback = sudosrv_get_sudorules_dp_callback;
     434           0 :         cb_ctx->ptr = cmd_ctx;
     435           0 :         cb_ctx->cctx = cmd_ctx->cli_ctx;
     436           0 :         cb_ctx->mem_ctx = cmd_ctx;
     437             : 
     438           0 :         tevent_req_set_callback(dpreq, sudosrv_dp_req_done, cb_ctx);
     439           0 :         ret = EAGAIN;
     440             : 
     441             :     } else {
     442             :         /* nothing is expired return what we have in the cache */
     443           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "About to get sudo rules from cache\n");
     444           0 :         ret = sudosrv_get_sudorules_from_cache(cmd_ctx, cmd_ctx,
     445             :                                                &cmd_ctx->rules,
     446             :                                                &cmd_ctx->num_rules);
     447           0 :         if (ret != EOK) {
     448           0 :             DEBUG(SSSDBG_OP_FAILURE,
     449             :                   "Failed to make a request to our cache [%d]: %s\n",
     450             :                    ret, strerror(ret));
     451           0 :             goto done;
     452             :         }
     453             :     }
     454             : 
     455           0 :     if (dpreq != NULL) {
     456           0 :         talloc_steal(cmd_ctx->cli_ctx, dpreq);
     457             :     }
     458             : 
     459           0 :     if (cb_ctx != NULL) {
     460           0 :         talloc_steal(cmd_ctx, cb_ctx);
     461             :     }
     462             : 
     463             : done:
     464           0 :     talloc_free(tmp_ctx);
     465           0 :     return ret;
     466             : }
     467             : 
     468             : static void
     469           0 : sudosrv_dp_req_done(struct tevent_req *req)
     470             : {
     471           0 :     struct dp_callback_ctx *cb_ctx =
     472           0 :         tevent_req_callback_data(req, struct dp_callback_ctx);
     473             :     struct cli_ctx *cli_ctx;
     474             : 
     475             :     errno_t ret;
     476             :     dbus_uint16_t err_maj;
     477             :     dbus_uint32_t err_min;
     478             :     char *err_msg;
     479             : 
     480           0 :     cli_ctx = talloc_get_type(cb_ctx->cctx, struct cli_ctx);
     481             : 
     482           0 :     ret = sss_dp_get_sudoers_recv(cb_ctx->mem_ctx, req,
     483             :                                   &err_maj, &err_min,
     484             :                                   &err_msg);
     485           0 :     talloc_free(req);
     486           0 :     if (ret != EOK) {
     487           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
     488           0 :         talloc_free(cli_ctx);
     489           0 :         return;
     490             :     }
     491             : 
     492           0 :     cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
     493             : }
     494             : 
     495             : static void
     496           0 : sudosrv_dp_oob_req_done(struct tevent_req *req)
     497             : {
     498           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Out of band refresh finished\n");
     499           0 :     talloc_free(req);
     500           0 : }
     501             : 
     502             : static void
     503           0 : sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min,
     504             :                                   const char *err_msg, void *ptr)
     505             : {
     506           0 :     struct sudo_cmd_ctx *cmd_ctx = talloc_get_type(ptr, struct sudo_cmd_ctx);
     507           0 :     struct tevent_req *dpreq = NULL;
     508             :     errno_t ret;
     509             : 
     510           0 :     if (err_maj) {
     511           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     512             :               "Unable to get information from Data Provider\n"
     513             :                "Error: %u, %u, %s\n"
     514             :                "Will try to return what we have in cache\n",
     515             :                (unsigned int)err_maj, (unsigned int)err_min, err_msg);
     516             :     }
     517             : 
     518           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "About to get sudo rules from cache\n");
     519           0 :     ret = sudosrv_get_sudorules_from_cache(cmd_ctx, cmd_ctx, &cmd_ctx->rules,
     520             :                                            &cmd_ctx->num_rules);
     521           0 :     if (ret != EOK) {
     522           0 :         DEBUG(SSSDBG_OP_FAILURE,
     523             :               "Failed to make a request to our cache [%d]: %s\n",
     524             :               ret, strerror(ret));
     525           0 :         sudosrv_cmd_done(cmd_ctx, EIO);
     526           0 :         return;
     527             :     }
     528             : 
     529           0 :     if (cmd_ctx->expired_rules_num > 0
     530           0 :         && err_min == ENOENT) {
     531           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     532             :               "Some expired rules were removed from the server, "
     533             :                "scheduling full refresh out of band\n");
     534           0 :         dpreq = sss_dp_get_sudoers_send(cmd_ctx->cli_ctx->rctx,
     535           0 :                                         cmd_ctx->cli_ctx->rctx,
     536             :                                         cmd_ctx->domain, false,
     537             :                                         SSS_DP_SUDO_FULL_REFRESH,
     538             :                                         cmd_ctx->orig_username,
     539             :                                         0, NULL);
     540           0 :         if (dpreq == NULL) {
     541           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     542             :                   "Cannot issue DP request.\n");
     543             :         } else {
     544           0 :             tevent_req_set_callback(dpreq, sudosrv_dp_oob_req_done, NULL);
     545             :         }
     546             :     }
     547             : 
     548           0 :     sudosrv_cmd_done(cmd_ctx, ret);
     549             : }
     550             : 
     551           0 : static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
     552             :                                                 struct sudo_cmd_ctx *cmd_ctx,
     553             :                                                 struct sysdb_attrs ***_rules,
     554             :                                                 uint32_t *_num_rules)
     555             : {
     556             :     TALLOC_CTX *tmp_ctx;
     557             :     errno_t ret;
     558           0 :     char **groupnames = NULL;
     559           0 :     const char *debug_name = NULL;
     560           0 :     unsigned int flags = SYSDB_SUDO_FILTER_NONE;
     561           0 :     struct sysdb_attrs **rules = NULL;
     562           0 :     uint32_t num_rules = 0;
     563           0 :     const char *attrs[] = { SYSDB_OBJECTCLASS,
     564             :                             SYSDB_SUDO_CACHE_AT_CN,
     565             :                             SYSDB_SUDO_CACHE_AT_USER,
     566             :                             SYSDB_SUDO_CACHE_AT_HOST,
     567             :                             SYSDB_SUDO_CACHE_AT_COMMAND,
     568             :                             SYSDB_SUDO_CACHE_AT_OPTION,
     569             :                             SYSDB_SUDO_CACHE_AT_RUNAS,
     570             :                             SYSDB_SUDO_CACHE_AT_RUNASUSER,
     571             :                             SYSDB_SUDO_CACHE_AT_RUNASGROUP,
     572             :                             SYSDB_SUDO_CACHE_AT_NOTBEFORE,
     573             :                             SYSDB_SUDO_CACHE_AT_NOTAFTER,
     574             :                             SYSDB_SUDO_CACHE_AT_ORDER,
     575             :                             NULL };
     576             : 
     577           0 :     if (cmd_ctx->domain == NULL) {
     578           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Domain is not set!\n");
     579           0 :         return EFAULT;
     580             :     }
     581             : 
     582           0 :     tmp_ctx = talloc_new(NULL);
     583           0 :     if (tmp_ctx == NULL) {
     584           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
     585           0 :         return ENOMEM;
     586             :     }
     587             : 
     588           0 :     switch (cmd_ctx->type) {
     589             :     case SSS_SUDO_USER:
     590           0 :         debug_name = cmd_ctx->cased_username;
     591           0 :         ret = sysdb_get_sudo_user_info(tmp_ctx,
     592             :                                        cmd_ctx->domain,
     593             :                                        cmd_ctx->orig_username,
     594             :                                        NULL, &groupnames);
     595           0 :         if (ret != EOK) {
     596           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     597             :                  "Unable to retrieve user info [%d]: %s\n",
     598             :                   ret, strerror(ret));
     599           0 :             goto done;
     600             :         }
     601           0 :         flags = SYSDB_SUDO_FILTER_USERINFO | SYSDB_SUDO_FILTER_INCLUDE_ALL;
     602           0 :         break;
     603             :     case SSS_SUDO_DEFAULTS:
     604           0 :         debug_name = "<default options>";
     605           0 :         flags = SYSDB_SUDO_FILTER_INCLUDE_DFL;
     606           0 :         break;
     607             :     }
     608             : 
     609           0 :     ret = sudosrv_get_sudorules_query_cache(tmp_ctx,
     610             :                                             cmd_ctx->domain, attrs, flags,
     611             :                                             cmd_ctx->orig_username,
     612             :                                             cmd_ctx->uid, groupnames,
     613           0 :                                             cmd_ctx->sudo_ctx->inverse_order,
     614             :                                             &rules, &num_rules);
     615           0 :     if (ret != EOK) {
     616           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     617             :              "Unable to retrieve sudo rules [%d]: %s\n", ret, strerror(ret));
     618           0 :         goto done;
     619             :     }
     620             : 
     621           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Returning %d rules for [%s@%s]\n",
     622             :                               num_rules, debug_name, cmd_ctx->domain->name);
     623             : 
     624           0 :     if (_rules != NULL) {
     625           0 :         *_rules = talloc_steal(mem_ctx, rules);
     626             :     }
     627             : 
     628           0 :     if (_num_rules != NULL) {
     629           0 :         *_num_rules = num_rules;
     630             :     }
     631             : 
     632           0 :     ret = EOK;
     633             : done:
     634           0 :     talloc_free(tmp_ctx);
     635           0 :     return ret;
     636             : }
     637             : 
     638             : static errno_t
     639             : sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool higher_wins);
     640             : 
     641           0 : static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
     642             :                                                  struct sss_domain_info *domain,
     643             :                                                  const char **attrs,
     644             :                                                  unsigned int flags,
     645             :                                                  const char *username,
     646             :                                                  uid_t uid,
     647             :                                                  char **groupnames,
     648             :                                                  bool inverse_order,
     649             :                                                  struct sysdb_attrs ***_rules,
     650             :                                                  uint32_t *_count)
     651             : {
     652             :     TALLOC_CTX *tmp_ctx;
     653             :     char *filter;
     654             :     errno_t ret;
     655             :     size_t count;
     656             :     struct sysdb_attrs **rules;
     657             :     struct ldb_message **msgs;
     658             : 
     659           0 :     tmp_ctx = talloc_new(NULL);
     660           0 :     if (tmp_ctx == NULL) return ENOMEM;
     661             : 
     662           0 :     ret = sysdb_get_sudo_filter(tmp_ctx, username, uid, groupnames,
     663             :                                 flags, &filter);
     664           0 :     if (ret != EOK) {
     665           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     666             :               "Could not construct the search filter [%d]: %s\n",
     667             :                ret, strerror(ret));
     668           0 :         goto done;
     669             :     }
     670             : 
     671           0 :     DEBUG(SSSDBG_FUNC_DATA, "Searching sysdb with [%s]\n", filter);
     672             : 
     673           0 :     if (IS_SUBDOMAIN(domain)) {
     674             :         /* rules are stored inside parent domain tree */
     675           0 :         domain = domain->parent;
     676             :     }
     677             : 
     678           0 :     ret = sysdb_search_custom(tmp_ctx, domain, filter,
     679             :                               SUDORULE_SUBDIR, attrs,
     680             :                               &count, &msgs);
     681           0 :     if (ret != EOK && ret != ENOENT) {
     682           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up SUDO rules\n");
     683           0 :         goto done;
     684           0 :     } if (ret == ENOENT) {
     685           0 :        *_rules = NULL;
     686           0 :        *_count = 0;
     687           0 :        ret = EOK;
     688           0 :        goto done;
     689             :     }
     690             : 
     691           0 :     ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &rules);
     692           0 :     if (ret != EOK) {
     693           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     694             :               "Could not convert ldb message to sysdb_attrs\n");
     695           0 :         goto done;
     696             :     }
     697             : 
     698           0 :     ret = sort_sudo_rules(rules, count, inverse_order);
     699           0 :     if (ret != EOK) {
     700           0 :         DEBUG(SSSDBG_OP_FAILURE,
     701             :               "Could not sort rules by sudoOrder\n");
     702           0 :         goto done;
     703             :     }
     704             : 
     705           0 :     *_rules = talloc_steal(mem_ctx, rules);
     706           0 :     *_count = (uint32_t)count;
     707             : 
     708           0 :     ret = EOK;
     709             : done:
     710           0 :     talloc_free(tmp_ctx);
     711           0 :     return ret;
     712             : }
     713             : 
     714             : static int
     715           0 : sudo_order_cmp(const void *a, const void *b, bool lower_wins)
     716             : {
     717             :     struct sysdb_attrs *r1, *r2;
     718             :     uint32_t o1, o2;
     719             :     int ret;
     720             : 
     721           0 :     r1 = * (struct sysdb_attrs * const *) a;
     722           0 :     r2 = * (struct sysdb_attrs * const *) b;
     723           0 :     if (!r1 || !r2) {
     724           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Wrong data?\n");
     725           0 :         return 0;
     726             :     }
     727             : 
     728           0 :     ret = sysdb_attrs_get_uint32_t(r1, SYSDB_SUDO_CACHE_AT_ORDER, &o1);
     729           0 :     if (ret == ENOENT) {
     730             :         /* man sudoers-ldap: If the sudoOrder attribute is not present,
     731             :          * a value of 0 is assumed */
     732           0 :         o1 = 0;
     733           0 :     } else if (ret != EOK) {
     734           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot get sudoOrder value\n");
     735           0 :         return 0;
     736             :     }
     737             : 
     738           0 :     ret = sysdb_attrs_get_uint32_t(r2, SYSDB_SUDO_CACHE_AT_ORDER, &o2);
     739           0 :     if (ret == ENOENT) {
     740             :         /* man sudoers-ldap: If the sudoOrder attribute is not present,
     741             :          * a value of 0 is assumed */
     742           0 :         o2 = 0;
     743           0 :     } else if (ret != EOK) {
     744           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot get sudoOrder value\n");
     745           0 :         return 0;
     746             :     }
     747             : 
     748           0 :     if (lower_wins) {
     749             :         /* The lowest value takes priority. Original wrong SSSD behaviour. */
     750           0 :         if (o1 > o2) {
     751           0 :             return 1;
     752           0 :         } else if (o1 < o2) {
     753           0 :             return -1;
     754             :         }
     755             :     } else {
     756             :         /* The higher value takes priority. Standard LDAP behaviour. */
     757           0 :         if (o1 < o2) {
     758           0 :             return 1;
     759           0 :         } else if (o1 > o2) {
     760           0 :             return -1;
     761             :         }
     762             :     }
     763             : 
     764           0 :     return 0;
     765             : }
     766             : 
     767             : static int
     768           0 : sudo_order_low_cmp_fn(const void *a, const void *b)
     769             : {
     770           0 :     return sudo_order_cmp(a, b, true);
     771             : }
     772             : 
     773             : static int
     774           0 : sudo_order_high_cmp_fn(const void *a, const void *b)
     775             : {
     776           0 :     return sudo_order_cmp(a, b, false);
     777             : }
     778             : 
     779             : static errno_t
     780           0 : sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool lower_wins)
     781             : {
     782           0 :     if (lower_wins) {
     783           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with lower-wins logic\n");
     784           0 :         qsort(rules, count, sizeof(struct sysdb_attrs *),
     785             :               sudo_order_low_cmp_fn);
     786             :     } else {
     787           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with higher-wins logic\n");
     788           0 :         qsort(rules, count, sizeof(struct sysdb_attrs *),
     789             :               sudo_order_high_cmp_fn);
     790             :     }
     791             : 
     792           0 :     return EOK;
     793             : }

Generated by: LCOV version 1.10