Hi, while experimenting with a modified version of deluser.c I've hit a bug in libpwdgrp. The attached drop in replacement for deluser.c triggers the bug if compiled with bb's libpwdgrp and instead works correctly with glibc.
To reproduce: adduser prova addgroup test1 addgroup test2 addgroup prova test1 addgroup prova test2 grep prova /etc/passwd /etc/group /etc/passwd:prova:x:1004:1005:,,,:/home/prova:/bin/bash /etc/group:test1:x:1008:prova /etc/group:test2:x:1009:prova /etc/group:prova:x:1005: with glibc: ./busybox deluser prova groups[2]=1009 groups[2] gr->gr_name=test2 groups[1]=1008 groups[1] gr->gr_name=test1 grep prova /etc/passwd /etc/group with bb's pwdgrp ./busybox deluser prova groups[2]=1009 groups[2] gr->gr_name=test2 groups[1]=1008 getgrgid failed errno=0 grep prova /etc/passwd /etc/group /etc/group:test1:x:1008:prova /etc/group:prova:x:1005: seems to me that subsequent calls to getgrgid and getgrnam fail Ciao, Tito
/* vi: set sw=4 ts=4: */ /* * deluser/delgroup implementation for busybox * * Copyright (C) 1999 by Lineo, inc. and John Beppu * Copyright (C) 1999,2000,2001 by John Beppu <[email protected]> * Copyright (C) 2007 by Tito Ragusa <[email protected]> * * Licensed under GPLv2, see file LICENSE in this source tree. * */ //usage:#define deluser_trivial_usage //usage: IF_LONG_OPTS("[--remove-home] ") "USER" //usage:#define deluser_full_usage "\n\n" //usage: "Delete USER from the system" // --remove-home is self-explanatory enough to put it in --help //usage:#define delgroup_trivial_usage //usage: IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" //usage:#define delgroup_full_usage "\n\n" //usage: "Delete group GROUP from the system" //usage: IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP") #include "libbb.h" int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int deluser_main(int argc, char **argv) { /* User or group name */ char *name; /* Username (non-NULL only in "delgroup USER GROUP" case) */ char *member; /* Name of passwd or group file */ const char *pfile; /* Name of shadow or gshadow file */ const char *sfile; /* Are we deluser or delgroup? */ int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); struct group *gr; struct passwd *pw; #if !ENABLE_LONG_OPTS const int opt_delhome = 0; #else int opt_delhome = 0; if (do_deluser) { applet_long_options = "remove-home\0" No_argument "\xff"; opt_delhome = getopt32(argv, ""); argv += opt_delhome; argc -= opt_delhome; } #endif if (geteuid() != 0) bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); name = argv[1]; member = NULL; switch (argc) { case 3: if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser) break; /* It's "delgroup USER GROUP" */ member = name; name = argv[2]; /* Fallthrough */ case 2: if (do_deluser) { /* "deluser USER" */ pw = xgetpwnam(name); /* bail out if USER is wrong */ pfile = bb_path_passwd_file; if (ENABLE_FEATURE_SHADOWPASSWDS) sfile = bb_path_shadow_file; if (opt_delhome) remove_file(pw->pw_dir, FILEUTILS_RECUR); } else { do_delgroup: /* "delgroup GROUP" or "delgroup USER GROUP" */ if (do_deluser < 0) { /* delgroup after deluser? */ gr = getgrnam(name); if (!gr) return EXIT_SUCCESS; } else { gr = xgetgrnam(name); /* bail out if GROUP is wrong */ } if (!member) { /* "delgroup GROUP" */ /* Check if the group is in use */ while ((pw = getpwent()) != NULL) { if (pw->pw_gid == gr->gr_gid) bb_error_msg_and_die("'%s' still has '%s' as their primary group!", pw->pw_name, name); } //endpwent(); } pfile = bb_path_group_file; if (ENABLE_FEATURE_SHADOWPASSWDS) sfile = bb_path_gshadow_file; } /* Modify pfile, then sfile */ do { if (update_passwd(pfile, name, NULL, member) == -1) return EXIT_FAILURE; if (ENABLE_FEATURE_SHADOWPASSWDS) { pfile = sfile; sfile = NULL; } } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile); if (ENABLE_DELGROUP && do_deluser > 0) { /* "deluser USER" also should try to delete * the USER from all groups in which he is member. */ gid_t *groups = NULL; int n = 64; retry: groups = xrealloc(groups, n * sizeof(gid_t)); if(getgrouplist(name, pw->pw_gid, groups, &n) == -1) goto retry; while (--n >= 1) { /* our gid is the last group */ printf("groups[%d]=%d\n", n, groups[n]); /* DEBUG */ gr = getgrgid(groups[n]); if (!gr) { printf("getgrgid failed errno=%d\n", errno); /* DEBUG */ continue; } printf("groups[%d] gr->gr_name=%s\n", n, gr->gr_name); /* DEBUG */ update_passwd(bb_path_group_file, gr->gr_name, NULL, name); if (ENABLE_FEATURE_SHADOWPASSWDS) update_passwd(bb_path_gshadow_file, gr->gr_name, NULL, name); } if (ENABLE_FEATURE_CLEAN_UP) free(groups); /* "deluser USER" also should try to delete * same-named group. IOW: do "delgroup USER" */ // On debian deluser is a perl script that calls userdel. // From man userdel: // If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will // delete the group with the same name as the user. do_deluser = -1; goto do_delgroup; } return EXIT_SUCCESS; } /* Reached only if number of command line args is wrong */ bb_show_usage(); }
_______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
