]> granicus.if.org Git - shadow/blob - src/newusers.c
[svn-upgrade] Integrating new upstream version, shadow (4.0.1)
[shadow] / src / newusers.c
1 /*
2  * Copyright 1990 - 1993, Julianne Frances Haugh
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      newusers - create users from a batch file
30  *
31  *      newusers creates a collection of entries in /etc/passwd
32  *      and related files by reading a passwd-format file and
33  *      adding entries in the related directories.
34  */
35
36 #include <config.h>
37
38 #include "rcsid.h"
39 RCSID (PKG_VER "$Id: newusers.c,v 1.15 2002/01/05 15:41:43 kloczek Exp $")
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include "prototypes.h"
43 #include "defines.h"
44 #include <stdio.h>
45 #include <pwd.h>
46 #include <grp.h>
47 #include <fcntl.h>
48 #ifdef USE_PAM
49 #include <security/pam_appl.h>
50 #include <security/pam_misc.h>
51 #include <pwd.h>
52 #endif                          /* USE_PAM */
53 static char *Prog;
54
55 #include "getdef.h"
56 #include "pwio.h"
57 #include "groupio.h"
58
59 #ifdef  SHADOWPWD
60 #include "shadowio.h"
61
62 static int is_shadow;
63 #endif
64
65 /* local function prototypes */
66 static void usage (void);
67 static int add_group (const char *, const char *, gid_t *);
68 static int add_user (const char *, const char *, uid_t *, gid_t);
69 static void update_passwd (struct passwd *, const char *);
70 static int add_passwd (struct passwd *, const char *);
71
72 /*
73  * usage - display usage message and exit
74  */
75
76 static void usage (void)
77 {
78         fprintf (stderr, _("Usage: %s [input]\n"), Prog);
79         exit (1);
80 }
81
82 /*
83  * add_group - create a new group or add a user to an existing group
84  */
85
86 static int add_group (const char *name, const char *gid, gid_t * ngid)
87 {
88         const struct passwd *pwd;
89         const struct group *grp;
90         struct group grent;
91         char *members[2];
92         int i;
93
94         /*
95          * Start by seeing if the named group already exists. This will be
96          * very easy to deal with if it does.
97          */
98
99         if ((grp = gr_locate (gid))) {
100               add_member:
101                 grent = *grp;
102                 *ngid = grent.gr_gid;
103                 for (i = 0; grent.gr_mem[i] != (char *) 0; i++)
104                         if (strcmp (grent.gr_mem[i], name) == 0)
105                                 return 0;
106
107                 grent.gr_mem =
108                     (char **) xmalloc (sizeof (char *) * (i + 2));
109                 memcpy (grent.gr_mem, grp->gr_mem,
110                         sizeof (char *) * (i + 2));
111                 grent.gr_mem[i] = xstrdup (name);
112                 grent.gr_mem[i + 1] = (char *) 0;
113
114                 return !gr_update (&grent);
115         }
116
117         /*
118          * The group did not exist, so I try to figure out what the GID is
119          * going to be. The gid parameter is probably "", meaning I figure
120          * out the GID from the password file. I want the UID and GID to
121          * match, unless the GID is already used.
122          */
123
124         if (gid[0] == '\0') {
125                 i = 100;
126                 for (pw_rewind (); (pwd = pw_next ());) {
127                         if (pwd->pw_uid >= i)
128                                 i = pwd->pw_uid + 1;
129                 }
130                 for (gr_rewind (); (grp = gr_next ());) {
131                         if (grp->gr_gid == i) {
132                                 i = -1;
133                                 break;
134                         }
135                 }
136         } else if (gid[0] >= '0' && gid[0] <= '9') {
137
138                 /*
139                  * The GID is a number, which means either this is a brand
140                  * new group, or an existing group. For existing groups I
141                  * just add myself as a member, just like I did earlier.
142                  */
143
144                 i = atoi (gid);
145                 for (gr_rewind (); (grp = gr_next ());)
146                         if (grp->gr_gid == i)
147                                 goto add_member;
148         } else
149                 /*
150                  * The last alternative is that the GID is a name which is
151                  * not already the name of an existing group, and I need to
152                  * figure out what group ID that group name is going to
153                  * have.
154                  */
155
156                 i = -1;
157
158         /*
159          * If I don't have a group ID by now, I'll go get the next one.
160          */
161
162         if (i == -1) {
163                 for (i = 100, gr_rewind (); (grp = gr_next ());)
164                         if (grp->gr_gid >= i)
165                                 i = grp->gr_gid + 1;
166         }
167
168         /*
169          * Now I have all of the fields required to create the new group.
170          */
171
172         if (gid[0] && (gid[0] <= '0' || gid[0] >= '9'))
173                 grent.gr_name = xstrdup (gid);
174         else
175                 grent.gr_name = xstrdup (name);
176
177         grent.gr_passwd = "x";  /* XXX warning: const */
178         grent.gr_gid = i;
179         members[0] = xstrdup (name);
180         members[1] = (char *) 0;
181         grent.gr_mem = members;
182
183         *ngid = grent.gr_gid;
184         return !gr_update (&grent);
185 }
186
187 /*
188  * add_user - create a new user ID
189  */
190
191 static int
192 add_user (const char *name, const char *uid, uid_t * nuid, gid_t gid)
193 {
194         const struct passwd *pwd;
195         struct passwd pwent;
196         uid_t i;
197
198         /*
199          * The first guess for the UID is either the numerical UID that the
200          * caller provided, or the next available UID.
201          */
202
203         if (uid[0] >= '0' && uid[0] <= '9') {
204                 i = atoi (uid);
205         } else if (uid[0] && (pwd = pw_locate (uid))) {
206                 i = pwd->pw_uid;
207         } else {
208                 i = 100;
209                 for (pw_rewind (); (pwd = pw_next ());)
210                         if (pwd->pw_uid >= i)
211                                 i = pwd->pw_uid + 1;
212         }
213
214         /*
215          * I don't want to fill in the entire password structure members
216          * JUST YET, since there is still more data to be added. So, I fill
217          * in the parts that I have.
218          */
219
220         pwent.pw_name = xstrdup (name);
221         pwent.pw_passwd = "x";  /* XXX warning: const */
222 #ifdef  ATT_AGE
223         pwent.pw_age = "";
224 #endif
225 #ifdef  ATT_COMMENT
226         pwent.pw_comment = "";
227 #endif
228 #ifdef  BSD_QUOTA
229         pwent.pw_quota = 0;
230 #endif
231         pwent.pw_uid = i;
232         pwent.pw_gid = gid;
233         pwent.pw_gecos = "";    /* XXX warning: const */
234         pwent.pw_dir = "";      /* XXX warning: const */
235         pwent.pw_shell = "";    /* XXX warning: const */
236
237         *nuid = i;
238         return !pw_update (&pwent);
239 }
240
241 static void update_passwd (struct passwd *pwd, const char *passwd)
242 {
243         pwd->pw_passwd = pw_encrypt (passwd, crypt_make_salt ());
244 #ifdef ATT_AGE
245         if (strlen (pwd->pw_age) == 4) {
246                 static char newage[5];
247                 extern char *l64a ();
248
249                 strcpy (newage, pwd->pw_age);
250                 strcpy (newage + 2, l64a (time ((time_t *) 0) / WEEK));
251                 pwd->pw_age = newage;
252         }
253 #endif
254 }
255
256 /*
257  * add_passwd - add or update the encrypted password
258  */
259
260 static int add_passwd (struct passwd *pwd, const char *passwd)
261 {
262 #ifdef  SHADOWPWD
263         const struct spwd *sp;
264         struct spwd spent;
265 #endif
266
267         /*
268          * In the case of regular password files, this is real easy - pwd
269          * points to the entry in the password file. Shadow files are
270          * harder since there are zillions of things to do ...
271          */
272
273         if (!is_shadow) {
274                 update_passwd (pwd, passwd);
275                 return 0;
276         }
277 #ifdef SHADOWPWD
278         /*
279          * Do the first and easiest shadow file case. The user already
280          * exists in the shadow password file.
281          */
282
283         if ((sp = spw_locate (pwd->pw_name))) {
284                 spent = *sp;
285                 spent.sp_pwdp = pw_encrypt (passwd, crypt_make_salt ());
286                 return !spw_update (&spent);
287         }
288
289         /*
290          * Pick the next easiest case - the user has an encrypted password
291          * which isn't equal to "x". The password was set to "x" earlier
292          * when the entry was created, so this user would have to have had
293          * the password set someplace else.
294          */
295
296         if (strcmp (pwd->pw_passwd, "x") != 0) {
297                 update_passwd (pwd, passwd);
298                 return 0;
299         }
300
301         /*
302          * Now the really hard case - I need to create an entirely new
303          * shadow password file entry.
304          */
305
306         spent.sp_namp = pwd->pw_name;
307         spent.sp_pwdp = pw_encrypt (passwd, crypt_make_salt ());
308         spent.sp_lstchg = time ((time_t *) 0) / SCALE;
309         spent.sp_min = getdef_num ("PASS_MIN_DAYS", 0);
310         /* 10000 is infinity this week */
311         spent.sp_max = getdef_num ("PASS_MAX_DAYS", 10000);
312         spent.sp_warn = getdef_num ("PASS_WARN_AGE", -1);
313         spent.sp_inact = -1;
314         spent.sp_expire = -1;
315         spent.sp_flag = -1;
316
317         return !spw_update (&spent);
318 #endif
319 }
320
321 #ifdef USE_PAM
322 static struct pam_conv conv = {
323         misc_conv,
324         NULL
325 };
326 #endif                          /* USE_PAM */
327
328 int main (int argc, char **argv)
329 {
330         char buf[BUFSIZ];
331         char *fields[8];
332         int nfields;
333         char *cp;
334         const struct passwd *pw;
335         struct passwd newpw;
336         int errors = 0;
337         int line = 0;
338         uid_t uid;
339         gid_t gid;
340
341 #ifdef USE_PAM
342         pam_handle_t *pamh = NULL;
343         struct passwd *pampw;
344         int retval;
345 #endif
346
347         Prog = Basename (argv[0]);
348
349         setlocale (LC_ALL, "");
350         bindtextdomain (PACKAGE, LOCALEDIR);
351         textdomain (PACKAGE);
352
353 #ifdef USE_PAM
354         retval = PAM_SUCCESS;
355
356         pampw = getpwuid (getuid ());
357         if (pampw == NULL) {
358                 retval = PAM_USER_UNKNOWN;
359         }
360
361         if (retval == PAM_SUCCESS) {
362                 retval =
363                     pam_start ("shadow", pampw->pw_name, &conv, &pamh);
364         }
365
366         if (retval == PAM_SUCCESS) {
367                 retval = pam_authenticate (pamh, 0);
368                 if (retval != PAM_SUCCESS) {
369                         pam_end (pamh, retval);
370                 }
371         }
372
373         if (retval == PAM_SUCCESS) {
374                 retval = pam_acct_mgmt (pamh, 0);
375                 if (retval != PAM_SUCCESS) {
376                         pam_end (pamh, retval);
377                 }
378         }
379
380         if (retval != PAM_SUCCESS) {
381                 fprintf (stderr, _("%s: PAM authentication failed\n"),
382                          Prog);
383                 exit (1);
384         }
385 #endif                          /* USE_PAM */
386
387         if (argc > 1 && argv[1][0] == '-')
388                 usage ();
389
390         if (argc == 2) {
391                 if (!freopen (argv[1], "r", stdin)) {
392                         snprintf (buf, sizeof buf, "%s: %s", Prog,
393                                   argv[1]);
394                         perror (buf);
395                         exit (1);
396                 }
397         }
398
399         /*
400          * Lock the password files and open them for update. This will bring
401          * all of the entries into memory where they may be searched for an
402          * modified, or new entries added. The password file is the key - if
403          * it gets locked, assume the others can be locked right away.
404          */
405
406         if (!pw_lock ()) {
407                 fprintf (stderr, _("%s: can't lock /etc/passwd.\n"), Prog);
408                 exit (1);
409         }
410 #ifdef  SHADOWPWD
411         is_shadow = spw_file_present ();
412
413         if ((is_shadow && !spw_lock ()) || !gr_lock ())
414 #else
415         if (!gr_lock ())
416 #endif
417         {
418                 fprintf (stderr,
419                          _("%s: can't lock files, try again later\n"),
420                          Prog);
421                 (void) pw_unlock ();
422 #ifdef  SHADOWPWD
423                 if (is_shadow)
424                         spw_unlock ();
425 #endif
426                 exit (1);
427         }
428 #ifdef  SHADOWPWD
429         if (!pw_open (O_RDWR) || (is_shadow && !spw_open (O_RDWR))
430             || !gr_open (O_RDWR))
431 #else
432         if (!pw_open (O_RDWR) || !gr_open (O_RDWR))
433 #endif
434         {
435                 fprintf (stderr, _("%s: can't open files\n"), Prog);
436                 (void) pw_unlock ();
437 #ifdef  SHADOWPWD
438                 if (is_shadow)
439                         spw_unlock ();
440 #endif
441                 (void) gr_unlock ();
442                 exit (1);
443         }
444
445         /*
446          * Read each line. The line has the same format as a password file
447          * entry, except that certain fields are not contrained to be
448          * numerical values. If a group ID is entered which does not already
449          * exist, an attempt is made to allocate the same group ID as the
450          * numerical user ID. Should that fail, the next available group ID
451          * over 100 is allocated. The pw_gid field will be updated with that
452          * value.
453          */
454
455         while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
456                 line++;
457                 if ((cp = strrchr (buf, '\n'))) {
458                         *cp = '\0';
459                 } else {
460                         fprintf (stderr, _("%s: line %d: line too long\n"),
461                                  Prog, line);
462                         errors++;
463                         continue;
464                 }
465
466                 /*
467                  * Break the string into fields and screw around with them.
468                  * There MUST be 7 colon separated fields, although the
469                  * values aren't that particular.
470                  */
471
472                 for (cp = buf, nfields = 0; nfields < 7; nfields++) {
473                         fields[nfields] = cp;
474                         if ((cp = strchr (cp, ':')))
475                                 *cp++ = '\0';
476                         else
477                                 break;
478                 }
479                 if (nfields != 6) {
480                         fprintf (stderr, _("%s: line %d: invalid line\n"),
481                                  Prog, line);
482                         continue;
483                 }
484
485                 /*
486                  * Now the fields are processed one by one. The first field
487                  * to be processed is the group name. A new group will be
488                  * created if the group name is non-numeric and does not
489                  * already exist. The named user will be the only member. If
490                  * there is no named group to be a member of, the UID will
491                  * be figured out and that value will be a candidate for a
492                  * new group, if that group ID exists, a whole new group ID
493                  * will be made up.
494                  */
495
496                 if (!(pw = pw_locate (fields[0])) &&
497                     add_group (fields[0], fields[3], &gid)) {
498                         fprintf (stderr,
499                                  _("%s: line %d: can't create GID\n"),
500                                  Prog, line);
501                         errors++;
502                         continue;
503                 }
504
505                 /*
506                  * Now we work on the user ID. It has to be specified either
507                  * as a numerical value, or left blank. If it is a numerical
508                  * value, that value will be used, otherwise the next
509                  * available user ID is computed and used. After this there
510                  * will at least be a (struct passwd) for the user.
511                  */
512
513                 if (!pw && add_user (fields[0], fields[2], &uid, gid)) {
514                         fprintf (stderr,
515                                  _("%s: line %d: can't create UID\n"),
516                                  Prog, line);
517                         errors++;
518                         continue;
519                 }
520
521                 /*
522                  * The password, gecos field, directory, and shell fields
523                  * all come next.
524                  */
525
526                 if (!(pw = pw_locate (fields[0]))) {
527                         fprintf (stderr,
528                                  _("%s: line %d: cannot find user %s\n"),
529                                  Prog, line, fields[0]);
530                         errors++;
531                         continue;
532                 }
533                 newpw = *pw;
534
535                 if (add_passwd (&newpw, fields[1])) {
536                         fprintf (stderr,
537                                  _("%s: line %d: can't update password\n"),
538                                  Prog, line);
539                         errors++;
540                         continue;
541                 }
542                 if (fields[4][0])
543                         newpw.pw_gecos = fields[4];
544
545                 if (fields[5][0])
546                         newpw.pw_dir = fields[5];
547
548                 if (fields[6][0])
549                         newpw.pw_shell = fields[6];
550
551                 if (newpw.pw_dir[0] && access (newpw.pw_dir, F_OK)) {
552                         if (mkdir (newpw.pw_dir,
553                                    0777 & ~getdef_num ("UMASK", 077)))
554                                 fprintf (stderr,
555                                          _("%s: line %d: mkdir failed\n"),
556                                          Prog, line);
557                         else if (chown
558                                  (newpw.pw_dir, newpw.pw_uid,
559                                   newpw.pw_gid))
560                                 fprintf (stderr,
561                                          _("%s: line %d: chown failed\n"),
562                                          Prog, line);
563                 }
564
565                 /*
566                  * Update the password entry with the new changes made.
567                  */
568
569                 if (!pw_update (&newpw)) {
570                         fprintf (stderr,
571                                  _("%s: line %d: can't update entry\n"),
572                                  Prog, line);
573                         errors++;
574                         continue;
575                 }
576         }
577
578         /*
579          * Any detected errors will cause the entire set of changes to be
580          * aborted. Unlocking the password file will cause all of the
581          * changes to be ignored. Otherwise the file is closed, causing the
582          * changes to be written out all at once, and then unlocked
583          * afterwards.
584          */
585
586         if (errors) {
587                 fprintf (stderr,
588                          _("%s: error detected, changes ignored\n"), Prog);
589                 (void) gr_unlock ();
590 #ifdef  SHADOWPWD
591                 if (is_shadow)
592                         spw_unlock ();
593 #endif
594                 (void) pw_unlock ();
595                 exit (1);
596         }
597 #ifdef  SHADOWPWD
598         if (!pw_close () || (is_shadow && !spw_close ()) || !gr_close ())
599 #else
600         if (!pw_close () || !gr_close ())
601 #endif
602         {
603                 fprintf (stderr, _("%s: error updating files\n"), Prog);
604                 (void) gr_unlock ();
605 #ifdef  SHADOWPWD
606                 if (is_shadow)
607                         spw_unlock ();
608 #endif
609                 (void) pw_unlock ();
610                 exit (1);
611         }
612         (void) gr_unlock ();
613 #ifdef  SHADOWPWD
614         if (is_shadow)
615                 spw_unlock ();
616 #endif
617         (void) pw_unlock ();
618
619 #ifdef USE_PAM
620         if (retval == PAM_SUCCESS) {
621                 retval = pam_chauthtok (pamh, 0);
622                 if (retval != PAM_SUCCESS) {
623                         pam_end (pamh, retval);
624                 }
625         }
626
627         if (retval != PAM_SUCCESS) {
628                 fprintf (stderr, _("%s: PAM chauthtok failed\n"), Prog);
629                 exit (1);
630         }
631
632         if (retval == PAM_SUCCESS)
633                 pam_end (pamh, PAM_SUCCESS);
634 #endif                          /* USE_PAM */
635
636         exit (0);
637  /*NOTREACHED*/}