1 /* vi: set sw=4 ts=4: */
3 * adduser - add users to /etc/passwd and /etc/shadow
5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
13 #define OPT_DONT_SET_PASS (1 << 4)
14 #define OPT_SYSTEM_ACCOUNT (1 << 5)
15 #define OPT_DONT_MAKE_HOME (1 << 6)
19 /* recoded such that the uid may be passed in *p */
20 static void passwd_study(struct passwd *p)
24 if (getpwnam(p->pw_name))
25 bb_error_msg_and_die("login '%s' is in use", p->pw_name);
27 if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
35 /* check for a free uid (and maybe gid) */
36 while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) {
39 bb_error_msg_and_die("no free uids left");
42 if (p->pw_gid == (gid_t)-1) {
43 p->pw_gid = p->pw_uid; /* new gid = uid */
44 if (getgrnam(p->pw_name))
45 bb_error_msg_and_die("group name '%s' is in use", p->pw_name);
49 static void addgroup_wrapper(struct passwd *p)
53 cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);
58 static void passwd_wrapper(const char *login) NORETURN;
60 static void passwd_wrapper(const char *login)
62 static const char prog[] ALIGN1 = "passwd";
64 BB_EXECLP(prog, prog, login, NULL);
65 bb_error_msg_and_die("cannot execute %s, you must set password manually", prog);
68 #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
69 static const char adduser_longopts[] ALIGN1 =
70 "home\0" Required_argument "h"
71 "gecos\0" Required_argument "g"
72 "shell\0" Required_argument "s"
73 "ingroup\0" Required_argument "G"
74 "disabled-password\0" No_argument "D"
75 "empty-password\0" No_argument "D"
76 "system\0" No_argument "S"
77 "no-create-home\0" No_argument "H"
82 * adduser will take a login_name as its first parameter.
84 * can be customized via command-line parameters.
86 int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
87 int adduser_main(int argc UNUSED_PARAM, char **argv)
90 const char *usegroup = NULL;
92 #if ENABLE_FEATURE_SHADOWPASSWDS
96 #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
97 applet_long_options = adduser_longopts;
102 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
105 pw.pw_gecos = (char *)"Linux User,,,";
106 pw.pw_shell = (char *)DEFAULT_SHELL;
109 /* exactly one non-option arg */
110 opt_complementary = "=1";
111 getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
114 /* fill in the passwd struct */
115 pw.pw_name = argv[0];
116 die_if_bad_username(pw.pw_name);
118 /* create string for $HOME if not specified already */
119 pw.pw_dir = xasprintf("/home/%s", argv[0]);
121 pw.pw_passwd = (char *)"x";
122 pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */
124 /* make sure everything is kosher and setup uid && maybe gid */
128 file = xfopen(bb_path_passwd_file, "a");
129 //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */
130 if (putpwent(&pw, file) != 0) {
131 bb_perror_nomsg_and_die();
133 /* do fclose even if !ENABLE_FEATURE_CLEAN_UP.
134 * We will exec passwd, files must be flushed & closed before that! */
137 #if ENABLE_FEATURE_SHADOWPASSWDS
138 /* add to shadow if necessary */
139 /* fopen(..., "a"); would create shadow file, which is wrong.
140 * If shadow file doesn't exist, admin probably does not want it */
141 fd = open_or_warn(bb_path_shadow_file, O_WRONLY | O_APPEND);
143 char *s = xasprintf("%s:!:%u:0:99999:7:::\n",
144 pw.pw_name, /* username */
145 (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */
146 /*0,*/ /* sp->sp_min */
147 /*99999,*/ /* sp->sp_max */
148 /*7*/ /* sp->sp_warn */
156 /* addgroup should be responsible for dealing w/ gshadow */
157 /* if using a pre-existing group, don't create one */
159 addgroup_wrapper(&pw);
161 /* Clear the umask for this process so it doesn't
162 * screw up the permissions on the mkdir and chown. */
164 if (!(option_mask32 & OPT_DONT_MAKE_HOME)) {
165 /* Set the owner and group so it is owned by the new user,
166 then fix up the permissions to 2755. Can't do it before
167 since chown will clear the setgid bit */
168 if (mkdir(pw.pw_dir, 0755)
169 || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid)
170 || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */
172 bb_simple_perror_msg(pw.pw_dir);
176 if (!(option_mask32 & OPT_DONT_SET_PASS)) {
177 /* interactively set passwd */
178 passwd_wrapper(pw.pw_name);