LCOV - code coverage report
Current view: top level - sss_client - nss_group.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 54 321 16.8 %
Date: 2016-06-29 Functions: 4 12 33.3 %

          Line data    Source code
       1             : /*
       2             :  * System Security Services Daemon. NSS client interface
       3             :  *
       4             :  * Copyright (C) Simo Sorce 2007
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of the
       9             :  * License, or (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /* GROUP database NSS interface */
      21             : 
      22             : #include <nss.h>
      23             : #include <errno.h>
      24             : #include <sys/types.h>
      25             : #include <unistd.h>
      26             : #include <stdlib.h>
      27             : #include <stdint.h>
      28             : #include <string.h>
      29             : #include <stdbool.h>
      30             : #include "sss_cli.h"
      31             : #include "nss_mc.h"
      32             : 
      33             : static struct sss_nss_getgrent_data {
      34             :     size_t len;
      35             :     size_t ptr;
      36             :     uint8_t *data;
      37             : } sss_nss_getgrent_data;
      38             : 
      39           0 : static void sss_nss_getgrent_data_clean(void)
      40             : {
      41           0 :     if (sss_nss_getgrent_data.data != NULL) {
      42           0 :         free(sss_nss_getgrent_data.data);
      43           0 :         sss_nss_getgrent_data.data = NULL;
      44             :     }
      45           0 :     sss_nss_getgrent_data.len = 0;
      46           0 :     sss_nss_getgrent_data.ptr = 0;
      47           0 : }
      48             : 
      49             : enum sss_nss_gr_type {
      50             :     GETGR_NONE,
      51             :     GETGR_NAME,
      52             :     GETGR_GID
      53             : };
      54             : 
      55             : static struct sss_nss_getgr_data {
      56             :     enum sss_nss_gr_type type;
      57             :     union {
      58             :         char *grname;
      59             :         gid_t gid;
      60             :     } id;
      61             : 
      62             :     uint8_t *repbuf;
      63             :     size_t replen;
      64             : } sss_nss_getgr_data;
      65             : 
      66          26 : static void sss_nss_getgr_data_clean(bool freebuf)
      67             : {
      68          26 :     if (sss_nss_getgr_data.type == GETGR_NAME) {
      69           0 :         free(sss_nss_getgr_data.id.grname);
      70             :     }
      71          26 :     if (freebuf) {
      72          26 :         free(sss_nss_getgr_data.repbuf);
      73             :     }
      74          26 :     memset(&sss_nss_getgr_data, 0, sizeof(struct sss_nss_getgr_data));
      75          26 : }
      76             : 
      77          26 : static enum nss_status sss_nss_get_getgr_cache(const char *name, gid_t gid,
      78             :                                                enum sss_nss_gr_type type,
      79             :                                                uint8_t **repbuf,
      80             :                                                size_t *replen,
      81             :                                                int *errnop)
      82             : {
      83          26 :     bool freebuf = true;
      84             :     enum nss_status status;
      85          26 :     int ret = 0;
      86             : 
      87          26 :     if (sss_nss_getgr_data.type != type) {
      88          26 :         status = NSS_STATUS_NOTFOUND;
      89          26 :         goto done;
      90             :     }
      91             : 
      92           0 :     switch (type) {
      93             :     case GETGR_NAME:
      94           0 :         ret = strcmp(name, sss_nss_getgr_data.id.grname);
      95           0 :         if (ret != 0) {
      96           0 :             status = NSS_STATUS_NOTFOUND;
      97           0 :             goto done;
      98             :         }
      99           0 :         break;
     100             :     case GETGR_GID:
     101           0 :         if (sss_nss_getgr_data.id.gid != gid) {
     102           0 :             status = NSS_STATUS_NOTFOUND;
     103           0 :             goto done;
     104             :         }
     105           0 :         break;
     106             :     default:
     107           0 :         status = NSS_STATUS_TRYAGAIN;
     108           0 :         ret = EINVAL;
     109           0 :         goto done;
     110             :     }
     111             : 
     112             :     /* ok we have it, remove from cache and pass back to the caller */
     113           0 :     *repbuf = sss_nss_getgr_data.repbuf;
     114           0 :     *replen = sss_nss_getgr_data.replen;
     115             : 
     116             :     /* prevent _clean() from freeing the buffer */
     117           0 :     freebuf = false;
     118           0 :     status = NSS_STATUS_SUCCESS;
     119             : 
     120             : done:
     121          26 :     sss_nss_getgr_data_clean(freebuf);
     122          26 :     *errnop = ret;
     123          26 :     return status;
     124             : }
     125             : 
     126             : /* this function always takes ownership of repbuf and NULLs it before
     127             :  * returning */
     128           0 : static void sss_nss_save_getgr_cache(const char *name, gid_t gid,
     129             :                                      enum sss_nss_gr_type type,
     130             :                                      uint8_t **repbuf, size_t replen)
     131             : {
     132           0 :     int ret = 0;
     133             : 
     134           0 :     sss_nss_getgr_data.type = type;
     135           0 :     sss_nss_getgr_data.repbuf = *repbuf;
     136           0 :     sss_nss_getgr_data.replen = replen;
     137             : 
     138           0 :     switch (type) {
     139             :     case GETGR_NAME:
     140           0 :         if (name == NULL) {
     141           0 :             ret = EINVAL;
     142           0 :             goto done;
     143             :         }
     144           0 :         sss_nss_getgr_data.id.grname = strdup(name);
     145           0 :         if (!sss_nss_getgr_data.id.grname) {
     146           0 :             ret = ENOMEM;
     147           0 :             goto done;
     148             :         }
     149           0 :         break;
     150             :     case GETGR_GID:
     151           0 :         if (gid == 0) {
     152           0 :             ret = EINVAL;
     153           0 :             goto done;
     154             :         }
     155           0 :         sss_nss_getgr_data.id.gid = gid;
     156           0 :         break;
     157             :     default:
     158           0 :         ret = EINVAL;
     159           0 :         goto done;
     160             :     }
     161             : 
     162             : done:
     163           0 :     if (ret) {
     164           0 :         sss_nss_getgr_data_clean(true);
     165             :     }
     166           0 :     *repbuf = NULL;
     167           0 : }
     168             : 
     169             : /* GETGRNAM Request:
     170             :  *
     171             :  * 0-X: string with name
     172             :  *
     173             :  * GERTGRGID Request:
     174             :  *
     175             :  * 0-7: 32bit number with gid
     176             :  *
     177             :  * INITGROUPS Request:
     178             :  *
     179             :  * 0-3: 32bit number with gid
     180             :  * 4-7: 32bit unsigned with max num of entries
     181             :  *
     182             :  * Replies:
     183             :  *
     184             :  * 0-3: 32bit unsigned number of results
     185             :  * 4-7: 32bit unsigned (reserved/padding)
     186             :  *  For each result (64bit padded ?):
     187             :  *  0-3: 32bit number gid
     188             :  *  4-7: 32bit unsigned number of members
     189             :  *  8-X: sequence of 0 terminated strings (name, passwd, mem..)
     190             :  *
     191             :  *  FIXME: do we need to pad so that each result is 32 bit aligned ?
     192             :  */
     193             : struct sss_nss_gr_rep {
     194             :     struct group *result;
     195             :     char *buffer;
     196             :     size_t buflen;
     197             : };
     198             : 
     199           0 : static int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr,
     200             :                                  uint8_t *buf, size_t *len)
     201             : {
     202             :     errno_t ret;
     203             :     size_t i, l, slen, ptmem, pad, dlen, glen;
     204             :     char *sbuf;
     205             :     uint32_t mem_num;
     206             :     uint32_t c;
     207             : 
     208           0 :     if (*len < 11) { /* not enough space for data, bad packet */
     209           0 :         return EBADMSG;
     210             :     }
     211             : 
     212           0 :     SAFEALIGN_COPY_UINT32(&c, buf, NULL);
     213           0 :     pr->result->gr_gid = c;
     214           0 :     SAFEALIGN_COPY_UINT32(&mem_num, buf+sizeof(uint32_t), NULL);
     215             : 
     216           0 :     sbuf = (char *)&buf[8];
     217           0 :     slen = *len - 8;
     218           0 :     dlen = pr->buflen;
     219             : 
     220           0 :     pr->result->gr_name = &(pr->buffer[0]);
     221           0 :     i = 0;
     222             : 
     223           0 :     ret = sss_readrep_copy_string(sbuf, &i,
     224             :                                   &slen, &dlen,
     225           0 :                                   &pr->result->gr_name,
     226             :                                   NULL);
     227           0 :     if (ret != EOK) return ret;
     228             : 
     229           0 :     pr->result->gr_passwd = &(pr->buffer[i]);
     230           0 :     ret = sss_readrep_copy_string(sbuf, &i,
     231             :                                   &slen, &dlen,
     232           0 :                                   &pr->result->gr_passwd,
     233             :                                   NULL);
     234           0 :     if (ret != EOK) return ret;
     235             : 
     236             :     /* Make sure pr->buffer[i+pad] is aligned to sizeof(char *) */
     237           0 :     pad = PADDING_SIZE(i, char *);
     238             : 
     239             :     /* now members */
     240           0 :     pr->result->gr_mem = DISCARD_ALIGN(&(pr->buffer[i+pad]), char **);
     241             : 
     242           0 :     ptmem = (sizeof(char *) * (mem_num + 1)) + pad;
     243           0 :     if (ptmem > dlen) {
     244           0 :         return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
     245             :     }
     246           0 :     dlen -= ptmem;
     247           0 :     ptmem += i;
     248           0 :     pr->result->gr_mem[mem_num] = NULL; /* terminate array */
     249             : 
     250           0 :     for (l = 0; l < mem_num; l++) {
     251           0 :         pr->result->gr_mem[l] = &(pr->buffer[ptmem]);
     252           0 :         ret = sss_readrep_copy_string(sbuf, &i,
     253             :                                       &slen, &dlen,
     254           0 :                                       &pr->result->gr_mem[l],
     255             :                                       &glen);
     256           0 :         if (ret != EOK) return ret;
     257             : 
     258           0 :         ptmem += glen + 1;
     259             :     }
     260             : 
     261           0 :     *len = slen -i;
     262           0 :     return 0;
     263             : }
     264             : 
     265             : /* INITGROUP Reply:
     266             :  *
     267             :  * 0-3: 32bit unsigned number of results
     268             :  * 4-7: 32bit unsigned (reserved/padding)
     269             :  * For each result:
     270             :  *  0-4: 32bit number with gid
     271             :  */
     272             : 
     273             : 
     274           0 : enum nss_status _nss_sss_initgroups_dyn(const char *user, gid_t group,
     275             :                                         long int *start, long int *size,
     276             :                                         gid_t **groups, long int limit,
     277             :                                         int *errnop)
     278             : {
     279             :     struct sss_cli_req_data rd;
     280             :     uint8_t *repbuf;
     281             :     size_t replen;
     282             :     enum nss_status nret;
     283           0 :     size_t buf_index = 0;
     284             :     size_t user_len;
     285             :     uint32_t num_ret;
     286             :     long int l, max_ret;
     287             :     int ret;
     288             : 
     289           0 :     ret = sss_strnlen(user, SSS_NAME_MAX, &user_len);
     290           0 :     if (ret != 0) {
     291           0 :         *errnop = EINVAL;
     292           0 :         return NSS_STATUS_NOTFOUND;
     293             :     }
     294             : 
     295           0 :     ret = sss_nss_mc_initgroups_dyn(user, user_len, group, start, size,
     296             :                                     groups, limit);
     297           0 :     switch (ret) {
     298             :     case 0:
     299           0 :         *errnop = 0;
     300           0 :         return NSS_STATUS_SUCCESS;
     301             :     case ERANGE:
     302           0 :         *errnop = ERANGE;
     303           0 :         return NSS_STATUS_TRYAGAIN;
     304             :     case ENOENT:
     305             :         /* fall through, we need to actively ask the parent
     306             :          * if no entry is found */
     307           0 :         break;
     308             :     default:
     309             :         /* if using the mmaped cache failed,
     310             :          * fall back to socket based comms */
     311           0 :         break;
     312             :     }
     313             : 
     314           0 :     rd.len = user_len + 1;
     315           0 :     rd.data = user;
     316             : 
     317           0 :     sss_nss_lock();
     318             : 
     319             :     /* previous thread might already initialize entry in mmap cache */
     320           0 :     ret = sss_nss_mc_initgroups_dyn(user, user_len, group, start, size,
     321             :                                     groups, limit);
     322           0 :     switch (ret) {
     323             :     case 0:
     324           0 :         *errnop = 0;
     325           0 :         nret = NSS_STATUS_SUCCESS;
     326           0 :         goto out;
     327             :     case ERANGE:
     328           0 :         *errnop = ERANGE;
     329           0 :         nret = NSS_STATUS_TRYAGAIN;
     330           0 :         goto out;
     331             :     case ENOENT:
     332             :         /* fall through, we need to actively ask the parent
     333             :          * if no entry is found */
     334           0 :         break;
     335             :     default:
     336             :         /* if using the mmaped cache failed,
     337             :          * fall back to socket based comms */
     338           0 :         break;
     339             :     }
     340             : 
     341           0 :     nret = sss_nss_make_request(SSS_NSS_INITGR, &rd,
     342             :                                 &repbuf, &replen, errnop);
     343           0 :     if (nret != NSS_STATUS_SUCCESS) {
     344           0 :         goto out;
     345             :     }
     346             : 
     347             :     /* no results if not found */
     348           0 :     SAFEALIGN_COPY_UINT32(&num_ret, repbuf, NULL);
     349           0 :     if (num_ret == 0) {
     350           0 :         free(repbuf);
     351           0 :         nret = NSS_STATUS_NOTFOUND;
     352           0 :         goto out;
     353             :     }
     354           0 :     max_ret = num_ret;
     355             : 
     356             :     /* check we have enough space in the buffer */
     357           0 :     if ((*size - *start) < num_ret) {
     358             :         long int newsize;
     359             :         gid_t *newgroups;
     360             : 
     361           0 :         newsize = *size + num_ret;
     362           0 :         if ((limit > 0) && (newsize > limit)) {
     363           0 :             newsize = limit;
     364           0 :             max_ret = newsize - *start;
     365             :         }
     366             : 
     367           0 :         newgroups = (gid_t *)realloc((*groups), newsize * sizeof(**groups));
     368           0 :         if (!newgroups) {
     369           0 :             *errnop = ENOMEM;
     370           0 :             free(repbuf);
     371           0 :             nret = NSS_STATUS_TRYAGAIN;
     372           0 :             goto out;
     373             :         }
     374           0 :         *groups = newgroups;
     375           0 :         *size = newsize;
     376             :     }
     377             : 
     378             :     /* Skip first two 32 bit values (number of results and
     379             :      * reserved padding) */
     380           0 :     buf_index = 2 * sizeof(uint32_t);
     381             : 
     382           0 :     for (l = 0; l < max_ret; l++) {
     383           0 :         SAFEALIGN_COPY_UINT32(&(*groups)[*start], repbuf + buf_index,
     384             :                                  &buf_index);
     385           0 :         *start += 1;
     386             :     }
     387             : 
     388           0 :     free(repbuf);
     389           0 :     nret = NSS_STATUS_SUCCESS;
     390             : 
     391             : out:
     392           0 :     sss_nss_unlock();
     393           0 :     return nret;
     394             : }
     395             : 
     396             : 
     397          24 : enum nss_status _nss_sss_getgrnam_r(const char *name, struct group *result,
     398             :                                     char *buffer, size_t buflen, int *errnop)
     399             : {
     400             :     struct sss_cli_req_data rd;
     401             :     struct sss_nss_gr_rep grrep;
     402             :     uint8_t *repbuf;
     403             :     size_t replen, len, name_len;
     404             :     uint32_t num_results;
     405             :     enum nss_status nret;
     406             :     int ret;
     407             : 
     408             :     /* Caught once glibc passing in buffer == 0x0 */
     409          24 :     if (!buffer || !buflen) {
     410           0 :         *errnop = ERANGE;
     411           0 :         return NSS_STATUS_TRYAGAIN;
     412             :     }
     413             : 
     414          24 :     ret = sss_strnlen(name, SSS_NAME_MAX, &name_len);
     415          24 :     if (ret != 0) {
     416           0 :         *errnop = EINVAL;
     417           0 :         return NSS_STATUS_NOTFOUND;
     418             :     }
     419             : 
     420          24 :     ret = sss_nss_mc_getgrnam(name, name_len, result, buffer, buflen);
     421          24 :     switch (ret) {
     422             :     case 0:
     423           0 :         *errnop = 0;
     424           0 :         return NSS_STATUS_SUCCESS;
     425             :     case ERANGE:
     426           0 :         *errnop = ERANGE;
     427           0 :         return NSS_STATUS_TRYAGAIN;
     428             :     case ENOENT:
     429             :         /* fall through, we need to actively ask the parent
     430             :          * if no entry is found */
     431          24 :         break;
     432             :     default:
     433             :         /* if using the mmaped cache failed,
     434             :          * fall back to socket based comms */
     435           0 :         break;
     436             :     }
     437             : 
     438          24 :     rd.len = name_len + 1;
     439          24 :     rd.data = name;
     440             : 
     441          24 :     sss_nss_lock();
     442             : 
     443             :     /* previous thread might already initialize entry in mmap cache */
     444          24 :     ret = sss_nss_mc_getgrnam(name, name_len, result, buffer, buflen);
     445          24 :     switch (ret) {
     446             :     case 0:
     447           0 :         *errnop = 0;
     448           0 :         nret = NSS_STATUS_SUCCESS;
     449           0 :         goto out;
     450             :     case ERANGE:
     451           0 :         *errnop = ERANGE;
     452           0 :         nret = NSS_STATUS_TRYAGAIN;
     453           0 :         goto out;
     454             :     case ENOENT:
     455             :         /* fall through, we need to actively ask the parent
     456             :          * if no entry is found */
     457          24 :         break;
     458             :     default:
     459             :         /* if using the mmaped cache failed,
     460             :          * fall back to socket based comms */
     461           0 :         break;
     462             :     }
     463             : 
     464          24 :     nret = sss_nss_get_getgr_cache(name, 0, GETGR_NAME,
     465             :                                    &repbuf, &replen, errnop);
     466          24 :     if (nret == NSS_STATUS_NOTFOUND) {
     467          24 :         nret = sss_nss_make_request(SSS_NSS_GETGRNAM, &rd,
     468             :                                     &repbuf, &replen, errnop);
     469             :     }
     470          24 :     if (nret != NSS_STATUS_SUCCESS) {
     471          24 :         goto out;
     472             :     }
     473             : 
     474           0 :     grrep.result = result;
     475           0 :     grrep.buffer = buffer;
     476           0 :     grrep.buflen = buflen;
     477             : 
     478             :     /* Get number of results from repbuf. */
     479           0 :     SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
     480             : 
     481             :     /* no results if not found */
     482           0 :     if (num_results == 0) {
     483           0 :         free(repbuf);
     484           0 :         nret = NSS_STATUS_NOTFOUND;
     485           0 :         goto out;
     486             :     }
     487             : 
     488             :     /* only 1 result is accepted for this function */
     489           0 :     if (num_results != 1) {
     490           0 :         *errnop = EBADMSG;
     491           0 :         free(repbuf);
     492           0 :         nret = NSS_STATUS_TRYAGAIN;
     493           0 :         goto out;
     494             :     }
     495             : 
     496           0 :     len = replen - 8;
     497           0 :     ret = sss_nss_getgr_readrep(&grrep, repbuf+8, &len);
     498           0 :     if (ret == ERANGE) {
     499           0 :         sss_nss_save_getgr_cache(name, 0, GETGR_NAME, &repbuf, replen);
     500             :     } else {
     501           0 :         free(repbuf);
     502             :     }
     503           0 :     if (ret) {
     504           0 :         *errnop = ret;
     505           0 :         nret = NSS_STATUS_TRYAGAIN;
     506           0 :         goto out;
     507             :     }
     508             : 
     509           0 :     nret = NSS_STATUS_SUCCESS;
     510             : 
     511             : out:
     512          24 :     sss_nss_unlock();
     513          24 :     return nret;
     514             : }
     515             : 
     516           2 : enum nss_status _nss_sss_getgrgid_r(gid_t gid, struct group *result,
     517             :                                     char *buffer, size_t buflen, int *errnop)
     518             : {
     519             :     struct sss_cli_req_data rd;
     520             :     struct sss_nss_gr_rep grrep;
     521             :     uint8_t *repbuf;
     522             :     size_t replen, len;
     523             :     uint32_t num_results;
     524             :     enum nss_status nret;
     525             :     uint32_t group_gid;
     526             :     int ret;
     527             : 
     528             :     /* Caught once glibc passing in buffer == 0x0 */
     529           2 :     if (!buffer || !buflen) return ERANGE;
     530             : 
     531           2 :     ret = sss_nss_mc_getgrgid(gid, result, buffer, buflen);
     532           2 :     switch (ret) {
     533             :     case 0:
     534           0 :         *errnop = 0;
     535           0 :         return NSS_STATUS_SUCCESS;
     536             :     case ERANGE:
     537           0 :         *errnop = ERANGE;
     538           0 :         return NSS_STATUS_TRYAGAIN;
     539             :     case ENOENT:
     540             :         /* fall through, we need to actively ask the parent
     541             :          * if no entry is found */
     542           2 :         break;
     543             :     default:
     544             :         /* if using the mmaped cache failed,
     545             :          * fall back to socket based comms */
     546           0 :         break;
     547             :     }
     548             : 
     549           2 :     group_gid = gid;
     550           2 :     rd.len = sizeof(uint32_t);
     551           2 :     rd.data = &group_gid;
     552             : 
     553           2 :     sss_nss_lock();
     554             : 
     555             :     /* previous thread might already initialize entry in mmap cache */
     556           2 :     ret = sss_nss_mc_getgrgid(gid, result, buffer, buflen);
     557           2 :     switch (ret) {
     558             :     case 0:
     559           0 :         *errnop = 0;
     560           0 :         nret = NSS_STATUS_SUCCESS;
     561           0 :         goto out;
     562             :     case ERANGE:
     563           0 :         *errnop = ERANGE;
     564           0 :         nret = NSS_STATUS_TRYAGAIN;
     565           0 :         goto out;
     566             :     case ENOENT:
     567             :         /* fall through, we need to actively ask the parent
     568             :          * if no entry is found */
     569           2 :         break;
     570             :     default:
     571             :         /* if using the mmaped cache failed,
     572             :          * fall back to socket based comms */
     573           0 :         break;
     574             :     }
     575             : 
     576           2 :     nret = sss_nss_get_getgr_cache(NULL, gid, GETGR_GID,
     577             :                                    &repbuf, &replen, errnop);
     578           2 :     if (nret == NSS_STATUS_NOTFOUND) {
     579           2 :         nret = sss_nss_make_request(SSS_NSS_GETGRGID, &rd,
     580             :                                     &repbuf, &replen, errnop);
     581             :     }
     582           2 :     if (nret != NSS_STATUS_SUCCESS) {
     583           2 :         goto out;
     584             :     }
     585             : 
     586           0 :     grrep.result = result;
     587           0 :     grrep.buffer = buffer;
     588           0 :     grrep.buflen = buflen;
     589             : 
     590             :     /* Get number of results from repbuf. */
     591           0 :     SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
     592             : 
     593             :     /* no results if not found */
     594           0 :     if (num_results == 0) {
     595           0 :         free(repbuf);
     596           0 :         nret = NSS_STATUS_NOTFOUND;
     597           0 :         goto out;
     598             :     }
     599             : 
     600             :     /* only 1 result is accepted for this function */
     601           0 :     if (num_results != 1) {
     602           0 :         *errnop = EBADMSG;
     603           0 :         free(repbuf);
     604           0 :         nret = NSS_STATUS_TRYAGAIN;
     605           0 :         goto out;
     606             :     }
     607             : 
     608           0 :     len = replen - 8;
     609           0 :     ret = sss_nss_getgr_readrep(&grrep, repbuf+8, &len);
     610           0 :     if (ret == ERANGE) {
     611           0 :         sss_nss_save_getgr_cache(NULL, gid, GETGR_GID, &repbuf, replen);
     612             :     } else {
     613           0 :         free(repbuf);
     614             :     }
     615           0 :     if (ret) {
     616           0 :         *errnop = ret;
     617           0 :         nret = NSS_STATUS_TRYAGAIN;
     618           0 :         goto out;
     619             :     }
     620             : 
     621           0 :     nret = NSS_STATUS_SUCCESS;
     622             : 
     623             : out:
     624           2 :     sss_nss_unlock();
     625           2 :     return nret;
     626             : }
     627             : 
     628           0 : enum nss_status _nss_sss_setgrent(void)
     629             : {
     630             :     enum nss_status nret;
     631             :     int errnop;
     632             : 
     633           0 :     sss_nss_lock();
     634             : 
     635             :     /* make sure we do not have leftovers, and release memory */
     636           0 :     sss_nss_getgrent_data_clean();
     637             : 
     638           0 :     nret = sss_nss_make_request(SSS_NSS_SETGRENT,
     639             :                                 NULL, NULL, NULL, &errnop);
     640           0 :     if (nret != NSS_STATUS_SUCCESS) {
     641           0 :         errno = errnop;
     642             :     }
     643             : 
     644           0 :     sss_nss_unlock();
     645           0 :     return nret;
     646             : }
     647             : 
     648           0 : static enum nss_status internal_getgrent_r(struct group *result,
     649             :                                            char *buffer, size_t buflen,
     650             :                                            int *errnop)
     651             : {
     652             :     struct sss_cli_req_data rd;
     653             :     struct sss_nss_gr_rep grrep;
     654             :     uint8_t *repbuf;
     655             :     size_t replen;
     656             :     uint32_t num_results;
     657             :     enum nss_status nret;
     658             :     uint32_t num_entries;
     659             :     int ret;
     660             : 
     661             :     /* Caught once glibc passing in buffer == 0x0 */
     662           0 :     if (!buffer || !buflen) return ERANGE;
     663             : 
     664             :     /* if there are leftovers return the next one */
     665           0 :     if (sss_nss_getgrent_data.data != NULL &&
     666           0 :         sss_nss_getgrent_data.ptr < sss_nss_getgrent_data.len) {
     667             : 
     668           0 :         repbuf = (uint8_t *)sss_nss_getgrent_data.data +
     669             :                     sss_nss_getgrent_data.ptr;
     670           0 :         replen = sss_nss_getgrent_data.len -
     671           0 :                     sss_nss_getgrent_data.ptr;
     672             : 
     673           0 :         grrep.result = result;
     674           0 :         grrep.buffer = buffer;
     675           0 :         grrep.buflen = buflen;
     676             : 
     677           0 :         ret = sss_nss_getgr_readrep(&grrep, repbuf, &replen);
     678           0 :         if (ret) {
     679           0 :             *errnop = ret;
     680           0 :             return NSS_STATUS_TRYAGAIN;
     681             :         }
     682             : 
     683             :         /* advance buffer pointer */
     684           0 :         sss_nss_getgrent_data.ptr = sss_nss_getgrent_data.len - replen;
     685             : 
     686           0 :         return NSS_STATUS_SUCCESS;
     687             :     }
     688             : 
     689             :     /* release memory if any */
     690           0 :     sss_nss_getgrent_data_clean();
     691             : 
     692             :     /* retrieve no more than SSS_NSS_MAX_ENTRIES at a time */
     693           0 :     num_entries = SSS_NSS_MAX_ENTRIES;
     694           0 :     rd.len = sizeof(uint32_t);
     695           0 :     rd.data = &num_entries;
     696             : 
     697           0 :     nret = sss_nss_make_request(SSS_NSS_GETGRENT, &rd,
     698             :                                 &repbuf, &replen, errnop);
     699           0 :     if (nret != NSS_STATUS_SUCCESS) {
     700           0 :         return nret;
     701             :     }
     702             : 
     703             :     /* Get number of results from repbuf. */
     704           0 :     SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
     705             : 
     706             :     /* no results if not found */
     707           0 :     if ((num_results == 0) || (replen - 8 == 0)) {
     708           0 :         free(repbuf);
     709           0 :         return NSS_STATUS_NOTFOUND;
     710             :     }
     711             : 
     712           0 :     sss_nss_getgrent_data.data = repbuf;
     713           0 :     sss_nss_getgrent_data.len = replen;
     714           0 :     sss_nss_getgrent_data.ptr = 8; /* skip metadata fields */
     715             : 
     716             :     /* call again ourselves, this will return the first result */
     717           0 :     return internal_getgrent_r(result, buffer, buflen, errnop);
     718             : }
     719             : 
     720           0 : enum nss_status _nss_sss_getgrent_r(struct group *result,
     721             :                                     char *buffer, size_t buflen, int *errnop)
     722             : {
     723             :     enum nss_status nret;
     724             : 
     725           0 :     sss_nss_lock();
     726           0 :     nret = internal_getgrent_r(result, buffer, buflen, errnop);
     727           0 :     sss_nss_unlock();
     728             : 
     729           0 :     return nret;
     730             : }
     731             : 
     732           0 : enum nss_status _nss_sss_endgrent(void)
     733             : {
     734             :     enum nss_status nret;
     735             :     int errnop;
     736             : 
     737           0 :     sss_nss_lock();
     738             : 
     739             :     /* make sure we do not have leftovers, and release memory */
     740           0 :     sss_nss_getgrent_data_clean();
     741             : 
     742           0 :     nret = sss_nss_make_request(SSS_NSS_ENDGRENT,
     743             :                                 NULL, NULL, NULL, &errnop);
     744           0 :     if (nret != NSS_STATUS_SUCCESS) {
     745           0 :         errno = errnop;
     746             :     }
     747             : 
     748           0 :     sss_nss_unlock();
     749           0 :     return nret;
     750             : }

Generated by: LCOV version 1.10