diff options
-rw-r--r-- | nslcd-common.h | 21 | ||||
-rw-r--r-- | nss/group.c | 57 |
2 files changed, 73 insertions, 5 deletions
diff --git a/nslcd-common.h b/nslcd-common.h index 933bd60..e1c5d9e 100644 --- a/nslcd-common.h +++ b/nslcd-common.h @@ -125,13 +125,30 @@ if ((bufptr+(size_t)tmp2int32)>buflen) \ { ERROR_OUT_BUFERROR(fp) } /* will not fit */ \ (arr)=(char **)(buffer+bufptr); \ - /* set last entry to NULL */ \ - (arr)[tmpint32]=NULL; \ /* read all entries */ \ bufptr+=(size_t)tmpint32; \ for (tmp2int32=0;tmp2int32<tmpint32;tmp2int32++) \ { \ opr \ + } \ + /* set last entry to NULL */ \ + (arr)[tmp2int32]=NULL; + +/* read a string from the stream but don't do anything with the result */ +#define SKIP_STRING(fp) \ + /* read the size of the string */ \ + READ_TYPE(fp,tmpint32,int32_t); \ + /* seek in the stream past the string contents */ \ + fseek(fp,(long)tmpint32,SEEK_CUR); \ + DEBUG_PRINT("SKIP_STRING()\n"); + +/* skip a loop of strings */ +#define SKIP_LOOP(fp) \ + READ_TYPE(fp,tmpint32,int32_t); \ + /* read all entries */ \ + for (tmp2int32=0;tmp2int32<tmpint32;tmp2int32++) \ + { \ + SKIP_STRING(fp); \ } #endif /* not _NSLCD_COMMON_H */ diff --git a/nss/group.c b/nss/group.c index 4c98f6b..b9ea5c2 100644 --- a/nss/group.c +++ b/nss/group.c @@ -77,13 +77,64 @@ enum nss_status _nss_ldap_getgrgid_r(gid_t gid,struct group *result,char *buffer return NSS_STATUS_SUCCESS; } -/* this function returns a list of groups */ +/* this function returns a list of groups, documentation for the + interface is scarce (any pointers are welcome) but this is + what is assumed the parameters mean: + + user IN - the user name to find groups for + group ingored - an extra gid to add to the list? + *start IN/OUT - where to write in the array, is incremented + *size IN - the size of the supplied array + *groupsp IN/OUT - the array of groupids + limit IN - the maximum number of groups to add + *errnop OUT - for returning errno + + This function cannot grow the array if it becomes too large + (and will return NSS_STATUS_TRYAGAIN on buffer problem) + because it has no way of free()ing the buffer. +*/ enum nss_status _nss_ldap_initgroups_dyn( const char *user,gid_t group,long int *start, long int *size,gid_t **groupsp,long int limit,int *errnop) { - return NSS_STATUS_UNAVAIL; - /* TODO: implement skipping of entries as we're only interested in gids */ + FILE *fp; + size_t bufptr=0; + int32_t cd; + int32_t tmpint32,tmp2int32; + gid_t gid; + int num=0; + /* open socket and write the request */ + OPEN_SOCK(fp); + WRITE_REQUEST(fp,NSLCD_ACTION_GROUP_BYMEMBER); + WRITE_STRING(fp,user); + WRITE_FLUSH(fp); + /* read response */ + READ_RESPONSEHEADER(fp,NSLCD_ACTION_GROUP_BYMEMBER); + /* read response code */ + READ_TYPE(fp,cd,int32_t); + /* loop over results */ + while (cd==NSLCD_RESULT_SUCCESS) + { + /* skip group name */ + SKIP_STRING(fp); + /* skip passwd entry */ + SKIP_STRING(fp); + /* read gid */ + READ_TYPE(fp,gid,gid_t); + /* skip members */ + SKIP_LOOP(fp); + /* check if entry would fit and we have not returned too many */ + if ( ((*start)>=(*size)) || (num>=limit) ) + { ERROR_OUT_BUFERROR(fp); } + /* add gid to list */ + (*groupsp)[*start++]=gid; + num++; + /* read next response code */ + READ_TYPE(fp,cd,int32_t); + } + /* close socket and we're done */ + fclose(fp); + return NSS_STATUS_SUCCESS; } /* thread-local file pointer to an ongoing request */ |