LCOV - code coverage report
Current view: top level - responder/nss - nsssrv_netgroup.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 515 0.0 %
Date: 2016-06-29 Functions: 0 20 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     nsssrv_netgroup.c
       5             : 
       6             :     Authors:
       7             :         Stephen Gallagher <sgallagh@redhat.com>
       8             : 
       9             :     Copyright (C) 2010 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : 
      26             : #include "util/util.h"
      27             : #include "responder/nss/nsssrv.h"
      28             : #include "responder/nss/nsssrv_private.h"
      29             : #include "responder/nss/nsssrv_netgroup.h"
      30             : #include "responder/common/negcache.h"
      31             : #include "confdb/confdb.h"
      32             : #include "db/sysdb.h"
      33             : 
      34           0 : static errno_t get_netgroup_entry(struct nss_ctx *nctx,
      35             :                                   char *name,
      36             :                                   struct getent_ctx **netgr)
      37             : {
      38             :     hash_key_t key;
      39             :     hash_value_t value;
      40             :     int hret;
      41             : 
      42           0 :     key.type = HASH_KEY_STRING;
      43           0 :     key.str = name;
      44             : 
      45           0 :     hret = hash_lookup(nctx->netgroups, &key, &value);
      46           0 :     if (hret == HASH_SUCCESS) {
      47           0 :         *netgr = talloc_get_type(value.ptr, struct getent_ctx);
      48           0 :         return EOK;
      49           0 :     } else if (hret == HASH_ERROR_KEY_NOT_FOUND) {
      50           0 :         return ENOENT;
      51             :     }
      52             : 
      53           0 :     DEBUG(SSSDBG_CRIT_FAILURE,
      54             :           "Unexpected error reading from netgroup hash [%d][%s]\n",
      55             :               hret, hash_error_string(hret));
      56           0 :     return EIO;
      57             : }
      58             : 
      59             : static int netgr_hash_remove(TALLOC_CTX *ctx);
      60           0 : static errno_t set_netgroup_entry(struct nss_ctx *nctx,
      61             :                                   struct getent_ctx *netgr)
      62             : {
      63             :     hash_key_t key;
      64             :     hash_value_t value;
      65             :     int hret;
      66             : 
      67           0 :     if (netgr->name == NULL) {
      68           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing netgroup name.\n");
      69           0 :         return EINVAL;
      70             :     }
      71             :     /* Add this entry to the hash table */
      72           0 :     key.type = HASH_KEY_STRING;
      73           0 :     key.str = netgr->name;
      74           0 :     value.type = HASH_VALUE_PTR;
      75           0 :     value.ptr = netgr;
      76           0 :     hret = hash_enter(nctx->netgroups, &key, &value);
      77           0 :     if (hret != EOK) {
      78           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
      79             :               "Unable to add hash table entry for [%s]\n", key.str);
      80           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
      81             :               "Hash error [%d][%s]\n", hret, hash_error_string(hret));
      82           0 :         return EIO;
      83             :     }
      84           0 :     talloc_steal(nctx->netgroups, netgr);
      85           0 :     talloc_set_destructor((TALLOC_CTX *) netgr, netgr_hash_remove);
      86             : 
      87           0 :     return EOK;
      88             : }
      89             : 
      90             : static struct tevent_req *setnetgrent_send(TALLOC_CTX *mem_ctx,
      91             :                                            const char *rawname,
      92             :                                            struct nss_cmd_ctx *cmdctx);
      93             : static void nss_cmd_setnetgrent_done(struct tevent_req *req);
      94           0 : int nss_cmd_setnetgrent(struct cli_ctx *client)
      95             : {
      96             :     struct nss_cmd_ctx *cmdctx;
      97             :     struct tevent_req *req;
      98             :     const char *rawname;
      99             :     uint8_t *body;
     100             :     size_t blen;
     101           0 :     errno_t ret = EOK;
     102             : 
     103             :     /* Reset the result cursor to zero */
     104           0 :     client->netgrent_cur = 0;
     105             : 
     106           0 :     cmdctx = talloc_zero(client, struct nss_cmd_ctx);
     107           0 :     if (!cmdctx) {
     108           0 :         return ENOMEM;
     109             :     }
     110           0 :     cmdctx->cctx = client;
     111             : 
     112             :     /* get netgroup name to query */
     113           0 :     sss_packet_get_body(client->creq->in, &body, &blen);
     114             : 
     115             :     /* if not terminated fail */
     116           0 :     if (body[blen -1] != '\0') {
     117           0 :         ret = EINVAL;
     118           0 :         goto done;
     119             :     }
     120             : 
     121             :     /* If the body isn't valid UTF-8, fail */
     122           0 :     if (!sss_utf8_check(body, blen -1)) {
     123           0 :         ret = EINVAL;
     124           0 :         goto done;
     125             :     }
     126             : 
     127           0 :     rawname = (const char *)body;
     128             : 
     129           0 :     req = setnetgrent_send(cmdctx, rawname, cmdctx);
     130           0 :     if (!req) {
     131           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error calling setnetgrent_send\n");
     132           0 :         ret = EIO;
     133           0 :         goto done;
     134             :     }
     135           0 :     tevent_req_set_callback(req, nss_cmd_setnetgrent_done, cmdctx);
     136             : 
     137             : done:
     138           0 :     return nss_cmd_done(cmdctx, ret);
     139             : }
     140             : 
     141           0 : static int netgr_hash_remove(TALLOC_CTX *ctx)
     142             : {
     143             :     int hret;
     144             :     hash_key_t key;
     145           0 :     struct getent_ctx *netgr =
     146             :             talloc_get_type(ctx, struct getent_ctx);
     147             : 
     148           0 :     if (netgr->lookup_table == NULL) {
     149           0 :         DEBUG(SSSDBG_TRACE_LIBS, "netgroup [%s] was already removed\n",
     150             :                                   netgr->name);
     151           0 :         return EOK;
     152             :     }
     153             : 
     154           0 :     key.type = HASH_KEY_STRING;
     155           0 :     key.str = netgr->name;
     156             : 
     157             :     /* Remove the netgroup result object from the lookup table */
     158           0 :     hret = hash_delete(netgr->lookup_table, &key);
     159           0 :     if (hret != HASH_SUCCESS) {
     160           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     161             :               "Could not remove key [%s] from table! [%d][%s]\n",
     162             :                   netgr->name, hret, hash_error_string(hret));
     163           0 :         return -1;
     164             :     }
     165           0 :     return 0;
     166             : }
     167             : 
     168             : struct setnetgrent_ctx {
     169             :     struct nss_ctx *nctx;
     170             :     struct nss_cmd_ctx *cmdctx;
     171             :     struct nss_dom_ctx *dctx;
     172             :     char *netgr_shortname;
     173             :     struct getent_ctx *netgr;
     174             :     const char *rawname;
     175             : };
     176             : static errno_t setnetgrent_retry(struct tevent_req *req);
     177             : static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx);
     178           0 : static struct tevent_req *setnetgrent_send(TALLOC_CTX *mem_ctx,
     179             :                                            const char *rawname,
     180             :                                            struct nss_cmd_ctx *cmdctx)
     181             : {
     182             :     char *domname;
     183             :     errno_t ret;
     184             :     struct tevent_req *req;
     185             :     struct setnetgrent_ctx *state;
     186             :     struct nss_dom_ctx *dctx;
     187             : 
     188           0 :     struct cli_ctx *client = cmdctx->cctx;
     189           0 :     struct nss_ctx *nctx =
     190           0 :             talloc_get_type(client->rctx->pvt_ctx, struct nss_ctx);
     191             : 
     192           0 :     req = tevent_req_create(mem_ctx, &state, struct setnetgrent_ctx);
     193           0 :     if (!req) {
     194           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     195             :               "Could not create tevent request for setnetgrent\n");
     196           0 :         return NULL;
     197             :     }
     198             : 
     199           0 :     state->nctx = nctx;
     200           0 :     state->cmdctx = cmdctx;
     201           0 :     state->rawname = rawname;
     202             : 
     203           0 :     state->dctx = talloc_zero(state, struct nss_dom_ctx);
     204           0 :     if (!state->dctx) {
     205           0 :         ret = ENOMEM;
     206           0 :         goto error;
     207             :     }
     208           0 :     dctx = state->dctx;
     209           0 :     dctx->cmdctx = state->cmdctx;
     210             : 
     211           0 :     ret = sss_parse_name_for_domains(state, client->rctx->domains,
     212             :                                      NULL, rawname,
     213           0 :                                      &domname, &state->netgr_shortname);
     214           0 :     if (ret != EOK) {
     215           0 :         DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", rawname);
     216           0 :         goto error;
     217             :     }
     218             : 
     219           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Requesting info for netgroup [%s] from [%s]\n",
     220             :               state->netgr_shortname, domname?domname:"<ALL>");
     221             : 
     222           0 :     if (domname) {
     223           0 :         dctx->domain = responder_get_domain(client->rctx, domname);
     224           0 :         if (!dctx->domain) {
     225           0 :             ret = EINVAL;
     226           0 :             goto error;
     227             :         }
     228             : 
     229             :         /* Save the netgroup name for getnetgrent */
     230           0 :         client->netgr_name = talloc_strdup(client, state->netgr_shortname);
     231           0 :         if (!client->netgr_name) {
     232           0 :             ret = ENOMEM;
     233           0 :             goto error;
     234             :         }
     235             :     } else {
     236             :         /* this is a multidomain search */
     237           0 :         dctx->domain = client->rctx->domains;
     238           0 :         cmdctx->check_next = true;
     239             : 
     240             :         /* Save the netgroup name for getnetgrent */
     241           0 :         client->netgr_name = talloc_strdup(client, rawname);
     242           0 :         if (!client->netgr_name) {
     243           0 :             ret = ENOMEM;
     244           0 :             goto error;
     245             :         }
     246             :     }
     247             : 
     248           0 :     ret = setnetgrent_retry(req);
     249           0 :     if (ret != EOK) {
     250           0 :         if (ret == EAGAIN) {
     251             :             /* We need to reenter the mainloop
     252             :              * We may be refreshing the cache
     253             :              */
     254           0 :             return req;
     255             :         }
     256             : 
     257           0 :         goto error;
     258             :     }
     259             : 
     260           0 :     return req;
     261             : 
     262             : error:
     263           0 :     tevent_req_error(req, ret);
     264           0 :     tevent_req_post(req, cmdctx->cctx->ev);
     265           0 :     return req;
     266             : }
     267             : 
     268           0 : static errno_t setnetgrent_retry(struct tevent_req *req)
     269             : {
     270             :     errno_t ret;
     271             :     struct setent_step_ctx *step_ctx;
     272             :     struct setnetgrent_ctx *state;
     273             :     struct cli_ctx *client;
     274             :     struct nss_ctx *nctx;
     275             :     struct nss_cmd_ctx *cmdctx;
     276             :     struct nss_dom_ctx *dctx;
     277             : 
     278           0 :     state = tevent_req_data(req, struct setnetgrent_ctx);
     279           0 :     dctx = state->dctx;
     280           0 :     cmdctx = state->cmdctx;
     281           0 :     client = cmdctx->cctx;
     282           0 :     nctx = talloc_get_type(client->rctx->pvt_ctx, struct nss_ctx);
     283             : 
     284           0 :     dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
     285             : 
     286             :     /* Is the result context already available?
     287             :      * Check for existing lookups for this netgroup
     288             :      */
     289           0 :     ret = get_netgroup_entry(nctx, client->netgr_name, &state->netgr);
     290           0 :     if (ret == EOK) {
     291             :         /* Another process already requested this netgroup
     292             :          * Check whether it's ready for processing.
     293             :          */
     294           0 :         if (state->netgr->ready) {
     295           0 :             if (state->netgr->found) {
     296             :                 /* Ready to process results */
     297           0 :                 tevent_req_done(req);
     298             :             } else {
     299           0 :                 tevent_req_error(req, ENOENT);
     300             :             }
     301             : 
     302           0 :             tevent_req_post(req, nctx->rctx->ev);
     303             :             /* Return EOK, otherwise this will be treated as
     304             :              * an error
     305             :              */
     306           0 :             return EOK;
     307             :         }
     308             : 
     309             :         /* Result object is still being constructed
     310             :          * Register for notification when it's ready
     311             :          */
     312           0 :         ret = nss_setent_add_ref(state, state->netgr, req);
     313           0 :         if (ret != EOK) {
     314           0 :             goto done;
     315             :         }
     316             :         /* Will return control below */
     317           0 :     } else if (ret == ENOENT) {
     318             :         /* This is the first attempt to request this netgroup
     319             :          */
     320           0 :         state->netgr = talloc_zero(nctx, struct getent_ctx);
     321           0 :         if (!state->netgr) {
     322           0 :             ret = ENOMEM;
     323           0 :             goto done;
     324             :         }
     325           0 :         dctx->netgr = state->netgr;
     326             : 
     327             :         /* Save the name used for the lookup table
     328             :          * so we can remove it in the destructor
     329             :          */
     330           0 :         state->netgr->name = talloc_strdup(state->netgr,
     331           0 :                                            client->netgr_name);
     332           0 :         if (!state->netgr->name) {
     333           0 :             talloc_free(state->netgr);
     334           0 :             ret = ENOMEM;
     335           0 :             goto done;
     336             :         }
     337             : 
     338           0 :         state->netgr->lookup_table = nctx->netgroups;
     339             : 
     340             :         /* Add a reference for ourselves */
     341           0 :         ret = nss_setent_add_ref(state, state->netgr, req);
     342           0 :         if (ret != EOK) {
     343           0 :             talloc_free(state->netgr);
     344           0 :             goto done;
     345             :         }
     346             : 
     347           0 :         ret = set_netgroup_entry(nctx, state->netgr);
     348           0 :         if (ret != EOK) {
     349           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "set_netgroup_entry failed.\n");
     350           0 :             talloc_free(state->netgr);
     351           0 :             goto done;
     352             :         }
     353             : 
     354             :         /* Perform lookup */
     355           0 :         step_ctx = talloc_zero(state->netgr, struct setent_step_ctx);
     356           0 :         if (!step_ctx) {
     357           0 :             ret = ENOMEM;
     358           0 :             goto done;
     359             :         }
     360             : 
     361             :         /* Steal the dom_ctx onto the step_ctx so it doesn't go out of scope if
     362             :          * this request is canceled while other requests are in-progress.
     363             :          */
     364           0 :         step_ctx->dctx = talloc_steal(step_ctx, state->dctx);
     365           0 :         step_ctx->nctx = state->nctx;
     366           0 :         step_ctx->getent_ctx = state->netgr;
     367           0 :         step_ctx->rctx = client->rctx;
     368           0 :         step_ctx->check_next = cmdctx->check_next;
     369           0 :         step_ctx->name =
     370           0 :                 talloc_strdup(step_ctx, state->netgr->name);
     371           0 :         if (!step_ctx->name) {
     372           0 :             ret = ENOMEM;
     373           0 :             goto done;
     374             :         }
     375             : 
     376           0 :         ret = lookup_netgr_step(step_ctx);
     377           0 :         switch (ret) {
     378             :         case EOK:
     379           0 :             break;
     380             :         case EMSGSIZE:
     381           0 :             state->netgr->ready = true;
     382           0 :             ret = ENOENT;
     383             :             /* FALLTHROUGH */
     384             :         default:
     385           0 :             goto done;
     386             :         }
     387           0 :         tevent_req_done(req);
     388           0 :         tevent_req_post(req, cmdctx->cctx->ev);
     389             :         /* Will return control below */
     390             :     } else {
     391             :         /* Unexpected error from hash_lookup */
     392           0 :         goto done;
     393             :     }
     394             : 
     395           0 :     ret = EOK;
     396             : 
     397             : done:
     398           0 :     return ret;
     399             : }
     400             : 
     401             : static void lookup_netgr_dp_callback(uint16_t err_maj, uint32_t err_min,
     402             :                                      const char *err_msg, void *ptr);
     403             : 
     404             : static void setnetgrent_result_timeout(struct tevent_context *ev,
     405             :                                        struct tevent_timer *te,
     406             :                                        struct timeval current_time,
     407             :                                        void *pvt);
     408             : 
     409             : /* Set up a lifetime timer for this result object
     410             :  * We don't want this result object to outlive the
     411             :  * entry cache refresh timeout
     412             :  */
     413           0 : static void set_netgr_lifetime(uint32_t lifetime,
     414             :                                struct setent_step_ctx *step_ctx,
     415             :                                struct getent_ctx *netgr)
     416             : {
     417             :     struct timeval tv;
     418             :     struct tevent_timer *te;
     419             : 
     420           0 :     tv = tevent_timeval_current_ofs(lifetime, 0);
     421           0 :     te = tevent_add_timer(step_ctx->nctx->rctx->ev,
     422             :                           step_ctx->nctx->gctx, tv,
     423             :                           setnetgrent_result_timeout,
     424             :                           netgr);
     425           0 :     if (!te) {
     426           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     427             :               "Could not set up life timer for setnetgrent result object. "
     428             :                   "Entries may become stale.\n");
     429             :     }
     430           0 : }
     431             : 
     432             : /* Create dummy netgroup to speed up repeated negative queries */
     433           0 : static errno_t create_negcache_netgr(struct setent_step_ctx *step_ctx)
     434             : {
     435             :     errno_t ret;
     436             :     uint32_t lifetime;
     437             :     struct getent_ctx *netgr;
     438             : 
     439             :     /* Is there already netgroup with such name? */
     440           0 :     ret = get_netgroup_entry(step_ctx->nctx, step_ctx->name,
     441             :                              &netgr);
     442           0 :     if (ret != EOK || netgr == NULL) {
     443             : 
     444           0 :         netgr = talloc_zero(step_ctx->nctx, struct getent_ctx);
     445           0 :         if (netgr == NULL) {
     446           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
     447           0 :             ret = ENOMEM;
     448           0 :             goto done;
     449             :         }
     450             : 
     451           0 :         netgr->entries = NULL;
     452           0 :         netgr->lookup_table = step_ctx->nctx->netgroups;
     453           0 :         netgr->name = talloc_strdup(netgr, step_ctx->name);
     454           0 :         if (netgr->name == NULL) {
     455           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
     456           0 :             ret = ENOMEM;
     457           0 :             goto done;
     458             :         }
     459             : 
     460           0 :         ret = set_netgroup_entry(step_ctx->nctx, netgr);
     461           0 :         if (ret != EOK) {
     462           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "set_netgroup_entry failed.\n");
     463           0 :             goto done;
     464             :         }
     465             :     }
     466             : 
     467           0 :     netgr->ready = true;
     468           0 :     netgr->found = false;
     469             : 
     470           0 :     lifetime = sss_ncache_get_timeout(step_ctx->nctx->rctx->ncache);
     471           0 :     set_netgr_lifetime(lifetime, step_ctx, netgr);
     472             : 
     473           0 :     ret = EOK;
     474             : 
     475             : done:
     476           0 :     if (ret != EOK) {
     477           0 :         talloc_free(netgr);
     478             :     }
     479             : 
     480           0 :     return ret;
     481             : }
     482             : 
     483           0 : static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
     484             : {
     485             :     errno_t ret;
     486           0 :     struct sss_domain_info *dom = step_ctx->dctx->domain;
     487             :     struct getent_ctx *netgr;
     488           0 :     char *name = NULL;
     489             :     uint32_t lifetime;
     490             :     TALLOC_CTX *tmp_ctx;
     491             : 
     492           0 :     tmp_ctx = talloc_new(NULL);
     493           0 :     if (tmp_ctx == NULL) {
     494           0 :         return ENOMEM;
     495             :     }
     496             : 
     497             :     /* Check each domain for this netgroup name */
     498           0 :     while (dom) {
     499             :         /* Netgroups are a special case. We have to ignore the
     500             :          * fully-qualified name requirement because memberNisNetgroup
     501             :          * entries do not have fully-qualified components and we need
     502             :          * to be able to always check them. So unlike the other
     503             :          * maps, here we avoid skipping over fully-qualified domains.
     504             :          */
     505             : 
     506           0 :         if (dom != step_ctx->dctx->domain) {
     507             :             /* make sure we reset the check_provider flag when we check
     508             :              * a new domain */
     509           0 :             step_ctx->dctx->check_provider =
     510           0 :                     NEED_CHECK_PROVIDER(dom->provider);
     511             :         }
     512             : 
     513             :         /* make sure to update the dctx if we changed domain */
     514           0 :         step_ctx->dctx->domain = dom;
     515             : 
     516           0 :         name = sss_get_cased_name(tmp_ctx, step_ctx->name,
     517           0 :                                   dom->case_sensitive);
     518           0 :         if (!name) {
     519           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "sss_get_cased_name failed\n");
     520           0 :             ret = ENOMEM;
     521           0 :             goto done;
     522             :         }
     523             : 
     524           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Requesting info for [%s@%s]\n",
     525             :                   name, dom->name);
     526           0 :         if (dom->sysdb == NULL) {
     527           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     528             :                   "Fatal: Sysdb CTX not found for this domain!\n");
     529           0 :             ret = EIO;
     530           0 :             goto done;
     531             :         }
     532             : 
     533             :         /* Look up the netgroup in the cache */
     534           0 :         ret = sysdb_getnetgr(step_ctx->dctx, dom, name, &step_ctx->dctx->res);
     535           0 :         if (ret == EOK) {
     536           0 :             if (step_ctx->dctx->res->count > 1) {
     537           0 :                 DEBUG(SSSDBG_FATAL_FAILURE,
     538             :                       "getnetgr call returned more than one result !?!\n");
     539           0 :                 ret = EMSGSIZE;
     540           0 :                 goto done;
     541             :             }
     542           0 :         } else if (ret == ENOENT) {
     543             :             /* This netgroup was not found in this domain */
     544           0 :             if (!step_ctx->dctx->check_provider) {
     545           0 :                 if (step_ctx->check_next) {
     546           0 :                     dom = get_next_domain(dom, 0);
     547           0 :                     continue;
     548             :                 } else {
     549           0 :                     break;
     550             :                 }
     551             :             }
     552             :         } else {
     553           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     554             :                   "Failed to make request to our cache!\n");
     555           0 :             ret = EIO;
     556           0 :             goto done;
     557             :         }
     558             : 
     559           0 :         ret = get_netgroup_entry(step_ctx->nctx, step_ctx->name,
     560             :                                  &netgr);
     561           0 :         if (ret != EOK) {
     562             :             /* Something really bad happened! */
     563           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Netgroup entry was lost!\n");
     564           0 :             goto done;
     565             :         }
     566             : 
     567             :         /* Convert the result to a list of entries */
     568           0 :         ret = sysdb_netgr_to_entries(netgr, step_ctx->dctx->res,
     569           0 :                                      &netgr->entries);
     570           0 :         if (ret == ENOENT) {
     571             :             /* This netgroup was not found in this domain */
     572           0 :             DEBUG(SSSDBG_OP_FAILURE, "No results for netgroup %s (domain %s)\n",
     573             :                       name, dom->name);
     574             : 
     575           0 :             if (!step_ctx->dctx->check_provider) {
     576           0 :                 if (step_ctx->check_next) {
     577           0 :                     dom = get_next_domain(dom, 0);
     578           0 :                     continue;
     579             :                 }
     580           0 :                 else break;
     581             :             }
     582           0 :             ret = EOK;
     583             :         }
     584             : 
     585           0 :         if (ret != EOK) {
     586           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     587             :                   "Failed to convert results into entries\n");
     588           0 :             netgr->ready = true;
     589           0 :             netgr->found = false;
     590           0 :             lifetime = sss_ncache_get_timeout(step_ctx->nctx->rctx->ncache);
     591           0 :             set_netgr_lifetime(lifetime, step_ctx, netgr);
     592           0 :             ret = EIO;
     593           0 :             goto done;
     594             :         }
     595             : 
     596             :         /* if this is a caching provider (or if we haven't checked the cache
     597             :          * yet) then verify that the cache is uptodate */
     598           0 :         if (step_ctx->dctx->check_provider) {
     599           0 :             ret = check_cache(step_ctx->dctx,
     600             :                               step_ctx->nctx,
     601           0 :                               step_ctx->dctx->res,
     602             :                               SSS_DP_NETGR,
     603             :                               name, 0, NULL,
     604             :                               lookup_netgr_dp_callback,
     605             :                               step_ctx);
     606           0 :             if (ret != EOK) {
     607             :                 /* May return EAGAIN legitimately to indicate that
     608             :                  * we need to reenter the mainloop
     609             :                  */
     610           0 :                 goto done;
     611             :             }
     612             :         }
     613             : 
     614             :         /* Results found */
     615           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Returning info for netgroup [%s@%s]\n",
     616             :                   name, dom->name);
     617           0 :         netgr->ready = true;
     618           0 :         netgr->found = true;
     619           0 :         if (step_ctx->nctx->cache_refresh_percent) {
     620           0 :             lifetime = dom->netgroup_timeout *
     621           0 :                 (step_ctx->nctx->cache_refresh_percent / 100.0);
     622             :         } else {
     623           0 :             lifetime = dom->netgroup_timeout;
     624             :         }
     625           0 :         if (lifetime < 10) lifetime = 10;
     626           0 :         set_netgr_lifetime(lifetime, step_ctx, netgr);
     627             : 
     628           0 :         ret = EOK;
     629           0 :         goto done;
     630             :     }
     631             : 
     632             :     /* If we've gotten here, then no domain contained this netgroup */
     633           0 :     DEBUG(SSSDBG_MINOR_FAILURE,
     634             :           "No matching domain found for [%s], fail!\n", step_ctx->name);
     635             : 
     636           0 :     ret = create_negcache_netgr(step_ctx);
     637           0 :     if (ret != EOK) {
     638             :         /* Failure can be ignored, because at worst, there will be a slowdown
     639             :          * at the next lookup
     640             :          */
     641           0 :         DEBUG(SSSDBG_TRACE_ALL,
     642             :               "create_negcache_netgr failed with: %d:[%s], ignored.\n",
     643             :               ret, sss_strerror(ret));
     644             :     }
     645             : 
     646           0 :     ret = ENOENT;
     647             : 
     648             : done:
     649           0 :     talloc_free(tmp_ctx);
     650           0 :     return ret;
     651             : }
     652             : 
     653           0 : static void lookup_netgr_dp_callback(uint16_t err_maj, uint32_t err_min,
     654             :                                      const char *err_msg, void *ptr)
     655             : {
     656           0 :     struct setent_step_ctx *step_ctx =
     657             :             talloc_get_type(ptr, struct setent_step_ctx);
     658           0 :     struct nss_dom_ctx *dctx = step_ctx->dctx;
     659           0 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     660             :     int ret;
     661             : 
     662           0 :     if (err_maj) {
     663           0 :         DEBUG(SSSDBG_OP_FAILURE,
     664             :               "Unable to get information from Data Provider\n"
     665             :                   "Error: %u, %u, %s\n"
     666             :                   "Will try to return what we have in cache\n",
     667             :                   (unsigned int)err_maj, (unsigned int)err_min, err_msg);
     668             :         /* Loop to the next domain if possible */
     669           0 :         if (cmdctx->check_next
     670           0 :                 && (dctx->domain = get_next_domain(dctx->domain, 0))) {
     671           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
     672             :         }
     673             :     }
     674             : 
     675             :     /* ok the backend returned, search to see if we have updated results */
     676           0 :     ret = lookup_netgr_step(step_ctx);
     677           0 :     if (ret == EAGAIN) {
     678           0 :         return;
     679             :     }
     680             : 
     681             :     /* We have results to return */
     682           0 :     if (ret == EOK) {
     683           0 :         nss_setent_notify_done(dctx->netgr);
     684             :     } else {
     685           0 :         nss_setent_notify_error(dctx->netgr, ret);
     686             :     }
     687             : }
     688             : 
     689           0 : static void setnetgrent_result_timeout(struct tevent_context *ev,
     690             :                                        struct tevent_timer *te,
     691             :                                        struct timeval current_time,
     692             :                                        void *pvt)
     693             : {
     694           0 :     struct getent_ctx *netgr =
     695             :             talloc_get_type(pvt, struct getent_ctx);
     696             : 
     697             :     /* Free the netgroup result context
     698             :      * The destructor for the netgroup will remove itself
     699             :      * from the hash table
     700             :      *
     701             :      * If additional getnetgrent() requests come in, they
     702             :      * will invoke an implicit setnetgrent() call and
     703             :      * refresh the result object
     704             :      */
     705           0 :     talloc_free(netgr);
     706           0 : }
     707             : 
     708           0 : static errno_t setnetgrent_recv(struct tevent_req *req)
     709             : {
     710           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     711           0 :     return EOK;
     712             : }
     713             : 
     714           0 : static void nss_cmd_setnetgrent_done(struct tevent_req *req)
     715             : {
     716             :     errno_t reqret;
     717             :     errno_t ret;
     718             :     struct sss_packet *packet;
     719             :     uint8_t *body;
     720             :     size_t blen;
     721             : 
     722           0 :     struct nss_cmd_ctx *cmdctx =
     723           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
     724             : 
     725           0 :     reqret = setnetgrent_recv(req);
     726           0 :     talloc_zfree(req);
     727           0 :     if (reqret != EOK && reqret != ENOENT) {
     728           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "setnetgrent failed\n");
     729           0 :         nss_cmd_done(cmdctx, reqret);
     730           0 :         return;
     731             :     }
     732             : 
     733             :     /* Either we succeeded or no domains were eligible */
     734           0 :     ret = sss_packet_new(cmdctx->cctx->creq, 0,
     735           0 :                          sss_packet_get_cmd(cmdctx->cctx->creq->in),
     736           0 :                          &cmdctx->cctx->creq->out);
     737           0 :     if (ret == EOK) {
     738           0 :         if (reqret == ENOENT) {
     739             :             /* Notify the caller that this entry wasn't found */
     740           0 :             sss_cmd_empty_packet(cmdctx->cctx->creq->out);
     741             :         } else {
     742           0 :             packet = cmdctx->cctx->creq->out;
     743           0 :             ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
     744           0 :             if (ret != EOK) {
     745           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't grow the packet\n");
     746           0 :                 NSS_CMD_FATAL_ERROR(cmdctx);
     747             :             }
     748             : 
     749           0 :             sss_packet_get_body(packet, &body, &blen);
     750             : 
     751             :             /* Got some results. */
     752           0 :             SAFEALIGN_SETMEM_UINT32(body, 1, NULL);
     753             : 
     754             :             /* reserved */
     755           0 :             SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
     756             :         }
     757             : 
     758           0 :         sss_cmd_done(cmdctx->cctx, cmdctx);
     759           0 :         return;
     760             :     }
     761             : 
     762           0 :     DEBUG(SSSDBG_CRIT_FAILURE, "Error creating packet\n");
     763             : }
     764             : 
     765             : static void setnetgrent_implicit_done(struct tevent_req *req);
     766             : static errno_t nss_cmd_getnetgrent_process(struct nss_cmd_ctx *cmdctx,
     767             :                                            struct getent_ctx *netgr);
     768           0 : int nss_cmd_getnetgrent(struct cli_ctx *client)
     769             : {
     770             :     errno_t ret;
     771             :     struct nss_ctx *nctx;
     772             :     struct nss_cmd_ctx *cmdctx;
     773             :     struct getent_ctx *netgr;
     774             :     struct tevent_req *req;
     775             : 
     776           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Requesting netgroup data\n");
     777             : 
     778           0 :     cmdctx = talloc_zero(client, struct nss_cmd_ctx);
     779           0 :     if (!cmdctx) {
     780           0 :         return ENOMEM;
     781             :     }
     782           0 :     cmdctx->cctx = client;
     783             : 
     784           0 :     nctx = talloc_get_type(client->rctx->pvt_ctx, struct nss_ctx);
     785             : 
     786           0 :     if (!client->netgr_name) {
     787             :         /* Tried to run getnetgrent without a preceding
     788             :          * setnetgrent. There is no way to determine which
     789             :          * netgroup is being requested.
     790             :          */
     791           0 :         return nss_cmd_done(cmdctx, EINVAL);
     792             :     }
     793             : 
     794             :     /* Look up the results from the hash */
     795           0 :     ret = get_netgroup_entry(nctx, client->netgr_name, &netgr);
     796           0 :     if (ret == ENOENT) {
     797             :         /* We need to invoke an implicit setnetgrent() to
     798             :          * wait for the result object to become available.
     799             :          */
     800             : 
     801           0 :         req = setnetgrent_send(cmdctx, client->netgr_name, cmdctx);
     802           0 :         if (!req) {
     803           0 :             return nss_cmd_done(cmdctx, EIO);
     804             :         }
     805           0 :         tevent_req_set_callback(req, setnetgrent_implicit_done, cmdctx);
     806             : 
     807           0 :         return EOK;
     808           0 :     } else if (ret != EOK) {
     809           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "An unexpected error occurred: [%d][%s]\n",
     810             :                   ret, strerror(ret));
     811             : 
     812           0 :         return nss_cmd_done(cmdctx, ret);
     813             :     }
     814             : 
     815             :     /* Hash entry was found. Is it ready? */
     816           0 :     if (!netgr->ready) {
     817             :         /* We need to invoke an implicit setnetgrent() to
     818             :          * wait for the result object to become available.
     819             :          */
     820           0 :         req = setnetgrent_send(cmdctx, client->netgr_name, cmdctx);
     821           0 :         if (!req) {
     822           0 :             return nss_cmd_done(cmdctx, EIO);
     823             :         }
     824           0 :         tevent_req_set_callback(req, setnetgrent_implicit_done, cmdctx);
     825             : 
     826           0 :         return EOK;
     827           0 :     } else if (!netgr->found) {
     828           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     829             :               "Results for [%s] not found.\n", client->netgr_name);
     830           0 :         return ENOENT;
     831             :     }
     832             : 
     833           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     834             :           "Returning results for [%s]\n", client->netgr_name);
     835             : 
     836             :     /* Read the result strings */
     837           0 :     ret = nss_cmd_getnetgrent_process(cmdctx, netgr);
     838           0 :     if (ret != EOK) {
     839           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed: [%d][%s]\n", ret, strerror(ret));
     840             :     }
     841           0 :     return ret;
     842             : }
     843             : 
     844           0 : static void setnetgrent_implicit_done(struct tevent_req *req)
     845             : {
     846             :     errno_t ret;
     847             :     struct getent_ctx *netgr;
     848           0 :     struct nss_cmd_ctx *cmdctx =
     849           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
     850           0 :     struct nss_ctx *nctx =
     851           0 :             talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct nss_ctx);
     852             : 
     853           0 :     ret = setnetgrent_recv(req);
     854           0 :     talloc_zfree(req);
     855             : 
     856             :     /* ENOENT is acceptable, it just means there were no values
     857             :      * to be returned. This will be handled gracefully in
     858             :      * nss_cmd_retnetgrent later
     859             :      */
     860           0 :     if (ret != EOK && ret != ENOENT) {
     861           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     862             :               "Implicit setnetgrent failed with unexpected error "
     863             :                   "[%d][%s]\n", ret, strerror(ret));
     864           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     865             :     }
     866             : 
     867           0 :     if (ret == ENOENT) {
     868             :         /* No entries found for this netgroup */
     869           0 :         nss_cmd_done(cmdctx, ret);
     870           0 :         return;
     871             :     }
     872             : 
     873             :     /* Look up the results from the hash */
     874           0 :     ret = get_netgroup_entry(nctx, cmdctx->cctx->netgr_name, &netgr);
     875           0 :     if (ret == ENOENT) {
     876             :         /* Critical error. This should never happen */
     877           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     878             :               "Implicit setnetgrent returned success without creating "
     879             :                   "result object.\n");
     880           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     881           0 :     } else if (ret != EOK) {
     882           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "An unexpected error occurred: [%d][%s]\n",
     883             :                   ret, strerror(ret));
     884             : 
     885           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     886             :     }
     887             : 
     888           0 :     if (!netgr->ready) {
     889             :         /* Critical error. This should never happen */
     890           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     891             :               "Implicit setnetgrent returned success without creating "
     892             :                   "result object.\n");
     893           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     894             :     }
     895             : 
     896           0 :     ret = nss_cmd_getnetgrent_process(cmdctx, netgr);
     897           0 :     if (ret != EOK) {
     898           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     899             :               "Immediate retrieval failed with unexpected error "
     900             :                   "[%d][%s]\n", ret, strerror(ret));
     901           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     902             :     }
     903             : }
     904             : 
     905             : static errno_t nss_cmd_retnetgrent(struct cli_ctx *client,
     906             :                                    struct sysdb_netgroup_ctx **entries,
     907             :                                    int num);
     908           0 : static errno_t nss_cmd_getnetgrent_process(struct nss_cmd_ctx *cmdctx,
     909             :                                            struct getent_ctx *netgr)
     910             : {
     911           0 :     struct cli_ctx *client = cmdctx->cctx;
     912             :     uint8_t *body;
     913             :     size_t blen;
     914             :     uint32_t num;
     915             :     errno_t ret;
     916             : 
     917             :     /* get max num of entries to return in one call */
     918           0 :     sss_packet_get_body(client->creq->in, &body, &blen);
     919           0 :     if (blen != sizeof(uint32_t)) {
     920           0 :         return EINVAL;
     921             :     }
     922           0 :     SAFEALIGN_COPY_UINT32(&num, body, NULL);
     923             : 
     924             :     /* create response packet */
     925           0 :     ret = sss_packet_new(client->creq, 0,
     926           0 :                          sss_packet_get_cmd(client->creq->in),
     927           0 :                          &client->creq->out);
     928           0 :     if (ret != EOK) {
     929           0 :         return ret;
     930             :     }
     931             : 
     932           0 :     if (!netgr->entries || netgr->entries[0] == NULL) {
     933             :         /* No entries */
     934           0 :         DEBUG(SSSDBG_FUNC_DATA, "No entries found\n");
     935           0 :         ret = sss_cmd_empty_packet(client->creq->out);
     936           0 :         if (ret != EOK) {
     937           0 :             return nss_cmd_done(cmdctx, ret);
     938             :         }
     939           0 :         goto done;
     940             :     }
     941             : 
     942           0 :     ret = nss_cmd_retnetgrent(client, netgr->entries, num);
     943             : 
     944             : done:
     945           0 :     sss_packet_set_error(client->creq->out, ret);
     946           0 :     sss_cmd_done(client, cmdctx);
     947             : 
     948           0 :     return EOK;
     949             : }
     950             : 
     951           0 : static errno_t nss_cmd_retnetgrent(struct cli_ctx *client,
     952             :                                    struct sysdb_netgroup_ctx **entries,
     953             :                                    int count)
     954             : {
     955             :     size_t len;
     956           0 :     size_t hostlen = 0;
     957           0 :     size_t userlen = 0;
     958           0 :     size_t domainlen = 0;
     959           0 :     size_t grouplen = 0;
     960             :     uint8_t *body;
     961             :     size_t blen, rp;
     962             :     errno_t ret;
     963           0 :     struct sss_packet *packet = client->creq->out;
     964             :     int num, start;
     965             : 
     966             :     /* first 2 fields (len and reserved), filled up later */
     967           0 :     rp = 2*sizeof(uint32_t);
     968           0 :     ret = sss_packet_grow(packet, rp);
     969           0 :     if (ret != EOK) return ret;
     970             : 
     971           0 :     start = client->netgrent_cur;
     972           0 :     num = 0;
     973           0 :     while (entries[client->netgrent_cur] &&
     974           0 :            (client->netgrent_cur - start) < count) {
     975           0 :         if (entries[client->netgrent_cur]->type == SYSDB_NETGROUP_TRIPLE_VAL) {
     976           0 :             hostlen = 1;
     977           0 :             if (entries[client->netgrent_cur]->value.triple.hostname) {
     978           0 :                 hostlen += strlen(entries[client->netgrent_cur]->value.triple.hostname);
     979             :             }
     980             : 
     981           0 :             userlen = 1;
     982           0 :             if (entries[client->netgrent_cur]->value.triple.username) {
     983           0 :                 userlen += strlen(entries[client->netgrent_cur]->value.triple.username);
     984             :             }
     985             : 
     986           0 :             domainlen = 1;
     987           0 :             if (entries[client->netgrent_cur]->value.triple.domainname) {
     988           0 :                 domainlen += strlen(entries[client->netgrent_cur]->value.triple.domainname);
     989             :             }
     990             : 
     991           0 :             len = sizeof(uint32_t) + hostlen + userlen + domainlen;
     992           0 :             ret = sss_packet_grow(packet, len);
     993           0 :             if (ret != EOK) {
     994           0 :                 return ret;
     995             :             }
     996           0 :             sss_packet_get_body(packet, &body, &blen);
     997             : 
     998           0 :             SAFEALIGN_SET_UINT32(&body[rp], SSS_NETGR_REP_TRIPLE, &rp);
     999             : 
    1000           0 :             if (hostlen == 1) {
    1001           0 :                 body[rp] = '\0';
    1002             :             } else {
    1003           0 :                 memcpy(&body[rp],
    1004           0 :                        entries[client->netgrent_cur]->value.triple.hostname,
    1005             :                        hostlen);
    1006             :             }
    1007           0 :             rp += hostlen;
    1008             : 
    1009           0 :             if (userlen == 1) {
    1010           0 :                 body[rp] = '\0';
    1011             :             } else {
    1012           0 :                 memcpy(&body[rp],
    1013           0 :                        entries[client->netgrent_cur]->value.triple.username,
    1014             :                        userlen);
    1015             :             }
    1016           0 :             rp += userlen;
    1017             : 
    1018           0 :             if (domainlen == 1) {
    1019           0 :                 body[rp] = '\0';
    1020             :             } else {
    1021           0 :                 memcpy(&body[rp],
    1022           0 :                        entries[client->netgrent_cur]->value.triple.domainname,
    1023             :                        domainlen);
    1024             :             }
    1025           0 :             rp += domainlen;
    1026           0 :         } else if (entries[client->netgrent_cur]->type == SYSDB_NETGROUP_GROUP_VAL) {
    1027           0 :             if (entries[client->netgrent_cur]->value.groupname == NULL ||
    1028           0 :                 entries[client->netgrent_cur]->value.groupname[0] == '\0') {
    1029           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1030             :                       "Empty netgroup member. Please check your cache.\n");
    1031           0 :                 continue;
    1032             :             }
    1033             : 
    1034           0 :             grouplen = 1 + strlen(entries[client->netgrent_cur]->value.groupname);
    1035             : 
    1036           0 :             len = sizeof(uint32_t) + grouplen;
    1037             : 
    1038           0 :             ret = sss_packet_grow(packet, len);
    1039           0 :             if (ret != EOK) {
    1040           0 :                 return ret;
    1041             :             }
    1042             : 
    1043           0 :             sss_packet_get_body(packet, &body, &blen);
    1044             : 
    1045           0 :             SAFEALIGN_SET_UINT32(&body[rp], SSS_NETGR_REP_GROUP, &rp);
    1046             : 
    1047           0 :             memcpy(&body[rp],
    1048           0 :                    entries[client->netgrent_cur]->value.groupname,
    1049             :                    grouplen);
    1050           0 :             rp += grouplen;
    1051             :         } else {
    1052           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1053             :                   "Unexpected value type for netgroup entry. "
    1054             :                       "Please check your cache.\n");
    1055           0 :             continue;
    1056             :         }
    1057             : 
    1058           0 :         num++;
    1059           0 :         client->netgrent_cur++;
    1060             :     }
    1061             : 
    1062           0 :     sss_packet_get_body(packet, &body, &blen);
    1063             : 
    1064             :     /* num results */
    1065           0 :     SAFEALIGN_COPY_UINT32(body, &num, NULL);
    1066             : 
    1067             :     /* reserved */
    1068           0 :     SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
    1069             : 
    1070           0 :     return EOK;
    1071             : }
    1072             : 
    1073           0 : int nss_cmd_endnetgrent(struct cli_ctx *client)
    1074             : {
    1075             :     errno_t ret;
    1076             : 
    1077             :     /* create response packet */
    1078           0 :     ret = sss_packet_new(client->creq, 0,
    1079           0 :                          sss_packet_get_cmd(client->creq->in),
    1080           0 :                          &client->creq->out);
    1081             : 
    1082           0 :     if (ret != EOK) {
    1083           0 :         return ret;
    1084             :     }
    1085             : 
    1086             :     /* Reset the indices so that subsequent requests start at zero */
    1087           0 :     client->netgrent_cur = 0;
    1088           0 :     talloc_zfree(client->netgr_name);
    1089             : 
    1090           0 :     sss_cmd_done(client, NULL);
    1091           0 :     return EOK;
    1092             : }
    1093             : 
    1094             : void
    1095           0 : netgroup_hash_delete_cb(hash_entry_t *item,
    1096             :                         hash_destroy_enum deltype, void *pvt)
    1097             : {
    1098             :     struct getent_ctx *netgr;
    1099             : 
    1100           0 :     if (deltype != HASH_ENTRY_DESTROY) {
    1101           0 :         return;
    1102             :     }
    1103             : 
    1104           0 :     netgr = talloc_get_type(item->value.ptr, struct getent_ctx);
    1105           0 :     if (!netgr) {
    1106           0 :         DEBUG(SSSDBG_OP_FAILURE, "Invalid netgroup\n");
    1107           0 :         return;
    1108             :     }
    1109             : 
    1110             :     /* So that the destructor wouldn't attempt to remove the netgroup from hash
    1111             :      * table */
    1112           0 :     netgr->lookup_table = NULL;
    1113             : }
    1114             : 
    1115           0 : errno_t nss_orphan_netgroups(struct nss_ctx *nctx)
    1116             : {
    1117             :     int hret;
    1118             :     unsigned long mcount;
    1119             :     unsigned long i;
    1120             :     hash_key_t *netgroups;
    1121             : 
    1122           0 :     if (!nctx || !nctx->netgroups) {
    1123           0 :         return EINVAL;
    1124             :     }
    1125             : 
    1126           0 :     hret = hash_keys(nctx->netgroups, &mcount, &netgroups);
    1127           0 :     if (hret != HASH_SUCCESS) {
    1128           0 :         return EIO;
    1129             :     }
    1130             : 
    1131           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Removing netgroups from memory cache.\n");
    1132             : 
    1133           0 :     for (i = 0; i < mcount; i++) {
    1134             :         /* netgroup entry will be deleted by setnetgrent_result_timeout */
    1135           0 :         hret = hash_delete(nctx->netgroups, &netgroups[i]);
    1136           0 :         if (hret != HASH_SUCCESS) {
    1137           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete key from hash\n");
    1138           0 :             continue;
    1139             :         }
    1140             :     }
    1141             : 
    1142           0 :     return EOK;
    1143             : }

Generated by: LCOV version 1.10