As posted to the openbsd forum in March, the usermod program only appends
users to secondary groups with the -G switch, rather than setting the 
secondary groups.

As mentioned previously, this problem has been around for some 10 years.

http://marc.info/?l=openbsd-misc&m=109088617022480&w=2
http://marc.info/?l=tru64-unix-managers&m=97203990632722&w=2

I've modified the user.c and changed the append_group function to become the 
modify_group function, and in the function, changed the code to remove the 
user from the given groups (and append him as before if he is supposed to be
there).

To append a user to a group, you would now do something like:

  $groups=`groups $user | sed -e 's/ /,/'`
  usermod -G $groups,newgroup $user

Diff appears below:

Steve Clarke


Index: user.c
===================================================================
RCS file: /cvs/src/usr.sbin/user/user.c,v
retrieving revision 1.81
diff -u -r1.81 user.c
--- user.c      16 Apr 2011 07:41:08 -0000      1.81
+++ user.c      17 Apr 2011 18:35:26 -0000
@@ -485,9 +485,9 @@
        return 1;
 }
 
-/* modify the group entries for all `groups', by adding `user' */
+/* modify the group entries for all `groups', by adding or removing `user' */
 static int
-append_group(char *user, int ngroups, const char **groups)
+modify_group(char *user, int ngroups, const char **groups)
 {
        struct group    *grp;
        struct stat     st;
@@ -500,20 +500,19 @@
        int             cc;
        int             i;
        int             j;
+       int             c ;
+       int             d ;
+       int             l ;
 
+       /* Check groups are valid */
        for (i = 0 ; i < ngroups ; i++) {
                if ((grp = getgrnam(groups[i])) == NULL) {
                        warnx("can't append group `%s' for user `%s'",
                            groups[i], user);
-               } else {
-                       for (j = 0 ; grp->gr_mem[j] ; j++) {
-                               if (strcmp(user, grp->gr_mem[j]) == 0) {
-                                       /* already in it */
-                                       groups[i] = "";
-                               }
-                       }
                }
        }
+
+       /* Open and lock files */
        if ((from = fopen(_PATH_GROUP, "r")) == NULL) {
                warn("can't append group for `%s': can't open `%s'", user,
                    _PATH_GROUP);
@@ -536,7 +535,10 @@
                warn("can't append group: fdopen `%s' failed", f);
                return 0;
        }
+
        while (fgets(buf, sizeof(buf), from) != NULL) {
+
+               /* Load entry from file */
                cc = strlen(buf);
                if (cc > 0 && buf[cc - 1] != '\n' && !feof(from)) {
                        while (fgetc(from) != '\n' && !feof(from))
@@ -545,30 +547,53 @@
                            _PATH_GROUP, buf, cc);
                        continue;
                }
-               if ((colon = strchr(buf, ':')) == NULL) {
+               while (isspace(buf[cc-1])) cc-- ;
+               buf[cc]='\0' ;
+
+                /* Remove username from list */
+               for (c=0,d=0; buf[c]!=':' && buf[c]!='\0'; c++,d++) ;
+               if (buf[d]==':') d++ ;
+               for (; buf[d]!=':' && buf[d]!='\0'; d++) ;
+               if (buf[d]==':') d++ ;
+               for (; buf[d]!=':' && buf[d]!='\0'; d++) ;
+               if (buf[d]!=':') {
                        warnx("badly formed entry `%s'", buf);
                        continue;
                }
+               l=strlen(user) ;
+               for (i=d; buf[i]!='\0' && 
+                   !(strncmp(user, &buf[i], l)==0 && 
+                   !isalnum(buf[i+l])); i++) ;
+               if (buf[i]!='\0') {
+                       if (buf[i-1]==',') { i-- ; l++ ; }
+                       else if (buf[i-1]==':') { l++ ; }
+                       for (i+=l; buf[i]!='\0'; i++) 
+                               buf[i-l]=buf[i] ;
+                       buf[i-l]='\0' ;
+                       cc=strlen(buf) ;
+               }
+
+               /* Append username to list if in group */
                for (i = 0 ; i < ngroups ; i++) {
-                       j = (int)(colon - buf);
+                       j = (int)c ;
                        if (strncmp(groups[i], buf, j) == 0 &&
                            groups[i][j] == '\0') {
-                               while (isspace(buf[cc - 1]))
-                                       cc--;
-                               buf[(j = cc)] = '\0';
-                               if (buf[strlen(buf) - 1] != ':')
+                               j=cc ;
+                               if (buf[strlen(buf)] != ':')
                                        strlcat(buf, ",", sizeof(buf));
-                               cc = strlcat(buf, user, sizeof(buf)) + 1;
-                               if (cc >= sizeof(buf)) {
+                               cc = strlcat(buf, user, sizeof(buf)) ;
+                               if (cc >= sizeof(buf)-1) {
                                        warnx("Warning: group `%s' would "
                                            "become too long, not modifying",
                                            groups[i]);
                                        cc = j + 1;
                                }
-                               buf[cc - 1] = '\n';
                                buf[cc] = '\0';
                        }
                }
+               buf[cc++]='\n' ;
+               buf[cc]='\0' ;
+
                if (fwrite(buf, cc, 1, to) != 1) {
                        (void) fclose(from);
                        (void) fclose(to);
@@ -1195,7 +1220,7 @@
                errx(EXIT_FAILURE, "can't create gid %d for login name %s",
                    gid, login_name);
        }
-       if (up->u_groupc > 0 && !append_group(login_name, up->u_groupc, up-
>u_groupv)) {
+       if (up->u_groupc > 0 && !modify_group(login_name, up->u_groupc, up-
>u_groupv)) {
                (void) close(ptmpfd);
                pw_abort();
                errx(EXIT_FAILURE, "can't append `%s' to new groups", 
login_name);
@@ -1538,7 +1563,7 @@
                            homedir, pwp->pw_dir);
                }
                if (up->u_groupc > 0 &&
-                   !append_group(newlogin, up->u_groupc, up->u_groupv)) {
+                   !modify_group(newlogin, up->u_groupc, up->u_groupv)) {
                        (void) close(ptmpfd);
                        pw_abort();
                        errx(EXIT_FAILURE, "can't append `%s' to new groups",
Index: usermod.8
===================================================================
RCS file: /cvs/src/usr.sbin/user/usermod.8,v
retrieving revision 1.25
diff -u -r1.25 usermod.8
--- usermod.8   8 Apr 2011 18:13:54 -0000       1.25
+++ usermod.8   17 Apr 2011 18:35:26 -0000
@@ -103,7 +103,12 @@
 .It Fl G Ar secondary-group[,group,...]
 Sets the secondary groups the user will be a member of in the
 .Pa /etc/group
-file.
+file.  If the user is not in a group that is listed, the user
+will be added to the
+.Pa /etc/group
+file.  If the user is a member of the group in the
+.Pa /etc/group
+file, but is not listed, he will be removed from that group.
 .It Xo
 .Fl g Ar gid | name | Li =uid
 .Xc
@@ -236,6 +241,9 @@
 .Nm
 utility first appeared in
 .Ox 2.7 .
+.Nm
+was modified in April 2011 to make the -G switch set secondary groups for 
user,
+rather than append user to listed groups.
 .Sh AUTHORS
 The
 .Nm

Reply via email to