LCOV - code coverage report
Current view: top level - nsswitch - winbind_nss_linux.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 254 351 72.4 %
Date: 2021-09-23 10:06:22 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      106373 : 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      108973 :         if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
      78           0 :                 return NULL;
      79             :         }
      80             : 
      81             :         /* Return an index into the static buffer */
      82             : 
      83      108973 :         result = *buffer;
      84      108973 :         *buffer += len;
      85      108973 :         *buflen -= len;
      86             : 
      87      106373 :         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           8 : 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           8 :         size_t len=1;
     103             : 
     104           8 :         *pp_buff = NULL;
     105           8 :         if (!ptr) {
     106           0 :                 return(false);
     107             :         }
     108             : 
     109           8 :         s = *ptr;
     110             : 
     111             :         /* default to simple separators */
     112           8 :         if (!sep) {
     113           0 :                 sep = " \t\n\r";
     114             :         }
     115             : 
     116             :         /* find the first non sep char */
     117          12 :         while (*s && strchr(sep,*s)) {
     118           0 :                 s++;
     119             :         }
     120             : 
     121             :         /* nothing left? */
     122           8 :         if (!*s) {
     123           4 :                 return false;
     124             :         }
     125             : 
     126             :         /* When restarting we need to go from here. */
     127           4 :         saved_s = s;
     128             : 
     129             :         /* Work out the length needed. */
     130          94 :         for (quoted = false; *s &&
     131         176 :                         (quoted || !strchr(sep,*s)); s++) {
     132          88 :                 if (*s == '\"') {
     133           0 :                         quoted = !quoted;
     134             :                 } else {
     135          88 :                         len++;
     136             :                 }
     137             :         }
     138             : 
     139             :         /* We started with len = 1 so we have space for the nul. */
     140           4 :         *pp_buff = (char *)malloc(len);
     141           4 :         if (!*pp_buff) {
     142           0 :                 return false;
     143             :         }
     144             : 
     145             :         /* copy over the token */
     146           4 :         pbuf = *pp_buff;
     147           4 :         s = saved_s;
     148          94 :         for (quoted = false; *s &&
     149         176 :                         (quoted || !strchr(sep,*s)); s++) {
     150          88 :                 if ( *s == '\"' ) {
     151           0 :                         quoted = !quoted;
     152             :                 } else {
     153          88 :                         *pbuf++ = *s;
     154             :                 }
     155             :         }
     156             : 
     157           4 :         *ptr = (*s) ? s+1 : s;
     158           4 :         *pbuf = 0;
     159             : 
     160           4 :         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       19533 : 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       19533 :         len = strlen(pw->pw_name) + 1;
     175             : 
     176       19533 :         if ((result->pw_name =
     177       19533 :              get_static(buffer, buflen, len)) == NULL) {
     178             : 
     179             :                 /* Out of memory */
     180             : 
     181           0 :                 return NSS_STATUS_TRYAGAIN;
     182             :         }
     183             : 
     184       20053 :         memcpy(result->pw_name, pw->pw_name, len);
     185             : 
     186             :         /* Password */
     187       19533 :         len = strlen(pw->pw_passwd) + 1;
     188             : 
     189       19533 :         if ((result->pw_passwd =
     190       19533 :              get_static(buffer, buflen, len)) == NULL) {
     191             : 
     192             :                 /* Out of memory */
     193             : 
     194           0 :                 return NSS_STATUS_TRYAGAIN;
     195             :         }
     196             : 
     197       20053 :         memcpy(result->pw_passwd, pw->pw_passwd, len);
     198             : 
     199             :         /* [ug]id */
     200             : 
     201       19533 :         result->pw_uid = pw->pw_uid;
     202       19533 :         result->pw_gid = pw->pw_gid;
     203             : 
     204             :         /* GECOS */
     205       19533 :         len = strlen(pw->pw_gecos) + 1;
     206             : 
     207       19533 :         if ((result->pw_gecos =
     208       19533 :              get_static(buffer, buflen, len)) == NULL) {
     209             : 
     210             :                 /* Out of memory */
     211             : 
     212           0 :                 return NSS_STATUS_TRYAGAIN;
     213             :         }
     214             : 
     215       20053 :         memcpy(result->pw_gecos, pw->pw_gecos, len);
     216             : 
     217             :         /* Home directory */
     218       19533 :         len = strlen(pw->pw_dir) + 1;
     219             : 
     220       19533 :         if ((result->pw_dir =
     221       19533 :              get_static(buffer, buflen, len)) == NULL) {
     222             : 
     223             :                 /* Out of memory */
     224             : 
     225           0 :                 return NSS_STATUS_TRYAGAIN;
     226             :         }
     227             : 
     228       20053 :         memcpy(result->pw_dir, pw->pw_dir, len);
     229             : 
     230             :         /* Logon shell */
     231       19533 :         len = strlen(pw->pw_shell) + 1;
     232             : 
     233       19533 :         if ((result->pw_shell =
     234       19533 :              get_static(buffer, buflen, len)) == NULL) {
     235             : 
     236             :                 /* Out of memory */
     237             : 
     238           0 :                 return NSS_STATUS_TRYAGAIN;
     239             :         }
     240             : 
     241       20053 :         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       19533 :         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        3768 : 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        3768 :         len = strlen(gr->gr_name) + 1;
     271             : 
     272        3768 :         if ((result->gr_name =
     273        3768 :              get_static(buffer, buflen, len)) == NULL) {
     274             : 
     275             :                 /* Out of memory */
     276             : 
     277           0 :                 return NSS_STATUS_TRYAGAIN;
     278             :         }
     279             : 
     280        3768 :         memcpy(result->gr_name, gr->gr_name, len);
     281             : 
     282             :         /* Password */
     283        3768 :         len = strlen(gr->gr_passwd) + 1;
     284             : 
     285        3768 :         if ((result->gr_passwd =
     286        3768 :              get_static(buffer, buflen, len)) == NULL) {
     287             : 
     288             :                 /* Out of memory */
     289           0 :                 return NSS_STATUS_TRYAGAIN;
     290             :         }
     291             : 
     292        3768 :         memcpy(result->gr_passwd, gr->gr_passwd, len);
     293             : 
     294             :         /* gid */
     295             : 
     296        3768 :         result->gr_gid = gr->gr_gid;
     297             : 
     298             :         /* Group membership */
     299             : 
     300        3768 :         if (!gr_mem) {
     301        2716 :                 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        3768 :         if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
     308        3654 :                 i = sizeof(char*) - i;
     309             : 
     310        3768 :         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        3768 :         result->gr_mem = (char **)(tst + i);
     318             : 
     319        3768 :         if (gr->num_gr_mem == 0) {
     320             : 
     321             :                 /* Group is empty */
     322             : 
     323        3764 :                 *(result->gr_mem) = NULL;
     324        3764 :                 return NSS_STATUS_SUCCESS;
     325             :         }
     326             : 
     327             :         /* Start looking at extra data */
     328             : 
     329           4 :         i = 0;
     330             : 
     331          10 :         while(next_token_alloc((const char **)&gr_mem, &name, ",")) {
     332             :                 /* Allocate space for member */
     333           4 :                 len = strlen(name) + 1;
     334             : 
     335           6 :                 if (((result->gr_mem)[i] =
     336           4 :                      get_static(buffer, buflen, len)) == NULL) {
     337           0 :                         free(name);
     338             :                         /* Out of memory */
     339           0 :                         return NSS_STATUS_TRYAGAIN;
     340             :                 }
     341           4 :                 memcpy((result->gr_mem)[i], name, len);
     342           4 :                 free(name);
     343           4 :                 i++;
     344             :         }
     345             : 
     346             :         /* Terminate list */
     347             : 
     348           4 :         (result->gr_mem)[i] = NULL;
     349             : 
     350           4 :         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             : NSS_STATUS
     365          74 : _nss_winbind_setpwent(void)
     366             : {
     367             :         NSS_STATUS ret;
     368             : #ifdef DEBUG_NSS
     369             :         fprintf(stderr, "[%5d]: setpwent\n", getpid());
     370             : #endif
     371             : 
     372             : #ifdef HAVE_PTHREAD
     373          74 :         pthread_mutex_lock(&winbind_nss_mutex);
     374             : #endif
     375             : 
     376          74 :         if (num_pw_cache > 0) {
     377           0 :                 ndx_pw_cache = num_pw_cache = 0;
     378           0 :                 winbindd_free_response(&getpwent_response);
     379             :         }
     380             : 
     381          74 :         winbind_set_client_name("nss_winbind");
     382          74 :         ret = winbindd_request_response(NULL, WINBINDD_SETPWENT, NULL, NULL);
     383             : #ifdef DEBUG_NSS
     384             :         fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
     385             :                 nss_err_str(ret), ret);
     386             : #endif
     387             : 
     388             : #ifdef HAVE_PTHREAD
     389          74 :         pthread_mutex_unlock(&winbind_nss_mutex);
     390             : #endif
     391          74 :         return ret;
     392             : }
     393             : 
     394             : /* Close ntdom password database "file pointer" */
     395             : 
     396             : NSS_STATUS
     397          10 : _nss_winbind_endpwent(void)
     398             : {
     399             :         NSS_STATUS ret;
     400             : #ifdef DEBUG_NSS
     401             :         fprintf(stderr, "[%5d]: endpwent\n", getpid());
     402             : #endif
     403             : 
     404             : #ifdef HAVE_PTHREAD
     405          10 :         pthread_mutex_lock(&winbind_nss_mutex);
     406             : #endif
     407             : 
     408          10 :         if (num_pw_cache > 0) {
     409           0 :                 ndx_pw_cache = num_pw_cache = 0;
     410           0 :                 winbindd_free_response(&getpwent_response);
     411             :         }
     412             : 
     413          10 :         winbind_set_client_name("nss_winbind");
     414          10 :         ret = winbindd_request_response(NULL, WINBINDD_ENDPWENT, NULL, NULL);
     415             : #ifdef DEBUG_NSS
     416             :         fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
     417             :                 nss_err_str(ret), ret);
     418             : #endif
     419             : 
     420             : #ifdef HAVE_PTHREAD
     421          10 :         pthread_mutex_unlock(&winbind_nss_mutex);
     422             : #endif
     423             : 
     424          10 :         return ret;
     425             : }
     426             : 
     427             : /* Fetch the next password entry from ntdom password database */
     428             : 
     429             : NSS_STATUS
     430        4106 : _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
     431             :                         size_t buflen, int *errnop)
     432             : {
     433             :         NSS_STATUS ret;
     434             :         struct winbindd_request request;
     435             :         static int called_again;
     436             : 
     437             : #ifdef DEBUG_NSS
     438             :         fprintf(stderr, "[%5d]: getpwent\n", getpid());
     439             : #endif
     440             : 
     441             : #ifdef HAVE_PTHREAD
     442        4106 :         pthread_mutex_lock(&winbind_nss_mutex);
     443             : #endif
     444             : 
     445             :         /* Return an entry from the cache if we have one, or if we are
     446             :            called again because we exceeded our static buffer.  */
     447             : 
     448        4192 :         if ((ndx_pw_cache < num_pw_cache) || called_again) {
     449        1049 :                 goto return_result;
     450             :         }
     451             : 
     452             :         /* Else call winbindd to get a bunch of entries */
     453             : 
     454         112 :         if (num_pw_cache > 0) {
     455           0 :                 winbindd_free_response(&getpwent_response);
     456             :         }
     457             : 
     458         112 :         ZERO_STRUCT(request);
     459         112 :         ZERO_STRUCT(getpwent_response);
     460             : 
     461         112 :         request.data.num_entries = MAX_GETPWENT_USERS;
     462             : 
     463         112 :         winbind_set_client_name("nss_winbind");
     464         112 :         ret = winbindd_request_response(NULL, WINBINDD_GETPWENT, &request,
     465             :                                &getpwent_response);
     466             : 
     467         112 :         if (ret == NSS_STATUS_SUCCESS) {
     468             :                 struct winbindd_pw *pw_cache;
     469             : 
     470             :                 /* Fill cache */
     471             : 
     472          38 :                 ndx_pw_cache = 0;
     473          38 :                 num_pw_cache = getpwent_response.data.num_entries;
     474             : 
     475             :                 /* Return a result */
     476             : 
     477        6977 :         return_result:
     478             : 
     479        4032 :                 pw_cache = (struct winbindd_pw *)
     480             :                         getpwent_response.extra_data.data;
     481             : 
     482             :                 /* Check data is valid */
     483             : 
     484        4032 :                 if (pw_cache == NULL) {
     485           0 :                         ret = NSS_STATUS_NOTFOUND;
     486           0 :                         goto done;
     487             :                 }
     488             : 
     489        4032 :                 ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
     490             :                                  &buffer, &buflen);
     491             : 
     492             :                 /* Out of memory - try again */
     493             : 
     494        4032 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     495           0 :                         called_again = true;
     496           0 :                         *errnop = errno = ERANGE;
     497           0 :                         goto done;
     498             :                 }
     499             : 
     500        4032 :                 *errnop = errno = 0;
     501        4032 :                 called_again = false;
     502        4032 :                 ndx_pw_cache++;
     503             : 
     504             :                 /* If we've finished with this lot of results free cache */
     505             : 
     506        4032 :                 if (ndx_pw_cache == num_pw_cache) {
     507          38 :                         ndx_pw_cache = num_pw_cache = 0;
     508          38 :                         winbindd_free_response(&getpwent_response);
     509             :                 }
     510             :         }
     511        7099 :         done:
     512             : #ifdef DEBUG_NSS
     513             :         fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
     514             :                 nss_err_str(ret), ret);
     515             : #endif
     516             : 
     517             : #ifdef HAVE_PTHREAD
     518        4106 :         pthread_mutex_unlock(&winbind_nss_mutex);
     519             : #endif
     520        4106 :         return ret;
     521             : }
     522             : 
     523             : /* Return passwd struct from uid */
     524             : 
     525             : NSS_STATUS
     526        5595 : _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
     527             :                         size_t buflen, int *errnop)
     528             : {
     529             :         NSS_STATUS ret;
     530             :         static struct winbindd_response response;
     531             :         struct winbindd_request request;
     532             :         static int keep_response;
     533             : 
     534             : #ifdef DEBUG_NSS
     535             :         fprintf(stderr, "[%5d]: getpwuid_r %d\n", getpid(), (unsigned int)uid);
     536             : #endif
     537             : 
     538             : #ifdef HAVE_PTHREAD
     539        5595 :         pthread_mutex_lock(&winbind_nss_mutex);
     540             : #endif
     541             : 
     542             :         /* If our static buffer needs to be expanded we are called again */
     543        6610 :         if (!keep_response || uid != response.data.pw.pw_uid) {
     544             : 
     545             :                 /* Call for the first time */
     546             : 
     547        5595 :                 response = (struct winbindd_response) {
     548             :                         .length = 0,
     549             :                 };
     550        5595 :                 request = (struct winbindd_request) {
     551             :                         .wb_flags = WBFLAG_FROM_NSS,
     552             :                         .data = {
     553             :                                 .uid = uid,
     554             :                         },
     555             :                 };
     556             : 
     557        5595 :                 winbind_set_client_name("nss_winbind");
     558        5595 :                 ret = winbindd_request_response(NULL, WINBINDD_GETPWUID, &request, &response);
     559             : 
     560       10175 :                 if (ret == NSS_STATUS_SUCCESS) {
     561        2680 :                         ret = fill_pwent(result, &response.data.pw,
     562             :                                          &buffer, &buflen);
     563             : 
     564        2680 :                         if (ret == NSS_STATUS_TRYAGAIN) {
     565           0 :                                 keep_response = true;
     566           0 :                                 *errnop = errno = ERANGE;
     567           0 :                                 goto done;
     568             :                         }
     569             :                 }
     570             : 
     571             :         } else {
     572             : 
     573             :                 /* We've been called again */
     574             : 
     575           0 :                 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
     576             : 
     577           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     578           0 :                         *errnop = errno = ERANGE;
     579           0 :                         goto done;
     580             :                 }
     581             : 
     582           0 :                 keep_response = false;
     583           0 :                 *errnop = errno = 0;
     584             :         }
     585             : 
     586        5595 :         winbindd_free_response(&response);
     587             : 
     588        5595 :         done:
     589             : 
     590             : #ifdef DEBUG_NSS
     591             :         fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
     592             :                 (unsigned int)uid, nss_err_str(ret), ret);
     593             : #endif
     594             : 
     595             : #ifdef HAVE_PTHREAD
     596        5595 :         pthread_mutex_unlock(&winbind_nss_mutex);
     597             : #endif
     598             : 
     599        5595 :         return ret;
     600             : }
     601             : 
     602             : /* Return passwd struct from username */
     603             : NSS_STATUS
     604       17676 : _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
     605             :                         size_t buflen, int *errnop)
     606             : {
     607             :         NSS_STATUS ret;
     608             :         static struct winbindd_response response;
     609             :         struct winbindd_request request;
     610             :         static int keep_response;
     611             : 
     612             : #ifdef DEBUG_NSS
     613             :         fprintf(stderr, "[%5d]: getpwnam_r %s\n", getpid(), name);
     614             : #endif
     615             : 
     616             : #ifdef HAVE_PTHREAD
     617       17676 :         pthread_mutex_lock(&winbind_nss_mutex);
     618             : #endif
     619             : 
     620             :         /* If our static buffer needs to be expanded we are called again */
     621             : 
     622       22647 :         if (!keep_response || strcmp(name,response.data.pw.pw_name) != 0) {
     623             : 
     624             :                 /* Call for the first time */
     625             : 
     626       17676 :                 response = (struct winbindd_response) {
     627             :                         .length = 0,
     628             :                 };
     629       17676 :                 request = (struct winbindd_request) {
     630             :                         .wb_flags = WBFLAG_FROM_NSS,
     631             :                 };
     632             : 
     633       17676 :                 strncpy(request.data.username, name,
     634             :                         sizeof(request.data.username) - 1);
     635             :                 request.data.username
     636       17144 :                         [sizeof(request.data.username) - 1] = '\0';
     637             : 
     638       17676 :                 winbind_set_client_name("nss_winbind");
     639       17676 :                 ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM, &request, &response);
     640             : 
     641       29849 :                 if (ret == NSS_STATUS_SUCCESS) {
     642       12821 :                         ret = fill_pwent(result, &response.data.pw, &buffer,
     643             :                                          &buflen);
     644             : 
     645       12821 :                         if (ret == NSS_STATUS_TRYAGAIN) {
     646           0 :                                 keep_response = true;
     647           0 :                                 *errnop = errno = ERANGE;
     648           0 :                                 goto done;
     649             :                         }
     650             :                 }
     651             : 
     652             :         } else {
     653             : 
     654             :                 /* We've been called again */
     655             : 
     656           0 :                 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
     657             : 
     658           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     659           0 :                         keep_response = true;
     660           0 :                         *errnop = errno = ERANGE;
     661           0 :                         goto done;
     662             :                 }
     663             : 
     664           0 :                 keep_response = false;
     665           0 :                 *errnop = errno = 0;
     666             :         }
     667             : 
     668       17676 :         winbindd_free_response(&response);
     669       17676 :         done:
     670             : #ifdef DEBUG_NSS
     671             :         fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
     672             :                 name, nss_err_str(ret), ret);
     673             : #endif
     674             : 
     675             : #ifdef HAVE_PTHREAD
     676       17676 :         pthread_mutex_unlock(&winbind_nss_mutex);
     677             : #endif
     678             : 
     679       17676 :         return ret;
     680             : }
     681             : 
     682             : /*
     683             :  * NSS group functions
     684             :  */
     685             : 
     686             : static struct winbindd_response getgrent_response;
     687             : 
     688             : static int ndx_gr_cache;                 /* Current index into grp cache */
     689             : static int num_gr_cache;                 /* Current size of grp cache */
     690             : 
     691             : /* Rewind "file pointer" to start of ntdom group database */
     692             : 
     693             : NSS_STATUS
     694          10 : _nss_winbind_setgrent(void)
     695             : {
     696             :         NSS_STATUS ret;
     697             : #ifdef DEBUG_NSS
     698             :         fprintf(stderr, "[%5d]: setgrent\n", getpid());
     699             : #endif
     700             : 
     701             : #ifdef HAVE_PTHREAD
     702          10 :         pthread_mutex_lock(&winbind_nss_mutex);
     703             : #endif
     704             : 
     705          10 :         if (num_gr_cache > 0) {
     706           0 :                 ndx_gr_cache = num_gr_cache = 0;
     707           0 :                 winbindd_free_response(&getgrent_response);
     708             :         }
     709             : 
     710          10 :         winbind_set_client_name("nss_winbind");
     711          10 :         ret = winbindd_request_response(NULL, WINBINDD_SETGRENT, NULL, NULL);
     712             : #ifdef DEBUG_NSS
     713             :         fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
     714             :                 nss_err_str(ret), ret);
     715             : #endif
     716             : 
     717             : #ifdef HAVE_PTHREAD
     718          10 :         pthread_mutex_unlock(&winbind_nss_mutex);
     719             : #endif
     720             : 
     721          10 :         return ret;
     722             : }
     723             : 
     724             : /* Close "file pointer" for ntdom group database */
     725             : 
     726             : NSS_STATUS
     727       39600 : _nss_winbind_endgrent(void)
     728             : {
     729             :         NSS_STATUS ret;
     730             : #ifdef DEBUG_NSS
     731             :         fprintf(stderr, "[%5d]: endgrent\n", getpid());
     732             : #endif
     733             : 
     734             : #ifdef HAVE_PTHREAD
     735       39600 :         pthread_mutex_lock(&winbind_nss_mutex);
     736             : #endif
     737             : 
     738       39600 :         if (num_gr_cache > 0) {
     739           0 :                 ndx_gr_cache = num_gr_cache = 0;
     740           0 :                 winbindd_free_response(&getgrent_response);
     741             :         }
     742             : 
     743       39600 :         winbind_set_client_name("nss_winbind");
     744       39600 :         ret = winbindd_request_response(NULL, WINBINDD_ENDGRENT, NULL, NULL);
     745             : #ifdef DEBUG_NSS
     746             :         fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
     747             :                 nss_err_str(ret), ret);
     748             : #endif
     749             : 
     750             : #ifdef HAVE_PTHREAD
     751       39600 :         pthread_mutex_unlock(&winbind_nss_mutex);
     752             : #endif
     753             : 
     754       39600 :         return ret;
     755             : }
     756             : 
     757             : /* Get next entry from ntdom group database */
     758             : 
     759             : static NSS_STATUS
     760       40648 : winbind_getgrent(enum winbindd_cmd cmd,
     761             :                  struct group *result,
     762             :                  char *buffer, size_t buflen, int *errnop)
     763             : {
     764             :         NSS_STATUS ret;
     765             :         static struct winbindd_request request;
     766             :         static int called_again;
     767             : 
     768             : 
     769             : #ifdef DEBUG_NSS
     770             :         fprintf(stderr, "[%5d]: getgrent\n", getpid());
     771             : #endif
     772             : 
     773             : #ifdef HAVE_PTHREAD
     774       40648 :         pthread_mutex_lock(&winbind_nss_mutex);
     775             : #endif
     776             : 
     777             :         /* Return an entry from the cache if we have one, or if we are
     778             :            called again because we exceeded our static buffer.  */
     779             : 
     780       78909 :         if ((ndx_gr_cache < num_gr_cache) || called_again) {
     781         368 :                 goto return_result;
     782             :         }
     783             : 
     784             :         /* Else call winbindd to get a bunch of entries */
     785             : 
     786       39610 :         if (num_gr_cache > 0) {
     787           0 :                 winbindd_free_response(&getgrent_response);
     788             :         }
     789             : 
     790       39610 :         ZERO_STRUCT(request);
     791       39610 :         ZERO_STRUCT(getgrent_response);
     792             : 
     793       39610 :         request.data.num_entries = MAX_GETGRENT_USERS;
     794             : 
     795       39610 :         winbind_set_client_name("nss_winbind");
     796       39610 :         ret = winbindd_request_response(NULL, cmd, &request,
     797             :                                &getgrent_response);
     798             : 
     799       39610 :         if (ret == NSS_STATUS_SUCCESS) {
     800             :                 struct winbindd_gr *gr_cache;
     801             :                 int mem_ofs;
     802             : 
     803             :                 /* Fill cache */
     804             : 
     805          10 :                 ndx_gr_cache = 0;
     806          10 :                 num_gr_cache = getgrent_response.data.num_entries;
     807             : 
     808             :                 /* Return a result */
     809             : 
     810        1718 :         return_result:
     811             : 
     812        1048 :                 gr_cache = (struct winbindd_gr *)
     813             :                         getgrent_response.extra_data.data;
     814             : 
     815             :                 /* Check data is valid */
     816             : 
     817        1048 :                 if (gr_cache == NULL) {
     818           0 :                         ret = NSS_STATUS_NOTFOUND;
     819           0 :                         goto done;
     820             :                 }
     821             : 
     822             :                 /* Fill group membership.  The offset into the extra data
     823             :                    for the group membership is the reported offset plus the
     824             :                    size of all the winbindd_gr records returned. */
     825             : 
     826        1048 :                 mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
     827             :                         num_gr_cache * sizeof(struct winbindd_gr);
     828             : 
     829        1048 :                 ret = fill_grent(result, &gr_cache[ndx_gr_cache],
     830        1048 :                                  ((char *)getgrent_response.extra_data.data)+mem_ofs,
     831             :                                  &buffer, &buflen);
     832             : 
     833             :                 /* Out of memory - try again */
     834             : 
     835        1048 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     836           0 :                         called_again = true;
     837           0 :                         *errnop = errno = ERANGE;
     838           0 :                         goto done;
     839             :                 }
     840             : 
     841        1048 :                 *errnop = 0;
     842        1048 :                 called_again = false;
     843        1048 :                 ndx_gr_cache++;
     844             : 
     845             :                 /* If we've finished with this lot of results free cache */
     846             : 
     847        1048 :                 if (ndx_gr_cache == num_gr_cache) {
     848          10 :                         ndx_gr_cache = num_gr_cache = 0;
     849          10 :                         winbindd_free_response(&getgrent_response);
     850             :                 }
     851             :         }
     852       79569 :         done:
     853             : #ifdef DEBUG_NSS
     854             :         fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
     855             :                 nss_err_str(ret), ret);
     856             : #endif
     857             : 
     858             : #ifdef HAVE_PTHREAD
     859       40648 :         pthread_mutex_unlock(&winbind_nss_mutex);
     860             : #endif
     861             : 
     862       40648 :         return ret;
     863             : }
     864             : 
     865             : 
     866             : NSS_STATUS
     867       40648 : _nss_winbind_getgrent_r(struct group *result,
     868             :                         char *buffer, size_t buflen, int *errnop)
     869             : {
     870       40648 :         return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
     871             : }
     872             : 
     873             : NSS_STATUS
     874           0 : _nss_winbind_getgrlst_r(struct group *result,
     875             :                         char *buffer, size_t buflen, int *errnop)
     876             : {
     877           0 :         return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
     878             : }
     879             : 
     880             : /* Return group struct from group name */
     881             : 
     882             : NSS_STATUS
     883        1577 : _nss_winbind_getgrnam_r(const char *name,
     884             :                         struct group *result, char *buffer,
     885             :                         size_t buflen, int *errnop)
     886             : {
     887             :         NSS_STATUS ret;
     888             :         static struct winbindd_response response;
     889             :         struct winbindd_request request;
     890             :         static int keep_response;
     891             : 
     892             : #ifdef DEBUG_NSS
     893             :         fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
     894             : #endif
     895             : 
     896             : #ifdef HAVE_PTHREAD
     897        1577 :         pthread_mutex_lock(&winbind_nss_mutex);
     898             : #endif
     899             : 
     900             :         /* If our static buffer needs to be expanded we are called again */
     901             :         /* Or if the stored response group name differs from the request. */
     902             : 
     903        1978 :         if (!keep_response || strcmp(name,response.data.gr.gr_name) != 0) {
     904             : 
     905             :                 /* Call for the first time */
     906             : 
     907        1577 :                 response = (struct winbindd_response) {
     908             :                         .length = 0,
     909             :                 };
     910        1577 :                 request = (struct winbindd_request) {
     911             :                         .wb_flags = WBFLAG_FROM_NSS,
     912             :                 };
     913             : 
     914        1577 :                 strncpy(request.data.groupname, name,
     915             :                         sizeof(request.data.groupname));
     916             :                 request.data.groupname
     917        1577 :                         [sizeof(request.data.groupname) - 1] = '\0';
     918             : 
     919        1577 :                 winbind_set_client_name("nss_winbind");
     920        1577 :                 ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM,
     921             :                                                 &request, &response);
     922             : 
     923        2753 :                 if (ret == NSS_STATUS_SUCCESS) {
     924        1088 :                         ret = fill_grent(result, &response.data.gr,
     925        1088 :                                          (char *)response.extra_data.data,
     926             :                                          &buffer, &buflen);
     927             : 
     928        1088 :                         if (ret == NSS_STATUS_TRYAGAIN) {
     929           0 :                                 keep_response = true;
     930           0 :                                 *errnop = errno = ERANGE;
     931           0 :                                 goto done;
     932             :                         }
     933             :                 }
     934             : 
     935             :         } else {
     936             : 
     937             :                 /* We've been called again */
     938             : 
     939           0 :                 ret = fill_grent(result, &response.data.gr,
     940           0 :                                  (char *)response.extra_data.data, &buffer,
     941             :                                  &buflen);
     942             : 
     943           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
     944           0 :                         keep_response = true;
     945           0 :                         *errnop = errno = ERANGE;
     946           0 :                         goto done;
     947             :                 }
     948             : 
     949           0 :                 keep_response = false;
     950           0 :                 *errnop = 0;
     951             :         }
     952             : 
     953        1577 :         winbindd_free_response(&response);
     954        1577 :         done:
     955             : #ifdef DEBUG_NSS
     956             :         fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
     957             :                 name, nss_err_str(ret), ret);
     958             : #endif
     959             : 
     960             : #ifdef HAVE_PTHREAD
     961        1577 :         pthread_mutex_unlock(&winbind_nss_mutex);
     962             : #endif
     963             : 
     964        1577 :         return ret;
     965             : }
     966             : 
     967             : /* Return group struct from gid */
     968             : 
     969             : NSS_STATUS
     970        1646 : _nss_winbind_getgrgid_r(gid_t gid,
     971             :                         struct group *result, char *buffer,
     972             :                         size_t buflen, int *errnop)
     973             : {
     974             :         NSS_STATUS ret;
     975             :         static struct winbindd_response response;
     976             :         struct winbindd_request request;
     977             :         static int keep_response;
     978             : 
     979             : #ifdef DEBUG_NSS
     980             :         fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
     981             : #endif
     982             : 
     983             : #ifdef HAVE_PTHREAD
     984        1646 :         pthread_mutex_lock(&winbind_nss_mutex);
     985             : #endif
     986             : 
     987             :         /* If our static buffer needs to be expanded we are called again */
     988             :         /* Or if the stored response group name differs from the request. */
     989             : 
     990        2059 :         if (!keep_response || gid != response.data.gr.gr_gid) {
     991             : 
     992             :                 /* Call for the first time */
     993             : 
     994        1646 :                 response = (struct winbindd_response) {
     995             :                         .length = 0,
     996             :                 };
     997        1646 :                 request = (struct winbindd_request) {
     998             :                         .wb_flags = WBFLAG_FROM_NSS,
     999             :                 };
    1000             : 
    1001             : 
    1002        1646 :                 request.data.gid = gid;
    1003             : 
    1004        1646 :                 winbind_set_client_name("nss_winbind");
    1005        1646 :                 ret = winbindd_request_response(NULL, WINBINDD_GETGRGID,
    1006             :                                                 &request, &response);
    1007             : 
    1008        2879 :                 if (ret == NSS_STATUS_SUCCESS) {
    1009             : 
    1010        1632 :                         ret = fill_grent(result, &response.data.gr,
    1011        1632 :                                          (char *)response.extra_data.data,
    1012             :                                          &buffer, &buflen);
    1013             : 
    1014        1632 :                         if (ret == NSS_STATUS_TRYAGAIN) {
    1015           0 :                                 keep_response = true;
    1016           0 :                                 *errnop = errno = ERANGE;
    1017           0 :                                 goto done;
    1018             :                         }
    1019             :                 }
    1020             : 
    1021             :         } else {
    1022             : 
    1023             :                 /* We've been called again */
    1024             : 
    1025           0 :                 ret = fill_grent(result, &response.data.gr,
    1026           0 :                                  (char *)response.extra_data.data, &buffer,
    1027             :                                  &buflen);
    1028             : 
    1029           0 :                 if (ret == NSS_STATUS_TRYAGAIN) {
    1030           0 :                         keep_response = true;
    1031           0 :                         *errnop = errno = ERANGE;
    1032           0 :                         goto done;
    1033             :                 }
    1034             : 
    1035           0 :                 keep_response = false;
    1036           0 :                 *errnop = 0;
    1037             :         }
    1038             : 
    1039        1646 :         winbindd_free_response(&response);
    1040        1646 :         done:
    1041             : #ifdef DEBUG_NSS
    1042             :         fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
    1043             :                 (unsigned int)gid, nss_err_str(ret), ret);
    1044             : #endif
    1045             : 
    1046             : #ifdef HAVE_PTHREAD
    1047        1646 :         pthread_mutex_unlock(&winbind_nss_mutex);
    1048             : #endif
    1049        1646 :         return ret;
    1050             : }
    1051             : 
    1052             : /* Initialise supplementary groups */
    1053             : 
    1054             : NSS_STATUS
    1055         692 : _nss_winbind_initgroups_dyn(const char *user, gid_t group, long int *start,
    1056             :                             long int *size, gid_t **groups, long int limit,
    1057             :                             int *errnop)
    1058             : {
    1059             :         NSS_STATUS ret;
    1060             :         struct winbindd_request request;
    1061             :         struct winbindd_response response;
    1062             :         int i;
    1063             : 
    1064             : #ifdef DEBUG_NSS
    1065             :         fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
    1066             :                 user, group);
    1067             : #endif
    1068             : 
    1069             : #ifdef HAVE_PTHREAD
    1070         692 :         pthread_mutex_lock(&winbind_nss_mutex);
    1071             : #endif
    1072             : 
    1073         692 :         ZERO_STRUCT(request);
    1074         692 :         ZERO_STRUCT(response);
    1075             : 
    1076         692 :         strncpy(request.data.username, user,
    1077             :                 sizeof(request.data.username) - 1);
    1078             : 
    1079         692 :         winbind_set_client_name("nss_winbind");
    1080         692 :         ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS,
    1081             :                                         &request, &response);
    1082             : 
    1083         692 :         if (ret == NSS_STATUS_SUCCESS) {
    1084         692 :                 int num_gids = response.data.num_entries;
    1085         692 :                 gid_t *gid_list = (gid_t *)response.extra_data.data;
    1086             : 
    1087             : #ifdef DEBUG_NSS
    1088             :                 fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
    1089             :                                 "and %d gids\n", getpid(),
    1090             :                                 user, num_gids);
    1091             : #endif
    1092         692 :                 if (gid_list == NULL) {
    1093           0 :                         ret = NSS_STATUS_NOTFOUND;
    1094           0 :                         goto done;
    1095             :                 }
    1096             : 
    1097             :                 /* Copy group list to client */
    1098             : 
    1099        2460 :                 for (i = 0; i < num_gids; i++) {
    1100             : 
    1101             : #ifdef DEBUG_NSS
    1102             :                         fprintf(stderr, "[%5d]: initgroups %s (%d): "
    1103             :                                         "processing gid %d \n", getpid(),
    1104             :                                         user, group, gid_list[i]);
    1105             : #endif
    1106             : 
    1107             :                         /* Skip primary group */
    1108             : 
    1109        1768 :                         if (gid_list[i] == group) {
    1110         692 :                                 continue;
    1111             :                         }
    1112             : 
    1113             :                         /* Skip groups without a mapping */
    1114        1076 :                         if (gid_list[i] == (uid_t)-1) {
    1115           0 :                                 continue;
    1116             :                         }
    1117             : 
    1118             :                         /* Filled buffer ? If so, resize. */
    1119             : 
    1120        1076 :                         if (*start == *size) {
    1121             :                                 long int newsize;
    1122             :                                 gid_t *newgroups;
    1123             : 
    1124           0 :                                 newsize = 2 * (*size);
    1125           0 :                                 if (limit > 0) {
    1126           0 :                                         if (*size == limit) {
    1127           0 :                                                 goto done;
    1128             :                                         }
    1129           0 :                                         if (newsize > limit) {
    1130           0 :                                                 newsize = limit;
    1131             :                                         }
    1132             :                                 }
    1133             : 
    1134           0 :                                 newgroups = (gid_t *)
    1135           0 :                                         realloc((*groups),
    1136             :                                                 newsize * sizeof(**groups));
    1137           0 :                                 if (!newgroups) {
    1138           0 :                                         *errnop = ENOMEM;
    1139           0 :                                         ret = NSS_STATUS_NOTFOUND;
    1140           0 :                                         goto done;
    1141             :                                 }
    1142           0 :                                 *groups = newgroups;
    1143           0 :                                 *size = newsize;
    1144             :                         }
    1145             : 
    1146             :                         /* Add to buffer */
    1147             : 
    1148        1076 :                         (*groups)[*start] = gid_list[i];
    1149        1076 :                         *start += 1;
    1150             :                 }
    1151             :         }
    1152             : 
    1153             :         /* Back to your regularly scheduled programming */
    1154             : 
    1155         692 :  done:
    1156             : #ifdef DEBUG_NSS
    1157             :         fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
    1158             :                 user, nss_err_str(ret), ret);
    1159             : #endif
    1160             : 
    1161             : #ifdef HAVE_PTHREAD
    1162         692 :         pthread_mutex_unlock(&winbind_nss_mutex);
    1163             : #endif
    1164             : 
    1165         692 :         return ret;
    1166             : }

Generated by: LCOV version 1.13