]> granicus.if.org Git - shadow/blob - src/gpasswd.c
* NEWS, src/userdel.c, src/lastlog.c, src/gpasswd.c,
[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 - 2009, 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 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 #ifdef SHADOWGRP
125 static void log_gpasswd_success_gshadow (unused void *arg);
126 #endif
127
128 /*
129  * usage - display usage message
130  */
131 static void usage (int status)
132 {
133         fprintf (status ? stderr : stdout,
134                  _("Usage: %s [option] GROUP\n"
135                    "\n"
136                    "Options:\n"
137                    "  -a, --add USER                add USER to GROUP\n"
138                    "  -d, --delete USER             remove USER from GROUP\n"
139                    "  -h, --help                    display this help message and exit\n"
140                    "  -r, --remove-password         remove the GROUP's password\n"
141                    "  -R, --restrict                restrict access to GROUP to its members\n"
142                    "  -M, --members USER,...        set the list of members of GROUP\n"
143                    "%s\n"
144                    "\n"),
145                  Prog,
146 #ifdef SHADOWGRP
147                  _("  -A, --administrators ADMIN,...\n"
148                    "                                set the list of administrators for GROUP\n"
149                    "Except for the -A and -M options, the options cannot be combined.\n")
150 #else
151                  _("The options cannot be combined.\n")
152 #endif
153                 );
154         exit (status);
155 }
156
157 /*
158  * catch_signals - set or reset termio modes.
159  *
160  *      catch_signals() is called before processing begins. signal() is then
161  *      called with catch_signals() as the signal handler. If signal later
162  *      calls catch_signals() with a signal number, the terminal modes are
163  *      then reset.
164  */
165 static RETSIGTYPE catch_signals (int killed)
166 {
167         static TERMIO sgtty;
168
169         if (0 != killed) {
170                 STTY (0, &sgtty);
171         } else {
172                 GTTY (0, &sgtty);
173         }
174
175         if (0 != killed) {
176                 (void) putchar ('\n');
177                 (void) fflush (stdout);
178                 exit (killed);
179         }
180 }
181
182 /*
183  * is_valid_user_list - check a comma-separated list of user names for validity
184  *
185  *      is_valid_user_list scans a comma-separated list of user names and
186  *      checks that each listed name exists is the user database.
187  *
188  *      It returns true if the list of users is valid.
189  */
190 static bool is_valid_user_list (const char *users)
191 {
192         char *username, *end;
193         bool is_valid = true;
194         char *tmpusers = xstrdup (users);
195
196         for (username = tmpusers;
197              (NULL != username) && ('\0' != *username);
198              username = end) {
199                 end = strchr (username, ',');
200                 if (NULL != end) {
201                         *end = '\0';
202                         end++;
203                 }
204
205                 /*
206                  * This user must exist.
207                  */
208
209                 /* local, no need for xgetpwnam */
210                 if (getpwnam (username) == NULL) {
211                         fprintf (stderr, _("%s: user '%s' does not exist\n"),
212                                  Prog, username);
213                         is_valid = false;
214                 }
215         }
216
217         free (tmpusers);
218
219         return is_valid;
220 }
221
222 static void failure (void)
223 {
224         fprintf (stderr, _("%s: Permission denied.\n"), Prog);
225         log_gpasswd_failure (": Permission denied");
226         exit (E_NOPERM);
227 }
228
229 /*
230  * process_flags - process the command line options and arguments
231  */
232 static void process_flags (int argc, char **argv)
233 {
234         int flag;
235         int option_index = 0;
236         static struct option long_options[] = {
237                 {"add", required_argument, NULL, 'a'},
238                 {"delete", required_argument, NULL, 'd'},
239                 {"help", no_argument, NULL, 'h'},
240                 {"remove-password", no_argument, NULL, 'r'},
241                 {"restrict", no_argument, NULL, 'R'},
242                 {"administrators", required_argument, NULL, 'A'},
243                 {"members", required_argument, NULL, 'M'},
244                 {NULL, 0, NULL, '\0'}
245                 };
246
247         while ((flag = getopt_long (argc, argv, "a:A:d:ghM:rR", long_options, &option_index)) != -1) {
248                 switch (flag) {
249                 case 'a':       /* add a user */
250                         aflg = true;
251                         user = optarg;
252                         /* local, no need for xgetpwnam */
253                         if (getpwnam (user) == NULL) {
254                                 fprintf (stderr,
255                                          _("%s: user '%s' does not exist\n"),
256                                          Prog, user);
257                                 exit (E_BAD_ARG);
258                         }
259                         break;
260 #ifdef SHADOWGRP
261                 case 'A':       /* set the list of administrators */
262                         if (!is_shadowgrp) {
263                                 fprintf (stderr,
264                                          _("%s: shadow group passwords required for -A\n"),
265                                          Prog);
266                                 exit (E_GSHADOW_NOTFOUND);
267                         }
268                         admins = optarg;
269                         if (!is_valid_user_list (admins)) {
270                                 exit (E_BAD_ARG);
271                         }
272                         Aflg = true;
273                         break;
274 #endif                          /* SHADOWGRP */
275                 case 'd':       /* delete a user */
276                         dflg = true;
277                         user = optarg;
278                         break;
279                 case 'g':       /* no-op from normal password */
280                         break;
281                 case 'h':
282                         usage (E_SUCCESS);
283                 case 'M':       /* set the list of members */
284                         members = optarg;
285                         if (!is_valid_user_list (members)) {
286                                 exit (E_BAD_ARG);
287                         }
288                         Mflg = true;
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 #ifdef SHADOWGRP
656 static void log_gpasswd_success_gshadow (unused void *arg)
657 {
658         char buf[1024];
659         snprintf (buf, 1023, " in %s", sgr_dbname ());
660         buf[1023] = '\0';
661         log_gpasswd_success (buf);
662 }
663 #endif                          /* SHADOWGRP */
664
665 /*
666  * close_files - close and unlock the group databases
667  *
668  *      This cause any changes in the databases to be committed.
669  *
670  *      It will call exit in case of error.
671  */
672 static void close_files (void)
673 {
674         if (gr_close () == 0) {
675                 fprintf (stderr,
676                          _("%s: failure while writing changes to %s\n"),
677                          Prog, gr_dbname ());
678                 exit (E_NOPERM);
679         }
680         add_cleanup (log_gpasswd_success_group, NULL);
681         del_cleanup (log_gpasswd_failure_group);
682
683         cleanup_unlock_group (NULL);
684         del_cleanup (cleanup_unlock_group);
685
686 #ifdef SHADOWGRP
687         if (is_shadowgrp) {
688                 if (sgr_close () == 0) {
689                         fprintf (stderr,
690                                  _("%s: failure while writing changes to %s\n"),
691                                  Prog, sgr_dbname ());
692                         exit (E_NOPERM);
693                 }
694                 add_cleanup (log_gpasswd_success_gshadow, NULL);
695                 del_cleanup (log_gpasswd_failure_gshadow);
696
697                 cleanup_unlock_gshadow (NULL);
698                 del_cleanup (cleanup_unlock_gshadow);
699         }
700 #endif                          /* SHADOWGRP */
701
702         log_gpasswd_success_system (NULL);
703         del_cleanup (log_gpasswd_success_group);
704 #ifdef SHADOWGRP
705         if (is_shadowgrp) {
706                 del_cleanup (log_gpasswd_success_gshadow);
707         }
708 #endif
709 }
710
711 /*
712  * check_perms - check if the user is allowed to change the password of
713  *               the specified group.
714  *
715  *      It only returns if the user is allowed.
716  */
717 #ifdef SHADOWGRP
718 static void check_perms (const struct group *gr, const struct sgrp *sg)
719 #else
720 static void check_perms (const struct group *gr)
721 #endif
722 {
723         /*
724          * Only root can use the -M and -A options.
725          */
726         if (!amroot && (Aflg || Mflg)) {
727                 failure ();
728         }
729
730 #ifdef SHADOWGRP
731         if (is_shadowgrp) {
732                 /*
733                  * The policy here for changing a group is that
734                  * 1) you must be root or
735                  * 2) you must be listed as an administrative member.
736                  * Administrative members can do anything to a group that
737                  * the root user can.
738                  */
739                 if (!amroot && !is_on_list (sg->sg_adm, myname)) {
740                         failure ();
741                 }
742         } else
743 #endif                          /* SHADOWGRP */
744         {
745 #ifdef FIRST_MEMBER_IS_ADMIN
746                 /*
747                  * The policy here for changing a group is that
748                  * 1) you must be root or
749                  * 2) you must be the first listed member of the group.
750                  * The first listed member of a group can do anything to
751                  * that group that the root user can. The rationale for
752                  * this hack is that the FIRST user is probably the most
753                  * important user in this entire group.
754                  *
755                  * This feature enabled by default could be a security
756                  * problem when installed on existing systems where the
757                  * first group member might be just a normal user.
758                  * --marekm
759                  */
760                 if (!amroot) {
761                         if (gr->gr_mem[0] == (char *) 0) {
762                                 failure ();
763                         }
764
765                         if (strcmp (gr->gr_mem[0], myname) != 0) {
766                                 failure ();
767                         }
768                 }
769 #else                           /* ! FIRST_MEMBER_IS_ADMIN */
770                 if (!amroot) {
771                         failure ();
772                 }
773 #endif
774         }
775 }
776
777 /*
778  * update_group - Update the group information in the databases
779  */
780 #ifdef SHADOWGRP
781 static void update_group (struct group *gr, struct sgrp *sg)
782 #else
783 static void update_group (struct group *gr)
784 #endif
785 {
786         if (gr_update (gr) == 0) {
787                 fprintf (stderr,
788                          _("%s: failed to prepare the new %s entry '%s'\n"),
789                          Prog, gr_dbname (), gr->gr_name);
790                 exit (1);
791         }
792 #ifdef SHADOWGRP
793         if (is_shadowgrp && (sgr_update (sg) == 0)) {
794                 fprintf (stderr,
795                          _("%s: failed to prepare the new %s entry '%s'\n"),
796                          Prog, sgr_dbname (), sg->sg_name);
797                 exit (1);
798         }
799 #endif                          /* SHADOWGRP */
800 }
801
802 /*
803  * get_group - get the current information for the group
804  *
805  *      The information are copied in group structure(s) so that they can be
806  *      modified later.
807  *
808  *      Note: If !is_shadowgrp, *sg will not be initialized.
809  */
810 #ifdef SHADOWGRP
811 static void get_group (struct group *gr, struct sgrp *sg)
812 #else
813 static void get_group (struct group *gr)
814 #endif
815 {
816         struct group const*tmpgr = NULL;
817 #ifdef SHADOWGRP
818         struct sgrp const*tmpsg = NULL;
819 #endif
820
821         if (gr_open (O_RDONLY) == 0) {
822                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
823                 SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
824                 exit (E_NOPERM);
825         }
826
827         tmpgr = gr_locate (group);
828         if (NULL == tmpgr) {
829                 fprintf (stderr,
830                          _("%s: group '%s' does not exist in %s\n"),
831                          Prog, group, gr_dbname ());
832                 exit (E_BAD_ARG);
833         }
834
835         *gr = *tmpgr;
836         gr->gr_name = xstrdup (tmpgr->gr_name);
837         gr->gr_passwd = xstrdup (tmpgr->gr_passwd);
838         gr->gr_mem = dup_list (tmpgr->gr_mem);
839
840         if (gr_close () == 0) {
841                 fprintf (stderr,
842                          _("%s: failure while closing read-only %s\n"),
843                          Prog, gr_dbname ());
844                 SYSLOG ((LOG_ERR,
845                          "failure while closing read-only %s",
846                          gr_dbname ()));
847                 exit (E_NOPERM);
848         }
849
850 #ifdef SHADOWGRP
851         if (is_shadowgrp) {
852                 if (sgr_open (O_RDONLY) == 0) {
853                         fprintf (stderr,
854                                  _("%s: cannot open %s\n"),
855                                  Prog, sgr_dbname ());
856                         SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
857                         exit (E_NOPERM);
858                 }
859                 tmpsg = sgr_locate (group);
860                 if (NULL != tmpsg) {
861                         *sg = *tmpsg;
862                         sg->sg_name = xstrdup (tmpsg->sg_name);
863                         sg->sg_passwd = xstrdup (tmpsg->sg_passwd);
864
865                         sg->sg_mem = dup_list (tmpsg->sg_mem);
866                         sg->sg_adm = dup_list (tmpsg->sg_adm);
867                 } else {
868                         sg->sg_name = xstrdup (group);
869                         sg->sg_passwd = gr->gr_passwd;
870                         gr->gr_passwd = SHADOW_PASSWD_STRING;   /* XXX warning: const */
871
872                         sg->sg_mem = dup_list (gr->gr_mem);
873
874                         sg->sg_adm = (char **) xmalloc (sizeof (char *) * 2);
875 #ifdef FIRST_MEMBER_IS_ADMIN
876                         if (sg->sg_mem[0]) {
877                                 sg->sg_adm[0] = xstrdup (sg->sg_mem[0]);
878                                 sg->sg_adm[1] = NULL;
879                         } else
880 #endif
881                         {
882                                 sg->sg_adm[0] = NULL;
883                         }
884
885                 }
886                 if (sgr_close () == 0) {
887                         fprintf (stderr,
888                                  _("%s: failure while closing read-only %s\n"),
889                                  Prog, sgr_dbname ());
890                         SYSLOG ((LOG_ERR,
891                                  "failure while closing read-only %s",
892                                  sgr_dbname ()));
893                         exit (E_NOPERM);
894                 }
895         }
896 #endif                          /* SHADOWGRP */
897 }
898
899 /*
900  * change_passwd - change the group's password
901  *
902  *      Get the new password from the user and update the password in the
903  *      group's structure.
904  *
905  *      It will call exit in case of error.
906  */
907 #ifdef SHADOWGRP
908 static void change_passwd (struct group *gr, struct sgrp *sg)
909 #else
910 static void change_passwd (struct group *gr)
911 #endif
912 {
913         char *cp;
914         static char pass[BUFSIZ];
915         int retries;
916
917         /*
918          * A new password is to be entered and it must be encrypted, etc.
919          * The password will be prompted for twice, and both entries must be
920          * identical. There is no need to validate the old password since
921          * the invoker is either the group owner, or root.
922          */
923         printf (_("Changing the password for group %s\n"), group);
924
925         for (retries = 0; retries < RETRIES; retries++) {
926                 cp = getpass (_("New Password: "));
927                 if (NULL == cp) {
928                         exit (1);
929                 }
930
931                 STRFCPY (pass, cp);
932                 strzero (cp);
933                 cp = getpass (_("Re-enter new password: "));
934                 if (NULL == cp) {
935                         exit (1);
936                 }
937
938                 if (strcmp (pass, cp) == 0) {
939                         strzero (cp);
940                         break;
941                 }
942
943                 strzero (cp);
944                 memzero (pass, sizeof pass);
945
946                 if (retries + 1 < RETRIES) {
947                         puts (_("They don't match; try again"));
948                 }
949         }
950
951         if (retries == RETRIES) {
952                 fprintf (stderr, _("%s: Try again later\n"), Prog);
953                 exit (1);
954         }
955
956         cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
957         memzero (pass, sizeof pass);
958 #ifdef SHADOWGRP
959         if (is_shadowgrp) {
960                 sg->sg_passwd = cp;
961         } else
962 #endif
963         {
964                 gr->gr_passwd = cp;
965         }
966 }
967
968 /*
969  * gpasswd - administer the /etc/group file
970  */
971 int main (int argc, char **argv)
972 {
973         struct group grent;
974 #ifdef SHADOWGRP
975         struct sgrp sgent;
976 #endif
977         struct passwd *pw = NULL;
978
979 #ifdef WITH_AUDIT
980         audit_help_open ();
981 #endif
982
983         sanitize_env ();
984         (void) setlocale (LC_ALL, "");
985         (void) bindtextdomain (PACKAGE, LOCALEDIR);
986         (void) textdomain (PACKAGE);
987
988         /*
989          * Make a note of whether or not this command was invoked by root.
990          * This will be used to bypass certain checks later on. Also, set
991          * the real user ID to match the effective user ID. This will
992          * prevent the invoker from issuing signals which would interfere
993          * with this command.
994          */
995         bywho = getuid ();
996         Prog = Basename (argv[0]);
997
998         OPENLOG ("gpasswd");
999         setbuf (stdout, NULL);
1000         setbuf (stderr, NULL);
1001
1002 #ifdef SHADOWGRP
1003         is_shadowgrp = sgr_file_present ();
1004 #endif
1005
1006         /*
1007          * Determine the name of the user that invoked this command. This
1008          * is really hit or miss because there are so many ways that command
1009          * can be executed and so many ways to trip up the routines that
1010          * report the user name.
1011          */
1012         pw = get_my_pwent ();
1013         if (NULL == pw) {
1014                 fprintf (stderr, _("%s: Cannot determine your user name.\n"),
1015                          Prog);
1016                 SYSLOG ((LOG_WARN,
1017                          "Cannot determine the user name of the caller (UID %lu)",
1018                          (unsigned long) getuid ()));
1019                 exit (E_NOPERM);
1020         }
1021         myname = xstrdup (pw->pw_name);
1022
1023         /*
1024          * Register an exit function to warn for any inconsistency that we
1025          * could create.
1026          */
1027         if (atexit (do_cleanups) != 0) {
1028                 fprintf(stderr, "%s: cannot set exit function\n", Prog);
1029                 exit (1);
1030         }
1031
1032         /* Parse the options */
1033         process_flags (argc, argv);
1034
1035         /*
1036          * Replicate the group so it can be modified later on.
1037          */
1038 #ifdef SHADOWGRP
1039         get_group (&grent, &sgent);
1040 #else
1041         get_group (&grent);
1042 #endif
1043
1044         /*
1045          * Check if the user is allowed to change the password of this group.
1046          */
1047 #ifdef SHADOWGRP
1048         check_perms (&grent, &sgent);
1049 #else
1050         check_perms (&grent);
1051 #endif
1052
1053         /*
1054          * Removing a password is straight forward. Just set the password
1055          * field to a "".
1056          */
1057         if (rflg) {
1058                 grent.gr_passwd = "";   /* XXX warning: const */
1059 #ifdef SHADOWGRP
1060                 sgent.sg_passwd = "";   /* XXX warning: const */
1061 #endif
1062                 goto output;
1063         } else if (Rflg) {
1064                 /*
1065                  * Same thing for restricting the group. Set the password
1066                  * field to "!".
1067                  */
1068                 grent.gr_passwd = "!";  /* XXX warning: const */
1069 #ifdef SHADOWGRP
1070                 sgent.sg_passwd = "!";  /* XXX warning: const */
1071 #endif
1072                 goto output;
1073         }
1074
1075         /*
1076          * Adding a member to a member list is pretty straightforward as
1077          * well. Call the appropriate routine and split.
1078          */
1079         if (aflg) {
1080                 printf (_("Adding user %s to group %s\n"), user, group);
1081                 grent.gr_mem = add_list (grent.gr_mem, user);
1082 #ifdef SHADOWGRP
1083                 if (is_shadowgrp) {
1084                         sgent.sg_mem = add_list (sgent.sg_mem, user);
1085                 }
1086 #endif
1087                 goto output;
1088         }
1089
1090         /*
1091          * Removing a member from the member list is the same deal as adding
1092          * one, except the routine is different.
1093          */
1094         if (dflg) {
1095                 bool removed = false;
1096
1097                 printf (_("Removing user %s from group %s\n"), user, group);
1098
1099                 if (is_on_list (grent.gr_mem, user)) {
1100                         removed = true;
1101                         grent.gr_mem = del_list (grent.gr_mem, user);
1102                 }
1103 #ifdef SHADOWGRP
1104                 if (is_shadowgrp) {
1105                         if (is_on_list (sgent.sg_mem, user)) {
1106                                 removed = true;
1107                                 sgent.sg_mem = del_list (sgent.sg_mem, user);
1108                         }
1109                 }
1110 #endif
1111                 if (!removed) {
1112                         fprintf (stderr,
1113                                  _("%s: user '%s' is not a member of '%s'\n"),
1114                                  Prog, user, group);
1115                         exit (E_BAD_ARG);
1116                 }
1117                 goto output;
1118         }
1119 #ifdef SHADOWGRP
1120         /*
1121          * Replacing the entire list of administrators is simple. Check the
1122          * list to make sure everyone is a real user. Then slap the new list
1123          * in place.
1124          */
1125         if (Aflg) {
1126                 sgent.sg_adm = comma_to_list (admins);
1127                 if (!Mflg) {
1128                         goto output;
1129                 }
1130         }
1131 #endif                          /* SHADOWGRP */
1132
1133         /*
1134          * Replacing the entire list of members is simple. Check the list to
1135          * make sure everyone is a real user. Then slap the new list in
1136          * place.
1137          */
1138         if (Mflg) {
1139 #ifdef SHADOWGRP
1140                 sgent.sg_mem = comma_to_list (members);
1141 #endif
1142                 grent.gr_mem = comma_to_list (members);
1143                 goto output;
1144         }
1145
1146         /*
1147          * If the password is being changed, the input and output must both
1148          * be a tty. The typical keyboard signals are caught so the termio
1149          * modes can be restored.
1150          */
1151         if ((isatty (0) == 0) || (isatty (1) == 0)) {
1152                 fprintf (stderr, _("%s: Not a tty\n"), Prog);
1153                 exit (E_NOPERM);
1154         }
1155
1156         catch_signals (0);      /* save tty modes */
1157
1158         (void) signal (SIGHUP, catch_signals);
1159         (void) signal (SIGINT, catch_signals);
1160         (void) signal (SIGQUIT, catch_signals);
1161         (void) signal (SIGTERM, catch_signals);
1162 #ifdef SIGTSTP
1163         (void) signal (SIGTSTP, catch_signals);
1164 #endif
1165
1166         /* Prompt for the new password */
1167 #ifdef SHADOWGRP
1168         change_passwd (&grent, &sgent);
1169 #else
1170         change_passwd (&grent);
1171 #endif
1172
1173         /*
1174          * This is the common arrival point to output the new group file.
1175          * The freshly crafted entry is in allocated space. The group file
1176          * will be locked and opened for writing. The new entry will be
1177          * output, etc.
1178          */
1179       output:
1180         if (setuid (0) != 0) {
1181                 fputs (_("Cannot change ID to root.\n"), stderr);
1182                 SYSLOG ((LOG_ERR, "can't setuid(0)"));
1183                 closelog ();
1184                 exit (E_NOPERM);
1185         }
1186         pwd_init ();
1187
1188         open_files ();
1189
1190 #ifdef SHADOWGRP
1191         update_group (&grent, &sgent);
1192 #else
1193         update_group (&grent);
1194 #endif
1195
1196         close_files ();
1197
1198         nscd_flush_cache ("group");
1199
1200         exit (E_SUCCESS);
1201 }
1202