]> granicus.if.org Git - shadow/blob - src/newusers.c
* src/faillog.c, src/chage.c, src/newusers.c, src/su.c: The getopt
[shadow] / src / newusers.c
1 /*
2  * Copyright (c) 1990 - 1993, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2000 - 2006, Tomasz Kłoczko
5  * Copyright (c) 2007 - 2011, Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /*
34  *      newusers - create users from a batch file
35  *
36  *      newusers creates a collection of entries in /etc/passwd
37  *      and related files by reading a passwd-format file and
38  *      adding entries in the related directories.
39  */
40
41 #include <config.h>
42
43 #ident "$Id$"
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <stdio.h>
48 #include <pwd.h>
49 #include <grp.h>
50 #include <fcntl.h>
51 #include <getopt.h>
52 #include <ctype.h>
53 #include <errno.h>
54 #include <string.h>
55 #ifdef ACCT_TOOLS_SETUID
56 #ifdef USE_PAM
57 #include "pam_defs.h"
58 #endif                          /* USE_PAM */
59 #endif                          /* ACCT_TOOLS_SETUID */
60 #include "prototypes.h"
61 #include "defines.h"
62 #include "getdef.h"
63 #include "groupio.h"
64 #include "nscd.h"
65 #include "pwio.h"
66 #include "sgroupio.h"
67 #include "shadowio.h"
68 #include "chkname.h"
69
70 /*
71  * Global variables
72  */
73 const char *Prog;
74
75 static bool rflg = false;       /* create a system account */
76 #ifndef USE_PAM
77 static /*@null@*//*@observer@*/char *crypt_method = NULL;
78 #define cflg (NULL != crypt_method)
79 #ifdef USE_SHA_CRYPT
80 static bool sflg = false;
81 static long sha_rounds = 5000;
82 #endif                          /* USE_SHA_CRYPT */
83 #endif                          /* !USE_PAM */
84
85 static bool is_shadow;
86 #ifdef SHADOWGRP
87 static bool is_shadow_grp;
88 static bool sgr_locked = false;
89 #endif
90 static bool pw_locked = false;
91 static bool gr_locked = false;
92 static bool spw_locked = false;
93
94 /* local function prototypes */
95 static void usage (int status);
96 static void fail_exit (int);
97 static int add_group (const char *, const char *, gid_t *, gid_t);
98 static int get_user_id (const char *, uid_t *);
99 static int add_user (const char *, uid_t, gid_t);
100 #ifndef USE_PAM
101 static void update_passwd (struct passwd *, const char *);
102 #endif                          /* !USE_PAM */
103 static int add_passwd (struct passwd *, const char *);
104 static void process_flags (int argc, char **argv);
105 static void check_flags (void);
106 static void check_perms (void);
107 static void open_files (void);
108 static void close_files (void);
109
110 /*
111  * usage - display usage message and exit
112  */
113 static void usage (int status)
114 {
115         FILE *usageout = (EXIT_SUCCESS != status) ? stderr : stdout;
116         (void) fprintf (usageout,
117                         _("Usage: %s [options]\n"
118                           "\n"
119                           "Options:\n"),
120                         Prog);
121 #ifndef USE_PAM
122         (void) fprintf (usageout,
123                         _("  -c, --crypt-method            the crypt method (one of %s)\n"),
124 #ifndef USE_SHA_CRYPT
125                         "NONE DES MD5"
126 #else                           /* USE_SHA_CRYPT */
127                         "NONE DES MD5 SHA256 SHA512"
128 #endif                          /* USE_SHA_CRYPT */
129                        );
130 #endif                          /* !USE_PAM */
131         (void) fputs (_("  -h, --help                    display this help message and exit\n"), usageout);
132         (void) fputs (_("  -r, --system                  create system accounts\n"), usageout);
133 #ifndef USE_PAM
134 #ifdef USE_SHA_CRYPT
135         (void) fputs (_("  -s, --sha-rounds              number of SHA rounds for the SHA*\n"
136                         "                                crypt algorithms\n"),
137                       usageout);
138 #endif                          /* USE_SHA_CRYPT */
139 #endif                          /* !USE_PAM */
140         (void) fputs ("\n", usageout);
141
142         exit (status);
143 }
144
145 /*
146  * fail_exit - undo as much as possible
147  */
148 static void fail_exit (int code)
149 {
150         if (spw_locked) {
151                 if (spw_unlock () == 0) {
152                         fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
153                         SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
154                         /* continue */
155                 }
156         }
157         if (pw_locked) {
158                 if (pw_unlock () == 0) {
159                         fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
160                         SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
161                         /* continue */
162                 }
163         }
164         if (gr_locked) {
165                 if (gr_unlock () == 0) {
166                         fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
167                         SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
168                         /* continue */
169                 }
170         }
171 #ifdef  SHADOWGRP
172         if (sgr_locked) {
173                 if (sgr_unlock () == 0) {
174                         fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
175                         SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
176                         /* continue */
177                 }
178         }
179 #endif
180
181         exit (code);
182 }
183
184 /*
185  * add_group - create a new group or add a user to an existing group
186  */
187 static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid)
188 {
189         const struct group *grp;
190         struct group grent;
191         char *members[1];
192 #ifdef SHADOWGRP
193         const struct sgrp *sg;
194 #endif
195
196         /*
197          * Start by seeing if the named group already exists. This will be
198          * very easy to deal with if it does.
199          */
200         grp = getgrnam (gid);
201         if (NULL == grp) {
202                 grp = gr_locate (gid);
203         }
204         if (NULL != grp) {
205                 /* The user will use this ID for her primary group */
206                 *ngid = grp->gr_gid;
207                 /* Don't check gshadow */
208                 return 0;
209         }
210
211         if (isdigit (gid[0])) {
212                 /*
213                  * The GID is a number, which means either this is a brand
214                  * new group, or an existing group.
215                  */
216
217                 if (get_gid (gid, &grent.gr_gid) == 0) {
218                         fprintf (stderr,
219                                  _("%s: invalid group ID '%s'\n"),
220                                  Prog, gid);
221                         return -1;
222                 }
223
224                 /* Look in both the system database (getgrgid) and in the
225                  * internal database (gr_locate_gid), which may contain
226                  * uncommitted changes */
227                 if (   (getgrgid ((gid_t) grent.gr_gid) != NULL)
228                     || (gr_locate_gid ((gid_t) grent.gr_gid) != NULL)) {
229                         /* The user will use this ID for her
230                          * primary group */
231                         *ngid = (gid_t) grent.gr_gid;
232                         return 0;
233                 }
234
235                 /* Do not create groups with GID == (gid_t)-1 */
236                 if (grent.gr_gid == (gid_t)-1) {
237                         fprintf (stderr,
238                                  _("%s: invalid group ID '%s'\n"),
239                                  Prog, gid);
240                         return -1;
241                 }
242         } else {
243                 /* The gid parameter can be "" or a name which is not
244                  * already the name of an existing group.
245                  * In both cases, figure out what group ID can be used.
246                  */
247                 if (find_new_gid(rflg, &grent.gr_gid, &uid) < 0) {
248                         return -1;
249                 }
250         }
251
252         /*
253          * Now I have all of the fields required to create the new group.
254          */
255         if (('\0' != gid[0]) && (!isdigit (gid[0]))) {
256                 grent.gr_name = xstrdup (gid);
257         } else {
258                 grent.gr_name = xstrdup (name);
259 /* FIXME: check if the group exists */
260         }
261
262         /* Check if this is a valid group name */
263         if (!is_valid_group_name (grent.gr_name)) {
264                 fprintf (stderr,
265                          _("%s: invalid group name '%s'\n"),
266                          Prog, grent.gr_name);
267                 free (grent.gr_name);
268                 return -1;
269         }
270
271         grent.gr_passwd = "*";  /* XXX warning: const */
272         members[0] = NULL;
273         grent.gr_mem = members;
274
275         *ngid = grent.gr_gid;
276
277 #ifdef SHADOWGRP
278         if (is_shadow_grp) {
279                 sg = sgr_locate (grent.gr_name);
280
281                 if (NULL != sg) {
282                         fprintf (stderr,
283                                  _("%s: group '%s' is a shadow group, but does not exist in /etc/group\n"),
284                                  Prog, grent.gr_name);
285                         return -1;
286                 }
287         }
288 #endif
289
290 #ifdef SHADOWGRP
291         if (is_shadow_grp) {
292                 struct sgrp sgrent;
293                 char *admins[1];
294                 sgrent.sg_name = grent.gr_name;
295                 sgrent.sg_passwd = "*"; /* XXX warning: const */
296                 grent.gr_passwd  = "x"; /* XXX warning: const */
297                 admins[0] = NULL;
298                 sgrent.sg_adm = admins;
299                 sgrent.sg_mem = members;
300
301                 if (sgr_update (&sgrent) == 0) {
302                         return -1;
303                 }
304         }
305 #endif
306
307         if (gr_update (&grent) == 0) {
308                 return -1;
309         }
310
311         return 0;
312 }
313
314 static int get_user_id (const char *uid, uid_t *nuid) {
315
316         /*
317          * The first guess for the UID is either the numerical UID that the
318          * caller provided, or the next available UID.
319          */
320         if (isdigit (uid[0])) {
321                 if ((get_uid (uid, nuid) == 0) || (*nuid == (uid_t)-1)) {
322                         fprintf (stderr,
323                                  _("%s: invalid user ID '%s'\n"),
324                                  Prog, uid);
325                         return -1;
326                 }
327         } else {
328                 if ('\0' != uid[0]) {
329                         const struct passwd *pwd;
330                         /* local, no need for xgetpwnam */
331                         pwd = getpwnam (uid);
332                         if (NULL == pwd) {
333                                 pwd = pw_locate (uid);
334                         }
335
336                         if (NULL != pwd) {
337                                 *nuid = pwd->pw_uid;
338                         } else {
339                                 fprintf (stderr,
340                                          _("%s: user '%s' does not exist\n"),
341                                          Prog, uid);
342                                 return -1;
343                         }
344                 } else {
345                         if (find_new_uid (rflg, nuid, NULL) < 0) {
346                                 return -1;
347                         }
348                 }
349         }
350
351         return 0;
352 }
353
354 /*
355  * add_user - create a new user ID
356  */
357 static int add_user (const char *name, uid_t uid, gid_t gid)
358 {
359         struct passwd pwent;
360
361         /* Check if this is a valid user name */
362         if (!is_valid_user_name (name)) {
363                 fprintf (stderr,
364                          _("%s: invalid user name '%s'\n"),
365                          Prog, name);
366                 return -1;
367         }
368
369         /*
370          * I don't want to fill in the entire password structure members
371          * JUST YET, since there is still more data to be added. So, I fill
372          * in the parts that I have.
373          */
374         pwent.pw_name = xstrdup (name);
375         pwent.pw_uid = uid;
376         pwent.pw_passwd = "x";  /* XXX warning: const */
377         pwent.pw_gid = gid;
378         pwent.pw_gecos = "";    /* XXX warning: const */
379         pwent.pw_dir = "";      /* XXX warning: const */
380         pwent.pw_shell = "";    /* XXX warning: const */
381
382         return (pw_update (&pwent) == 0) ? -1 : 0;
383 }
384
385 #ifndef USE_PAM
386 static void update_passwd (struct passwd *pwd, const char *password)
387 {
388         void *crypt_arg = NULL;
389         if (crypt_method != NULL) {
390 #ifdef USE_SHA_CRYPT
391                 if (sflg) {
392                         crypt_arg = &sha_rounds;
393                 }
394 #endif
395         }
396
397         if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) {
398                 pwd->pw_passwd = (char *)password;
399         } else {
400                 pwd->pw_passwd = pw_encrypt (password,
401                                              crypt_make_salt (crypt_method,
402                                                               crypt_arg));
403         }
404 }
405 #endif                          /* !USE_PAM */
406
407 /*
408  * add_passwd - add or update the encrypted password
409  */
410 static int add_passwd (struct passwd *pwd, const char *password)
411 {
412         const struct spwd *sp;
413         struct spwd spent;
414
415 #ifndef USE_PAM
416         void *crypt_arg = NULL;
417         if (crypt_method != NULL) {
418 #ifdef USE_SHA_CRYPT
419                 if (sflg) {
420                         crypt_arg = &sha_rounds;
421                 }
422 #endif                          /* USE_SHA_CRYPT */
423         }
424
425         /*
426          * In the case of regular password files, this is real easy - pwd
427          * points to the entry in the password file. Shadow files are
428          * harder since there are zillions of things to do ...
429          */
430         if (!is_shadow) {
431                 update_passwd (pwd, password);
432                 return 0;
433         }
434 #endif                          /* USE_PAM */
435
436         /*
437          * Do the first and easiest shadow file case. The user already
438          * exists in the shadow password file.
439          */
440         sp = spw_locate (pwd->pw_name);
441 #ifndef USE_PAM
442         if (NULL != sp) {
443                 spent = *sp;
444                 if (   (NULL != crypt_method)
445                     && (0 == strcmp(crypt_method, "NONE"))) {
446                         spent.sp_pwdp = (char *)password;
447                 } else {
448                         const char *salt = crypt_make_salt (crypt_method,
449                                                             crypt_arg);
450                         spent.sp_pwdp = pw_encrypt (password, salt);
451                 }
452                 spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
453                 if (0 == spent.sp_lstchg) {
454                         /* Better disable aging than requiring a password
455                          * change */
456                         spent.sp_lstchg = -1;
457                 }
458                 return (spw_update (&spent) == 0);
459         }
460
461         /*
462          * Pick the next easiest case - the user has an encrypted password
463          * which isn't equal to "x". The password was set to "x" earlier
464          * when the entry was created, so this user would have to have had
465          * the password set someplace else.
466          */
467         if (strcmp (pwd->pw_passwd, "x") != 0) {
468                 update_passwd (pwd, password);
469                 return 0;
470         }
471 #else                           /* USE_PAM */
472         /*
473          * If there is already a shadow entry, do not touch it.
474          * If there is already a passwd entry with a password, do not
475          * touch it.
476          * The password will be updated later for all users using PAM.
477          */
478         if (   (NULL != sp)
479             || (strcmp (pwd->pw_passwd, "x") != 0)) {
480                 return 0;
481         }
482 #endif                          /* USE_PAM */
483
484         /*
485          * Now the really hard case - I need to create an entirely new
486          * shadow password file entry.
487          */
488         spent.sp_namp = pwd->pw_name;
489 #ifndef USE_PAM
490         if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) {
491                 spent.sp_pwdp = (char *)password;
492         } else {
493                 const char *salt = crypt_make_salt (crypt_method, crypt_arg);
494                 spent.sp_pwdp = pw_encrypt (password, salt);
495         }
496 #else
497         /*
498          * Lock the password.
499          * The password will be updated later for all users using PAM.
500          */
501         spent.sp_pwdp = "!";
502 #endif
503         spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
504         if (0 == spent.sp_lstchg) {
505                 /* Better disable aging than requiring a password change */
506                 spent.sp_lstchg = -1;
507         }
508         spent.sp_min    = getdef_num ("PASS_MIN_DAYS", 0);
509         /* 10000 is infinity this week */
510         spent.sp_max    = getdef_num ("PASS_MAX_DAYS", 10000);
511         spent.sp_warn   = getdef_num ("PASS_WARN_AGE", -1);
512         spent.sp_inact  = -1;
513         spent.sp_expire = -1;
514         spent.sp_flag   = SHADOW_SP_FLAG_UNSET;
515
516         return (spw_update (&spent) == 0);
517 }
518
519 /*
520  * process_flags - parse the command line options
521  *
522  *      It will not return if an error is encountered.
523  */
524 static void process_flags (int argc, char **argv)
525 {
526         int c;
527         static struct option long_options[] = {
528 #ifndef USE_PAM
529                 {"crypt-method", required_argument, NULL, 'c'},
530 #ifdef USE_SHA_CRYPT
531                 {"sha-rounds", required_argument, NULL, 's'},
532 #endif                          /* USE_SHA_CRYPT */
533 #endif                          /* !USE_PAM */
534                 {"help", no_argument, NULL, 'h'},
535                 {"system", no_argument, NULL, 'r'},
536                 {NULL, 0, NULL, '\0'}
537         };
538
539         while ((c = getopt_long (argc, argv,
540 #ifndef USE_PAM
541 #ifdef USE_SHA_CRYPT
542                                  "c:hrs:",
543 #else                           /* !USE_SHA_CRYPT */
544                                  "c:hr",
545 #endif                          /* !USE_SHA_CRYPT */
546 #else                           /* USE_PAM */
547                                  "hr",
548 #endif
549                                  long_options, NULL)) != -1) {
550                 switch (c) {
551                 case 'h':
552                         usage (EXIT_SUCCESS);
553                         break;
554                 case 'r':
555                         rflg = true;
556                         break;
557 #ifndef USE_PAM
558                 case 'c':
559                         crypt_method = optarg;
560                         break;
561 #ifdef USE_SHA_CRYPT
562                 case 's':
563                         sflg = true;
564                         if (getlong(optarg, &sha_rounds) == 0) {
565                                 fprintf (stderr,
566                                          _("%s: invalid numeric argument '%s'\n"),
567                                          Prog, optarg);
568                                 usage (EXIT_FAILURE);
569                         }
570                         break;
571 #endif                          /* USE_SHA_CRYPT */
572 #endif                          /* !USE_PAM */
573                 default:
574                         usage (EXIT_FAILURE);
575                         break;
576                 }
577         }
578
579         if (argv[optind] != NULL) {
580                 if (freopen (argv[optind], "r", stdin) == NULL) {
581                         char buf[BUFSIZ];
582                         snprintf (buf, sizeof buf, "%s: %s", Prog, argv[1]);
583                         perror (buf);
584                         fail_exit (EXIT_FAILURE);
585                 }
586         }
587
588         /* validate options */
589         check_flags ();
590 }
591
592 /*
593  * check_flags - check flags and parameters consistency
594  *
595  *      It will not return if an error is encountered.
596  */
597 static void check_flags (void)
598 {
599 #ifndef USE_PAM
600 #ifdef USE_SHA_CRYPT
601         if (sflg && !cflg) {
602                 fprintf (stderr,
603                          _("%s: %s flag is only allowed with the %s flag\n"),
604                          Prog, "-s", "-c");
605                 usage (EXIT_FAILURE);
606         }
607 #endif                          /* USE_SHA_CRYPT */
608
609         if (cflg) {
610                 if (   (0 != strcmp (crypt_method, "DES"))
611                     && (0 != strcmp (crypt_method, "MD5"))
612                     && (0 != strcmp (crypt_method, "NONE"))
613 #ifdef USE_SHA_CRYPT
614                     && (0 != strcmp (crypt_method, "SHA256"))
615                     && (0 != strcmp (crypt_method, "SHA512"))
616 #endif                          /* USE_SHA_CRYPT */
617                     ) {
618                         fprintf (stderr,
619                                  _("%s: unsupported crypt method: %s\n"),
620                                  Prog, crypt_method);
621                         usage (EXIT_FAILURE);
622                 }
623         }
624 #endif                          /* !USE_PAM */
625 }
626
627 /*
628  * check_perms - check if the caller is allowed to add a group
629  *
630  *      With PAM support, the setuid bit can be set on groupadd to allow
631  *      non-root users to groups.
632  *      Without PAM support, only users who can write in the group databases
633  *      can add groups.
634  *
635  *      It will not return if the user is not allowed.
636  */
637 static void check_perms (void)
638 {
639 #ifdef ACCT_TOOLS_SETUID
640 #ifdef USE_PAM
641         pam_handle_t *pamh = NULL;
642         int retval;
643         struct passwd *pampw;
644
645         pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
646         if (NULL == pampw) {
647                 fprintf (stderr,
648                          _("%s: Cannot determine your user name.\n"),
649                          Prog);
650                 fail_exit (EXIT_FAILURE);
651         }
652
653         retval = pam_start ("newusers", pampw->pw_name, &conv, &pamh);
654
655         if (PAM_SUCCESS == retval) {
656                 retval = pam_authenticate (pamh, 0);
657         }
658
659         if (PAM_SUCCESS == retval) {
660                 retval = pam_acct_mgmt (pamh, 0);
661         }
662
663         if (NULL != pamh) {
664                 (void) pam_end (pamh, retval);
665         }
666         if (PAM_SUCCESS != retval) {
667                 fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
668                 fail_exit (EXIT_FAILURE);
669         }
670 #endif                          /* USE_PAM */
671 #endif                          /* ACCT_TOOLS_SETUID */
672 }
673
674 /*
675  * open_files - lock and open the password, group and shadow databases
676  */
677 static void open_files (void)
678 {
679         /*
680          * Lock the password files and open them for update. This will bring
681          * all of the entries into memory where they may be searched for an
682          * modified, or new entries added. The password file is the key - if
683          * it gets locked, assume the others can be locked right away.
684          */
685         if (pw_lock () == 0) {
686                 fprintf (stderr,
687                          _("%s: cannot lock %s; try again later.\n"),
688                          Prog, pw_dbname ());
689                 fail_exit (EXIT_FAILURE);
690         }
691         pw_locked = true;
692         if (is_shadow) {
693                 if (spw_lock () == 0) {
694                         fprintf (stderr,
695                                  _("%s: cannot lock %s; try again later.\n"),
696                                  Prog, spw_dbname ());
697                         fail_exit (EXIT_FAILURE);
698                 }
699                 spw_locked = true;
700         }
701         if (gr_lock () == 0) {
702                 fprintf (stderr,
703                          _("%s: cannot lock %s; try again later.\n"),
704                          Prog, gr_dbname ());
705                 fail_exit (EXIT_FAILURE);
706         }
707         gr_locked = true;
708 #ifdef SHADOWGRP
709         if (is_shadow_grp) {
710                 if (sgr_lock () == 0) {
711                         fprintf (stderr,
712                                  _("%s: cannot lock %s; try again later.\n"),
713                                  Prog, sgr_dbname ());
714                         fail_exit (EXIT_FAILURE);
715                 }
716                 sgr_locked = true;
717         }
718 #endif
719
720         if (pw_open (O_RDWR) == 0) {
721                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ());
722                 fail_exit (EXIT_FAILURE);
723         }
724         if (is_shadow && (spw_open (O_RDWR) == 0)) {
725                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ());
726                 fail_exit (EXIT_FAILURE);
727         }
728         if (gr_open (O_RDWR) == 0) {
729                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
730                 fail_exit (EXIT_FAILURE);
731         }
732 #ifdef SHADOWGRP
733         if (is_shadow_grp && (sgr_open (O_RDWR) == 0)) {
734                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ());
735                 fail_exit (EXIT_FAILURE);
736         }
737 #endif
738 }
739
740 /*
741  * close_files - close and unlock the password, group and shadow databases
742  */
743 static void close_files (void)
744 {
745         if (pw_close () == 0) {
746                 fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ());
747                 SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ()));
748                 fail_exit (EXIT_FAILURE);
749         }
750         if (pw_unlock () == 0) {
751                 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
752                 SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
753                 /* continue */
754         }
755         pw_locked = false;
756
757         if (is_shadow) {
758                 if (spw_close () == 0) {
759                         fprintf (stderr,
760                                  _("%s: failure while writing changes to %s\n"),
761                                  Prog, spw_dbname ());
762                         SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ()));
763                         fail_exit (EXIT_FAILURE);
764                 }
765                 if (spw_unlock () == 0) {
766                         fprintf (stderr,
767                                  _("%s: failed to unlock %s\n"),
768                                  Prog, spw_dbname ());
769                         SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
770                         /* continue */
771                 }
772                 spw_locked = false;
773         }
774
775         if (gr_close () == 0) {
776                 fprintf (stderr,
777                          _("%s: failure while writing changes to %s\n"),
778                          Prog, gr_dbname ());
779                 SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ()));
780                 fail_exit (EXIT_FAILURE);
781         }
782         if (gr_unlock () == 0) {
783                 fprintf (stderr,
784                          _("%s: failed to unlock %s\n"),
785                          Prog, gr_dbname ());
786                 SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
787                 /* continue */
788         }
789         gr_locked = false;
790
791 #ifdef SHADOWGRP
792         if (is_shadow_grp) {
793                 if (sgr_close () == 0) {
794                         fprintf (stderr,
795                                  _("%s: failure while writing changes to %s\n"),
796                                  Prog, sgr_dbname ());
797                         SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ()));
798                         fail_exit (EXIT_FAILURE);
799                 }
800                 if (sgr_unlock () == 0) {
801                         fprintf (stderr,
802                                  _("%s: failed to unlock %s\n"),
803                                  Prog, sgr_dbname ());
804                         SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
805                         /* continue */
806                 }
807                 sgr_locked = false;
808         }
809 #endif
810 }
811
812 int main (int argc, char **argv)
813 {
814         char buf[BUFSIZ];
815         char *fields[8];
816         int nfields;
817         char *cp;
818         const struct passwd *pw;
819         struct passwd newpw;
820         int errors = 0;
821         int line = 0;
822         uid_t uid;
823         gid_t gid;
824 #ifdef USE_PAM
825         int *lines = NULL;
826         char **usernames = NULL;
827         char **passwords = NULL;
828         unsigned int nusers = 0;
829 #endif                          /* USE_PAM */
830
831         Prog = Basename (argv[0]);
832
833         (void) setlocale (LC_ALL, "");
834         (void) bindtextdomain (PACKAGE, LOCALEDIR);
835         (void) textdomain (PACKAGE);
836
837         OPENLOG ("newusers");
838
839         process_flags (argc, argv);
840
841         check_perms ();
842
843         is_shadow = spw_file_present ();
844
845 #ifdef SHADOWGRP
846         is_shadow_grp = sgr_file_present ();
847 #endif
848
849         open_files ();
850
851         /*
852          * Read each line. The line has the same format as a password file
853          * entry, except that certain fields are not constrained to be
854          * numerical values. If a group ID is entered which does not already
855          * exist, an attempt is made to allocate the same group ID as the
856          * numerical user ID. Should that fail, the next available group ID
857          * over 100 is allocated. The pw_gid field will be updated with that
858          * value.
859          */
860         while (fgets (buf, (int) sizeof buf, stdin) != (char *) 0) {
861                 line++;
862                 cp = strrchr (buf, '\n');
863                 if (NULL != cp) {
864                         *cp = '\0';
865                 } else {
866                         if (feof (stdin) == 0) {
867                                 fprintf (stderr,
868                                          _("%s: line %d: line too long\n"),
869                                          Prog, line);
870                                 errors++;
871                                 continue;
872                         }
873                 }
874
875                 /*
876                  * Break the string into fields and screw around with them.
877                  * There MUST be 7 colon separated fields, although the
878                  * values aren't that particular.
879                  */
880                 for (cp = buf, nfields = 0; nfields < 7; nfields++) {
881                         fields[nfields] = cp;
882                         cp = strchr (cp, ':');
883                         if (NULL != cp) {
884                                 *cp = '\0';
885                                 cp++;
886                         } else {
887                                 break;
888                         }
889                 }
890                 if (nfields != 6) {
891                         fprintf (stderr, _("%s: line %d: invalid line\n"),
892                                  Prog, line);
893                         errors++;
894                         continue;
895                 }
896
897                 /*
898                  * First check if we have to create or update an user
899                  */
900                 pw = pw_locate (fields[0]);
901                 /* local, no need for xgetpwnam */
902                 if (   (NULL == pw)
903                     && (getpwnam (fields[0]) != NULL)) {
904                         fprintf (stderr, _("%s: cannot update the entry of user %s (not in the passwd database)\n"), Prog, fields[0]);
905                         errors++;
906                         continue;
907                 }
908
909                 if (   (NULL == pw)
910                     && (get_user_id (fields[2], &uid) != 0)) {
911                         fprintf (stderr,
912                                  _("%s: line %d: can't create user\n"),
913                                  Prog, line);
914                         errors++;
915                         continue;
916                 }
917
918                 /*
919                  * Processed is the group name. A new group will be
920                  * created if the group name is non-numeric and does not
921                  * already exist. If the group name is a number (which is not
922                  * an existing GID), a group with the same name as the user
923                  * will be created, with the given GID. The given or created
924                  * group will be the primary group of the user. If
925                  * there is no named group to be a member of, the UID will
926                  * be figured out and that value will be a candidate for a
927                  * new group, if that group ID exists, a whole new group ID
928                  * will be made up.
929                  */
930                 if (   (NULL == pw)
931                     && (add_group (fields[0], fields[3], &gid, uid) != 0)) {
932                         fprintf (stderr,
933                                  _("%s: line %d: can't create group\n"),
934                                  Prog, line);
935                         errors++;
936                         continue;
937                 }
938
939                 /*
940                  * Now we work on the user ID. It has to be specified either
941                  * as a numerical value, or left blank. If it is a numerical
942                  * value, that value will be used, otherwise the next
943                  * available user ID is computed and used. After this there
944                  * will at least be a (struct passwd) for the user.
945                  */
946                 if (   (NULL == pw)
947                     && (add_user (fields[0], uid, gid) != 0)) {
948                         fprintf (stderr,
949                                  _("%s: line %d: can't create user\n"),
950                                  Prog, line);
951                         errors++;
952                         continue;
953                 }
954
955                 /*
956                  * The password, gecos field, directory, and shell fields
957                  * all come next.
958                  */
959                 pw = pw_locate (fields[0]);
960                 if (NULL == pw) {
961                         fprintf (stderr,
962                                  _("%s: line %d: user '%s' does not exist in %s\n"),
963                                  Prog, line, fields[0], pw_dbname ());
964                         errors++;
965                         continue;
966                 }
967                 newpw = *pw;
968
969 #ifdef USE_PAM
970                 /* keep the list of user/password for later update by PAM */
971                 nusers++;
972                 lines     = realloc (lines,     sizeof (lines[0])     * nusers);
973                 usernames = realloc (usernames, sizeof (usernames[0]) * nusers);
974                 passwords = realloc (passwords, sizeof (passwords[0]) * nusers);
975                 lines[nusers-1]     = line;
976                 usernames[nusers-1] = strdup (fields[0]);
977                 passwords[nusers-1] = strdup (fields[1]);
978 #endif                          /* USE_PAM */
979                 if (add_passwd (&newpw, fields[1]) != 0) {
980                         fprintf (stderr,
981                                  _("%s: line %d: can't update password\n"),
982                                  Prog, line);
983                         errors++;
984                         continue;
985                 }
986                 if ('\0' != fields[4][0]) {
987                         newpw.pw_gecos = fields[4];
988                 }
989
990                 if ('\0' != fields[5][0]) {
991                         newpw.pw_dir = fields[5];
992                 }
993
994                 if ('\0' != fields[6][0]) {
995                         newpw.pw_shell = fields[6];
996                 }
997
998                 if (   ('\0' != newpw.pw_dir[0])
999                     && (access (newpw.pw_dir, F_OK) != 0)) {
1000 /* FIXME: should check for directory */
1001                         mode_t msk = 0777 & ~getdef_num ("UMASK",
1002                                                          GETDEF_DEFAULT_UMASK);
1003                         if (mkdir (newpw.pw_dir, msk) != 0) {
1004                                 fprintf (stderr,
1005                                          _("%s: line %d: mkdir %s failed: %s\n"),
1006                                          Prog, line, newpw.pw_dir,
1007                                          strerror (errno));
1008                         } else if (chown (newpw.pw_dir,
1009                                           newpw.pw_uid,
1010                                           newpw.pw_gid) != 0) {
1011                                 fprintf (stderr,
1012                                          _("%s: line %d: chown %s failed: %s\n"),
1013                                          Prog, line, newpw.pw_dir,
1014                                          strerror (errno));
1015                         }
1016                 }
1017
1018                 /*
1019                  * Update the password entry with the new changes made.
1020                  */
1021                 if (pw_update (&newpw) == 0) {
1022                         fprintf (stderr,
1023                                  _("%s: line %d: can't update entry\n"),
1024                                  Prog, line);
1025                         errors++;
1026                         continue;
1027                 }
1028         }
1029
1030         /*
1031          * Any detected errors will cause the entire set of changes to be
1032          * aborted. Unlocking the password file will cause all of the
1033          * changes to be ignored. Otherwise the file is closed, causing the
1034          * changes to be written out all at once, and then unlocked
1035          * afterwards.
1036          */
1037         if (0 != errors) {
1038                 fprintf (stderr,
1039                          _("%s: error detected, changes ignored\n"), Prog);
1040                 fail_exit (EXIT_FAILURE);
1041         }
1042
1043         close_files ();
1044
1045         nscd_flush_cache ("passwd");
1046         nscd_flush_cache ("group");
1047
1048 #ifdef USE_PAM
1049         unsigned int i;
1050         /* Now update the passwords using PAM */
1051         for (i = 0; i < nusers; i++) {
1052                 if (do_pam_passwd_non_interractive ("newusers", usernames[i], passwords[i]) != 0) {
1053                         fprintf (stderr,
1054                                  _("%s: (line %d, user %s) password not changed\n"),
1055                                  Prog, lines[i], usernames[i]);
1056                         errors++;
1057                 }
1058         }
1059 #endif                          /* USE_PAM */
1060
1061         return ((0 == errors) ? EXIT_SUCCESS : EXIT_FAILURE);
1062 }
1063