LCOV - code coverage report
Current view: top level - responder/nss - nsssrv_cmd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1148 2635 43.6 %
Date: 2016-06-29 Functions: 52 88 59.1 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    NSS Responder
       5             : 
       6             :    Copyright (C) Simo Sorce <ssorce@redhat.com>   2008
       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 "util/util.h"
      23             : #include "util/sss_nss.h"
      24             : #include "util/sss_cli_cmd.h"
      25             : #include "util/crypto/sss_crypto.h"
      26             : #include "util/cert.h"
      27             : #include "responder/nss/nsssrv.h"
      28             : #include "responder/nss/nsssrv_private.h"
      29             : #include "responder/nss/nsssrv_netgroup.h"
      30             : #include "responder/nss/nsssrv_services.h"
      31             : #include "responder/nss/nsssrv_mmap_cache.h"
      32             : #include "responder/common/negcache.h"
      33             : #include "responder/common/responder_cache_req.h"
      34             : #include "providers/data_provider.h"
      35             : #include "confdb/confdb.h"
      36             : #include "db/sysdb.h"
      37             : #include "sss_client/idmap/sss_nss_idmap.h"
      38             : #include <time.h>
      39             : 
      40           4 : static int nss_cmd_send_error(struct nss_cmd_ctx *cmdctx, int err)
      41             : {
      42           4 :     return sss_cmd_send_error(cmdctx->cctx, err);
      43             : }
      44             : 
      45          12 : static int nss_cmd_send_empty(struct nss_cmd_ctx *cmdctx)
      46             : {
      47          12 :     struct cli_ctx *cctx = cmdctx->cctx;
      48          12 :     return sss_cmd_send_empty(cctx, cmdctx);
      49             : }
      50             : 
      51         103 : int nss_cmd_done(struct nss_cmd_ctx *cmdctx, int ret)
      52             : {
      53         103 :     switch (ret) {
      54             :     case EOK:
      55             :         /* all fine, just return here */
      56          35 :         break;
      57             : 
      58             :     case ENOENT:
      59          12 :         ret = nss_cmd_send_empty(cmdctx);
      60          12 :         if (ret) {
      61           0 :             return EFAULT;
      62             :         }
      63          12 :         break;
      64             : 
      65             :     case EAGAIN:
      66             :         /* async processing, just return here */
      67          52 :         break;
      68             : 
      69             :     case EFAULT:
      70             :         /* very bad error */
      71           0 :         return EFAULT;
      72             : 
      73             :     default:
      74           4 :         ret = nss_cmd_send_error(cmdctx, ret);
      75           4 :         if (ret) {
      76           0 :             return EFAULT;
      77             :         }
      78           4 :         sss_cmd_done(cmdctx->cctx, cmdctx);
      79           4 :         break;
      80             :     }
      81             : 
      82         103 :     return EOK;
      83             : }
      84             : 
      85             : /***************************
      86             :  *  Enumeration procedures *
      87             :  ***************************/
      88           0 : errno_t nss_setent_add_ref(TALLOC_CTX *memctx,
      89             :                            struct getent_ctx *getent_ctx,
      90             :                            struct tevent_req *req)
      91             : {
      92           0 :     return setent_add_ref(memctx, getent_ctx, &getent_ctx->reqs, req);
      93             : }
      94             : 
      95           0 : void nss_setent_notify_error(struct getent_ctx *getent_ctx, errno_t ret)
      96             : {
      97           0 :     return setent_notify(&getent_ctx->reqs, ret);
      98             : }
      99             : 
     100           0 : void nss_setent_notify_done(struct getent_ctx *getent_ctx)
     101             : {
     102           0 :     return setent_notify_done(&getent_ctx->reqs);
     103             : }
     104             : 
     105             : struct setent_ctx {
     106             :     struct cli_ctx *client;
     107             :     struct nss_ctx *nctx;
     108             :     struct nss_dom_ctx *dctx;
     109             :     struct getent_ctx *getent_ctx;
     110             : };
     111             : 
     112          32 : static int nss_reset_negcache(struct resp_ctx *rctx)
     113             : {
     114          32 :     return sss_ncache_reset_repopulate_permanent(rctx, rctx->ncache);
     115             : }
     116             : 
     117             : /****************************************************************************
     118             :  * PASSWD db related functions
     119             :  ***************************************************************************/
     120             : 
     121           0 : void nss_update_pw_memcache(struct nss_ctx *nctx)
     122             : {
     123             :     struct sss_domain_info *dom;
     124             :     struct ldb_result *res;
     125             :     uint64_t exp;
     126             :     struct sized_string key;
     127             :     const char *id;
     128             :     time_t now;
     129             :     int ret;
     130             :     int i;
     131             : 
     132           0 :     now = time(NULL);
     133             : 
     134           0 :     for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, 0)) {
     135           0 :         ret = sysdb_enumpwent_with_views(nctx, dom, &res);
     136           0 :         if (ret != EOK) {
     137           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     138             :                   "Failed to enumerate users for domain [%s]\n", dom->name);
     139           0 :             continue;
     140             :         }
     141             : 
     142           0 :         for (i = 0; i < res->count; i++) {
     143           0 :             exp = ldb_msg_find_attr_as_uint64(res->msgs[i],
     144             :                                               SYSDB_CACHE_EXPIRE, 0);
     145           0 :             if (exp >= now) {
     146           0 :                 continue;
     147             :             }
     148             : 
     149             :             /* names require more manipulation (build up fqname conditionally),
     150             :              * but uidNumber is unique and always resolvable too, so we use
     151             :              * that to update the cache, as it points to the same entry */
     152           0 :             id = sss_view_ldb_msg_find_attr_as_string(dom, res->msgs[i],
     153             :                                                       SYSDB_UIDNUM, NULL);
     154           0 :             if (!id) {
     155           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     156             :                       "Failed to find uidNumber in %s.\n",
     157             :                        ldb_dn_get_linearized(res->msgs[i]->dn));
     158           0 :                 continue;
     159             :             }
     160           0 :             to_sized_string(&key, id);
     161             : 
     162           0 :             ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &key);
     163           0 :             if (ret != EOK && ret != ENOENT) {
     164           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     165             :                       "Internal failure in memory cache code: %d [%s]\n",
     166             :                        ret, strerror(ret));
     167             :             }
     168             : 
     169           0 :             ret = sss_mmap_cache_pw_invalidate(nctx->initgr_mc_ctx, &key);
     170           0 :             if (ret != EOK && ret != ENOENT) {
     171           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     172             :                       "Internal failure in memory cache code: %d [%s]\n",
     173             :                       ret, strerror(ret));
     174             :             }
     175             :         }
     176             : 
     177           0 :         talloc_zfree(res);
     178             :     }
     179           0 : }
     180             : 
     181          12 : static gid_t get_gid_override(struct ldb_message *msg,
     182             :                               struct sss_domain_info *dom)
     183             : {
     184          24 :     return dom->override_gid ?
     185             :         dom->override_gid :
     186          12 :         ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
     187             : }
     188             : 
     189          12 : static const char *get_homedir_override(TALLOC_CTX *mem_ctx,
     190             :                                         struct ldb_message *msg,
     191             :                                         struct nss_ctx *nctx,
     192             :                                         struct sss_domain_info *dom,
     193             :                                         struct sss_nss_homedir_ctx *homedir_ctx)
     194             : {
     195             :     const char *homedir;
     196          12 :     const char *orig_name = homedir_ctx->username;
     197             :     errno_t ret;
     198             : 
     199          12 :     homedir = sss_view_ldb_msg_find_attr_as_string(dom, msg, SYSDB_HOMEDIR,
     200             :                                                    NULL);
     201          12 :     homedir_ctx->original = homedir;
     202             : 
     203             :     /* Subdomain users store FQDN in their name attribute */
     204          12 :     ret = sss_parse_name_const(mem_ctx, dom->names, orig_name,
     205             :                                NULL, &homedir_ctx->username);
     206          12 :     if (ret != EOK) {
     207           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Could not parse [%s] into "
     208             :               "name-value components.\n", orig_name);
     209           0 :         return NULL;
     210             :     }
     211             : 
     212             :     /* Check to see which homedir_prefix to use. */
     213          12 :     if (dom->homedir_substr != NULL) {
     214           0 :         homedir_ctx->config_homedir_substr = dom->homedir_substr;
     215          12 :     } else if (nctx->homedir_substr != NULL) {
     216           0 :         homedir_ctx->config_homedir_substr = nctx->homedir_substr;
     217             :     }
     218             : 
     219             :     /* Check whether we are unconditionally overriding the server
     220             :      * for home directory locations.
     221             :      */
     222          12 :     if (dom->override_homedir) {
     223           0 :         return expand_homedir_template(mem_ctx, dom->override_homedir,
     224             :                                        homedir_ctx);
     225          12 :     } else if (nctx->override_homedir) {
     226           0 :         return expand_homedir_template(mem_ctx, nctx->override_homedir,
     227             :                                        homedir_ctx);
     228             :     }
     229             : 
     230          12 :     if (!homedir || *homedir == '\0') {
     231             :         /* In the case of a NULL or empty homedir, check to see if
     232             :          * we have a fallback homedir to use.
     233             :          */
     234           0 :         if (dom->fallback_homedir) {
     235           0 :             return expand_homedir_template(mem_ctx, dom->fallback_homedir,
     236             :                                            homedir_ctx);
     237           0 :         } else if (nctx->fallback_homedir) {
     238           0 :             return expand_homedir_template(mem_ctx, nctx->fallback_homedir,
     239             :                                            homedir_ctx);
     240             :         }
     241             :     }
     242             : 
     243             :     /* Provider can also return template, try to expand it.*/
     244          12 :     return expand_homedir_template(mem_ctx, homedir, homedir_ctx);
     245             : }
     246             : 
     247          12 : static const char *get_shell_override(TALLOC_CTX *mem_ctx,
     248             :                                       struct ldb_message *msg,
     249             :                                       struct nss_ctx *nctx,
     250             :                                       struct sss_domain_info *dom)
     251             : {
     252             :     const char *user_shell;
     253             :     int i;
     254             : 
     255             :     /* Check whether we are unconditionally overriding the server
     256             :      * for the login shell.
     257             :      */
     258          12 :     if (dom->override_shell) {
     259           0 :         return dom->override_shell;
     260          12 :     } else if (nctx->override_shell) {
     261           0 :         return nctx->override_shell;
     262             :     }
     263             : 
     264          12 :     user_shell = sss_view_ldb_msg_find_attr_as_string(dom, msg, SYSDB_SHELL,
     265             :                                                       NULL);
     266          12 :     if (!user_shell) {
     267             :         /* Check whether there is a default shell specified */
     268           0 :         if (dom->default_shell) {
     269           0 :             return talloc_strdup(mem_ctx, dom->default_shell);
     270           0 :         } else if (nctx->default_shell) {
     271           0 :             return talloc_strdup(mem_ctx, nctx->default_shell);
     272             :         }
     273           0 :         return NULL;
     274             :     }
     275          12 :     if (!nctx->allowed_shells && !nctx->vetoed_shells) return talloc_strdup(mem_ctx, user_shell);
     276             : 
     277           0 :     if (nctx->vetoed_shells) {
     278           0 :         for (i=0; nctx->vetoed_shells[i]; i++) {
     279           0 :             if (strcmp(nctx->vetoed_shells[i], user_shell) == 0) {
     280           0 :                 DEBUG(SSSDBG_FUNC_DATA, "The shell '%s' is vetoed. "
     281             :                          "Using fallback\n", user_shell);
     282           0 :                 return talloc_strdup(mem_ctx, nctx->shell_fallback);
     283             :             }
     284             :         }
     285             :     }
     286             : 
     287           0 :     if (nctx->etc_shells) {
     288           0 :         for (i=0; nctx->etc_shells[i]; i++) {
     289           0 :             if (strcmp(user_shell, nctx->etc_shells[i]) == 0) {
     290           0 :                 DEBUG(SSSDBG_TRACE_ALL, "Shell %s found in /etc/shells\n",
     291             :                         nctx->etc_shells[i]);
     292           0 :                 break;
     293             :             }
     294             :         }
     295             : 
     296           0 :         if (nctx->etc_shells[i]) {
     297           0 :             DEBUG(SSSDBG_TRACE_ALL, "Using original shell '%s'\n", user_shell);
     298           0 :             return talloc_strdup(mem_ctx, user_shell);
     299             :         }
     300             :     }
     301             : 
     302           0 :     if (nctx->allowed_shells) {
     303           0 :         if (strcmp(nctx->allowed_shells[0], "*") == 0) {
     304           0 :             DEBUG(SSSDBG_FUNC_DATA,
     305             :                   "The shell '%s' is allowed but does not exist. "
     306             :                   "Using fallback\n", user_shell);
     307           0 :             return talloc_strdup(mem_ctx, nctx->shell_fallback);
     308             :         } else {
     309           0 :             for (i=0; nctx->allowed_shells[i]; i++) {
     310           0 :                 if (strcmp(nctx->allowed_shells[i], user_shell) == 0) {
     311           0 :                     DEBUG(SSSDBG_FUNC_DATA,
     312             :                           "The shell '%s' is allowed but does not exist. "
     313             :                           "Using fallback\n", user_shell);
     314           0 :                     return talloc_strdup(mem_ctx, nctx->shell_fallback);
     315             :                 }
     316             :             }
     317             :         }
     318             :     }
     319             : 
     320           0 :     DEBUG(SSSDBG_FUNC_DATA,
     321             :           "The shell '%s' is not allowed and does not exist.\n",
     322             :               user_shell);
     323           0 :     return talloc_strdup(mem_ctx, NOLOGIN_SHELL);
     324             : }
     325             : 
     326          12 : static int fill_pwent(struct sss_packet *packet,
     327             :                       struct sss_domain_info *dom,
     328             :                       struct nss_ctx *nctx,
     329             :                       bool filter_users, bool pw_mmap_cache,
     330             :                       struct ldb_message **msgs,
     331             :                       int *count)
     332             : {
     333             :     struct ldb_message *msg;
     334             :     uint8_t *body;
     335             :     const char *upn;
     336             :     const char *tmpstr;
     337             :     const char *orig_name;
     338             :     struct sized_string name;
     339             :     struct sized_string gecos;
     340             :     struct sized_string homedir;
     341             :     struct sized_string shell;
     342             :     struct sized_string pwfield;
     343             :     struct sized_string fullname;
     344             :     uint32_t uid;
     345             :     uint32_t gid;
     346             :     size_t rsize, rp, blen;
     347          12 :     int fq_len = 0;
     348             :     int i, ret, num;
     349          12 :     bool add_domain = (!IS_SUBDOMAIN(dom) && dom->fqnames);
     350          12 :     const char *domain = dom->name;
     351          12 :     bool packet_initialized = false;
     352             :     int ncret;
     353          12 :     TALLOC_CTX *tmp_ctx = NULL;
     354             :     struct sss_nss_homedir_ctx homedir_ctx;
     355             : 
     356          12 :     to_sized_string(&pwfield, nctx->pwfield);
     357             : 
     358          12 :     rp = 2*sizeof(uint32_t);
     359             : 
     360          12 :     num = 0;
     361          24 :     for (i = 0; i < *count; i++) {
     362          12 :         talloc_zfree(tmp_ctx);
     363          12 :         tmp_ctx = talloc_new(NULL);
     364             : 
     365          12 :         msg = msgs[i];
     366             : 
     367          12 :         upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL);
     368             : 
     369          12 :         if (DOM_HAS_VIEWS(dom)) {
     370           0 :             orig_name = ldb_msg_find_attr_as_string(msg,
     371             :                                                     OVERRIDE_PREFIX SYSDB_NAME,
     372             :                                                     NULL);
     373           0 :             if (orig_name != NULL && IS_SUBDOMAIN(dom)) {
     374             :                 /* Override names are not fully qualified */
     375           0 :                 add_domain = true;
     376             :             }
     377             : 
     378           0 :             gid = ldb_msg_find_attr_as_uint64(msg,
     379             :                                               OVERRIDE_PREFIX SYSDB_GIDNUM, 0);
     380             :         } else {
     381          12 :             orig_name = NULL;
     382          12 :             gid = 0;
     383             :         }
     384             : 
     385          12 :         if (orig_name == NULL) {
     386          12 :             orig_name = ldb_msg_find_attr_as_string(msg,
     387             :                                                     SYSDB_DEFAULT_OVERRIDE_NAME,
     388             :                                                     NULL);
     389          12 :             if (orig_name == NULL) {
     390          12 :                 orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
     391             :             }
     392             :         }
     393             : 
     394          12 :         uid = sss_view_ldb_msg_find_attr_as_uint64(dom, msg, SYSDB_UIDNUM, 0);
     395             : 
     396          12 :         if (gid == 0) {
     397          12 :             gid = get_gid_override(msg, dom);
     398             :         }
     399             : 
     400          12 :         if (!orig_name || !uid || !gid) {
     401           0 :             DEBUG(SSSDBG_OP_FAILURE, "Incomplete user object for %s[%llu]! Skipping\n",
     402             :                       orig_name?orig_name:"<NULL>", (unsigned long long int)uid);
     403           0 :             continue;
     404             :         }
     405             : 
     406          12 :         if (filter_users) {
     407           3 :             ncret = sss_ncache_check_user(nctx->rctx->ncache, dom, orig_name);
     408           3 :             if (ncret == EEXIST) {
     409           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
     410             :                       "User [%s@%s] filtered out! (negative cache)\n",
     411             :                        orig_name, domain);
     412           0 :                 continue;
     413             :             }
     414             :         }
     415             : 
     416          12 :         if (!packet_initialized) {
     417             :             /* first 2 fields (len and reserved), filled up later */
     418          12 :             ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
     419          12 :             if (ret != EOK) return ret;
     420          12 :             packet_initialized = true;
     421             :         }
     422             : 
     423          12 :         tmpstr = sss_get_cased_name(tmp_ctx, orig_name, dom->case_preserve);
     424          12 :         if (tmpstr == NULL) {
     425           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     426             :                   "sss_get_cased_name failed, skipping\n");
     427           0 :             continue;
     428             :         }
     429             : 
     430          12 :         tmpstr = sss_replace_space(tmp_ctx, tmpstr,
     431          12 :                                    nctx->rctx->override_space);
     432          12 :         if (tmpstr == NULL) {
     433           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     434             :                   "sss_replace_space failed, skipping\n");
     435           0 :             continue;
     436             :         }
     437             : 
     438          12 :         to_sized_string(&name, tmpstr);
     439             : 
     440          12 :         tmpstr = sss_view_ldb_msg_find_attr_as_string(dom, msg, SYSDB_GECOS,
     441             :                                                       NULL);
     442          12 :         if (!tmpstr) {
     443           0 :             to_sized_string(&gecos, "");
     444             :         } else {
     445          12 :             to_sized_string(&gecos, tmpstr);
     446             :         }
     447             : 
     448          12 :         ZERO_STRUCT(homedir_ctx);
     449             : 
     450          12 :         homedir_ctx.username = name.str;
     451          12 :         homedir_ctx.uid = uid;
     452          12 :         homedir_ctx.domain = dom->name;
     453          12 :         homedir_ctx.upn = upn;
     454             : 
     455          12 :         tmpstr = get_homedir_override(tmp_ctx, msg, nctx, dom, &homedir_ctx);
     456          12 :         if (!tmpstr) {
     457           0 :             to_sized_string(&homedir, "/");
     458             :         } else {
     459          12 :             to_sized_string(&homedir, tmpstr);
     460             :         }
     461             : 
     462          12 :         tmpstr = get_shell_override(tmp_ctx, msg, nctx, dom);
     463          12 :         if (!tmpstr) {
     464           0 :             to_sized_string(&shell, "");
     465             :         } else {
     466          12 :             to_sized_string(&shell, tmpstr);
     467             :         }
     468             : 
     469          36 :         rsize = 2 * sizeof(uint32_t) + name.len + gecos.len +
     470          24 :                                        homedir.len + shell.len + pwfield.len;
     471             : 
     472          12 :         if (add_domain) {
     473           2 :             fq_len = sss_fqname(NULL, 0, dom->names, dom, name.str);
     474           2 :             if (fq_len >= 0) {
     475           2 :                 fq_len += 1;
     476           2 :                 rsize -= name.len;
     477           2 :                 rsize += fq_len;
     478             :             } else {
     479           0 :                 fq_len = 0;
     480             :             }
     481             :         }
     482             : 
     483          12 :         ret = sss_packet_grow(packet, rsize);
     484          12 :         if (ret != EOK) {
     485           0 :             num = 0;
     486           0 :             goto done;
     487             :         }
     488          12 :         sss_packet_get_body(packet, &body, &blen);
     489             : 
     490          12 :         SAFEALIGN_SET_UINT32(&body[rp], uid, &rp);
     491          12 :         SAFEALIGN_SET_UINT32(&body[rp], gid, &rp);
     492             : 
     493          12 :         if (add_domain) {
     494           2 :             ret = sss_fqname((char *) &body[rp], fq_len, dom->names, dom, name.str);
     495           2 :             if (ret < 0 || ret != fq_len - 1) {
     496           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     497             :                       "Failed to generate a fully qualified name for user "
     498             :                           "[%s] in [%s]! Skipping user.\n", name.str, domain);
     499           0 :                 continue;
     500             :             }
     501             :         } else {
     502          10 :             memcpy(&body[rp], name.str, name.len);
     503             :         }
     504          12 :         to_sized_string(&fullname, (const char *)&body[rp]);
     505          12 :         rp += fullname.len;
     506             : 
     507          12 :         memcpy(&body[rp], pwfield.str, pwfield.len);
     508          12 :         rp += pwfield.len;
     509          12 :         memcpy(&body[rp], gecos.str, gecos.len);
     510          12 :         rp += gecos.len;
     511          12 :         memcpy(&body[rp], homedir.str, homedir.len);
     512          12 :         rp += homedir.len;
     513          12 :         memcpy(&body[rp], shell.str, shell.len);
     514          12 :         rp += shell.len;
     515             : 
     516          12 :         num++;
     517             : 
     518          12 :         if (pw_mmap_cache && nctx->pwd_mc_ctx) {
     519           0 :             ret = sss_mmap_cache_pw_store(&nctx->pwd_mc_ctx,
     520             :                                           &fullname, &pwfield,
     521             :                                           uid, gid,
     522             :                                           &gecos, &homedir, &shell);
     523           0 :             if (ret != EOK && ret != ENOMEM) {
     524           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     525             :                       "Failed to store user %s(%s) in mmap cache!\n",
     526             :                         name.str, domain);
     527             :             }
     528             :         }
     529             :     }
     530          12 :     talloc_zfree(tmp_ctx);
     531             : 
     532             : done:
     533          12 :     *count = i;
     534             : 
     535             :     /* if there are no results just return ENOENT,
     536             :      * let the caller decide if this is the last packet or not */
     537          12 :     if (!packet_initialized) return ENOENT;
     538             : 
     539          12 :     sss_packet_get_body(packet, &body, &blen);
     540          12 :     SAFEALIGN_COPY_UINT32(body, &num, NULL); /* num results */
     541          12 :     SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL); /* reserved */
     542             : 
     543          12 :     return EOK;
     544             : }
     545             : 
     546          12 : static int nss_cmd_getpw_send_reply(struct nss_dom_ctx *dctx, bool filter)
     547             : {
     548          12 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     549          12 :     struct cli_ctx *cctx = cmdctx->cctx;
     550             :     struct nss_ctx *nctx;
     551             :     int ret;
     552             :     int i;
     553             : 
     554          12 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
     555             : 
     556          24 :     ret = sss_packet_new(cctx->creq, 0,
     557          12 :                          sss_packet_get_cmd(cctx->creq->in),
     558          12 :                          &cctx->creq->out);
     559          12 :     if (ret != EOK) {
     560           0 :         return EFAULT;
     561             :     }
     562          12 :     i = dctx->res->count;
     563             : 
     564          12 :     ret = fill_pwent(cctx->creq->out,
     565             :                      dctx->domain,
     566             :                      nctx, filter, true,
     567          12 :                      dctx->res->msgs, &i);
     568          12 :     if (ret) {
     569           0 :         return ret;
     570             :     }
     571          12 :     sss_packet_set_error(cctx->creq->out, EOK);
     572          12 :     sss_cmd_done(cctx, cmdctx);
     573          12 :     return EOK;
     574             : }
     575             : 
     576             : static bool
     577          28 : is_refreshed_on_bg(enum sss_dp_acct_type req_type,
     578             :                    uint32_t refresh_expired_interval)
     579             : {
     580          28 :     if (refresh_expired_interval == 0) {
     581          28 :         return false;
     582             :     }
     583             : 
     584           0 :     switch (req_type) {
     585             :     case SSS_DP_NETGR:
     586             :     case SSS_DP_USER:
     587             :     case SSS_DP_GROUP:
     588           0 :         return true;
     589             :     default:
     590           0 :         return false;
     591             :     }
     592             : 
     593             :     return false;
     594             : }
     595             : 
     596             : static void nsssrv_dp_send_acct_req_done(struct tevent_req *req);
     597             : 
     598          37 : static void get_dp_name_and_id(TALLOC_CTX *mem_ctx,
     599             :                               struct sss_domain_info *dom,
     600             :                               enum sss_dp_acct_type req_type,
     601             :                               const char *opt_name,
     602             :                               uint32_t opt_id,
     603             :                               const char **_name,
     604             :                               uint32_t *_id)
     605             : {
     606             :     TALLOC_CTX *tmp_ctx;
     607          37 :     struct ldb_result *res = NULL;
     608             :     const char *attr;
     609             :     const char *name;
     610             :     uint32_t id;
     611             :     errno_t ret;
     612             : 
     613             :     /* First set the same values to make things easier. */
     614          37 :     *_name = opt_name;
     615          37 :     *_id = opt_id;
     616             : 
     617          37 :     if (!DOM_HAS_VIEWS(dom) || !is_local_view(dom->view_name)) {
     618          37 :         DEBUG(SSSDBG_TRACE_FUNC, "Not a LOCAL view, continuing with "
     619             :               "provided values.\n");
     620          74 :         return;
     621             :     }
     622             : 
     623           0 :     tmp_ctx = talloc_new(NULL);
     624           0 :     if (tmp_ctx == NULL) {
     625           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
     626           0 :         return;
     627             :     }
     628             : 
     629           0 :     if (opt_name != NULL) {
     630           0 :         switch (req_type) {
     631             :         case SSS_DP_USER:
     632             :         case SSS_DP_INITGROUPS:
     633           0 :             ret = sysdb_getpwnam_with_views(tmp_ctx, dom, opt_name, &res);
     634           0 :             if (ret != EOK) {
     635           0 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     636             :                       "sysdb_getpwnam_with_views() failed [%d]: %s\n",
     637             :                       ret, sss_strerror(ret));
     638           0 :                 goto done;
     639             :             }
     640           0 :             break;
     641             :         case SSS_DP_GROUP:
     642           0 :             ret = sysdb_getgrnam_with_views(tmp_ctx, dom, opt_name, &res);
     643           0 :             if (ret != EOK) {
     644           0 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     645             :                       "sysdb_getgrnam_with_views() failed [%d]: %s\n",
     646             :                       ret, sss_strerror(ret));
     647           0 :                 goto done;
     648             :             }
     649           0 :             break;
     650             :         default:
     651           0 :             goto done;
     652             :         }
     653             : 
     654           0 :         if (res == NULL || res->count != 1) {
     655             :             /* This should not happen with LOCAL view and overridden value. */
     656           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Entry is missing?! Continuing with "
     657             :                   "provided values.\n");
     658           0 :             goto done;
     659             :         }
     660             : 
     661           0 :         name = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
     662           0 :         if (name == NULL) {
     663           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL\n");
     664           0 :             goto done;
     665             :         }
     666             : 
     667           0 :         *_name = talloc_steal(mem_ctx, name);
     668           0 :     } else if (opt_id != 0) {
     669           0 :         switch (req_type) {
     670             :         case SSS_DP_USER:
     671           0 :             ret = sysdb_getpwuid_with_views(tmp_ctx, dom, opt_id, &res);
     672           0 :             if (ret != EOK) {
     673           0 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     674             :                       "sysdb_getpwuid_with_views() failed [%d]: %s\n",
     675             :                       ret, sss_strerror(ret));
     676           0 :                 goto done;
     677             :             }
     678             : 
     679           0 :             attr = SYSDB_UIDNUM;
     680           0 :             break;
     681             :         case SSS_DP_GROUP:
     682           0 :             ret = sysdb_getgrgid_with_views(tmp_ctx, dom, opt_id, &res);
     683           0 :             if (ret != EOK) {
     684           0 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     685             :                       "sysdb_getgrgid_with_views() failed [%d]: %s\n",
     686             :                       ret, sss_strerror(ret));
     687           0 :                 goto done;
     688             :             }
     689             : 
     690           0 :             attr = SYSDB_GIDNUM;
     691           0 :             break;
     692             :         default:
     693           0 :             goto done;
     694             :         }
     695             : 
     696           0 :         if (res == NULL || res->count != 1) {
     697             :             /* This should not happen with LOCAL view and overridden value. */
     698           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Entry is missing?! Continuing with "
     699             :                   "provided values.\n");
     700           0 :             goto done;
     701             :         }
     702             : 
     703           0 :         id = ldb_msg_find_attr_as_uint64(res->msgs[0], attr, 0);
     704           0 :         if (id == 0) {
     705           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0\n");
     706           0 :             goto done;
     707             :         }
     708             : 
     709           0 :         *_id = id;
     710             :     }
     711             : 
     712             : done:
     713           0 :     talloc_free(tmp_ctx);
     714             : }
     715             : 
     716             : /* FIXME: do not check res->count, but get in a msgs and check in parent */
     717          37 : errno_t check_cache(struct nss_dom_ctx *dctx,
     718             :                     struct nss_ctx *nctx,
     719             :                     struct ldb_result *res,
     720             :                     enum sss_dp_acct_type req_type,
     721             :                     const char *opt_name,
     722             :                     uint32_t opt_id,
     723             :                     const char *extra,
     724             :                     sss_dp_callback_t callback,
     725             :                     void *pvt)
     726             : {
     727             :     errno_t ret;
     728          37 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     729          37 :     struct cli_ctx *cctx = cmdctx->cctx;
     730          37 :     struct tevent_req *req = NULL;
     731          37 :     struct dp_callback_ctx *cb_ctx = NULL;
     732          37 :     uint64_t cacheExpire = 0;
     733          37 :     const char *name = opt_name;
     734          37 :     uint32_t id = opt_id;
     735             : 
     736             :     /* when searching for a user or netgroup, more than one reply is a
     737             :      * db error
     738             :      */
     739          55 :     if ((req_type == SSS_DP_USER || req_type == SSS_DP_NETGR) &&
     740          18 :             (res->count > 1)) {
     741           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     742             :               "getpwXXX call returned more than one result! DB Corrupted?\n");
     743           0 :         return ENOENT;
     744             :     }
     745             : 
     746             :     /* In case of local view we have to always contant DP with the original
     747             :      * name or id. */
     748          37 :     get_dp_name_and_id(dctx->cmdctx, dctx->domain, req_type, opt_name, opt_id,
     749             :                        &name, &id);
     750             : 
     751             :     /* if we have any reply let's check cache validity */
     752          37 :     if (res->count > 0) {
     753             :         bool refreshed_on_bg;
     754          28 :         uint32_t bg_refresh_interval = dctx->domain->refresh_expired_interval;
     755             : 
     756          28 :         if (req_type == SSS_DP_INITGROUPS) {
     757           4 :             cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0],
     758             :                                                       SYSDB_INITGR_EXPIRE,
     759             :                                                       0);
     760             :         } else {
     761          24 :             cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0],
     762             :                                                       SYSDB_CACHE_EXPIRE,
     763             :                                                       0);
     764             :         }
     765             : 
     766             :         /* Check if background refresh is enabled for this entry */
     767          28 :         refreshed_on_bg = is_refreshed_on_bg(req_type, bg_refresh_interval);
     768             : 
     769             :         /* if we have any reply let's check cache validity */
     770          28 :         ret = sss_cmd_check_cache(res->msgs[0],
     771             :                                   nctx->cache_refresh_percent,
     772             :                                   cacheExpire);
     773          28 :         if (ret == EOK || (ret == EAGAIN && refreshed_on_bg))  {
     774          23 :             DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning..\n");
     775          23 :             return EOK;
     776           5 :         } else if (ret != EAGAIN && ret != ENOENT) {
     777           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache: %d\n", ret);
     778           0 :             goto error;
     779             :         }
     780             :     } else {
     781             :         /* No replies */
     782           9 :         ret = ENOENT;
     783             :     }
     784             : 
     785             :     /* EAGAIN (off band) or ENOENT (cache miss) -> check cache */
     786          14 :     if (ret == EAGAIN) {
     787             :         /* No callback required
     788             :          * This was an out-of-band update. We'll return EOK
     789             :          * so the calling function can return the cached entry
     790             :          * immediately.
     791             :          */
     792           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     793             :              "Performing midpoint cache update on [%s]\n", name);
     794             : 
     795           0 :         req = sss_dp_get_account_send(cctx, cctx->rctx, dctx->domain, true,
     796             :                                       req_type, name, id, extra);
     797           0 :         if (!req) {
     798           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     799             :                   "Out of memory sending out-of-band data provider "
     800             :                    "request\n");
     801             :             /* This is non-fatal, so we'll continue here */
     802             :         } else {
     803           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Updating cache out-of-band\n");
     804             :         }
     805             : 
     806             :         /* We don't need to listen for a reply, so we will free the
     807             :          * request here.
     808             :          */
     809           0 :         talloc_zfree(req);
     810             : 
     811             :     } else {
     812             :        /* This is a cache miss. Or the cache is expired.
     813             :         * We need to get the updated user information before returning it.
     814             :         */
     815             : 
     816             :         /* dont loop forever :-) */
     817          14 :         dctx->check_provider = false;
     818             : 
     819             :         /* keep around current data in case backend is offline */
     820          14 :         if (res->count) {
     821           5 :             dctx->res = talloc_steal(dctx, res);
     822             :         }
     823             : 
     824          14 :         req = sss_dp_get_account_send(cctx, cctx->rctx, dctx->domain, true,
     825             :                                       req_type, name, id, extra);
     826          14 :         if (!req) {
     827           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     828             :                   "Out of memory sending data provider request\n");
     829           0 :             ret = ENOMEM;
     830           0 :             goto error;
     831             :         }
     832             : 
     833          14 :         cb_ctx = talloc_zero(dctx, struct dp_callback_ctx);
     834          14 :         if(!cb_ctx) {
     835           0 :             talloc_zfree(req);
     836           0 :             ret = ENOMEM;
     837           0 :             goto error;
     838             :         }
     839          14 :         cb_ctx->callback = callback;
     840          14 :         cb_ctx->ptr = pvt;
     841          14 :         cb_ctx->cctx = dctx->cmdctx->cctx;
     842          14 :         cb_ctx->mem_ctx = dctx;
     843             : 
     844          14 :         tevent_req_set_callback(req, nsssrv_dp_send_acct_req_done, cb_ctx);
     845             : 
     846          14 :         return EAGAIN;
     847             :     }
     848             : 
     849           0 :     return EOK;
     850             : 
     851             : error:
     852           0 :     ret = nss_cmd_send_error(cmdctx, ret);
     853           0 :     if (ret != EOK) {
     854           0 :         NSS_CMD_FATAL_ERROR_CODE(cctx, ret);
     855             :     }
     856           0 :     sss_cmd_done(cctx, cmdctx);
     857           0 :     return EOK;
     858             : }
     859             : 
     860          14 : static void nsssrv_dp_send_acct_req_done(struct tevent_req *req)
     861             : {
     862          14 :     struct dp_callback_ctx *cb_ctx =
     863          14 :             tevent_req_callback_data(req, struct dp_callback_ctx);
     864             : 
     865             :     errno_t ret;
     866             :     dbus_uint16_t err_maj;
     867             :     dbus_uint32_t err_min;
     868             :     char *err_msg;
     869             : 
     870          14 :     ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
     871             :                                   &err_maj, &err_min,
     872             :                                   &err_msg);
     873          14 :     talloc_zfree(req);
     874          14 :     if (ret != EOK) {
     875          14 :         NSS_CMD_FATAL_ERROR(cb_ctx->cctx);
     876             :     }
     877             : 
     878          14 :     cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
     879             : }
     880             : 
     881           4 : static int delete_entry_from_memcache(struct sss_domain_info *dom, char *name,
     882             :                                       struct sss_mc_ctx *mc_ctx,
     883             :                                       enum sss_mc_type type)
     884             : {
     885           4 :     TALLOC_CTX *tmp_ctx = NULL;
     886             :     struct sized_string delete_name;
     887           4 :     char *fqdn = NULL;
     888             :     int ret;
     889             : 
     890           4 :     tmp_ctx = talloc_new(NULL);
     891           4 :     if (tmp_ctx == NULL) {
     892           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
     893           0 :         return ENOMEM;
     894             :     }
     895             : 
     896           4 :     if (dom->fqnames) {
     897           0 :         fqdn = sss_tc_fqname(tmp_ctx, dom->names, dom, name);
     898           0 :         if (fqdn == NULL) {
     899           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
     900           0 :             ret = ENOMEM;
     901           0 :             goto done;
     902             :         }
     903           0 :         to_sized_string(&delete_name, fqdn);
     904             :     } else {
     905           4 :         to_sized_string(&delete_name, name);
     906             :     }
     907             : 
     908           4 :     switch (type) {
     909             :     case SSS_MC_PASSWD:
     910           2 :         ret = sss_mmap_cache_pw_invalidate(mc_ctx, &delete_name);
     911           2 :         if (ret != EOK && ret != ENOENT) {
     912           2 :             DEBUG(SSSDBG_CRIT_FAILURE,
     913             :                   "Internal failure in memory cache code: %d [%s]\n",
     914             :                   ret, strerror(ret));
     915           2 :             goto done;
     916             :         }
     917           0 :         break;
     918             :     case SSS_MC_GROUP:
     919           0 :         ret = sss_mmap_cache_gr_invalidate(mc_ctx, &delete_name);
     920           0 :         if (ret != EOK && ret != ENOENT) {
     921           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     922             :                   "Internal failure in memory cache code: %d [%s]\n",
     923             :                   ret, strerror(ret));
     924           0 :             goto done;
     925             :         }
     926           0 :         break;
     927             :     case SSS_MC_INITGROUPS:
     928           2 :         ret = sss_mmap_cache_initgr_invalidate(mc_ctx, &delete_name);
     929           2 :         if (ret != EOK && ret != ENOENT) {
     930           2 :             DEBUG(SSSDBG_CRIT_FAILURE,
     931             :                   "Internal failure in memory cache code: %d [%s]\n",
     932             :                   ret, strerror(ret));
     933           2 :             goto done;
     934             :         }
     935           0 :         break;
     936             :     default:
     937           0 :         ret = EINVAL;
     938           0 :         goto done;
     939             :     }
     940             : 
     941           0 :     ret = EOK;
     942             : done:
     943           4 :     talloc_free(tmp_ctx);
     944           4 :     return ret;
     945             : 
     946             : }
     947             : 
     948             : static void nss_cmd_getby_dp_callback(uint16_t err_maj, uint32_t err_min,
     949             :                                       const char *err_msg, void *ptr);
     950             : 
     951             : /* search for a user.
     952             :  * Returns:
     953             :  *   ENOENT, if user is definitely not found
     954             :  *   EAGAIN, if user is being fetched from backend via async operations
     955             :  *   EOK, if found
     956             :  *   anything else on a fatal error
     957             :  */
     958             : 
     959          18 : static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
     960             : {
     961          18 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     962          18 :     struct sss_domain_info *dom = dctx->domain;
     963          18 :     struct cli_ctx *cctx = cmdctx->cctx;
     964          18 :     char *name = NULL;
     965             :     struct nss_ctx *nctx;
     966             :     int ret;
     967             :     static const char *user_attrs[] = SYSDB_PW_ATTRS;
     968             :     struct ldb_message *msg;
     969          18 :     const char *extra_flag = NULL;
     970             : 
     971          18 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
     972             : 
     973          18 :     while (dom) {
     974             :        /* if it is a domainless search, skip domains that require fully
     975             :          * qualified names instead */
     976          36 :         while (dom && cmdctx->check_next && dom->fqnames
     977           0 :                 && !cmdctx->name_is_upn) {
     978           0 :             dom = get_next_domain(dom, 0);
     979             :         }
     980             : 
     981          18 :         if (!dom) break;
     982             : 
     983          18 :         if (dom != dctx->domain) {
     984             :             /* make sure we reset the check_provider flag when we check
     985             :              * a new domain */
     986           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
     987             :         }
     988             : 
     989             :         /* make sure to update the dctx if we changed domain */
     990          18 :         dctx->domain = dom;
     991             : 
     992          18 :         talloc_free(name);
     993          18 :         name = sss_get_cased_name(cmdctx, cmdctx->name, dom->case_sensitive);
     994          18 :         if (!name) return ENOMEM;
     995             : 
     996          18 :         name = sss_reverse_replace_space(dctx, name,
     997          18 :                                          nctx->rctx->override_space);
     998          18 :         if (name == NULL) {
     999           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1000             :                   "sss_reverse_replace_space failed\n");
    1001           0 :             return ENOMEM;
    1002             :         }
    1003             : 
    1004             :         /* verify this user has not yet been negatively cached,
    1005             :         * or has been permanently filtered */
    1006          18 :         ret = sss_ncache_check_user(nctx->rctx->ncache, dom, name);
    1007             : 
    1008             :         /* if neg cached, return we didn't find it */
    1009          18 :         if (ret == EEXIST) {
    1010           3 :             DEBUG(SSSDBG_TRACE_FUNC,
    1011             :                   "User [%s] does not exist in [%s]! (negative cache)\n",
    1012             :                    name, dom->name);
    1013             :             /* if a multidomain search, try with next */
    1014           3 :             if (cmdctx->check_next) {
    1015           3 :                 if (cmdctx->name_is_upn) {
    1016           2 :                     dom = get_next_domain(dom, SSS_GND_DESCEND);
    1017             :                 } else {
    1018           1 :                     dom = get_next_domain(dom, 0);
    1019             :                 }
    1020           3 :                 continue;
    1021             :             }
    1022             :             /* There are no further domains or this was a
    1023             :              * fully-qualified user request.
    1024             :              */
    1025           0 :             return ENOENT;
    1026             :         }
    1027             : 
    1028          15 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1029             :               "Requesting info for [%s@%s]\n", name, dom->name);
    1030             : 
    1031          15 :         if (dom->sysdb == NULL) {
    1032           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1033             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    1034           0 :             return EIO;
    1035             :         }
    1036             : 
    1037          15 :         if (cmdctx->name_is_upn) {
    1038           3 :             ret = sysdb_search_user_by_upn(cmdctx, dom, name, user_attrs, &msg);
    1039           3 :             if (ret != EOK && ret != ENOENT) {
    1040           0 :                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_upn failed.\n");
    1041           0 :                 return ret;
    1042             :             }
    1043             : 
    1044           3 :             dctx->res = talloc_zero(cmdctx, struct ldb_result);
    1045           3 :             if (dctx->res == NULL) {
    1046           0 :                 DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
    1047           0 :                 return ENOMEM;
    1048             :             }
    1049             : 
    1050           3 :             if (ret == ENOENT) {
    1051           2 :                 dctx->res->count = 0;
    1052           2 :                 dctx->res->msgs = NULL;
    1053           2 :                 ret = EOK;
    1054             :             } else {
    1055           1 :                 dctx->res->count = 1;
    1056           1 :                 dctx->res->msgs = talloc_array(dctx->res,
    1057             :                                                struct ldb_message *, 1);
    1058           1 :                 if (dctx->res->msgs == NULL) {
    1059           0 :                     DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
    1060           0 :                     return ENOMEM;
    1061             :                 }
    1062             : 
    1063           1 :                 dctx->res->msgs[0] = talloc_steal(dctx->res->msgs, msg);
    1064             :             }
    1065             :         } else {
    1066          12 :             ret = sysdb_getpwnam_with_views(cmdctx, dom, name, &dctx->res);
    1067             :         }
    1068          15 :         if (ret != EOK) {
    1069           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1070             :                   "Failed to make request to our cache!\n");
    1071           0 :             return EIO;
    1072             :         }
    1073             : 
    1074          15 :         if (dctx->res->count > 1) {
    1075           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1076             :                   "getpwnam call returned more than one result !?!\n");
    1077           0 :             sss_log(SSS_LOG_ERR,
    1078             :                     "More users have the same name [%s@%s] in SSSD cache. "
    1079             :                     "SSSD will not work correctly.\n",
    1080             :                     name, dom->name);
    1081           0 :             return ENOENT;
    1082             :         }
    1083             : 
    1084          15 :         if (dctx->res->count == 0 && !dctx->check_provider) {
    1085             :             /* set negative cache only if not result of cache check */
    1086           2 :             ret = sss_ncache_set_user(nctx->rctx->ncache, false, dom, name);
    1087           2 :             if (ret != EOK) {
    1088           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for %s@%s\n",
    1089             :                       name, dom->name);
    1090             :             }
    1091             : 
    1092             :             /* if a multidomain search, try with next */
    1093           2 :             if (cmdctx->check_next) {
    1094           2 :                 if (cmdctx->name_is_upn) {
    1095           1 :                     dom = get_next_domain(dom, SSS_GND_DESCEND);
    1096             :                 } else {
    1097           1 :                     dom = get_next_domain(dom, 0);
    1098             :                 }
    1099           2 :                 if (dom) continue;
    1100             :             }
    1101             : 
    1102           2 :             DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n");
    1103             : 
    1104             :             /* User not found in ldb -> delete user from memory cache. */
    1105           2 :             ret = delete_entry_from_memcache(dctx->domain, name,
    1106             :                                              nctx->pwd_mc_ctx, SSS_MC_PASSWD);
    1107           2 :             if (ret != EOK) {
    1108           2 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    1109             :                       "Deleting user from memcache failed.\n");
    1110             :             }
    1111             : 
    1112           2 :             ret = delete_entry_from_memcache(dctx->domain, name,
    1113             :                                              nctx->initgr_mc_ctx,
    1114             :                                              SSS_MC_INITGROUPS);
    1115           2 :             if (ret != EOK) {
    1116           2 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    1117             :                       "Deleting user from memcache failed.\n");
    1118             :             }
    1119             : 
    1120           2 :             return ENOENT;
    1121             :         }
    1122             : 
    1123             :         /* if this is a caching provider (or if we haven't checked the cache
    1124             :          * yet) then verify that the cache is uptodate */
    1125          13 :         if (dctx->check_provider) {
    1126             : 
    1127          11 :             if (cmdctx->name_is_upn) {
    1128           2 :                 extra_flag = EXTRA_NAME_IS_UPN;
    1129           9 :             } else if (DOM_HAS_VIEWS(dom) && (dctx->res->count == 0
    1130           0 :                     || ldb_msg_find_attr_as_string(dctx->res->msgs[0],
    1131             :                                                    OVERRIDE_PREFIX SYSDB_NAME,
    1132             :                                                    NULL) != NULL)) {
    1133           0 :                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
    1134             :             } else {
    1135           9 :                 extra_flag = NULL;
    1136             :             }
    1137             : 
    1138          11 :             ret = check_cache(dctx, nctx, dctx->res, SSS_DP_USER, name, 0,
    1139             :                               extra_flag, nss_cmd_getby_dp_callback, dctx);
    1140          11 :             if (ret != EOK) {
    1141             :                 /* Anything but EOK means we should reenter the mainloop
    1142             :                  * because we may be refreshing the cache
    1143             :                  */
    1144           4 :                 return ret;
    1145             :             }
    1146             :         }
    1147             : 
    1148             :         /* One result found */
    1149           9 :         DEBUG(SSSDBG_TRACE_FUNC,
    1150             :               "Returning info for user [%s@%s]\n", name, dom->name);
    1151             : 
    1152           9 :         return EOK;
    1153             :     }
    1154             : 
    1155           3 :     DEBUG(SSSDBG_MINOR_FAILURE,
    1156             :           "No matching domain found for [%s], fail!\n", cmdctx->name);
    1157           3 :     return ENOENT;
    1158             : }
    1159             : 
    1160             : static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx);
    1161             : static int nss_cmd_getgr_send_reply(struct nss_dom_ctx *dctx, bool filter);
    1162             : static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx);
    1163             : static int nss_cmd_initgr_send_reply(struct nss_dom_ctx *dctx);
    1164             : static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx);
    1165             : static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx);
    1166             : static errno_t nss_cmd_getbysid_search(struct nss_dom_ctx *dctx);
    1167             : static errno_t nss_cmd_getbysid_send_reply(struct nss_dom_ctx *dctx);
    1168             : static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx);
    1169             : 
    1170           8 : static int nss_cmd_assume_upn(struct nss_dom_ctx *dctx)
    1171             : {
    1172             :     int ret;
    1173             : 
    1174           8 :     if (dctx->domain == NULL) {
    1175           6 :         dctx->domain = dctx->cmdctx->cctx->rctx->domains;
    1176           6 :         dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
    1177           6 :         dctx->cmdctx->check_next = true;
    1178           6 :         dctx->cmdctx->name = talloc_strdup(dctx->cmdctx, dctx->rawname);
    1179           6 :         dctx->cmdctx->name_is_upn = true;
    1180           6 :         if (dctx->cmdctx->name == NULL) {
    1181           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
    1182           0 :             return ENOMEM;
    1183             :         }
    1184             :     }
    1185             : 
    1186           8 :     switch (dctx->cmdctx->cmd) {
    1187             :     case SSS_NSS_GETPWNAM:
    1188           4 :         ret = nss_cmd_getpwnam_search(dctx);
    1189           4 :         if (ret == EOK) {
    1190           1 :             ret = nss_cmd_getpw_send_reply(dctx, false);
    1191             :         }
    1192           4 :         break;
    1193             :     case SSS_NSS_INITGR:
    1194           4 :         ret = nss_cmd_initgroups_search(dctx);
    1195           4 :         if (ret == EOK) {
    1196           1 :             ret = nss_cmd_initgr_send_reply(dctx);
    1197             :         }
    1198           4 :         break;
    1199             :     default:
    1200           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    1201             :               dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    1202           0 :         ret = EINVAL;
    1203             :     }
    1204             : 
    1205           8 :     return ret;
    1206             : }
    1207             : 
    1208          14 : static void nss_cmd_getby_dp_callback(uint16_t err_maj, uint32_t err_min,
    1209             :                                       const char *err_msg, void *ptr)
    1210             : {
    1211          14 :     struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx);
    1212          14 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    1213          14 :     struct cli_ctx *cctx = cmdctx->cctx;
    1214             :     int ret;
    1215             :     uint32_t gnd_flags;
    1216          14 :     struct nss_ctx *nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    1217             : 
    1218          14 :     if (err_maj) {
    1219           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1220             :               "Unable to get information from Data Provider\n"
    1221             :                   "Error: %u, %u, %s\n"
    1222             :                   "Will try to return what we have in cache\n",
    1223             :                   (unsigned int)err_maj, (unsigned int)err_min, err_msg);
    1224             : 
    1225           0 :         if ((dctx->res && dctx->res->count == 1) ||
    1226           0 :             (dctx->cmdctx->cmd == SSS_NSS_INITGR &&
    1227           0 :              dctx->res && dctx->res->count != 0)) {
    1228           0 :             switch (dctx->cmdctx->cmd) {
    1229             :             case SSS_NSS_GETPWNAM:
    1230           0 :                 ret = nss_cmd_getpw_send_reply(dctx, false);
    1231           0 :                 break;
    1232             :             case SSS_NSS_GETGRNAM:
    1233           0 :                 ret = nss_cmd_getgr_send_reply(dctx, false);
    1234           0 :                 break;
    1235             :             case SSS_NSS_INITGR:
    1236           0 :                 ret = nss_cmd_initgr_send_reply(dctx);
    1237           0 :                 break;
    1238             :             case SSS_NSS_GETPWUID:
    1239           0 :                 ret = nss_cmd_getpw_send_reply(dctx, true);
    1240           0 :                 break;
    1241             :             case SSS_NSS_GETGRGID:
    1242           0 :                 ret = nss_cmd_getgr_send_reply(dctx, true);
    1243           0 :                 break;
    1244             :             case SSS_NSS_GETNAMEBYSID:
    1245             :             case SSS_NSS_GETIDBYSID:
    1246             :             case SSS_NSS_GETSIDBYNAME:
    1247             :             case SSS_NSS_GETORIGBYNAME:
    1248             :             case SSS_NSS_GETSIDBYID:
    1249           0 :                 ret = nss_cmd_getbysid_send_reply(dctx);
    1250           0 :                 break;
    1251             :             default:
    1252           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    1253             :                       dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    1254           0 :                 ret = EINVAL;
    1255             :             }
    1256           0 :             goto done;
    1257             :         }
    1258             : 
    1259             :         /* Since subdomain users and groups are fully qualified they are
    1260             :          * typically not subject of multi-domain searches. But since POSIX
    1261             :          * ID do not contain a domain name we have to descend to subdomains
    1262             :          * here. */
    1263           0 :         switch (dctx->cmdctx->cmd) {
    1264             :         case SSS_NSS_GETPWUID:
    1265           0 :             ret = sss_ncache_set_uid(nctx->rctx->ncache, false, dctx->domain,
    1266             :                                      cmdctx->id);
    1267           0 :             if (ret != EOK) {
    1268           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    1269             :                       "Cannot set negative cache for UID %"PRIu32"\n",
    1270             :                       cmdctx->id);
    1271             :             }
    1272           0 :             gnd_flags = SSS_GND_DESCEND;
    1273           0 :             break;
    1274             :         case SSS_NSS_GETGRGID:
    1275           0 :             ret = sss_ncache_set_gid(nctx->rctx->ncache, false, dctx->domain,
    1276             :                                      cmdctx->id);
    1277           0 :             if (ret != EOK) {
    1278           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    1279             :                       "Cannot set negative cache for GID %"PRIu32"\n",
    1280             :                       cmdctx->id);
    1281             :             }
    1282           0 :             gnd_flags = SSS_GND_DESCEND;
    1283           0 :             break;
    1284             :         case SSS_NSS_GETSIDBYID:
    1285           0 :             ret = sss_ncache_set_uid(nctx->rctx->ncache, false, dctx->domain,
    1286             :                                      cmdctx->id);
    1287           0 :             if (ret != EOK) {
    1288           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    1289             :                       "Cannot set negative cache for UID %"PRIu32"\n",
    1290             :                        cmdctx->id);
    1291             :             }
    1292           0 :             ret = sss_ncache_set_gid(nctx->rctx->ncache, false, dctx->domain,
    1293             :                                      cmdctx->id);
    1294           0 :             if (ret != EOK) {
    1295           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    1296             :                       "Cannot set negative cache for GID %"PRIu32"\n",
    1297             :                       cmdctx->id);
    1298             :             }
    1299           0 :             gnd_flags = SSS_GND_DESCEND;
    1300           0 :             break;
    1301             :         default:
    1302             :             /* Do not descend to subdomains */
    1303           0 :             gnd_flags = 0;
    1304             :         }
    1305             : 
    1306             :         /* no previous results, just loop to next domain if possible */
    1307           0 :         if (cmdctx->check_next &&
    1308           0 :             get_next_domain(dctx->domain, gnd_flags)) {
    1309           0 :             dctx->domain = get_next_domain(dctx->domain, gnd_flags);
    1310           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
    1311             :         } else {
    1312             :             /* nothing available */
    1313           0 :             ret = ENOENT;
    1314           0 :             goto done;
    1315             :         }
    1316             :     }
    1317             : 
    1318             :     /* ok the backend returned, search to see if we have updated results */
    1319          14 :     switch (dctx->cmdctx->cmd) {
    1320             :     case SSS_NSS_GETPWNAM:
    1321           4 :         ret = nss_cmd_getpwnam_search(dctx);
    1322           4 :         if (ret == EOK) {
    1323             :             /* we have results to return */
    1324           2 :             ret = nss_cmd_getpw_send_reply(dctx, false);
    1325             :         }
    1326           4 :         break;
    1327             :     case SSS_NSS_GETGRNAM:
    1328           0 :         ret = nss_cmd_getgrnam_search(dctx);
    1329           0 :         if (ret == EOK) {
    1330             :             /* we have results to return */
    1331           0 :             ret = nss_cmd_getgr_send_reply(dctx, false);
    1332             :         }
    1333           0 :         break;
    1334             :     case SSS_NSS_INITGR:
    1335           5 :         ret = nss_cmd_initgroups_search(dctx);
    1336           5 :         if (ret == EOK) {
    1337             :             /* we have results to return */
    1338           3 :             ret = nss_cmd_initgr_send_reply(dctx);
    1339             :         }
    1340           5 :         break;
    1341             :     case SSS_NSS_GETPWUID:
    1342           3 :         ret = nss_cmd_getpwuid_search(dctx);
    1343           3 :         if (ret == EOK) {
    1344             :             /* we have results to return */
    1345           2 :             ret = nss_cmd_getpw_send_reply(dctx, true);
    1346             :         }
    1347           3 :         break;
    1348             :     case SSS_NSS_GETGRGID:
    1349           0 :         ret = nss_cmd_getgrgid_search(dctx);
    1350           0 :         if (ret == EOK) {
    1351             :             /* we have results to return */
    1352           0 :             ret = nss_cmd_getgr_send_reply(dctx, true);
    1353             :         }
    1354           0 :         break;
    1355             :     case SSS_NSS_GETNAMEBYSID:
    1356             :     case SSS_NSS_GETIDBYSID:
    1357           2 :         ret = nss_cmd_getbysid_search(dctx);
    1358           2 :         if (ret == EOK) {
    1359           1 :             ret = nss_cmd_getbysid_send_reply(dctx);
    1360             :         }
    1361           2 :         break;
    1362             :     case SSS_NSS_GETSIDBYNAME:
    1363             :     case SSS_NSS_GETORIGBYNAME:
    1364           0 :         ret = nss_cmd_getsidby_search(dctx);
    1365           0 :         if (ret == EOK) {
    1366           0 :             ret = nss_cmd_getbysid_send_reply(dctx);
    1367             :         }
    1368           0 :         break;
    1369             :     case SSS_NSS_GETSIDBYID:
    1370           0 :         ret = nss_cmd_getsidby_search(dctx);
    1371           0 :         if (ret == EOK) {
    1372           0 :             ret = nss_cmd_getbysid_send_reply(dctx);
    1373             :         }
    1374           0 :         break;
    1375             :     default:
    1376           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    1377             :               dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    1378           0 :         ret = EINVAL;
    1379             :     }
    1380             : 
    1381             : done:
    1382          14 :     if (ret == ENOENT
    1383           6 :         && (dctx->cmdctx->cmd == SSS_NSS_GETPWNAM
    1384           4 :                 || dctx->cmdctx->cmd == SSS_NSS_INITGR)
    1385           4 :         && dctx->rawname != NULL && strchr(dctx->rawname, '@') != NULL) {
    1386             :         /* assume Kerberos principal */
    1387           2 :         ret = nss_cmd_assume_upn(dctx);
    1388             :     }
    1389             : 
    1390          14 :     ret = nss_cmd_done(cmdctx, ret);
    1391          14 :     if (ret) {
    1392           0 :         NSS_CMD_FATAL_ERROR(cctx);
    1393             :     }
    1394             : }
    1395             : 
    1396           6 : static int nss_check_name_of_well_known_sid(struct nss_cmd_ctx *cmdctx,
    1397             :                                             const char *full_name)
    1398             : {
    1399           6 :     char *wk_name = NULL;
    1400           6 :     char *wk_dom_name = NULL;
    1401             :     const char *wk_sid;
    1402             :     int ret;
    1403             :     struct sized_string sid;
    1404             :     uint8_t *body;
    1405             :     size_t blen;
    1406             :     struct cli_ctx *cctx;
    1407             :     struct nss_ctx *nss_ctx;
    1408           6 :     size_t pctr = 0;
    1409             : 
    1410           6 :     nss_ctx = talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct nss_ctx);
    1411           6 :     ret = sss_parse_name(cmdctx, nss_ctx->global_names, full_name,
    1412             :                          &wk_dom_name, &wk_name);
    1413           6 :     if (ret != EOK) {
    1414           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_parse_name failed.\n");
    1415           0 :         return ret;
    1416             :     }
    1417             : 
    1418           6 :     if (wk_dom_name == NULL || wk_name == NULL) {
    1419           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1420             :               "Unable to split [%s] in name and domain part. " \
    1421             :               "Skipping check for well-known name.\n", full_name);
    1422             : 
    1423           0 :         return ENOENT;
    1424             :     }
    1425             : 
    1426           6 :     ret = name_to_well_known_sid(wk_dom_name, wk_name, &wk_sid);
    1427           6 :     talloc_free(wk_dom_name);
    1428           6 :     talloc_free(wk_name);
    1429           6 :     if (ret != EOK) {
    1430           2 :         DEBUG(SSSDBG_TRACE_ALL, "Name [%s] is not the name of a " \
    1431             :                                  "Well-Known SID.\n", full_name);
    1432           2 :         return ret;
    1433             :     }
    1434             : 
    1435           4 :     to_sized_string(&sid, wk_sid);
    1436             : 
    1437           4 :     cctx = cmdctx->cctx;
    1438           8 :     ret = sss_packet_new(cctx->creq, sid.len + 3 * sizeof(uint32_t),
    1439           4 :                          sss_packet_get_cmd(cctx->creq->in),
    1440           4 :                          &cctx->creq->out);
    1441           4 :     if (ret != EOK) {
    1442           0 :         return ENOMEM;
    1443             :     }
    1444             : 
    1445           4 :     sss_packet_get_body(cctx->creq->out, &body, &blen);
    1446           4 :     SAFEALIGN_SETMEM_UINT32(body, 1, &pctr);  /* num results */
    1447           4 :     SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */
    1448           4 :     SAFEALIGN_SETMEM_UINT32(body + pctr, SSS_ID_TYPE_GID, &pctr);
    1449           4 :     memcpy(&body[pctr], sid.str, sid.len);
    1450             : 
    1451           4 :     sss_packet_set_error(cctx->creq->out, EOK);
    1452           4 :     sss_cmd_done(cctx, cmdctx);
    1453           4 :     return EOK;
    1454             : }
    1455             : 
    1456             : static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx);
    1457             : static void nss_cmd_getbynam_done(struct tevent_req *req);
    1458          13 : static int nss_cmd_getpwnam(struct cli_ctx *cctx)
    1459             : {
    1460          13 :     return nss_cmd_getbynam(SSS_NSS_GETPWNAM, cctx);
    1461             : }
    1462             : 
    1463          40 : static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx)
    1464             : {
    1465             : 
    1466             :     struct tevent_req *req;
    1467             :     struct nss_cmd_ctx *cmdctx;
    1468             :     struct nss_dom_ctx *dctx;
    1469             :     const char *rawname;
    1470             :     char *domname;
    1471             :     uint8_t *body;
    1472             :     size_t blen;
    1473             :     int ret;
    1474             : 
    1475          40 :     switch(cmd) {
    1476             :     case SSS_NSS_GETPWNAM:
    1477             :     case SSS_NSS_GETGRNAM:
    1478             :     case SSS_NSS_INITGR:
    1479             :     case SSS_NSS_GETSIDBYNAME:
    1480             :     case SSS_NSS_GETORIGBYNAME:
    1481          40 :         break;
    1482             :     default:
    1483           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command type [%d][%s].\n",
    1484             :               cmd, sss_cmd2str(cmd));
    1485           0 :         return EINVAL;
    1486             :     }
    1487             : 
    1488          40 :     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
    1489          40 :     if (!cmdctx) {
    1490           0 :         return ENOMEM;
    1491             :     }
    1492          40 :     cmdctx->cctx = cctx;
    1493          40 :     cmdctx->cmd = cmd;
    1494             : 
    1495          40 :     dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
    1496          40 :     if (!dctx) {
    1497           0 :         ret = ENOMEM;
    1498           0 :         goto done;
    1499             :     }
    1500          40 :     dctx->cmdctx = cmdctx;
    1501             : 
    1502             :     /* get user name to query */
    1503          40 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
    1504             : 
    1505             :     /* if not terminated fail */
    1506          40 :     if (body[blen -1] != '\0') {
    1507           0 :         ret = EINVAL;
    1508           0 :         goto done;
    1509             :     }
    1510             : 
    1511             :     /* If the body isn't valid UTF-8, fail */
    1512          40 :     if (!sss_utf8_check(body, blen -1)) {
    1513           0 :         ret = EINVAL;
    1514           0 :         goto done;
    1515             :     }
    1516             : 
    1517          40 :     rawname = (const char *)body;
    1518          40 :     dctx->mc_name = rawname;
    1519             : 
    1520          40 :     DEBUG(SSSDBG_TRACE_FUNC, "Running command [%d][%s] with input [%s].\n",
    1521             :           cmd, sss_cmd2str(dctx->cmdctx->cmd), rawname);
    1522             : 
    1523          40 :     if (dctx->cmdctx->cmd == SSS_NSS_GETSIDBYNAME) {
    1524           6 :         ret = nss_check_name_of_well_known_sid(cmdctx, rawname);
    1525           6 :         if (ret != ENOENT) {
    1526           6 :             if (ret == EOK) {
    1527           4 :                 DEBUG(SSSDBG_TRACE_ALL, "Name [%s] is the name of a " \
    1528             :                                          "Well-Known SID.\n", rawname);
    1529             :             } else {
    1530           2 :                 DEBUG(SSSDBG_OP_FAILURE,
    1531             :                       "nss_check_name_of_well_known_sid failed.\n");
    1532             :             }
    1533           6 :             goto done;
    1534             :         }
    1535             :     }
    1536             : 
    1537             :     /* We need to attach to subdomain request, if the first one is not
    1538             :      * finished yet. We may not be able to lookup object in AD otherwise. */
    1539          34 :     if (cctx->rctx->get_domains_last_call.tv_sec == 0) {
    1540          34 :         req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, NULL);
    1541          34 :         if (req == NULL) {
    1542           0 :             ret = ENOMEM;
    1543             :         } else {
    1544          34 :             dctx->rawname = rawname;
    1545          34 :             tevent_req_set_callback(req, nss_cmd_getbynam_done, dctx);
    1546          34 :             ret = EAGAIN;
    1547             :         }
    1548          34 :         goto done;
    1549             :     }
    1550             : 
    1551           0 :     domname = NULL;
    1552           0 :     ret = sss_parse_name_for_domains(cmdctx, cctx->rctx->domains,
    1553           0 :                                      cctx->rctx->default_domain, rawname,
    1554             :                                      &domname, &cmdctx->name);
    1555           0 :     if (ret == EAGAIN) {
    1556           0 :         req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, domname);
    1557           0 :         if (req == NULL) {
    1558           0 :             ret = ENOMEM;
    1559             :         } else {
    1560           0 :             dctx->rawname = rawname;
    1561           0 :             tevent_req_set_callback(req, nss_cmd_getbynam_done, dctx);
    1562           0 :             ret = EAGAIN;
    1563             :         }
    1564           0 :         goto done;
    1565           0 :     } else if (ret != EOK) {
    1566           0 :         DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", rawname);
    1567           0 :         ret = ENOENT;
    1568           0 :         goto done;
    1569             :     }
    1570             : 
    1571           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Requesting info for [%s] from [%s]\n",
    1572             :               cmdctx->name, domname?domname:"<ALL>");
    1573             : 
    1574           0 :     if (domname) {
    1575           0 :         dctx->domain = responder_get_domain(cctx->rctx, domname);
    1576           0 :         if (!dctx->domain) {
    1577           0 :             ret = ENOENT;
    1578           0 :             goto done;
    1579             :         }
    1580             :     } else {
    1581             :         /* this is a multidomain search */
    1582           0 :         dctx->rawname = rawname;
    1583           0 :         dctx->domain = cctx->rctx->domains;
    1584           0 :         cmdctx->check_next = true;
    1585           0 :         if (cctx->rctx->get_domains_last_call.tv_sec == 0) {
    1586           0 :             req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, false, NULL);
    1587           0 :             if (req == NULL) {
    1588           0 :                 ret = ENOMEM;
    1589             :             } else {
    1590           0 :                 tevent_req_set_callback(req, nss_cmd_getbynam_done, dctx);
    1591           0 :                 ret = EAGAIN;
    1592             :             }
    1593           0 :             goto done;
    1594             :         }
    1595             :     }
    1596             : 
    1597           0 :     dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
    1598             : 
    1599             :     /* ok, find it ! */
    1600           0 :     switch (dctx->cmdctx->cmd) {
    1601             :     case SSS_NSS_GETPWNAM:
    1602           0 :         ret = nss_cmd_getpwnam_search(dctx);
    1603           0 :         if (ret == EOK) {
    1604             :             /* we have results to return */
    1605           0 :             ret = nss_cmd_getpw_send_reply(dctx, false);
    1606           0 :         } else if (ret == ENOENT
    1607           0 :                 && dctx->rawname != NULL
    1608           0 :                 && strchr(dctx->rawname, '@') != NULL) {
    1609             :             /* assume Kerberos principal */
    1610           0 :             ret = nss_cmd_assume_upn(dctx);
    1611             :         }
    1612           0 :         break;
    1613             :     case SSS_NSS_GETGRNAM:
    1614           0 :         ret = nss_cmd_getgrnam_search(dctx);
    1615           0 :         if (ret == EOK) {
    1616             :             /* we have results to return */
    1617           0 :             ret = nss_cmd_getgr_send_reply(dctx, false);
    1618             :         }
    1619           0 :         break;
    1620             :     case SSS_NSS_INITGR:
    1621           0 :         ret = nss_cmd_initgroups_search(dctx);
    1622           0 :         if (ret == EOK) {
    1623             :             /* we have results to return */
    1624           0 :             ret = nss_cmd_initgr_send_reply(dctx);
    1625           0 :         } else if (ret == ENOENT
    1626           0 :                 && dctx->rawname != NULL
    1627           0 :                 && strchr(dctx->rawname, '@') != NULL) {
    1628             :             /* assume Kerberos principal */
    1629           0 :             ret = nss_cmd_assume_upn(dctx);
    1630             :         }
    1631           0 :         break;
    1632             :     case SSS_NSS_GETSIDBYNAME:
    1633             :     case SSS_NSS_GETORIGBYNAME:
    1634           0 :         ret = nss_cmd_getsidby_search(dctx);
    1635           0 :         if (ret == EOK) {
    1636           0 :             ret = nss_cmd_getbysid_send_reply(dctx);
    1637             :         }
    1638           0 :         break;
    1639             :     default:
    1640           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    1641             :               dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    1642           0 :         ret = EINVAL;
    1643             :     }
    1644             : 
    1645             : done:
    1646          40 :     return nss_cmd_done(cmdctx, ret);
    1647             : }
    1648             : 
    1649          34 : static void nss_cmd_getbynam_done(struct tevent_req *req)
    1650             : {
    1651          34 :     struct nss_dom_ctx *dctx = tevent_req_callback_data(req, struct nss_dom_ctx);
    1652          34 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    1653          34 :     struct cli_ctx *cctx = cmdctx->cctx;
    1654          34 :     char *domname = NULL;
    1655          34 :     const char *rawname = dctx->rawname;
    1656             :     errno_t ret;
    1657             : 
    1658          34 :     ret = sss_dp_get_domains_recv(req);
    1659          34 :     talloc_free(req);
    1660          34 :     if (ret != EOK) {
    1661           0 :         goto done;
    1662             :     }
    1663             : 
    1664          68 :     ret = sss_parse_name_for_domains(cmdctx, cctx->rctx->domains,
    1665          34 :                                      cctx->rctx->default_domain, rawname,
    1666             :                                      &domname, &cmdctx->name);
    1667          34 :     if (ret == EAGAIN && (dctx->cmdctx->cmd == SSS_NSS_GETPWNAM
    1668           3 :                             || dctx->cmdctx->cmd == SSS_NSS_INITGR)) {
    1669             :         /* assume Kerberos principal */
    1670           6 :         ret = nss_cmd_assume_upn(dctx);
    1671           6 :         goto done;
    1672          28 :     } else if (ret != EOK) {
    1673           0 :         DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", rawname);
    1674           0 :         ret = ENOENT;
    1675           0 :         goto done;
    1676             :     }
    1677             : 
    1678          28 :     ret = nss_reset_negcache(cctx->rctx);
    1679          28 :     if (ret != EOK) {
    1680           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Cannot reset negcache records\n");
    1681             :         /* Not fatal */
    1682             :     }
    1683             : 
    1684          28 :     DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%s] from [%s]\n",
    1685             :               cmdctx->name, domname?domname:"<ALL>");
    1686             : 
    1687          28 :     if (domname) {
    1688           6 :         dctx->domain = responder_get_domain(cctx->rctx, domname);
    1689           6 :         if (dctx->domain == NULL) {
    1690           0 :             ret = ENOENT;
    1691           0 :             goto done;
    1692             :         }
    1693             :     } else {
    1694             :         /* this is a multidomain search */
    1695          22 :         dctx->domain = cctx->rctx->domains;
    1696          22 :         cmdctx->check_next = true;
    1697             :     }
    1698             : 
    1699          28 :     dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
    1700             : 
    1701             :     /* ok, find it ! */
    1702          28 :     switch (dctx->cmdctx->cmd) {
    1703             :     case SSS_NSS_GETPWNAM:
    1704          10 :         ret = nss_cmd_getpwnam_search(dctx);
    1705          10 :         if (ret == EOK) {
    1706             :             /* we have results to return */
    1707           6 :             ret = nss_cmd_getpw_send_reply(dctx, false);
    1708           4 :         } else if (ret == ENOENT
    1709           1 :                     && dctx->rawname != NULL
    1710           1 :                     && strchr(dctx->rawname, '@') != NULL) {
    1711             :             /* assume Kerberos principal */
    1712           0 :             ret = nss_cmd_assume_upn(dctx);
    1713             :         }
    1714          10 :         break;
    1715             :     case SSS_NSS_GETGRNAM:
    1716           9 :         ret = nss_cmd_getgrnam_search(dctx);
    1717           9 :         if (ret == EOK) {
    1718             :             /* we have results to return */
    1719           9 :             ret = nss_cmd_getgr_send_reply(dctx, false);
    1720             :         }
    1721           9 :         break;
    1722             :     case SSS_NSS_INITGR:
    1723           6 :         ret = nss_cmd_initgroups_search(dctx);
    1724           6 :         if (ret == EOK) {
    1725             :             /* we have results to return */
    1726           1 :             ret = nss_cmd_initgr_send_reply(dctx);
    1727           5 :         } else if (ret == ENOENT
    1728           1 :                     && dctx->rawname != NULL
    1729           1 :                     && strchr(dctx->rawname, '@') != NULL) {
    1730             :             /* assume Kerberos principal */
    1731           0 :             ret = nss_cmd_assume_upn(dctx);
    1732             :         }
    1733           6 :         break;
    1734             :     case SSS_NSS_GETSIDBYNAME:
    1735             :     case SSS_NSS_GETORIGBYNAME:
    1736           3 :         ret = nss_cmd_getsidby_search(dctx);
    1737           3 :         if (ret == EOK) {
    1738           3 :             ret = nss_cmd_getbysid_send_reply(dctx);
    1739             :         }
    1740           3 :         break;
    1741             :     default:
    1742           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    1743             :               dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    1744           0 :         ret = EINVAL;
    1745             :     }
    1746             : 
    1747             : done:
    1748          34 :     nss_cmd_done(cmdctx, ret);
    1749          34 : }
    1750             : 
    1751             : /* search for a uid.
    1752             :  * Returns:
    1753             :  *   ENOENT, if uid is definitely not found
    1754             :  *   EAGAIN, if uid is being fetched from backend via async operations
    1755             :  *   EOK, if found
    1756             :  *   anything else on a fatal error
    1757             :  */
    1758             : 
    1759           7 : static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx)
    1760             : {
    1761           7 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    1762           7 :     struct sss_domain_info *dom = dctx->domain;
    1763           7 :     struct cli_ctx *cctx = cmdctx->cctx;
    1764             :     struct nss_ctx *nctx;
    1765             :     int ret;
    1766             :     int err;
    1767           7 :     const char *extra_flag = NULL;
    1768             : 
    1769           7 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    1770             : 
    1771           7 :     while (dom) {
    1772             : 
    1773             :         /* check that the uid is valid for this domain */
    1774          14 :         if ((dom->id_min && (cmdctx->id < dom->id_min)) ||
    1775           7 :             (dom->id_max && (cmdctx->id > dom->id_max))) {
    1776           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    1777             :                   "Uid [%"PRIu32"] does not exist in domain [%s]! "
    1778             :                       "(id out of range)\n",
    1779             :                       cmdctx->id, dom->name);
    1780           0 :             if (cmdctx->check_next) {
    1781           0 :                 dom = get_next_domain(dom, SSS_GND_DESCEND);
    1782           0 :                 continue;
    1783             :             }
    1784           0 :             ret = ENOENT;
    1785           0 :             goto done;
    1786             :         }
    1787             : 
    1788           7 :         if (dom != dctx->domain) {
    1789             :             /* make sure we reset the check_provider flag when we check
    1790             :              * a new domain */
    1791           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    1792             :         }
    1793             : 
    1794             :         /* make sure to update the dctx if we changed domain */
    1795           7 :         dctx->domain = dom;
    1796             : 
    1797           7 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1798             :               "Requesting info for [%"PRIu32"@%s]\n", cmdctx->id, dom->name);
    1799             : 
    1800           7 :         if (dom->sysdb == NULL) {
    1801           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1802             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    1803           0 :             ret = EIO;
    1804           0 :             goto done;
    1805             :         }
    1806             : 
    1807           7 :         ret = sysdb_getpwuid_with_views(cmdctx, dom, cmdctx->id, &dctx->res);
    1808           7 :         if (ret != EOK) {
    1809           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1810             :                   "Failed to make request to our cache!\n");
    1811           0 :             ret = EIO;
    1812           0 :             goto done;
    1813             :         }
    1814             : 
    1815           7 :         if (dctx->res->count > 1) {
    1816           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1817             :                   "getpwuid call returned more than one result !?!\n");
    1818           0 :             sss_log(SSS_LOG_ERR,
    1819             :                     "More users have the same UID [%"PRIu32"] in directory "
    1820             :                     "server. SSSD will not work correctly.\n", cmdctx->id);
    1821           0 :             ret = ENOENT;
    1822           0 :             goto done;
    1823             :         }
    1824             : 
    1825           7 :         if (dctx->res->count == 0 && !dctx->check_provider) {
    1826             :             /* if a multidomain search, try with next */
    1827           1 :             if (cmdctx->check_next) {
    1828           1 :                 dom = get_next_domain(dom, SSS_GND_DESCEND);
    1829           1 :                 continue;
    1830             :             }
    1831             : 
    1832             :             /* set negative cache only if not result of cache check */
    1833           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "No results for getpwuid call\n");
    1834           0 :             ret = ENOENT;
    1835           0 :             goto done;
    1836             :         }
    1837             : 
    1838             :         /* if this is a caching provider (or if we haven't checked the cache
    1839             :          * yet) then verify that the cache is uptodate */
    1840           6 :         if (dctx->check_provider) {
    1841             : 
    1842           4 :             if (DOM_HAS_VIEWS(dom) && (dctx->res->count == 0
    1843           0 :                     || ldb_msg_find_attr_as_uint64(dctx->res->msgs[0],
    1844             :                                                    OVERRIDE_PREFIX SYSDB_UIDNUM,
    1845             :                                                    0) != 0)) {
    1846           0 :                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
    1847             :             } else {
    1848           4 :                 extra_flag = NULL;
    1849             :             }
    1850             : 
    1851           4 :             ret = check_cache(dctx, nctx, dctx->res, SSS_DP_USER, NULL,
    1852             :                               cmdctx->id, extra_flag, nss_cmd_getby_dp_callback,
    1853             :                               dctx);
    1854           4 :             if (ret != EOK) {
    1855             :                 /* Anything but EOK means we should reenter the mainloop
    1856             :                  * because we may be refreshing the cache
    1857             :                  */
    1858           3 :                 goto done;
    1859             :             }
    1860             :         }
    1861             : 
    1862             :         /* One result found */
    1863           3 :         DEBUG(SSSDBG_TRACE_FUNC,
    1864             :               "Returning info for uid [%"PRIu32"@%s]\n", cmdctx->id, dom->name);
    1865             : 
    1866           3 :         ret = EOK;
    1867           3 :         goto done;
    1868             :     }
    1869             : 
    1870             :     /* All domains were tried and none had the entry. */
    1871           1 :     ret = ENOENT;
    1872             : done:
    1873           7 :     if (ret == ENOENT) {
    1874             :         /* The entry was not found, need to set result in negative cache */
    1875           1 :         err = sss_ncache_set_uid(nctx->rctx->ncache, false, NULL, cmdctx->id);
    1876           1 :         if (err != EOK) {
    1877           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1878             :                 "Cannot set negative cache for UID %"PRIu32"\n", cmdctx->id);
    1879             :         }
    1880           1 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1881             :               "No matching domain found for [%"PRIu32"]\n", cmdctx->id);
    1882             :     }
    1883             : 
    1884           7 :     return ret;
    1885             : }
    1886             : 
    1887             : static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx);
    1888             : static int nss_cmd_getbyid(enum sss_cli_command cmd, struct cli_ctx *cctx);
    1889             : static void nss_cmd_getbyid_done(struct tevent_req *req);
    1890           5 : static int nss_cmd_getpwuid(struct cli_ctx *cctx)
    1891             : {
    1892           5 :     return nss_cmd_getbyid(SSS_NSS_GETPWUID, cctx);
    1893             : }
    1894             : 
    1895           5 : static int nss_cmd_getbyid(enum sss_cli_command cmd, struct cli_ctx *cctx)
    1896             : {
    1897             :     struct nss_cmd_ctx *cmdctx;
    1898             :     struct nss_dom_ctx *dctx;
    1899             :     struct nss_ctx *nctx;
    1900             :     uint8_t *body;
    1901             :     size_t blen;
    1902             :     int ret;
    1903             :     struct tevent_req *req;
    1904             : 
    1905           5 :     switch (cmd) {
    1906             :     case SSS_NSS_GETPWUID:
    1907             :     case SSS_NSS_GETGRGID:
    1908             :     case SSS_NSS_GETSIDBYID:
    1909           5 :         break;
    1910             :     default:
    1911           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command type [%d][%s].\n",
    1912             :               cmd, sss_cmd2str(cmd));
    1913           0 :         return EINVAL;
    1914             :     }
    1915             : 
    1916           5 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    1917             : 
    1918           5 :     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
    1919           5 :     if (!cmdctx) {
    1920           0 :         return ENOMEM;
    1921             :     }
    1922           5 :     cmdctx->cctx = cctx;
    1923           5 :     cmdctx->cmd = cmd;
    1924             : 
    1925           5 :     dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
    1926           5 :     if (!dctx) {
    1927           0 :         ret = ENOMEM;
    1928           0 :         goto done;
    1929             :     }
    1930           5 :     dctx->cmdctx = cmdctx;
    1931             : 
    1932             :     /* get id to query */
    1933           5 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
    1934             : 
    1935           5 :     if (blen != sizeof(uint32_t)) {
    1936           0 :         ret = EINVAL;
    1937           0 :         goto done;
    1938             :     }
    1939           5 :     SAFEALIGN_COPY_UINT32(&cmdctx->id, body, NULL);
    1940             : 
    1941           5 :     DEBUG(SSSDBG_TRACE_FUNC, "Running command [%d][%s] with id [%"PRIu32"].\n",
    1942             :           dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd), cmdctx->id);
    1943             : 
    1944           5 :     switch(dctx->cmdctx->cmd) {
    1945             :     case SSS_NSS_GETPWUID:
    1946           5 :         ret = sss_ncache_check_uid(nctx->rctx->ncache, NULL, cmdctx->id);
    1947           5 :         if (ret == EEXIST) {
    1948           1 :             DEBUG(SSSDBG_TRACE_FUNC,
    1949             :                   "Uid [%"PRIu32"] does not exist! (negative cache)\n",
    1950             :                    cmdctx->id);
    1951           1 :             ret = ENOENT;
    1952           1 :             goto done;
    1953             :         }
    1954           4 :         break;
    1955             :     case SSS_NSS_GETGRGID:
    1956           0 :         ret = sss_ncache_check_gid(nctx->rctx->ncache, NULL, cmdctx->id);
    1957           0 :         if (ret == EEXIST) {
    1958           0 :             DEBUG(SSSDBG_TRACE_FUNC,
    1959             :                   "Gid [%"PRIu32"] does not exist! (negative cache)\n",
    1960             :                    cmdctx->id);
    1961           0 :             ret = ENOENT;
    1962           0 :             goto done;
    1963             :         }
    1964           0 :         break;
    1965             :     case SSS_NSS_GETSIDBYID:
    1966           0 :         ret = sss_ncache_check_uid(nctx->rctx->ncache, NULL, cmdctx->id);
    1967           0 :         if (ret != EEXIST) {
    1968           0 :             ret = sss_ncache_check_gid(nctx->rctx->ncache, NULL, cmdctx->id);
    1969             :         }
    1970           0 :         if (ret == EEXIST) {
    1971           0 :             DEBUG(SSSDBG_TRACE_FUNC,
    1972             :                   "Id [%"PRIu32"] does not exist! (negative cache)\n",
    1973             :                    cmdctx->id);
    1974           0 :             ret = ENOENT;
    1975           0 :             goto done;
    1976             :         }
    1977           0 :         break;
    1978             :     default:
    1979           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    1980             :               dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    1981           0 :         ret = EINVAL;
    1982           0 :         goto done;
    1983             :     }
    1984             : 
    1985             :     /* id searches are always multidomain */
    1986           4 :     dctx->domain = cctx->rctx->domains;
    1987           4 :     cmdctx->check_next = true;
    1988             : 
    1989           4 :     dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
    1990             : 
    1991           4 :     if (cctx->rctx->get_domains_last_call.tv_sec == 0) {
    1992           4 :         req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, false, NULL);
    1993           4 :         if (req == NULL) {
    1994           0 :             ret = ENOMEM;
    1995             :         } else {
    1996           4 :             tevent_req_set_callback(req, nss_cmd_getbyid_done, dctx);
    1997           4 :             ret = EAGAIN;
    1998             :         }
    1999           4 :         goto done;
    2000             :     }
    2001             : 
    2002             :     /* ok, find it ! */
    2003           0 :     switch(dctx->cmdctx->cmd) {
    2004             :     case SSS_NSS_GETPWUID:
    2005           0 :         ret = nss_cmd_getpwuid_search(dctx);
    2006           0 :         if (ret == EOK) {
    2007             :             /* we have results to return */
    2008           0 :             ret = nss_cmd_getpw_send_reply(dctx, true);
    2009             :         }
    2010           0 :         break;
    2011             :     case SSS_NSS_GETGRGID:
    2012           0 :         ret = nss_cmd_getgrgid_search(dctx);
    2013           0 :         if (ret == EOK) {
    2014             :             /* we have results to return */
    2015           0 :             ret = nss_cmd_getgr_send_reply(dctx, true);
    2016             :         }
    2017           0 :         break;
    2018             :     case SSS_NSS_GETSIDBYID:
    2019           0 :         ret = nss_cmd_getsidby_search(dctx);
    2020           0 :         if (ret == EOK) {
    2021           0 :             ret = nss_cmd_getbysid_send_reply(dctx);
    2022             :         }
    2023           0 :         break;
    2024             :     default:
    2025           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    2026             :               dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    2027           0 :         ret = EINVAL;
    2028             :     }
    2029             : 
    2030             : done:
    2031           5 :     return nss_cmd_done(cmdctx, ret);
    2032             : }
    2033             : 
    2034           4 : static void nss_cmd_getbyid_done(struct tevent_req *req)
    2035             : {
    2036           4 :     struct nss_dom_ctx *dctx = tevent_req_callback_data(req, struct nss_dom_ctx);
    2037           4 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    2038             :     errno_t ret;
    2039             : 
    2040           4 :     ret = sss_dp_get_domains_recv(req);
    2041           4 :     talloc_free(req);
    2042           4 :     if (ret != EOK) {
    2043           0 :         goto done;
    2044             :     }
    2045             : 
    2046           4 :     ret = nss_reset_negcache(cmdctx->cctx->rctx);
    2047           4 :     if (ret != EOK) {
    2048           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Cannot reset negcache records\n");
    2049             :         /* Not fatal */
    2050             :     }
    2051             : 
    2052             :     /* ok, find it ! */
    2053           4 :     switch(dctx->cmdctx->cmd) {
    2054             :     case SSS_NSS_GETPWUID:
    2055           4 :         ret = nss_cmd_getpwuid_search(dctx);
    2056           4 :         if (ret == EOK) {
    2057             :             /* we have results to return */
    2058           1 :             ret = nss_cmd_getpw_send_reply(dctx, true);
    2059             :         }
    2060           4 :         break;
    2061             :     case SSS_NSS_GETGRGID:
    2062           0 :         ret = nss_cmd_getgrgid_search(dctx);
    2063           0 :         if (ret == EOK) {
    2064             :             /* we have results to return */
    2065           0 :             ret = nss_cmd_getgr_send_reply(dctx, true);
    2066             :         }
    2067           0 :         break;
    2068             :     case SSS_NSS_GETNAMEBYSID:
    2069             :     case SSS_NSS_GETIDBYSID:
    2070           0 :         ret = responder_get_domain_by_id(cmdctx->cctx->rctx, cmdctx->secid,
    2071             :                                          &dctx->domain);
    2072           0 :         if (ret != EOK) {
    2073           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot find domain for SID [%s].\n",
    2074             :                                       cmdctx->secid);
    2075           0 :             ret = ENOENT;
    2076           0 :             goto done;
    2077             :         }
    2078             : 
    2079           0 :         dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
    2080             : 
    2081           0 :         ret = nss_cmd_getbysid_search(dctx);
    2082           0 :         if (ret == EOK) {
    2083           0 :             ret = nss_cmd_getbysid_send_reply(dctx);
    2084             :         }
    2085           0 :         break;
    2086             :     case SSS_NSS_GETSIDBYID:
    2087           0 :         ret = nss_cmd_getsidby_search(dctx);
    2088           0 :         if (ret == EOK) {
    2089           0 :             ret = nss_cmd_getbysid_send_reply(dctx);
    2090             :         }
    2091           0 :         break;
    2092             :     default:
    2093           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command [%d][%s].\n",
    2094             :               dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd));
    2095           0 :         ret = EINVAL;
    2096             :     }
    2097             : 
    2098             : done:
    2099           4 :     nss_cmd_done(cmdctx, ret);
    2100           4 : }
    2101             : 
    2102             : /* to keep it simple at this stage we are retrieving the
    2103             :  * full enumeration again for each request for each process
    2104             :  * and we also block on setpwent() for the full time needed
    2105             :  * to retrieve the data. And endpwent() frees all the data.
    2106             :  * Next steps are:
    2107             :  * - use an nsssrv wide cache with data already structured
    2108             :  *   so that it can be immediately returned (see nscd way)
    2109             :  * - use mutexes so that setpwent() can return immediately
    2110             :  *   even if the data is still being fetched
    2111             :  * - make getpwent() wait on the mutex
    2112             :  *
    2113             :  * Alternatively:
    2114             :  * - use a smarter search mechanism that keeps track of the
    2115             :  *   last user searched and return the next X users doing
    2116             :  *   an alphabetic sort and starting from the user following
    2117             :  *   the last returned user.
    2118             :  */
    2119             : static int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx);
    2120             : struct tevent_req * nss_cmd_setpwent_send(TALLOC_CTX *mem_ctx,
    2121             :                                           struct cli_ctx *client);
    2122             : static void nss_cmd_setpwent_done(struct tevent_req *req);
    2123           0 : static int nss_cmd_setpwent(struct cli_ctx *cctx)
    2124             : {
    2125             :     struct nss_cmd_ctx *cmdctx;
    2126             :     struct tevent_req *req;
    2127           0 :     errno_t ret = EOK;
    2128             : 
    2129           0 :     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
    2130           0 :     if (!cmdctx) {
    2131           0 :         return ENOMEM;
    2132             :     }
    2133           0 :     cmdctx->cctx = cctx;
    2134             : 
    2135           0 :     req = nss_cmd_setpwent_send(cmdctx, cctx);
    2136           0 :     if (!req) {
    2137           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2138             :               "Fatal error calling nss_cmd_setpwent_send\n");
    2139           0 :         ret = EIO;
    2140           0 :         goto done;
    2141             :     }
    2142           0 :     tevent_req_set_callback(req, nss_cmd_setpwent_done, cmdctx);
    2143             : 
    2144             : done:
    2145           0 :     return nss_cmd_done(cmdctx, ret);
    2146             : }
    2147             : 
    2148             : static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx);
    2149           0 : struct tevent_req *nss_cmd_setpwent_send(TALLOC_CTX *mem_ctx,
    2150             :                                          struct cli_ctx *client)
    2151             : {
    2152             :     errno_t ret;
    2153             :     struct nss_ctx *nctx;
    2154             :     struct tevent_req *req;
    2155             :     struct setent_ctx *state;
    2156             :     struct sss_domain_info *dom;
    2157             :     struct setent_step_ctx *step_ctx;
    2158             : 
    2159           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Received setpwent request\n");
    2160           0 :     nctx = talloc_get_type(client->rctx->pvt_ctx, struct nss_ctx);
    2161             : 
    2162             :     /* Reset the read pointers */
    2163           0 :     client->pwent_dom_idx = 0;
    2164           0 :     client->pwent_cur = 0;
    2165             : 
    2166           0 :     req = tevent_req_create(mem_ctx, &state, struct setent_ctx);
    2167           0 :     if (!req) {
    2168           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2169             :               "Could not create tevent request for setpwent\n");
    2170           0 :         return NULL;
    2171             :     }
    2172             : 
    2173           0 :     state->nctx = nctx;
    2174           0 :     state->client = client;
    2175             : 
    2176           0 :     state->dctx = talloc_zero(state, struct nss_dom_ctx);
    2177           0 :     if (!state->dctx) {
    2178           0 :         ret = ENOMEM;
    2179           0 :         goto error;
    2180             :     }
    2181             : 
    2182             :     /* check if enumeration is enabled in any domain */
    2183           0 :     for (dom = client->rctx->domains; dom;
    2184           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND)) {
    2185           0 :         if (dom->enumerate == true) break;
    2186             :     }
    2187           0 :     state->dctx->domain = dom;
    2188             : 
    2189           0 :     if (state->dctx->domain == NULL) {
    2190           0 :         DEBUG(SSSDBG_OP_FAILURE, "Enumeration disabled on all domains!\n");
    2191           0 :         ret = ENOENT;
    2192           0 :         goto error;
    2193             :     }
    2194             : 
    2195           0 :     state->dctx->check_provider =
    2196           0 :             NEED_CHECK_PROVIDER(state->dctx->domain->provider);
    2197             : 
    2198             :     /* Is the result context already available */
    2199           0 :     if (state->nctx->pctx) {
    2200           0 :         if (state->nctx->pctx->ready) {
    2201             :             /* All of the necessary data is in place
    2202             :              * We can return now, getpwent requests will work at this point
    2203             :              */
    2204           0 :             tevent_req_done(req);
    2205           0 :             tevent_req_post(req, state->nctx->rctx->ev);
    2206             :         }
    2207             :         else {
    2208             :             /* Object is still being constructed
    2209             :              * Register for notification when it's
    2210             :              * ready.
    2211             :              */
    2212           0 :             ret = nss_setent_add_ref(state, state->nctx->pctx, req);
    2213           0 :             if (ret != EOK) {
    2214           0 :                 talloc_free(req);
    2215           0 :                 return NULL;
    2216             :             }
    2217             :         }
    2218           0 :         return req;
    2219             :     }
    2220             : 
    2221             :     /* Create a new result context
    2222             :      * We are creating it on the nss_ctx so that it doesn't
    2223             :      * go away if the original request does. We will delete
    2224             :      * it when the refcount goes to zero;
    2225             :      */
    2226           0 :     state->nctx->pctx = talloc_zero(nctx, struct getent_ctx);
    2227           0 :     if (!state->nctx->pctx) {
    2228           0 :         ret = ENOMEM;
    2229           0 :         goto error;
    2230             :     }
    2231           0 :     state->getent_ctx = nctx->pctx;
    2232             : 
    2233             :     /* Add a callback reference for ourselves */
    2234           0 :     ret = nss_setent_add_ref(state, state->nctx->pctx, req);
    2235           0 :     if (ret) goto error;
    2236             : 
    2237             :     /* ok, start the searches */
    2238           0 :     step_ctx = talloc_zero(state->getent_ctx, struct setent_step_ctx);
    2239           0 :     if (!step_ctx) {
    2240           0 :         ret = ENOMEM;
    2241           0 :         goto error;
    2242             :     }
    2243             : 
    2244             :     /* Steal the dom_ctx onto the step_ctx so it doesn't go out of scope if
    2245             :      * this request is canceled while other requests are in-progress.
    2246             :      */
    2247           0 :     step_ctx->dctx = talloc_steal(step_ctx, state->dctx);
    2248           0 :     step_ctx->nctx = state->nctx;
    2249           0 :     step_ctx->getent_ctx = state->getent_ctx;
    2250           0 :     step_ctx->rctx = client->rctx;
    2251           0 :     step_ctx->cctx = client;
    2252           0 :     step_ctx->returned_to_mainloop = false;
    2253             : 
    2254           0 :     ret = nss_cmd_setpwent_step(step_ctx);
    2255           0 :     if (ret != EOK && ret != EAGAIN) goto error;
    2256             : 
    2257           0 :     if (ret == EOK) {
    2258           0 :         tevent_req_post(req, client->rctx->ev);
    2259             :     }
    2260             : 
    2261           0 :     return req;
    2262             : 
    2263             :  error:
    2264           0 :      tevent_req_error(req, ret);
    2265           0 :      tevent_req_post(req, client->rctx->ev);
    2266           0 :      return req;
    2267             : }
    2268             : 
    2269             : static void nss_cmd_setpwent_dp_callback(uint16_t err_maj, uint32_t err_min,
    2270             :                                          const char *err_msg, void *ptr);
    2271             : static void setpwent_result_timeout(struct tevent_context *ev,
    2272             :                                     struct tevent_timer *te,
    2273             :                                     struct timeval current_time,
    2274             :                                     void *pvt);
    2275             : 
    2276             : /* nss_cmd_setpwent_step returns
    2277             :  *   EOK if everything is done and the request needs to be posted explicitly
    2278             :  *   EAGAIN if the caller can safely return to the main loop
    2279             :  */
    2280           0 : static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
    2281             : {
    2282             :     errno_t ret;
    2283           0 :     struct sss_domain_info *dom = step_ctx->dctx->domain;
    2284           0 :     struct resp_ctx *rctx = step_ctx->rctx;
    2285           0 :     struct nss_dom_ctx *dctx = step_ctx->dctx;
    2286           0 :     struct getent_ctx *pctx = step_ctx->getent_ctx;
    2287           0 :     struct nss_ctx *nctx = step_ctx->nctx;
    2288             :     struct ldb_result *res;
    2289             :     struct timeval tv;
    2290             :     struct tevent_timer *te;
    2291             :     struct tevent_req *dpreq;
    2292             :     struct dp_callback_ctx *cb_ctx;
    2293             : 
    2294           0 :     while (dom) {
    2295           0 :         while (dom && dom->enumerate == false) {
    2296           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND);
    2297             :         }
    2298             : 
    2299           0 :         if (!dom) break;
    2300             : 
    2301           0 :         if (dom != dctx->domain) {
    2302             :             /* make sure we reset the check_provider flag when we check
    2303             :              * a new domain */
    2304           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    2305             :         }
    2306             : 
    2307             :         /* make sure to update the dctx if we changed domain */
    2308           0 :         dctx->domain = dom;
    2309             : 
    2310           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    2311             :               "Requesting info for domain [%s]\n", dom->name);
    2312             : 
    2313           0 :         if (dom->sysdb == NULL) {
    2314           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2315             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    2316           0 :             return EIO;
    2317             :         }
    2318             : 
    2319             :         /* if this is a caching provider (or if we haven't checked the cache
    2320             :          * yet) then verify that the cache is uptodate */
    2321           0 :         if (dctx->check_provider) {
    2322           0 :             step_ctx->returned_to_mainloop = true;
    2323             :             /* Only do this once per provider */
    2324           0 :             dctx->check_provider = false;
    2325             : 
    2326           0 :             dpreq = sss_dp_get_account_send(step_ctx, rctx, dctx->domain, true,
    2327             :                                           SSS_DP_USER, NULL, 0, NULL);
    2328           0 :             if (!dpreq) {
    2329           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    2330             :                       "Enum Cache refresh for domain [%s] failed."
    2331             :                        " Trying to return what we have in cache!\n",
    2332             :                        dom->name);
    2333             :             } else {
    2334           0 :                 cb_ctx = talloc_zero(step_ctx, struct dp_callback_ctx);
    2335           0 :                 if(!cb_ctx) {
    2336           0 :                     talloc_zfree(dpreq);
    2337           0 :                     return ENOMEM;
    2338             :                 }
    2339             : 
    2340           0 :                 cb_ctx->callback = nss_cmd_setpwent_dp_callback;
    2341           0 :                 cb_ctx->ptr = step_ctx;
    2342           0 :                 cb_ctx->cctx = step_ctx->cctx;
    2343           0 :                 cb_ctx->mem_ctx = step_ctx;
    2344             : 
    2345           0 :                 tevent_req_set_callback(dpreq, nsssrv_dp_send_acct_req_done, cb_ctx);
    2346             : 
    2347           0 :                 return EAGAIN;
    2348             :             }
    2349             :         }
    2350             : 
    2351           0 :         ret = sysdb_enumpwent_with_views(dctx, dom, &res);
    2352           0 :         if (ret != EOK) {
    2353           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2354             :                   "Enum from cache failed, skipping domain [%s]\n",
    2355             :                       dom->name);
    2356           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND);
    2357           0 :             continue;
    2358             :         }
    2359             : 
    2360           0 :         if (res->count == 0) {
    2361           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    2362             :                   "Domain [%s] has no users, skipping.\n", dom->name);
    2363           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND);
    2364           0 :             continue;
    2365             :         }
    2366             : 
    2367           0 :         nctx->pctx->doms = talloc_realloc(pctx, pctx->doms,
    2368             :                                     struct dom_ctx, pctx->num +1);
    2369           0 :         if (!pctx->doms) {
    2370           0 :             talloc_free(pctx);
    2371           0 :             nctx->pctx = NULL;
    2372           0 :             return ENOMEM;
    2373             :         }
    2374             : 
    2375           0 :         nctx->pctx->doms[pctx->num].domain = dctx->domain;
    2376           0 :         nctx->pctx->doms[pctx->num].res = talloc_steal(pctx->doms, res);
    2377             : 
    2378           0 :         nctx->pctx->num++;
    2379             : 
    2380             :         /* do not reply until all domain searches are done */
    2381           0 :         dom = get_next_domain(dom, SSS_GND_DESCEND);
    2382             :     }
    2383             : 
    2384             :     /* We've finished all our lookups
    2385             :      * The result object is now safe to read.
    2386             :      */
    2387           0 :     nctx->pctx->ready = true;
    2388             : 
    2389             :     /* Set up a lifetime timer for this result object
    2390             :      * We don't want this result object to outlive the
    2391             :      * enum cache refresh timeout
    2392             :      */
    2393           0 :     tv = tevent_timeval_current_ofs(nctx->enum_cache_timeout, 0);
    2394           0 :     te = tevent_add_timer(rctx->ev, nctx->pctx, tv,
    2395             :                           setpwent_result_timeout, nctx);
    2396           0 :     if (!te) {
    2397           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2398             :               "Could not set up life timer for setpwent result object. "
    2399             :                   "Entries may become stale.\n");
    2400             :     }
    2401             : 
    2402             :     /* Notify the waiting clients */
    2403           0 :     nss_setent_notify_done(nctx->pctx);
    2404             : 
    2405           0 :     if (step_ctx->returned_to_mainloop) {
    2406           0 :         return EAGAIN;
    2407             :     } else {
    2408           0 :         return EOK;
    2409             :     }
    2410             : }
    2411             : 
    2412           0 : static void setpwent_result_timeout(struct tevent_context *ev,
    2413             :                                     struct tevent_timer *te,
    2414             :                                     struct timeval current_time,
    2415             :                                     void *pvt)
    2416             : {
    2417           0 :     struct nss_ctx *nctx = talloc_get_type(pvt, struct nss_ctx);
    2418             : 
    2419           0 :     DEBUG(SSSDBG_CRIT_FAILURE,
    2420             :           "setpwent result object has expired. Cleaning up.\n");
    2421             : 
    2422             :     /* Free the passwd enumeration context.
    2423             :      * If additional getpwent requests come in, they will invoke
    2424             :      * an implicit setpwent and refresh the result object.
    2425             :      */
    2426           0 :     talloc_zfree(nctx->pctx);
    2427           0 : }
    2428             : 
    2429           0 : static void nss_cmd_setpwent_dp_callback(uint16_t err_maj, uint32_t err_min,
    2430             :                                          const char *err_msg, void *ptr)
    2431             : {
    2432           0 :     struct setent_step_ctx *step_ctx =
    2433             :             talloc_get_type(ptr, struct setent_step_ctx);
    2434             :     int ret;
    2435             : 
    2436           0 :     if (err_maj) {
    2437           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2438             :               "Unable to get information from Data Provider\n"
    2439             :                   "Error: %u, %u, %s\n"
    2440             :                   "Will try to return what we have in cache\n",
    2441             :                   (unsigned int)err_maj, (unsigned int)err_min, err_msg);
    2442             :     }
    2443             : 
    2444           0 :     ret = nss_cmd_setpwent_step(step_ctx);
    2445           0 :     if (ret != EOK && ret != EAGAIN) {
    2446             :         /* Notify any waiting processes of failure */
    2447           0 :         nss_setent_notify_error(step_ctx->nctx->pctx, ret);
    2448             :     }
    2449           0 : }
    2450             : 
    2451           0 : static errno_t nss_cmd_setpwent_recv(struct tevent_req *req)
    2452             : {
    2453           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    2454           0 :     return EOK;
    2455             : }
    2456             : 
    2457           0 : static void nss_cmd_setpwent_done(struct tevent_req *req)
    2458             : {
    2459             :     errno_t ret;
    2460           0 :     struct nss_cmd_ctx *cmdctx =
    2461           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
    2462             : 
    2463           0 :     ret = nss_cmd_setpwent_recv(req);
    2464           0 :     talloc_zfree(req);
    2465           0 :     if (ret == EOK || ret == ENOENT) {
    2466             :         /* Either we succeeded or no domains were eligible */
    2467           0 :         ret = sss_packet_new(cmdctx->cctx->creq, 0,
    2468           0 :                              sss_packet_get_cmd(cmdctx->cctx->creq->in),
    2469           0 :                              &cmdctx->cctx->creq->out);
    2470           0 :         if (ret == EOK) {
    2471           0 :             sss_cmd_done(cmdctx->cctx, cmdctx);
    2472           0 :             return;
    2473             :         }
    2474             :     }
    2475             : 
    2476             :     /* Something bad happened */
    2477           0 :     nss_cmd_done(cmdctx, ret);
    2478             : }
    2479             : 
    2480             : static void nss_cmd_implicit_setpwent_done(struct tevent_req *req);
    2481           0 : static int nss_cmd_getpwent(struct cli_ctx *cctx)
    2482             : {
    2483             :     struct nss_ctx *nctx;
    2484             :     struct nss_cmd_ctx *cmdctx;
    2485             :     struct tevent_req *req;
    2486             : 
    2487           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Requesting info for all accounts\n");
    2488             : 
    2489           0 :     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
    2490           0 :     if (!cmdctx) {
    2491           0 :         return ENOMEM;
    2492             :     }
    2493           0 :     cmdctx->cctx = cctx;
    2494             : 
    2495             :     /* Save the current index and cursor locations
    2496             :      * If we end up calling setpwent implicitly, because the response object
    2497             :      * expired and has to be recreated, we want to resume from the same
    2498             :      * location.
    2499             :      */
    2500           0 :     cmdctx->saved_dom_idx = cctx->pwent_dom_idx;
    2501           0 :     cmdctx->saved_cur = cctx->pwent_cur;
    2502             : 
    2503           0 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    2504           0 :     if(!nctx->pctx || !nctx->pctx->ready) {
    2505             :         /* Make sure we invoke setpwent if it hasn't been run or is still
    2506             :          * processing from another client
    2507             :          */
    2508           0 :         req = nss_cmd_setpwent_send(cctx, cctx);
    2509           0 :         if (!req) {
    2510           0 :             return EIO;
    2511             :         }
    2512           0 :         tevent_req_set_callback(req, nss_cmd_implicit_setpwent_done, cmdctx);
    2513           0 :         return EOK;
    2514             :     }
    2515             : 
    2516           0 :     return nss_cmd_getpwent_immediate(cmdctx);
    2517             : }
    2518             : 
    2519             : static int nss_cmd_retpwent(struct cli_ctx *cctx, int num);
    2520           0 : static int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx)
    2521             : {
    2522           0 :     struct cli_ctx *cctx = cmdctx->cctx;
    2523             :     uint8_t *body;
    2524             :     size_t blen;
    2525             :     uint32_t num;
    2526             :     int ret;
    2527             : 
    2528             :     /* get max num of entries to return in one call */
    2529           0 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
    2530           0 :     if (blen != sizeof(uint32_t)) {
    2531           0 :         return EINVAL;
    2532             :     }
    2533           0 :     SAFEALIGN_COPY_UINT32(&num, body, NULL);
    2534             : 
    2535             :     /* create response packet */
    2536           0 :     ret = sss_packet_new(cctx->creq, 0,
    2537           0 :                          sss_packet_get_cmd(cctx->creq->in),
    2538           0 :                          &cctx->creq->out);
    2539           0 :     if (ret != EOK) {
    2540           0 :         return ret;
    2541             :     }
    2542             : 
    2543           0 :     ret = nss_cmd_retpwent(cctx, num);
    2544             : 
    2545           0 :     sss_packet_set_error(cctx->creq->out, ret);
    2546           0 :     sss_cmd_done(cctx, cmdctx);
    2547             : 
    2548           0 :     return EOK;
    2549             : }
    2550             : 
    2551           0 : static int nss_cmd_retpwent(struct cli_ctx *cctx, int num)
    2552             : {
    2553             :     struct nss_ctx *nctx;
    2554             :     struct getent_ctx *pctx;
    2555           0 :     struct ldb_message **msgs = NULL;
    2556           0 :     struct dom_ctx *pdom = NULL;
    2557           0 :     int n = 0;
    2558           0 :     int ret = ENOENT;
    2559             : 
    2560           0 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    2561           0 :     if (!nctx->pctx) goto none;
    2562             : 
    2563           0 :     pctx = nctx->pctx;
    2564             : 
    2565           0 :     while (ret == ENOENT) {
    2566           0 :         if (cctx->pwent_dom_idx >= pctx->num) break;
    2567             : 
    2568           0 :         pdom = &pctx->doms[cctx->pwent_dom_idx];
    2569             : 
    2570           0 :         n = pdom->res->count - cctx->pwent_cur;
    2571           0 :         if (n <= 0 && (cctx->pwent_dom_idx+1 < pctx->num)) {
    2572           0 :             cctx->pwent_dom_idx++;
    2573           0 :             pdom = &pctx->doms[cctx->pwent_dom_idx];
    2574           0 :             n = pdom->res->count;
    2575           0 :             cctx->pwent_cur = 0;
    2576             :         }
    2577             : 
    2578           0 :         if (!n) break;
    2579             : 
    2580           0 :         if (n < 0) {
    2581           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Negative difference"
    2582             :                   "[%d - %d = %d]\n", pdom->res->count, cctx->pwent_cur, n);
    2583           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Domain: %d (total %d)\n",
    2584             :                                         cctx->pwent_dom_idx, pctx->num);
    2585           0 :             break;
    2586             :         }
    2587             : 
    2588           0 :         if (n > num) n = num;
    2589             : 
    2590           0 :         msgs = &(pdom->res->msgs[cctx->pwent_cur]);
    2591             : 
    2592           0 :         ret = fill_pwent(cctx->creq->out, pdom->domain, nctx,
    2593             :                          true, false, msgs, &n);
    2594             : 
    2595           0 :         cctx->pwent_cur += n;
    2596             :     }
    2597             : 
    2598             : none:
    2599           0 :     if (ret == ENOENT) {
    2600           0 :         ret = sss_cmd_empty_packet(cctx->creq->out);
    2601             :     }
    2602           0 :     return ret;
    2603             : }
    2604             : 
    2605           0 : static void nss_cmd_implicit_setpwent_done(struct tevent_req *req)
    2606             : {
    2607             :     errno_t ret;
    2608           0 :     struct nss_cmd_ctx *cmdctx =
    2609           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
    2610             : 
    2611           0 :     ret = nss_cmd_setpwent_recv(req);
    2612           0 :     talloc_zfree(req);
    2613             : 
    2614             :     /* ENOENT is acceptable, as it just means that there were no entries
    2615             :      * to be returned. This will be handled gracefully in nss_cmd_retpwent
    2616             :      * later.
    2617             :      */
    2618           0 :     if (ret != EOK && ret != ENOENT) {
    2619           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2620             :               "Implicit setpwent failed with unexpected error [%d][%s]\n",
    2621             :                   ret, strerror(ret));
    2622           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
    2623             :     }
    2624             : 
    2625             :     /* Restore the saved index and cursor locations */
    2626           0 :     cmdctx->cctx->pwent_dom_idx = cmdctx->saved_dom_idx;
    2627           0 :     cmdctx->cctx->pwent_cur = cmdctx->saved_cur;
    2628             : 
    2629           0 :     ret = nss_cmd_getpwent_immediate(cmdctx);
    2630           0 :     if (ret != EOK) {
    2631           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2632             :               "Immediate retrieval failed with unexpected error "
    2633             :                   "[%d][%s]\n", ret, strerror(ret));
    2634           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
    2635             :     }
    2636             : }
    2637             : 
    2638           0 : static int nss_cmd_endpwent(struct cli_ctx *cctx)
    2639             : {
    2640             :     struct nss_ctx *nctx;
    2641             :     int ret;
    2642             : 
    2643           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Terminating request info for all accounts\n");
    2644             : 
    2645           0 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    2646             : 
    2647             :     /* create response packet */
    2648           0 :     ret = sss_packet_new(cctx->creq, 0,
    2649           0 :                          sss_packet_get_cmd(cctx->creq->in),
    2650           0 :                          &cctx->creq->out);
    2651             : 
    2652           0 :     if (ret != EOK) {
    2653           0 :         return ret;
    2654             :     }
    2655           0 :     if (nctx->pctx == NULL) goto done;
    2656             : 
    2657             :     /* Reset the indices so that subsequent requests start at zero */
    2658           0 :     cctx->pwent_dom_idx = 0;
    2659           0 :     cctx->pwent_cur = 0;
    2660             : 
    2661             : done:
    2662           0 :     sss_cmd_done(cctx, NULL);
    2663           0 :     return EOK;
    2664             : }
    2665             : 
    2666             : /****************************************************************************
    2667             :  * GROUP db related functions
    2668             :  ***************************************************************************/
    2669             : 
    2670           0 : void nss_update_gr_memcache(struct nss_ctx *nctx)
    2671             : {
    2672             :     struct sss_domain_info *dom;
    2673             :     struct ldb_result *res;
    2674             :     uint64_t exp;
    2675             :     struct sized_string key;
    2676             :     const char *id;
    2677             :     time_t now;
    2678             :     int ret;
    2679             :     int i;
    2680             : 
    2681           0 :     now = time(NULL);
    2682             : 
    2683           0 :     for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, 0)) {
    2684           0 :         ret = sysdb_enumgrent_with_views(nctx, dom, &res);
    2685           0 :         if (ret != EOK) {
    2686           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2687             :                   "Failed to enumerate users for domain [%s]\n", dom->name);
    2688           0 :             continue;
    2689             :         }
    2690             : 
    2691           0 :         for (i = 0; i < res->count; i++) {
    2692           0 :             exp = ldb_msg_find_attr_as_uint64(res->msgs[i],
    2693             :                                               SYSDB_CACHE_EXPIRE, 0);
    2694           0 :             if (exp >= now) {
    2695           0 :                 continue;
    2696             :             }
    2697             : 
    2698             :             /* names require more manipulation (build up fqname conditionally),
    2699             :              * but uidNumber is unique and always resolvable too, so we use
    2700             :              * that to update the cache, as it points to the same entry */
    2701           0 :             id = sss_view_ldb_msg_find_attr_as_string(dom, res->msgs[i],
    2702             :                                                       SYSDB_GIDNUM, NULL);
    2703           0 :             if (!id) {
    2704           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    2705             :                       "Failed to find gidNumber in %s.\n",
    2706             :                        ldb_dn_get_linearized(res->msgs[i]->dn));
    2707           0 :                 continue;
    2708             :             }
    2709           0 :             to_sized_string(&key, id);
    2710             : 
    2711           0 :             ret = sss_mmap_cache_gr_invalidate(nctx->grp_mc_ctx, &key);
    2712           0 :             if (ret != EOK && ret != ENOENT) {
    2713           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    2714             :                       "Internal failure in memory cache code: %d [%s]\n",
    2715             :                        ret, strerror(ret));
    2716             :             }
    2717             :         }
    2718           0 :         talloc_zfree(res);
    2719             :     }
    2720           0 : }
    2721             : 
    2722             : #define GID_ROFFSET 0
    2723             : #define MNUM_ROFFSET sizeof(uint32_t)
    2724             : #define STRS_ROFFSET 2*sizeof(uint32_t)
    2725             : 
    2726          15 : static int parse_member(TALLOC_CTX *mem_ctx, struct sss_domain_info *group_dom,
    2727             :                         const char *member, struct sss_domain_info **_member_dom,
    2728             :                         struct sized_string *_name, bool *_add_domain)
    2729             : {
    2730             :     errno_t ret;
    2731             :     char *username;
    2732             :     char *domname;
    2733             :     const char *use_member;
    2734             :     struct sss_domain_info *member_dom;
    2735             :     bool add_domain;
    2736             : 
    2737          15 :     ret = sss_parse_name(mem_ctx, group_dom->names, member, &domname, &username);
    2738          15 :     if (ret != EOK) {
    2739           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Could not parse [%s] into "
    2740             :               "name-value components.\n", member);
    2741           0 :         return ret;
    2742             :     }
    2743             : 
    2744          15 :     add_domain = (!IS_SUBDOMAIN(group_dom) && group_dom->fqnames);
    2745          15 :     use_member = member;
    2746          15 :     member_dom = group_dom;
    2747             : 
    2748          15 :     if (IS_SUBDOMAIN(group_dom) == false && domname != NULL) {
    2749             :         /* The group is stored in the parent domain, but the member comes from.
    2750             :          * a subdomain. No need to add the domain component, it's already
    2751             :          * present in the memberuid/ghost attribute
    2752             :          */
    2753           2 :         add_domain = false;
    2754             :     }
    2755             : 
    2756          15 :     if (IS_SUBDOMAIN(group_dom) == true && domname == NULL) {
    2757             :         /* The group is stored in a subdomain, but the member comes
    2758             :          * from the parent domain. Need to add the domain component
    2759             :          * of the parent domain
    2760             :          */
    2761           1 :         add_domain = true;
    2762           1 :         use_member = username;
    2763           1 :         member_dom = group_dom->parent;
    2764             :     }
    2765             : 
    2766          15 :     to_sized_string(_name, use_member);
    2767          15 :     *_add_domain = add_domain;
    2768          15 :     *_member_dom = member_dom;
    2769          15 :     return EOK;
    2770             : }
    2771             : 
    2772           6 : static int fill_members(struct sss_packet *packet,
    2773             :                         struct sss_domain_info *dom,
    2774             :                         struct nss_ctx *nctx,
    2775             :                         struct ldb_message_element *el,
    2776             :                         size_t *_rzero,
    2777             :                         size_t *_rsize,
    2778             :                         int *_memnum)
    2779             : {
    2780           6 :     int i, ret = EOK;
    2781           6 :     int memnum = *_memnum;
    2782           6 :     size_t rzero= *_rzero;
    2783           6 :     size_t rsize = *_rsize;
    2784             :     const char *tmpstr;
    2785             :     struct sized_string name;
    2786           6 :     TALLOC_CTX *tmp_ctx = NULL;
    2787             : 
    2788           6 :     int nlen = 0;
    2789             : 
    2790             :     uint8_t *body;
    2791             :     size_t blen;
    2792             : 
    2793           6 :     const char *domain = dom->name;
    2794             :     bool add_domain;
    2795             :     struct sss_domain_info *member_dom;
    2796             : 
    2797           6 :     tmp_ctx = talloc_new(NULL);
    2798           6 :     if (tmp_ctx == NULL) {
    2799           0 :         return ENOMEM;
    2800             :     }
    2801             : 
    2802           6 :     sss_packet_get_body(packet, &body, &blen);
    2803          21 :     for (i = 0; i < el->num_values; i++) {
    2804          15 :         tmpstr = sss_get_cased_name(tmp_ctx, (char *)el->values[i].data,
    2805          15 :                                     dom->case_preserve);
    2806          15 :         if (tmpstr == NULL) {
    2807           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2808             :                   "sss_get_cased_name failed, skipping\n");
    2809           0 :             continue;
    2810             :         }
    2811             : 
    2812          15 :         tmpstr = sss_replace_space(tmp_ctx, tmpstr,
    2813          15 :                                    nctx->rctx->override_space);
    2814          15 :         if (tmpstr == NULL) {
    2815           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2816             :                   "sss_replace_space failed\n");
    2817           0 :             ret = ENOMEM;
    2818           0 :             goto done;
    2819             :         }
    2820             : 
    2821          15 :         if (nctx->filter_users_in_groups) {
    2822           0 :             ret = sss_ncache_check_user(nctx->rctx->ncache, dom, tmpstr);
    2823           0 :             if (ret == EEXIST) {
    2824           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
    2825             :                       "Group [%s] member [%s@%s] filtered out!"
    2826             :                        " (negative cache)\n",
    2827             :                        (char *)&body[rzero+STRS_ROFFSET], tmpstr, domain);
    2828           0 :                 continue;
    2829             :             }
    2830             :         }
    2831             : 
    2832          15 :         ret = parse_member(tmp_ctx, dom, tmpstr, &member_dom, &name, &add_domain);
    2833          15 :         if (ret != EOK) {
    2834           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    2835             :                   "Could not process member %s, skipping\n", tmpstr);
    2836           0 :             continue;
    2837             :         }
    2838             : 
    2839          15 :         if (add_domain) {
    2840           5 :             nlen = sss_fqname(NULL, 0, member_dom->names, member_dom,
    2841             :                               name.str);
    2842           5 :             if (nlen >= 0) {
    2843           5 :                 nlen += 1;
    2844             :             } else {
    2845             :                 /* Other failures caught below */
    2846           0 :                 nlen = 0;
    2847             :             }
    2848             :         } else {
    2849          10 :             nlen = name.len;
    2850             :         }
    2851             : 
    2852          15 :         ret = sss_packet_grow(packet, nlen);
    2853          15 :         if (ret != EOK) {
    2854           0 :             goto done;
    2855             :         }
    2856          15 :         sss_packet_get_body(packet, &body, &blen);
    2857             : 
    2858          15 :         if (add_domain) {
    2859          10 :             ret = sss_fqname((char *)&body[rzero + rsize], nlen,
    2860           5 :                              member_dom->names, member_dom, name.str);
    2861           5 :             if (ret < 0 || ret != nlen - 1) {
    2862           0 :                 DEBUG(SSSDBG_OP_FAILURE, "Failed to generate a fully qualified name"
    2863             :                                           " for member [%s@%s] of group [%s]!"
    2864             :                                           " Skipping\n", name.str, domain,
    2865             :                                           (char *)&body[rzero+STRS_ROFFSET]);
    2866             :                 /* reclaim space */
    2867           0 :                 ret = sss_packet_shrink(packet, nlen);
    2868           0 :                 if (ret != EOK) {
    2869           0 :                     goto done;
    2870             :                 }
    2871           0 :                 continue;
    2872             :             }
    2873             : 
    2874             :         } else {
    2875          10 :             memcpy(&body[rzero + rsize], name.str, name.len);
    2876             :         }
    2877             : 
    2878          15 :         rsize += nlen;
    2879          15 :         memnum++;
    2880             :     }
    2881             : 
    2882           6 :     ret = 0;
    2883             : 
    2884             : done:
    2885           6 :     *_memnum = memnum;
    2886           6 :     *_rzero = rzero;
    2887           6 :     *_rsize = rsize;
    2888           6 :     talloc_zfree(tmp_ctx);
    2889           6 :     return ret;
    2890             : }
    2891             : 
    2892           9 : static int fill_grent(struct sss_packet *packet,
    2893             :                       struct sss_domain_info *dom,
    2894             :                       struct nss_ctx *nctx,
    2895             :                       bool filter_groups, bool gr_mmap_cache,
    2896             :                       struct ldb_message **msgs,
    2897             :                       int *count)
    2898             : {
    2899             :     struct ldb_message *msg;
    2900             :     struct ldb_message_element *el;
    2901             :     uint8_t *body;
    2902             :     size_t blen;
    2903             :     uint32_t gid;
    2904             :     const char *tmpstr;
    2905           9 :     const char *orig_name = NULL;
    2906             :     struct sized_string name;
    2907             :     struct sized_string pwfield;
    2908             :     struct sized_string fullname;
    2909           9 :     int fq_len = 0;
    2910           9 :     int i = 0;
    2911             :     int ret, num, memnum;
    2912             :     size_t rzero, rsize;
    2913           9 :     bool add_domain = (!IS_SUBDOMAIN(dom) && dom->fqnames);
    2914           9 :     const char *domain = dom->name;
    2915           9 :     TALLOC_CTX *tmp_ctx = NULL;
    2916             : 
    2917           9 :     to_sized_string(&pwfield, nctx->pwfield);
    2918             : 
    2919           9 :     num = 0;
    2920             : 
    2921             :     /* first 2 fields (len and reserved), filled up later */
    2922           9 :     ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
    2923           9 :     if (ret != EOK) {
    2924           0 :         goto done;
    2925             :     }
    2926           9 :     sss_packet_get_body(packet, &body, &blen);
    2927           9 :     rzero = 2*sizeof(uint32_t);
    2928           9 :     rsize = 0;
    2929             : 
    2930          18 :     for (i = 0; i < *count; i++) {
    2931           9 :         talloc_zfree(tmp_ctx);
    2932           9 :         tmp_ctx = talloc_new(NULL);
    2933           9 :         msg = msgs[i];
    2934             : 
    2935             :         /* new group */
    2936           9 :         if (!ldb_msg_check_string_attribute(msg, "objectClass",
    2937             :                                             SYSDB_GROUP_CLASS)) {
    2938           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Wrong object (%s) found on stack!\n",
    2939             :                       ldb_dn_get_linearized(msg->dn));
    2940           0 :             continue;
    2941             :         }
    2942             : 
    2943             :         /* new result starts at end of previous result */
    2944           9 :         rzero += rsize;
    2945           9 :         rsize = 0;
    2946             : 
    2947             :         /* find group name/gid */
    2948             : 
    2949             :         /* start with an empty name for each iteration */
    2950           9 :         orig_name = NULL;
    2951           9 :         if (DOM_HAS_VIEWS(dom)) {
    2952           0 :             orig_name = ldb_msg_find_attr_as_string(msg,
    2953             :                                                     OVERRIDE_PREFIX SYSDB_NAME,
    2954             :                                                     NULL);
    2955           0 :             if (orig_name != NULL && IS_SUBDOMAIN(dom)) {
    2956             :                 /* Override names are not fully qualified */
    2957           0 :                 add_domain = true;
    2958             :             }
    2959             :         }
    2960           9 :         if (orig_name == NULL) {
    2961           9 :             orig_name = ldb_msg_find_attr_as_string(msg,
    2962             :                                                     SYSDB_DEFAULT_OVERRIDE_NAME,
    2963             :                                                     NULL);
    2964           9 :             if (orig_name == NULL) {
    2965           9 :                 orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
    2966             :             }
    2967             :         }
    2968             : 
    2969           9 :         gid = sss_view_ldb_msg_find_attr_as_uint64(dom, msg, SYSDB_GIDNUM, 0);
    2970           9 :         if (!orig_name || !gid) {
    2971           0 :             DEBUG(SSSDBG_OP_FAILURE,
    2972             :                   "Incomplete group object for %s[%llu]! Skipping\n",
    2973             :                       orig_name?orig_name:"<NULL>", (unsigned long long int)gid);
    2974           0 :             continue;
    2975             :         }
    2976             : 
    2977           9 :         if (filter_groups) {
    2978           0 :             ret = sss_ncache_check_group(nctx->rctx->ncache, dom, orig_name);
    2979           0 :             if (ret == EEXIST) {
    2980           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
    2981             :                       "Group [%s@%s] filtered out! (negative cache)\n",
    2982             :                        orig_name, domain);
    2983           0 :                 continue;
    2984             :             }
    2985             :         }
    2986             : 
    2987           9 :         tmpstr = sss_get_cased_name(tmp_ctx, orig_name, dom->case_preserve);
    2988           9 :         if (tmpstr == NULL) {
    2989           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2990             :                   "sss_get_cased_name failed, skipping\n");
    2991           0 :             continue;
    2992             :         }
    2993             : 
    2994           9 :         tmpstr = sss_replace_space(tmp_ctx, tmpstr,
    2995           9 :                                    nctx->rctx->override_space);
    2996           9 :         if (tmpstr == NULL) {
    2997           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2998             :                   "sss_replace_space failed, skipping\n");
    2999           0 :             continue;
    3000             :         }
    3001             : 
    3002           9 :         to_sized_string(&name, tmpstr);
    3003             : 
    3004             :         /* fill in gid and name and set pointer for number of members */
    3005           9 :         rsize = STRS_ROFFSET + name.len + pwfield.len; /* name\0x\0 */
    3006             : 
    3007           9 :         if (add_domain) {
    3008           2 :             fq_len = sss_fqname(NULL, 0, dom->names, dom, name.str);
    3009           2 :             if (fq_len >= 0) {
    3010           2 :                 fq_len += 1;
    3011           2 :                 rsize -= name.len;
    3012           2 :                 rsize += fq_len;
    3013             :             } else {
    3014             :                 /* Other failures caught below */
    3015           0 :                 fq_len = 0;
    3016             :             }
    3017             :         }
    3018             : 
    3019           9 :         ret = sss_packet_grow(packet, rsize);
    3020           9 :         if (ret != EOK) {
    3021           0 :             num = 0;
    3022           0 :             goto done;
    3023             :         }
    3024           9 :         sss_packet_get_body(packet, &body, &blen);
    3025             : 
    3026             :         /*  0-3: 32bit number gid */
    3027           9 :         SAFEALIGN_SET_UINT32(&body[rzero+GID_ROFFSET], gid, NULL);
    3028             : 
    3029             :         /*  4-7: 32bit unsigned number of members */
    3030           9 :         SAFEALIGN_SET_UINT32(&body[rzero+MNUM_ROFFSET], 0, NULL);
    3031             : 
    3032             :         /*  8-X: sequence of strings (name, passwd, mem..) */
    3033           9 :         if (add_domain) {
    3034           2 :             ret = sss_fqname((char *)&body[rzero+STRS_ROFFSET], fq_len,
    3035             :                              dom->names, dom, name.str);
    3036           2 :             if (ret < 0 || ret != fq_len - 1) {
    3037           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    3038             :                       "Failed to generate a fully qualified name for"
    3039             :                           " group [%s] in [%s]! Skipping\n", name.str, domain);
    3040             :                 /* reclaim space */
    3041           0 :                 ret = sss_packet_shrink(packet, rsize);
    3042           0 :                 if (ret != EOK) {
    3043           0 :                     num = 0;
    3044           0 :                     goto done;
    3045             :                 }
    3046           0 :                 rsize = 0;
    3047           0 :                 continue;
    3048             :             }
    3049             :         } else {
    3050           7 :             memcpy(&body[rzero+STRS_ROFFSET], name.str, name.len);
    3051             :         }
    3052           9 :         to_sized_string(&fullname, (const char *)&body[rzero+STRS_ROFFSET]);
    3053             : 
    3054             :         /* group passwd field */
    3055          18 :         memcpy(&body[rzero+STRS_ROFFSET + fullname.len],
    3056           9 :                                             pwfield.str, pwfield.len);
    3057             : 
    3058           9 :         memnum = 0;
    3059           9 :         if (!dom->ignore_group_members) {
    3060           9 :             el = sss_view_ldb_msg_find_element(dom, msg, SYSDB_MEMBERUID);
    3061           9 :             if (el) {
    3062           6 :                 ret = fill_members(packet, dom, nctx, el, &rzero, &rsize,
    3063             :                                    &memnum);
    3064           6 :                 if (ret != EOK) {
    3065           0 :                     num = 0;
    3066           0 :                     goto done;
    3067             :                 }
    3068           6 :                 sss_packet_get_body(packet, &body, &blen);
    3069             :             }
    3070           9 :             el = ldb_msg_find_element(msg, SYSDB_GHOST);
    3071           9 :             if (el) {
    3072           0 :                 if (DOM_HAS_VIEWS(dom) && !is_local_view(dom->view_name)
    3073           0 :                         && el->num_values != 0) {
    3074           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
    3075             :                           "Domain has a view [%s] but group [%s] still has " \
    3076             :                           "ghost members.\n", dom->view_name, orig_name);
    3077           0 :                     num = 0;
    3078           0 :                     goto done;
    3079             :                 }
    3080           0 :                 ret = fill_members(packet, dom, nctx, el, &rzero, &rsize,
    3081             :                                    &memnum);
    3082           0 :                 if (ret != EOK) {
    3083           0 :                     num = 0;
    3084           0 :                     goto done;
    3085             :                 }
    3086           0 :                 sss_packet_get_body(packet, &body, &blen);
    3087             :             }
    3088             :         }
    3089           9 :         if (memnum) {
    3090             :             /* set num of members */
    3091           6 :             SAFEALIGN_SET_UINT32(&body[rzero+MNUM_ROFFSET], memnum, NULL);
    3092             :         }
    3093             : 
    3094           9 :         num++;
    3095             : 
    3096           9 :         if (gr_mmap_cache && nctx->grp_mc_ctx) {
    3097             :             /* body was reallocated, so fullname might be pointing to
    3098             :              * where body used to be, not where it is */
    3099           0 :             to_sized_string(&fullname, (const char *)&body[rzero+STRS_ROFFSET]);
    3100           0 :             ret = sss_mmap_cache_gr_store(&nctx->grp_mc_ctx,
    3101             :                                           &fullname, &pwfield, gid, memnum,
    3102           0 :                                           (char *)&body[rzero] + STRS_ROFFSET +
    3103           0 :                                             fullname.len + pwfield.len,
    3104           0 :                                           rsize - STRS_ROFFSET -
    3105           0 :                                             fullname.len - pwfield.len);
    3106           0 :             if (ret != EOK && ret != ENOMEM) {
    3107           0 :                 DEBUG(SSSDBG_OP_FAILURE,
    3108             :                       "Failed to store group %s(%s) in mmap cache!\n",
    3109             :                       name.str, domain);
    3110             :             }
    3111             :         }
    3112             : 
    3113           9 :         continue;
    3114             :     }
    3115           9 :     talloc_zfree(tmp_ctx);
    3116             : 
    3117             : done:
    3118           9 :     *count = i;
    3119             : 
    3120           9 :     if (num == 0) {
    3121             :         /* if num is 0 most probably something went wrong,
    3122             :          * reset packet and return ENOENT */
    3123           0 :         ret = sss_packet_set_size(packet, 0);
    3124           0 :         if (ret != EOK) return ret;
    3125           0 :         return ENOENT;
    3126             :     }
    3127             : 
    3128           9 :     SAFEALIGN_COPY_UINT32(body, &num, NULL); /* num results */
    3129           9 :     SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL); /* reserved */
    3130             : 
    3131           9 :     return EOK;
    3132             : }
    3133             : 
    3134           9 : static int nss_cmd_getgr_send_reply(struct nss_dom_ctx *dctx, bool filter)
    3135             : {
    3136           9 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    3137           9 :     struct cli_ctx *cctx = cmdctx->cctx;
    3138             :     struct nss_ctx *nctx;
    3139             :     int ret;
    3140             :     int i;
    3141             : 
    3142           9 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    3143             : 
    3144          18 :     ret = sss_packet_new(cctx->creq, 0,
    3145           9 :                          sss_packet_get_cmd(cctx->creq->in),
    3146           9 :                          &cctx->creq->out);
    3147           9 :     if (ret != EOK) {
    3148           0 :         return EFAULT;
    3149             :     }
    3150           9 :     i = dctx->res->count;
    3151           9 :     ret = fill_grent(cctx->creq->out,
    3152             :                      dctx->domain,
    3153             :                      nctx, filter, true,
    3154           9 :                      dctx->res->msgs, &i);
    3155           9 :     if (ret) {
    3156           0 :         return ret;
    3157             :     }
    3158           9 :     sss_packet_set_error(cctx->creq->out, EOK);
    3159           9 :     sss_cmd_done(cctx, cmdctx);
    3160           9 :     return EOK;
    3161             : }
    3162             : 
    3163             : /* search for a group.
    3164             :  * Returns:
    3165             :  *   ENOENT, if group is definitely not found
    3166             :  *   EAGAIN, if group is being fetched from backend via async operations
    3167             :  *   EOK, if found
    3168             :  *   anything else on a fatal error
    3169             :  */
    3170             : 
    3171           9 : static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
    3172             : {
    3173           9 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    3174           9 :     struct sss_domain_info *dom = dctx->domain;
    3175           9 :     struct cli_ctx *cctx = cmdctx->cctx;
    3176           9 :     char *name = NULL;
    3177             :     struct nss_ctx *nctx;
    3178             :     int ret;
    3179           9 :     const char *extra_flag = NULL;
    3180             : 
    3181           9 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    3182             : 
    3183           9 :     while (dom) {
    3184             :        /* if it is a domainless search, skip domains that require fully
    3185             :          * qualified names instead */
    3186          18 :         while (dom && cmdctx->check_next && dom->fqnames) {
    3187           0 :             dom = get_next_domain(dom, 0);
    3188             :         }
    3189             : 
    3190           9 :         if (!dom) break;
    3191             : 
    3192           9 :         if (dom != dctx->domain) {
    3193             :             /* make sure we reset the check_provider flag when we check
    3194             :              * a new domain */
    3195           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    3196             :         }
    3197             : 
    3198             :         /* make sure to update the dctx if we changed domain */
    3199           9 :         dctx->domain = dom;
    3200             : 
    3201           9 :         talloc_free(name);
    3202           9 :         name = sss_get_cased_name(dctx, cmdctx->name, dom->case_sensitive);
    3203           9 :         if (!name) return ENOMEM;
    3204             : 
    3205           9 :         name = sss_reverse_replace_space(dctx, name,
    3206           9 :                                          nctx->rctx->override_space);
    3207           9 :         if (name == NULL) {
    3208           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    3209             :                   "sss_reverse_replace_space failed\n");
    3210           0 :             return ENOMEM;
    3211             :         }
    3212             : 
    3213             :         /* verify this group has not yet been negatively cached,
    3214             :         * or has been permanently filtered */
    3215           9 :         ret = sss_ncache_check_group(nctx->rctx->ncache, dom, name);
    3216             : 
    3217             :         /* if neg cached, return we didn't find it */
    3218           9 :         if (ret == EEXIST) {
    3219           0 :             DEBUG(SSSDBG_TRACE_FUNC,
    3220             :                   "Group [%s] does not exist in [%s]! (negative cache)\n",
    3221             :                    name, dom->name);
    3222             :             /* if a multidomain search, try with next */
    3223           0 :             if (cmdctx->check_next) {
    3224           0 :                 dom = get_next_domain(dom, 0);
    3225           0 :                 continue;
    3226             :             }
    3227             :             /* There are no further domains or this was a
    3228             :              * fully-qualified user request.
    3229             :              */
    3230           0 :             return ENOENT;
    3231             :         }
    3232             : 
    3233           9 :         DEBUG(SSSDBG_CONF_SETTINGS,
    3234             :               "Requesting info for [%s@%s]\n", name, dom->name);
    3235             : 
    3236           9 :         if (dom->sysdb == NULL) {
    3237           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    3238             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    3239           0 :             return EIO;
    3240             :         }
    3241             : 
    3242           9 :         ret = sysdb_getgrnam_with_views(cmdctx, dom, name, &dctx->res);
    3243           9 :         if (ret != EOK) {
    3244           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    3245             :                   "Failed to make request to our cache!\n");
    3246           0 :             return EIO;
    3247             :         }
    3248             : 
    3249           9 :         if (dctx->res->count > 1) {
    3250           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    3251             :                   "getgrnam call returned more than one result !?!\n");
    3252           0 :             sss_log(SSS_LOG_ERR,
    3253             :                     "More groups have the same name [%s@%s] in SSSD cache. "
    3254             :                     "SSSD will not work correctly.\n",
    3255             :                     name, dom->name);
    3256           0 :             return ENOENT;
    3257             :         }
    3258             : 
    3259           9 :         if (dctx->res->count == 0 && !dctx->check_provider) {
    3260             :             /* set negative cache only if not result of cache check */
    3261           0 :             ret = sss_ncache_set_group(nctx->rctx->ncache, false, dom, name);
    3262           0 :             if (ret != EOK) {
    3263           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for %s@%s\n",
    3264             :                       name, dom->name);
    3265             :             }
    3266             : 
    3267             :             /* if a multidomain search, try with next */
    3268           0 :             if (cmdctx->check_next) {
    3269           0 :                 dom = get_next_domain(dom, 0);
    3270           0 :                 if (dom) continue;
    3271             :             }
    3272             : 
    3273           0 :             DEBUG(SSSDBG_OP_FAILURE, "No results for getgrnam call\n");
    3274             : 
    3275             :             /* Group not found in ldb -> delete group from memory cache. */
    3276           0 :             ret = delete_entry_from_memcache(dctx->domain, name,
    3277             :                                              nctx->grp_mc_ctx, SSS_MC_GROUP);
    3278           0 :             if (ret != EOK) {
    3279           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    3280             :                       "Deleting group from memcache failed.\n");
    3281             :             }
    3282             : 
    3283             : 
    3284           0 :             return ENOENT;
    3285             :         }
    3286             : 
    3287             :         /* if this is a caching provider (or if we haven't checked the cache
    3288             :          * yet) then verify that the cache is uptodate */
    3289           9 :         if (dctx->check_provider) {
    3290             : 
    3291           9 :             if (DOM_HAS_VIEWS(dom) && (dctx->res->count == 0
    3292           0 :                     || ldb_msg_find_attr_as_string(dctx->res->msgs[0],
    3293             :                                                    OVERRIDE_PREFIX SYSDB_NAME,
    3294             :                                                    NULL) != NULL)) {
    3295           0 :                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
    3296             :             } else {
    3297           9 :                 extra_flag = NULL;
    3298             :             }
    3299             : 
    3300           9 :             ret = check_cache(dctx, nctx, dctx->res, SSS_DP_GROUP, name, 0,
    3301             :                               extra_flag, nss_cmd_getby_dp_callback, dctx);
    3302           9 :             if (ret != EOK) {
    3303             :                 /* Anything but EOK means we should reenter the mainloop
    3304             :                  * because we may be refreshing the cache
    3305             :                  */
    3306           0 :                 return ret;
    3307             :             }
    3308             :         }
    3309             : 
    3310             :         /* One result found */
    3311           9 :         DEBUG(SSSDBG_TRACE_FUNC,
    3312             :               "Returning info for group [%s@%s]\n", name, dom->name);
    3313             : 
    3314           9 :         return EOK;
    3315             :     }
    3316             : 
    3317           0 :     DEBUG(SSSDBG_MINOR_FAILURE,
    3318             :           "No matching domain found for [%s], fail!\n", cmdctx->name);
    3319           0 :     return ENOENT;
    3320             : }
    3321             : 
    3322           9 : static int nss_cmd_getgrnam(struct cli_ctx *cctx)
    3323             : {
    3324           9 :     return nss_cmd_getbynam(SSS_NSS_GETGRNAM, cctx);
    3325             : }
    3326             : 
    3327             : /* search for a gid.
    3328             :  * Returns:
    3329             :  *   ENOENT, if gid is definitely not found
    3330             :  *   EAGAIN, if gid is being fetched from backend via async operations
    3331             :  *   EOK, if found
    3332             :  *   anything else on a fatal error
    3333             :  */
    3334             : 
    3335           0 : static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx)
    3336             : {
    3337           0 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    3338           0 :     struct sss_domain_info *dom = dctx->domain;
    3339           0 :     struct cli_ctx *cctx = cmdctx->cctx;
    3340             :     struct nss_ctx *nctx;
    3341             :     int ret;
    3342             :     int err;
    3343           0 :     const char *extra_flag = NULL;
    3344             : 
    3345           0 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    3346             : 
    3347           0 :     while (dom) {
    3348             : 
    3349             :         /* check that the gid is valid for this domain */
    3350           0 :         if ((dom->id_min && (cmdctx->id < dom->id_min)) ||
    3351           0 :             (dom->id_max && (cmdctx->id > dom->id_max))) {
    3352           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    3353             :                   "Gid [%"PRIu32"] does not exist in domain [%s]! "
    3354             :                       "(id out of range)\n",
    3355             :                       cmdctx->id, dom->name);
    3356           0 :             if (cmdctx->check_next) {
    3357           0 :                 dom = get_next_domain(dom, SSS_GND_DESCEND);
    3358           0 :                 continue;
    3359             :             }
    3360           0 :             ret = ENOENT;
    3361           0 :             goto done;
    3362             :         }
    3363             : 
    3364           0 :         if (dom != dctx->domain) {
    3365             :             /* make sure we reset the check_provider flag when we check
    3366             :              * a new domain */
    3367           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    3368             :         }
    3369             : 
    3370             :         /* make sure to update the dctx if we changed domain */
    3371           0 :         dctx->domain = dom;
    3372             : 
    3373           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
    3374             :               "Requesting info for [%"PRIu32"@%s]\n", cmdctx->id, dom->name);
    3375             : 
    3376           0 :         if (dom->sysdb == NULL) {
    3377           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    3378             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    3379           0 :             ret = EIO;
    3380           0 :             goto done;
    3381             :         }
    3382             : 
    3383           0 :         ret = sysdb_getgrgid_with_views(cmdctx, dom, cmdctx->id, &dctx->res);
    3384           0 :         if (ret != EOK) {
    3385           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    3386             :                   "Failed to make request to our cache!\n");
    3387           0 :             ret = EIO;
    3388           0 :             goto done;
    3389             :         }
    3390             : 
    3391           0 :         if (dctx->res->count > 1) {
    3392           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    3393             :                   "getgrgid call returned more than one result !?!\n");
    3394           0 :             sss_log(SSS_LOG_ERR,
    3395             :                     "More groups have the same GID [%"PRIu32"] in directory "
    3396             :                     "server. SSSD will not work correctly.\n", cmdctx->id);
    3397           0 :             ret = ENOENT;
    3398           0 :             goto done;
    3399             :         }
    3400             : 
    3401           0 :         if (dctx->res->count == 0 && !dctx->check_provider) {
    3402             :             /* if a multidomain search, try with next */
    3403           0 :             if (cmdctx->check_next) {
    3404           0 :                 dom = get_next_domain(dom, SSS_GND_DESCEND);
    3405           0 :                 continue;
    3406             :             }
    3407             : 
    3408             :             /* set negative cache only if not result of cache check */
    3409           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "No results for getgrgid call\n");
    3410           0 :             ret = ENOENT;
    3411           0 :             goto done;
    3412             :         }
    3413             : 
    3414             :         /* if this is a caching provider (or if we haven't checked the cache
    3415             :          * yet) then verify that the cache is uptodate */
    3416           0 :         if (dctx->check_provider) {
    3417             : 
    3418           0 :             if (DOM_HAS_VIEWS(dom) && (dctx->res->count == 0
    3419           0 :                     || ldb_msg_find_attr_as_uint64(dctx->res->msgs[0],
    3420             :                                                    OVERRIDE_PREFIX SYSDB_GIDNUM,
    3421             :                                                    0) != 0)) {
    3422           0 :                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
    3423             :             } else {
    3424           0 :                 extra_flag = NULL;
    3425             :             }
    3426             : 
    3427           0 :             ret = check_cache(dctx, nctx, dctx->res, SSS_DP_GROUP, NULL,
    3428             :                               cmdctx->id, extra_flag, nss_cmd_getby_dp_callback,
    3429             :                               dctx);
    3430           0 :             if (ret != EOK) {
    3431             :                 /* Anything but EOK means we should reenter the mainloop
    3432             :                  * because we may be refreshing the cache
    3433             :                  */
    3434           0 :                 goto done;
    3435             :             }
    3436             :         }
    3437             : 
    3438             :         /* One result found */
    3439           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    3440             :               "Returning info for gid [%"PRIu32"@%s]\n", cmdctx->id, dom->name);
    3441             : 
    3442             :         /* Success. Break from the loop and return EOK */
    3443           0 :         ret = EOK;
    3444           0 :         goto done;
    3445             :     }
    3446             : 
    3447             :     /* All domains were tried and none had the entry. */
    3448           0 :     ret = ENOENT;
    3449             : done:
    3450           0 :     if (ret == ENOENT) {
    3451             :         /* The entry was not found, need to set result in negative cache */
    3452           0 :         err = sss_ncache_set_gid(nctx->rctx->ncache, false, NULL, cmdctx->id);
    3453           0 :         if (err != EOK) {
    3454           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    3455             :                 "Cannot set negative cache for GID %"PRIu32"\n", cmdctx->id);
    3456             :         }
    3457           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    3458             :               "No matching domain found for [%"PRIu32"]\n", cmdctx->id);
    3459             :     }
    3460             : 
    3461           0 :     return ret;
    3462             : }
    3463             : 
    3464           0 : static int nss_cmd_getgrgid(struct cli_ctx *cctx)
    3465             : {
    3466           0 :     return nss_cmd_getbyid(SSS_NSS_GETGRGID, cctx);
    3467             : }
    3468             : 
    3469             : /* to keep it simple at this stage we are retrieving the
    3470             :  * full enumeration again for each request for each process
    3471             :  * and we also block on setgrent() for the full time needed
    3472             :  * to retrieve the data. And endgrent() frees all the data.
    3473             :  * Next steps are:
    3474             :  * - use and nsssrv wide cache with data already structured
    3475             :  *   so that it can be immediately returned (see nscd way)
    3476             :  * - use mutexes so that setgrent() can return immediately
    3477             :  *   even if the data is still being fetched
    3478             :  * - make getgrent() wait on the mutex
    3479             :  */
    3480             : struct tevent_req *nss_cmd_setgrent_send(TALLOC_CTX *mem_ctx,
    3481             :                                          struct cli_ctx *client);
    3482             : static void nss_cmd_setgrent_done(struct tevent_req *req);
    3483           0 : static int nss_cmd_setgrent(struct cli_ctx *cctx)
    3484             : {
    3485             :     struct nss_cmd_ctx *cmdctx;
    3486             :     struct tevent_req *req;
    3487           0 :     errno_t ret = EOK;
    3488             : 
    3489           0 :     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
    3490           0 :     if (!cmdctx) {
    3491           0 :         return ENOMEM;
    3492             :     }
    3493           0 :     cmdctx->cctx = cctx;
    3494             : 
    3495           0 :     req = nss_cmd_setgrent_send(cmdctx, cctx);
    3496           0 :     if (!req) {
    3497           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    3498             :               "Fatal error calling nss_cmd_setgrent_send\n");
    3499           0 :         ret = EIO;
    3500           0 :         goto done;
    3501             :     }
    3502           0 :     tevent_req_set_callback(req, nss_cmd_setgrent_done, cmdctx);
    3503             : 
    3504             : done:
    3505           0 :     return nss_cmd_done(cmdctx, ret);
    3506             : }
    3507             : 
    3508             : static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx);
    3509           0 : struct tevent_req *nss_cmd_setgrent_send(TALLOC_CTX *mem_ctx,
    3510             :                                          struct cli_ctx *client)
    3511             : {
    3512             :     errno_t ret;
    3513             :     struct nss_ctx *nctx;
    3514             :     struct tevent_req *req;
    3515             :     struct setent_ctx *state;
    3516             :     struct sss_domain_info *dom;
    3517             :     struct setent_step_ctx *step_ctx;
    3518             : 
    3519           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Received setgrent request\n");
    3520           0 :     nctx = talloc_get_type(client->rctx->pvt_ctx, struct nss_ctx);
    3521             : 
    3522             :     /* Reset the read pointers */
    3523           0 :     client->grent_dom_idx = 0;
    3524           0 :     client->grent_cur = 0;
    3525             : 
    3526           0 :     req = tevent_req_create(mem_ctx, &state, struct setent_ctx);
    3527           0 :     if (!req) {
    3528           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    3529             :               "Could not create tevent request for setgrent\n");
    3530           0 :         return NULL;
    3531             :     }
    3532             : 
    3533           0 :     state->nctx = nctx;
    3534           0 :     state->client = client;
    3535             : 
    3536           0 :     state->dctx = talloc_zero(state, struct nss_dom_ctx);
    3537           0 :     if (!state->dctx) {
    3538           0 :         ret = ENOMEM;
    3539           0 :         goto error;
    3540             :     }
    3541             : 
    3542             :     /* check if enumeration is enabled in any domain */
    3543           0 :     for (dom = client->rctx->domains; dom;
    3544           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND)) {
    3545           0 :         if (dom->enumerate == true) break;
    3546             :     }
    3547           0 :     state->dctx->domain = dom;
    3548             : 
    3549           0 :     if (state->dctx->domain == NULL) {
    3550           0 :         DEBUG(SSSDBG_OP_FAILURE, "Enumeration disabled on all domains!\n");
    3551           0 :         ret = ENOENT;
    3552           0 :         goto error;
    3553             :     }
    3554             : 
    3555           0 :     state->dctx->check_provider =
    3556           0 :             NEED_CHECK_PROVIDER(state->dctx->domain->provider);
    3557             : 
    3558             :     /* Is the result context already available */
    3559           0 :     if (state->nctx->gctx) {
    3560           0 :         if (state->nctx->gctx->ready) {
    3561             :             /* All of the necessary data is in place
    3562             :              * We can return now, getgrent requests will work at this point
    3563             :              */
    3564           0 :             tevent_req_done(req);
    3565           0 :             tevent_req_post(req, state->nctx->rctx->ev);
    3566             :         }
    3567             :         else {
    3568             :             /* Object is still being constructed
    3569             :              * Register for notification when it's
    3570             :              * ready.
    3571             :              */
    3572           0 :             ret = nss_setent_add_ref(state, state->nctx->gctx, req);
    3573           0 :             if (ret != EOK) {
    3574           0 :                 talloc_free(req);
    3575           0 :                 return NULL;
    3576             :             }
    3577             :         }
    3578           0 :         return req;
    3579             :     }
    3580             : 
    3581             :     /* Create a new result context
    3582             :      * We are creating it on the nss_ctx so that it doesn't
    3583             :      * go away if the original request does. We will delete
    3584             :      * it when the refcount goes to zero;
    3585             :      */
    3586           0 :     state->nctx->gctx = talloc_zero(nctx, struct getent_ctx);
    3587           0 :     if (!state->nctx->gctx) {
    3588           0 :         ret = ENOMEM;
    3589           0 :         goto error;
    3590             :     }
    3591           0 :     state->getent_ctx = nctx->gctx;
    3592             : 
    3593             :     /* Add a callback reference for ourselves */
    3594           0 :     ret = nss_setent_add_ref(state, state->nctx->gctx, req);
    3595           0 :     if (ret) goto error;
    3596             : 
    3597             :     /* ok, start the searches */
    3598           0 :     step_ctx = talloc_zero(state->getent_ctx, struct setent_step_ctx);
    3599           0 :     if (!step_ctx) {
    3600           0 :         ret = ENOMEM;
    3601           0 :         goto error;
    3602             :     }
    3603             : 
    3604             :     /* Steal the dom_ctx onto the step_ctx so it doesn't go out of scope if
    3605             :      * this request is canceled while other requests are in-progress.
    3606             :      */
    3607           0 :     step_ctx->dctx = talloc_steal(step_ctx, state->dctx);
    3608           0 :     step_ctx->nctx = state->nctx;
    3609           0 :     step_ctx->getent_ctx = state->getent_ctx;
    3610           0 :     step_ctx->rctx = client->rctx;
    3611           0 :     step_ctx->cctx = client;
    3612           0 :     step_ctx->returned_to_mainloop = false;
    3613             : 
    3614           0 :     ret = nss_cmd_setgrent_step(step_ctx);
    3615           0 :     if (ret != EOK && ret != EAGAIN) goto error;
    3616             : 
    3617           0 :     if (ret == EOK) {
    3618           0 :         tevent_req_post(req, client->rctx->ev);
    3619             :     }
    3620             : 
    3621           0 :     return req;
    3622             : 
    3623             :  error:
    3624           0 :      tevent_req_error(req, ret);
    3625           0 :      tevent_req_post(req, client->rctx->ev);
    3626           0 :      return req;
    3627             : }
    3628             : 
    3629             : static void nss_cmd_setgrent_dp_callback(uint16_t err_maj, uint32_t err_min,
    3630             :                                          const char *err_msg, void *ptr);
    3631             : static void setgrent_result_timeout(struct tevent_context *ev,
    3632             :                                     struct tevent_timer *te,
    3633             :                                     struct timeval current_time,
    3634             :                                     void *pvt);
    3635             : 
    3636             : /* nss_cmd_setgrent_step returns
    3637             :  *   EOK if everything is done and the request needs to be posted explicitly
    3638             :  *   EAGAIN if the caller can safely return to the main loop
    3639             :  */
    3640           0 : static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
    3641             : {
    3642             :     errno_t ret;
    3643           0 :     struct sss_domain_info *dom = step_ctx->dctx->domain;
    3644           0 :     struct resp_ctx *rctx = step_ctx->rctx;
    3645           0 :     struct nss_dom_ctx *dctx = step_ctx->dctx;
    3646           0 :     struct getent_ctx *gctx = step_ctx->getent_ctx;
    3647           0 :     struct nss_ctx *nctx = step_ctx->nctx;
    3648             :     struct ldb_result *res;
    3649             :     struct timeval tv;
    3650             :     struct tevent_timer *te;
    3651             :     struct tevent_req *dpreq;
    3652             :     struct dp_callback_ctx *cb_ctx;
    3653             : 
    3654           0 :     while (dom) {
    3655           0 :         while (dom && dom->enumerate == false) {
    3656           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND);
    3657             :         }
    3658             : 
    3659           0 :         if (!dom) break;
    3660             : 
    3661           0 :         if (dom != dctx->domain) {
    3662             :             /* make sure we reset the check_provider flag when we check
    3663             :              * a new domain */
    3664           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    3665             :         }
    3666             : 
    3667             :         /* make sure to update the dctx if we changed domain */
    3668           0 :         dctx->domain = dom;
    3669             : 
    3670           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    3671             :               "Requesting info for domain [%s]\n", dom->name);
    3672             : 
    3673           0 :         if (dom->sysdb == NULL) {
    3674           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    3675             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    3676           0 :             return EIO;
    3677             :         }
    3678             : 
    3679             :         /* if this is a caching provider (or if we haven't checked the cache
    3680             :          * yet) then verify that the cache is uptodate */
    3681           0 :         if (dctx->check_provider) {
    3682           0 :             step_ctx->returned_to_mainloop = true;
    3683             :             /* Only do this once per provider */
    3684           0 :             dctx->check_provider = false;
    3685             : 
    3686           0 :             dpreq = sss_dp_get_account_send(step_ctx, rctx, dctx->domain, true,
    3687             :                                             SSS_DP_GROUP, NULL, 0, NULL);
    3688           0 :             if (!dpreq) {
    3689           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    3690             :                       "Enum Cache refresh for domain [%s] failed."
    3691             :                        " Trying to return what we have in cache!\n",
    3692             :                        dom->name);
    3693             :             } else {
    3694           0 :                 cb_ctx = talloc_zero(step_ctx, struct dp_callback_ctx);
    3695           0 :                 if(!cb_ctx) {
    3696           0 :                     talloc_zfree(dpreq);
    3697           0 :                     return ENOMEM;
    3698             :                 }
    3699             : 
    3700           0 :                 cb_ctx->callback = nss_cmd_setgrent_dp_callback;
    3701           0 :                 cb_ctx->ptr = step_ctx;
    3702           0 :                 cb_ctx->cctx = step_ctx->cctx;
    3703           0 :                 cb_ctx->mem_ctx = step_ctx;
    3704             : 
    3705           0 :                 tevent_req_set_callback(dpreq, nsssrv_dp_send_acct_req_done, cb_ctx);
    3706             : 
    3707           0 :                 return EAGAIN;
    3708             :             }
    3709             :         }
    3710             : 
    3711           0 :         ret = sysdb_enumgrent_with_views(dctx, dom, &res);
    3712           0 :         if (ret != EOK) {
    3713           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    3714             :                   "Enum from cache failed, skipping domain [%s]\n",
    3715             :                       dom->name);
    3716           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND);
    3717           0 :             continue;
    3718             :         }
    3719             : 
    3720           0 :         if (res->count == 0) {
    3721           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    3722             :                   "Domain [%s] has no groups, skipping.\n", dom->name);
    3723           0 :             dom = get_next_domain(dom, SSS_GND_DESCEND);
    3724           0 :             continue;
    3725             :         }
    3726             : 
    3727           0 :         nctx->gctx->doms = talloc_realloc(gctx, gctx->doms,
    3728             :                                     struct dom_ctx, gctx->num +1);
    3729           0 :         if (!gctx->doms) {
    3730           0 :             talloc_free(gctx);
    3731           0 :             nctx->gctx = NULL;
    3732           0 :             return ENOMEM;
    3733             :         }
    3734             : 
    3735           0 :         nctx->gctx->doms[gctx->num].domain = dctx->domain;
    3736           0 :         nctx->gctx->doms[gctx->num].res = talloc_steal(gctx->doms, res);
    3737             : 
    3738           0 :         nctx->gctx->num++;
    3739             : 
    3740             :         /* do not reply until all domain searches are done */
    3741           0 :         dom = get_next_domain(dom, SSS_GND_DESCEND);
    3742             :     }
    3743             : 
    3744             :     /* We've finished all our lookups
    3745             :      * The result object is now safe to read.
    3746             :      */
    3747           0 :     nctx->gctx->ready = true;
    3748             : 
    3749             :     /* Set up a lifetime timer for this result object
    3750             :      * We don't want this result object to outlive the
    3751             :      * enum cache refresh timeout
    3752             :      */
    3753           0 :     tv = tevent_timeval_current_ofs(nctx->enum_cache_timeout, 0);
    3754           0 :     te = tevent_add_timer(rctx->ev, nctx->gctx, tv,
    3755             :                           setgrent_result_timeout, nctx);
    3756           0 :     if (!te) {
    3757           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    3758             :               "Could not set up life timer for setgrent result object. "
    3759             :                   "Entries may become stale.\n");
    3760             :     }
    3761             : 
    3762             :     /* Notify the waiting clients */
    3763           0 :     nss_setent_notify_done(nctx->gctx);
    3764             : 
    3765           0 :     if (step_ctx->returned_to_mainloop) {
    3766           0 :         return EAGAIN;
    3767             :     } else {
    3768           0 :         return EOK;
    3769             :     }
    3770             : 
    3771             : }
    3772             : 
    3773           0 : static void setgrent_result_timeout(struct tevent_context *ev,
    3774             :                                     struct tevent_timer *te,
    3775             :                                     struct timeval current_time,
    3776             :                                     void *pvt)
    3777             : {
    3778           0 :     struct nss_ctx *nctx = talloc_get_type(pvt, struct nss_ctx);
    3779             : 
    3780           0 :     DEBUG(SSSDBG_CRIT_FAILURE,
    3781             :           "setgrent result object has expired. Cleaning up.\n");
    3782             : 
    3783             :     /* Free the group enumeration context.
    3784             :      * If additional getgrent requests come in, they will invoke
    3785             :      * an implicit setgrent and refresh the result object.
    3786             :      */
    3787           0 :     talloc_zfree(nctx->gctx);
    3788           0 : }
    3789             : 
    3790           0 : static void nss_cmd_setgrent_dp_callback(uint16_t err_maj, uint32_t err_min,
    3791             :                                          const char *err_msg, void *ptr)
    3792             : {
    3793           0 :     struct setent_step_ctx *step_ctx =
    3794             :             talloc_get_type(ptr, struct setent_step_ctx);
    3795             :     int ret;
    3796             : 
    3797           0 :     if (err_maj) {
    3798           0 :         DEBUG(SSSDBG_OP_FAILURE,
    3799             :               "Unable to get information from Data Provider\n"
    3800             :                   "Error: %u, %u, %s\n"
    3801             :                   "Will try to return what we have in cache\n",
    3802             :                   (unsigned int)err_maj, (unsigned int)err_min, err_msg);
    3803             :     }
    3804             : 
    3805           0 :     ret = nss_cmd_setgrent_step(step_ctx);
    3806           0 :     if (ret != EOK && ret != EAGAIN) {
    3807             :         /* Notify any waiting processes of failure */
    3808           0 :         nss_setent_notify_error(step_ctx->nctx->gctx, ret);
    3809             :     }
    3810           0 : }
    3811             : 
    3812           0 : static errno_t nss_cmd_setgrent_recv(struct tevent_req *req)
    3813             : {
    3814           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    3815           0 :     return EOK;
    3816             : }
    3817             : 
    3818           0 : static void nss_cmd_setgrent_done(struct tevent_req *req)
    3819             : {
    3820             :     errno_t ret;
    3821           0 :     struct nss_cmd_ctx *cmdctx =
    3822           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
    3823             : 
    3824           0 :     ret = nss_cmd_setgrent_recv(req);
    3825           0 :     talloc_zfree(req);
    3826           0 :     if (ret == EOK || ret == ENOENT) {
    3827             :         /* Either we succeeded or no domains were eligible */
    3828           0 :         ret = sss_packet_new(cmdctx->cctx->creq, 0,
    3829           0 :                              sss_packet_get_cmd(cmdctx->cctx->creq->in),
    3830           0 :                              &cmdctx->cctx->creq->out);
    3831           0 :         if (ret == EOK) {
    3832           0 :             sss_cmd_done(cmdctx->cctx, cmdctx);
    3833           0 :             return;
    3834             :         }
    3835             :     }
    3836             : 
    3837             :     /* Something bad happened */
    3838           0 :     nss_cmd_done(cmdctx, ret);
    3839             : }
    3840             : 
    3841           0 : static int nss_cmd_retgrent(struct cli_ctx *cctx, int num)
    3842             : {
    3843             :     struct nss_ctx *nctx;
    3844             :     struct getent_ctx *gctx;
    3845           0 :     struct ldb_message **msgs = NULL;
    3846           0 :     struct dom_ctx *gdom = NULL;
    3847           0 :     int n = 0;
    3848           0 :     int ret = ENOENT;
    3849             : 
    3850           0 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    3851           0 :     if (!nctx->gctx) goto none;
    3852             : 
    3853           0 :     gctx = nctx->gctx;
    3854             : 
    3855           0 :     while (ret == ENOENT) {
    3856           0 :         if (cctx->grent_dom_idx >= gctx->num) break;
    3857             : 
    3858           0 :         gdom = &gctx->doms[cctx->grent_dom_idx];
    3859             : 
    3860           0 :         n = gdom->res->count - cctx->grent_cur;
    3861           0 :         if (n <= 0 && (cctx->grent_dom_idx+1 < gctx->num)) {
    3862           0 :             cctx->grent_dom_idx++;
    3863           0 :             gdom = &gctx->doms[cctx->grent_dom_idx];
    3864           0 :             n = gdom->res->count;
    3865           0 :             cctx->grent_cur = 0;
    3866             :         }
    3867             : 
    3868           0 :         if (!n) break;
    3869             : 
    3870           0 :         if (n > num) n = num;
    3871             : 
    3872           0 :         msgs = &(gdom->res->msgs[cctx->grent_cur]);
    3873             : 
    3874           0 :         ret = fill_grent(cctx->creq->out,
    3875             :                          gdom->domain,
    3876             :                          nctx, true, false, msgs, &n);
    3877             : 
    3878           0 :         cctx->grent_cur += n;
    3879             :     }
    3880             : 
    3881             : none:
    3882           0 :     if (ret == ENOENT) {
    3883           0 :         ret = sss_cmd_empty_packet(cctx->creq->out);
    3884             :     }
    3885           0 :     return ret;
    3886             : }
    3887             : 
    3888           0 : static int nss_cmd_getgrent_immediate(struct nss_cmd_ctx *cmdctx)
    3889             : {
    3890           0 :     struct cli_ctx *cctx = cmdctx->cctx;
    3891             :     uint8_t *body;
    3892             :     size_t blen;
    3893             :     uint32_t num;
    3894             :     int ret;
    3895             : 
    3896             :     /* get max num of entries to return in one call */
    3897           0 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
    3898           0 :     if (blen != sizeof(uint32_t)) {
    3899           0 :         return EINVAL;
    3900             :     }
    3901           0 :     SAFEALIGN_COPY_UINT32(&num, body, NULL);
    3902             : 
    3903             :     /* create response packet */
    3904           0 :     ret = sss_packet_new(cctx->creq, 0,
    3905           0 :                          sss_packet_get_cmd(cctx->creq->in),
    3906           0 :                          &cctx->creq->out);
    3907           0 :     if (ret != EOK) {
    3908           0 :         return ret;
    3909             :     }
    3910             : 
    3911           0 :     ret = nss_cmd_retgrent(cctx, num);
    3912             : 
    3913           0 :     sss_packet_set_error(cctx->creq->out, ret);
    3914           0 :     sss_cmd_done(cctx, cmdctx);
    3915             : 
    3916           0 :     return EOK;
    3917             : }
    3918             : 
    3919             : static void nss_cmd_implicit_setgrent_done(struct tevent_req *req);
    3920           0 : static int nss_cmd_getgrent(struct cli_ctx *cctx)
    3921             : {
    3922             :     struct nss_ctx *nctx;
    3923             :     struct nss_cmd_ctx *cmdctx;
    3924             :     struct tevent_req *req;
    3925             : 
    3926           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Requesting info for all groups\n");
    3927             : 
    3928           0 :     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
    3929           0 :     if (!cmdctx) {
    3930           0 :         return ENOMEM;
    3931             :     }
    3932           0 :     cmdctx->cctx = cctx;
    3933             : 
    3934             :     /* Save the current index and cursor locations
    3935             :      * If we end up calling setgrent implicitly, because the response object
    3936             :      * expired and has to be recreated, we want to resume from the same
    3937             :      * location.
    3938             :      */
    3939           0 :     cmdctx->saved_dom_idx = cctx->grent_dom_idx;
    3940           0 :     cmdctx->saved_cur = cctx->grent_cur;
    3941             : 
    3942           0 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    3943           0 :     if(!nctx->gctx || !nctx->gctx->ready) {
    3944             :         /* Make sure we invoke setgrent if it hasn't been run or is still
    3945             :          * processing from another client
    3946             :          */
    3947           0 :         req = nss_cmd_setgrent_send(cctx, cctx);
    3948           0 :         if (!req) {
    3949           0 :             return EIO;
    3950             :         }
    3951           0 :         tevent_req_set_callback(req, nss_cmd_implicit_setgrent_done, cmdctx);
    3952           0 :         return EOK;
    3953             :     }
    3954             : 
    3955           0 :     return nss_cmd_getgrent_immediate(cmdctx);
    3956             : }
    3957             : 
    3958           0 : static void nss_cmd_implicit_setgrent_done(struct tevent_req *req)
    3959             : {
    3960             :     errno_t ret;
    3961           0 :     struct nss_cmd_ctx *cmdctx =
    3962           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
    3963             : 
    3964           0 :     ret = nss_cmd_setgrent_recv(req);
    3965           0 :     talloc_zfree(req);
    3966             : 
    3967             :     /* ENOENT is acceptable, as it just means that there were no entries
    3968             :      * to be returned. This will be handled gracefully in nss_cmd_retpwent
    3969             :      * later.
    3970             :      */
    3971           0 :     if (ret != EOK && ret != ENOENT) {
    3972           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    3973             :               "Implicit setgrent failed with unexpected error [%d][%s]\n",
    3974             :                   ret, strerror(ret));
    3975           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
    3976             :     }
    3977             : 
    3978             :     /* Restore the saved index and cursor locations */
    3979           0 :     cmdctx->cctx->grent_dom_idx = cmdctx->saved_dom_idx;
    3980           0 :     cmdctx->cctx->grent_cur = cmdctx->saved_cur;
    3981             : 
    3982           0 :     ret = nss_cmd_getgrent_immediate(cmdctx);
    3983           0 :     if (ret != EOK) {
    3984           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    3985             :               "Immediate retrieval failed with unexpected error "
    3986             :                   "[%d][%s]\n", ret, strerror(ret));
    3987           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
    3988             :     }
    3989             : }
    3990             : 
    3991           0 : static int nss_cmd_endgrent(struct cli_ctx *cctx)
    3992             : {
    3993             :     struct nss_ctx *nctx;
    3994             :     int ret;
    3995             : 
    3996           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Terminating request info for all groups\n");
    3997             : 
    3998           0 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    3999             : 
    4000             :     /* create response packet */
    4001           0 :     ret = sss_packet_new(cctx->creq, 0,
    4002           0 :                          sss_packet_get_cmd(cctx->creq->in),
    4003           0 :                          &cctx->creq->out);
    4004             : 
    4005           0 :     if (ret != EOK) {
    4006           0 :         return ret;
    4007             :     }
    4008           0 :     if (nctx->gctx == NULL) goto done;
    4009             : 
    4010             :     /* Reset the indices so that subsequent requests start at zero */
    4011           0 :     cctx->grent_dom_idx = 0;
    4012           0 :     cctx->grent_cur = 0;
    4013             : 
    4014             : done:
    4015           0 :     sss_cmd_done(cctx, NULL);
    4016           0 :     return EOK;
    4017             : }
    4018             : 
    4019           0 : void nss_update_initgr_memcache(struct nss_ctx *nctx,
    4020             :                                 const char *name, const char *domain,
    4021             :                                 int gnum, uint32_t *groups)
    4022             : {
    4023           0 :     TALLOC_CTX *tmp_ctx = NULL;
    4024             :     struct sss_domain_info *dom;
    4025             :     struct ldb_result *res;
    4026             :     struct sized_string delete_name;
    4027           0 :     bool changed = false;
    4028             :     uint32_t id;
    4029           0 :     uint32_t gids[gnum];
    4030             :     int ret;
    4031             :     int i, j;
    4032             : 
    4033           0 :     for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, 0)) {
    4034           0 :         if (strcasecmp(dom->name, domain) == 0) {
    4035           0 :             break;
    4036             :         }
    4037             :     }
    4038             : 
    4039           0 :     if (dom == NULL) {
    4040           0 :         DEBUG(SSSDBG_OP_FAILURE,
    4041             :               "Unknown domain (%s) requested by provider\n", domain);
    4042           0 :         return;
    4043             :     }
    4044             : 
    4045           0 :     tmp_ctx = talloc_new(NULL);
    4046             : 
    4047           0 :     ret = sysdb_initgroups(tmp_ctx, dom, name, &res);
    4048           0 :     if (ret != EOK && ret != ENOENT) {
    4049           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    4050             :               "Failed to make request to our cache! [%d][%s]\n",
    4051             :                ret, strerror(ret));
    4052           0 :         goto done;
    4053             :     }
    4054             : 
    4055             :     /* copy, we need the original intact in case we need to invalidate
    4056             :      * all the original groups */
    4057           0 :     memcpy(gids, groups, gnum * sizeof(uint32_t));
    4058             : 
    4059           0 :     if (ret == ENOENT || res->count == 0) {
    4060             :         /* The user is gone. Invalidate the mc record */
    4061           0 :         to_sized_string(&delete_name, name);
    4062           0 :         ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &delete_name);
    4063           0 :         if (ret != EOK && ret != ENOENT) {
    4064           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    4065             :                   "Internal failure in memory cache code: %d [%s]\n",
    4066             :                   ret, strerror(ret));
    4067             :         }
    4068             : 
    4069             :         /* Also invalidate his groups */
    4070           0 :         changed = true;
    4071             :     } else {
    4072             :         /* we skip the first entry, it's the user itself */
    4073           0 :         for (i = 0; i < res->count; i++) {
    4074           0 :             id = ldb_msg_find_attr_as_uint(res->msgs[i], SYSDB_GIDNUM, 0);
    4075           0 :             if (id == 0) {
    4076             :                 /* probably non-posix group, skip */
    4077           0 :                 continue;
    4078             :             }
    4079           0 :             for (j = 0; j < gnum; j++) {
    4080           0 :                 if (gids[j] == id) {
    4081           0 :                     gids[j] = 0;
    4082           0 :                     break;
    4083             :                 }
    4084             :             }
    4085           0 :             if (j >= gnum) {
    4086             :                 /* we couldn't find a match, this means the groups have
    4087             :                  * changed after the refresh */
    4088           0 :                 changed = true;
    4089           0 :                 break;
    4090             :             }
    4091             :         }
    4092             : 
    4093           0 :         if (!changed) {
    4094           0 :             for (j = 0; j < gnum; j++) {
    4095           0 :                 if (gids[j] != 0) {
    4096             :                     /* we found an un-cleared groups, this means the groups
    4097             :                      * have changed after the refresh (some got deleted) */
    4098           0 :                     changed = true;
    4099           0 :                     break;
    4100             :                 }
    4101             :             }
    4102             :         }
    4103             :     }
    4104             : 
    4105           0 :     if (changed) {
    4106           0 :         char *fq_name = sss_tc_fqname(tmp_ctx, dom->names, dom, name);
    4107           0 :         if (!fq_name) {
    4108           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    4109             :                   "Could not create fq name\n");
    4110           0 :             goto done;
    4111             :         }
    4112             : 
    4113           0 :         for (i = 0; i < gnum; i++) {
    4114           0 :             id = groups[i];
    4115             : 
    4116           0 :             ret = sss_mmap_cache_gr_invalidate_gid(nctx->grp_mc_ctx, id);
    4117           0 :             if (ret != EOK && ret != ENOENT) {
    4118           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    4119             :                       "Internal failure in memory cache code: %d [%s]\n",
    4120             :                        ret, strerror(ret));
    4121             :             }
    4122             :         }
    4123             : 
    4124           0 :         to_sized_string(&delete_name, fq_name);
    4125           0 :         ret = sss_mmap_cache_initgr_invalidate(nctx->initgr_mc_ctx,
    4126             :                                                &delete_name);
    4127           0 :         if (ret != EOK && ret != ENOENT) {
    4128           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    4129             :                   "Internal failure in memory cache code: %d [%s]\n",
    4130             :                   ret, strerror(ret));
    4131             :         }
    4132             :     }
    4133             : 
    4134             : done:
    4135           0 :     talloc_free(tmp_ctx);
    4136             : }
    4137             : 
    4138             : /* FIXME: what about mpg, should we return the user's GID ? */
    4139             : /* FIXME: should we filter out GIDs ? */
    4140           5 : static int fill_initgr(struct sss_packet *packet,
    4141             :                        struct sss_domain_info *dom,
    4142             :                        struct ldb_result *res,
    4143             :                        struct nss_ctx *nctx,
    4144             :                        const char *mc_name,
    4145             :                        const char *name)
    4146             : {
    4147             :     uint8_t *body;
    4148             :     size_t blen;
    4149             :     gid_t gid;
    4150             :     int ret, i;
    4151             :     uint32_t num;
    4152             :     size_t bindex;
    4153           5 :     int skipped = 0;
    4154             :     const char *posix;
    4155             :     gid_t orig_primary_gid;
    4156             :     struct sized_string rawname;
    4157             :     uint8_t *gids;
    4158             : 
    4159           5 :     if (res->count == 0) {
    4160           0 :         return ENOENT;
    4161             :     }
    4162             : 
    4163             :     /* one less, the first one is the user entry */
    4164           5 :     num = res->count -1;
    4165             : 
    4166           5 :     ret = sss_packet_grow(packet, (2 + res->count) * sizeof(uint32_t));
    4167           5 :     if (ret != EOK) {
    4168           0 :         return ret;
    4169             :     }
    4170           5 :     sss_packet_get_body(packet, &body, &blen);
    4171             : 
    4172           5 :     orig_primary_gid = sss_view_ldb_msg_find_attr_as_uint64(dom, res->msgs[0],
    4173             :                                                      SYSDB_PRIMARY_GROUP_GIDNUM,
    4174             :                                                      0);
    4175             : 
    4176             :     /* If the GID of the original primary group is available but equal to the
    4177             :     * current primary GID it must not be added. */
    4178           5 :     if (orig_primary_gid != 0) {
    4179           0 :         gid = sss_view_ldb_msg_find_attr_as_uint64(dom, res->msgs[0],
    4180             :                                                    SYSDB_GIDNUM, 0);
    4181             : 
    4182           0 :         if (orig_primary_gid == gid) {
    4183           0 :             orig_primary_gid = 0;
    4184             :         }
    4185             :     }
    4186             : 
    4187             :     /* 0-3: 32bit unsigned number of results
    4188             :      * 4-7: 32bit unsigned (reserved/padding) */
    4189           5 :     bindex = 2 * sizeof(uint32_t);
    4190           5 :     gids = body + bindex;
    4191             : 
    4192             :     /* skip first entry, it's the user entry */
    4193          15 :     for (i = 0; i < num; i++) {
    4194          10 :         gid = sss_view_ldb_msg_find_attr_as_uint64(dom, res->msgs[i + 1],
    4195             :                                                    SYSDB_GIDNUM, 0);
    4196          10 :         posix = ldb_msg_find_attr_as_string(res->msgs[i + 1],
    4197             :                                             SYSDB_POSIX, NULL);
    4198          10 :         if (!gid) {
    4199           0 :             if (posix && strcmp(posix, "FALSE") == 0) {
    4200           0 :                 skipped++;
    4201           0 :                 continue;
    4202             :             } else {
    4203           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    4204             :                       "Incomplete group object for initgroups! Aborting\n");
    4205           0 :                 return EFAULT;
    4206             :             }
    4207             :         }
    4208          10 :         SAFEALIGN_COPY_UINT32(body + bindex, &gid, &bindex);
    4209             : 
    4210             :         /* do not add the GID of the original primary group is the user is
    4211             :          * already and explicit member of the group. */
    4212          10 :         if (orig_primary_gid == gid) {
    4213           0 :             orig_primary_gid = 0;
    4214             :         }
    4215             :     }
    4216             : 
    4217           5 :     if (orig_primary_gid != 0) {
    4218           0 :         SAFEALIGN_COPY_UINT32(body + bindex, &orig_primary_gid, &bindex);
    4219           0 :         num++;
    4220             :     }
    4221             : 
    4222           5 :     SAFEALIGN_SETMEM_UINT32(body, num - skipped, NULL); /* num results */
    4223           5 :     SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL); /* reserved */
    4224           5 :     blen = bindex;
    4225           5 :     ret = sss_packet_set_size(packet, blen);
    4226           5 :     if (ret != EOK) {
    4227           0 :         DEBUG(SSSDBG_OP_FAILURE,
    4228             :               "Could not set packet size to value:%zu\n", blen);
    4229           0 :         return ret;
    4230             :     }
    4231             : 
    4232           5 :     if (nctx->initgr_mc_ctx) {
    4233             :         struct sized_string unique_name;
    4234           0 :         char *fq_name = sss_tc_fqname(packet, dom->names, dom, name);
    4235           0 :         if (!fq_name) {
    4236           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    4237             :                   "Could not create fq name\n");
    4238           0 :             return ENOMEM;
    4239             :         }
    4240             : 
    4241           0 :         to_sized_string(&rawname, mc_name);
    4242           0 :         to_sized_string(&unique_name, fq_name);
    4243           0 :         ret = sss_mmap_cache_initgr_store(&nctx->initgr_mc_ctx, &rawname,
    4244             :                                           &unique_name, num - skipped, gids);
    4245           0 :         if (ret != EOK && ret != ENOMEM) {
    4246           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    4247             :                   "Failed to store user %s(%s) in mmap cache!\n",
    4248             :                   rawname.str, dom->name);
    4249             :         }
    4250             :     }
    4251             : 
    4252           5 :     return EOK;
    4253             : }
    4254             : 
    4255           5 : static int nss_cmd_initgr_send_reply(struct nss_dom_ctx *dctx)
    4256             : {
    4257           5 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    4258           5 :     struct cli_ctx *cctx = cmdctx->cctx;
    4259             :     struct nss_ctx *nctx;
    4260             :     int ret;
    4261             : 
    4262           5 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    4263             : 
    4264          10 :     ret = sss_packet_new(cctx->creq, 0,
    4265           5 :                          sss_packet_get_cmd(cctx->creq->in),
    4266           5 :                          &cctx->creq->out);
    4267           5 :     if (ret != EOK) {
    4268           0 :         return EFAULT;
    4269             :     }
    4270             : 
    4271           5 :     ret = fill_initgr(cctx->creq->out, dctx->domain, dctx->res, nctx,
    4272             :                       dctx->mc_name, cmdctx->normalized_name);
    4273           5 :     if (ret) {
    4274           0 :         return ret;
    4275             :     }
    4276           5 :     sss_packet_set_error(cctx->creq->out, EOK);
    4277           5 :     sss_cmd_done(cctx, cmdctx);
    4278           5 :     return EOK;
    4279             : }
    4280             : 
    4281          15 : static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
    4282             : {
    4283          15 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    4284          15 :     struct sss_domain_info *dom = dctx->domain;
    4285          15 :     struct cli_ctx *cctx = cmdctx->cctx;
    4286          15 :     char *name = NULL;
    4287             :     struct nss_ctx *nctx;
    4288             :     int ret;
    4289             :     static const char *user_attrs[] = SYSDB_PW_ATTRS;
    4290             :     struct ldb_message *msg;
    4291             :     const char *sysdb_name;
    4292             :     size_t c;
    4293          15 :     const char *extra_flag = NULL;
    4294             : 
    4295          15 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    4296             : 
    4297          15 :     while (dom) {
    4298             :        /* if it is a domainless search, skip domains that require fully
    4299             :          * qualified names instead */
    4300          30 :         while (dom && cmdctx->check_next && dom->fqnames
    4301           0 :                 && !cmdctx->name_is_upn) {
    4302           0 :             dom = get_next_domain(dom, 0);
    4303             :         }
    4304             : 
    4305          15 :         if (!dom) break;
    4306             : 
    4307          15 :         if (dom != dctx->domain) {
    4308             :             /* make sure we reset the check_provider flag when we check
    4309             :              * a new domain */
    4310           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    4311             :         }
    4312             : 
    4313             :         /* make sure to update the dctx if we changed domain */
    4314          15 :         dctx->domain = dom;
    4315             : 
    4316          15 :         talloc_zfree(cmdctx->normalized_name);
    4317          15 :         name = sss_get_cased_name(dctx, cmdctx->name, dom->case_sensitive);
    4318          15 :         if (!name) return ENOMEM;
    4319             : 
    4320          15 :         name = sss_reverse_replace_space(cmdctx, name,
    4321          15 :                                          nctx->rctx->override_space);
    4322             :         /* save name so it can be used in initgr reply */
    4323          15 :         cmdctx->normalized_name = name;
    4324          15 :         if (name == NULL) {
    4325           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    4326             :                   "sss_reverse_replace_space failed\n");
    4327           0 :             return ENOMEM;
    4328             :         }
    4329             : 
    4330             :         /* verify this user has not yet been negatively cached,
    4331             :         * or has been permanently filtered */
    4332          15 :         ret = sss_ncache_check_user(nctx->rctx->ncache, dom, name);
    4333             : 
    4334             :         /* if neg cached, return we didn't find it */
    4335          15 :         if (ret == EEXIST) {
    4336           3 :             DEBUG(SSSDBG_TRACE_FUNC,
    4337             :                   "User [%s] does not exist in [%s]! (negative cache)\n",
    4338             :                    name, dom->name);
    4339             :             /* if a multidomain search, try with next */
    4340           3 :             if (cmdctx->check_next) {
    4341           3 :                 dom = get_next_domain(dom, 0);
    4342           3 :                 continue;
    4343             :             }
    4344             :             /* There are no further domains or this was a
    4345             :              * fully-qualified user request.
    4346             :              */
    4347           0 :             return ENOENT;
    4348             :         }
    4349             : 
    4350          12 :         DEBUG(SSSDBG_CONF_SETTINGS,
    4351             :               "Requesting info for [%s@%s]\n", name, dom->name);
    4352             : 
    4353          12 :         if (dom->sysdb == NULL) {
    4354           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    4355             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    4356           0 :             return EIO;
    4357             :         }
    4358             : 
    4359          12 :         if (cmdctx->name_is_upn) {
    4360           3 :             ret = sysdb_search_user_by_upn(cmdctx, dom, name, user_attrs, &msg);
    4361           3 :             if (ret == ENOENT) {
    4362           2 :                 dctx->res = talloc_zero(cmdctx, struct ldb_result);
    4363           2 :                 if (dctx->res == NULL) {
    4364           0 :                     DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
    4365           0 :                     return ENOMEM;
    4366             :                 }
    4367             : 
    4368           2 :                 dctx->res->count = 0;
    4369           2 :                 dctx->res->msgs = NULL;
    4370           2 :                 ret = EOK;
    4371           1 :             } else if (ret != EOK) {
    4372           0 :                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_upn failed.\n");
    4373           0 :                 return ret;
    4374             :             } else {
    4375           1 :                 sysdb_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
    4376           1 :                 if (sysdb_name == NULL) {
    4377           0 :                     DEBUG(SSSDBG_OP_FAILURE,
    4378             :                         "Sysdb entry does not have a name.\n");
    4379           0 :                     return EINVAL;
    4380             :                 }
    4381             : 
    4382           1 :                 ret = sysdb_initgroups(cmdctx, dom, sysdb_name, &dctx->res);
    4383           1 :                 if (ret == EOK && DOM_HAS_VIEWS(dom)) {
    4384           0 :                     for (c = 0; c < dctx->res->count; c++) {
    4385           0 :                         ret = sysdb_add_overrides_to_object(dom, dctx->res->msgs[c],
    4386             :                                                             NULL, NULL);
    4387           0 :                         if (ret != EOK) {
    4388           0 :                             DEBUG(SSSDBG_OP_FAILURE,
    4389             :                                 "sysdb_add_overrides_to_object failed.\n");
    4390           0 :                             return ret;
    4391             :                         }
    4392             :                     }
    4393             :                 }
    4394             :             }
    4395             :         } else {
    4396           9 :             ret = sysdb_initgroups_with_views(cmdctx, dom, name, &dctx->res);
    4397             :         }
    4398          12 :         if (ret != EOK) {
    4399           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    4400             :                   "Failed to make request to our cache! [%d][%s]\n",
    4401             :                       ret, strerror(ret));
    4402           0 :             return EIO;
    4403             :         }
    4404             : 
    4405          12 :         if (dctx->res->count == 0 && !dctx->check_provider) {
    4406             :             /* set negative cache only if not result of cache check */
    4407           2 :             ret = sss_ncache_set_user(nctx->rctx->ncache, false, dom, name);
    4408           2 :             if (ret != EOK) {
    4409           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for %s@%s\n",
    4410             :                       name, dom->name);
    4411             :             }
    4412             : 
    4413             :             /* if a multidomain search, try with next */
    4414           2 :             if (cmdctx->check_next) {
    4415           2 :                 dom = get_next_domain(dom, 0);
    4416           2 :                 if (dom) continue;
    4417             :             }
    4418             : 
    4419           2 :             DEBUG(SSSDBG_OP_FAILURE, "No results for initgroups call\n");
    4420             : 
    4421           2 :             return ENOENT;
    4422             :         }
    4423             : 
    4424             :         /* if this is a caching provider (or if we haven't checked the cache
    4425             :          * yet) then verify that the cache is uptodate */
    4426          10 :         if (dctx->check_provider) {
    4427             : 
    4428           7 :             if (cmdctx->name_is_upn) {
    4429           2 :                 extra_flag = EXTRA_NAME_IS_UPN;
    4430           5 :             } else if (DOM_HAS_VIEWS(dom) && (dctx->res->count == 0
    4431           0 :                     || ldb_msg_find_attr_as_string(dctx->res->msgs[0],
    4432             :                                                    OVERRIDE_PREFIX SYSDB_NAME,
    4433             :                                                    NULL) != NULL)) {
    4434           0 :                 extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
    4435             :             } else {
    4436           5 :                 extra_flag = NULL;
    4437             :             }
    4438             : 
    4439           7 :             ret = check_cache(dctx, nctx, dctx->res, SSS_DP_INITGROUPS, name, 0,
    4440             :                               extra_flag, nss_cmd_getby_dp_callback, dctx);
    4441           7 :             if (ret != EOK) {
    4442             :                 /* Anything but EOK means we should reenter the mainloop
    4443             :                  * because we may be refreshing the cache
    4444             :                  */
    4445           5 :                 return ret;
    4446             :             }
    4447             :         }
    4448             : 
    4449           5 :         DEBUG(SSSDBG_TRACE_FUNC,
    4450             :               "Initgroups for [%s@%s] completed\n", name, dom->name);
    4451           5 :         return EOK;
    4452             :     }
    4453             : 
    4454           3 :     DEBUG(SSSDBG_MINOR_FAILURE,
    4455             :           "No matching domain found for [%s], fail!\n", cmdctx->name);
    4456           3 :     return ENOENT;
    4457             : }
    4458             : 
    4459             : /* for now, if we are online, try to always query the backend */
    4460           9 : static int nss_cmd_initgroups(struct cli_ctx *cctx)
    4461             : {
    4462           9 :     return nss_cmd_getbynam(SSS_NSS_INITGR, cctx);
    4463             : }
    4464             : 
    4465           3 : static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
    4466             : {
    4467           3 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    4468           3 :     struct sss_domain_info *dom = dctx->domain;
    4469           3 :     struct cli_ctx *cctx = cmdctx->cctx;
    4470             :     struct sysdb_ctx *sysdb;
    4471             :     struct nss_ctx *nctx;
    4472             :     int ret;
    4473             :     int err;
    4474           3 :     const char *default_attrs[] = {SYSDB_NAME, SYSDB_OBJECTCLASS, SYSDB_SID_STR,
    4475             :                                    ORIGINALAD_PREFIX SYSDB_NAME,
    4476             :                                    ORIGINALAD_PREFIX SYSDB_UIDNUM,
    4477             :                                    ORIGINALAD_PREFIX SYSDB_GIDNUM,
    4478             :                                    ORIGINALAD_PREFIX SYSDB_GECOS,
    4479             :                                    ORIGINALAD_PREFIX SYSDB_HOMEDIR,
    4480             :                                    ORIGINALAD_PREFIX SYSDB_SHELL,
    4481             :                                    SYSDB_UPN,
    4482             :                                    SYSDB_DEFAULT_OVERRIDE_NAME,
    4483             :                                    SYSDB_AD_ACCOUNT_EXPIRES,
    4484             :                                    SYSDB_AD_USER_ACCOUNT_CONTROL,
    4485             :                                    SYSDB_SSH_PUBKEY,
    4486             :                                    SYSDB_USER_CERT,
    4487             :                                    SYSDB_ORIG_DN,
    4488             :                                    SYSDB_ORIG_MEMBEROF,
    4489             :                                    SYSDB_DEFAULT_ATTRS, NULL};
    4490             :     const char **attrs;
    4491           3 :     bool user_found = false;
    4492           3 :     bool group_found = false;
    4493           3 :     struct ldb_message *msg = NULL;
    4494           3 :     char *sysdb_name = NULL;
    4495           3 :     char *name = NULL;
    4496             :     char *req_name;
    4497             :     uint32_t req_id;
    4498             :     enum sss_dp_acct_type req_type;
    4499             : 
    4500           3 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    4501             : 
    4502           3 :     while (dom) {
    4503             : 
    4504           3 :         if (cmdctx->cmd == SSS_NSS_GETSIDBYID) {
    4505             :             /* check that the uid is valid for this domain */
    4506           0 :             if ((dom->id_min && (cmdctx->id < dom->id_min)) ||
    4507           0 :                 (dom->id_max && (cmdctx->id > dom->id_max))) {
    4508           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
    4509             :                       "Uid [%"PRIu32"] does not exist in domain [%s]! "
    4510             :                        "(id out of range)\n",
    4511             :                        cmdctx->id, dom->name);
    4512           0 :                 if (cmdctx->check_next) {
    4513           0 :                     dom = get_next_domain(dom, SSS_GND_DESCEND);
    4514           0 :                     continue;
    4515             :                 }
    4516           0 :                 ret = ENOENT;
    4517           0 :                 goto done;
    4518             :             }
    4519             :         } else {
    4520             :            /* if it is a domainless search, skip domains that require fully
    4521             :             * qualified names instead */
    4522           6 :             while (dom && cmdctx->check_next && dom->fqnames) {
    4523           0 :                 dom = get_next_domain(dom, 0);
    4524             :             }
    4525             : 
    4526           3 :             if (!dom) break;
    4527             :         }
    4528             : 
    4529           3 :         if (dom != dctx->domain) {
    4530             :             /* make sure we reset the check_provider flag when we check
    4531             :              * a new domain */
    4532           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    4533             :         }
    4534             : 
    4535             :         /* make sure to update the dctx if we changed domain */
    4536           3 :         dctx->domain = dom;
    4537             : 
    4538           3 :         if (cmdctx->cmd == SSS_NSS_GETSIDBYID) {
    4539           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%"PRIu32"@%s]\n",
    4540             :                                       cmdctx->id, dom->name);
    4541             : 
    4542           0 :             ret = sss_ncache_check_uid(nctx->rctx->ncache, dom, cmdctx->id);
    4543           0 :             if (ret == EEXIST) {
    4544           0 :                 ret = sss_ncache_check_gid(nctx->rctx->ncache, dom, cmdctx->id);
    4545           0 :                 if (ret == EEXIST) {
    4546           0 :                     DEBUG(SSSDBG_TRACE_FUNC,
    4547             :                           "ID [%"PRIu32"] does not exist in [%s]! (negative cache)\n",
    4548             :                            cmdctx->id, dom->name);
    4549             :                     /* if a multidomain search, try with next, including
    4550             :                      * sub-domains */
    4551           0 :                     if (cmdctx->check_next) {
    4552           0 :                         dom = get_next_domain(dom, SSS_GND_DESCEND);
    4553           0 :                         continue;
    4554             :                     }
    4555             :                     /* There are no further domains. */
    4556           0 :                     ret = ENOENT;
    4557           0 :                     goto done;
    4558             :                 }
    4559             :             }
    4560             : 
    4561             :         } else {
    4562           3 :             talloc_free(name);
    4563           3 :             talloc_zfree(sysdb_name);
    4564             : 
    4565           3 :             name = sss_get_cased_name(cmdctx, cmdctx->name, dom->case_sensitive);
    4566           3 :             if (name == NULL) {
    4567           0 :                 DEBUG(SSSDBG_OP_FAILURE, "sss_get_cased_name failed.\n");
    4568           0 :                 ret = ENOMEM;
    4569           0 :                 goto done;
    4570             :             }
    4571             : 
    4572           3 :             name = sss_reverse_replace_space(dctx, name,
    4573           3 :                                              nctx->rctx->override_space);
    4574           3 :             if (name == NULL) {
    4575           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    4576             :                       "sss_reverse_replace_space failed\n");
    4577           0 :                 ret = ENOMEM;
    4578           0 :                 goto done;
    4579             :             }
    4580             : 
    4581             :             /* For subdomains a fully qualified name is needed for
    4582             :              * sysdb_search_user_by_name and sysdb_search_group_by_name. */
    4583           3 :             if (IS_SUBDOMAIN(dom)) {
    4584           0 :                 sysdb_name = sss_tc_fqname(cmdctx, dom->names, dom, name);
    4585           0 :                 if (sysdb_name == NULL) {
    4586           0 :                     DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
    4587           0 :                     ret = ENOMEM;
    4588           0 :                     goto done;
    4589             :                 }
    4590             :             }
    4591             : 
    4592             : 
    4593             :             /* verify this name has not yet been negatively cached, as user
    4594             :              * and groupm, or has been permanently filtered */
    4595           3 :             ret = sss_ncache_check_user(nctx->rctx->ncache, dom, name);
    4596             : 
    4597           3 :             if (ret == EEXIST) {
    4598           0 :                 ret = sss_ncache_check_group(nctx->rctx->ncache, dom, name);
    4599           0 :                 if (ret == EEXIST) {
    4600             :                     /* if neg cached, return we didn't find it */
    4601           0 :                     DEBUG(SSSDBG_TRACE_FUNC,
    4602             :                           "SID [%s] does not exist in [%s]! (negative cache)\n",
    4603             :                            name, dom->name);
    4604             :                     /* if a multidomain search, try with next */
    4605           0 :                     if (cmdctx->check_next) {
    4606           0 :                         dom = get_next_domain(dom, 0);
    4607           0 :                         continue;
    4608             :                     }
    4609             :                     /* There are no further domains or this was a
    4610             :                      * fully-qualified user request.
    4611             :                      */
    4612           0 :                     ret = ENOENT;
    4613           0 :                     goto done;
    4614             :                 }
    4615             :             }
    4616             : 
    4617           3 :             DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%s@%s]\n",
    4618             :                                       name, dom->name);
    4619             :         }
    4620             : 
    4621             : 
    4622           3 :         sysdb = dom->sysdb;
    4623           3 :         if (sysdb == NULL) {
    4624           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    4625             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    4626           0 :             ret = EIO;
    4627           0 :             goto done;
    4628             :         }
    4629             : 
    4630           3 :         attrs = default_attrs;
    4631           3 :         if (cmdctx->cmd == SSS_NSS_GETORIGBYNAME
    4632           3 :                 && nctx->extra_attributes != NULL) {
    4633           2 :             ret = add_strings_lists(cmdctx, default_attrs,
    4634             :                                     nctx->extra_attributes, false,
    4635             :                                     discard_const(&attrs));
    4636           2 :             if (ret != EOK) {
    4637           0 :                 DEBUG(SSSDBG_OP_FAILURE, "add_strings_lists failed.\n");
    4638           0 :                 goto done;
    4639             :             }
    4640             :         }
    4641             : 
    4642           3 :         if (cmdctx->cmd == SSS_NSS_GETSIDBYID) {
    4643           0 :             ret = sysdb_search_user_by_uid(cmdctx, dom, cmdctx->id, attrs,
    4644             :                                            &msg);
    4645           0 :             if (ret != EOK && ret != ENOENT) {
    4646           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    4647             :                       "Failed to make request to our cache!\n");
    4648           0 :                 ret = EIO;
    4649           0 :                 goto done;
    4650             :             }
    4651             : 
    4652           0 :             if (ret == EOK) {
    4653           0 :                 user_found = true;
    4654             :             } else {
    4655           0 :                 talloc_free(msg);
    4656           0 :                 ret = sysdb_search_group_by_gid(cmdctx, dom, cmdctx->id, attrs,
    4657             :                                                 &msg);
    4658           0 :                 if (ret != EOK && ret != ENOENT) {
    4659           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
    4660             :                           "Failed to make request to our cache!\n");
    4661           0 :                     ret = EIO;
    4662           0 :                     goto done;
    4663             :                 }
    4664             : 
    4665           0 :                 if (ret == EOK) {
    4666           0 :                     group_found = true;
    4667             :                 }
    4668             :             }
    4669             :         } else {
    4670           3 :             ret = sysdb_search_user_by_name(cmdctx, dom,
    4671             :                                             sysdb_name ? sysdb_name : name,
    4672             :                                             attrs, &msg);
    4673           3 :             if (ret != EOK && ret != ENOENT) {
    4674           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    4675             :                       "Failed to make request to our cache!\n");
    4676           0 :                 ret = EIO;
    4677           0 :                 goto done;
    4678             :             }
    4679             : 
    4680           3 :             if (ret == EOK) {
    4681           3 :                 user_found = true;
    4682             :             } else {
    4683           0 :                 talloc_free(msg);
    4684           0 :                 ret = sysdb_search_group_by_name(cmdctx, dom,
    4685             :                                                  sysdb_name ? sysdb_name : name,
    4686             :                                                  attrs, &msg);
    4687           0 :                 if (ret != EOK && ret != ENOENT) {
    4688           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
    4689             :                           "Failed to make request to our cache!\n");
    4690           0 :                     ret = EIO;
    4691           0 :                     goto done;
    4692             :                 }
    4693             : 
    4694           0 :                 if (ret == EOK) {
    4695           0 :                     group_found = true;
    4696             :                 }
    4697             :             }
    4698             :         }
    4699             : 
    4700           3 :         dctx->res = talloc_zero(cmdctx, struct ldb_result);
    4701           3 :         if (dctx->res == NULL) {
    4702           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
    4703           0 :             ret = ENOMEM;
    4704           0 :             goto done;
    4705             :         }
    4706             : 
    4707           3 :         if (user_found || group_found) {
    4708           3 :             dctx->res->count = 1;
    4709           3 :             dctx->res->msgs = talloc_array(dctx->res, struct ldb_message *, 1);
    4710           3 :             if (dctx->res->msgs == NULL) {
    4711           0 :                 DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
    4712           0 :                 ret = ENOMEM;
    4713           0 :                 goto done;
    4714             :             }
    4715           3 :             dctx->res->msgs[0] = talloc_steal(dctx->res, msg);
    4716             :         }
    4717             : 
    4718           3 :         if (dctx->res->count == 0 && !dctx->check_provider) {
    4719           0 :             if (cmdctx->cmd == SSS_NSS_GETSIDBYNAME
    4720           0 :                     || cmdctx->cmd == SSS_NSS_GETORIGBYNAME) {
    4721           0 :                 ret = sss_ncache_set_user(nctx->rctx->ncache, false, dom, name);
    4722           0 :                 if (ret != EOK) {
    4723           0 :                     DEBUG(SSSDBG_MINOR_FAILURE,
    4724             :                           "Cannot set negcache for %s@%s\n", name, dom->name);
    4725             :                 }
    4726             : 
    4727           0 :                 ret = sss_ncache_set_group(nctx->rctx->ncache, false, dom, name);
    4728           0 :                 if (ret != EOK) {
    4729           0 :                     DEBUG(SSSDBG_MINOR_FAILURE,
    4730             :                           "Cannot set negcache for %s@%s\n", name, dom->name);
    4731             :                 }
    4732             :             }
    4733             :             /* if a multidomain search, try with next */
    4734           0 :             if (cmdctx->check_next) {
    4735           0 :                 dom = get_next_domain(dom, SSS_GND_DESCEND);
    4736           0 :                 continue;
    4737             :             }
    4738             : 
    4739           0 :             DEBUG(SSSDBG_OP_FAILURE, "No matching user or group found.\n");
    4740           0 :             ret = ENOENT;
    4741           0 :             goto done;
    4742             :         }
    4743             : 
    4744             :         /* if this is a caching provider (or if we haven't checked the cache
    4745             :          * yet) then verify that the cache is uptodate */
    4746           3 :         if (dctx->check_provider) {
    4747           3 :             if (cmdctx->cmd == SSS_NSS_GETSIDBYID) {
    4748           0 :                 req_name = NULL;
    4749           0 :                 req_id = cmdctx->id;
    4750             :             } else {
    4751           3 :                 req_name = name;
    4752           3 :                 req_id = 0;
    4753             :             }
    4754           3 :             if (user_found) {
    4755           3 :                 req_type = SSS_DP_USER;
    4756           0 :             } else if (group_found) {
    4757           0 :                 req_type = SSS_DP_GROUP;
    4758             :             } else {
    4759           0 :                 req_type = SSS_DP_USER_AND_GROUP;
    4760             :             }
    4761             : 
    4762           3 :             ret = check_cache(dctx, nctx, dctx->res,
    4763             :                               req_type, req_name, req_id, NULL,
    4764             :                               nss_cmd_getby_dp_callback,
    4765             :                               dctx);
    4766           3 :             if (ret != EOK) {
    4767             :                 /* Anything but EOK means we should reenter the mainloop
    4768             :                  * because we may be refreshing the cache
    4769             :                  */
    4770           0 :                 goto done;
    4771             :             }
    4772             :         }
    4773             : 
    4774             :         /* One result found */
    4775           3 :         if (cmdctx->cmd == SSS_NSS_GETSIDBYID) {
    4776           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Returning info for id [%"PRIu32"@%s]\n",
    4777             :                                      cmdctx->id, dom->name);
    4778             :         } else {
    4779           3 :             DEBUG(SSSDBG_TRACE_FUNC, "Returning info for user/group [%s@%s]\n",
    4780             :                                       name, dom->name);
    4781             :         }
    4782             : 
    4783             :         /* Success. Break from the loop and return EOK */
    4784           3 :         ret = EOK;
    4785           3 :         goto done;
    4786             :     }
    4787             : 
    4788             :     /* All domains were tried and none had the entry. */
    4789           0 :     ret = ENOENT;
    4790             : done:
    4791           3 :     if (ret == ENOENT) {
    4792             :         /* The entry was not found, need to set result in negative cache */
    4793           0 :         if (cmdctx->cmd == SSS_NSS_GETSIDBYID) {
    4794           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    4795             :                 "No matching domain found for [%"PRIu32"], fail!\n", cmdctx->id);
    4796           0 :             err = sss_ncache_set_uid(nctx->rctx->ncache, false, NULL, cmdctx->id);
    4797           0 :             if (err != EOK) {
    4798           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    4799             :                     "Cannot set negative cache for UID %"PRIu32"\n", cmdctx->id);
    4800             :             }
    4801             : 
    4802           0 :             err = sss_ncache_set_gid(nctx->rctx->ncache, false, NULL, cmdctx->id);
    4803           0 :             if (err != EOK) {
    4804           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    4805             :                     "Cannot set negative cache for GID %"PRIu32"\n", cmdctx->id);
    4806             :             }
    4807             :         } else {
    4808           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    4809             :                   "No matching domain found for [%s], fail!\n", cmdctx->name);
    4810             :         }
    4811             :     }
    4812           3 :     return ret;
    4813             : }
    4814             : 
    4815           6 : static errno_t nss_cmd_getbysid_search(struct nss_dom_ctx *dctx)
    4816             : {
    4817           6 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    4818           6 :     struct sss_domain_info *dom = dctx->domain;
    4819           6 :     struct cli_ctx *cctx = cmdctx->cctx;
    4820             :     struct sysdb_ctx *sysdb;
    4821             :     struct nss_ctx *nctx;
    4822             :     int ret;
    4823             : 
    4824           6 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    4825             : 
    4826           6 :     DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%s@%s]\n", cmdctx->secid,
    4827             :                                                                dom->name);
    4828             : 
    4829           6 :     sysdb = dom->sysdb;
    4830           6 :     if (sysdb == NULL) {
    4831           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Fatal: Sysdb CTX not found for this " \
    4832             :                                      "domain!\n");
    4833           0 :         return EIO;
    4834             :     }
    4835             : 
    4836             :     /* verify this user has not yet been negatively cached,
    4837             :         * or has been permanently filtered */
    4838           6 :     ret = sss_ncache_check_sid(nctx->rctx->ncache, cmdctx->secid);
    4839           6 :     if (ret == EEXIST) {
    4840           1 :         DEBUG(SSSDBG_TRACE_FUNC,
    4841             :               "SID [%s] does not exist! (negative cache)\n", cmdctx->secid);
    4842           1 :         return ENOENT;
    4843             :     }
    4844             : 
    4845           5 :     ret = sysdb_search_object_by_sid(cmdctx, dom, cmdctx->secid, NULL,
    4846             :                                      &dctx->res);
    4847           5 :     if (ret == ENOENT) {
    4848           2 :         if (!dctx->check_provider) {
    4849           1 :             DEBUG(SSSDBG_OP_FAILURE, "No results for getbysid call.\n");
    4850             : 
    4851             :             /* set negative cache only if not result of cache check */
    4852           1 :             ret = sss_ncache_set_sid(nctx->rctx->ncache, false, cmdctx->secid);
    4853           1 :             if (ret != EOK) {
    4854           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    4855             :                       "Cannot set negative cache for %s\n", cmdctx->secid);
    4856             :             }
    4857             : 
    4858           1 :             return ENOENT;
    4859             :         }
    4860             : 
    4861           1 :         dctx->res = talloc_zero(cmdctx, struct ldb_result);
    4862           1 :         if (dctx->res == NULL) {
    4863           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
    4864           0 :             return ENOMEM;
    4865             :         }
    4866             :         /* Fall through and call the backend */
    4867           3 :     } else if (ret != EOK) {
    4868           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache!\n");
    4869           0 :         return EIO;
    4870             :     }
    4871             : 
    4872           4 :     if (dctx->res->count > 1) {
    4873           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \
    4874             :                                      "result !?!\n");
    4875           0 :         return ENOENT;
    4876             :     }
    4877             : 
    4878             :     /* if this is a caching provider (or if we haven't checked the cache
    4879             :      * yet) then verify that the cache is uptodate */
    4880           4 :     if (dctx->check_provider) {
    4881           3 :         ret = check_cache(dctx, nctx, dctx->res,
    4882           3 :                           SSS_DP_SECID, cmdctx->secid, 0, NULL,
    4883             :                           nss_cmd_getby_dp_callback,
    4884             :                           dctx);
    4885           3 :         if (ret != EOK) {
    4886             :             /* Anything but EOK means we should reenter the mainloop
    4887             :              * because we may be refreshing the cache
    4888             :              */
    4889           2 :             return ret;
    4890             :         }
    4891             :     }
    4892             : 
    4893             :     /* One result found */
    4894           2 :     DEBUG(SSSDBG_TRACE_FUNC, "Returning info for sid [%s@%s]\n", cmdctx->secid,
    4895             :                                                                   dom->name);
    4896             : 
    4897           2 :     return EOK;
    4898             : }
    4899             : 
    4900           5 : static errno_t find_sss_id_type(struct ldb_message *msg,
    4901             :                                 bool mpg,
    4902             :                                 enum sss_id_type *id_type)
    4903             : {
    4904             :     size_t c;
    4905             :     struct ldb_message_element *el;
    4906           5 :     struct ldb_val *val = NULL;
    4907             : 
    4908           5 :     el = ldb_msg_find_element(msg, SYSDB_OBJECTCLASS);
    4909           5 :     if (el == NULL) {
    4910           0 :         DEBUG(SSSDBG_OP_FAILURE, "Objectclass attribute not found.\n");
    4911           0 :         return EINVAL;
    4912             :     }
    4913             : 
    4914           5 :     for (c = 0; c < el->num_values; c++) {
    4915           5 :         val = &(el->values[c]);
    4916          10 :         if (strncasecmp(SYSDB_USER_CLASS,
    4917           5 :                         (char *)val->data, val->length) == 0) {
    4918           5 :             break;
    4919             :         }
    4920             :     }
    4921             : 
    4922           5 :     if (c == el->num_values) {
    4923           0 :         *id_type = SSS_ID_TYPE_GID;
    4924             :     } else {
    4925           5 :         if (mpg) {
    4926           0 :             *id_type = SSS_ID_TYPE_BOTH;
    4927             :         } else {
    4928           5 :             *id_type = SSS_ID_TYPE_UID;
    4929             :         }
    4930             :     }
    4931             : 
    4932           5 :     return EOK;
    4933             : }
    4934             : 
    4935           0 : static errno_t fill_sid(struct sss_packet *packet,
    4936             :                         enum sss_id_type id_type,
    4937             :                         struct ldb_message *msg)
    4938             : {
    4939             :     int ret;
    4940             :     const char *sid_str;
    4941             :     struct sized_string sid;
    4942             :     uint8_t *body;
    4943             :     size_t blen;
    4944           0 :     size_t pctr = 0;
    4945             : 
    4946           0 :     sid_str = ldb_msg_find_attr_as_string(msg, SYSDB_SID_STR, NULL);
    4947           0 :     if (sid_str == NULL) {
    4948           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing SID.\n");
    4949           0 :         return EINVAL;
    4950             :     }
    4951             : 
    4952           0 :     to_sized_string(&sid, sid_str);
    4953             : 
    4954           0 :     ret = sss_packet_grow(packet, sid.len +  3* sizeof(uint32_t));
    4955           0 :     if (ret != EOK) {
    4956           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
    4957           0 :         return ret;
    4958             :     }
    4959             : 
    4960           0 :     sss_packet_get_body(packet, &body, &blen);
    4961           0 :     SAFEALIGN_SETMEM_UINT32(body, 1, &pctr); /* Num results */
    4962           0 :     SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */
    4963           0 :     SAFEALIGN_COPY_UINT32(body + pctr, &id_type, &pctr);
    4964           0 :     memcpy(&body[pctr], sid.str, sid.len);
    4965             : 
    4966           0 :     return EOK;
    4967             : }
    4968             : 
    4969           5 : static errno_t process_attr_list(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    4970             :                                  const char **attr_list,
    4971             :                                  struct sized_string **_keys,
    4972             :                                  struct sized_string **_vals,
    4973             :                                  size_t *array_size, size_t *sum, size_t *found)
    4974             : {
    4975             :     size_t c;
    4976             :     size_t d;
    4977             :     struct sized_string *keys;
    4978             :     struct sized_string *vals;
    4979             :     struct ldb_val val;
    4980             :     struct ldb_message_element *el;
    4981             :     bool use_base64;
    4982             : 
    4983           5 :     keys = *_keys;
    4984           5 :     vals = *_vals;
    4985             : 
    4986          54 :     for (c = 0; attr_list[c] != NULL; c++) {
    4987          49 :         el = ldb_msg_find_element(msg, attr_list[c]);
    4988          49 :         if (el != NULL &&  el->num_values > 0) {
    4989          12 :             if (el->num_values > 1) {
    4990           1 :                 *array_size += el->num_values;
    4991           1 :                 keys = talloc_realloc(mem_ctx, keys, struct sized_string,
    4992             :                                       *array_size);
    4993           1 :                 vals = talloc_realloc(mem_ctx, vals, struct sized_string,
    4994             :                                       *array_size);
    4995           1 :                 if (keys == NULL || vals == NULL) {
    4996           0 :                     DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
    4997           0 :                     return ENOMEM;
    4998             :                 }
    4999             :             }
    5000             : 
    5001          12 :             use_base64 = false;
    5002          12 :             if (strcmp(attr_list[c], SYSDB_USER_CERT) == 0) {
    5003           0 :                 use_base64 = true;
    5004             :             }
    5005          26 :             for (d = 0; d < el->num_values; d++) {
    5006          14 :                 to_sized_string(&keys[*found], attr_list[c]);
    5007          14 :                 *sum += keys[*found].len;
    5008          14 :                 if (use_base64) {
    5009           0 :                     val.data = (uint8_t *) sss_base64_encode(vals,
    5010           0 :                                                           el->values[d].data,
    5011           0 :                                                           el->values[d].length);
    5012           0 :                     if (val.data != NULL) {
    5013           0 :                         val.length = strlen((char *)val.data);
    5014             :                     }
    5015             :                 } else {
    5016          14 :                     val = el->values[d];
    5017             :                 }
    5018          14 :                 if (val.data == NULL || val.data[val.length] != '\0') {
    5019           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
    5020             :                           "Unexpected attribute value found for [%s].\n",
    5021             :                           attr_list[c]);
    5022           0 :                     return EINVAL;
    5023             :                 }
    5024          14 :                 to_sized_string(&vals[*found], (const char *)val.data);
    5025          14 :                 *sum += vals[*found].len;
    5026             : 
    5027          14 :                 (*found)++;
    5028             :             }
    5029             :         }
    5030             :     }
    5031             : 
    5032           5 :     *_keys = keys;
    5033           5 :     *_vals = vals;
    5034             : 
    5035           5 :     return EOK;
    5036             : }
    5037             : 
    5038           3 : static errno_t fill_orig(struct sss_packet *packet,
    5039             :                          struct resp_ctx *rctx,
    5040             :                          enum sss_id_type id_type,
    5041             :                          struct ldb_message *msg)
    5042             : {
    5043             :     int ret;
    5044             :     TALLOC_CTX *tmp_ctx;
    5045             :     uint8_t *body;
    5046             :     size_t blen;
    5047           3 :     size_t pctr = 0;
    5048             :     size_t c;
    5049             :     size_t sum;
    5050             :     size_t found;
    5051             :     size_t array_size;
    5052           3 :     size_t extra_attrs_count = 0;
    5053           3 :     const char **extra_attrs_list = NULL;
    5054           3 :     const char *orig_attr_list[] = {SYSDB_SID_STR,
    5055             :                                     ORIGINALAD_PREFIX SYSDB_NAME,
    5056             :                                     ORIGINALAD_PREFIX SYSDB_UIDNUM,
    5057             :                                     ORIGINALAD_PREFIX SYSDB_GIDNUM,
    5058             :                                     ORIGINALAD_PREFIX SYSDB_HOMEDIR,
    5059             :                                     ORIGINALAD_PREFIX SYSDB_GECOS,
    5060             :                                     ORIGINALAD_PREFIX SYSDB_SHELL,
    5061             :                                     SYSDB_UPN,
    5062             :                                     SYSDB_DEFAULT_OVERRIDE_NAME,
    5063             :                                     SYSDB_AD_ACCOUNT_EXPIRES,
    5064             :                                     SYSDB_AD_USER_ACCOUNT_CONTROL,
    5065             :                                     SYSDB_SSH_PUBKEY,
    5066             :                                     SYSDB_USER_CERT,
    5067             :                                     SYSDB_ORIG_DN,
    5068             :                                     SYSDB_ORIG_MEMBEROF,
    5069             :                                     NULL};
    5070             :     struct sized_string *keys;
    5071             :     struct sized_string *vals;
    5072             :     struct nss_ctx *nctx;
    5073             : 
    5074           3 :     tmp_ctx = talloc_new(NULL);
    5075           3 :     if (tmp_ctx == NULL) {
    5076           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
    5077           0 :         return ENOMEM;
    5078             :     }
    5079             : 
    5080           3 :     nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
    5081           3 :     if (nctx->extra_attributes != NULL) {
    5082           2 :         extra_attrs_list = nctx->extra_attributes;
    5083           8 :             for(extra_attrs_count = 0;
    5084           6 :                 extra_attrs_list[extra_attrs_count] != NULL;
    5085           4 :                 extra_attrs_count++);
    5086             :     }
    5087             : 
    5088           3 :     array_size = sizeof(orig_attr_list) + extra_attrs_count;
    5089           3 :     keys = talloc_array(tmp_ctx, struct sized_string, array_size);
    5090           3 :     vals = talloc_array(tmp_ctx, struct sized_string, array_size);
    5091           3 :     if (keys == NULL || vals == NULL) {
    5092           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
    5093           0 :         ret = ENOMEM;
    5094           0 :         goto done;
    5095             :     }
    5096             : 
    5097           3 :     sum = 0;
    5098           3 :     found = 0;
    5099             : 
    5100           3 :     ret = process_attr_list(tmp_ctx, msg, orig_attr_list, &keys, &vals,
    5101             :                             &array_size, &sum, &found);
    5102           3 :     if (ret != EOK) {
    5103           0 :         DEBUG(SSSDBG_OP_FAILURE, "process_attr_list failed.\n");
    5104           0 :         goto done;
    5105             :     }
    5106             : 
    5107           3 :     if (extra_attrs_count != 0) {
    5108           2 :         ret = process_attr_list(tmp_ctx, msg, extra_attrs_list, &keys, &vals,
    5109             :                                 &array_size, &sum, &found);
    5110           2 :         if (ret != EOK) {
    5111           0 :             DEBUG(SSSDBG_OP_FAILURE, "process_attr_list failed.\n");
    5112           0 :             goto done;
    5113             :         }
    5114             :     }
    5115             : 
    5116           3 :     ret = sss_packet_grow(packet, sum +  3 * sizeof(uint32_t));
    5117           3 :     if (ret != EOK) {
    5118           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
    5119           0 :         goto done;
    5120             :     }
    5121             : 
    5122           3 :     sss_packet_get_body(packet, &body, &blen);
    5123           3 :     SAFEALIGN_SETMEM_UINT32(body, 1, &pctr); /* Num results */
    5124           3 :     SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */
    5125           3 :     SAFEALIGN_COPY_UINT32(body + pctr, &id_type, &pctr);
    5126          17 :     for (c = 0; c < found; c++) {
    5127          14 :         memcpy(&body[pctr], keys[c].str, keys[c].len);
    5128          14 :         pctr+= keys[c].len;
    5129          14 :         memcpy(&body[pctr], vals[c].str, vals[c].len);
    5130          14 :         pctr+= vals[c].len;
    5131             :     }
    5132             : 
    5133           3 :     ret = EOK;
    5134             : 
    5135             : done:
    5136           3 :     talloc_free(tmp_ctx);
    5137             : 
    5138           3 :     return ret;
    5139             : }
    5140             : 
    5141           3 : static errno_t fill_name(struct sss_packet *packet,
    5142             :                          struct sss_domain_info *dom,
    5143             :                          enum sss_id_type id_type,
    5144             :                          bool apply_no_view,
    5145             :                          struct ldb_message *msg)
    5146             : {
    5147             :     int ret;
    5148           3 :     TALLOC_CTX *tmp_ctx = NULL;
    5149           3 :     const char *orig_name = NULL;
    5150             :     const char *cased_name;
    5151             :     const char *fq_name;
    5152             :     struct sized_string name;
    5153           3 :     bool add_domain = (!IS_SUBDOMAIN(dom) && dom->fqnames);
    5154             :     uint8_t *body;
    5155             :     size_t blen;
    5156           3 :     size_t pctr = 0;
    5157             : 
    5158           3 :     if (apply_no_view) {
    5159           3 :         orig_name = ldb_msg_find_attr_as_string(msg,
    5160             :                                                 ORIGINALAD_PREFIX SYSDB_NAME,
    5161             :                                                 NULL);
    5162             :     } else {
    5163           0 :         if (DOM_HAS_VIEWS(dom)) {
    5164           0 :             orig_name = ldb_msg_find_attr_as_string(msg,
    5165             :                                                     OVERRIDE_PREFIX SYSDB_NAME,
    5166             :                                                     NULL);
    5167           0 :             if (orig_name != NULL && IS_SUBDOMAIN(dom)) {
    5168             :                 /* Override names are un-qualified */
    5169           0 :                 add_domain = true;
    5170             :             }
    5171             :         }
    5172             :     }
    5173             : 
    5174           3 :     if (orig_name == NULL) {
    5175           3 :         orig_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
    5176             :     }
    5177           3 :     if (orig_name == NULL) {
    5178           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing name.\n");
    5179           0 :         return EINVAL;
    5180             :     }
    5181             : 
    5182           3 :     tmp_ctx = talloc_new(NULL);
    5183           3 :     if (tmp_ctx == NULL) {
    5184           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
    5185           0 :         return ENOMEM;
    5186             :     }
    5187             : 
    5188           3 :     cased_name= sss_get_cased_name(tmp_ctx, orig_name, dom->case_sensitive);
    5189           3 :     if (cased_name == NULL) {
    5190           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_get_cased_name failed.\n");
    5191           0 :         ret = ENOMEM;
    5192           0 :         goto done;
    5193             :     }
    5194             : 
    5195           3 :     if (add_domain) {
    5196           0 :         fq_name = sss_tc_fqname(tmp_ctx, dom->names, dom, cased_name);
    5197           0 :         if (fq_name == NULL) {
    5198           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
    5199           0 :             ret = ENOMEM;
    5200           0 :             goto done;
    5201             :         }
    5202           0 :         to_sized_string(&name, fq_name);
    5203             :     } else {
    5204           3 :         to_sized_string(&name, cased_name);
    5205             :     }
    5206             : 
    5207           3 :     ret = sss_packet_grow(packet, name.len + 3 * sizeof(uint32_t));
    5208           3 :     if (ret != EOK) {
    5209           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
    5210           0 :         goto done;
    5211             :     }
    5212             : 
    5213           3 :     sss_packet_get_body(packet, &body, &blen);
    5214           3 :     SAFEALIGN_SETMEM_UINT32(body, 1, &pctr); /* Num results */
    5215           3 :     SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */
    5216           3 :     SAFEALIGN_COPY_UINT32(body + pctr, &id_type, &pctr);
    5217           3 :     memcpy(&body[pctr], name.str, name.len);
    5218             : 
    5219             : 
    5220           3 :     ret = EOK;
    5221             : 
    5222             : done:
    5223           3 :     talloc_free(tmp_ctx);
    5224             : 
    5225           3 :     return ret;
    5226             : }
    5227             : 
    5228           0 : static errno_t fill_id(struct sss_packet *packet,
    5229             :                        enum sss_id_type id_type,
    5230             :                        struct ldb_message *msg)
    5231             : {
    5232             :     int ret;
    5233             :     uint8_t *body;
    5234             :     size_t blen;
    5235           0 :     size_t pctr = 0;
    5236             :     uint64_t tmp_id;
    5237             :     uint32_t id;
    5238             : 
    5239           0 :     if (id_type == SSS_ID_TYPE_GID) {
    5240           0 :         tmp_id = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
    5241             :     } else {
    5242           0 :         tmp_id = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
    5243             :     }
    5244             : 
    5245           0 :     if (tmp_id == 0 || tmp_id >= UINT32_MAX) {
    5246           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid POSIX ID.\n");
    5247           0 :         return EINVAL;
    5248             :     }
    5249           0 :     id = (uint32_t) tmp_id;
    5250             : 
    5251           0 :     ret = sss_packet_grow(packet, 4 * sizeof(uint32_t));
    5252           0 :     if (ret != EOK) {
    5253           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
    5254           0 :         return ret;
    5255             :     }
    5256             : 
    5257           0 :     sss_packet_get_body(packet, &body, &blen);
    5258           0 :     SAFEALIGN_SETMEM_UINT32(body, 1, &pctr); /* Num results */
    5259           0 :     SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */
    5260           0 :     SAFEALIGN_COPY_UINT32(body + pctr, &id_type, &pctr);
    5261           0 :     SAFEALIGN_COPY_UINT32(body + pctr, &id, &pctr);
    5262             : 
    5263           0 :     return EOK;
    5264             : }
    5265             : 
    5266           5 : static errno_t nss_cmd_getbysid_send_reply(struct nss_dom_ctx *dctx)
    5267             : {
    5268           5 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
    5269           5 :     struct cli_ctx *cctx = cmdctx->cctx;
    5270             :     int ret;
    5271             :     enum sss_id_type id_type;
    5272             : 
    5273           5 :     if (dctx->res->count > 1) {
    5274           0 :         return EINVAL;
    5275           5 :     } else if (dctx->res->count == 0) {
    5276           0 :         return ENOENT;
    5277             :     }
    5278             : 
    5279          10 :     ret = sss_packet_new(cctx->creq, 0,
    5280           5 :                          sss_packet_get_cmd(cctx->creq->in),
    5281           5 :                          &cctx->creq->out);
    5282           5 :     if (ret != EOK) {
    5283           0 :         return EFAULT;
    5284             :     }
    5285             : 
    5286           5 :     ret = find_sss_id_type(dctx->res->msgs[0], dctx->domain->mpg, &id_type);
    5287           5 :     if (ret != 0) {
    5288           0 :         DEBUG(SSSDBG_OP_FAILURE, "find_sss_id_type failed.\n");
    5289           0 :         return ret;
    5290             :     }
    5291             : 
    5292           5 :     switch(cmdctx->cmd) {
    5293             :     case SSS_NSS_GETNAMEBYSID:
    5294           2 :         ret = fill_name(cctx->creq->out,
    5295             :                         dctx->domain,
    5296             :                         id_type,
    5297             :                         true,
    5298           2 :                         dctx->res->msgs[0]);
    5299           2 :         break;
    5300             :     case SSS_NSS_GETIDBYSID:
    5301           0 :         ret = fill_id(cctx->creq->out, id_type, dctx->res->msgs[0]);
    5302           0 :         break;
    5303             :     case SSS_NSS_GETSIDBYNAME:
    5304             :     case SSS_NSS_GETSIDBYID:
    5305           0 :         ret = fill_sid(cctx->creq->out, id_type, dctx->res->msgs[0]);
    5306           0 :         break;
    5307             :     case SSS_NSS_GETORIGBYNAME:
    5308           3 :         ret = fill_orig(cctx->creq->out, cctx->rctx, id_type,
    5309           3 :                         dctx->res->msgs[0]);
    5310           3 :         break;
    5311             :     default:
    5312           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported request type.\n");
    5313           0 :         return EINVAL;
    5314             :     }
    5315           5 :     if (ret != EOK) {
    5316           0 :         return ret;
    5317             :     }
    5318             : 
    5319           5 :     sss_packet_set_error(cctx->creq->out, EOK);
    5320           5 :     sss_cmd_done(cctx, cmdctx);
    5321           5 :     return EOK;
    5322             : }
    5323             : 
    5324           8 : static int nss_check_well_known_sid(struct nss_cmd_ctx *cmdctx)
    5325             : {
    5326             :     const char *wk_name;
    5327             :     const char *wk_dom_name;
    5328             :     int ret;
    5329           8 :     char *fq_name = NULL;
    5330             :     struct sized_string name;
    5331             :     uint8_t *body;
    5332             :     size_t blen;
    5333             :     struct cli_ctx *cctx;
    5334             :     struct nss_ctx *nss_ctx;
    5335           8 :     size_t pctr = 0;
    5336             : 
    5337           8 :     ret = well_known_sid_to_name(cmdctx->secid, &wk_dom_name, &wk_name);
    5338           8 :     if (ret != EOK) {
    5339           5 :         DEBUG(SSSDBG_TRACE_ALL, "SID [%s] is not a Well-Known SID.\n",
    5340             :                                  cmdctx->secid);
    5341           5 :         return ret;
    5342             :     }
    5343             : 
    5344           3 :     if (cmdctx->cmd != SSS_NSS_GETNAMEBYSID) {
    5345           1 :         DEBUG(SSSDBG_TRACE_ALL,
    5346             :               "Well-Known SIDs can only be translated to names.\n");
    5347           1 :         return EINVAL;
    5348             :     }
    5349             : 
    5350           2 :     if (wk_dom_name != NULL) {
    5351           2 :         nss_ctx = talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct nss_ctx);
    5352           2 :         fq_name = sss_tc_fqname2(cmdctx, nss_ctx->global_names,
    5353             :                                  wk_dom_name, wk_dom_name, wk_name);
    5354           2 :         if (fq_name == NULL) {
    5355           0 :             DEBUG(SSSDBG_OP_FAILURE, "sss_tc_fqname2 failed.\n");
    5356           0 :             return ENOMEM;
    5357             :         }
    5358           2 :         to_sized_string(&name, fq_name);
    5359             :     } else {
    5360           0 :         to_sized_string(&name, wk_name);
    5361             :     }
    5362             : 
    5363           2 :     cctx = cmdctx->cctx;
    5364           4 :     ret = sss_packet_new(cctx->creq, name.len + 3 * sizeof(uint32_t),
    5365           2 :                          sss_packet_get_cmd(cctx->creq->in),
    5366           2 :                          &cctx->creq->out);
    5367           2 :     if (ret != EOK) {
    5368           0 :         talloc_free(fq_name);
    5369           0 :         return ENOMEM;
    5370             :     }
    5371             : 
    5372           2 :     sss_packet_get_body(cctx->creq->out, &body, &blen);
    5373           2 :     SAFEALIGN_SETMEM_UINT32(body, 1, &pctr); /* num results */
    5374           2 :     SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */
    5375           2 :     SAFEALIGN_SETMEM_UINT32(body + pctr, SSS_ID_TYPE_GID, &pctr);
    5376           2 :     memcpy(&body[pctr], name.str, name.len);
    5377             : 
    5378           2 :     sss_packet_set_error(cctx->creq->out, EOK);
    5379           2 :     sss_cmd_done(cctx, cmdctx);
    5380           2 :     return EOK;
    5381             : }
    5382             : 
    5383           8 : static int nss_cmd_getbysid(enum sss_cli_command cmd, struct cli_ctx *cctx)
    5384             : {
    5385             : 
    5386             :     struct tevent_req *req;
    5387             :     struct nss_cmd_ctx *cmdctx;
    5388             :     struct nss_dom_ctx *dctx;
    5389             :     const char *sid_str;
    5390             :     uint8_t *body;
    5391             :     size_t blen;
    5392             :     int ret;
    5393             :     struct nss_ctx *nctx;
    5394             :     enum idmap_error_code err;
    5395           8 :     uint8_t *bin_sid = NULL;
    5396             :     size_t bin_sid_length;
    5397             : 
    5398           8 :     if (cmd != SSS_NSS_GETNAMEBYSID && cmd != SSS_NSS_GETIDBYSID) {
    5399           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command type [%d][%s].\n",
    5400             :               cmd, sss_cmd2str(cmd));
    5401           0 :         return EINVAL;
    5402             :     }
    5403             : 
    5404           8 :     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);
    5405           8 :     if (!cmdctx) {
    5406           0 :         return ENOMEM;
    5407             :     }
    5408           8 :     cmdctx->cctx = cctx;
    5409           8 :     cmdctx->cmd = cmd;
    5410             : 
    5411           8 :     dctx = talloc_zero(cmdctx, struct nss_dom_ctx);
    5412           8 :     if (!dctx) {
    5413           0 :         ret = ENOMEM;
    5414           0 :         goto done;
    5415             :     }
    5416           8 :     dctx->cmdctx = cmdctx;
    5417             : 
    5418             :     /* get SID to query */
    5419           8 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
    5420             : 
    5421             :     /* if not terminated fail */
    5422           8 :     if (body[blen -1] != '\0') {
    5423           0 :         ret = EINVAL;
    5424           0 :         goto done;
    5425             :     }
    5426             : 
    5427           8 :     sid_str = (const char *) body;
    5428             : 
    5429           8 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    5430             : 
    5431             :     /* If the body isn't a SID, fail */
    5432           8 :     err = sss_idmap_sid_to_bin_sid(nctx->idmap_ctx, sid_str,
    5433             :                                    &bin_sid, &bin_sid_length);
    5434           8 :     sss_idmap_free_bin_sid(nctx->idmap_ctx, bin_sid);
    5435           8 :     if (err != IDMAP_SUCCESS) {
    5436           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_sid_to_bin_sid failed for [%s].\n",
    5437             :                                   body);
    5438           0 :         ret = EINVAL;
    5439           0 :         goto done;
    5440             :     }
    5441             : 
    5442           8 :     DEBUG(SSSDBG_TRACE_FUNC, "Running command [%d][%s] with SID [%s].\n",
    5443             :           dctx->cmdctx->cmd, sss_cmd2str(dctx->cmdctx->cmd), sid_str);
    5444             : 
    5445           8 :     cmdctx->secid = talloc_strdup(cmdctx, sid_str);
    5446           8 :     if (cmdctx->secid == NULL) {
    5447           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
    5448           0 :         ret = ENOMEM;
    5449           0 :         goto done;
    5450             :     }
    5451             : 
    5452           8 :     ret = nss_check_well_known_sid(cmdctx);
    5453           8 :     switch (ret) {
    5454             :     case EOK:
    5455           2 :         DEBUG(SSSDBG_TRACE_ALL, "SID [%s] is a Well-Known SID.\n", sid_str);
    5456             :         /* message is already send and cmdctx is freed, we can just return */
    5457           2 :         return EOK;
    5458             :         break;
    5459             :     case ENOENT:
    5460           4 :         break;
    5461             :     default:
    5462           2 :         DEBUG(SSSDBG_OP_FAILURE, "nss_check_well_known_sid failed.\n");
    5463           2 :         goto done;
    5464             :     }
    5465             : 
    5466           4 :     ret = responder_get_domain_by_id(cctx->rctx, cmdctx->secid, &dctx->domain);
    5467           4 :     if (ret == EAGAIN || ret == ENOENT) {
    5468           0 :         req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, NULL);
    5469           0 :         if (req == NULL) {
    5470           0 :             ret = ENOMEM;
    5471             :         } else {
    5472           0 :             dctx->rawname = sid_str;
    5473           0 :             tevent_req_set_callback(req, nss_cmd_getbyid_done, dctx);
    5474           0 :             ret = EAGAIN;
    5475             :         }
    5476           0 :         goto done;
    5477           4 :     } else if (ret != EOK) {
    5478           0 :         DEBUG(SSSDBG_OP_FAILURE, "responder_get_domain_by_id failed.\n");
    5479           0 :         goto done;
    5480             :     }
    5481             : 
    5482           4 :     DEBUG(SSSDBG_CONF_SETTINGS, "Requesting info for [%s] from [%s]\n",
    5483             :               cmdctx->secid, dctx->domain->name);
    5484             : 
    5485           4 :     dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
    5486             : 
    5487             :     /* ok, find it ! */
    5488           4 :     ret = nss_cmd_getbysid_search(dctx);
    5489           4 :     if (ret == EOK) {
    5490           1 :         ret = nss_cmd_getbysid_send_reply(dctx);
    5491             :     }
    5492             : 
    5493             : done:
    5494           6 :     return nss_cmd_done(cmdctx, ret);
    5495             : }
    5496             : 
    5497             : static void users_find_by_cert_done(struct tevent_req *req);
    5498             : 
    5499           3 : static int nss_cmd_getbycert(enum sss_cli_command cmd, struct cli_ctx *cctx)
    5500             : {
    5501             : 
    5502             :     struct tevent_req *req;
    5503             :     uint8_t *body;
    5504             :     size_t blen;
    5505             :     int ret;
    5506             :     const char *derb64;
    5507           3 :     char *pem_cert = NULL;
    5508             :     size_t pem_size;
    5509             :     struct nss_ctx *nctx;
    5510             : 
    5511           3 :     nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
    5512             : 
    5513           3 :     if (cmd != SSS_NSS_GETNAMEBYCERT) {
    5514           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command type [%d][%s].\n",
    5515             :               cmd, sss_cmd2str(cmd));
    5516           0 :         return EINVAL;
    5517             :     }
    5518             : 
    5519             :     /* get certificate to query */
    5520           3 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
    5521             : 
    5522             :     /* if not terminated fail */
    5523           3 :     if (body[blen - 1] != '\0') {
    5524           0 :         return EINVAL;
    5525             :     }
    5526             : 
    5527           3 :     derb64 = (const char *)body;
    5528           3 :     DEBUG(SSSDBG_TRACE_ALL, "cert [%s]\n", derb64);
    5529             : 
    5530             :     /* check input */
    5531           3 :     ret = sss_cert_derb64_to_pem(cctx, derb64, &pem_cert, &pem_size);
    5532           3 :     talloc_free(pem_cert);
    5533           3 :     if (ret != EOK) {
    5534           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_cert_pem_to_derb64 failed.\n");
    5535           0 :         return ret;
    5536             :     }
    5537             : 
    5538           3 :     req = cache_req_user_by_cert_send(cctx, cctx->rctx->ev, cctx->rctx,
    5539           3 :                                       nctx->rctx->ncache, 0, NULL, derb64);
    5540           3 :     if (req == NULL) {
    5541           0 :         return ENOMEM;
    5542             :     }
    5543             : 
    5544           3 :     tevent_req_set_callback(req, users_find_by_cert_done, cctx);
    5545             : 
    5546           3 :     return EOK;
    5547             : }
    5548             : 
    5549           3 : static void users_find_by_cert_done(struct tevent_req *req)
    5550             : {
    5551             :     struct cli_ctx *cctx;
    5552             :     struct sss_domain_info *domain;
    5553             :     struct ldb_result *result;
    5554             :     errno_t ret;
    5555             : 
    5556           3 :     cctx = tevent_req_callback_data(req, struct cli_ctx);
    5557             : 
    5558           3 :     ret = cache_req_user_by_cert_recv(cctx, req, &result, &domain, NULL);
    5559           3 :     talloc_zfree(req);
    5560           3 :     if (ret == ENOENT || result->count == 0) {
    5561           2 :         ret = ENOENT;
    5562           2 :         goto done;
    5563           1 :     } else if (ret != EOK) {
    5564           0 :         goto done;
    5565             :     }
    5566             : 
    5567           1 :     if (result->count > 1) {
    5568           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    5569             :               "Found more than 1 result with certficate search.\n");
    5570             : 
    5571           0 :         ret = EINVAL;
    5572           0 :         goto done;
    5573             :     }
    5574             : 
    5575           2 :     ret = sss_packet_new(cctx->creq, 0,
    5576           1 :                          sss_packet_get_cmd(cctx->creq->in),
    5577           1 :                          &cctx->creq->out);
    5578           1 :     if (ret != EOK) {
    5579           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_packet_new failed.\n");
    5580           0 :         ret = EFAULT;
    5581           0 :         goto done;
    5582             :     }
    5583             : 
    5584           1 :     ret = fill_name(cctx->creq->out, domain, SSS_ID_TYPE_UID, true,
    5585           1 :                     result->msgs[0]);
    5586           1 :     if (ret != EOK) {
    5587           0 :         DEBUG(SSSDBG_OP_FAILURE, "fill_name failed.\n");
    5588           0 :         goto done;
    5589             :     }
    5590             : 
    5591           1 :     ret = EOK;
    5592             : 
    5593             : done:
    5594           3 :     if (ret == EOK) {
    5595           1 :         sss_packet_set_error(cctx->creq->out, EOK);
    5596           1 :         sss_cmd_done(cctx, NULL);
    5597           2 :     } else if (ret == ENOENT) {
    5598           2 :         sss_cmd_send_empty(cctx, NULL);
    5599             :     } else {
    5600           0 :         sss_cmd_send_error(cctx, ret);
    5601             :     }
    5602             : 
    5603           3 :     return;
    5604             : }
    5605             : 
    5606           6 : static int nss_cmd_getsidbyname(struct cli_ctx *cctx)
    5607             : {
    5608           6 :     return nss_cmd_getbynam(SSS_NSS_GETSIDBYNAME, cctx);
    5609             : }
    5610             : 
    5611           0 : static int nss_cmd_getsidbyid(struct cli_ctx *cctx)
    5612             : {
    5613           0 :     return nss_cmd_getbyid(SSS_NSS_GETSIDBYID, cctx);
    5614             : }
    5615             : 
    5616           7 : static int nss_cmd_getnamebysid(struct cli_ctx *cctx)
    5617             : {
    5618           7 :     return nss_cmd_getbysid(SSS_NSS_GETNAMEBYSID, cctx);
    5619             : }
    5620             : 
    5621           1 : static int nss_cmd_getidbysid(struct cli_ctx *cctx)
    5622             : {
    5623           1 :     return nss_cmd_getbysid(SSS_NSS_GETIDBYSID, cctx);
    5624             : }
    5625             : 
    5626           3 : static int nss_cmd_getorigbyname(struct cli_ctx *cctx)
    5627             : {
    5628           3 :     return nss_cmd_getbynam(SSS_NSS_GETORIGBYNAME, cctx);
    5629             : }
    5630             : 
    5631           3 : static int nss_cmd_getnamebycert(struct cli_ctx *cctx)
    5632             : {
    5633           3 :     return nss_cmd_getbycert(SSS_NSS_GETNAMEBYCERT, cctx);
    5634             : }
    5635             : 
    5636           0 : struct cli_protocol_version *register_cli_protocol_version(void)
    5637             : {
    5638             :     static struct cli_protocol_version nss_cli_protocol_version[] = {
    5639             :         {1, "2008-09-05", "initial version, \\0 terminated strings"},
    5640             :         {0, NULL, NULL}
    5641             :     };
    5642             : 
    5643           0 :     return nss_cli_protocol_version;
    5644             : }
    5645             : 
    5646             : static struct sss_cmd_table nss_cmds[] = {
    5647             :     {SSS_GET_VERSION, sss_cmd_get_version},
    5648             :     {SSS_NSS_GETPWNAM, nss_cmd_getpwnam},
    5649             :     {SSS_NSS_GETPWUID, nss_cmd_getpwuid},
    5650             :     {SSS_NSS_SETPWENT, nss_cmd_setpwent},
    5651             :     {SSS_NSS_GETPWENT, nss_cmd_getpwent},
    5652             :     {SSS_NSS_ENDPWENT, nss_cmd_endpwent},
    5653             :     {SSS_NSS_GETGRNAM, nss_cmd_getgrnam},
    5654             :     {SSS_NSS_GETGRGID, nss_cmd_getgrgid},
    5655             :     {SSS_NSS_SETGRENT, nss_cmd_setgrent},
    5656             :     {SSS_NSS_GETGRENT, nss_cmd_getgrent},
    5657             :     {SSS_NSS_ENDGRENT, nss_cmd_endgrent},
    5658             :     {SSS_NSS_INITGR, nss_cmd_initgroups},
    5659             :     {SSS_NSS_SETNETGRENT, nss_cmd_setnetgrent},
    5660             :     {SSS_NSS_GETNETGRENT, nss_cmd_getnetgrent},
    5661             :     {SSS_NSS_ENDNETGRENT, nss_cmd_endnetgrent},
    5662             :     {SSS_NSS_GETSERVBYNAME, nss_cmd_getservbyname},
    5663             :     {SSS_NSS_GETSERVBYPORT, nss_cmd_getservbyport},
    5664             :     {SSS_NSS_SETSERVENT, nss_cmd_setservent},
    5665             :     {SSS_NSS_GETSERVENT, nss_cmd_getservent},
    5666             :     {SSS_NSS_ENDSERVENT, nss_cmd_endservent},
    5667             :     {SSS_NSS_GETSIDBYNAME, nss_cmd_getsidbyname},
    5668             :     {SSS_NSS_GETSIDBYID, nss_cmd_getsidbyid},
    5669             :     {SSS_NSS_GETNAMEBYSID, nss_cmd_getnamebysid},
    5670             :     {SSS_NSS_GETIDBYSID, nss_cmd_getidbysid},
    5671             :     {SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname},
    5672             :     {SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert},
    5673             :     {SSS_CLI_NULL, NULL}
    5674             : };
    5675             : 
    5676          46 : struct sss_cmd_table *get_nss_cmds(void) {
    5677          46 :     return nss_cmds;
    5678             : }

Generated by: LCOV version 1.10