Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nslcd-common.h21
-rw-r--r--nss/group.c57
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 */