adduser.c 10 KB

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