LCOV - code coverage report
Current view: top level - responder/common - responder_cache_req.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 521 691 75.4 %
Date: 2016-06-29 Functions: 41 42 97.6 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Pavel Březina <pbrezina@redhat.com>
       4             : 
       5             :     Copyright (C) 2014 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <dbus/dbus.h>
      22             : #include <ldb.h>
      23             : #include <talloc.h>
      24             : #include <tevent.h>
      25             : 
      26             : #include "util/util.h"
      27             : #include "db/sysdb.h"
      28             : #include "responder/common/responder_cache_req.h"
      29             : #include "providers/data_provider.h"
      30             : 
      31             : #define CACHE_REQ_DEBUG(level, cr, fmt, ...) \
      32             :     DEBUG(level, "Cache Request [%s #%u]: " fmt, \
      33             :           (cr)->reqname, (cr)->reqid, ##__VA_ARGS__)
      34             : 
      35          10 : static errno_t updated_users_by_filter(TALLOC_CTX *mem_ctx,
      36             :                                        struct sss_domain_info *domain,
      37             :                                        const char *name_filter,
      38             :                                        time_t since,
      39             :                                        struct ldb_result **_res)
      40             : {
      41             :     int ret;
      42             :     char *recent_filter;
      43             : 
      44          10 :     recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
      45             :                                     SYSDB_LAST_UPDATE, since);
      46          10 :     if (recent_filter == NULL) {
      47           0 :         return ENOMEM;
      48             :     }
      49             : 
      50          10 :     ret = sysdb_enumpwent_filter_with_views(mem_ctx, domain,
      51             :                                             name_filter, recent_filter,
      52             :                                             _res);
      53          10 :     talloc_free(recent_filter);
      54          10 :     return ret;
      55             : }
      56             : 
      57           8 : static errno_t updated_groups_by_filter(TALLOC_CTX *mem_ctx,
      58             :                                         struct sss_domain_info *domain,
      59             :                                         const char *name_filter,
      60             :                                         time_t since,
      61             :                                         struct ldb_result **_res)
      62             : {
      63             :     int ret;
      64             :     char *recent_filter;
      65             : 
      66           8 :     recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
      67             :                                     SYSDB_LAST_UPDATE, since);
      68           8 :     if (recent_filter == NULL) {
      69           0 :         return ENOMEM;
      70             :     }
      71             : 
      72           8 :     ret = sysdb_enumgrent_filter_with_views(mem_ctx, domain,
      73             :                                             name_filter, recent_filter,
      74             :                                             _res);
      75           8 :     talloc_free(recent_filter);
      76           8 :     return ret;
      77             : }
      78             : 
      79             : struct cache_req_data {
      80             :     enum cache_req_type type;
      81             :     struct {
      82             :         const char *input;  /* Original input. */
      83             :         const char *name;   /* Parsed name or UPN. */
      84             :         const char *lookup; /* Converted per domain rules. */
      85             :     } name;
      86             :     uint32_t id;
      87             :     const char *cert;
      88             :     const char *sid;
      89             :     const char **attrs;
      90             : };
      91             : 
      92             : static struct cache_req_data *
      93          77 : cache_req_data_create(TALLOC_CTX *mem_ctx,
      94             :                       enum cache_req_type type,
      95             :                       struct cache_req_data *input)
      96             : {
      97             :     struct cache_req_data *data;
      98             :     errno_t ret;
      99             : 
     100          77 :     data = talloc_zero(mem_ctx, struct cache_req_data);
     101          77 :     if (data == NULL) {
     102           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
     103           0 :         return NULL;
     104             :     }
     105             : 
     106          77 :     data->type = type;
     107             : 
     108          77 :     switch (type) {
     109             :     case CACHE_REQ_USER_BY_NAME:
     110             :     case CACHE_REQ_USER_BY_UPN:
     111             :     case CACHE_REQ_GROUP_BY_NAME:
     112             :     case CACHE_REQ_USER_BY_FILTER:
     113             :     case CACHE_REQ_GROUP_BY_FILTER:
     114             :     case CACHE_REQ_INITGROUPS:
     115             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     116          35 :         if (input->name.input == NULL) {
     117           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
     118           0 :             ret = ERR_INTERNAL;
     119           0 :             goto done;
     120             :         }
     121             : 
     122          35 :         data->name.input = talloc_strdup(data, input->name.input);
     123          35 :         if (data->name.input == NULL) {
     124           0 :             ret = ENOMEM;
     125           0 :             goto done;
     126             :         }
     127          35 :         break;
     128             :     case CACHE_REQ_USER_BY_CERT:
     129          10 :         if (input->cert == NULL) {
     130           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: certificate cannot be NULL!\n");
     131           0 :             ret = ERR_INTERNAL;
     132           0 :             goto done;
     133             :         }
     134             : 
     135          10 :         data->cert = talloc_strdup(data, input->cert);
     136          10 :         if (data->cert == NULL) {
     137           0 :             ret = ENOMEM;
     138           0 :             goto done;
     139             :         }
     140          10 :         break;
     141             :     case CACHE_REQ_USER_BY_ID:
     142             :     case CACHE_REQ_GROUP_BY_ID:
     143          16 :         if (input->id == 0) {
     144           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0!\n");
     145           0 :             ret = ERR_INTERNAL;
     146           0 :             goto done;
     147             :         }
     148             : 
     149          16 :         data->id = input->id;
     150          16 :         break;
     151             :     case CACHE_REQ_OBJECT_BY_SID:
     152          16 :         if (input->sid == NULL) {
     153           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: SID cannot be NULL!\n");
     154           0 :             ret = ERR_INTERNAL;
     155           0 :             goto done;
     156             :         }
     157             : 
     158          16 :         data->sid = talloc_strdup(data, input->sid);
     159          16 :         if (data->sid == NULL) {
     160           0 :             ret = ENOMEM;
     161           0 :             goto done;
     162             :         }
     163          16 :         break;
     164             :     }
     165             : 
     166          77 :     if (input->attrs != NULL) {
     167          16 :         data->attrs = dup_string_list(data, input->attrs);
     168          16 :         if (data->attrs == NULL) {
     169           0 :             ret = ENOMEM;
     170           0 :             goto done;
     171             :         }
     172             :     }
     173             : 
     174          77 :     ret = EOK;
     175             : 
     176             : done:
     177          77 :     if (ret != EOK) {
     178           0 :         talloc_zfree(data);
     179           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create cache_req data "
     180             :               "[%d]: %s\n", ret, sss_strerror(ret));
     181           0 :         return NULL;
     182             :     }
     183             : 
     184          77 :     return data;
     185             : }
     186             : 
     187             : struct cache_req_data *
     188          35 : cache_req_data_name(TALLOC_CTX *mem_ctx,
     189             :                     enum cache_req_type type,
     190             :                     const char *name)
     191             : {
     192          35 :     struct cache_req_data input = {0};
     193             : 
     194          35 :     input.name.input = name;
     195             : 
     196          35 :     return cache_req_data_create(mem_ctx, type, &input);
     197             : }
     198             : 
     199             : struct cache_req_data *
     200          16 : cache_req_data_id(TALLOC_CTX *mem_ctx,
     201             :                   enum cache_req_type type,
     202             :                   uint32_t id)
     203             : {
     204          16 :     struct cache_req_data input = {0};
     205             : 
     206          16 :     input.id = id;
     207             : 
     208          16 :     return cache_req_data_create(mem_ctx, type, &input);
     209             : }
     210             : 
     211             : struct cache_req_data *
     212          10 : cache_req_data_cert(TALLOC_CTX *mem_ctx,
     213             :                     enum cache_req_type type,
     214             :                     const char *cert)
     215             : {
     216          10 :     struct cache_req_data input = {0};
     217             : 
     218          10 :     input.cert = cert;
     219             : 
     220          10 :     return cache_req_data_create(mem_ctx, type, &input);
     221             : }
     222             : 
     223             : struct cache_req_data *
     224          16 : cache_req_data_sid(TALLOC_CTX *mem_ctx,
     225             :                    enum cache_req_type type,
     226             :                    const char *sid,
     227             :                    const char **attrs)
     228             : {
     229          16 :     struct cache_req_data input = {0};
     230             : 
     231          16 :     input.sid = sid;
     232          16 :     input.attrs = attrs;
     233             : 
     234          16 :     return cache_req_data_create(mem_ctx, type, &input);
     235             : }
     236             : 
     237             : struct cache_req {
     238             :     /* Provided input. */
     239             :     struct cache_req_data *data;
     240             : 
     241             :     /* Data Provider request type resolved from @type.
     242             :      * FIXME: This is currently needed for data provider calls. We should
     243             :      * refactor responder_dp.c to get rid of this member. */
     244             :     enum sss_dp_acct_type dp_type;
     245             : 
     246             :     /* Domain related informations. */
     247             :     struct sss_domain_info *domain;
     248             : 
     249             :     /* Debug information */
     250             :     uint32_t reqid;
     251             :     const char *reqname;
     252             :     const char *debugobj;
     253             : 
     254             :     /* Time when the request started. Useful for by-filter lookups */
     255             :     time_t req_start;
     256             : };
     257             : 
     258             : static void
     259          77 : cache_req_set_dp(struct cache_req *cr, enum cache_req_type type)
     260             : {
     261          77 :     switch (type) {
     262             :     case CACHE_REQ_USER_BY_NAME:
     263             :     case CACHE_REQ_USER_BY_UPN:
     264             :     case CACHE_REQ_USER_BY_ID:
     265          25 :         cr->dp_type = SSS_DP_USER;
     266          25 :         break;
     267             : 
     268             :     case CACHE_REQ_GROUP_BY_NAME:
     269             :     case CACHE_REQ_GROUP_BY_ID:
     270          17 :         cr->dp_type = SSS_DP_GROUP;
     271          17 :         break;
     272             : 
     273             :     case CACHE_REQ_INITGROUPS:
     274             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     275           0 :         cr->dp_type = SSS_DP_INITGROUPS;
     276           0 :         break;
     277             : 
     278             :     case CACHE_REQ_USER_BY_CERT:
     279          10 :         cr->dp_type = SSS_DP_CERT;
     280          10 :         break;
     281             : 
     282             :     case CACHE_REQ_USER_BY_FILTER:
     283           5 :         cr->dp_type = SSS_DP_WILDCARD_USER;
     284           5 :         break;
     285             : 
     286             :     case CACHE_REQ_GROUP_BY_FILTER:
     287           4 :         cr->dp_type = SSS_DP_WILDCARD_GROUP;
     288           4 :         break;
     289             : 
     290             :     case CACHE_REQ_OBJECT_BY_SID:
     291          16 :         cr->dp_type = SSS_DP_SECID;
     292          16 :         break;
     293             :     }
     294             : 
     295          77 :     return;
     296             : }
     297             : 
     298             : static void
     299          77 : cache_req_set_reqname(struct cache_req *cr, enum cache_req_type type)
     300             : {
     301          77 :     switch (type) {
     302             :     case CACHE_REQ_USER_BY_NAME:
     303          17 :         cr->reqname = "User by name";
     304          17 :         break;
     305             :     case CACHE_REQ_USER_BY_UPN:
     306           0 :         cr->reqname = "User by UPN";
     307           0 :         break;
     308             :     case CACHE_REQ_USER_BY_ID:
     309           8 :         cr->reqname = "User by ID";
     310           8 :         break;
     311             :     case CACHE_REQ_GROUP_BY_NAME:
     312           9 :         cr->reqname = "Group by name";
     313           9 :         break;
     314             :     case CACHE_REQ_GROUP_BY_ID:
     315           8 :         cr->reqname = "Group by ID";
     316           8 :         break;
     317             :     case CACHE_REQ_INITGROUPS:
     318           0 :         cr->reqname = "Initgroups by name";
     319           0 :         break;
     320             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     321           0 :         cr->reqname = "Initgroups by UPN";
     322           0 :         break;
     323             :     case CACHE_REQ_USER_BY_CERT:
     324          10 :         cr->reqname = "User by certificate";
     325          10 :         break;
     326             :     case CACHE_REQ_USER_BY_FILTER:
     327           5 :         cr->reqname = "User by filter";
     328           5 :         break;
     329             :     case CACHE_REQ_GROUP_BY_FILTER:
     330           4 :         cr->reqname = "Group by filter";
     331           4 :         break;
     332             :     case CACHE_REQ_OBJECT_BY_SID:
     333          16 :         cr->reqname = "Object by SID";
     334          16 :         break;
     335             :     }
     336             : 
     337          77 :     return;
     338             : }
     339             : 
     340             : static struct cache_req *
     341          77 : cache_req_create(TALLOC_CTX *mem_ctx,
     342             :                  struct resp_ctx *rctx,
     343             :                  struct cache_req_data *data)
     344             : {
     345             :     struct cache_req *cr;
     346             : 
     347          77 :     cr = talloc_zero(mem_ctx, struct cache_req);
     348          77 :     if (cr == NULL) {
     349           0 :         return NULL;
     350             :     }
     351             : 
     352          77 :     cr->data = data;
     353          77 :     cr->req_start = time(NULL);
     354             : 
     355             :     /* It is perfectly fine to just overflow here. */
     356          77 :     cr->reqid = rctx->cache_req_num++;
     357             : 
     358          77 :     cache_req_set_reqname(cr, data->type);
     359          77 :     cache_req_set_dp(cr, data->type);
     360             : 
     361          77 :     return cr;
     362             : }
     363             : 
     364             : static errno_t
     365          35 : cache_req_set_name(struct cache_req *cr, const char *name)
     366             : {
     367             :     const char *dup_name;
     368             : 
     369          35 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Setting name [%s]\n", name);
     370             : 
     371          35 :     dup_name = talloc_strdup(cr->data, name);
     372          35 :     if (dup_name == NULL) {
     373           0 :         return ENOMEM;
     374             :     }
     375             : 
     376          35 :     talloc_zfree(cr->data->name.name);
     377          35 :     cr->data->name.name = dup_name;
     378             : 
     379          35 :     return EOK;
     380             : }
     381             : 
     382             : static errno_t
     383         119 : cache_req_set_domain(struct cache_req *cr,
     384             :                      struct sss_domain_info *domain,
     385             :                      struct resp_ctx *rctx)
     386             : {
     387         119 :     TALLOC_CTX *tmp_ctx = NULL;
     388         119 :     const char *name = NULL;
     389         119 :     const char *debugobj = NULL;
     390             :     errno_t ret;
     391             : 
     392         119 :     tmp_ctx = talloc_new(NULL);
     393         119 :     if (tmp_ctx == NULL) {
     394           0 :         return ENOMEM;
     395             :     }
     396             : 
     397         119 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Using domain [%s]\n", domain->name);
     398             : 
     399         119 :     talloc_zfree(cr->data->name.lookup);
     400         119 :     talloc_zfree(cr->debugobj);
     401             : 
     402         119 :     switch (cr->data->type) {
     403             :     case CACHE_REQ_USER_BY_NAME:
     404             :     case CACHE_REQ_USER_BY_UPN:
     405             :     case CACHE_REQ_GROUP_BY_NAME:
     406             :     case CACHE_REQ_USER_BY_FILTER:
     407             :     case CACHE_REQ_GROUP_BY_FILTER:
     408             :     case CACHE_REQ_INITGROUPS:
     409             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     410          53 :         if (cr->data->name.name == NULL) {
     411           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
     412           0 :             ret = ERR_INTERNAL;
     413           0 :             goto done;
     414             :         }
     415             : 
     416          53 :         name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
     417          53 :                                   domain->case_sensitive);
     418          53 :         if (name == NULL) {
     419           0 :             ret = ENOMEM;
     420           0 :             goto done;
     421             :         }
     422             : 
     423          53 :         name = sss_reverse_replace_space(tmp_ctx, name, rctx->override_space);
     424          53 :         if (name == NULL) {
     425           0 :             ret = ENOMEM;
     426           0 :             goto done;
     427             :         }
     428             : 
     429          53 :         debugobj = talloc_asprintf(tmp_ctx, "%s@%s", name, domain->name);
     430          53 :         if (debugobj == NULL) {
     431           0 :             ret = ENOMEM;
     432           0 :             goto done;
     433             :         }
     434             : 
     435          53 :         break;
     436             : 
     437             :     case CACHE_REQ_USER_BY_ID:
     438          28 :         debugobj = talloc_asprintf(tmp_ctx, "UID:%d@%s",
     439          14 :                                    cr->data->id, domain->name);
     440          14 :         if (debugobj == NULL) {
     441           0 :             ret = ENOMEM;
     442           0 :             goto done;
     443             :         }
     444          14 :         break;
     445             : 
     446             :     case CACHE_REQ_GROUP_BY_ID:
     447          28 :         debugobj = talloc_asprintf(tmp_ctx, "GID:%d@%s",
     448          14 :                                    cr->data->id, domain->name);
     449          14 :         if (debugobj == NULL) {
     450           0 :             ret = ENOMEM;
     451           0 :             goto done;
     452             :         }
     453          14 :         break;
     454             :     case CACHE_REQ_USER_BY_CERT:
     455             :         /* certificates might be quite long, only use the last 10 charcters
     456             :          * for logging */
     457          20 :         debugobj = talloc_asprintf(tmp_ctx, "CERT:%s@%s",
     458          10 :                                    get_last_x_chars(cr->data->cert, 10),
     459             :                                    domain->name);
     460          10 :         if (debugobj == NULL) {
     461           0 :             ret = ENOMEM;
     462           0 :             goto done;
     463             :         }
     464          10 :         break;
     465             :     case CACHE_REQ_OBJECT_BY_SID:
     466          56 :         debugobj = talloc_asprintf(tmp_ctx, "SID:%s@%s",
     467          28 :                                    cr->data->sid, domain->name);
     468          28 :         if (debugobj == NULL) {
     469           0 :             ret = ENOMEM;
     470           0 :             goto done;
     471             :         }
     472          28 :         break;
     473             :     }
     474             : 
     475         119 :     cr->domain = domain;
     476         119 :     cr->data->name.lookup = talloc_steal(cr->data, name);
     477         119 :     cr->debugobj = talloc_steal(cr, debugobj);
     478             : 
     479         119 :     ret = EOK;
     480             : 
     481             : done:
     482         119 :     talloc_free(tmp_ctx);
     483         119 :     return ret;
     484             : }
     485             : 
     486             : static bool
     487         183 : cache_req_is_upn(struct cache_req *cr)
     488             : {
     489         183 :     switch (cr->data->type) {
     490             :     case CACHE_REQ_USER_BY_UPN:
     491             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     492          27 :         return true;
     493             :     default:
     494         156 :         return false;
     495             :     }
     496             : }
     497             : 
     498             : static bool
     499          24 : cache_req_assume_upn(struct cache_req *cr)
     500             : {
     501             :     errno_t ret;
     502             :     bool bret;
     503             : 
     504          24 :     if (cr->data->name.input == NULL
     505          16 :             || strchr(cr->data->name.input, '@') == NULL) {
     506          16 :         return false;
     507             :     }
     508             : 
     509           8 :     switch (cr->data->type) {
     510             :     case CACHE_REQ_USER_BY_NAME:
     511           8 :         cr->data->type = CACHE_REQ_USER_BY_UPN;
     512           8 :         bret = true;
     513           8 :         break;
     514             :     case CACHE_REQ_INITGROUPS:
     515           0 :         cr->data->type = CACHE_REQ_INITGROUPS_BY_UPN;
     516           0 :         bret = true;
     517           0 :         break;
     518             :     default:
     519           0 :         bret = false;
     520           0 :         break;
     521             :     }
     522             : 
     523           8 :     if (bret == true) {
     524           8 :         ret = cache_req_set_name(cr, cr->data->name.input);
     525           8 :         if (ret != EOK) {
     526           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_set_name() failed\n");
     527           0 :             return false;
     528             :         }
     529             : 
     530           8 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Assuming UPN [%s]\n",
     531             :                         cr->data->name.input);
     532             :     }
     533             : 
     534           8 :     return bret;
     535             : }
     536             : 
     537         119 : static errno_t cache_req_check_ncache(struct cache_req *cr,
     538             :                                       struct sss_nc_ctx *ncache)
     539             : {
     540         119 :     errno_t ret = ERR_INTERNAL;
     541             : 
     542         119 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Checking negative cache "
     543             :                     "for [%s]\n", cr->debugobj);
     544             : 
     545         119 :     switch (cr->data->type) {
     546             :     case CACHE_REQ_USER_BY_NAME:
     547             :     case CACHE_REQ_USER_BY_UPN:
     548             :     case CACHE_REQ_INITGROUPS:
     549             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     550          29 :         ret = sss_ncache_check_user(ncache, cr->domain, cr->data->name.lookup);
     551          29 :         break;
     552             :     case CACHE_REQ_GROUP_BY_NAME:
     553          15 :         ret = sss_ncache_check_group(ncache, cr->domain, cr->data->name.lookup);
     554          15 :         break;
     555             :     case CACHE_REQ_USER_BY_ID:
     556          14 :         ret = sss_ncache_check_uid(ncache, NULL, cr->data->id);
     557          14 :         break;
     558             :     case CACHE_REQ_GROUP_BY_ID:
     559          14 :         ret = sss_ncache_check_gid(ncache, NULL, cr->data->id);
     560          14 :         break;
     561             :     case CACHE_REQ_USER_BY_CERT:
     562          10 :         ret = sss_ncache_check_cert(ncache, cr->data->cert);
     563          10 :         break;
     564             :     case CACHE_REQ_USER_BY_FILTER:
     565             :     case CACHE_REQ_GROUP_BY_FILTER:
     566           9 :         ret = EOK;
     567           9 :         break;
     568             :     case CACHE_REQ_OBJECT_BY_SID:
     569          28 :         ret = sss_ncache_check_sid(ncache, cr->data->sid);
     570          28 :         break;
     571             :     }
     572             : 
     573         119 :     if (ret == EEXIST) {
     574           8 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "[%s] does not exist "
     575             :                         "(negative cache)\n", cr->debugobj);
     576             :     }
     577             : 
     578         119 :     return ret;
     579             : }
     580             : 
     581          63 : static void cache_req_add_to_ncache(struct cache_req *cr,
     582             :                                     struct sss_nc_ctx *ncache)
     583             : {
     584          63 :     errno_t ret = ERR_INTERNAL;
     585             : 
     586          63 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Adding [%s] to negative cache\n",
     587             :                     cr->debugobj);
     588             : 
     589          63 :     switch (cr->data->type) {
     590             :     case CACHE_REQ_USER_BY_NAME:
     591             :     case CACHE_REQ_USER_BY_UPN:
     592             :     case CACHE_REQ_INITGROUPS:
     593             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     594          16 :         ret = sss_ncache_set_user(ncache, false, cr->domain,
     595          16 :                                   cr->data->name.lookup);
     596          16 :         break;
     597             :     case CACHE_REQ_GROUP_BY_NAME:
     598           8 :         ret = sss_ncache_set_group(ncache, false, cr->domain,
     599           8 :                                    cr->data->name.lookup);
     600           8 :         break;
     601             :     case CACHE_REQ_USER_BY_FILTER:
     602             :     case CACHE_REQ_GROUP_BY_FILTER:
     603             :         /* Nothing to do, adding a wildcard request to ncache doesn't
     604             :          * make sense */
     605             :     case CACHE_REQ_USER_BY_ID:
     606             :     case CACHE_REQ_GROUP_BY_ID:
     607             :     case CACHE_REQ_USER_BY_CERT:
     608             :     case CACHE_REQ_OBJECT_BY_SID:
     609             :         /* Nothing to do. Those types must be unique among all domains so
     610             :          * the don't contain domain part. Therefore they must be set only
     611             :          * if all domains are search and the entry is not found. */
     612          39 :         ret = EOK;
     613          39 :         break;
     614             :     }
     615             : 
     616          63 :     if (ret != EOK) {
     617           0 :         CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr,
     618             :                         "Cannot set negative cache for [%s] [%d]: %s\n",
     619             :                         cr->debugobj, ret, sss_strerror(ret));
     620             : 
     621             :         /* not fatal */
     622             :     }
     623             : 
     624          63 :     return;
     625             : }
     626             : 
     627          13 : static void cache_req_add_to_ncache_global(struct cache_req *cr,
     628             :                                            struct sss_nc_ctx *ncache)
     629             : {
     630          13 :     errno_t ret = ERR_INTERNAL;
     631             : 
     632          13 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Adding [%s] to global "
     633             :                     "negative cache\n", cr->debugobj);
     634             : 
     635          13 :     switch (cr->data->type) {
     636             :     case CACHE_REQ_USER_BY_FILTER:
     637             :     case CACHE_REQ_GROUP_BY_FILTER:
     638             :         /* Nothing to do, adding a wildcard request to ncache doesn't
     639             :          * make sense */
     640             :     case CACHE_REQ_USER_BY_NAME:
     641             :     case CACHE_REQ_USER_BY_UPN:
     642             :     case CACHE_REQ_GROUP_BY_NAME:
     643             :     case CACHE_REQ_INITGROUPS:
     644             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     645             :         /* Nothing to do. Those types are already in ncache for selected
     646             :          * domains. */
     647           5 :         ret = EOK;
     648           5 :         break;
     649             :     case CACHE_REQ_USER_BY_ID:
     650           1 :         ret = sss_ncache_set_uid(ncache, false, NULL, cr->data->id);
     651           1 :         break;
     652             :     case CACHE_REQ_GROUP_BY_ID:
     653           1 :         ret = sss_ncache_set_gid(ncache, false, NULL, cr->data->id);
     654           1 :         break;
     655             :     case CACHE_REQ_USER_BY_CERT:
     656           4 :         ret = sss_ncache_set_cert(ncache, false, cr->data->cert);
     657           4 :         break;
     658             :     case CACHE_REQ_OBJECT_BY_SID:
     659           2 :         ret = sss_ncache_set_sid(ncache, false, cr->data->sid);
     660           2 :         break;
     661             :     }
     662             : 
     663          13 :     if (ret != EOK) {
     664           0 :         CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr, "Cannot set negcache for "
     665             :                         "[%s] [%d]: %s\n", cr->debugobj,
     666             :                         ret, sss_strerror(ret));
     667             : 
     668             :         /* not fatal */
     669             :     }
     670             : 
     671          13 :     return;
     672             : }
     673             : 
     674         198 : static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx,
     675             :                                     struct cache_req *cr,
     676             :                                     struct ldb_result **_result)
     677             : {
     678         198 :     struct ldb_result *result = NULL;
     679         198 :     bool one_item_only = false;
     680         198 :     errno_t ret = ERR_INTERNAL;
     681             : 
     682         198 :     CACHE_REQ_DEBUG(SSSDBG_FUNC_DATA, cr, "Requesting info for [%s]\n",
     683             :                     cr->debugobj);
     684             : 
     685         198 :     switch (cr->data->type) {
     686             :     case CACHE_REQ_USER_BY_NAME:
     687          24 :         one_item_only = true;
     688          24 :         ret = sysdb_getpwnam_with_views(mem_ctx, cr->domain,
     689          24 :                                         cr->data->name.lookup, &result);
     690          24 :         break;
     691             :     case CACHE_REQ_USER_BY_UPN:
     692          23 :         one_item_only = true;
     693          23 :         ret = sysdb_getpwupn(mem_ctx, cr->domain,
     694          23 :                              cr->data->name.lookup, &result);
     695          23 :         break;
     696             :     case CACHE_REQ_USER_BY_ID:
     697          23 :         one_item_only = true;
     698          23 :         ret = sysdb_getpwuid_with_views(mem_ctx, cr->domain,
     699          23 :                                         cr->data->id, &result);
     700          23 :         break;
     701             :     case CACHE_REQ_GROUP_BY_NAME:
     702          24 :         one_item_only = true;
     703          24 :         ret = sysdb_getgrnam_with_views(mem_ctx, cr->domain,
     704          24 :                                         cr->data->name.lookup, &result);
     705          24 :         break;
     706             :     case CACHE_REQ_GROUP_BY_ID:
     707          23 :         one_item_only = true;
     708          23 :         ret = sysdb_getgrgid_with_views(mem_ctx, cr->domain,
     709          23 :                                         cr->data->id, &result);
     710          23 :         break;
     711             :     case CACHE_REQ_INITGROUPS:
     712           0 :         one_item_only = false;
     713           0 :         ret = sysdb_initgroups_with_views(mem_ctx, cr->domain,
     714           0 :                                           cr->data->name.lookup, &result);
     715           0 :         break;
     716             :     case CACHE_REQ_INITGROUPS_BY_UPN:
     717           0 :         one_item_only = false;
     718           0 :         ret = sysdb_initgroups_by_upn(mem_ctx, cr->domain,
     719           0 :                                       cr->data->name.lookup, &result);
     720           0 :         break;
     721             :     case CACHE_REQ_USER_BY_CERT:
     722          17 :         one_item_only = true;
     723          17 :         ret = sysdb_search_user_by_cert_with_views(mem_ctx, cr->domain,
     724          17 :                                                    cr->data->cert, &result);
     725          17 :         break;
     726             :     case CACHE_REQ_USER_BY_FILTER:
     727          10 :         one_item_only = false;
     728          20 :         ret = updated_users_by_filter(mem_ctx, cr->domain,
     729          10 :                                       cr->data->name.lookup, cr->req_start,
     730             :                                       &result);
     731          10 :         break;
     732             :     case CACHE_REQ_GROUP_BY_FILTER:
     733           8 :         one_item_only = false;
     734          16 :         ret = updated_groups_by_filter(mem_ctx, cr->domain,
     735           8 :                                        cr->data->name.lookup, cr->req_start,
     736             :                                        &result);
     737           8 :         break;
     738             :     case CACHE_REQ_OBJECT_BY_SID:
     739          46 :         one_item_only = true;
     740          92 :         ret = sysdb_search_object_by_sid(mem_ctx, cr->domain,
     741          92 :                                          cr->data->sid, cr->data->attrs,
     742             :                                          &result);
     743          46 :         break;
     744             :     }
     745             : 
     746         198 :     if (ret != EOK) {
     747          62 :         goto done;
     748         136 :     } else if (result->count == 0) {
     749          81 :         ret = ENOENT;
     750          81 :         goto done;
     751          55 :     } else if (one_item_only && result->count > 1) {
     752           0 :         ret = ERR_INTERNAL;
     753           0 :         CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
     754             :                         "Multiple objects were found when "
     755             :                         "sysdb search expected only one!\n");
     756           0 :         goto done;
     757             :     }
     758             : 
     759          55 :     *_result = result;
     760             : 
     761             : done:
     762         198 :     return ret;
     763             : }
     764             : 
     765             : /* Return true if the request bypasses cache or false if the cache_req
     766             :  * code can leverage sysdb for this request.
     767             :  */
     768          31 : static bool cache_req_bypass_cache(struct cache_req *cr)
     769             : {
     770          62 :     if (cr->data->type == CACHE_REQ_USER_BY_FILTER ||
     771          31 :             cr->data->type == CACHE_REQ_GROUP_BY_FILTER) {
     772           0 :         return true;
     773             :     }
     774             : 
     775          31 :     return false;
     776             : }
     777             : 
     778         111 : static errno_t cache_req_expiration_status(struct cache_req *cr,
     779             :                                            struct ldb_result *result,
     780             :                                            time_t cache_refresh_percent)
     781             : {
     782             :     time_t expire;
     783             : 
     784         111 :     if (result == NULL || result->count == 0 || cache_req_bypass_cache(cr)) {
     785          80 :         return ENOENT;
     786             :     }
     787             : 
     788          31 :     if (cr->data->type == CACHE_REQ_INITGROUPS) {
     789           0 :         expire = ldb_msg_find_attr_as_uint64(result->msgs[0],
     790             :                                              SYSDB_INITGR_EXPIRE, 0);
     791             :     } else {
     792          31 :         expire = ldb_msg_find_attr_as_uint64(result->msgs[0],
     793             :                                              SYSDB_CACHE_EXPIRE, 0);
     794             :     }
     795             : 
     796          31 :     return sss_cmd_check_cache(result->msgs[0], cache_refresh_percent, expire);
     797             : }
     798             : 
     799         111 : static void cache_req_dpreq_params(TALLOC_CTX *mem_ctx,
     800             :                                    struct cache_req *cr,
     801             :                                    struct ldb_result *result,
     802             :                                    const char **_string,
     803             :                                    uint32_t *_id,
     804             :                                    const char **_flag)
     805             : {
     806         111 :     struct ldb_result *user = NULL;
     807         111 :     const char *name = NULL;
     808         111 :     uint32_t id = 0;
     809             :     errno_t ret;
     810             : 
     811         111 :     *_id = cr->data->id;
     812         111 :     *_string = cr->data->name.lookup;
     813         111 :     *_flag = NULL;
     814             : 
     815         111 :     if (cache_req_is_upn(cr)) {
     816          13 :         *_flag = EXTRA_NAME_IS_UPN;
     817         124 :         return;
     818             :     }
     819             : 
     820          98 :     if (cr->data->type == CACHE_REQ_USER_BY_CERT) {
     821           9 :         *_string = cr->data->cert;
     822           9 :         return;
     823          89 :     } else if (cr->data->type == CACHE_REQ_OBJECT_BY_SID) {
     824          26 :         *_string = cr->data->sid;
     825          26 :         return;
     826             :     }
     827             : 
     828          63 :     if (!DOM_HAS_VIEWS(cr->domain)) {
     829          63 :         return;
     830             :     }
     831             : 
     832             :     /* We must search with views. */
     833           0 :     if (result == NULL || result->count == 0) {
     834           0 :         *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
     835           0 :         return;
     836             :     }
     837             : 
     838             :     /* If domain has views we will try to user original values instead of the
     839             :      * overridden ones. This is a must for the LOCAL view since we can't look
     840             :      * it up otherwise. But it is also a shortcut for non-local views where
     841             :      * we will not fail over to the overridden value. */
     842             : 
     843           0 :     switch (cr->data->type) {
     844             :     case CACHE_REQ_USER_BY_NAME:
     845             :     case CACHE_REQ_GROUP_BY_NAME:
     846           0 :        name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL);
     847           0 :        if (name == NULL) {
     848           0 :            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL\n");
     849             :        }
     850           0 :        break;
     851             :     case CACHE_REQ_USER_BY_ID:
     852           0 :        id = ldb_msg_find_attr_as_uint64(result->msgs[0], SYSDB_UIDNUM, 0);
     853           0 :        if (id == 0) {
     854           0 :            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0\n");
     855             :        }
     856           0 :        break;
     857             :     case CACHE_REQ_GROUP_BY_ID:
     858           0 :        id = ldb_msg_find_attr_as_uint64(result->msgs[0], SYSDB_GIDNUM, 0);
     859           0 :        if (id == 0) {
     860           0 :            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0\n");
     861             :        }
     862           0 :        break;
     863             :     case CACHE_REQ_INITGROUPS:
     864           0 :         ret = sysdb_getpwnam_with_views(NULL, cr->domain,
     865           0 :                                         cr->data->name.lookup, &user);
     866           0 :         if (ret != EOK || user == NULL || user->count != 1) {
     867             :             /* Case where the user is not found has been already handled. If
     868             :              * this is not OK, it is an error. */
     869           0 :             CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
     870             :                             "Unable to match initgroups user [%d]: %s\n",
     871             :                             ret, sss_strerror(ret));
     872           0 :             break;
     873             :         }
     874             : 
     875           0 :         name = ldb_msg_find_attr_as_string(user->msgs[0], SYSDB_NAME,
     876             :                                            NULL);
     877           0 :         if (name == NULL) {
     878           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL\n");
     879           0 :             break;
     880             :         }
     881             : 
     882           0 :         talloc_steal(mem_ctx, name);
     883           0 :         talloc_free(user);
     884           0 :         break;
     885             :     default:
     886           0 :         return;
     887             :     }
     888             : 
     889             :     /* Now we have the original name and id. We don't have to search with
     890             :      * views unless some error occurred. */
     891           0 :     if (name == NULL && id == 0) {
     892           0 :         *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
     893           0 :         return;
     894             :     }
     895             : 
     896           0 :     *_string = talloc_steal(mem_ctx, name);
     897           0 :     *_id = id;
     898             : }
     899             : 
     900             : struct cache_req_cache_state {
     901             :     /* input data */
     902             :     struct tevent_context *ev;
     903             :     struct resp_ctx *rctx;
     904             :     struct sss_nc_ctx *ncache;
     905             :     int cache_refresh_percent;
     906             :     struct cache_req *cr;
     907             : 
     908             :     /* output data */
     909             :     struct ldb_result *result;
     910             : };
     911             : 
     912             : static errno_t cache_req_cache_search(struct tevent_req *req);
     913             : static errno_t cache_req_cache_check(struct tevent_req *req);
     914             : static void cache_req_cache_done(struct tevent_req *subreq);
     915             : 
     916         119 : static struct tevent_req *cache_req_cache_send(TALLOC_CTX *mem_ctx,
     917             :                                                struct tevent_context *ev,
     918             :                                                struct resp_ctx *rctx,
     919             :                                                struct sss_nc_ctx *ncache,
     920             :                                                int cache_refresh_percent,
     921             :                                                struct cache_req *cr)
     922             : {
     923         119 :     struct cache_req_cache_state *state = NULL;
     924         119 :     struct tevent_req *req = NULL;
     925             :     errno_t ret;
     926             : 
     927         119 :     req = tevent_req_create(mem_ctx, &state, struct cache_req_cache_state);
     928         119 :     if (req == NULL) {
     929           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
     930           0 :         return NULL;
     931             :     }
     932             : 
     933         119 :     state->ev = ev;
     934         119 :     state->rctx = rctx;
     935         119 :     state->ncache = ncache;
     936         119 :     state->cache_refresh_percent = cache_refresh_percent;
     937         119 :     state->cr = cr;
     938             : 
     939             :     /* Check negative cache first. */
     940         119 :     ret = cache_req_check_ncache(state->cr, state->ncache);
     941         119 :     if (ret == EEXIST) {
     942           8 :         ret = ENOENT;
     943           8 :         goto immediately;
     944             :     }
     945             : 
     946             :     /* We will first search the cache. If we get cache miss or the entry
     947             :      * is expired we will contact data provider and then search again. */
     948         111 :     ret = cache_req_cache_search(req);
     949         111 :     if (ret != EAGAIN) {
     950          24 :         goto immediately;
     951             :     }
     952             : 
     953          87 :     return req;
     954             : 
     955             : immediately:
     956          32 :     if (ret == EOK) {
     957          24 :         tevent_req_done(req);
     958             :     } else {
     959           8 :         tevent_req_error(req, ret);
     960             :     }
     961          32 :     tevent_req_post(req, ev);
     962             : 
     963          32 :     return req;
     964             : }
     965             : 
     966         111 : static errno_t cache_req_cache_search(struct tevent_req *req)
     967             : {
     968         111 :     struct cache_req_cache_state *state = NULL;
     969             :     errno_t ret;
     970             : 
     971         111 :     state = tevent_req_data(req, struct cache_req_cache_state);
     972             : 
     973         111 :     ret = cache_req_get_object(state, state->cr, &state->result);
     974         111 :     if (ret != EOK && ret != ENOENT) {
     975           0 :         CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, "Failed to make "
     976             :                         "request to our cache [%d]: %s\n",
     977             :                         ret, sss_strerror(ret));
     978           0 :         return ret;
     979             :     }
     980             : 
     981             :     /* Verify that the cache is up to date. */
     982         111 :     ret = cache_req_cache_check(req);
     983         111 :     if (ret != EOK) {
     984          87 :         CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, state->cr,
     985             :                         "Cannot find info for [%s]\n", state->cr->debugobj);
     986          87 :         return ret;
     987             :     }
     988             : 
     989             :     /* One result found */
     990          24 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
     991             :                     "Returning info for [%s]\n", state->cr->debugobj);
     992          24 :     return EOK;
     993             : }
     994             : 
     995         111 : static errno_t cache_req_cache_check(struct tevent_req *req)
     996             : {
     997         111 :     struct cache_req_cache_state *state = NULL;
     998         111 :     struct tevent_req *subreq = NULL;
     999         111 :     const char *extra_flag = NULL;
    1000             :     const char *search_str;
    1001             :     uint32_t search_id;
    1002             :     errno_t ret;
    1003             : 
    1004         111 :     state = tevent_req_data(req, struct cache_req_cache_state);
    1005             : 
    1006         111 :     cache_req_dpreq_params(state, state->cr, state->result,
    1007             :                            &search_str, &search_id, &extra_flag);
    1008             : 
    1009         111 :     ret = cache_req_expiration_status(state->cr, state->result,
    1010         111 :                                       state->cache_refresh_percent);
    1011             : 
    1012         111 :     switch (ret) {
    1013             :     case EOK:
    1014          17 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
    1015             :                         "[%s] entry is valid\n", state->cr->debugobj);
    1016          17 :         return EOK;
    1017             :     case EAGAIN:
    1018             :         /* Out of band update. The calling function will return the cached
    1019             :          * entry immediately. No callback is required. */
    1020             : 
    1021           7 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
    1022             :                         "Performing midpoint cache update of [%s]\n",
    1023             :                         state->cr->debugobj);
    1024             : 
    1025          21 :         subreq = sss_dp_get_account_send(state, state->rctx,
    1026           7 :                                          state->cr->domain, true,
    1027           7 :                                          state->cr->dp_type,
    1028             :                                          search_str, search_id, extra_flag);
    1029           7 :         if (subreq == NULL) {
    1030           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory sending out-of-band "
    1031             :                                        "data provider request\n");
    1032             :             /* This is non-fatal, so we'll continue here */
    1033             :         }
    1034             : 
    1035           7 :         return EOK;
    1036             :     case ENOENT:
    1037             :         /* Cache miss or the cache is expired. We need to get the updated
    1038             :          * information before returning it. */
    1039             : 
    1040          87 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
    1041             :                         "Looking up [%s] in data provider\n",
    1042             :                         state->cr->debugobj);
    1043             : 
    1044         261 :         subreq = sss_dp_get_account_send(state, state->rctx,
    1045          87 :                                          state->cr->domain, true,
    1046          87 :                                          state->cr->dp_type,
    1047             :                                          search_str, search_id, extra_flag);
    1048          87 :         if (subreq == NULL) {
    1049           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1050             :                   "Out of memory sending data provider request\n");
    1051           0 :             return ENOMEM;
    1052             :         }
    1053             : 
    1054          87 :         tevent_req_set_callback(subreq, cache_req_cache_done, req);
    1055          87 :         return EAGAIN;
    1056             :     default:
    1057             :         /* error */
    1058           0 :         CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, "Error checking "
    1059             :                         "cache [%d]: %s\n", ret, sss_strerror(ret));
    1060           0 :         return ret;
    1061             :     }
    1062             : }
    1063             : 
    1064          87 : static void cache_req_cache_done(struct tevent_req *subreq)
    1065             : {
    1066          87 :     struct cache_req_cache_state *state = NULL;
    1067          87 :     struct tevent_req *req = NULL;
    1068          87 :     char *err_msg = NULL;
    1069             :     dbus_uint16_t err_maj;
    1070             :     dbus_uint32_t err_min;
    1071             :     errno_t ret;
    1072             : 
    1073          87 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1074          87 :     state = tevent_req_data(req, struct cache_req_cache_state);
    1075             : 
    1076          87 :     ret = sss_dp_get_account_recv(state, subreq, &err_maj, &err_min, &err_msg);
    1077          87 :     talloc_zfree(subreq);
    1078          87 :     if (ret != EOK) {
    1079           0 :         CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, state->cr,
    1080             :                         "Could not get account info [%d]: %s\n",
    1081             :                         ret, sss_strerror(ret));
    1082             :     }
    1083             : 
    1084          87 :     if (err_maj) {
    1085           0 :         CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, state->cr,
    1086             :               "Data Provider Error: %u, %u, %s (will return cached data)\n",
    1087             :               (unsigned int)err_maj, (unsigned int)err_min, err_msg);
    1088             :     }
    1089             : 
    1090             :     /* Get result from cache again. */
    1091          87 :     ret = cache_req_get_object(state, state->cr, &state->result);
    1092          87 :     if (ret == ENOENT) {
    1093          63 :         cache_req_add_to_ncache(state->cr, state->ncache);
    1094          63 :         ret = ENOENT;
    1095          24 :     } else if (ret != EOK) {
    1096           0 :         CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
    1097             :                         "Failed to make request to our cache [%d]: %s\n",
    1098             :                         ret, sss_strerror(ret));
    1099             :     }
    1100             : 
    1101          87 :     if (ret != EOK) {
    1102          63 :         tevent_req_error(req, ret);
    1103         150 :         return;
    1104             :     }
    1105             : 
    1106             :     /* One result found */
    1107          24 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
    1108             :                     "Returning %u results for [%s]\n", state->result->count,
    1109             :                     state->cr->debugobj);
    1110             : 
    1111          24 :     tevent_req_done(req);
    1112             : }
    1113             : 
    1114         119 : static errno_t cache_req_cache_recv(TALLOC_CTX *mem_ctx,
    1115             :                                     struct tevent_req *req,
    1116             :                                     struct ldb_result **_result)
    1117             : {
    1118         119 :     struct cache_req_cache_state *state = NULL;
    1119         119 :     state = tevent_req_data(req, struct cache_req_cache_state);
    1120             : 
    1121         190 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1122             : 
    1123          48 :     *_result = talloc_steal(mem_ctx, state->result);
    1124             : 
    1125          48 :     return EOK;
    1126             : }
    1127             : 
    1128             : 
    1129             : struct cache_req_state {
    1130             :     /* input data */
    1131             :     struct tevent_context *ev;
    1132             :     struct resp_ctx *rctx;
    1133             :     struct sss_nc_ctx *ncache;
    1134             :     int cache_refresh_percent;
    1135             :     struct cache_req *cr;
    1136             : 
    1137             :     /* work data */
    1138             :     struct ldb_result *result;
    1139             :     struct sss_domain_info *domain;
    1140             :     struct sss_domain_info *selected_domain;
    1141             :     bool check_next;
    1142             : };
    1143             : 
    1144             : static void cache_req_input_parsed(struct tevent_req *subreq);
    1145             : 
    1146             : static errno_t cache_req_select_domains(struct tevent_req *req,
    1147             :                                         const char *domain);
    1148             : 
    1149             : static errno_t cache_req_next_domain(struct tevent_req *req);
    1150             : 
    1151             : static void cache_req_done(struct tevent_req *subreq);
    1152             : 
    1153          77 : struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
    1154             :                                   struct tevent_context *ev,
    1155             :                                   struct resp_ctx *rctx,
    1156             :                                   struct sss_nc_ctx *ncache,
    1157             :                                   int cache_refresh_percent,
    1158             :                                   const char *domain,
    1159             :                                   struct cache_req_data *data)
    1160             : {
    1161          77 :     struct cache_req_state *state = NULL;
    1162          77 :     struct cache_req *cr = NULL;
    1163          77 :     struct tevent_req *req = NULL;
    1164          77 :     struct tevent_req *subreq = NULL;
    1165             :     errno_t ret;
    1166             : 
    1167          77 :     req = tevent_req_create(mem_ctx, &state, struct cache_req_state);
    1168          77 :     if (req == NULL) {
    1169           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
    1170           0 :         return NULL;
    1171             :     }
    1172             : 
    1173          77 :     state->ev = ev;
    1174          77 :     state->rctx = rctx;
    1175          77 :     state->ncache = ncache;
    1176          77 :     state->cache_refresh_percent = cache_refresh_percent;
    1177          77 :     state->cr = cr = cache_req_create(state, rctx, data);
    1178          77 :     if (state->cr == NULL) {
    1179           0 :         ret = ENOMEM;
    1180           0 :         goto immediately;
    1181             :     }
    1182             : 
    1183          77 :     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "New request\n");
    1184             : 
    1185          77 :     if (cr->data->name.input != NULL && domain == NULL) {
    1186             :         /* Parse input name first, since it may contain domain name. */
    1187          14 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Parsing input name [%s]\n",
    1188             :                         cr->data->name.input);
    1189             : 
    1190          14 :         subreq = sss_parse_inp_send(state, rctx, cr->data->name.input);
    1191          14 :         if (subreq == NULL) {
    1192           0 :             ret = ENOMEM;
    1193           0 :             goto immediately;
    1194             :         }
    1195             : 
    1196          14 :         tevent_req_set_callback(subreq, cache_req_input_parsed, req);
    1197             :     } else {
    1198          63 :         if (state->cr->data->name.input != NULL) {
    1199          21 :             ret = cache_req_set_name(cr, cr->data->name.input);
    1200          21 :             if (ret != EOK) {
    1201           0 :                 goto immediately;
    1202             :             }
    1203             :         }
    1204             : 
    1205          63 :         ret = cache_req_select_domains(req, domain);
    1206          63 :         if (ret != EAGAIN) {
    1207           0 :             goto immediately;
    1208             :         }
    1209             :     }
    1210             : 
    1211          77 :     return req;
    1212             : 
    1213             : immediately:
    1214           0 :     if (ret == EOK) {
    1215           0 :         tevent_req_done(req);
    1216             :     } else {
    1217           0 :         tevent_req_error(req, ret);
    1218             :     }
    1219           0 :     tevent_req_post(req, ev);
    1220             : 
    1221           0 :     return req;
    1222             : }
    1223             : 
    1224          14 : static void cache_req_input_parsed(struct tevent_req *subreq)
    1225             : {
    1226             :     struct tevent_req *req;
    1227             :     struct cache_req_state *state;
    1228             :     char *name;
    1229             :     char *domain;
    1230             :     errno_t ret;
    1231             :     bool maybe_upn;
    1232             : 
    1233          14 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1234          14 :     state = tevent_req_data(req, struct cache_req_state);
    1235             : 
    1236          14 :     ret = sss_parse_inp_recv(subreq, state, &name, &domain);
    1237          14 :     switch (ret) {
    1238             :     case EOK:
    1239           6 :         ret = cache_req_set_name(state->cr, name);
    1240           6 :         if (ret != EOK) {
    1241           0 :             tevent_req_error(req, ret);
    1242           0 :             return;
    1243             :         }
    1244           6 :         break;
    1245             :     case ERR_DOMAIN_NOT_FOUND:
    1246           8 :         maybe_upn = cache_req_assume_upn(state->cr);
    1247           8 :         if (!maybe_upn) {
    1248           0 :             tevent_req_error(req, ret);
    1249           0 :             return;
    1250             :         }
    1251             : 
    1252           8 :         domain = NULL;
    1253           8 :         break;
    1254             :     default:
    1255           0 :         tevent_req_error(req, ret);
    1256           0 :         return;
    1257             :     }
    1258             : 
    1259          14 :     ret = cache_req_select_domains(req, domain);
    1260          14 :     if (ret != EAGAIN) {
    1261           0 :         tevent_req_error(req, ret);
    1262           0 :         return;
    1263             :     }
    1264             : }
    1265             : 
    1266          77 : static errno_t cache_req_select_domains(struct tevent_req *req,
    1267             :                                         const char *domain)
    1268             : {
    1269          77 :     struct cache_req_state *state = NULL;
    1270             : 
    1271          77 :     state = tevent_req_data(req, struct cache_req_state);
    1272             : 
    1273          77 :     if (domain != NULL) {
    1274          47 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
    1275             :                         "Performing a single domain search\n");
    1276             : 
    1277          47 :         state->domain = responder_get_domain(state->rctx, domain);
    1278          47 :         if (state->domain == NULL) {
    1279           0 :             return ERR_DOMAIN_NOT_FOUND;
    1280             :         }
    1281             : 
    1282          47 :         state->check_next = false;
    1283             :     } else {
    1284          30 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
    1285             :                         "Performing a multi-domain search\n");
    1286             : 
    1287          30 :         state->domain = state->rctx->domains;
    1288          30 :         state->check_next = true;
    1289             :     }
    1290             : 
    1291          77 :     return cache_req_next_domain(req);
    1292             : }
    1293             : 
    1294         132 : static errno_t cache_req_next_domain(struct tevent_req *req)
    1295             : {
    1296         132 :     struct cache_req_state *state = NULL;
    1297         132 :     struct tevent_req *subreq = NULL;
    1298             :     errno_t ret;
    1299             : 
    1300         132 :     state = tevent_req_data(req, struct cache_req_state);
    1301             : 
    1302         132 :     while (state->domain != NULL) {
    1303             :        /* If it is a domainless search, skip domains that require fully
    1304             :         * qualified names instead. */
    1305         238 :         while (state->domain != NULL && state->check_next
    1306          72 :                 && state->domain->fqnames
    1307           0 :                 && state->cr->data->type != CACHE_REQ_USER_BY_CERT
    1308           0 :                 && !cache_req_is_upn(state->cr)) {
    1309           0 :             state->domain = get_next_domain(state->domain, 0);
    1310             :         }
    1311             : 
    1312         119 :         state->selected_domain = state->domain;
    1313             : 
    1314         119 :         if (state->domain == NULL) {
    1315           0 :             break;
    1316             :         }
    1317             : 
    1318         119 :         ret = cache_req_set_domain(state->cr, state->domain,
    1319             :                                          state->rctx);
    1320         119 :         if (ret != EOK) {
    1321           0 :             return ret;
    1322             :         }
    1323             : 
    1324         119 :         subreq = cache_req_cache_send(state, state->ev, state->rctx,
    1325             :                                       state->ncache,
    1326             :                                       state->cache_refresh_percent,
    1327             :                                       state->cr);
    1328         119 :         if (subreq == NULL) {
    1329           0 :             return ENOMEM;
    1330             :         }
    1331             : 
    1332         119 :         tevent_req_set_callback(subreq, cache_req_done, req);
    1333             : 
    1334             :         /* we will continue with the following domain the next time */
    1335         119 :         if (state->check_next) {
    1336          72 :             if (cache_req_is_upn(state->cr)
    1337          58 :                     || state->cr->data->type == CACHE_REQ_USER_BY_CERT ) {
    1338          24 :                 state->domain = get_next_domain(state->domain, SSS_GND_DESCEND);
    1339             :             } else {
    1340          48 :                 state->domain = get_next_domain(state->domain, 0);
    1341             :             }
    1342             :         }
    1343             : 
    1344         119 :         return EAGAIN;
    1345             :     }
    1346             : 
    1347             :     /* If the object searched has to be unique among all maintained domains,
    1348             :      * we have to add it into negative cache here when all domains have
    1349             :      * been searched. */
    1350             : 
    1351          13 :     cache_req_add_to_ncache_global(state->cr, state->ncache);
    1352             : 
    1353          13 :     return ENOENT;
    1354             : }
    1355             : 
    1356         119 : static void cache_req_done(struct tevent_req *subreq)
    1357             : {
    1358         119 :     struct cache_req_state *state = NULL;
    1359         119 :     struct tevent_req *req = NULL;
    1360             :     errno_t ret;
    1361             : 
    1362         119 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1363         119 :     state = tevent_req_data(req, struct cache_req_state);
    1364             : 
    1365         119 :     ret = cache_req_cache_recv(state, subreq, &state->result);
    1366         119 :     talloc_zfree(subreq);
    1367         119 :     if (ret == EOK) {
    1368          48 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Finished: Success\n");
    1369          48 :         tevent_req_done(req);
    1370          48 :         return;
    1371             :     }
    1372             : 
    1373          71 :     if (state->check_next == false) {
    1374          16 :         if (ret == ENOENT && cache_req_assume_upn(state->cr)) {
    1375             :             /* search by upn now */
    1376           0 :             cache_req_select_domains(req, NULL);
    1377           0 :             return;
    1378             :         }
    1379             : 
    1380          16 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Finished: Not found\n");
    1381          16 :         tevent_req_error(req, ret);
    1382          16 :         return;
    1383             :     }
    1384             : 
    1385          55 :     ret = cache_req_next_domain(req);
    1386          55 :     if (ret != EAGAIN) {
    1387          13 :         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
    1388             :                         "Finished: Error %d: %s\n", ret, sss_strerror(ret));
    1389          13 :         tevent_req_error(req, ret);
    1390             :     }
    1391             : 
    1392          55 :     return;
    1393             : }
    1394             : 
    1395          77 : errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
    1396             :                        struct tevent_req *req,
    1397             :                        struct ldb_result **_result,
    1398             :                        struct sss_domain_info **_domain,
    1399             :                        char **_name)
    1400             : {
    1401          77 :     struct cache_req_state *state = NULL;
    1402             :     char *name;
    1403             : 
    1404          77 :     state = tevent_req_data(req, struct cache_req_state);
    1405             : 
    1406         106 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1407             : 
    1408          48 :     if (_name != NULL) {
    1409          17 :         if (state->cr->data->name.lookup == NULL) {
    1410           0 :             *_name = NULL;
    1411             :         } else {
    1412          17 :             name = talloc_strdup(mem_ctx, state->cr->data->name.name);
    1413          17 :             if (name == NULL) {
    1414           0 :                 return ENOMEM;
    1415             :             }
    1416             : 
    1417          17 :             *_name = name;
    1418             :         }
    1419             :     }
    1420             : 
    1421          48 :     if (_result != NULL) {
    1422          48 :         *_result = talloc_steal(mem_ctx, state->result);
    1423             :     }
    1424             : 
    1425          48 :     if (_domain != NULL) {
    1426          48 :         *_domain = state->selected_domain;
    1427             :     }
    1428             : 
    1429          48 :     return EOK;
    1430             : }
    1431             : 
    1432             : static struct tevent_req *
    1433          77 : cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx,
    1434             :                               struct tevent_context *ev,
    1435             :                               struct resp_ctx *rctx,
    1436             :                               struct sss_nc_ctx *ncache,
    1437             :                               int cache_refresh_percent,
    1438             :                               const char *domain,
    1439             :                               struct cache_req_data *data)
    1440             : {
    1441             :     struct tevent_req *req;
    1442             : 
    1443          77 :     req = cache_req_send(mem_ctx, ev, rctx, ncache,
    1444             :                          cache_refresh_percent, domain, data);
    1445          77 :     if (req == NULL) {
    1446           0 :         talloc_zfree(data);
    1447           0 :         return NULL;
    1448             :     }
    1449             : 
    1450          77 :     talloc_steal(req, data);
    1451             : 
    1452          77 :     return req;
    1453             : }
    1454             : 
    1455             : struct tevent_req *
    1456          17 : cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
    1457             :                             struct tevent_context *ev,
    1458             :                             struct resp_ctx *rctx,
    1459             :                             struct sss_nc_ctx *ncache,
    1460             :                             int cache_refresh_percent,
    1461             :                             const char *domain,
    1462             :                             const char *name)
    1463             : {
    1464             :     struct cache_req_data *data;
    1465             : 
    1466          17 :     data = cache_req_data_name(mem_ctx, CACHE_REQ_USER_BY_NAME, name);
    1467          17 :     if (data == NULL) {
    1468           0 :         return NULL;
    1469             :     }
    1470             : 
    1471          17 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
    1472             :                                          cache_refresh_percent, domain, data);
    1473             : }
    1474             : 
    1475             : struct tevent_req *
    1476           8 : cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
    1477             :                           struct tevent_context *ev,
    1478             :                           struct resp_ctx *rctx,
    1479             :                           struct sss_nc_ctx *ncache,
    1480             :                           int cache_refresh_percent,
    1481             :                           const char *domain,
    1482             :                           uid_t uid)
    1483             : {
    1484             :     struct cache_req_data *data;
    1485             : 
    1486           8 :     data = cache_req_data_id(mem_ctx, CACHE_REQ_USER_BY_ID, uid);
    1487           8 :     if (data == NULL) {
    1488           0 :         return NULL;
    1489             :     }
    1490             : 
    1491           8 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
    1492             :                                          cache_refresh_percent, domain, data);
    1493             : }
    1494             : 
    1495             : struct tevent_req *
    1496          10 : cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
    1497             :                             struct tevent_context *ev,
    1498             :                             struct resp_ctx *rctx,
    1499             :                             struct sss_nc_ctx *ncache,
    1500             :                             int cache_refresh_percent,
    1501             :                             const char *domain,
    1502             :                             const char *pem_cert)
    1503             : {
    1504             :     struct cache_req_data *data;
    1505             : 
    1506          10 :     data = cache_req_data_cert(mem_ctx, CACHE_REQ_USER_BY_CERT, pem_cert);
    1507          10 :     if (data == NULL) {
    1508           0 :         return NULL;
    1509             :     }
    1510             : 
    1511          10 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
    1512             :                                          cache_refresh_percent,
    1513             :                                          domain, data);
    1514             : }
    1515             : 
    1516             : struct tevent_req *
    1517           9 : cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
    1518             :                              struct tevent_context *ev,
    1519             :                              struct resp_ctx *rctx,
    1520             :                              struct sss_nc_ctx *ncache,
    1521             :                              int cache_refresh_percent,
    1522             :                              const char *domain,
    1523             :                              const char *name)
    1524             : {
    1525             :     struct cache_req_data *data;
    1526             : 
    1527           9 :     data = cache_req_data_name(mem_ctx, CACHE_REQ_GROUP_BY_NAME, name);
    1528           9 :     if (data == NULL) {
    1529           0 :         return NULL;
    1530             :     }
    1531             : 
    1532           9 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
    1533             :                                          cache_refresh_percent, domain, data);
    1534             : }
    1535             : 
    1536             : struct tevent_req *
    1537           8 : cache_req_group_by_id_send(TALLOC_CTX *mem_ctx,
    1538             :                            struct tevent_context *ev,
    1539             :                            struct resp_ctx *rctx,
    1540             :                            struct sss_nc_ctx *ncache,
    1541             :                            int cache_refresh_percent,
    1542             :                            const char *domain,
    1543             :                            gid_t gid)
    1544             : {
    1545             :     struct cache_req_data *data;
    1546             : 
    1547           8 :     data = cache_req_data_id(mem_ctx, CACHE_REQ_GROUP_BY_ID, gid);
    1548           8 :     if (data == NULL) {
    1549           0 :         return NULL;
    1550             :     }
    1551             : 
    1552           8 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
    1553             :                                          cache_refresh_percent, domain, data);
    1554             : }
    1555             : 
    1556             : struct tevent_req *
    1557           0 : cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
    1558             :                               struct tevent_context *ev,
    1559             :                               struct resp_ctx *rctx,
    1560             :                               struct sss_nc_ctx *ncache,
    1561             :                               int cache_refresh_percent,
    1562             :                               const char *domain,
    1563             :                               const char *name)
    1564             : {
    1565             :     struct cache_req_data *data;
    1566             : 
    1567           0 :     data = cache_req_data_name(mem_ctx, CACHE_REQ_INITGROUPS, name);
    1568           0 :     if (data == NULL) {
    1569           0 :         return NULL;
    1570             :     }
    1571             : 
    1572           0 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
    1573             :                                          cache_refresh_percent, domain, data);
    1574             : }
    1575             : 
    1576             : struct tevent_req *
    1577           5 : cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
    1578             :                               struct tevent_context *ev,
    1579             :                               struct resp_ctx *rctx,
    1580             :                               const char *domain,
    1581             :                               const char *filter)
    1582             : {
    1583             :     struct cache_req_data *data;
    1584             : 
    1585           5 :     data = cache_req_data_name(mem_ctx, CACHE_REQ_USER_BY_FILTER, filter);
    1586           5 :     if (data == NULL) {
    1587           0 :         return NULL;
    1588             :     }
    1589             : 
    1590           5 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL,
    1591             :                                          0, domain, data);
    1592             : }
    1593             : 
    1594             : struct tevent_req *
    1595           4 : cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
    1596             :                                struct tevent_context *ev,
    1597             :                                struct resp_ctx *rctx,
    1598             :                                const char *domain,
    1599             :                                const char *filter)
    1600             : {
    1601             :     struct cache_req_data *data;
    1602             : 
    1603           4 :     data = cache_req_data_name(mem_ctx, CACHE_REQ_GROUP_BY_FILTER, filter);
    1604           4 :     if (data == NULL) {
    1605           0 :         return NULL;
    1606             :     }
    1607             : 
    1608           4 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL,
    1609             :                                          0, domain, data);
    1610             : }
    1611             : 
    1612             : struct tevent_req *
    1613          16 : cache_req_object_by_sid_send(TALLOC_CTX *mem_ctx,
    1614             :                              struct tevent_context *ev,
    1615             :                              struct resp_ctx *rctx,
    1616             :                              struct sss_nc_ctx *ncache,
    1617             :                              int cache_refresh_percent,
    1618             :                              const char *domain,
    1619             :                              const char *sid,
    1620             :                              const char **attrs)
    1621             : {
    1622             :     struct cache_req_data *data;
    1623             : 
    1624          16 :     data = cache_req_data_sid(mem_ctx, CACHE_REQ_OBJECT_BY_SID, sid, attrs);
    1625          16 :     if (data == NULL) {
    1626           0 :         return NULL;
    1627             :     }
    1628             : 
    1629          16 :     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
    1630             :                                          cache_refresh_percent, domain, data);
    1631             : }

Generated by: LCOV version 1.10