adduser.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * adduser - add users to /etc/passwd and /etc/shadow
  4. *
  5. * Copyright (C) 1999 by Lineo, inc. and John Beppu
  6. * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
  7. *
  8. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  9. */
  10. //config:config ADDUSER
  11. //config: bool "adduser (15 kb)"
  12. //config: default y
  13. //config: select LONG_OPTS
  14. //config: help
  15. //config: Utility for creating a new user account.
  16. //config:
  17. //config:config FEATURE_CHECK_NAMES
  18. //config: bool "Enable sanity check on user/group names in adduser and addgroup"
  19. //config: default n
  20. //config: depends on ADDUSER || ADDGROUP
  21. //config: help
  22. //config: Enable sanity check on user and group names in adduser and addgroup.
  23. //config: To avoid problems, the user or group name should consist only of
  24. //config: letters, digits, underscores, periods, at signs and dashes,
  25. //config: and not start with a dash (as defined by IEEE Std 1003.1-2001).
  26. //config: For compatibility with Samba machine accounts "$" is also supported
  27. //config: at the end of the user or group name.
  28. //config:
  29. //config:config LAST_ID
  30. //config: int "Last valid uid or gid for adduser and addgroup"
  31. //config: depends on ADDUSER || ADDGROUP
  32. //config: default 60000
  33. //config: help
  34. //config: Last valid uid or gid for adduser and addgroup
  35. //config:
  36. //config:config FIRST_SYSTEM_ID
  37. //config: int "First valid system uid or gid for adduser and addgroup"
  38. //config: depends on ADDUSER || ADDGROUP
  39. //config: range 0 LAST_ID
  40. //config: default 100
  41. //config: help
  42. //config: First valid system uid or gid for adduser and addgroup
  43. //config:
  44. //config:config LAST_SYSTEM_ID
  45. //config: int "Last valid system uid or gid for adduser and addgroup"
  46. //config: depends on ADDUSER || ADDGROUP
  47. //config: range FIRST_SYSTEM_ID LAST_ID
  48. //config: default 999
  49. //config: help
  50. //config: Last valid system uid or gid for adduser and addgroup
  51. //applet:IF_ADDUSER(APPLET_NOEXEC(adduser, adduser, BB_DIR_USR_SBIN, BB_SUID_DROP, adduser))
  52. //kbuild:lib-$(CONFIG_ADDUSER) += adduser.o
  53. //usage:#define adduser_trivial_usage
  54. //usage: "[OPTIONS] USER [GROUP]"
  55. //usage:#define adduser_full_usage "\n\n"
  56. //usage: "Create new user, or add USER to GROUP\n"
  57. //usage: "\n -h DIR Home directory"
  58. //usage: "\n -g GECOS GECOS field"
  59. //usage: "\n -s SHELL Login shell"
  60. //usage: "\n -G GRP Group"
  61. //usage: "\n -S Create a system user"
  62. //usage: "\n -D Don't assign a password"
  63. //usage: "\n -H Don't create home directory"
  64. //usage: "\n -u UID User id"
  65. //usage: "\n -k SKEL Skeleton directory (/etc/skel)"
  66. #include "libbb.h"
  67. #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID
  68. #error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config
  69. #endif
  70. #if CONFIG_LAST_ID < CONFIG_LAST_SYSTEM_ID
  71. #error Bad LAST_ID or LAST_SYSTEM_ID in .config
  72. #endif
  73. /* #define OPT_HOME (1 << 0) */ /* unused */
  74. /* #define OPT_GECOS (1 << 1) */ /* unused */
  75. #define OPT_SHELL (1 << 2)
  76. #define OPT_GID (1 << 3)
  77. #define OPT_DONT_SET_PASS (1 << 4)
  78. #define OPT_SYSTEM_ACCOUNT (1 << 5)
  79. #define OPT_DONT_MAKE_HOME (1 << 6)
  80. #define OPT_UID (1 << 7)
  81. #define OPT_SKEL (1 << 8)
  82. /* remix */
  83. /* recoded such that the uid may be passed in *p */
  84. static void passwd_study(struct passwd *p)
  85. {
  86. int max = CONFIG_LAST_ID;
  87. if (getpwnam(p->pw_name)) {
  88. bb_error_msg_and_die("%s '%s' in use", "user", p->pw_name);
  89. /* this format string is reused in adduser and addgroup */
  90. }
  91. if (!(option_mask32 & OPT_UID)) {
  92. if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
  93. p->pw_uid = CONFIG_FIRST_SYSTEM_ID;
  94. max = CONFIG_LAST_SYSTEM_ID;
  95. } else {
  96. p->pw_uid = CONFIG_LAST_SYSTEM_ID + 1;
  97. }
  98. }
  99. /* check for a free uid (and maybe gid) */
  100. while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) {
  101. if (option_mask32 & OPT_UID) {
  102. /* -u N, cannot pick uid other than N: error */
  103. bb_error_msg_and_die("%s '%s' in use", "uid", itoa(p->pw_uid));
  104. /* this format string is reused in adduser and addgroup */
  105. }
  106. if (p->pw_uid == max) {
  107. bb_error_msg_and_die("no %cids left", 'u');
  108. /* this format string is reused in adduser and addgroup */
  109. }
  110. p->pw_uid++;
  111. }
  112. if (p->pw_gid == (gid_t)-1) {
  113. p->pw_gid = p->pw_uid; /* new gid = uid */
  114. if (getgrnam(p->pw_name)) {
  115. bb_error_msg_and_die("%s '%s' in use", "group", p->pw_name);
  116. /* this format string is reused in adduser and addgroup */
  117. }
  118. }
  119. }
  120. static int addgroup_wrapper(struct passwd *p, const char *group_name)
  121. {
  122. char *argv[6];
  123. argv[0] = (char*)"addgroup";
  124. if (group_name) {
  125. /* Add user to existing group */
  126. argv[1] = (char*)"--";
  127. argv[2] = p->pw_name;
  128. argv[3] = (char*)group_name;
  129. argv[4] = NULL;
  130. } else {
  131. /* Add user to his own group with the first free gid
  132. * found in passwd_study.
  133. */
  134. argv[1] = (char*)"--gid";
  135. argv[2] = utoa(p->pw_gid);
  136. argv[3] = (char*)"--";
  137. argv[4] = p->pw_name;
  138. argv[5] = NULL;
  139. }
  140. return spawn_and_wait(argv);
  141. }
  142. static void passwd_wrapper(const char *login_name) NORETURN;
  143. static void passwd_wrapper(const char *login_name)
  144. {
  145. BB_EXECLP("passwd", "passwd", "--", login_name, NULL);
  146. bb_simple_error_msg_and_die("can't execute passwd, you must set password manually");
  147. }
  148. //FIXME: upstream adduser has no short options! NOT COMPATIBLE!
  149. static const char adduser_longopts[] ALIGN1 =
  150. "home\0" Required_argument "h"
  151. "gecos\0" Required_argument "g"
  152. "shell\0" Required_argument "s"
  153. "ingroup\0" Required_argument "G"
  154. "disabled-password\0" No_argument "D"
  155. "empty-password\0" No_argument "D"
  156. "system\0" No_argument "S"
  157. "no-create-home\0" No_argument "H"
  158. "uid\0" Required_argument "u"
  159. "skel\0" Required_argument "k"
  160. ;
  161. /*
  162. * adduser will take a login_name as its first parameter.
  163. * home, shell, gecos:
  164. * can be customized via command-line parameters.
  165. */
  166. int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  167. int adduser_main(int argc UNUSED_PARAM, char **argv)
  168. {
  169. struct passwd pw;
  170. const char *usegroup = NULL;
  171. char *p;
  172. unsigned opts;
  173. char *uid;
  174. const char *skel = "/etc/skel";
  175. /* got root? */
  176. if (geteuid()) {
  177. bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);
  178. }
  179. pw.pw_gecos = (char *)"Linux User,,,";
  180. /* We assume that newly created users "inherit" root's shell setting */
  181. pw.pw_shell = xstrdup(get_shell_name()); /* might come from getpwnam(), need to make a copy */
  182. pw.pw_dir = NULL;
  183. opts = getopt32long(argv, "^"
  184. "h:g:s:G:DSHu:k:"
  185. /* at least one and at most two non-option args */
  186. /* disable interactive passwd for system accounts */
  187. "\0" "-1:?2:SD",
  188. adduser_longopts,
  189. &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell,
  190. &usegroup, &uid, &skel
  191. );
  192. if (opts & OPT_UID)
  193. pw.pw_uid = xatou_range(uid, 0, CONFIG_LAST_ID);
  194. argv += optind;
  195. pw.pw_name = argv[0];
  196. if (!opts && argv[1]) {
  197. /* if called with two non-option arguments, adduser
  198. * will add an existing user to an existing group.
  199. */
  200. return addgroup_wrapper(&pw, argv[1]);
  201. }
  202. /* fill in the passwd struct */
  203. die_if_bad_username(pw.pw_name);
  204. if (!pw.pw_dir) {
  205. /* create string for $HOME if not specified already */
  206. pw.pw_dir = xasprintf("/home/%s", argv[0]);
  207. }
  208. pw.pw_passwd = (char *)"x";
  209. if (opts & OPT_SYSTEM_ACCOUNT) {
  210. if (!usegroup) {
  211. usegroup = "nogroup";
  212. }
  213. if (!(opts & OPT_SHELL)) {
  214. pw.pw_shell = (char *) "/bin/false";
  215. }
  216. }
  217. pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */
  218. /* make sure everything is kosher and setup uid && maybe gid */
  219. passwd_study(&pw);
  220. p = xasprintf("x:%u:%u:%s:%s:%s",
  221. (unsigned) pw.pw_uid, (unsigned) pw.pw_gid,
  222. pw.pw_gecos, pw.pw_dir, pw.pw_shell);
  223. if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) {
  224. return EXIT_FAILURE;
  225. }
  226. if (ENABLE_FEATURE_CLEAN_UP)
  227. free(p);
  228. #if ENABLE_FEATURE_SHADOWPASSWDS
  229. /* /etc/shadow fields:
  230. * 1. username
  231. * 2. encrypted password
  232. * 3. last password change (unix date (unix time/24*60*60))
  233. * 4. minimum days required between password changes
  234. * 5. maximum days password is valid
  235. * 6. days before password is to expire that user is warned
  236. * 7. days after password expires that account is disabled
  237. * 8. unix date when login expires (i.e. when it may no longer be used)
  238. */
  239. /* fields: 2 3 4 5 6 78 */
  240. p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL)) / (24*60*60));
  241. /* ignore errors: if file is missing we suppose admin doesn't want it */
  242. update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL);
  243. if (ENABLE_FEATURE_CLEAN_UP)
  244. free(p);
  245. #endif
  246. /* add to group */
  247. addgroup_wrapper(&pw, usegroup);
  248. /* clear the umask for this process so it doesn't
  249. * screw up the permissions on the mkdir and chown. */
  250. umask(0);
  251. if (!(opts & OPT_DONT_MAKE_HOME)) {
  252. /* set the owner and group so it is owned by the new user,
  253. * then fix up the permissions to 2755. Can't do it before
  254. * since chown will clear the setgid bit */
  255. int mkdir_err = mkdir(pw.pw_dir, 0755);
  256. if (mkdir_err == 0) {
  257. /* New home. Copy /etc/skel to it */
  258. const char *args[] = {
  259. "chown",
  260. "-R",
  261. xasprintf("%u:%u", (int)pw.pw_uid, (int)pw.pw_gid),
  262. pw.pw_dir,
  263. NULL
  264. };
  265. /* Be silent on any errors (like: no /etc/skel) */
  266. if (!(opts & OPT_SKEL))
  267. logmode = LOGMODE_NONE;
  268. copy_file(skel, pw.pw_dir, FILEUTILS_RECUR);
  269. logmode = LOGMODE_STDIO;
  270. chown_main(4, (char**)args);
  271. }
  272. if ((mkdir_err != 0 && errno != EEXIST)
  273. || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid) != 0
  274. || chmod(pw.pw_dir, 02755) != 0 /* set setgid bit on homedir */
  275. ) {
  276. bb_simple_perror_msg(pw.pw_dir);
  277. }
  278. }
  279. if (!(opts & OPT_DONT_SET_PASS)) {
  280. /* interactively set passwd */
  281. passwd_wrapper(pw.pw_name);
  282. }
  283. return EXIT_SUCCESS;
  284. }