aboutsummaryrefslogtreecommitdiff
path: root/adduser.c
diff options
context:
space:
mode:
authorandersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277>2001-08-21 16:18:59 +0000
committerandersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277>2001-08-21 16:18:59 +0000
commit6e33165982a8ba691371185cb898643ec9e78ba6 (patch)
tree9b048f58d1c11600df69323327124425a2f78f63 /adduser.c
parentf55eed1a6ff910575e85e3bfa9cbae62039f8901 (diff)
downloadbusybox-w32-6e33165982a8ba691371185cb898643ec9e78ba6.tar.gz
busybox-w32-6e33165982a8ba691371185cb898643ec9e78ba6.tar.bz2
busybox-w32-6e33165982a8ba691371185cb898643ec9e78ba6.zip
Initial merge of all tinylogin applets that do not require crypt.
There is some optimization that can be done to better use libbb in these applets. There is also redundancy between stty and getty which could be eliminated. -Erik git-svn-id: svn://busybox.net/trunk/busybox@3318 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'adduser.c')
-rw-r--r--adduser.c366
1 files changed, 366 insertions, 0 deletions
diff --git a/adduser.c b/adduser.c
new file mode 100644
index 000000000..6bd2c253e
--- /dev/null
+++ b/adduser.c
@@ -0,0 +1,366 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * adduser - add users to /etc/passwd and /etc/shadow
4 *
5 *
6 * Copyright (C) 1999 by Lineo, inc.
7 * Written by John Beppu <beppu@lineo.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <errno.h>
26#include <fcntl.h>
27#include <stdarg.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <shadow.h>
32#include <time.h>
33#include <unistd.h>
34#include <sys/param.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37#include "busybox.h"
38#include "pwd_grp/pwd.h"
39#include "pwd_grp/grp.h"
40
41#define PASSWD_FILE "/etc/passwd"
42#define SHADOW_FILE "/etc/gshadow"
43
44#if 0
45# define PASSWD_FILE "passwd"
46# define SHADOW_FILE "shadow"
47#endif
48
49/* structs __________________________ */
50
51typedef struct {
52 uid_t u;
53 gid_t g;
54} Id;
55
56/* data _____________________________ */
57
58/* defaults : should this be in an external file? */
59static char *default_passwd = "x";
60static char *default_gecos = "Embedix User,,,";
61static char *default_home_prefix = "/home";
62static char *default_shell = "/bin/sh";
63
64/* shadow in use? */
65static int shadow_enabled = 0;
66
67/* I was doing this all over the place */
68static FILE *fopen_wrapper(const char *filename, const char *mode)
69{
70 FILE *f;
71
72 f = fopen(filename, mode);
73 if (f == NULL) {
74 fprintf(stderr, "adduser: %s: %s\n", filename, strerror(errno));
75 }
76 return f;
77}
78
79/* remix */
80/* EDR recoded such that the uid may be passed in *p */
81static int passwd_study(const char *filename, struct passwd *p)
82{
83 struct passwd *pw;
84 FILE *passwd;
85
86 const int min = 500;
87 const int max = 65000;
88
89 passwd = fopen_wrapper(filename, "r");
90 if (!passwd)
91 return 4;
92
93 /* EDR if uid is out of bounds, set to min */
94 if ((p->pw_uid > max) || (p->pw_uid < min))
95 p->pw_uid = min;
96
97 /* stuff to do:
98 * make sure login isn't taken;
99 * find free uid and gid;
100 */
101 while ((pw = fgetpwent(passwd))) {
102 if (strcmp(pw->pw_name, p->pw_name) == 0) {
103 /* return 0; */
104 return 1;
105 }
106 if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max)
107 && (pw->pw_uid >= min)) {
108 p->pw_uid = pw->pw_uid + 1;
109 }
110 }
111
112 /* EDR check for an already existing gid */
113 while (getgrgid(p->pw_uid) != NULL)
114 p->pw_uid++;
115
116 /* EDR also check for an existing group definition */
117 if (getgrnam(p->pw_name) != NULL)
118 return 3;
119
120 /* EDR bounds check */
121 if ((p->pw_uid > max) || (p->pw_uid < min))
122 return 2;
123
124 /* EDR create new gid always = uid */
125 p->pw_gid = p->pw_uid;
126
127 /* return 1; */
128 return 0;
129}
130
131static void addgroup_wrapper(const char *login, gid_t gid)
132{
133 int argc = 4;
134 char *argv[] = { "addgroup", "-g", NULL, NULL };
135 char group_id[8];
136 char group_name[32];
137
138 strncpy(group_name, login, 32);
139 argv[3] = group_name;
140 sprintf(group_id, "%d", gid);
141 argv[2] = group_id;
142 addgroup_main(argc, argv);
143}
144
145static void passwd_wrapper(const char *login)
146{
147 char *prog = "passwd";
148 execlp(prog, prog, login, NULL);
149 error_msg_and_die("Failed to execute 'passwd', you must set the password for '%s' manually\n", login);
150}
151
152/*
153 * pwd_to_spwd - create entries for new spwd structure
154 *
155 * pwd_to_spwd() creates a new (struct spwd) containing the
156 * information in the pointed-to (struct passwd).
157 */
158#define DAY (24L*3600L)
159#define WEEK (7*DAY)
160#define SCALE DAY
161static struct spwd *pwd_to_spwd(const struct passwd *pw)
162{
163 static struct spwd sp;
164
165 /*
166 * Nice, easy parts first. The name and passwd map directly
167 * from the old password structure to the new one.
168 */
169 sp.sp_namp = pw->pw_name;
170 sp.sp_pwdp = pw->pw_passwd;
171
172 /*
173 * Defaults used if there is no pw_age information.
174 */
175 sp.sp_min = 0;
176 sp.sp_max = (10000L * DAY) / SCALE;
177 sp.sp_lstchg = time((time_t *) 0) / SCALE;
178
179 /*
180 * These fields have no corresponding information in the password
181 * file. They are set to uninitialized values.
182 */
183 sp.sp_warn = -1;
184 sp.sp_expire = -1;
185 sp.sp_inact = -1;
186 sp.sp_flag = -1;
187
188 return &sp;
189}
190
191/* putpwent(3) remix */
192static int adduser(const char *filename, struct passwd *p)
193{
194 FILE *passwd;
195 int r;
196 FILE *shadow;
197 struct spwd *sp;
198
199 /* make sure everything is kosher and setup uid && gid */
200 passwd = fopen_wrapper(filename, "a");
201 if (passwd == NULL) {
202 /* return -1; */
203 return 1;
204 }
205 fseek(passwd, 0, SEEK_END);
206
207 /* if (passwd_study(filename, p) == 0) { */
208 r = passwd_study(filename, p);
209 if (r) {
210 if (r == 1)
211 error_msg("%s: login already in use\n", p->pw_name);
212 else if (r == 2)
213 error_msg("illegal uid or no uids left\n");
214 else if (r == 3)
215 error_msg("group name %s already in use\n", p->pw_name);
216 else
217 error_msg("generic error.\n");
218 /* return -1; */
219 return 1;
220 }
221
222 /* add to passwd */
223 if (putpwent(p, passwd) == -1) {
224 /* return -1; */
225 return 1;
226 }
227 fclose(passwd);
228
229 /* add to shadow if necessary */
230 if (shadow_enabled) {
231 shadow = fopen_wrapper(SHADOW_FILE, "a");
232 if (shadow == NULL) {
233 /* return -1; */
234 return 1;
235 }
236 fseek(shadow, 0, SEEK_END);
237 sp = pwd_to_spwd(p);
238 sp->sp_max = 99999; /* debianish */
239 sp->sp_warn = 7;
240 fprintf(shadow, "%s:!:%ld:%ld:%ld:%ld:::\n",
241 sp->sp_namp, sp->sp_lstchg, sp->sp_min, sp->sp_max,
242 sp->sp_warn);
243 fclose(shadow);
244 }
245
246 /* add to group */
247 /* addgroup should be responsible for dealing w/ gshadow */
248 addgroup_wrapper(p->pw_name, p->pw_gid);
249
250 /* Clear the umask for this process so it doesn't
251 * * screw up the permissions on the mkdir and chown. */
252 umask(0);
253
254 /* mkdir */
255 if (mkdir(p->pw_dir, 0755)) {
256 perror_msg("%s", p->pw_dir);
257 }
258 /* Set the owner and group so it is owned by the new user. */
259 if (chown(p->pw_dir, p->pw_uid, p->pw_gid)) {
260 perror_msg("%s", p->pw_dir);
261 }
262 /* Now fix up the permissions to 2755. Can't do it before now
263 * since chown will clear the setgid bit */
264 if (chmod(p->pw_dir, 02755)) {
265 perror_msg("%s", p->pw_dir);
266 }
267 /* interactively set passwd */
268 passwd_wrapper(p->pw_name);
269
270 return 0;
271}
272
273
274/* return current uid (root is always uid == 0, right?) */
275static uid_t i_am_not_root()
276{
277 return geteuid();
278}
279
280/*
281 * adduser will take a login_name as its first parameter.
282 *
283 * home
284 * shell
285 * gecos
286 *
287 * can be customized via command-line parameters.
288 * ________________________________________________________________________ */
289int adduser_main(int argc, char **argv)
290{
291 int i;
292 char opt;
293 char *login;
294 char *gecos;
295 char *home = NULL;
296 char *shell;
297 char path[MAXPATHLEN];
298
299 struct passwd pw;
300
301 /* init */
302 if (argc < 2) {
303 show_usage();
304 }
305 gecos = default_gecos;
306 shell = default_shell;
307
308 /* get args */
309 for (i = 1; i < argc; i++) {
310 if (argv[i][0] == '-') {
311 opt = argv[i][1];
312 switch (opt) {
313 case 'h':
314 home = argv[++i];
315 break;
316 case 'g':
317 gecos = argv[++i];
318 break;
319 case 's':
320 shell = argv[++i];
321 break;
322 default:
323 error_msg("invalid option -- %c\n", opt);
324 break;
325 }
326 } else {
327 break;
328 }
329 }
330
331 /* got root? */
332 if (i_am_not_root()) {
333 error_msg_and_die( "Only root may add a user or group to the system.\n");
334 }
335
336 /* get login */
337 if (i >= argc) {
338 error_msg_and_die( "adduser: no user specified\n");
339 }
340 login = argv[i];
341
342 /* create string for $HOME if not specified already */
343 if (!home) {
344 snprintf(path, MAXPATHLEN, "%s/%s", default_home_prefix, login);
345 path[MAXPATHLEN - 1] = 0;
346 home = path;
347 }
348 /* is /etc/shadow in use? */
349 shadow_enabled = (0 == access(SHADOW_FILE, F_OK));
350
351 /* create a passwd struct */
352 pw.pw_name = login;
353 pw.pw_passwd = default_passwd;
354 pw.pw_uid = 0;
355 pw.pw_gid = 0;
356 pw.pw_gecos = gecos;
357 pw.pw_dir = home;
358 pw.pw_shell = shell;
359
360 /* grand finale */
361 i = adduser(PASSWD_FILE, &pw);
362
363 return (i);
364}
365
366/* $Id: adduser.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */