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

Generated by: LCOV version 1.14