LCOV - code coverage report
Current view: top level - nsswitch - winbind_nss_linux.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 254 351 72.4 %
Date: 2024-06-13 04:01:37 Functions: 16 17 94.1 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Windows NT Domain nsswitch module
       5             : 
       6             :    Copyright (C) Tim Potter 2000
       7             : 
       8             :    This library is free software; you can redistribute it and/or
       9             :    modify it under the terms of the GNU Lesser General Public
      10             :    License as published by the Free Software Foundation; either
      11             :    version 3 of the License, or (at your option) any later version.
      12             : 
      13             :    This library is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :    Library General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU Lesser General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "winbind_client.h"
      23             : 
      24             : #ifdef HAVE_PTHREAD_H
      25             : #include <pthread.h>
      26             : #endif
      27             : 
      28             : #ifdef HAVE_PTHREAD
      29             : static pthread_mutex_t winbind_nss_mutex = PTHREAD_MUTEX_INITIALIZER;
      30             : #endif
      31             : 
      32             : /* Maximum number of users to pass back over the unix domain socket
      33             :    per call. This is not a static limit on the total number of users
      34             :    or groups returned in total. */
      35             : 
      36             : #define MAX_GETPWENT_USERS 250
      37             : #define MAX_GETGRENT_USERS 250
      38             : 
      39             : /*************************************************************************
      40             :  ************************************************************************/
      41             : 
      42             : #ifdef DEBUG_NSS
      43             : static const char *nss_err_str(NSS_STATUS ret)
      44             : {
      45             :         switch (ret) {
      46             :                 case NSS_STATUS_TRYAGAIN:
      47             :                         return "NSS_STATUS_TRYAGAIN";
      48             :                 case NSS_STATUS_SUCCESS:
      49             :                         return "NSS_STATUS_SUCCESS";
      50             :                 case NSS_STATUS_NOTFOUND:
      51             :                         return "NSS_STATUS_NOTFOUND";
      52             :                 case NSS_STATUS_UNAVAIL:
      53             :                         return "NSS_STATUS_UNAVAIL";
      54             : #ifdef NSS_STATUS_RETURN
      55             :                 case NSS_STATUS_RETURN:
      56             :                         return "NSS_STATUS_RETURN";
      57             : #endif
      58             :                 default:
      59             :                         return "UNKNOWN RETURN CODE!!!!!!!";
      60             :         }
      61             : }
      62             : #endif
      63             : 
      64             : /* Prototypes from wb_common.c */
      65             : 
      66             : /* Allocate some space from the nss static buffer.  The buffer and buflen
      67             :    are the pointers passed in by the C library to the _nss_ntdom_*
      68             :    functions. */
      69             : 
      70       40846 : static char *get_static(char **buffer, size_t *buflen, size_t len)
      71             : {
      72             :         char *result;
      73             : 
      74             :         /* Error check.  We return false if things aren't set up right, or
      75             :            there isn't enough buffer space left. */
      76             : 
      77       40846 :         if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
      78           0 :                 return NULL;
      79             :         }
      80             : 
      81             :         /* Return an index into the static buffer */
      82             : 
      83       40846 :         result = *buffer;
      84       40846 :         *buffer += len;
      85       40846 :         *buflen -= len;
      86             : 
      87       40846 :         return result;
      88             : }
      89             : 
      90             : /* I've copied the strtok() replacement function next_token_Xalloc() from
      91             :    lib/util_str.c as I really don't want to have to link in any other
      92             :    objects if I can possibly avoid it. */
      93             : 
      94          16 : static bool next_token_alloc(const char **ptr,
      95             :                                 char **pp_buff,
      96             :                                 const char *sep)
      97             : {
      98             :         const char *s;
      99             :         const char *saved_s;
     100             :         char *pbuf;
     101             :         bool quoted;
     102          16 :         size_t len=1;
     103             : 
     104          16 :         *pp_buff = NULL;
     105          16 :         if (!ptr) {
     106           0 :                 return(false);
     107             :         }
     108             : 
     109          16 :         s = *ptr;
     110             : 
     111             :         /* default to simple separators */
     112          16 :         if (!sep) {
     113           0 :                 sep = " \t\n\r";
     114             :         }
     115             : 
     116             :         /* find the first non sep char */
     117          24 :         while (*s && strchr(sep,*s)) {
     118           0 :                 s++;
     119             :         }
     120             : 
     121             :         /* nothing left? */
     122          16 :         if (!*s) {
     123           8 :                 return false;
     124             :         }
     125             : 
     126             :         /* When restarting we need to go from here. */
     127           8 :         saved_s = s;
     128             : 
     129             :         /* Work out the length needed. */
     130         188 :         for (quoted = false; *s &&
     131         352 :                         (quoted || !strchr(sep,*s)); s++) {
     132         176 :                 if (*s == '\"') {
     133           0 :                         quoted = !quoted;
     134             :                 } else {
     135         176 :                         len++;
     136             :                 }
     137             :         }
     138             : 
     139             :         /* We started with len = 1 so we have space for the nul. */
     140           8 :         *pp_buff = (char *)malloc(len);
     141           8 :         if (!*pp_buff) {
     142           0 :                 return false;
     143             :         }
     144             : 
     145             :         /* copy over the token */
     146           8 :         pbuf = *pp_buff;
     147           8 :         s = saved_s;
     148         188 :         for (quoted = false; *s &&
     149         352 :                         (quoted || !strchr(sep,*s)); s++) {
     150         176 :                 if ( *s == '\"' ) {
     151           0 :                         quoted = !quoted;
     152             :                 } else {
     153         176 :                         *pbuf++ = *s;
     154             :                 }
     155             :         }
     156             : 
     157           8 :         *ptr = (*s) ? s+1 : s;
     158           8 :         *pbuf = 0;
     159             : 
     160           8 :         return true;
     161             : }
     162             : 
     163             : /* Fill a pwent structure from a winbindd_response structure.  We use
     164             :    the static data passed to us by libc to put strings and stuff in.
     165             :    Return NSS_STATUS_TRYAGAIN if we run out of memory. */
     166             : 
     167        6274 : static NSS_STATUS fill_pwent(struct passwd *result,
     168             :                                   struct winbindd_pw *pw,
     169             :                                   char **buffer, size_t *buflen)
     170             : {
     171             :         size_t len;
     172             : 
     173             :         /* User name */
     174        6274 :         len = strlen(pw->pw_name) + 1;
     175             : 
     176        6274 :         if ((result->pw_name =
     177        6274 :              get_static(buffer, buflen, len)) == NULL) {
     178             : 
     179             :                 /* Out of memory */
     180             : 
     181           0 :                 return NSS_STATUS_TRYAGAIN;
     182             :         }
     183             : 
     184        6274 :         memcpy(result->pw_name, pw->pw_name, len);
     185             : 
     186             :         /* Password */
     187        6274 :         len = strlen(pw->pw_passwd) + 1;
     188             : 
     189        6274 :         if ((result->pw_passwd =
     190        6274 :              get_static(buffer, buflen, len)) == NULL) {
     191             : 
     192             :                 /* Out of memory */
     193             : 
     194           0 :                 return NSS_STATUS_TRYAGAIN;
     195             :         }
     196             : 
     197        6274 :         memcpy(result->pw_passwd, pw->pw_passwd, len);
     198             : 
     199             :         /* [ug]id */
     200             : 
     201        6274 :         result->pw_uid = pw->pw_uid;
     202        6274 :         result->pw_gid = pw->pw_gid;
     203             : 
     204             :         /* GECOS */
     205        6274 :         len = strlen(pw->pw_gecos) + 1;
     206             : 
     207        6274 :         if ((result->pw_gecos =
     208        6274 :              get_static(buffer, buflen, len)) == NULL) {
     209             : 
     210             :                 /* Out of memory */
     211             : 
     212           0 :                 return NSS_STATUS_TRYAGAIN;
     213             :         }
     214             : 
     215        6274 :         memcpy(result->pw_gecos, pw->pw_gecos, len);
     216             : 
     217             :         /* Home directory */
     218        6274 :         len = strlen(pw->pw_dir) + 1;
     219             : 
     220        6274 :         if ((result->pw_dir =
     221        6274 :              get_static(buffer, buflen, len)) == NULL) {
     222             : 
     223             :                 /* Out of memory */
     224             : 
     225           0 :                 return NSS_STATUS_TRYAGAIN;
     226             :         }
     227             : 
     228        6274 :         memcpy(result->pw_dir, pw->pw_dir, len);
     229             : 
     230             :         /* Logon shell */
     231        6274 :         len = strlen(pw->pw_shell) + 1;
     232             : 
     233        6274 :         if ((result->pw_shell =
     234        6274 :              get_static(buffer, buflen, len)) == NULL) {
     235             : 
     236             :                 /* Out of memory */
     237             : 
     238           0 :                 return NSS_STATUS_TRYAGAIN;
     239             :         }
     240             : 
     241        6274 :         memcpy(result->pw_shell, pw->pw_shell, len);
     242             : 
     243             :         /* The struct passwd for Solaris has some extra fields which must
     244             :            be initialised or nscd crashes. */
     245             : 
     246             : #ifdef HAVE_PASSWD_PW_COMMENT
     247             :         result->pw_comment = "";
     248             : #endif
     249             : 
     250             : #ifdef HAVE_PASSWD_PW_AGE
     251             :         result->pw_age = "";
     252             : #endif
     253             : 
     254        6274 :         return NSS_STATUS_SUCCESS;
     255             : }
     256             : 
     257             : /* Fill a grent structure from a winbindd_response structure.  We use
     258             :    the static data passed to us by libc to put strings and stuff in.
     259             :    Return NSS_STATUS_TRYAGAIN if we run out of memory. */
     260             : 
     261        3156 : static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
     262             :                       const char *gr_mem, char **buffer, size_t *buflen)
     263             : {
     264             :         char *name;
     265             :         int i;
     266             :         char *tst;
     267             :         size_t len;
     268             : 
     269             :         /* Group name */
     270        3156 :         len = strlen(gr->gr_name) + 1;
     271             : 
     272        3156 :         if ((result->gr_name =
     273        3156 :              get_static(buffer, buflen, len)) == NULL) {
     274             : 
     275             :                 /* Out of memory */
     276             : 
     277           0 :                 return NSS_STATUS_TRYAGAIN;
     278             :         }
     279             : 
     280        3156 :         memcpy(result->gr_name, gr->gr_name, len);
     281             : 
     282             :         /* Password */
     283        3156 :         len = strlen(gr->gr_passwd) + 1;
     284             : 
     285        3156 :         if ((result->gr_passwd =
     286        3156 :              get_static(buffer, buflen, len)) == NULL) {
     287             : 
     288             :                 /* Out of memory */
     289           0 :                 return NSS_STATUS_TRYAGAIN;
     290             :         }
     291             : 
     292        3156 :         memcpy(result->gr_passwd, gr->gr_passwd, len);
     293             : 
     294             :         /* gid */
     295             : 
     296        3156 :         result->gr_gid = gr->gr_gid;
     297             : 
     298             :         /* Group membership */
     299             : 
     300        3156 :         if (!gr_mem) {
     301         520 :                 gr->num_gr_mem = 0;
     302             :         }
     303             : 
     304             :         /* this next value is a pointer to a pointer so let's align it */
     305             : 
     306             :         /* Calculate number of extra bytes needed to align on pointer size boundry */
     307        3156 :         if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
     308        2740 :                 i = sizeof(char*) - i;
     309             : 
     310        3156 :         if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
     311             :                                  sizeof(char *)+i))) == NULL) {
     312             : 
     313             :                 /* Out of memory */
     314             : 
     315           0 :                 return NSS_STATUS_TRYAGAIN;
     316             :         }
     317        3156 :         result->gr_mem = (char **)(tst + i);
     318             : 
     319        3156 :         if (gr->num_gr_mem == 0) {
     320             : 
     321             :                 /* Group is empty */
     322             : 
     323        3148 :                 *(result->gr_mem) = NULL;
     324        3148 :                 return NSS_STATUS_SUCCESS;
     325             :         }
     326             : 
     327             :         /* Start looking at extra data */
     328             : 
     329           8 :         i = 0;
     330             : 
     331          20 :         while(next_token_alloc((const char **)&gr_mem, &name, ",")) {
     332             :                 /* Allocate space for member */
     333           8 :                 len = strlen(name) + 1;
     334             : 
     335          12 :                 if (((result->gr_mem)[i] =
     336           8 :                      get_static(buffer, buflen, len)) == NULL) {
     337           0 :                         free(name);
     338             :                         /* Out of memory */
     339           0 :                         return NSS_STATUS_TRYAGAIN;
     340             :                 }
     341           8 :                 memcpy((result->gr_mem)[i], name, len);
     342           8 :                 free(name);
     343           8 :                 i++;
     344             :         }
     345             : 
     346             :         /* Terminate list */
     347             : 
     348           8 :         (result->gr_mem)[i] = NULL;
     349             : 
     350           8 :         return NSS_STATUS_SUCCESS;
     351             : }
     352             : 
     353             : /*
     354             :  * NSS user functions
     355             :  */
     356             : 
     357             : static struct winbindd_response getpwent_response;
     358             : 
     359             : static int ndx_pw_cache;                 /* Current index into pwd cache */
     360             : static int num_pw_cache;                 /* Current size of pwd cache */
     361             : 
     362             : /* Rewind "file pointer" to start of ntdom password database */
     363             : 
     364             : _PUBLIC_ON_LINUX_
     365             : NSS_STATUS
     366          14 : _nss_winbind_setpwent(void)
     367             : {
     368             :         NSS_STATUS ret;
     369             : #ifdef DEBUG_NSS
     370             :         fprintf(stderr, "[%5d]: setpwent\n", getpid());
     371             : #endif
     372             : 
     373             : #ifdef HAVE_PTHREAD
     374          14 :         pthread_mutex_lock(&winbind_nss_mutex);
     375             : #endif
     376             : 
     377          14 :         if (num_pw_cache > 0) {
     378           0 :                 ndx_pw_cache = num_pw_cache = 0;
     379           0 :                 winbindd_free_response(&getpwent_response);
     380             :         }
     381             : 
     382          14 :         winbind_set_client_name("nss_winbind");
     383          14 :         ret = winbindd_request_response(NULL, WINBINDD_SETPWENT, NULL, NULL);
     384             : #ifdef DEBUG_NSS
     385             :         fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
     386             :                 nss_err_str(ret), ret);
     387             : #endif
     388             : 
     389             : #ifdef HAVE_PTHREAD
     390          14 :         pthread_mutex_unlock(&winbind_nss_mutex);
     391             : #endif
     392          14 :         return ret;
     393             : }
     394             : 
     395             : /* Close ntdom password database "file pointer" */
     396             : 
     397             : _PUBLIC_ON_LINUX_
     398             : NSS_STATUS
     399        3676 : _nss_winbind_endpwent(void)
     400             : {
     401             :         NSS_STATUS ret;
     402             : #ifdef DEBUG_NSS
     403             :         fprintf(stderr, "[%5d]: endpwent\n", getpid());
     404             : #endif
     405             : 
     406             : #ifdef HAVE_PTHREAD
     407        3676 :         pthread_mutex_lock(&winbind_nss_mutex);
     408             : #endif
     409             : 
     410        3676 :         if (num_pw_cache > 0) {
     411           0 :                 ndx_pw_cache = num_pw_cache = 0;
     412           0 :                 winbindd_free_response(&getpwent_response);
     413             :         }
     414             : 
     415        3676 :         winbind_set_client_name("nss_winbind");
     416        3676 :         ret = winbindd_request_response(NULL, WINBINDD_ENDPWENT, NULL, NULL);
     417             : #ifdef DEBUG_NSS
     418             :         fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
     419             :                 nss_err_str(ret), ret);
     420             : #endif
     421             : 
     422             : #ifdef HAVE_PTHREAD
     423        3676 :         pthread_mutex_unlock(&winbind_nss_mutex);
     424             : #endif
     425             : 
     426        3676 :         return ret;
     427             : }
     428             : 
     429             : /* Fetch the next password entry from ntdom password database */
     430             : 
     431             : _PUBLIC_ON_LINUX_
     432             : NSS_STATUS
     433         194 : _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
     434             :                         size_t buflen, int *errnop)
     435             : {
     436             :         NSS_STATUS ret;
     437             :         struct winbindd_request request;
     438             :         static int called_again;
     439             : 
     440             : #ifdef DEBUG_NSS
     441             :         fprintf(stderr, "[%5d]: getpwent\n", getpid());
     442             : #endif
     443             : 
     444             : #ifdef HAVE_PTHREAD
     445         194 :         pthread_mutex_lock(&winbind_nss_mutex);
     446             : #endif
     447             : 
     448             :         /* Return an entry from the cache if we have one, or if we are
     449             :            called again because we exceeded our static buffer.  */
     450             : 
     451         208 :         if ((ndx_pw_cache < num_pw_cache) || called_again) {
     452          83 :                 goto return_result;
     453             :         }
     454             : 
     455             :         /* Else call winbindd to get a bunch of entries */
     456             : 
     457          28 :         if (num_pw_cache > 0) {
     458           0 :                 winbindd_free_response(&getpwent_response);
     459             :         }
     460             : 
     461          28 :         ZERO_STRUCT(request);
     462          28 :         ZERO_STRUCT(getpwent_response);
     463             : 
     464          28 :         request.data.num_entries = MAX_GETPWENT_USERS;
     465             : 
     466          28 :         winbind_set_client_name("nss_winbind");
     467          28 :         ret = winbindd_request_response(NULL, WINBINDD_GETPWENT, &request,
     468             :                                &getpwent_response);
     469             : 
     470          28 :         if (ret == NSS_STATUS_SUCCESS) {
     471             :                 struct winbindd_pw *pw_cache;
     472             : 
     473             :                 /* Fill cache */
     474             : 
     475          14 :                 ndx_pw_cache = 0;
     476          14 :                 num_pw_cache = getpwent_response.data.num_entries;
     477             : 
     478             :                 /* Return a result */
     479             : 
     480         263 :         return_result:
     481             : 
     482         180 :                 pw_cache = (struct winbindd_pw *)
     483             :                         getpwent_response.extra_data.data;
     484             : 
     485             :                 /* Check data is valid */
     486             : 
     487         180 :                 if (pw_cache == NULL) {
     488           0 :                         ret = NSS_STATUS_NOTFOUND;
     489           0 :                         goto done;
     490             :                 }
     491             : 
     492         180 :                 ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
     493             :                                  &buffer, &buflen);
     494             : 
     495             :                 /* Out of memory - try again */
     496             : 
     497         180 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     498           0 :                         called_again = true;
     499           0 :                         *errnop = errno = ERANGE;
     500           0 :                         goto done;
     501             :                 }
     502             : 
     503         180 :                 *errnop = errno = 0;
     504         180 :                 called_again = false;
     505         180 :                 ndx_pw_cache++;
     506             : 
     507             :                 /* If we've finished with this lot of results free cache */
     508             : 
     509         180 :                 if (ndx_pw_cache == num_pw_cache) {
     510          14 :                         ndx_pw_cache = num_pw_cache = 0;
     511          14 :                         winbindd_free_response(&getpwent_response);
     512             :                 }
     513             :         }
     514         277 :         done:
     515             : #ifdef DEBUG_NSS
     516             :         fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
     517             :                 nss_err_str(ret), ret);
     518             : #endif
     519             : 
     520             : #ifdef HAVE_PTHREAD
     521         194 :         pthread_mutex_unlock(&winbind_nss_mutex);
     522             : #endif
     523         194 :         return ret;
     524             : }
     525             : 
     526             : /* Return passwd struct from uid */
     527             : 
     528             : _PUBLIC_ON_LINUX_
     529             : NSS_STATUS
     530        2613 : _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
     531             :                         size_t buflen, int *errnop)
     532             : {
     533             :         NSS_STATUS ret;
     534             :         static struct winbindd_response response;
     535             :         struct winbindd_request request;
     536             :         static int keep_response;
     537             : 
     538             : #ifdef DEBUG_NSS
     539             :         fprintf(stderr, "[%5d]: getpwuid_r %d\n", getpid(), (unsigned int)uid);
     540             : #endif
     541             : 
     542             : #ifdef HAVE_PTHREAD
     543        2613 :         pthread_mutex_lock(&winbind_nss_mutex);
     544             : #endif
     545             : 
     546             :         /* If our static buffer needs to be expanded we are called again */
     547        3137 :         if (!keep_response || uid != response.data.pw.pw_uid) {
     548             : 
     549             :                 /* Call for the first time */
     550             : 
     551        2613 :                 response = (struct winbindd_response) {
     552             :                         .length = 0,
     553             :                 };
     554        2613 :                 request = (struct winbindd_request) {
     555             :                         .wb_flags = WBFLAG_FROM_NSS,
     556             :                         .data = {
     557             :                                 .uid = uid,
     558             :                         },
     559             :                 };
     560             : 
     561        2613 :                 winbind_set_client_name("nss_winbind");
     562        2613 :                 ret = winbindd_request_response(NULL, WINBINDD_GETPWUID, &request, &response);
     563             : 
     564        4702 :                 if (ret == NSS_STATUS_SUCCESS) {
     565         937 :                         ret = fill_pwent(result, &response.data.pw,
     566             :                                          &buffer, &buflen);
     567             : 
     568         937 :                         if (ret == NSS_STATUS_TRYAGAIN) {
     569           0 :                                 keep_response = true;
     570           0 :                                 *errnop = errno = ERANGE;
     571           0 :                                 goto done;
     572             :                         }
     573             :                 }
     574             : 
     575             :         } else {
     576             : 
     577             :                 /* We've been called again */
     578             : 
     579           0 :                 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
     580             : 
     581           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     582           0 :                         *errnop = errno = ERANGE;
     583           0 :                         goto done;
     584             :                 }
     585             : 
     586           0 :                 keep_response = false;
     587           0 :                 *errnop = errno = 0;
     588             :         }
     589             : 
     590        2613 :         winbindd_free_response(&response);
     591             : 
     592        2613 :         done:
     593             : 
     594             : #ifdef DEBUG_NSS
     595             :         fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
     596             :                 (unsigned int)uid, nss_err_str(ret), ret);
     597             : #endif
     598             : 
     599             : #ifdef HAVE_PTHREAD
     600        2613 :         pthread_mutex_unlock(&winbind_nss_mutex);
     601             : #endif
     602             : 
     603        2613 :         return ret;
     604             : }
     605             : 
     606             : /* Return passwd struct from username */
     607             : _PUBLIC_ON_LINUX_
     608             : NSS_STATUS
     609        6068 : _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
     610             :                         size_t buflen, int *errnop)
     611             : {
     612             :         NSS_STATUS ret;
     613             :         static struct winbindd_response response;
     614             :         struct winbindd_request request;
     615             :         static int keep_response;
     616             : 
     617             : #ifdef DEBUG_NSS
     618             :         fprintf(stderr, "[%5d]: getpwnam_r %s\n", getpid(), name);
     619             : #endif
     620             : 
     621             : #ifdef HAVE_PTHREAD
     622        6068 :         pthread_mutex_lock(&winbind_nss_mutex);
     623             : #endif
     624             : 
     625             :         /* If our static buffer needs to be expanded we are called again */
     626             : 
     627        7508 :         if (!keep_response || strcmp(name,response.data.pw.pw_name) != 0) {
     628             : 
     629             :                 /* Call for the first time */
     630             : 
     631        6068 :                 response = (struct winbindd_response) {
     632             :                         .length = 0,
     633             :                 };
     634        6068 :                 request = (struct winbindd_request) {
     635             :                         .wb_flags = WBFLAG_FROM_NSS,
     636             :                 };
     637             : 
     638        6068 :                 strncpy(request.data.username, name,
     639             :                         sizeof(request.data.username) - 1);
     640             :                 request.data.username
     641        6068 :                         [sizeof(request.data.username) - 1] = '\0';
     642             : 
     643        6068 :                 winbind_set_client_name("nss_winbind");
     644        6068 :                 ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM, &request, &response);
     645             : 
     646       10696 :                 if (ret == NSS_STATUS_SUCCESS) {
     647        5157 :                         ret = fill_pwent(result, &response.data.pw, &buffer,
     648             :                                          &buflen);
     649             : 
     650        5157 :                         if (ret == NSS_STATUS_TRYAGAIN) {
     651           0 :                                 keep_response = true;
     652           0 :                                 *errnop = errno = ERANGE;
     653           0 :                                 goto done;
     654             :                         }
     655             :                 }
     656             : 
     657             :         } else {
     658             : 
     659             :                 /* We've been called again */
     660             : 
     661           0 :                 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
     662             : 
     663           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     664           0 :                         keep_response = true;
     665           0 :                         *errnop = errno = ERANGE;
     666           0 :                         goto done;
     667             :                 }
     668             : 
     669           0 :                 keep_response = false;
     670           0 :                 *errnop = errno = 0;
     671             :         }
     672             : 
     673        6068 :         winbindd_free_response(&response);
     674        6068 :         done:
     675             : #ifdef DEBUG_NSS
     676             :         fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
     677             :                 name, nss_err_str(ret), ret);
     678             : #endif
     679             : 
     680             : #ifdef HAVE_PTHREAD
     681        6068 :         pthread_mutex_unlock(&winbind_nss_mutex);
     682             : #endif
     683             : 
     684        6068 :         return ret;
     685             : }
     686             : 
     687             : /*
     688             :  * NSS group functions
     689             :  */
     690             : 
     691             : static struct winbindd_response getgrent_response;
     692             : 
     693             : static int ndx_gr_cache;                 /* Current index into grp cache */
     694             : static int num_gr_cache;                 /* Current size of grp cache */
     695             : 
     696             : /* Rewind "file pointer" to start of ntdom group database */
     697             : 
     698             : _PUBLIC_ON_LINUX_
     699             : NSS_STATUS
     700        2924 : _nss_winbind_setgrent(void)
     701             : {
     702             :         NSS_STATUS ret;
     703             : #ifdef DEBUG_NSS
     704             :         fprintf(stderr, "[%5d]: setgrent\n", getpid());
     705             : #endif
     706             : 
     707             : #ifdef HAVE_PTHREAD
     708        2924 :         pthread_mutex_lock(&winbind_nss_mutex);
     709             : #endif
     710             : 
     711        2924 :         if (num_gr_cache > 0) {
     712           0 :                 ndx_gr_cache = num_gr_cache = 0;
     713           0 :                 winbindd_free_response(&getgrent_response);
     714             :         }
     715             : 
     716        2924 :         winbind_set_client_name("nss_winbind");
     717        2924 :         ret = winbindd_request_response(NULL, WINBINDD_SETGRENT, NULL, NULL);
     718             : #ifdef DEBUG_NSS
     719             :         fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
     720             :                 nss_err_str(ret), ret);
     721             : #endif
     722             : 
     723             : #ifdef HAVE_PTHREAD
     724        2924 :         pthread_mutex_unlock(&winbind_nss_mutex);
     725             : #endif
     726             : 
     727        2924 :         return ret;
     728             : }
     729             : 
     730             : /* Close "file pointer" for ntdom group database */
     731             : 
     732             : _PUBLIC_ON_LINUX_
     733             : NSS_STATUS
     734        2924 : _nss_winbind_endgrent(void)
     735             : {
     736             :         NSS_STATUS ret;
     737             : #ifdef DEBUG_NSS
     738             :         fprintf(stderr, "[%5d]: endgrent\n", getpid());
     739             : #endif
     740             : 
     741             : #ifdef HAVE_PTHREAD
     742        2924 :         pthread_mutex_lock(&winbind_nss_mutex);
     743             : #endif
     744             : 
     745        2924 :         if (num_gr_cache > 0) {
     746           0 :                 ndx_gr_cache = num_gr_cache = 0;
     747           0 :                 winbindd_free_response(&getgrent_response);
     748             :         }
     749             : 
     750        2924 :         winbind_set_client_name("nss_winbind");
     751        2924 :         ret = winbindd_request_response(NULL, WINBINDD_ENDGRENT, NULL, NULL);
     752             : #ifdef DEBUG_NSS
     753             :         fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
     754             :                 nss_err_str(ret), ret);
     755             : #endif
     756             : 
     757             : #ifdef HAVE_PTHREAD
     758        2924 :         pthread_mutex_unlock(&winbind_nss_mutex);
     759             : #endif
     760             : 
     761        2924 :         return ret;
     762             : }
     763             : 
     764             : /* Get next entry from ntdom group database */
     765             : 
     766             : static NSS_STATUS
     767        5552 : winbind_getgrent(enum winbindd_cmd cmd,
     768             :                  struct group *result,
     769             :                  char *buffer, size_t buflen, int *errnop)
     770             : {
     771             :         NSS_STATUS ret;
     772             :         static struct winbindd_request request;
     773             :         static int called_again;
     774             : 
     775             : 
     776             : #ifdef DEBUG_NSS
     777             :         fprintf(stderr, "[%5d]: getgrent\n", getpid());
     778             : #endif
     779             : 
     780             : #ifdef HAVE_PTHREAD
     781        5552 :         pthread_mutex_lock(&winbind_nss_mutex);
     782             : #endif
     783             : 
     784             :         /* Return an entry from the cache if we have one, or if we are
     785             :            called again because we exceeded our static buffer.  */
     786             : 
     787        7539 :         if ((ndx_gr_cache < num_gr_cache) || called_again) {
     788        1241 :                 goto return_result;
     789             :         }
     790             : 
     791             :         /* Else call winbindd to get a bunch of entries */
     792             : 
     793        3070 :         if (num_gr_cache > 0) {
     794           0 :                 winbindd_free_response(&getgrent_response);
     795             :         }
     796             : 
     797        3070 :         ZERO_STRUCT(request);
     798        3070 :         ZERO_STRUCT(getgrent_response);
     799             : 
     800        3070 :         request.data.num_entries = MAX_GETGRENT_USERS;
     801             : 
     802        3070 :         winbind_set_client_name("nss_winbind");
     803        3070 :         ret = winbindd_request_response(NULL, cmd, &request,
     804             :                                &getgrent_response);
     805             : 
     806        3070 :         if (ret == NSS_STATUS_SUCCESS) {
     807             :                 struct winbindd_gr *gr_cache;
     808             :                 int mem_ofs;
     809             : 
     810             :                 /* Fill cache */
     811             : 
     812         146 :                 ndx_gr_cache = 0;
     813         146 :                 num_gr_cache = getgrent_response.data.num_entries;
     814             : 
     815             :                 /* Return a result */
     816             : 
     817        3869 :         return_result:
     818             : 
     819        2628 :                 gr_cache = (struct winbindd_gr *)
     820             :                         getgrent_response.extra_data.data;
     821             : 
     822             :                 /* Check data is valid */
     823             : 
     824        2628 :                 if (gr_cache == NULL) {
     825           0 :                         ret = NSS_STATUS_NOTFOUND;
     826           0 :                         goto done;
     827             :                 }
     828             : 
     829             :                 /* Fill group membership.  The offset into the extra data
     830             :                    for the group membership is the reported offset plus the
     831             :                    size of all the winbindd_gr records returned. */
     832             : 
     833        2628 :                 mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
     834             :                         num_gr_cache * sizeof(struct winbindd_gr);
     835             : 
     836        2628 :                 ret = fill_grent(result, &gr_cache[ndx_gr_cache],
     837        2628 :                                  ((char *)getgrent_response.extra_data.data)+mem_ofs,
     838             :                                  &buffer, &buflen);
     839             : 
     840             :                 /* Out of memory - try again */
     841             : 
     842        2628 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     843           0 :                         called_again = true;
     844           0 :                         *errnop = errno = ERANGE;
     845           0 :                         goto done;
     846             :                 }
     847             : 
     848        2628 :                 *errnop = 0;
     849        2628 :                 called_again = false;
     850        2628 :                 ndx_gr_cache++;
     851             : 
     852             :                 /* If we've finished with this lot of results free cache */
     853             : 
     854        2628 :                 if (ndx_gr_cache == num_gr_cache) {
     855         146 :                         ndx_gr_cache = num_gr_cache = 0;
     856         146 :                         winbindd_free_response(&getgrent_response);
     857             :                 }
     858             :         }
     859        8634 :         done:
     860             : #ifdef DEBUG_NSS
     861             :         fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
     862             :                 nss_err_str(ret), ret);
     863             : #endif
     864             : 
     865             : #ifdef HAVE_PTHREAD
     866        5552 :         pthread_mutex_unlock(&winbind_nss_mutex);
     867             : #endif
     868             : 
     869        5552 :         return ret;
     870             : }
     871             : 
     872             : 
     873             : _PUBLIC_ON_LINUX_
     874             : NSS_STATUS
     875        5552 : _nss_winbind_getgrent_r(struct group *result,
     876             :                         char *buffer, size_t buflen, int *errnop)
     877             : {
     878        5552 :         return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
     879             : }
     880             : 
     881             : _PUBLIC_ON_LINUX_
     882             : NSS_STATUS
     883           0 : _nss_winbind_getgrlst_r(struct group *result,
     884             :                         char *buffer, size_t buflen, int *errnop)
     885             : {
     886           0 :         return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
     887             : }
     888             : 
     889             : /* Return group struct from group name */
     890             : 
     891             : _PUBLIC_ON_LINUX_
     892             : NSS_STATUS
     893         372 : _nss_winbind_getgrnam_r(const char *name,
     894             :                         struct group *result, char *buffer,
     895             :                         size_t buflen, int *errnop)
     896             : {
     897             :         NSS_STATUS ret;
     898             :         static struct winbindd_response response;
     899             :         struct winbindd_request request;
     900             :         static int keep_response;
     901             : 
     902             : #ifdef DEBUG_NSS
     903             :         fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
     904             : #endif
     905             : 
     906             : #ifdef HAVE_PTHREAD
     907         372 :         pthread_mutex_lock(&winbind_nss_mutex);
     908             : #endif
     909             : 
     910             :         /* If our static buffer needs to be expanded we are called again */
     911             :         /* Or if the stored response group name differs from the request. */
     912             : 
     913         490 :         if (!keep_response || strcmp(name,response.data.gr.gr_name) != 0) {
     914             : 
     915             :                 /* Call for the first time */
     916             : 
     917         372 :                 response = (struct winbindd_response) {
     918             :                         .length = 0,
     919             :                 };
     920         372 :                 request = (struct winbindd_request) {
     921             :                         .wb_flags = WBFLAG_FROM_NSS,
     922             :                 };
     923             : 
     924         372 :                 strncpy(request.data.groupname, name,
     925             :                         sizeof(request.data.groupname));
     926             :                 request.data.groupname
     927         372 :                         [sizeof(request.data.groupname) - 1] = '\0';
     928             : 
     929         372 :                 winbind_set_client_name("nss_winbind");
     930         372 :                 ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM,
     931             :                                                 &request, &response);
     932             : 
     933         626 :                 if (ret == NSS_STATUS_SUCCESS) {
     934         224 :                         ret = fill_grent(result, &response.data.gr,
     935         224 :                                          (char *)response.extra_data.data,
     936             :                                          &buffer, &buflen);
     937             : 
     938         224 :                         if (ret == NSS_STATUS_TRYAGAIN) {
     939           0 :                                 keep_response = true;
     940           0 :                                 *errnop = errno = ERANGE;
     941           0 :                                 goto done;
     942             :                         }
     943             :                 }
     944             : 
     945             :         } else {
     946             : 
     947             :                 /* We've been called again */
     948             : 
     949           0 :                 ret = fill_grent(result, &response.data.gr,
     950           0 :                                  (char *)response.extra_data.data, &buffer,
     951             :                                  &buflen);
     952             : 
     953           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     954           0 :                         keep_response = true;
     955           0 :                         *errnop = errno = ERANGE;
     956           0 :                         goto done;
     957             :                 }
     958             : 
     959           0 :                 keep_response = false;
     960           0 :                 *errnop = 0;
     961             :         }
     962             : 
     963         372 :         winbindd_free_response(&response);
     964         372 :         done:
     965             : #ifdef DEBUG_NSS
     966             :         fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
     967             :                 name, nss_err_str(ret), ret);
     968             : #endif
     969             : 
     970             : #ifdef HAVE_PTHREAD
     971         372 :         pthread_mutex_unlock(&winbind_nss_mutex);
     972             : #endif
     973             : 
     974         372 :         return ret;
     975             : }
     976             : 
     977             : /* Return group struct from gid */
     978             : 
     979             : _PUBLIC_ON_LINUX_
     980             : NSS_STATUS
     981         308 : _nss_winbind_getgrgid_r(gid_t gid,
     982             :                         struct group *result, char *buffer,
     983             :                         size_t buflen, int *errnop)
     984             : {
     985             :         NSS_STATUS ret;
     986             :         static struct winbindd_response response;
     987             :         struct winbindd_request request;
     988             :         static int keep_response;
     989             : 
     990             : #ifdef DEBUG_NSS
     991             :         fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
     992             : #endif
     993             : 
     994             : #ifdef HAVE_PTHREAD
     995         308 :         pthread_mutex_lock(&winbind_nss_mutex);
     996             : #endif
     997             : 
     998             :         /* If our static buffer needs to be expanded we are called again */
     999             :         /* Or if the stored response group name differs from the request. */
    1000             : 
    1001         462 :         if (!keep_response || gid != response.data.gr.gr_gid) {
    1002             : 
    1003             :                 /* Call for the first time */
    1004             : 
    1005         308 :                 response = (struct winbindd_response) {
    1006             :                         .length = 0,
    1007             :                 };
    1008         308 :                 request = (struct winbindd_request) {
    1009             :                         .wb_flags = WBFLAG_FROM_NSS,
    1010             :                 };
    1011             : 
    1012             : 
    1013         308 :                 request.data.gid = gid;
    1014             : 
    1015         308 :                 winbind_set_client_name("nss_winbind");
    1016         308 :                 ret = winbindd_request_response(NULL, WINBINDD_GETGRGID,
    1017             :                                                 &request, &response);
    1018             : 
    1019         462 :                 if (ret == NSS_STATUS_SUCCESS) {
    1020             : 
    1021         304 :                         ret = fill_grent(result, &response.data.gr,
    1022         304 :                                          (char *)response.extra_data.data,
    1023             :                                          &buffer, &buflen);
    1024             : 
    1025         304 :                         if (ret == NSS_STATUS_TRYAGAIN) {
    1026           0 :                                 keep_response = true;
    1027           0 :                                 *errnop = errno = ERANGE;
    1028           0 :                                 goto done;
    1029             :                         }
    1030             :                 }
    1031             : 
    1032             :         } else {
    1033             : 
    1034             :                 /* We've been called again */
    1035             : 
    1036           0 :                 ret = fill_grent(result, &response.data.gr,
    1037           0 :                                  (char *)response.extra_data.data, &buffer,
    1038             :                                  &buflen);
    1039             : 
    1040           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
    1041           0 :                         keep_response = true;
    1042           0 :                         *errnop = errno = ERANGE;
    1043           0 :                         goto done;
    1044             :                 }
    1045             : 
    1046           0 :                 keep_response = false;
    1047           0 :                 *errnop = 0;
    1048             :         }
    1049             : 
    1050         308 :         winbindd_free_response(&response);
    1051         308 :         done:
    1052             : #ifdef DEBUG_NSS
    1053             :         fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
    1054             :                 (unsigned int)gid, nss_err_str(ret), ret);
    1055             : #endif
    1056             : 
    1057             : #ifdef HAVE_PTHREAD
    1058         308 :         pthread_mutex_unlock(&winbind_nss_mutex);
    1059             : #endif
    1060         308 :         return ret;
    1061             : }
    1062             : 
    1063             : /* Initialise supplementary groups */
    1064             : 
    1065             : _PUBLIC_ON_LINUX_
    1066             : NSS_STATUS
    1067          50 : _nss_winbind_initgroups_dyn(const char *user, gid_t group, long int *start,
    1068             :                             long int *size, gid_t **groups, long int limit,
    1069             :                             int *errnop)
    1070             : {
    1071             :         NSS_STATUS ret;
    1072             :         struct winbindd_request request;
    1073             :         struct winbindd_response response;
    1074             :         int i;
    1075             : 
    1076             : #ifdef DEBUG_NSS
    1077             :         fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
    1078             :                 user, group);
    1079             : #endif
    1080             : 
    1081             : #ifdef HAVE_PTHREAD
    1082          50 :         pthread_mutex_lock(&winbind_nss_mutex);
    1083             : #endif
    1084             : 
    1085          50 :         ZERO_STRUCT(request);
    1086          50 :         ZERO_STRUCT(response);
    1087             : 
    1088          50 :         strncpy(request.data.username, user,
    1089             :                 sizeof(request.data.username) - 1);
    1090             : 
    1091          50 :         winbind_set_client_name("nss_winbind");
    1092          50 :         ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS,
    1093             :                                         &request, &response);
    1094             : 
    1095          50 :         if (ret == NSS_STATUS_SUCCESS) {
    1096          50 :                 int num_gids = response.data.num_entries;
    1097          50 :                 gid_t *gid_list = (gid_t *)response.extra_data.data;
    1098             : 
    1099             : #ifdef DEBUG_NSS
    1100             :                 fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
    1101             :                                 "and %d gids\n", getpid(),
    1102             :                                 user, num_gids);
    1103             : #endif
    1104          50 :                 if (gid_list == NULL) {
    1105           0 :                         ret = NSS_STATUS_NOTFOUND;
    1106           0 :                         goto done;
    1107             :                 }
    1108             : 
    1109             :                 /* Copy group list to client */
    1110             : 
    1111         176 :                 for (i = 0; i < num_gids; i++) {
    1112             : 
    1113             : #ifdef DEBUG_NSS
    1114             :                         fprintf(stderr, "[%5d]: initgroups %s (%d): "
    1115             :                                         "processing gid %d \n", getpid(),
    1116             :                                         user, group, gid_list[i]);
    1117             : #endif
    1118             : 
    1119             :                         /* Skip primary group */
    1120             : 
    1121         126 :                         if (gid_list[i] == group) {
    1122          50 :                                 continue;
    1123             :                         }
    1124             : 
    1125             :                         /* Skip groups without a mapping */
    1126          76 :                         if (gid_list[i] == (uid_t)-1) {
    1127           0 :                                 continue;
    1128             :                         }
    1129             : 
    1130             :                         /* Filled buffer ? If so, resize. */
    1131             : 
    1132          76 :                         if (*start == *size) {
    1133             :                                 long int newsize;
    1134             :                                 gid_t *newgroups;
    1135             : 
    1136           0 :                                 newsize = 2 * (*size);
    1137           0 :                                 if (limit > 0) {
    1138           0 :                                         if (*size == limit) {
    1139           0 :                                                 goto done;
    1140             :                                         }
    1141           0 :                                         if (newsize > limit) {
    1142           0 :                                                 newsize = limit;
    1143             :                                         }
    1144             :                                 }
    1145             : 
    1146           0 :                                 newgroups = (gid_t *)
    1147           0 :                                         realloc((*groups),
    1148             :                                                 newsize * sizeof(**groups));
    1149           0 :                                 if (!newgroups) {
    1150           0 :                                         *errnop = ENOMEM;
    1151           0 :                                         ret = NSS_STATUS_NOTFOUND;
    1152           0 :                                         goto done;
    1153             :                                 }
    1154           0 :                                 *groups = newgroups;
    1155           0 :                                 *size = newsize;
    1156             :                         }
    1157             : 
    1158             :                         /* Add to buffer */
    1159             : 
    1160          76 :                         (*groups)[*start] = gid_list[i];
    1161          76 :                         *start += 1;
    1162             :                 }
    1163             :         }
    1164             : 
    1165             :         /* Back to your regularly scheduled programming */
    1166             : 
    1167          50 :  done:
    1168             : #ifdef DEBUG_NSS
    1169             :         fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
    1170             :                 user, nss_err_str(ret), ret);
    1171             : #endif
    1172             : 
    1173             : #ifdef HAVE_PTHREAD
    1174          50 :         pthread_mutex_unlock(&winbind_nss_mutex);
    1175             : #endif
    1176             : 
    1177          50 :         return ret;
    1178             : }

Generated by: LCOV version 1.13