source: MondoRescue/branches/3.3/mindi-busybox/loginutils/adduser.c@ 3622

Last change on this file since 3622 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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