ash: builtin: Mark more regular built-ins
[oweals/busybox.git] / loginutils / adduser.c
index dc02444766378cd11ec395d1bc55aec3a96080d6..d3c795afa48bec5306c475b510c9cd02680ed4e2 100644 (file)
@@ -7,6 +7,51 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
+//config:config ADDUSER
+//config:      bool "adduser (15 kb)"
+//config:      default y
+//config:      select LONG_OPTS
+//config:      help
+//config:      Utility for creating a new user account.
+//config:
+//config:config FEATURE_CHECK_NAMES
+//config:      bool "Enable sanity check on user/group names in adduser and addgroup"
+//config:      default n
+//config:      depends on ADDUSER || ADDGROUP
+//config:      help
+//config:      Enable sanity check on user and group names in adduser and addgroup.
+//config:      To avoid problems, the user or group name should consist only of
+//config:      letters, digits, underscores, periods, at signs and dashes,
+//config:      and not start with a dash (as defined by IEEE Std 1003.1-2001).
+//config:      For compatibility with Samba machine accounts "$" is also supported
+//config:      at the end of the user or group name.
+//config:
+//config:config LAST_ID
+//config:      int "Last valid uid or gid for adduser and addgroup"
+//config:      depends on ADDUSER || ADDGROUP
+//config:      default 60000
+//config:      help
+//config:      Last valid uid or gid for adduser and addgroup
+//config:
+//config:config FIRST_SYSTEM_ID
+//config:      int "First valid system uid or gid for adduser and addgroup"
+//config:      depends on ADDUSER || ADDGROUP
+//config:      range 0 LAST_ID
+//config:      default 100
+//config:      help
+//config:      First valid system uid or gid for adduser and addgroup
+//config:
+//config:config LAST_SYSTEM_ID
+//config:      int "Last valid system uid or gid for adduser and addgroup"
+//config:      depends on ADDUSER || ADDGROUP
+//config:      range FIRST_SYSTEM_ID LAST_ID
+//config:      default 999
+//config:      help
+//config:      Last valid system uid or gid for adduser and addgroup
+
+//applet:IF_ADDUSER(APPLET_NOEXEC(adduser, adduser, BB_DIR_USR_SBIN, BB_SUID_DROP, adduser))
+
+//kbuild:lib-$(CONFIG_ADDUSER) += adduser.o
 
 //usage:#define adduser_trivial_usage
 //usage:       "[OPTIONS] USER [GROUP]"
 //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       -G GRP          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"
+//usage:     "\n       -k SKEL         Skeleton directory (/etc/skel)"
 
 #include "libbb.h"
 
 #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID
 #error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config
 #endif
+#if CONFIG_LAST_ID < CONFIG_LAST_SYSTEM_ID
+#error Bad LAST_ID or LAST_SYSTEM_ID in .config
+#endif
+
 
 /* #define OPT_HOME           (1 << 0) */ /* unused */
 /* #define OPT_GECOS          (1 << 1) */ /* unused */
 #define OPT_SYSTEM_ACCOUNT (1 << 5)
 #define OPT_DONT_MAKE_HOME (1 << 6)
 #define OPT_UID            (1 << 7)
+#define OPT_SKEL           (1 << 8)
 
-/* We assume UID_T_MAX == INT_MAX */
 /* remix */
 /* recoded such that the uid may be passed in *p */
 static void passwd_study(struct passwd *p)
 {
-       int max = UINT_MAX;
+       int max = CONFIG_LAST_ID;
 
        if (getpwnam(p->pw_name)) {
                bb_error_msg_and_die("%s '%s' in use", "user", p->pw_name);
@@ -54,7 +104,6 @@ static void passwd_study(struct passwd *p)
                        max = CONFIG_LAST_SYSTEM_ID;
                } else {
                        p->pw_uid = CONFIG_LAST_SYSTEM_ID + 1;
-                       max = 64999;
                }
        }
        /* check for a free uid (and maybe gid) */
@@ -95,15 +144,7 @@ static int addgroup_wrapper(struct passwd *p, const char *group_name)
                /* 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;
@@ -118,10 +159,10 @@ 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_error_msg_and_die("can't execute passwd, you must set password manually");
+       bb_simple_error_msg_and_die("can't execute passwd, you must set password manually");
 }
 
-#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
+//FIXME: upstream adduser has no short options! NOT COMPATIBLE!
 static const char adduser_longopts[] ALIGN1 =
                "home\0"                Required_argument "h"
                "gecos\0"               Required_argument "g"
@@ -132,8 +173,8 @@ static const char adduser_longopts[] ALIGN1 =
                "system\0"              No_argument       "S"
                "no-create-home\0"      No_argument       "H"
                "uid\0"                 Required_argument "u"
+               "skel\0"                Required_argument "k"
                ;
-#endif
 
 /*
  * adduser will take a login_name as its first parameter.
@@ -147,33 +188,31 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
        const char *usegroup = NULL;
        char *p;
        unsigned opts;
-
-#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
-       applet_long_options = adduser_longopts;
-#endif
+       char *uid;
+       const char *skel = "/etc/skel";
 
        /* got root? */
        if (geteuid()) {
-               bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+               bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);
        }
 
        pw.pw_gecos = (char *)"Linux User,,,";
        /* We assume that newly created users "inherit" root's shell setting */
-       pw.pw_shell = (char *)get_shell_name();
+       pw.pw_shell = xstrdup(get_shell_name()); /* might come from getpwnam(), need to make a copy */
        pw.pw_dir = NULL;
 
-       /* at most two non-option args */
-       /* disable interactive passwd for system accounts */
-       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 {
-               unsigned uid;
-               opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid);
-               if (opts & OPT_UID) {
-                       pw.pw_uid = uid;
-               }
-       }
+       opts = getopt32long(argv, "^"
+                       "h:g:s:G:DSHu:k:"
+                       /* at least one and at most two non-option args */
+                       /* disable interactive passwd for system accounts */
+                       "\0" "-1:?2:SD",
+                       adduser_longopts,
+                       &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell,
+                       &usegroup, &uid, &skel
+       );
+       if (opts & OPT_UID)
+               pw.pw_uid = xatou_range(uid, 0, CONFIG_LAST_ID);
+
        argv += optind;
        pw.pw_name = argv[0];
 
@@ -252,8 +291,9 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
                                NULL
                        };
                        /* Be silent on any errors (like: no /etc/skel) */
-                       logmode = LOGMODE_NONE;
-                       copy_file("/etc/skel", pw.pw_dir, FILEUTILS_RECUR);
+                       if (!(opts & OPT_SKEL))
+                               logmode = LOGMODE_NONE;
+                       copy_file(skel, pw.pw_dir, FILEUTILS_RECUR);
                        logmode = LOGMODE_STDIO;
                        chown_main(4, (char**)args);
                }