Supplementary Groups

Many people are members of several functional groups. Having access to files based on a single group designation is inconvenient. This often requires the user to switch between groups, using the newgrp(1) command, simply to gain the correct access permissions.

Supplementary groups makes it possible for a user to have access to all files at the group level, even when the groups differ. An example illustrates this problem:

  • Account erin is a member of group projectx.

  • Account scott is a member of group projectq.

Erin and Scott are working on similar programs within each of their own projects (projects X and Q), and they are in dispute. Laura, their supervisor, wants to compare the files to see how much they differ.

The difficulty is that Erin and Scott each own their files. However, Erin's file grants read permission to the group projectx, and Scott's file grants read permission to the group projectq. Laura cannot be in the correct group to read both of them at the same time.

Supplementary groups allow Laura to be a member of both groups at the same time. This allows her to be granted read access to both files at once, even when the groups differ. Laura is able to perform a diff(1) command without having to copy one file and then perform a newgrp(1) command.

The getgroups(2) Function

The id(1) command reports all of the supplementary groups that you are currently in. This is accomplished with a call to the getgroups(2) function. Its synopsis is as follows:

#include <sys/types.h>
#include <unistd.h>

int getgroups(int gidsetlen, gid_t *gidset);

The getgroups(2) function returns a list of group ID values in the array pointed to by gidset. The list can have no more than gidsetlen values, and the number of groups returned in the array is the return value. A return value of -1 indicates that an error has occurred (check errno). If your platform has the sysconf(2) value for _SC_NGROUPS_MAX defined as zero, then zero is returned by getgroups(2). This indicates no supplementary group support.

When the argument gidsetlen is zero, the return value indicates how many supplementary groups there are to be returned. No change is made to the set given by the gidset argument in this case. This can be used to determine how large the array should be.

Note

For many systems, the maximum possible number of supplementary groups is determined by calling sysconf(2) using _SC_NGROUPS_MAX.


An example of getgroups(2) is found in Listing 12.1.

Code Listing 12.1. getgroups.c—An Example Using getgroups(2)
1:   /* getgroups.c */
2:
3:   #include <stdio.h>
4:   #include <stdlib.h>
5:   #include <unistd.h>
6:   #include <sys/types.h>
7:   #include <grp.h>
8:   #include <errno.h>
9:
10:  int
11:  main(int argc,char **argv,char **envp) {
12:      int x;                                  /* Index */
13:      int n;                                  /* groups returned */
14:      struct group *grp;                      /* /etc/group entry */
15:      int setlen = sysconf(_SC_NGROUPS_MAX);  /* Max # groups */
16:      gid_t *gidset = 0;                      /* sup. grp array */
17:
18:      printf("setlen = %d
",setlen);         /* Print max # groups */
19:      if ( setlen < 1 )
20:          exit(1);                            /* Quit if we have none */
21:     
22:      /*
23:       * Allocate the set to maximum size :
24:       */
25:      gidset = (gid_t *) malloc(setlen * sizeof *gidset);
26:
27:      /*
28:       * Obtain the list of supplementary groups :
29:       */
30:      n = getgroups(setlen,gidset);
31:
32:      /*
33:       * Display the supplementary groups found :
34:       */
35:      for ( x=0; x<n; ++x ) {
36:          grp = getgrgid(gidset[x]);
37:          printf("Supplemental group: %5d  %s
",
38:              gidset[x],
39:              grp ? grp->gr_name : "?");
40:      }
41:
42:      return 0;
43:  }

The program in Listing 12.1 first calls on sysconf(2) to determine what the maximum number of supplementary groups is for this system (line 15). Once that value is known (variable setlen), then the array gidset is allocated, in line 25, by calling malloc(3). An alternative would have been to call getgroups(2) with a zero value for the array length. This would have indicated how many group ID values to expect.

After the getgroups(2) function is called in line 30, the entries are displayed in the for loop in lines 35–40. Notice the use of getgrgid(3) in line 36 to convert the group ID number into a name (displayed in line 39).

Compiling and running the program on your system should return results similar to this:

$ make
cc -c -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -Wall getgroups.c
cc -o getgroups getgroups.o
$ ./getgroups
setlen = 16
Supplemental group:  1001  me
Supplemental group:  2010  mygrp
$

On this FreeBSD system, you can see that a maximum of 16 supplementary groups is supported. Two supplementary groups are returned and reported here.

Setting Groups with setgroups(2)

The login(1) program, which determines the groups to which your account belongs, must call on a function to establish your list of supplementary groups. This is accomplished with the setgroups(2) function:

#include <sys/param.h>
#include <unistd.h>

int setgroups(int ngroups, const gid_t *gidset);

The number of groups being established is given in ngroups, and the array of values is given by the pointer gidset. This function returns 0 upon success or -1 if an error occurs. Expect to get the error EPERM if you call this function without being the super user, because only the super user is permitted to set supplementary groups.

Setting Groups for a Specific Username

The function initgroups(3) is a convenience function that might be used by login(1) instead of building its own array of groups. The FreeBSD and AIX synopsis for initgroups(3) is as follows:

/* FreeBSD and IBM AIX 4.3 */

#include <unistd.h>

int initgroups(const char *name, int basegid);

There is considerable variation of this on other UNIX platforms. Variation occurs with the include files used and the type of the second argument. The synopsis for HPUX-11 is as follows:

/* HPUX-11 */

#include <unistd.h>

int initgroups(char *name, gid_t basegid);

The next synopsis is valid for UnixWare 7, Solaris 8, and Linux:

/* UnixWare 7, Solaris 8, and Linux */

#include <grp.h>
#include <sys/types.h>

int initgroups(char *name, gid_t basegid);

The last synopsis is for SGI IRIX 6.5. There is no <grp.h> file included.

/* SGI IRIX 6.5 */

#include <sys/types.h>

int initgroups(char *name, gid_t basegid);

With this function, a program such as login(1) needs only to supply the user's name in argument name and a current group ID basegid. The function initgroups(3) builds an array of all groups to which the named user belongs and calls on setgroups(2) to make it so.

The function returns 0 when successful or -1 when it fails (check errno). Since initgroups(3) calls on setgroups(2), only a super user will be successful in making this call.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.210.17