adduser: trivial code movement
[oweals/busybox.git] / loginutils / adduser.c
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 "busybox.h"
12
13 #define DONT_SET_PASS                   (1 << 4)
14 #define DONT_MAKE_HOME                  (1 << 6)
15
16
17 /* remix */
18 /* EDR recoded such that the uid may be passed in *p */
19 static 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
27         passwd = xfopen(filename, "r");
28
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
33         /* stuff to do:
34          * 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
48         if (p->pw_gid == 0) {
49                 /* EDR check for an already existing gid */
50                 while (getgrgid(p->pw_uid) != NULL)
51                         p->pw_uid++;
52
53                 /* 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         }
60
61         /* EDR bounds check */
62         if ((p->pw_uid > max) || (p->pw_uid < min))
63                 return 2;
64
65         /* return 1; */
66         return 0;
67 }
68
69 static void addgroup_wrapper(struct passwd *p)
70 {
71         char *cmd;
72
73         cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name);
74         system(cmd);
75         free(cmd);
76 }
77
78 static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN;
79
80 static void passwd_wrapper(const char *login)
81 {
82         static const char prog[] = "passwd";
83         execlp(prog, prog, login, NULL);
84         bb_error_msg_and_die("failed to execute '%s', you must set the password for '%s' manually", prog, login);
85 }
86
87 /* putpwent(3) remix */
88 static int adduser(struct passwd *p, unsigned long flags)
89 {
90         FILE *file;
91         int addgroup = !p->pw_gid;
92
93         /* make sure everything is kosher and setup uid && gid */
94         file = xfopen(bb_path_passwd_file, "a");
95         fseek(file, 0, SEEK_END);
96
97         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         }
105
106         /* add to passwd */
107         if (putpwent(p, file) == -1) {
108                 bb_perror_nomsg_and_die();
109         }
110         fclose(file);
111
112 #if ENABLE_FEATURE_SHADOWPASSWDS
113         /* add to shadow if necessary */
114         file = xfopen(bb_path_shadow_file, "a");
115         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);
123 #endif
124
125         /* add to group */
126         /* addgroup should be responsible for dealing w/ gshadow */
127         /* if using a pre-existing group, don't create one */
128         if (addgroup) addgroup_wrapper(p);
129
130         /* Clear the umask for this process so it doesn't
131          * * screw up the permissions on the mkdir and chown. */
132         umask(0);
133         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)) {
140                         bb_perror_msg("%s", p->pw_dir);
141                 }
142         }
143
144         if (!(flags & DONT_SET_PASS)) {
145                 /* interactively set passwd */
146                 passwd_wrapper(p->pw_name);
147         }
148
149         return 0;
150 }
151
152 /*
153  * adduser will take a login_name as its first parameter.
154  *
155  * home
156  * shell
157  * gecos
158  *
159  * can be customized via command-line parameters.
160  * ________________________________________________________________________ */
161 int adduser_main(int argc, char **argv)
162 {
163         struct passwd pw;
164         const char *usegroup = NULL;
165         unsigned long flags;
166
167         /* got root? */
168         if (geteuid()) {
169                 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
170         }
171
172         pw.pw_gecos = "Linux User,,,";
173         pw.pw_shell = (char *)DEFAULT_SHELL;
174         pw.pw_dir = NULL;
175
176         /* check for min, max and missing args and exit on error */
177         opt_complementary = "-1:?1:?";
178         flags = getopt32(argc, argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
179
180         /* create string for $HOME if not specified already */
181         if (!pw.pw_dir) {
182                 snprintf(bb_common_bufsiz1, BUFSIZ, "/home/%s", argv[optind]);
183                 pw.pw_dir = bb_common_bufsiz1;
184         }
185
186         /* create a passwd struct */
187         pw.pw_name = argv[optind];
188         pw.pw_passwd = "x";
189         pw.pw_uid = 0;
190         pw.pw_gid = (usegroup) ? bb_xgetgrnam(usegroup) : 0; /* exits on failure */
191
192         /* grand finale */
193         return adduser(&pw, flags);
194 }