LCOV - code coverage report
Current view: top level - responder/nss - nsssrv_netgroup.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 508 0.0 %
Date: 2015-10-19 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             :     struct getent_ctx *netgr;
     437             : 
     438           0 :     netgr = talloc_zero(step_ctx->nctx, struct getent_ctx);
     439           0 :     if (netgr == NULL) {
     440           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
     441           0 :         ret = ENOMEM;
     442           0 :         goto done;
     443             :     } else {
     444           0 :         netgr->ready = true;
     445           0 :         netgr->found = false;
     446           0 :         netgr->entries = NULL;
     447           0 :         netgr->lookup_table = step_ctx->nctx->netgroups;
     448           0 :         netgr->name = talloc_strdup(netgr, step_ctx->name);
     449           0 :         if (netgr->name == NULL) {
     450           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
     451           0 :             ret = ENOMEM;
     452           0 :             goto done;
     453             :         }
     454             : 
     455           0 :         ret = set_netgroup_entry(step_ctx->nctx, netgr);
     456           0 :         if (ret != EOK) {
     457           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "set_netgroup_entry failed.\n");
     458           0 :             goto done;
     459             :         }
     460           0 :         set_netgr_lifetime(step_ctx->nctx->neg_timeout, step_ctx, netgr);
     461             :     }
     462             : 
     463             : done:
     464           0 :     if (ret != EOK) {
     465           0 :         talloc_free(netgr);
     466             :     }
     467           0 :     return ret;
     468             : }
     469             : 
     470           0 : static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
     471             : {
     472             :     errno_t ret;
     473           0 :     struct sss_domain_info *dom = step_ctx->dctx->domain;
     474             :     struct getent_ctx *netgr;
     475           0 :     char *name = NULL;
     476             :     uint32_t lifetime;
     477             : 
     478             :     /* Check each domain for this netgroup name */
     479           0 :     while (dom) {
     480             :         /* Netgroups are a special case. We have to ignore the
     481             :          * fully-qualified name requirement because memberNisNetgroup
     482             :          * entries do not have fully-qualified components and we need
     483             :          * to be able to always check them. So unlike the other
     484             :          * maps, here we avoid skipping over fully-qualified domains.
     485             :          */
     486             : 
     487           0 :         if (dom != step_ctx->dctx->domain) {
     488             :             /* make sure we reset the check_provider flag when we check
     489             :              * a new domain */
     490           0 :             step_ctx->dctx->check_provider =
     491           0 :                     NEED_CHECK_PROVIDER(dom->provider);
     492             :         }
     493             : 
     494             :         /* make sure to update the dctx if we changed domain */
     495           0 :         step_ctx->dctx->domain = dom;
     496             : 
     497           0 :         talloc_free(name);
     498           0 :         name = sss_get_cased_name(step_ctx, step_ctx->name,
     499           0 :                                   dom->case_sensitive);
     500           0 :         if (!name) {
     501           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "sss_get_cased_name failed\n");
     502           0 :             ret = ENOMEM;
     503           0 :             goto done;
     504             :         }
     505             : 
     506           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Requesting info for [%s@%s]\n",
     507             :                   name, dom->name);
     508           0 :         if (dom->sysdb == NULL) {
     509           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     510             :                   "Fatal: Sysdb CTX not found for this domain!\n");
     511           0 :             ret = EIO;
     512           0 :             goto done;
     513             :         }
     514             : 
     515             :         /* Look up the netgroup in the cache */
     516           0 :         ret = sysdb_getnetgr(step_ctx->dctx, dom, name, &step_ctx->dctx->res);
     517           0 :         if (ret == EOK) {
     518           0 :             if (step_ctx->dctx->res->count > 1) {
     519           0 :                 DEBUG(SSSDBG_FATAL_FAILURE,
     520             :                       "getnetgr call returned more than one result !?!\n");
     521           0 :                 ret = EMSGSIZE;
     522           0 :                 goto done;
     523             :             }
     524           0 :         } else if (ret == ENOENT) {
     525             :             /* This netgroup was not found in this domain */
     526           0 :             if (!step_ctx->dctx->check_provider) {
     527           0 :                 if (step_ctx->check_next) {
     528           0 :                     dom = get_next_domain(dom, false);
     529           0 :                     continue;
     530             :                 } else {
     531           0 :                     break;
     532             :                 }
     533             :             }
     534             :         } else {
     535           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     536             :                   "Failed to make request to our cache!\n");
     537           0 :             ret = EIO;
     538           0 :             goto done;
     539             :         }
     540             : 
     541           0 :         ret = get_netgroup_entry(step_ctx->nctx, step_ctx->name,
     542             :                                  &netgr);
     543           0 :         if (ret != EOK) {
     544             :             /* Something really bad happened! */
     545           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Netgroup entry was lost!\n");
     546           0 :             goto done;
     547             :         }
     548             : 
     549             :         /* Convert the result to a list of entries */
     550           0 :         ret = sysdb_netgr_to_entries(netgr, step_ctx->dctx->res,
     551           0 :                                      &netgr->entries);
     552           0 :         if (ret == ENOENT) {
     553             :             /* This netgroup was not found in this domain */
     554           0 :             DEBUG(SSSDBG_OP_FAILURE, "No results for netgroup %s (domain %s)\n",
     555             :                       name, dom->name);
     556             : 
     557           0 :             if (!step_ctx->dctx->check_provider) {
     558           0 :                 if (step_ctx->check_next) {
     559           0 :                     dom = get_next_domain(dom, false);
     560           0 :                     continue;
     561             :                 }
     562           0 :                 else break;
     563             :             }
     564           0 :             ret = EOK;
     565             :         }
     566             : 
     567           0 :         if (ret != EOK) {
     568           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     569             :                   "Failed to convert results into entries\n");
     570           0 :             netgr->ready = true;
     571           0 :             netgr->found = false;
     572           0 :             set_netgr_lifetime(step_ctx->nctx->neg_timeout, step_ctx, netgr);
     573           0 :             ret = EIO;
     574           0 :             goto done;
     575             :         }
     576             : 
     577             :         /* if this is a caching provider (or if we haven't checked the cache
     578             :          * yet) then verify that the cache is uptodate */
     579           0 :         if (step_ctx->dctx->check_provider) {
     580           0 :             ret = check_cache(step_ctx->dctx,
     581             :                               step_ctx->nctx,
     582           0 :                               step_ctx->dctx->res,
     583             :                               SSS_DP_NETGR,
     584             :                               name, 0, NULL,
     585             :                               lookup_netgr_dp_callback,
     586             :                               step_ctx);
     587           0 :             if (ret != EOK) {
     588             :                 /* May return EAGAIN legitimately to indicate that
     589             :                  * we need to reenter the mainloop
     590             :                  */
     591           0 :                 goto done;
     592             :             }
     593             :         }
     594             : 
     595             :         /* Results found */
     596           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Returning info for netgroup [%s@%s]\n",
     597             :                   name, dom->name);
     598           0 :         netgr->ready = true;
     599           0 :         netgr->found = true;
     600           0 :         if (step_ctx->nctx->cache_refresh_percent) {
     601           0 :             lifetime = dom->netgroup_timeout *
     602           0 :                 (step_ctx->nctx->cache_refresh_percent / 100.0);
     603             :         } else {
     604           0 :             lifetime = dom->netgroup_timeout;
     605             :         }
     606           0 :         if (lifetime < 10) lifetime = 10;
     607           0 :         set_netgr_lifetime(lifetime, step_ctx, netgr);
     608             : 
     609           0 :         ret = EOK;
     610           0 :         goto done;
     611             :     }
     612             : 
     613             :     /* If we've gotten here, then no domain contained this netgroup */
     614           0 :     DEBUG(SSSDBG_MINOR_FAILURE,
     615             :           "No matching domain found for [%s], fail!\n", step_ctx->name);
     616             : 
     617           0 :     ret = create_negcache_netgr(step_ctx);
     618           0 :     if (ret != EOK) {
     619             :         /* Failure can be ignored, because at worst, there will be a slowdown
     620             :          * at the next lookup
     621             :          */
     622           0 :         DEBUG(SSSDBG_TRACE_ALL,
     623             :               "create_negcache_netgr failed with: %d:[%s], ignored.\n",
     624             :               ret, sss_strerror(ret));
     625             :     }
     626           0 :     ret = ENOENT;
     627             : 
     628             : done:
     629           0 :     talloc_free(name);
     630           0 :     return ret;
     631             : }
     632             : 
     633           0 : static void lookup_netgr_dp_callback(uint16_t err_maj, uint32_t err_min,
     634             :                                      const char *err_msg, void *ptr)
     635             : {
     636           0 :     struct setent_step_ctx *step_ctx =
     637             :             talloc_get_type(ptr, struct setent_step_ctx);
     638           0 :     struct nss_dom_ctx *dctx = step_ctx->dctx;
     639           0 :     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     640             :     int ret;
     641             : 
     642           0 :     if (err_maj) {
     643           0 :         DEBUG(SSSDBG_OP_FAILURE,
     644             :               "Unable to get information from Data Provider\n"
     645             :                   "Error: %u, %u, %s\n"
     646             :                   "Will try to return what we have in cache\n",
     647             :                   (unsigned int)err_maj, (unsigned int)err_min, err_msg);
     648             :         /* Loop to the next domain if possible */
     649           0 :         if (cmdctx->check_next && get_next_domain(dctx->domain, false)) {
     650           0 :             dctx->domain = get_next_domain(dctx->domain, false);
     651           0 :             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
     652             :         }
     653             :     }
     654             : 
     655             :     /* ok the backend returned, search to see if we have updated results */
     656           0 :     ret = lookup_netgr_step(step_ctx);
     657           0 :     if (ret == EAGAIN) {
     658           0 :         return;
     659             :     }
     660             : 
     661             :     /* We have results to return */
     662           0 :     if (ret == EOK) {
     663           0 :         nss_setent_notify_done(dctx->netgr);
     664             :     } else {
     665           0 :         nss_setent_notify_error(dctx->netgr, ret);
     666             :     }
     667             : }
     668             : 
     669           0 : static void setnetgrent_result_timeout(struct tevent_context *ev,
     670             :                                        struct tevent_timer *te,
     671             :                                        struct timeval current_time,
     672             :                                        void *pvt)
     673             : {
     674           0 :     struct getent_ctx *netgr =
     675             :             talloc_get_type(pvt, struct getent_ctx);
     676             : 
     677             :     /* Free the netgroup result context
     678             :      * The destructor for the netgroup will remove itself
     679             :      * from the hash table
     680             :      *
     681             :      * If additional getnetgrent() requests come in, they
     682             :      * will invoke an implicit setnetgrent() call and
     683             :      * refresh the result object
     684             :      */
     685           0 :     talloc_free(netgr);
     686           0 : }
     687             : 
     688           0 : static errno_t setnetgrent_recv(struct tevent_req *req)
     689             : {
     690           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     691           0 :     return EOK;
     692             : }
     693             : 
     694           0 : static void nss_cmd_setnetgrent_done(struct tevent_req *req)
     695             : {
     696             :     errno_t reqret;
     697             :     errno_t ret;
     698             :     struct sss_packet *packet;
     699             :     uint8_t *body;
     700             :     size_t blen;
     701             : 
     702           0 :     struct nss_cmd_ctx *cmdctx =
     703           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
     704             : 
     705           0 :     reqret = setnetgrent_recv(req);
     706           0 :     talloc_zfree(req);
     707           0 :     if (reqret != EOK && reqret != ENOENT) {
     708           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "setnetgrent failed\n");
     709           0 :         nss_cmd_done(cmdctx, reqret);
     710           0 :         return;
     711             :     }
     712             : 
     713             :     /* Either we succeeded or no domains were eligible */
     714           0 :     ret = sss_packet_new(cmdctx->cctx->creq, 0,
     715           0 :                          sss_packet_get_cmd(cmdctx->cctx->creq->in),
     716           0 :                          &cmdctx->cctx->creq->out);
     717           0 :     if (ret == EOK) {
     718           0 :         if (reqret == ENOENT) {
     719             :             /* Notify the caller that this entry wasn't found */
     720           0 :             sss_cmd_empty_packet(cmdctx->cctx->creq->out);
     721             :         } else {
     722           0 :             packet = cmdctx->cctx->creq->out;
     723           0 :             ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
     724           0 :             if (ret != EOK) {
     725           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't grow the packet\n");
     726           0 :                 NSS_CMD_FATAL_ERROR(cmdctx);
     727             :             }
     728             : 
     729           0 :             sss_packet_get_body(packet, &body, &blen);
     730             : 
     731             :             /* Got some results. */
     732           0 :             SAFEALIGN_SETMEM_UINT32(body, 1, NULL);
     733             : 
     734             :             /* reserved */
     735           0 :             SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
     736             :         }
     737             : 
     738           0 :         sss_cmd_done(cmdctx->cctx, cmdctx);
     739           0 :         return;
     740             :     }
     741             : 
     742           0 :     DEBUG(SSSDBG_CRIT_FAILURE, "Error creating packet\n");
     743             : }
     744             : 
     745             : static void setnetgrent_implicit_done(struct tevent_req *req);
     746             : static errno_t nss_cmd_getnetgrent_process(struct nss_cmd_ctx *cmdctx,
     747             :                                            struct getent_ctx *netgr);
     748           0 : int nss_cmd_getnetgrent(struct cli_ctx *client)
     749             : {
     750             :     errno_t ret;
     751             :     struct nss_ctx *nctx;
     752             :     struct nss_cmd_ctx *cmdctx;
     753             :     struct getent_ctx *netgr;
     754             :     struct tevent_req *req;
     755             : 
     756           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Requesting netgroup data\n");
     757             : 
     758           0 :     cmdctx = talloc_zero(client, struct nss_cmd_ctx);
     759           0 :     if (!cmdctx) {
     760           0 :         return ENOMEM;
     761             :     }
     762           0 :     cmdctx->cctx = client;
     763             : 
     764           0 :     nctx = talloc_get_type(client->rctx->pvt_ctx, struct nss_ctx);
     765             : 
     766           0 :     if (!client->netgr_name) {
     767             :         /* Tried to run getnetgrent without a preceding
     768             :          * setnetgrent. There is no way to determine which
     769             :          * netgroup is being requested.
     770             :          */
     771           0 :         return nss_cmd_done(cmdctx, EINVAL);
     772             :     }
     773             : 
     774             :     /* Look up the results from the hash */
     775           0 :     ret = get_netgroup_entry(nctx, client->netgr_name, &netgr);
     776           0 :     if (ret == ENOENT) {
     777             :         /* We need to invoke an implicit setnetgrent() to
     778             :          * wait for the result object to become available.
     779             :          */
     780             : 
     781           0 :         req = setnetgrent_send(cmdctx, client->netgr_name, cmdctx);
     782           0 :         if (!req) {
     783           0 :             return nss_cmd_done(cmdctx, EIO);
     784             :         }
     785           0 :         tevent_req_set_callback(req, setnetgrent_implicit_done, cmdctx);
     786             : 
     787           0 :         return EOK;
     788           0 :     } else if (ret != EOK) {
     789           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "An unexpected error occurred: [%d][%s]\n",
     790             :                   ret, strerror(ret));
     791             : 
     792           0 :         return nss_cmd_done(cmdctx, ret);
     793             :     }
     794             : 
     795             :     /* Hash entry was found. Is it ready? */
     796           0 :     if (!netgr->ready) {
     797             :         /* We need to invoke an implicit setnetgrent() to
     798             :          * wait for the result object to become available.
     799             :          */
     800           0 :         req = setnetgrent_send(cmdctx, client->netgr_name, cmdctx);
     801           0 :         if (!req) {
     802           0 :             return nss_cmd_done(cmdctx, EIO);
     803             :         }
     804           0 :         tevent_req_set_callback(req, setnetgrent_implicit_done, cmdctx);
     805             : 
     806           0 :         return EOK;
     807           0 :     } else if (!netgr->found) {
     808           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     809             :               "Results for [%s] not found.\n", client->netgr_name);
     810           0 :         return ENOENT;
     811             :     }
     812             : 
     813           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     814             :           "Returning results for [%s]\n", client->netgr_name);
     815             : 
     816             :     /* Read the result strings */
     817           0 :     ret = nss_cmd_getnetgrent_process(cmdctx, netgr);
     818           0 :     if (ret != EOK) {
     819           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed: [%d][%s]\n", ret, strerror(ret));
     820             :     }
     821           0 :     return ret;
     822             : }
     823             : 
     824           0 : static void setnetgrent_implicit_done(struct tevent_req *req)
     825             : {
     826             :     errno_t ret;
     827             :     struct getent_ctx *netgr;
     828           0 :     struct nss_cmd_ctx *cmdctx =
     829           0 :             tevent_req_callback_data(req, struct nss_cmd_ctx);
     830           0 :     struct nss_ctx *nctx =
     831           0 :             talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct nss_ctx);
     832             : 
     833           0 :     ret = setnetgrent_recv(req);
     834           0 :     talloc_zfree(req);
     835             : 
     836             :     /* ENOENT is acceptable, it just means there were no values
     837             :      * to be returned. This will be handled gracefully in
     838             :      * nss_cmd_retnetgrent later
     839             :      */
     840           0 :     if (ret != EOK && ret != ENOENT) {
     841           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     842             :               "Implicit setnetgrent failed with unexpected error "
     843             :                   "[%d][%s]\n", ret, strerror(ret));
     844           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     845             :     }
     846             : 
     847           0 :     if (ret == ENOENT) {
     848             :         /* No entries found for this netgroup */
     849           0 :         nss_cmd_done(cmdctx, ret);
     850           0 :         return;
     851             :     }
     852             : 
     853             :     /* Look up the results from the hash */
     854           0 :     ret = get_netgroup_entry(nctx, cmdctx->cctx->netgr_name, &netgr);
     855           0 :     if (ret == ENOENT) {
     856             :         /* Critical error. This should never happen */
     857           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     858             :               "Implicit setnetgrent returned success without creating "
     859             :                   "result object.\n");
     860           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     861           0 :     } else if (ret != EOK) {
     862           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "An unexpected error occurred: [%d][%s]\n",
     863             :                   ret, strerror(ret));
     864             : 
     865           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     866             :     }
     867             : 
     868           0 :     if (!netgr->ready) {
     869             :         /* Critical error. This should never happen */
     870           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     871             :               "Implicit setnetgrent returned success without creating "
     872             :                   "result object.\n");
     873           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     874             :     }
     875             : 
     876           0 :     ret = nss_cmd_getnetgrent_process(cmdctx, netgr);
     877           0 :     if (ret != EOK) {
     878           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     879             :               "Immediate retrieval failed with unexpected error "
     880             :                   "[%d][%s]\n", ret, strerror(ret));
     881           0 :         NSS_CMD_FATAL_ERROR(cmdctx);
     882             :     }
     883             : }
     884             : 
     885             : static errno_t nss_cmd_retnetgrent(struct cli_ctx *client,
     886             :                                    struct sysdb_netgroup_ctx **entries,
     887             :                                    int num);
     888           0 : static errno_t nss_cmd_getnetgrent_process(struct nss_cmd_ctx *cmdctx,
     889             :                                            struct getent_ctx *netgr)
     890             : {
     891           0 :     struct cli_ctx *client = cmdctx->cctx;
     892             :     uint8_t *body;
     893             :     size_t blen;
     894             :     uint32_t num;
     895             :     errno_t ret;
     896             : 
     897             :     /* get max num of entries to return in one call */
     898           0 :     sss_packet_get_body(client->creq->in, &body, &blen);
     899           0 :     if (blen != sizeof(uint32_t)) {
     900           0 :         return EINVAL;
     901             :     }
     902           0 :     SAFEALIGN_COPY_UINT32(&num, body, NULL);
     903             : 
     904             :     /* create response packet */
     905           0 :     ret = sss_packet_new(client->creq, 0,
     906           0 :                          sss_packet_get_cmd(client->creq->in),
     907           0 :                          &client->creq->out);
     908           0 :     if (ret != EOK) {
     909           0 :         return ret;
     910             :     }
     911             : 
     912           0 :     if (!netgr->entries || netgr->entries[0] == NULL) {
     913             :         /* No entries */
     914           0 :         DEBUG(SSSDBG_FUNC_DATA, "No entries found\n");
     915           0 :         ret = sss_cmd_empty_packet(client->creq->out);
     916           0 :         if (ret != EOK) {
     917           0 :             return nss_cmd_done(cmdctx, ret);
     918             :         }
     919           0 :         goto done;
     920             :     }
     921             : 
     922           0 :     ret = nss_cmd_retnetgrent(client, netgr->entries, num);
     923             : 
     924             : done:
     925           0 :     sss_packet_set_error(client->creq->out, ret);
     926           0 :     sss_cmd_done(client, cmdctx);
     927             : 
     928           0 :     return EOK;
     929             : }
     930             : 
     931           0 : static errno_t nss_cmd_retnetgrent(struct cli_ctx *client,
     932             :                                    struct sysdb_netgroup_ctx **entries,
     933             :                                    int count)
     934             : {
     935             :     size_t len;
     936           0 :     size_t hostlen = 0;
     937           0 :     size_t userlen = 0;
     938           0 :     size_t domainlen = 0;
     939           0 :     size_t grouplen = 0;
     940             :     uint8_t *body;
     941             :     size_t blen, rp;
     942             :     errno_t ret;
     943           0 :     struct sss_packet *packet = client->creq->out;
     944             :     int num, start;
     945             : 
     946             :     /* first 2 fields (len and reserved), filled up later */
     947           0 :     rp = 2*sizeof(uint32_t);
     948           0 :     ret = sss_packet_grow(packet, rp);
     949           0 :     if (ret != EOK) return ret;
     950             : 
     951           0 :     start = client->netgrent_cur;
     952           0 :     num = 0;
     953           0 :     while (entries[client->netgrent_cur] &&
     954           0 :            (client->netgrent_cur - start) < count) {
     955           0 :         if (entries[client->netgrent_cur]->type == SYSDB_NETGROUP_TRIPLE_VAL) {
     956           0 :             hostlen = 1;
     957           0 :             if (entries[client->netgrent_cur]->value.triple.hostname) {
     958           0 :                 hostlen += strlen(entries[client->netgrent_cur]->value.triple.hostname);
     959             :             }
     960             : 
     961           0 :             userlen = 1;
     962           0 :             if (entries[client->netgrent_cur]->value.triple.username) {
     963           0 :                 userlen += strlen(entries[client->netgrent_cur]->value.triple.username);
     964             :             }
     965             : 
     966           0 :             domainlen = 1;
     967           0 :             if (entries[client->netgrent_cur]->value.triple.domainname) {
     968           0 :                 domainlen += strlen(entries[client->netgrent_cur]->value.triple.domainname);
     969             :             }
     970             : 
     971           0 :             len = sizeof(uint32_t) + hostlen + userlen + domainlen;
     972           0 :             ret = sss_packet_grow(packet, len);
     973           0 :             if (ret != EOK) {
     974           0 :                 return ret;
     975             :             }
     976           0 :             sss_packet_get_body(packet, &body, &blen);
     977             : 
     978           0 :             SAFEALIGN_SET_UINT32(&body[rp], SSS_NETGR_REP_TRIPLE, &rp);
     979             : 
     980           0 :             if (hostlen == 1) {
     981           0 :                 body[rp] = '\0';
     982             :             } else {
     983           0 :                 memcpy(&body[rp],
     984           0 :                        entries[client->netgrent_cur]->value.triple.hostname,
     985             :                        hostlen);
     986             :             }
     987           0 :             rp += hostlen;
     988             : 
     989           0 :             if (userlen == 1) {
     990           0 :                 body[rp] = '\0';
     991             :             } else {
     992           0 :                 memcpy(&body[rp],
     993           0 :                        entries[client->netgrent_cur]->value.triple.username,
     994             :                        userlen);
     995             :             }
     996           0 :             rp += userlen;
     997             : 
     998           0 :             if (domainlen == 1) {
     999           0 :                 body[rp] = '\0';
    1000             :             } else {
    1001           0 :                 memcpy(&body[rp],
    1002           0 :                        entries[client->netgrent_cur]->value.triple.domainname,
    1003             :                        domainlen);
    1004             :             }
    1005           0 :             rp += domainlen;
    1006           0 :         } else if (entries[client->netgrent_cur]->type == SYSDB_NETGROUP_GROUP_VAL) {
    1007           0 :             if (entries[client->netgrent_cur]->value.groupname == NULL ||
    1008           0 :                 entries[client->netgrent_cur]->value.groupname[0] == '\0') {
    1009           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1010             :                       "Empty netgroup member. Please check your cache.\n");
    1011           0 :                 continue;
    1012             :             }
    1013             : 
    1014           0 :             grouplen = 1 + strlen(entries[client->netgrent_cur]->value.groupname);
    1015             : 
    1016           0 :             len = sizeof(uint32_t) + grouplen;
    1017             : 
    1018           0 :             ret = sss_packet_grow(packet, len);
    1019           0 :             if (ret != EOK) {
    1020           0 :                 return ret;
    1021             :             }
    1022             : 
    1023           0 :             sss_packet_get_body(packet, &body, &blen);
    1024             : 
    1025           0 :             SAFEALIGN_SET_UINT32(&body[rp], SSS_NETGR_REP_GROUP, &rp);
    1026             : 
    1027           0 :             memcpy(&body[rp],
    1028           0 :                    entries[client->netgrent_cur]->value.groupname,
    1029             :                    grouplen);
    1030           0 :             rp += grouplen;
    1031             :         } else {
    1032           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1033             :                   "Unexpected value type for netgroup entry. "
    1034             :                       "Please check your cache.\n");
    1035           0 :             continue;
    1036             :         }
    1037             : 
    1038           0 :         num++;
    1039           0 :         client->netgrent_cur++;
    1040             :     }
    1041             : 
    1042           0 :     sss_packet_get_body(packet, &body, &blen);
    1043             : 
    1044             :     /* num results */
    1045           0 :     SAFEALIGN_COPY_UINT32(body, &num, NULL);
    1046             : 
    1047             :     /* reserved */
    1048           0 :     SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
    1049             : 
    1050           0 :     return EOK;
    1051             : }
    1052             : 
    1053           0 : int nss_cmd_endnetgrent(struct cli_ctx *client)
    1054             : {
    1055             :     errno_t ret;
    1056             : 
    1057             :     /* create response packet */
    1058           0 :     ret = sss_packet_new(client->creq, 0,
    1059           0 :                          sss_packet_get_cmd(client->creq->in),
    1060           0 :                          &client->creq->out);
    1061             : 
    1062           0 :     if (ret != EOK) {
    1063           0 :         return ret;
    1064             :     }
    1065             : 
    1066             :     /* Reset the indices so that subsequent requests start at zero */
    1067           0 :     client->netgrent_cur = 0;
    1068           0 :     talloc_zfree(client->netgr_name);
    1069             : 
    1070           0 :     sss_cmd_done(client, NULL);
    1071           0 :     return EOK;
    1072             : }
    1073             : 
    1074             : void
    1075           0 : netgroup_hash_delete_cb(hash_entry_t *item,
    1076             :                         hash_destroy_enum deltype, void *pvt)
    1077             : {
    1078             :     struct getent_ctx *netgr;
    1079             : 
    1080           0 :     if (deltype != HASH_ENTRY_DESTROY) {
    1081           0 :         return;
    1082             :     }
    1083             : 
    1084           0 :     netgr = talloc_get_type(item->value.ptr, struct getent_ctx);
    1085           0 :     if (!netgr) {
    1086           0 :         DEBUG(SSSDBG_OP_FAILURE, "Invalid netgroup\n");
    1087           0 :         return;
    1088             :     }
    1089             : 
    1090             :     /* So that the destructor wouldn't attempt to remove the netgroup from hash
    1091             :      * table */
    1092           0 :     netgr->lookup_table = NULL;
    1093             : }
    1094             : 
    1095           0 : errno_t nss_orphan_netgroups(struct nss_ctx *nctx)
    1096             : {
    1097             :     int hret;
    1098             :     unsigned long mcount;
    1099             :     unsigned long i;
    1100             :     hash_key_t *netgroups;
    1101             : 
    1102           0 :     if (!nctx || !nctx->netgroups) {
    1103           0 :         return EINVAL;
    1104             :     }
    1105             : 
    1106           0 :     hret = hash_keys(nctx->netgroups, &mcount, &netgroups);
    1107           0 :     if (hret != HASH_SUCCESS) {
    1108           0 :         return EIO;
    1109             :     }
    1110             : 
    1111           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Removing netgroups from memory cache.\n");
    1112             : 
    1113           0 :     for (i = 0; i < mcount; i++) {
    1114             :         /* netgroup entry will be deleted by setnetgrent_result_timeout */
    1115           0 :         hret = hash_delete(nctx->netgroups, &netgroups[i]);
    1116           0 :         if (hret != HASH_SUCCESS) {
    1117           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete key from hash\n");
    1118           0 :             continue;
    1119             :         }
    1120             :     }
    1121             : 
    1122           0 :     return EOK;
    1123             : }

Generated by: LCOV version 1.10