useradd.c 4.9 KB

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