Home | History | Annotate | Download | only in pending
      1 /* useradd.c - add a new user
      2  *
      3  * Copyright 2013 Ashwini Kumar <ak.ashwini (at) gmail.com>
      4  * Copyright 2013 Kyungwan Han <asura321 (at) gmail.com>
      5  *
      6  * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/useradd.html
      7 
      8 USE_USERADD(NEWTOY(useradd, "<1>2u#<0G:s:g:h:SDH", TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
      9 USE_USERADD(OLDTOY(adduser, useradd, TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
     10 
     11 config USERADD
     12   bool "useradd"
     13   default n
     14   help
     15     usage: useradd [-SDH] [-h DIR] [-s SHELL] [-G GRP] [-g NAME] [-u UID] USER [GROUP]
     16 
     17     Create new user, or add USER to GROUP
     18 
     19     -D       Don't assign a password
     20     -g NAME  Real name
     21     -G GRP   Add user to existing group
     22     -h DIR   Home directory
     23     -H       Don't create home directory
     24     -s SHELL Login shell
     25     -S       Create a system user
     26     -u UID   User id
     27 */
     28 
     29 #define FOR_useradd
     30 #include "toys.h"
     31 
     32 GLOBALS(
     33   char *dir;
     34   char *gecos;
     35   char *shell;
     36   char *u_grp;
     37   long uid;
     38 
     39   long gid;
     40 )
     41 
     42 void useradd_main(void)
     43 {
     44   char *s = *toys.optargs, *entry;
     45   struct passwd pwd;
     46 
     47   // Act like groupadd?
     48   if (toys.optc == 2) {
     49     if (toys.optflags) help_exit("options with USER GROUP");
     50     xexec((char *[]){"groupadd", toys.optargs[0], toys.optargs[1], 0});
     51   }
     52 
     53   // Sanity check user to add
     54   if (s[strcspn(s, ":/\n")] || strlen(s) > LOGIN_NAME_MAX)
     55     error_exit("bad username");
     56   // race condition: two adds at same time?
     57   if (getpwnam(s)) error_exit("'%s' in use", s);
     58 
     59   // Add a new group to the system, if UID is given then that is validated
     60   // to be free, else a free UID is choosen by self.
     61   // SYSTEM IDs are considered in the range 100 ... 999
     62   // add_user(), add a new entry in /etc/passwd, /etc/shadow files
     63 
     64   pwd.pw_name = s;
     65   pwd.pw_passwd = "x";
     66   pwd.pw_gecos = TT.gecos ? TT.gecos : "Linux User,";
     67   pwd.pw_dir = TT.dir ? TT.dir : xmprintf("/home/%s", *toys.optargs);
     68 
     69   if (!TT.shell) {
     70     TT.shell = getenv("SHELL");
     71 
     72     if (!TT.shell) {
     73       struct passwd *pw = getpwuid(getuid());
     74 
     75       if (pw && pw->pw_shell && *pw->pw_shell) TT.shell = xstrdup(pw->pw_shell);
     76       else TT.shell = "/bin/sh";
     77     }
     78   }
     79   pwd.pw_shell = TT.shell;
     80 
     81   if (toys.optflags & FLAG_u) {
     82     if (TT.uid > INT_MAX) error_exit("bad uid");
     83     if (getpwuid(TT.uid)) error_exit("uid '%ld' in use", TT.uid);
     84   } else {
     85     if (toys.optflags & FLAG_S) TT.uid = CFG_TOYBOX_UID_SYS;
     86     else TT.uid = CFG_TOYBOX_UID_USR;
     87     //find unused uid
     88     while (getpwuid(TT.uid)) TT.uid++;
     89   }
     90   pwd.pw_uid = TT.uid;
     91 
     92   if (toys.optflags & FLAG_G) TT.gid = xgetgrnam(TT.u_grp)->gr_gid;
     93   else {
     94     // Set the GID for the user, if not specified
     95     if (toys.optflags & FLAG_S) TT.gid = CFG_TOYBOX_UID_SYS;
     96     else TT.gid = CFG_TOYBOX_UID_USR;
     97     if (getgrnam(pwd.pw_name)) error_exit("group '%s' in use", pwd.pw_name);
     98     //find unused gid
     99     while (getgrgid(TT.gid)) TT.gid++;
    100   }
    101   pwd.pw_gid = TT.gid;
    102 
    103   // Create a new group for user
    104   if (!(toys.optflags & FLAG_G)) {
    105     char *s = xmprintf("-g%ld", (long)pwd.pw_gid);
    106 
    107     if (xrun((char *[]){"groupadd", *toys.optargs, s, 0}))
    108       error_msg("addgroup -g%ld fail", (long)pwd.pw_gid);
    109     free(s);
    110   }
    111 
    112   /*add user to system
    113    * 1. add an entry to /etc/passwd and /etcshadow file
    114    * 2. Copy /etc/skel dir contents to use home dir
    115    * 3. update the user passwd by running 'passwd' utility
    116    */
    117 
    118   // 1. add an entry to /etc/passwd and /etc/shadow file
    119   entry = xmprintf("%s:%s:%ld:%ld:%s:%s:%s", pwd.pw_name, pwd.pw_passwd,
    120       (long)pwd.pw_uid, (long)pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
    121       pwd.pw_shell);
    122   if (update_password("/etc/passwd", pwd.pw_name, entry)) error_exit("updating passwd file failed");
    123   free(entry);
    124 
    125   if (toys.optflags & FLAG_S)
    126   entry = xmprintf("%s:!!:%u::::::", pwd.pw_name,
    127       (unsigned)(time(NULL))/(24*60*60)); //passwd is not set initially
    128   else entry = xmprintf("%s:!!:%u:0:99999:7:::", pwd.pw_name,
    129             (unsigned)(time(0))/(24*60*60)); //passwd is not set initially
    130   update_password("/etc/shadow", pwd.pw_name, entry);
    131   free(entry);
    132 
    133   // create home dir & copy skel dir to home
    134   if (!(toys.optflags & (FLAG_S|FLAG_H))) {
    135     char *skel = "/etc/skel", *p = pwd.pw_dir;
    136 
    137     // Copy and change ownership
    138     if (access(p, F_OK)) {
    139       if (!access(skel, R_OK))
    140         toys.exitval = xrun((char *[]){"cp", "-R", skel, p, 0});
    141       else toys.exitval = xrun((char *[]){"mkdir", "-p", p, 0});
    142       if (!toys.exitval)
    143         toys.exitval |= xrun((char *[]){"chown", "-R",
    144           xmprintf("%lu:%lu", TT.uid, TT.gid), p, 0});
    145       wfchmodat(AT_FDCWD, p, 0700);
    146     } else fprintf(stderr, "'%s' exists, not copying '%s'", p, skel);
    147   }
    148 
    149   //3. update the user passwd by running 'passwd' utility
    150   if (!(toys.optflags & FLAG_D))
    151     if (xrun((char *[]){"passwd", pwd.pw_name, 0})) error_exit("passwd");
    152 
    153   if (toys.optflags & FLAG_G) {
    154     /*add user to the existing group, invoke addgroup command */
    155     if (xrun((char *[]){"groupadd", *toys.optargs, TT.u_grp, 0}))
    156       error_exit("groupadd");
    157   }
    158 }
    159