OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / tinylogin / adduser.c
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 "tinylogin.h"
26 #include "shadow_.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <getopt.h>
38
39 #if 0
40 #  define PASSWD_FILE "passwd"
41 #  define SHADOW_FILE "shadow"
42 #endif
43
44 /* structs __________________________ */
45
46 typedef struct {
47         uid_t u;
48         gid_t g;
49 } Id;
50
51 /* data _____________________________ */
52
53 /* defaults : should this be in an external file? */
54 static char *default_passwd = "x";
55 static char *default_gecos = "";
56 static char *default_home_prefix = "/home";
57 static char *default_shell = "/bin/sh";
58
59 #ifdef TLG_FEATURE_SHADOWPASSWDS
60 /* shadow in use? */
61 static int shadow_enabled = 0;
62 #endif                                                  /* TLG_FEATURE_SHADOWPASSWDS */
63
64 /* I was doing this all over the place */
65 static FILE *fopen_wrapper(const char *filename, const char *mode)
66 {
67         FILE *f;
68
69         f = fopen(filename, mode);
70         if (f == NULL) {
71                 fprintf(stderr, "adduser: %s: %s\n", filename, strerror(errno));
72         }
73         return f;
74 }
75
76 /* remix */
77 /* EDR recoded such that the uid may be passed in *p */
78 static int passwd_study(const char *filename, struct passwd *p)
79 {
80         struct passwd *pw;
81         FILE *passwd;
82
83         const int min = 500;
84         const int max = 65000;
85
86         passwd = fopen_wrapper(filename, "r");
87         if (!passwd)
88                 return 4;
89
90         /* EDR if uid is out of bounds, set to min */
91         if ((p->pw_uid > max) || (p->pw_uid < min))
92                 p->pw_uid = min;
93
94         /* stuff to do:  
95          * make sure login isn't taken;
96          * find free uid and gid;
97          */
98         while ((pw = tlg_fgetpwent(passwd))) {
99                 if (strcmp(pw->pw_name, p->pw_name) == 0) {
100                         /* return 0; */
101                         return 1;
102                 }
103                 if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max)
104                         && (pw->pw_uid >= min)) {
105                         p->pw_uid = pw->pw_uid + 1;
106                 }
107         }
108
109         /* EDR check for an already existing gid */
110         while (tlg_getgrgid(p->pw_uid) != NULL)
111                 p->pw_uid++;
112
113         /* EDR also check for an existing group definition */
114         if (tlg_getgrnam(p->pw_name) != NULL)
115                 return 3;
116
117         /* EDR bounds check */
118         if ((p->pw_uid > max) || (p->pw_uid < min))
119                 return 2;
120
121         /* EDR create new gid always = uid */
122         p->pw_gid = p->pw_uid;
123
124         /* return 1; */
125         return 0;
126 }
127
128 static void addgroup_wrapper(const char *login, gid_t gid)
129 {
130         int argc = 4;
131         char *argv[] = { "addgroup", "-g", NULL, NULL };
132         char group_id[8];
133         char group_name[32];
134
135         strncpy(group_name, login, 32);
136         argv[3] = group_name;
137         sprintf(group_id, "%d", gid);
138         argv[2] = group_id;
139         optind = 0;
140         addgroup_main(argc, argv);
141 }
142
143 #ifdef TLG_PASSWD
144 static void passwd_wrapper(const char *login)
145 {
146         int argc = 2;
147         char *argv[] = { "passwd", NULL };
148         char login_name[32];
149
150         strncpy(login_name, login, 32);
151         argv[1] = login_name;
152         optind = 0;
153         passwd_main(argc, argv);
154 }
155 #endif                                                  /* TLG_PASSWD */
156
157 /* putpwent(3) remix */
158 static int adduser(const char *filename, struct passwd *p)
159 {
160         FILE *passwd;
161         int r;
162
163 #ifdef TLG_FEATURE_SHADOWPASSWDS
164         FILE *shadow;
165         struct spwd *sp;
166 #endif                                                  /* TLG_FEATURE_SHADOWPASSWDS */
167
168         /* make sure everything is kosher and setup uid && gid */
169         passwd = fopen_wrapper(filename, "a");
170         if (passwd == NULL) {
171                 /* return -1; */
172                 return 1;
173         }
174         fseek(passwd, 0, SEEK_END);
175
176         /* if (passwd_study(filename, p) == 0) { */
177         r = passwd_study(filename, p);
178         if (r) {
179                 if (r == 1)
180                         error_msg("%s: login already in use\n", p->pw_name);
181                 else if (r == 2)
182                         error_msg("illegal uid or no uids left\n");
183                 else if (r == 3)
184                         error_msg("group name %s already in use\n", p->pw_name);
185                 else
186                         error_msg("generic error.\n");
187                 /* return -1; */
188                 return 1;
189         }
190
191         /* add to passwd */
192         if (tlg_putpwent(p, passwd) == -1) {
193                 /* return -1; */
194                 return 1;
195         }
196         fclose(passwd);
197
198 #ifdef TLG_FEATURE_SHADOWPASSWDS
199         /* add to shadow if necessary */
200         if (shadow_enabled) {
201                 shadow = fopen_wrapper(SHADOW_FILE, "a");
202                 if (shadow == NULL) {
203                         /* return -1; */
204                         return 1;
205                 }
206                 fseek(shadow, 0, SEEK_END);
207                 sp = pwd_to_spwd(p);
208                 sp->sp_max = 99999;             /* debianish */
209                 sp->sp_warn = 7;
210                 fprintf(shadow, "%s:!:%ld:%ld:%ld:%ld:::\n",
211                                 sp->sp_namp, sp->sp_lstchg, sp->sp_min, sp->sp_max,
212                                 sp->sp_warn);
213                 fclose(shadow);
214         }
215 #endif                                                  /* TLG_FEATURE_SHADOWPASSWDS */
216
217         /* add to group */
218         /* addgroup should be responsible for dealing w/ gshadow */
219         addgroup_wrapper(p->pw_name, p->pw_gid);
220
221         /* Clear the umask for this process so it doesn't
222          * * screw up the permissions on the mkdir and chown. */
223         umask(0);
224
225         /* mkdir */
226         if (mkdir(p->pw_dir, 0755)) {
227                 perror_msg("%s", p->pw_dir);
228         }
229         /* Set the owner and group so it is owned by the new user. */
230         if (chown(p->pw_dir, p->pw_uid, p->pw_gid)) {
231                 perror_msg("%s", p->pw_dir);
232         }
233         /* Now fix up the permissions to 2755. Can't do it before now
234          * since chown will clear the setgid bit */
235         if (chmod(p->pw_dir, 02755)) {
236                 perror_msg("%s", p->pw_dir);
237         }
238 #ifdef TLG_PASSWD
239 #ifndef CONFIG_DISKtel
240         /* interactively set passwd */
241         passwd_wrapper(p->pw_name);
242 #endif
243 #endif                                                  /* TLG_PASSWD */
244
245         return 0;
246 }
247
248
249 /* return current uid (root is always uid == 0, right?) */
250 static uid_t i_am_not_root()
251 {
252         return geteuid();
253 }
254
255 /*
256  * adduser will take a login_name as its first parameter.
257  *
258  * home
259  * shell
260  * gecos 
261  *
262  * can be customized via command-line parameters.
263  * ________________________________________________________________________ */
264 int adduser_main(int argc, char **argv)
265 {
266         int i;
267         int opt;
268         char *login;
269         char *gecos;
270         char *home = NULL;
271         char *shell;
272         char path[MAXPATHLEN];
273
274         struct passwd pw;
275
276         /* init */
277         if (argc < 2) {
278                 usage(adduser_usage);
279         }
280         gecos = default_gecos;
281         shell = default_shell;
282
283         /* get args */
284         while((opt = getopt(argc, argv, "h:g:s:")) != -1){
285                 switch (opt){
286                 case 'h':
287                         home = optarg;
288                         break;
289                 case 'g':
290                         gecos = optarg;
291                         break;
292                 case 's':
293                         shell = optarg;
294                         break;
295                 default:
296                         usage(adduser_usage);
297                         exit(1);
298                 }
299         }
300
301         /* got root? */
302         if (i_am_not_root()) {
303                 error_msg_and_die( "Only root may add a user or group to the system.\n");
304         }
305
306         /* get login */
307         if (optind >= argc) {
308                 error_msg_and_die( "adduser: no user specified\n");
309         }
310         login = argv[optind];
311
312         /* create string for $HOME if not specified already */
313         if (!home) {
314                 snprintf(path, MAXPATHLEN, "%s/%s", default_home_prefix, login);
315                 path[MAXPATHLEN - 1] = 0;
316                 home = path;
317         }
318 #ifdef TLG_FEATURE_SHADOWPASSWDS
319         /* is /etc/shadow in use? */
320         /* shadow_enabled = file_exists(SHADOW_FILE); */
321         shadow_enabled = (0 == access(SHADOW_FILE, F_OK));
322 #endif                                                  /* TLG_FEATURE_SHADOWPASSWDS */
323
324         /* create a passwd struct */
325         pw.pw_name = login;
326         pw.pw_passwd = default_passwd;
327         pw.pw_uid = 0;
328         pw.pw_gid = 0;
329         pw.pw_gecos = gecos;
330         pw.pw_dir = home;
331         pw.pw_shell = shell;
332
333         /* grand finale */
334         i = adduser(PASSWD_FILE, &pw);
335
336         return (i);
337 }
338
339 /* $Id: adduser.c,v 1.8 2004-05-27 13:47:29 gerg Exp $ */