blob: 8101b20b4febfddad64653cda792e6a1433e701b [file] [log] [blame]
Robert Griebl1fca5582002-06-04 20:45:46 +00001/* 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 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00008 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Robert Griebl1fca5582002-06-04 20:45:46 +00009 */
10
Robert Griebl1fca5582002-06-04 20:45:46 +000011#include "busybox.h"
Robert Griebl1fca5582002-06-04 20:45:46 +000012
Rob Landley9a2dd512006-04-04 19:19:53 +000013#define DONT_SET_PASS (1 << 4)
14#define DONT_MAKE_HOME (1 << 6)
Robert Griebl1fca5582002-06-04 20:45:46 +000015
16
Robert Griebl1fca5582002-06-04 20:45:46 +000017/* remix */
18/* EDR recoded such that the uid may be passed in *p */
19static int passwd_study(const char *filename, struct passwd *p)
20{
21 struct passwd *pw;
22 FILE *passwd;
23
24 const int min = 500;
25 const int max = 65000;
26
Rob Landleyd921b2e2006-08-03 15:41:12 +000027 passwd = xfopen(filename, "r");
Robert Griebl1fca5582002-06-04 20:45:46 +000028
29 /* EDR if uid is out of bounds, set to min */
30 if ((p->pw_uid > max) || (p->pw_uid < min))
31 p->pw_uid = min;
32
Eric Andersenc7bda1c2004-03-15 08:29:22 +000033 /* stuff to do:
Robert Griebl1fca5582002-06-04 20:45:46 +000034 * make sure login isn't taken;
35 * find free uid and gid;
36 */
37 while ((pw = fgetpwent(passwd))) {
38 if (strcmp(pw->pw_name, p->pw_name) == 0) {
39 /* return 0; */
40 return 1;
41 }
42 if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max)
43 && (pw->pw_uid >= min)) {
44 p->pw_uid = pw->pw_uid + 1;
45 }
46 }
47
Eric Andersenf0f754a2003-06-21 20:03:07 +000048 if (p->pw_gid == 0) {
49 /* EDR check for an already existing gid */
50 while (getgrgid(p->pw_uid) != NULL)
51 p->pw_uid++;
Robert Griebl1fca5582002-06-04 20:45:46 +000052
Eric Andersenf0f754a2003-06-21 20:03:07 +000053 /* EDR also check for an existing group definition */
54 if (getgrnam(p->pw_name) != NULL)
55 return 3;
56
57 /* EDR create new gid always = uid */
58 p->pw_gid = p->pw_uid;
59 }
Robert Griebl1fca5582002-06-04 20:45:46 +000060
61 /* EDR bounds check */
62 if ((p->pw_uid > max) || (p->pw_uid < min))
63 return 2;
64
Robert Griebl1fca5582002-06-04 20:45:46 +000065 /* return 1; */
66 return 0;
67}
68
Rob Landley9a2dd512006-04-04 19:19:53 +000069static void addgroup_wrapper(struct passwd *p)
Robert Griebl1fca5582002-06-04 20:45:46 +000070{
Eric Andersenc38678d2002-09-16 06:22:25 +000071 char *cmd;
Robert Griebl1fca5582002-06-04 20:45:46 +000072
Rob Landleyd921b2e2006-08-03 15:41:12 +000073 cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name);
Robert Griebl2c0d0f02002-07-16 23:50:05 +000074 system(cmd);
75 free(cmd);
Robert Griebl1fca5582002-06-04 20:45:46 +000076}
77
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000078static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN;
Eric Andersenc38678d2002-09-16 06:22:25 +000079
Robert Griebl1fca5582002-06-04 20:45:46 +000080static void passwd_wrapper(const char *login)
81{
82 static const char prog[] = "passwd";
83 execlp(prog, prog, login, NULL);
Manuel Novoa III cad53642003-03-19 09:13:01 +000084 bb_error_msg_and_die("Failed to execute '%s', you must set the password for '%s' manually", prog, login);
Robert Griebl1fca5582002-06-04 20:45:46 +000085}
86
Robert Griebl1fca5582002-06-04 20:45:46 +000087/* putpwent(3) remix */
Rob Landley9a2dd512006-04-04 19:19:53 +000088static int adduser(struct passwd *p, unsigned long flags)
Robert Griebl1fca5582002-06-04 20:45:46 +000089{
Rob Landley9a2dd512006-04-04 19:19:53 +000090 FILE *file;
Rob Landley62103752006-07-16 18:58:18 +000091 int addgroup = !p->pw_gid;
Robert Griebl1fca5582002-06-04 20:45:46 +000092
93 /* make sure everything is kosher and setup uid && gid */
Rob Landleyd921b2e2006-08-03 15:41:12 +000094 file = xfopen(bb_path_passwd_file, "a");
Rob Landley9a2dd512006-04-04 19:19:53 +000095 fseek(file, 0, SEEK_END);
Robert Griebl1fca5582002-06-04 20:45:46 +000096
Rob Landley9a2dd512006-04-04 19:19:53 +000097 switch (passwd_study(bb_path_passwd_file, p)) {
98 case 1:
99 bb_error_msg_and_die("%s: login already in use", p->pw_name);
100 case 2:
101 bb_error_msg_and_die("illegal uid or no uids left");
102 case 3:
103 bb_error_msg_and_die("%s: group name already in use", p->pw_name);
104 }
Robert Griebl1fca5582002-06-04 20:45:46 +0000105
106 /* add to passwd */
Rob Landley9a2dd512006-04-04 19:19:53 +0000107 if (putpwent(p, file) == -1) {
108 bb_perror_nomsg_and_die();
Robert Griebl1fca5582002-06-04 20:45:46 +0000109 }
Rob Landley9a2dd512006-04-04 19:19:53 +0000110 fclose(file);
Robert Griebl1fca5582002-06-04 20:45:46 +0000111
Rob Landley9a2dd512006-04-04 19:19:53 +0000112#if ENABLE_FEATURE_SHADOWPASSWDS
Robert Griebl1fca5582002-06-04 20:45:46 +0000113 /* add to shadow if necessary */
Rob Landleyd921b2e2006-08-03 15:41:12 +0000114 file = xfopen(bb_path_shadow_file, "a");
Rob Landley9a2dd512006-04-04 19:19:53 +0000115 fseek(file, 0, SEEK_END);
116 fprintf(file, "%s:!:%ld:%d:%d:%d:::\n",
117 p->pw_name, /* username */
118 time(NULL) / 86400, /* sp->sp_lstchg */
119 0, /* sp->sp_min */
120 99999, /* sp->sp_max */
121 7); /* sp->sp_warn */
122 fclose(file);
Robert Griebl1fca5582002-06-04 20:45:46 +0000123#endif
124
Rob Landley9a2dd512006-04-04 19:19:53 +0000125 /* add to group */
126 /* addgroup should be responsible for dealing w/ gshadow */
127 /* if using a pre-existing group, don't create one */
Rob Landley62103752006-07-16 18:58:18 +0000128 if (addgroup) addgroup_wrapper(p);
129
Robert Griebl1fca5582002-06-04 20:45:46 +0000130 /* Clear the umask for this process so it doesn't
131 * * screw up the permissions on the mkdir and chown. */
132 umask(0);
Rob Landley9a2dd512006-04-04 19:19:53 +0000133 if (!(flags & DONT_MAKE_HOME)) {
134 /* Set the owner and group so it is owned by the new user,
135 then fix up the permissions to 2755. Can't do it before
136 since chown will clear the setgid bit */
137 if (mkdir(p->pw_dir, 0755)
138 || chown(p->pw_dir, p->pw_uid, p->pw_gid)
139 || chmod(p->pw_dir, 02755)) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000140 bb_perror_msg("%s", p->pw_dir);
141 }
Robert Griebl1fca5582002-06-04 20:45:46 +0000142 }
Eric Andersenf0f754a2003-06-21 20:03:07 +0000143
Rob Landley9a2dd512006-04-04 19:19:53 +0000144 if (!(flags & DONT_SET_PASS)) {
Eric Andersenf0f754a2003-06-21 20:03:07 +0000145 /* interactively set passwd */
146 passwd_wrapper(p->pw_name);
Robert Griebl1fca5582002-06-04 20:45:46 +0000147 }
Eric Andersenf0f754a2003-06-21 20:03:07 +0000148
149 return 0;
Robert Griebl1fca5582002-06-04 20:45:46 +0000150}
151
Robert Griebl1fca5582002-06-04 20:45:46 +0000152/*
153 * adduser will take a login_name as its first parameter.
154 *
155 * home
156 * shell
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000157 * gecos
Robert Griebl1fca5582002-06-04 20:45:46 +0000158 *
159 * can be customized via command-line parameters.
160 * ________________________________________________________________________ */
161int adduser_main(int argc, char **argv)
162{
Eric Andersenf0f754a2003-06-21 20:03:07 +0000163 struct passwd pw;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000164 const char *usegroup = NULL;
Rob Landley9a2dd512006-04-04 19:19:53 +0000165 unsigned long flags;
Robert Griebl1fca5582002-06-04 20:45:46 +0000166
Rob Landley9a2dd512006-04-04 19:19:53 +0000167 pw.pw_gecos = "Linux User,,,";
168 pw.pw_shell = (char *)DEFAULT_SHELL;
169 pw.pw_dir = NULL;
Eric Andersenf0f754a2003-06-21 20:03:07 +0000170
Rob Landley9a2dd512006-04-04 19:19:53 +0000171 /* check for min, max and missing args and exit on error */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000172 opt_complementary = "-1:?1:?";
173 flags = getopt32(argc, argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
Robert Griebl1fca5582002-06-04 20:45:46 +0000174
175 /* got root? */
Rob Landley9a2dd512006-04-04 19:19:53 +0000176 if(geteuid()) {
177 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000178 }
Robert Griebl1fca5582002-06-04 20:45:46 +0000179
180 /* create string for $HOME if not specified already */
Rob Landley9a2dd512006-04-04 19:19:53 +0000181 if (!pw.pw_dir) {
182 snprintf(bb_common_bufsiz1, BUFSIZ, "/home/%s", argv[optind]);
183 pw.pw_dir = &bb_common_bufsiz1[0];
Robert Griebl1fca5582002-06-04 20:45:46 +0000184 }
Robert Griebl1fca5582002-06-04 20:45:46 +0000185
186 /* create a passwd struct */
Rob Landley9a2dd512006-04-04 19:19:53 +0000187 pw.pw_name = argv[optind];
188 pw.pw_passwd = "x";
Robert Griebl1fca5582002-06-04 20:45:46 +0000189 pw.pw_uid = 0;
Rob Landley9a2dd512006-04-04 19:19:53 +0000190 pw.pw_gid = (usegroup) ? bb_xgetgrnam(usegroup) : 0; /* exits on failure */
Eric Andersenf0f754a2003-06-21 20:03:07 +0000191
Robert Griebl1fca5582002-06-04 20:45:46 +0000192 /* grand finale */
Rob Landley9a2dd512006-04-04 19:19:53 +0000193 return adduser(&pw, flags);
Robert Griebl1fca5582002-06-04 20:45:46 +0000194}