]> granicus.if.org Git - shadow/blob - src/gpasswd.c
Re-indent.
[shadow] / src / gpasswd.c
1 /*
2  * Copyright (c) 1990 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2001 - 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 #include <config.h>
34
35 #ident "$Id$"
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <getopt.h>
40 #include <grp.h>
41 #include <pwd.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include "defines.h"
46 #include "groupio.h"
47 #include "nscd.h"
48 #include "prototypes.h"
49 #ifdef SHADOWGRP
50 #include "sgroupio.h"
51 #endif
52 /*@-exitarg@*/
53 #include "exitcodes.h"
54
55 /*
56  * Global variables
57  */
58 /* The name of this command, as it is invoked */
59 const char *Prog;
60
61 #ifdef SHADOWGRP
62 /* Indicate if shadow groups are enabled on the system
63  * (/etc/gshadow present) */
64 static bool is_shadowgrp;
65 #endif
66
67 /* Flags set by options */
68 static bool aflg = false;
69 static bool Aflg = false;
70 static bool dflg = false;
71 static bool Mflg = false;
72 static bool rflg = false;
73 static bool Rflg = false;
74 /* The name of the group that is being affected */
75 static char *group = NULL;
76 /* The name of the user being added (-a) or removed (-d) from group */
77 static char *user = NULL;
78 /* The new list of members set with -M */
79 static char *members = NULL;
80 #ifdef SHADOWGRP
81 /* The new list of group administrators set with -A */
82 static char *admins = NULL;
83 #endif
84 /* The name of the caller */
85 static char *myname = NULL;
86 /* The UID of the caller */
87 static uid_t bywho;
88 /* Indicate if gpasswd was called by root */
89 #define amroot  (0 == bywho)
90
91 /* The number of retries for th user to provide and repeat a new password */
92 #ifndef RETRIES
93 #define RETRIES 3
94 #endif
95
96 /* local function prototypes */
97 static void usage (int status);
98 static RETSIGTYPE catch_signals (int killed);
99 static bool is_valid_user_list (const char *users);
100 static void process_flags (int argc, char **argv);
101 static void check_flags (int argc, int opt_index);
102 static void open_files (void);
103 static void close_files (void);
104 #ifdef SHADOWGRP
105 static void get_group (struct group *gr, struct sgrp *sg);
106 static void check_perms (const struct group *gr, const struct sgrp *sg);
107 static void update_group (struct group *gr, struct sgrp *sg);
108 static void change_passwd (struct group *gr, struct sgrp *sg);
109 #else
110 static void get_group (struct group *gr);
111 static void check_perms (const struct group *gr);
112 static void update_group (struct group *gr);
113 static void change_passwd (struct group *gr);
114 #endif
115 static void log_gpasswd_failure (const char *suffix);
116 static void log_gpasswd_failure_system (unused void *arg);
117 static void log_gpasswd_failure_group (unused void *arg);
118 #ifdef SHADOWGRP
119 static void log_gpasswd_failure_gshadow (unused void *arg);
120 #endif
121 static void log_gpasswd_success (const char *suffix);
122 static void log_gpasswd_success_system (unused void *arg);
123 static void log_gpasswd_success_group (unused void *arg);
124
125 /*
126  * usage - display usage message
127  */
128 static void usage (int status)
129 {
130         FILE *usageout = (E_SUCCESS != status) ? stderr : stdout;
131         (void) fprintf (usageout,
132                         _("Usage: %s [option] GROUP\n"
133                           "\n"
134                           "Options:\n"),
135                         Prog);
136         (void) fputs (_("  -a, --add USER                add USER to GROUP\n"), usageout);
137         (void) fputs (_("  -d, --delete USER             remove USER from GROUP\n"), usageout);
138         (void) fputs (_("  -h, --help                    display this help message and exit\n"), usageout);
139         (void) fputs (_("  -Q, --root CHROOT_DIR         directory to chroot into\n"), usageout);
140         (void) fputs (_("  -r, --remove-password         remove the GROUP's password\n"), usageout);
141         (void) fputs (_("  -R, --restrict                restrict access to GROUP to its members\n"), usageout);
142         (void) fputs (_("  -M, --members USER,...        set the list of members of GROUP\n"), usageout);
143 #ifdef SHADOWGRP
144         (void) fputs (_("  -A, --administrators ADMIN,...\n"
145                         "                                set the list of administrators for GROUP\n"), usageout);
146         (void) fputs (_("Except for the -A and -M options, the options cannot be combined.\n"), usageout);
147 #else
148         (void) fputs (_("The options cannot be combined.\n"), usageout);
149 #endif
150         exit (status);
151 }
152
153 /*
154  * catch_signals - set or reset termio modes.
155  *
156  *      catch_signals() is called before processing begins. signal() is then
157  *      called with catch_signals() as the signal handler. If signal later
158  *      calls catch_signals() with a signal number, the terminal modes are
159  *      then reset.
160  */
161 static RETSIGTYPE catch_signals (int killed)
162 {
163         static TERMIO sgtty;
164
165         if (0 != killed) {
166                 STTY (0, &sgtty);
167         } else {
168                 GTTY (0, &sgtty);
169         }
170
171         if (0 != killed) {
172                 (void) putchar ('\n');
173                 (void) fflush (stdout);
174                 exit (killed);
175         }
176 }
177
178 /*
179  * is_valid_user_list - check a comma-separated list of user names for validity
180  *
181  *      is_valid_user_list scans a comma-separated list of user names and
182  *      checks that each listed name exists is the user database.
183  *
184  *      It returns true if the list of users is valid.
185  */
186 static bool is_valid_user_list (const char *users)
187 {
188         char *username, *end;
189         bool is_valid = true;
190         char *tmpusers = xstrdup (users);
191
192         for (username = tmpusers;
193              (NULL != username) && ('\0' != *username);
194              username = end) {
195                 end = strchr (username, ',');
196                 if (NULL != end) {
197                         *end = '\0';
198                         end++;
199                 }
200
201                 /*
202                  * This user must exist.
203                  */
204
205                 /* local, no need for xgetpwnam */
206                 if (getpwnam (username) == NULL) {
207                         fprintf (stderr, _("%s: user '%s' does not exist\n"),
208                                  Prog, username);
209                         is_valid = false;
210                 }
211         }
212
213         free (tmpusers);
214
215         return is_valid;
216 }
217
218 static void failure (void)
219 {
220         fprintf (stderr, _("%s: Permission denied.\n"), Prog);
221         log_gpasswd_failure (": Permission denied");
222         exit (E_NOPERM);
223 }
224
225 /*
226  * process_flags - process the command line options and arguments
227  */
228 static void process_flags (int argc, char **argv)
229 {
230         int c;
231         static struct option long_options[] = {
232                 {"add", required_argument, NULL, 'a'},
233                 {"delete", required_argument, NULL, 'd'},
234                 {"help", no_argument, NULL, 'h'},
235                 {"remove-password", no_argument, NULL, 'r'},
236                 {"restrict", no_argument, NULL, 'R'},
237                 {"administrators", required_argument, NULL, 'A'},
238                 {"members", required_argument, NULL, 'M'},
239                 {"root", required_argument, NULL, 'Q'},
240                 {NULL, 0, NULL, '\0'}
241                 };
242
243         while ((c = getopt_long (argc, argv, "a:A:d:ghM:Q:rR",
244                                  long_options, NULL)) != -1) {
245                 switch (c) {
246                 case 'a':       /* add a user */
247                         aflg = true;
248                         user = optarg;
249                         /* local, no need for xgetpwnam */
250                         if (getpwnam (user) == NULL) {
251                                 fprintf (stderr,
252                                          _("%s: user '%s' does not exist\n"),
253                                          Prog, user);
254                                 exit (E_BAD_ARG);
255                         }
256                         break;
257 #ifdef SHADOWGRP
258                 case 'A':       /* set the list of administrators */
259                         if (!is_shadowgrp) {
260                                 fprintf (stderr,
261                                          _("%s: shadow group passwords required for -A\n"),
262                                          Prog);
263                                 exit (E_GSHADOW_NOTFOUND);
264                         }
265                         admins = optarg;
266                         if (!is_valid_user_list (admins)) {
267                                 exit (E_BAD_ARG);
268                         }
269                         Aflg = true;
270                         break;
271 #endif                          /* SHADOWGRP */
272                 case 'd':       /* delete a user */
273                         dflg = true;
274                         user = optarg;
275                         break;
276                 case 'g':       /* no-op from normal password */
277                         break;
278                 case 'h':
279                         usage (E_SUCCESS);
280                         break;
281                 case 'M':       /* set the list of members */
282                         members = optarg;
283                         if (!is_valid_user_list (members)) {
284                                 exit (E_BAD_ARG);
285                         }
286                         Mflg = true;
287                         break;
288                 case 'Q':       /* no-op, handled in process_root_flag () */
289                         break;
290                 case 'r':       /* remove group password */
291                         rflg = true;
292                         break;
293                 case 'R':       /* restrict group password */
294                         Rflg = true;
295                         break;
296                 default:
297                         usage (E_USAGE);
298                 }
299         }
300
301         /* Get the name of the group that is being affected. */
302         group = argv[optind];
303
304         check_flags (argc, optind);
305 }
306
307 /*
308  * check_flags - check the validity of options
309  */
310 static void check_flags (int argc, int opt_index)
311 {
312         int exclusive = 0;
313         /*
314          * Make sure exclusive flags are exclusive
315          */
316         if (aflg) {
317                 exclusive++;
318         }
319         if (dflg) {
320                 exclusive++;
321         }
322         if (rflg) {
323                 exclusive++;
324         }
325         if (Rflg) {
326                 exclusive++;
327         }
328         if (Aflg || Mflg) {
329                 exclusive++;
330         }
331         if (exclusive > 1) {
332                 usage (E_USAGE);
333         }
334
335         /*
336          * Make sure one (and only one) group was provided
337          */
338         if ((argc != (opt_index+1)) || (NULL == group)) {
339                 usage (E_USAGE);
340         }
341 }
342
343 /*
344  * open_files - lock and open the group databases
345  *
346  *      It will call exit in case of error.
347  */
348 static void open_files (void)
349 {
350         if (gr_lock () == 0) {
351                 fprintf (stderr,
352                          _("%s: cannot lock %s; try again later.\n"),
353                          Prog, gr_dbname ());
354                 exit (E_NOPERM);
355         }
356         add_cleanup (cleanup_unlock_group, NULL);
357
358 #ifdef SHADOWGRP
359         if (is_shadowgrp) {
360                 if (sgr_lock () == 0) {
361                         fprintf (stderr,
362                                  _("%s: cannot lock %s; try again later.\n"),
363                                  Prog, sgr_dbname ());
364                         exit (E_NOPERM);
365                 }
366                 add_cleanup (cleanup_unlock_gshadow, NULL);
367         }
368 #endif                          /* SHADOWGRP */
369
370         add_cleanup (log_gpasswd_failure_system, NULL);
371
372         if (gr_open (O_RDWR) == 0) {
373                 fprintf (stderr,
374                          _("%s: cannot open %s\n"),
375                          Prog, gr_dbname ());
376                 SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
377                 exit (E_NOPERM);
378         }
379
380 #ifdef SHADOWGRP
381         if (is_shadowgrp) {
382                 if (sgr_open (O_RDWR) == 0) {
383                         fprintf (stderr,
384                                  _("%s: cannot open %s\n"),
385                                  Prog, sgr_dbname ());
386                         SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
387                         exit (E_NOPERM);
388                 }
389                 add_cleanup (log_gpasswd_failure_gshadow, NULL);
390         }
391 #endif                          /* SHADOWGRP */
392
393         add_cleanup (log_gpasswd_failure_group, NULL);
394         del_cleanup (log_gpasswd_failure_system);
395 }
396
397 static void log_gpasswd_failure (const char *suffix)
398 {
399 #ifdef WITH_AUDIT
400         char buf[1024];
401 #endif
402         if (aflg) {
403                 SYSLOG ((LOG_ERR,
404                          "%s failed to add user %s to group %s%s",
405                          myname, user, group, suffix));
406 #ifdef WITH_AUDIT
407                 snprintf (buf, 1023,
408                           "%s failed to add user %s to group %s%s",
409                           myname, user, group, suffix);
410                 buf[1023] = '\0';
411                 audit_logger (AUDIT_USER_ACCT, Prog,
412                               buf,
413                               group, AUDIT_NO_ID,
414                               SHADOW_AUDIT_FAILURE);
415 #endif
416         } else if (dflg) {
417                 SYSLOG ((LOG_ERR,
418                          "%s failed to remove user %s from group %s%s",
419                          myname, user, group, suffix));
420 #ifdef WITH_AUDIT
421                 snprintf (buf, 1023,
422                           "%s failed to remove user %s from group %s%s",
423                           myname, user, group, suffix);
424                 buf[1023] = '\0';
425                 audit_logger (AUDIT_USER_ACCT, Prog,
426                               buf,
427                               group, AUDIT_NO_ID,
428                               SHADOW_AUDIT_FAILURE);
429 #endif
430         } else if (rflg) {
431                 SYSLOG ((LOG_ERR,
432                          "%s failed to remove password of group %s%s",
433                          myname, group, suffix));
434 #ifdef WITH_AUDIT
435                 snprintf (buf, 1023,
436                           "%s failed to remove password of group %s%s",
437                           myname, group, suffix);
438                 buf[1023] = '\0';
439                 audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
440                               buf,
441                               group, AUDIT_NO_ID,
442                               SHADOW_AUDIT_FAILURE);
443 #endif
444         } else if (Rflg) {
445                 SYSLOG ((LOG_ERR,
446                          "%s failed to restrict access to group %s%s",
447                          myname, group, suffix));
448 #ifdef WITH_AUDIT
449                 snprintf (buf, 1023,
450                           "%s failed to restrict access to group %s%s",
451                           myname, group, suffix);
452                 buf[1023] = '\0';
453                 audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
454                               buf,
455                               group, AUDIT_NO_ID,
456                               SHADOW_AUDIT_FAILURE);
457 #endif
458         } else if (Aflg || Mflg) {
459 #ifdef SHADOWGRP
460                 if (Aflg) {
461                         SYSLOG ((LOG_ERR,
462                                  "%s failed to set the administrators of group %s to %s%s",
463                                  myname, group, admins, suffix));
464 #ifdef WITH_AUDIT
465                         snprintf (buf, 1023,
466                                   "%s failed to set the administrators of group %s to %s%s",
467                                   myname, group, admins, suffix);
468                         buf[1023] = '\0';
469                         audit_logger (AUDIT_USER_ACCT, Prog,
470                                       buf,
471                                       group, AUDIT_NO_ID,
472                                       SHADOW_AUDIT_FAILURE);
473 #endif
474                 }
475 #endif                          /* SHADOWGRP */
476                 if (Mflg) {
477                         SYSLOG ((LOG_ERR,
478                                  "%s failed to set the members of group %s to %s%s",
479                                  myname, group, members, suffix));
480 #ifdef WITH_AUDIT
481                         snprintf (buf, 1023,
482                                   "%s failed to set the members of group %s to %s%s",
483                                   myname, group, members, suffix);
484                         buf[1023] = '\0';
485                         audit_logger (AUDIT_USER_ACCT, Prog,
486                                       buf,
487                                       group, AUDIT_NO_ID,
488                                       SHADOW_AUDIT_FAILURE);
489 #endif
490                 }
491         } else {
492                 SYSLOG ((LOG_ERR,
493                          "%s failed to change password of group %s%s",
494                          myname, group, suffix));
495 #ifdef WITH_AUDIT
496                 snprintf (buf, 1023,
497                           "%s failed to change password of group %s%s",
498                           myname, group, suffix);
499                 buf[1023] = '\0';
500                 audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
501                               buf,
502                               group, AUDIT_NO_ID,
503                               SHADOW_AUDIT_FAILURE);
504 #endif
505         }
506 }
507
508 static void log_gpasswd_failure_system (unused void *arg)
509 {
510         log_gpasswd_failure ("");
511 }
512
513 static void log_gpasswd_failure_group (unused void *arg)
514 {
515         char buf[1024];
516         snprintf (buf, 1023, " in %s", gr_dbname ());
517         buf[1023] = '\0';
518         log_gpasswd_failure (buf);
519 }
520
521 #ifdef SHADOWGRP
522 static void log_gpasswd_failure_gshadow (unused void *arg)
523 {
524         char buf[1024];
525         snprintf (buf, 1023, " in %s", sgr_dbname ());
526         buf[1023] = '\0';
527         log_gpasswd_failure (buf);
528 }
529 #endif                          /* SHADOWGRP */
530
531 static void log_gpasswd_success (const char *suffix)
532 {
533 #ifdef WITH_AUDIT
534         char buf[1024];
535 #endif
536         if (aflg) {
537                 SYSLOG ((LOG_INFO,
538                          "user %s added by %s to group %s%s",
539                          user, myname, group, suffix));
540 #ifdef WITH_AUDIT
541                 snprintf (buf, 1023,
542                           "user %s added by %s to group %s%s",
543                           user, myname, group, suffix);
544                 buf[1023] = '\0';
545                 audit_logger (AUDIT_USER_ACCT, Prog,
546                               buf,
547                               group, AUDIT_NO_ID,
548                               SHADOW_AUDIT_SUCCESS);
549 #endif
550         } else if (dflg) {
551                 SYSLOG ((LOG_INFO,
552                          "user %s removed by %s from group %s%s",
553                          user, myname, group, suffix));
554 #ifdef WITH_AUDIT
555                 snprintf (buf, 1023,
556                           "user %s removed by %s from group %s%s",
557                           user, myname, group, suffix);
558                 buf[1023] = '\0';
559                 audit_logger (AUDIT_USER_ACCT, Prog,
560                               buf,
561                               group, AUDIT_NO_ID,
562                               SHADOW_AUDIT_SUCCESS);
563 #endif
564         } else if (rflg) {
565                 SYSLOG ((LOG_INFO,
566                          "password of group %s removed by %s%s",
567                          group, myname, suffix));
568 #ifdef WITH_AUDIT
569                 snprintf (buf, 1023,
570                           "password of group %s removed by %s%s",
571                           group, myname, suffix);
572                 buf[1023] = '\0';
573                 audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
574                               buf,
575                               group, AUDIT_NO_ID,
576                               SHADOW_AUDIT_SUCCESS);
577 #endif
578         } else if (Rflg) {
579                 SYSLOG ((LOG_INFO,
580                          "access to group %s restricted by %s%s",
581                          group, myname, suffix));
582 #ifdef WITH_AUDIT
583                 snprintf (buf, 1023,
584                           "access to group %s restricted by %s%s",
585                           group, myname, suffix);
586                 buf[1023] = '\0';
587                 audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
588                               buf,
589                               group, AUDIT_NO_ID,
590                               SHADOW_AUDIT_SUCCESS);
591 #endif
592         } else if (Aflg || Mflg) {
593 #ifdef SHADOWGRP
594                 if (Aflg) {
595                         SYSLOG ((LOG_INFO,
596                                  "administrators of group %s set by %s to %s%s",
597                                  group, myname, admins, suffix));
598 #ifdef WITH_AUDIT
599                         snprintf (buf, 1023,
600                                   "administrators of group %s set by %s to %s%s",
601                                   group, myname, admins, suffix);
602                         buf[1023] = '\0';
603                         audit_logger (AUDIT_USER_ACCT, Prog,
604                                       buf,
605                                       group, AUDIT_NO_ID,
606                                       SHADOW_AUDIT_SUCCESS);
607 #endif
608                 }
609 #endif                          /* SHADOWGRP */
610                 if (Mflg) {
611                         SYSLOG ((LOG_INFO,
612                                  "members of group %s set by %s to %s%s",
613                                  group, myname, members, suffix));
614 #ifdef WITH_AUDIT
615                         snprintf (buf, 1023,
616                                   "members of group %s set by %s to %s%s",
617                                   group, myname, members, suffix);
618                         buf[1023] = '\0';
619                         audit_logger (AUDIT_USER_ACCT, Prog,
620                                       buf,
621                                       group, AUDIT_NO_ID,
622                                       SHADOW_AUDIT_SUCCESS);
623 #endif
624                 }
625         } else {
626                 SYSLOG ((LOG_INFO,
627                          "password of group %s changed by %s%s",
628                          group, myname, suffix));
629 #ifdef WITH_AUDIT
630                 snprintf (buf, 1023,
631                           "password of group %s changed by %s%s",
632                           group, myname, suffix);
633                 buf[1023] = '\0';
634                 audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
635                               buf,
636                               group, AUDIT_NO_ID,
637                               SHADOW_AUDIT_SUCCESS);
638 #endif
639         }
640 }
641
642 static void log_gpasswd_success_system (unused void *arg)
643 {
644         log_gpasswd_success ("");
645 }
646
647 static void log_gpasswd_success_group (unused void *arg)
648 {
649         char buf[1024];
650         snprintf (buf, 1023, " in %s", gr_dbname ());
651         buf[1023] = '\0';
652         log_gpasswd_success (buf);
653 }
654
655 /*
656  * close_files - close and unlock the group databases
657  *
658  *      This cause any changes in the databases to be committed.
659  *
660  *      It will call exit in case of error.
661  */
662 static void close_files (void)
663 {
664         if (gr_close () == 0) {
665                 fprintf (stderr,
666                          _("%s: failure while writing changes to %s\n"),
667                          Prog, gr_dbname ());
668                 exit (E_NOPERM);
669         }
670         add_cleanup (log_gpasswd_success_group, NULL);
671         del_cleanup (log_gpasswd_failure_group);
672
673         cleanup_unlock_group (NULL);
674         del_cleanup (cleanup_unlock_group);
675
676 #ifdef SHADOWGRP
677         if (is_shadowgrp) {
678                 if (sgr_close () == 0) {
679                         fprintf (stderr,
680                                  _("%s: failure while writing changes to %s\n"),
681                                  Prog, sgr_dbname ());
682                         exit (E_NOPERM);
683                 }
684                 del_cleanup (log_gpasswd_failure_gshadow);
685
686                 cleanup_unlock_gshadow (NULL);
687                 del_cleanup (cleanup_unlock_gshadow);
688         }
689 #endif                          /* SHADOWGRP */
690
691         log_gpasswd_success_system (NULL);
692         del_cleanup (log_gpasswd_success_group);
693 }
694
695 /*
696  * check_perms - check if the user is allowed to change the password of
697  *               the specified group.
698  *
699  *      It only returns if the user is allowed.
700  */
701 #ifdef SHADOWGRP
702 static void check_perms (const struct group *gr, const struct sgrp *sg)
703 #else
704 static void check_perms (const struct group *gr)
705 #endif
706 {
707         /*
708          * Only root can use the -M and -A options.
709          */
710         if (!amroot && (Aflg || Mflg)) {
711                 failure ();
712         }
713
714 #ifdef SHADOWGRP
715         if (is_shadowgrp) {
716                 /*
717                  * The policy here for changing a group is that
718                  * 1) you must be root or
719                  * 2) you must be listed as an administrative member.
720                  * Administrative members can do anything to a group that
721                  * the root user can.
722                  */
723                 if (!amroot && !is_on_list (sg->sg_adm, myname)) {
724                         failure ();
725                 }
726         } else
727 #endif                          /* SHADOWGRP */
728         {
729 #ifdef FIRST_MEMBER_IS_ADMIN
730                 /*
731                  * The policy here for changing a group is that
732                  * 1) you must be root or
733                  * 2) you must be the first listed member of the group.
734                  * The first listed member of a group can do anything to
735                  * that group that the root user can. The rationale for
736                  * this hack is that the FIRST user is probably the most
737                  * important user in this entire group.
738                  *
739                  * This feature enabled by default could be a security
740                  * problem when installed on existing systems where the
741                  * first group member might be just a normal user.
742                  * --marekm
743                  */
744                 if (!amroot) {
745                         if (gr->gr_mem[0] == (char *) 0) {
746                                 failure ();
747                         }
748
749                         if (strcmp (gr->gr_mem[0], myname) != 0) {
750                                 failure ();
751                         }
752                 }
753 #else                           /* ! FIRST_MEMBER_IS_ADMIN */
754                 if (!amroot) {
755                         failure ();
756                 }
757 #endif
758         }
759 }
760
761 /*
762  * update_group - Update the group information in the databases
763  */
764 #ifdef SHADOWGRP
765 static void update_group (struct group *gr, struct sgrp *sg)
766 #else
767 static void update_group (struct group *gr)
768 #endif
769 {
770         if (gr_update (gr) == 0) {
771                 fprintf (stderr,
772                          _("%s: failed to prepare the new %s entry '%s'\n"),
773                          Prog, gr_dbname (), gr->gr_name);
774                 exit (1);
775         }
776 #ifdef SHADOWGRP
777         if (is_shadowgrp && (sgr_update (sg) == 0)) {
778                 fprintf (stderr,
779                          _("%s: failed to prepare the new %s entry '%s'\n"),
780                          Prog, sgr_dbname (), sg->sg_name);
781                 exit (1);
782         }
783 #endif                          /* SHADOWGRP */
784 }
785
786 /*
787  * get_group - get the current information for the group
788  *
789  *      The information are copied in group structure(s) so that they can be
790  *      modified later.
791  *
792  *      Note: If !is_shadowgrp, *sg will not be initialized.
793  */
794 #ifdef SHADOWGRP
795 static void get_group (struct group *gr, struct sgrp *sg)
796 #else
797 static void get_group (struct group *gr)
798 #endif
799 {
800         struct group const*tmpgr = NULL;
801 #ifdef SHADOWGRP
802         struct sgrp const*tmpsg = NULL;
803 #endif
804
805         if (gr_open (O_RDONLY) == 0) {
806                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
807                 SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
808                 exit (E_NOPERM);
809         }
810
811         tmpgr = gr_locate (group);
812         if (NULL == tmpgr) {
813                 fprintf (stderr,
814                          _("%s: group '%s' does not exist in %s\n"),
815                          Prog, group, gr_dbname ());
816                 exit (E_BAD_ARG);
817         }
818
819         *gr = *tmpgr;
820         gr->gr_name = xstrdup (tmpgr->gr_name);
821         gr->gr_passwd = xstrdup (tmpgr->gr_passwd);
822         gr->gr_mem = dup_list (tmpgr->gr_mem);
823
824         if (gr_close () == 0) {
825                 fprintf (stderr,
826                          _("%s: failure while closing read-only %s\n"),
827                          Prog, gr_dbname ());
828                 SYSLOG ((LOG_ERR,
829                          "failure while closing read-only %s",
830                          gr_dbname ()));
831                 exit (E_NOPERM);
832         }
833
834 #ifdef SHADOWGRP
835         if (is_shadowgrp) {
836                 if (sgr_open (O_RDONLY) == 0) {
837                         fprintf (stderr,
838                                  _("%s: cannot open %s\n"),
839                                  Prog, sgr_dbname ());
840                         SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
841                         exit (E_NOPERM);
842                 }
843                 tmpsg = sgr_locate (group);
844                 if (NULL != tmpsg) {
845                         *sg = *tmpsg;
846                         sg->sg_name = xstrdup (tmpsg->sg_name);
847                         sg->sg_passwd = xstrdup (tmpsg->sg_passwd);
848
849                         sg->sg_mem = dup_list (tmpsg->sg_mem);
850                         sg->sg_adm = dup_list (tmpsg->sg_adm);
851                 } else {
852                         sg->sg_name = xstrdup (group);
853                         sg->sg_passwd = gr->gr_passwd;
854                         gr->gr_passwd = SHADOW_PASSWD_STRING;   /* XXX warning: const */
855
856                         sg->sg_mem = dup_list (gr->gr_mem);
857
858                         sg->sg_adm = (char **) xmalloc (sizeof (char *) * 2);
859 #ifdef FIRST_MEMBER_IS_ADMIN
860                         if (sg->sg_mem[0]) {
861                                 sg->sg_adm[0] = xstrdup (sg->sg_mem[0]);
862                                 sg->sg_adm[1] = NULL;
863                         } else
864 #endif
865                         {
866                                 sg->sg_adm[0] = NULL;
867                         }
868
869                 }
870                 if (sgr_close () == 0) {
871                         fprintf (stderr,
872                                  _("%s: failure while closing read-only %s\n"),
873                                  Prog, sgr_dbname ());
874                         SYSLOG ((LOG_ERR,
875                                  "failure while closing read-only %s",
876                                  sgr_dbname ()));
877                         exit (E_NOPERM);
878                 }
879         }
880 #endif                          /* SHADOWGRP */
881 }
882
883 /*
884  * change_passwd - change the group's password
885  *
886  *      Get the new password from the user and update the password in the
887  *      group's structure.
888  *
889  *      It will call exit in case of error.
890  */
891 #ifdef SHADOWGRP
892 static void change_passwd (struct group *gr, struct sgrp *sg)
893 #else
894 static void change_passwd (struct group *gr)
895 #endif
896 {
897         char *cp;
898         static char pass[BUFSIZ];
899         int retries;
900
901         /*
902          * A new password is to be entered and it must be encrypted, etc.
903          * The password will be prompted for twice, and both entries must be
904          * identical. There is no need to validate the old password since
905          * the invoker is either the group owner, or root.
906          */
907         printf (_("Changing the password for group %s\n"), group);
908
909         for (retries = 0; retries < RETRIES; retries++) {
910                 cp = getpass (_("New Password: "));
911                 if (NULL == cp) {
912                         exit (1);
913                 }
914
915                 STRFCPY (pass, cp);
916                 strzero (cp);
917                 cp = getpass (_("Re-enter new password: "));
918                 if (NULL == cp) {
919                         exit (1);
920                 }
921
922                 if (strcmp (pass, cp) == 0) {
923                         strzero (cp);
924                         break;
925                 }
926
927                 strzero (cp);
928                 memzero (pass, sizeof pass);
929
930                 if (retries + 1 < RETRIES) {
931                         puts (_("They don't match; try again"));
932                 }
933         }
934
935         if (retries == RETRIES) {
936                 fprintf (stderr, _("%s: Try again later\n"), Prog);
937                 exit (1);
938         }
939
940         cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
941         memzero (pass, sizeof pass);
942 #ifdef SHADOWGRP
943         if (is_shadowgrp) {
944                 sg->sg_passwd = cp;
945         } else
946 #endif
947         {
948                 gr->gr_passwd = cp;
949         }
950 }
951
952 /*
953  * gpasswd - administer the /etc/group file
954  */
955 int main (int argc, char **argv)
956 {
957         struct group grent;
958 #ifdef SHADOWGRP
959         struct sgrp sgent;
960 #endif
961         struct passwd *pw = NULL;
962
963 #ifdef WITH_AUDIT
964         audit_help_open ();
965 #endif
966
967         sanitize_env ();
968         (void) setlocale (LC_ALL, "");
969         (void) bindtextdomain (PACKAGE, LOCALEDIR);
970         (void) textdomain (PACKAGE);
971
972         /*
973          * Make a note of whether or not this command was invoked by root.
974          * This will be used to bypass certain checks later on. Also, set
975          * the real user ID to match the effective user ID. This will
976          * prevent the invoker from issuing signals which would interfere
977          * with this command.
978          */
979         bywho = getuid ();
980         Prog = Basename (argv[0]);
981
982         OPENLOG ("gpasswd");
983         setbuf (stdout, NULL);
984         setbuf (stderr, NULL);
985
986         process_root_flag ("-Q", argc, argv);
987
988 #ifdef SHADOWGRP
989         is_shadowgrp = sgr_file_present ();
990 #endif
991
992         /*
993          * Determine the name of the user that invoked this command. This
994          * is really hit or miss because there are so many ways that command
995          * can be executed and so many ways to trip up the routines that
996          * report the user name.
997          */
998         pw = get_my_pwent ();
999         if (NULL == pw) {
1000                 fprintf (stderr, _("%s: Cannot determine your user name.\n"),
1001                          Prog);
1002                 SYSLOG ((LOG_WARN,
1003                          "Cannot determine the user name of the caller (UID %lu)",
1004                          (unsigned long) getuid ()));
1005                 exit (E_NOPERM);
1006         }
1007         myname = xstrdup (pw->pw_name);
1008
1009         /*
1010          * Register an exit function to warn for any inconsistency that we
1011          * could create.
1012          */
1013         if (atexit (do_cleanups) != 0) {
1014                 fprintf(stderr, "%s: cannot set exit function\n", Prog);
1015                 exit (1);
1016         }
1017
1018         /* Parse the options */
1019         process_flags (argc, argv);
1020
1021         /*
1022          * Replicate the group so it can be modified later on.
1023          */
1024 #ifdef SHADOWGRP
1025         get_group (&grent, &sgent);
1026 #else
1027         get_group (&grent);
1028 #endif
1029
1030         /*
1031          * Check if the user is allowed to change the password of this group.
1032          */
1033 #ifdef SHADOWGRP
1034         check_perms (&grent, &sgent);
1035 #else
1036         check_perms (&grent);
1037 #endif
1038
1039         /*
1040          * Removing a password is straight forward. Just set the password
1041          * field to a "".
1042          */
1043         if (rflg) {
1044                 grent.gr_passwd = "";   /* XXX warning: const */
1045 #ifdef SHADOWGRP
1046                 sgent.sg_passwd = "";   /* XXX warning: const */
1047 #endif
1048                 goto output;
1049         } else if (Rflg) {
1050                 /*
1051                  * Same thing for restricting the group. Set the password
1052                  * field to "!".
1053                  */
1054                 grent.gr_passwd = "!";  /* XXX warning: const */
1055 #ifdef SHADOWGRP
1056                 sgent.sg_passwd = "!";  /* XXX warning: const */
1057 #endif
1058                 goto output;
1059         }
1060
1061         /*
1062          * Adding a member to a member list is pretty straightforward as
1063          * well. Call the appropriate routine and split.
1064          */
1065         if (aflg) {
1066                 printf (_("Adding user %s to group %s\n"), user, group);
1067                 grent.gr_mem = add_list (grent.gr_mem, user);
1068 #ifdef SHADOWGRP
1069                 if (is_shadowgrp) {
1070                         sgent.sg_mem = add_list (sgent.sg_mem, user);
1071                 }
1072 #endif
1073                 goto output;
1074         }
1075
1076         /*
1077          * Removing a member from the member list is the same deal as adding
1078          * one, except the routine is different.
1079          */
1080         if (dflg) {
1081                 bool removed = false;
1082
1083                 printf (_("Removing user %s from group %s\n"), user, group);
1084
1085                 if (is_on_list (grent.gr_mem, user)) {
1086                         removed = true;
1087                         grent.gr_mem = del_list (grent.gr_mem, user);
1088                 }
1089 #ifdef SHADOWGRP
1090                 if (is_shadowgrp) {
1091                         if (is_on_list (sgent.sg_mem, user)) {
1092                                 removed = true;
1093                                 sgent.sg_mem = del_list (sgent.sg_mem, user);
1094                         }
1095                 }
1096 #endif
1097                 if (!removed) {
1098                         fprintf (stderr,
1099                                  _("%s: user '%s' is not a member of '%s'\n"),
1100                                  Prog, user, group);
1101                         exit (E_BAD_ARG);
1102                 }
1103                 goto output;
1104         }
1105 #ifdef SHADOWGRP
1106         /*
1107          * Replacing the entire list of administrators is simple. Check the
1108          * list to make sure everyone is a real user. Then slap the new list
1109          * in place.
1110          */
1111         if (Aflg) {
1112                 sgent.sg_adm = comma_to_list (admins);
1113                 if (!Mflg) {
1114                         goto output;
1115                 }
1116         }
1117 #endif                          /* SHADOWGRP */
1118
1119         /*
1120          * Replacing the entire list of members is simple. Check the list to
1121          * make sure everyone is a real user. Then slap the new list in
1122          * place.
1123          */
1124         if (Mflg) {
1125 #ifdef SHADOWGRP
1126                 sgent.sg_mem = comma_to_list (members);
1127 #endif
1128                 grent.gr_mem = comma_to_list (members);
1129                 goto output;
1130         }
1131
1132         /*
1133          * If the password is being changed, the input and output must both
1134          * be a tty. The typical keyboard signals are caught so the termio
1135          * modes can be restored.
1136          */
1137         if ((isatty (0) == 0) || (isatty (1) == 0)) {
1138                 fprintf (stderr, _("%s: Not a tty\n"), Prog);
1139                 exit (E_NOPERM);
1140         }
1141
1142         catch_signals (0);      /* save tty modes */
1143
1144         (void) signal (SIGHUP, catch_signals);
1145         (void) signal (SIGINT, catch_signals);
1146         (void) signal (SIGQUIT, catch_signals);
1147         (void) signal (SIGTERM, catch_signals);
1148 #ifdef SIGTSTP
1149         (void) signal (SIGTSTP, catch_signals);
1150 #endif
1151
1152         /* Prompt for the new password */
1153 #ifdef SHADOWGRP
1154         change_passwd (&grent, &sgent);
1155 #else
1156         change_passwd (&grent);
1157 #endif
1158
1159         /*
1160          * This is the common arrival point to output the new group file.
1161          * The freshly crafted entry is in allocated space. The group file
1162          * will be locked and opened for writing. The new entry will be
1163          * output, etc.
1164          */
1165       output:
1166         if (setuid (0) != 0) {
1167                 fputs (_("Cannot change ID to root.\n"), stderr);
1168                 SYSLOG ((LOG_ERR, "can't setuid(0)"));
1169                 closelog ();
1170                 exit (E_NOPERM);
1171         }
1172         pwd_init ();
1173
1174         open_files ();
1175
1176 #ifdef SHADOWGRP
1177         update_group (&grent, &sgent);
1178 #else
1179         update_group (&grent);
1180 #endif
1181
1182         close_files ();
1183
1184         nscd_flush_cache ("group");
1185
1186         exit (E_SUCCESS);
1187 }
1188