/*
 * @(#) group.c  RCS: $Revision: 1.3 $ $Date: 95/03/02 12:54:11 $
 *
 * Get the supplementary group id list from the system /etc/group database.
 *
 * There is no POSIX compliant way to do this. BSD provides "initgroups". 
 *
 * This routine is designed to avoid having to depend upon NGROUPS_MAX being
 * a compile-time value.  The caller must supply storage for the array.  Also,
 * error checking and reporting can be done at a finer grain with this design.
 *
 * Depends upon the routine getgrent(3) being available, which it isn't on
 * posix, but almost always is provided by the unix vendor.
 */
#if !defined(_POSIX_SOURCE)
#define _POSIX_SOURCE
#endif
#include <unistd.h>
#include <limits.h>	/* NGROUPS_MAX */
#include <stdio.h>      /* grp.h */
#include <string.h>	/* strcmp */
#include <grp.h>	/* getgrent */
#include <sys/types.h>	/* gid_t */
#include "group.h"
#include "deslogin.h"	/* debug */
#include "log.h"	/* log */

/*
 * Return the list of supplemenatary group id's from the group database 
 * for the given user.   Used to get argument for setgroups(2).
 *
 * Input: 
 *    gidsetsetsize - number of elements in the array grouplist
 *                    may be zero to query the number of groups only.
 *    grouplist     - the array to fill in with group id's for the user
 *    name          - the name of the user to get the group list for.
 *
 * Returns: the number of group ids the user actually may have.
 *          < 0 if the group database couldn't be opened or was empty
 *          may be greater than gidsetsize
 */
int getLoginGroups(gidsetsize, grouplist, name)
   int gidsetsize;
   gid_t grouplist[];
   char *name;
{
   struct group *grent;
   register gid_t gid;
   register char **mem;
   register int ngroups = -1;

   /*
    * Opens the file /etc/group, and gets the first entry, may call network
    * services for yellow pages lookup.
    */
   grent = getgrent();
   if (grent) {
      ngroups = 0;
      do {
         mem = grent->gr_mem;
	 gid = grent->gr_gid;
	 while (*mem) {
	    if (strcmp(name, *mem) == 0) {
	       if (debug > 1) {
		  log("%s: user %s in group %d(%s)\n", 
		     progName, name, gid, grent->gr_name);
	       }
	       if ((ngroups < gidsetsize) && (grouplist)) {
		  grouplist[ngroups] = gid;
	       }
	       ngroups++;
	       break;
	    }
	    mem++;
	 }
	 grent = getgrent();
      } while (grent);
      endgrent();		/* close the database file */
   }

   return ngroups;
}


/*
 * AnnexB.4.2.3:2669-2670:
 * The related function setgroups() is a privileged operation and
 * is not covered by POSIX.1.
 *
 * It's usually supplied by the vendor if you #define the appropriate
 # symbol (__HPUX_SOURCE __OSF_SOURCE etc).
 */
int setGroups(ngroups, gidset)
   int ngroups;
   gid_t *gidset;
{
   int res;
   res = setgroups(ngroups, gidset);
   return res;
}
