toybox/toys/pending/useradd.c
<<
>>
Prefs
   1/* useradd.c - add a new user
   2 *
   3 * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
   4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
   5 *
   6 * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/useradd.html
   7
   8USE_USERADD(NEWTOY(useradd, "<1>2u#<0G:s:g:h:SDH", TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
   9USE_USERADD(OLDTOY(adduser, useradd, TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
  10
  11config 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
  32GLOBALS(
  33  char *dir;
  34  char *gecos;
  35  char *shell;
  36  char *u_grp;
  37  long uid;
  38
  39  long gid;
  40)
  41
  42void 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