udhcpc: fix a problem with binary-encoded options #2
[oweals/busybox.git] / loginutils / adduser.c
index d938b80f317e34e554491e2f16ef045aa595326a..dc02444766378cd11ec395d1bc55aec3a96080d6 100644 (file)
@@ -7,6 +7,20 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
+
+//usage:#define adduser_trivial_usage
+//usage:       "[OPTIONS] USER [GROUP]"
+//usage:#define adduser_full_usage "\n\n"
+//usage:       "Create new user, or add USER to GROUP\n"
+//usage:     "\n       -h DIR          Home directory"
+//usage:     "\n       -g GECOS        GECOS field"
+//usage:     "\n       -s SHELL        Login shell"
+//usage:     "\n       -G GRP          Add user to existing group"
+//usage:     "\n       -S              Create a system user"
+//usage:     "\n       -D              Don't assign a password"
+//usage:     "\n       -H              Don't create home directory"
+//usage:     "\n       -u UID          User id"
+
 #include "libbb.h"
 
 #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID
@@ -52,6 +66,7 @@ static void passwd_study(struct passwd *p)
                }
                if (p->pw_uid == max) {
                        bb_error_msg_and_die("no %cids left", 'u');
+                       /* this format string is reused in adduser and addgroup */
                }
                p->pw_uid++;
        }
@@ -65,24 +80,44 @@ static void passwd_study(struct passwd *p)
        }
 }
 
-static void addgroup_wrapper(struct passwd *p, const char *group_name)
+static int addgroup_wrapper(struct passwd *p, const char *group_name)
 {
-       char *cmd;
-
-       if (group_name) /* Add user to existing group */
-               cmd = xasprintf("addgroup '%s' '%s'", p->pw_name, group_name);
-       else    /* Add user to his own group with the first free gid found in passwd_study */
-               cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);
-       /* Warning: to be compatible with external addgroup programs we should use --gid instead */
-       system(cmd);
-       free(cmd);
+       char *argv[6];
+
+       argv[0] = (char*)"addgroup";
+       if (group_name) {
+               /* Add user to existing group */
+               argv[1] = (char*)"--";
+               argv[2] = p->pw_name;
+               argv[3] = (char*)group_name;
+               argv[4] = NULL;
+       } else {
+               /* Add user to his own group with the first free gid
+                * found in passwd_study.
+                */
+#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS || !ENABLE_ADDGROUP
+               /* We try to use --gid, not -g, because "standard" addgroup
+                * has no short option -g, it has only long --gid.
+                */
+               argv[1] = (char*)"--gid";
+#else
+               /* Breaks if system in fact does NOT use busybox addgroup */
+               argv[1] = (char*)"-g";
+#endif
+               argv[2] = utoa(p->pw_gid);
+               argv[3] = (char*)"--";
+               argv[4] = p->pw_name;
+               argv[5] = NULL;
+       }
+
+       return spawn_and_wait(argv);
 }
 
 static void passwd_wrapper(const char *login_name) NORETURN;
 
 static void passwd_wrapper(const char *login_name)
 {
-       BB_EXECLP("passwd", "passwd", login_name, NULL);
+       BB_EXECLP("passwd", "passwd", "--", login_name, NULL);
        bb_error_msg_and_die("can't execute passwd, you must set password manually");
 }
 
@@ -123,12 +158,13 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
        }
 
        pw.pw_gecos = (char *)"Linux User,,,";
-       pw.pw_shell = (char *)DEFAULT_SHELL;
+       /* We assume that newly created users "inherit" root's shell setting */
+       pw.pw_shell = (char *)get_shell_name();
        pw.pw_dir = NULL;
 
-       /* exactly one non-option arg */
+       /* at most two non-option args */
        /* disable interactive passwd for system accounts */
-       opt_complementary = "=1:SD:u+";
+       opt_complementary = "?2:SD:u+";
        if (sizeof(pw.pw_uid) == sizeof(int)) {
                opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid);
        } else {
@@ -139,9 +175,16 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
                }
        }
        argv += optind;
+       pw.pw_name = argv[0];
+
+       if (!opts && argv[1]) {
+               /* if called with two non-option arguments, adduser
+                * will add an existing user to an existing group.
+                */
+               return addgroup_wrapper(&pw, argv[1]);
+       }
 
        /* fill in the passwd struct */
-       pw.pw_name = argv[0];
        die_if_bad_username(pw.pw_name);
        if (!pw.pw_dir) {
                /* create string for $HOME if not specified already */
@@ -169,7 +212,6 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
        }
        if (ENABLE_FEATURE_CLEAN_UP)
                free(p);
-
 #if ENABLE_FEATURE_SHADOWPASSWDS
        /* /etc/shadow fields:
         * 1. username
@@ -203,9 +245,11 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
                if (mkdir_err == 0) {
                        /* New home. Copy /etc/skel to it */
                        const char *args[] = {
-                               "chown", "-R",
+                               "chown",
+                               "-R",
                                xasprintf("%u:%u", (int)pw.pw_uid, (int)pw.pw_gid),
-                               pw.pw_dir, NULL
+                               pw.pw_dir,
+                               NULL
                        };
                        /* Be silent on any errors (like: no /etc/skel) */
                        logmode = LOGMODE_NONE;