source: branches/stable/mindi-busybox/loginutils/adduser.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 4.9 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 the GPL v2 or later, see the file LICENSE in this tarball.
9 */
10
11#include <stdio.h>
12#include <sys/types.h>
13#include <string.h>
14#include <unistd.h>
15#include <time.h>
16#include <getopt.h>
17#include <sys/stat.h>
18
19#include "busybox.h"
20
21#define DONT_SET_PASS           (1 << 4)
22#define DONT_MAKE_HOME          (1 << 6)
23
24
25/* remix */
26/* EDR recoded such that the uid may be passed in *p */
27static int passwd_study(const char *filename, struct passwd *p)
28{
29    struct passwd *pw;
30    FILE *passwd;
31
32    const int min = 500;
33    const int max = 65000;
34
35    passwd = bb_xfopen(filename, "r");
36
37    /* EDR if uid is out of bounds, set to min */
38    if ((p->pw_uid > max) || (p->pw_uid < min))
39        p->pw_uid = min;
40
41    /* stuff to do:
42     * make sure login isn't taken;
43     * find free uid and gid;
44     */
45    while ((pw = fgetpwent(passwd))) {
46        if (strcmp(pw->pw_name, p->pw_name) == 0) {
47            /* return 0; */
48            return 1;
49        }
50        if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max)
51            && (pw->pw_uid >= min)) {
52            p->pw_uid = pw->pw_uid + 1;
53        }
54    }
55
56    if (p->pw_gid == 0) {
57        /* EDR check for an already existing gid */
58        while (getgrgid(p->pw_uid) != NULL)
59            p->pw_uid++;
60
61        /* EDR also check for an existing group definition */
62        if (getgrnam(p->pw_name) != NULL)
63            return 3;
64
65        /* EDR create new gid always = uid */
66        p->pw_gid = p->pw_uid;
67    }
68
69    /* EDR bounds check */
70    if ((p->pw_uid > max) || (p->pw_uid < min))
71        return 2;
72
73    /* return 1; */
74    return 0;
75}
76
77static void addgroup_wrapper(struct passwd *p)
78{
79    char *cmd;
80
81    cmd = bb_xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name);
82    system(cmd);
83    free(cmd);
84}
85
86static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN;
87
88static void passwd_wrapper(const char *login)
89{
90    static const char prog[] = "passwd";
91    execlp(prog, prog, login, NULL);
92    bb_error_msg_and_die("Failed to execute '%s', you must set the password for '%s' manually", prog, login);
93}
94
95/* putpwent(3) remix */
96static int adduser(struct passwd *p, unsigned long flags)
97{
98    FILE *file;
99    int addgroup = !p->pw_gid;
100
101    /* make sure everything is kosher and setup uid && gid */
102    file = bb_xfopen(bb_path_passwd_file, "a");
103    fseek(file, 0, SEEK_END);
104
105    switch (passwd_study(bb_path_passwd_file, p)) {
106        case 1:
107            bb_error_msg_and_die("%s: login already in use", p->pw_name);
108        case 2:
109            bb_error_msg_and_die("illegal uid or no uids left");
110        case 3:
111            bb_error_msg_and_die("%s: group name already in use", p->pw_name);
112    }
113
114    /* add to passwd */
115    if (putpwent(p, file) == -1) {
116        bb_perror_nomsg_and_die();
117    }
118    fclose(file);
119
120#if ENABLE_FEATURE_SHADOWPASSWDS
121    /* add to shadow if necessary */
122    file = bb_xfopen(bb_path_shadow_file, "a");
123    fseek(file, 0, SEEK_END);
124    fprintf(file, "%s:!:%ld:%d:%d:%d:::\n",
125                    p->pw_name,             /* username */
126                    time(NULL) / 86400,     /* sp->sp_lstchg */ 
127                    0,                      /* sp->sp_min */
128                    99999,                  /* sp->sp_max */
129                    7);                     /* sp->sp_warn */
130    fclose(file);
131#endif
132
133    /* add to group */
134    /* addgroup should be responsible for dealing w/ gshadow */
135    /* if using a pre-existing group, don't create one */
136    if (addgroup) addgroup_wrapper(p);
137
138    /* Clear the umask for this process so it doesn't
139     * * screw up the permissions on the mkdir and chown. */
140    umask(0);
141    if (!(flags & DONT_MAKE_HOME)) {
142        /* Set the owner and group so it is owned by the new user,
143           then fix up the permissions to 2755. Can't do it before
144           since chown will clear the setgid bit */
145        if (mkdir(p->pw_dir, 0755)
146        || chown(p->pw_dir, p->pw_uid, p->pw_gid)
147        || chmod(p->pw_dir, 02755)) {
148            bb_perror_msg("%s", p->pw_dir);
149        }
150    }
151
152    if (!(flags & DONT_SET_PASS)) {
153        /* interactively set passwd */
154        passwd_wrapper(p->pw_name);
155    }
156
157    return 0;
158}
159
160/*
161 * adduser will take a login_name as its first parameter.
162 *
163 * home
164 * shell
165 * gecos
166 *
167 * can be customized via command-line parameters.
168 * ________________________________________________________________________ */
169int adduser_main(int argc, char **argv)
170{
171    struct passwd pw;
172    const char *usegroup = NULL;
173    unsigned long flags;
174
175    pw.pw_gecos = "Linux User,,,";
176    pw.pw_shell = (char *)DEFAULT_SHELL;
177    pw.pw_dir = NULL;
178
179    /* check for min, max and missing args and exit on error */
180    bb_opt_complementally = "-1:?1:?";
181    flags = bb_getopt_ulflags(argc, argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
182
183    /* got root? */
184    if(geteuid()) {
185        bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
186    }
187
188    /* create string for $HOME if not specified already */
189    if (!pw.pw_dir) {
190        snprintf(bb_common_bufsiz1, BUFSIZ, "/home/%s", argv[optind]);
191        pw.pw_dir =  &bb_common_bufsiz1[0];
192    }
193
194    /* create a passwd struct */
195    pw.pw_name = argv[optind];
196    pw.pw_passwd = "x";
197    pw.pw_uid = 0;
198    pw.pw_gid = (usegroup) ? bb_xgetgrnam(usegroup) : 0; /* exits on failure */
199
200    /* grand finale */
201    return adduser(&pw, flags);
202}
Note: See TracBrowser for help on using the repository browser.