]> granicus.if.org Git - shadow/blob - src/groupmod.c
* src/su.c: Extract export of environment from main().
[shadow] / src / groupmod.c
1 /*
2  * Copyright (c) 1991 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2000 - 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 <ctype.h>
38 #include <fcntl.h>
39 #include <getopt.h>
40 #include <grp.h>
41 #include <stdio.h>
42 #include <sys/types.h>
43 #ifdef ACCT_TOOLS_SETUID
44 #ifdef USE_PAM
45 #include "pam_defs.h"
46 #include <pwd.h>
47 #endif                          /* USE_PAM */
48 #endif                          /* ACCT_TOOLS_SETUID */
49 #include "chkname.h"
50 #include "defines.h"
51 #include "groupio.h"
52 #include "pwio.h"
53 #include "nscd.h"
54 #include "prototypes.h"
55 #ifdef  SHADOWGRP
56 #include "sgroupio.h"
57 #endif
58 /*
59  * exit status values
60  */
61 /*@-exitarg@*/
62 #define E_SUCCESS       0       /* success */
63 #define E_USAGE         2       /* invalid command syntax */
64 #define E_BAD_ARG       3       /* invalid argument to option */
65 #define E_GID_IN_USE    4       /* gid already in use (and no -o) */
66 #define E_NOTFOUND      6       /* specified group doesn't exist */
67 #define E_NAME_IN_USE   9       /* group name already in use */
68 #define E_GRP_UPDATE    10      /* can't update group file */
69 /*
70  * Global variables
71  */
72 const char *Prog;
73
74 #ifdef  SHADOWGRP
75 static bool is_shadow_grp;
76 #endif                          /* SHADOWGRP */
77 static char *group_name;
78 static char *group_newname;
79 static char *group_passwd;
80 static gid_t group_id;
81 static gid_t group_newid;
82
83 struct cleanup_info_mod info_passwd;
84 struct cleanup_info_mod info_group;
85 #ifdef  SHADOWGRP
86 struct cleanup_info_mod info_gshadow;
87 #endif
88
89 static bool
90     oflg = false,               /* permit non-unique group ID to be specified with -g */
91     gflg = false,               /* new ID value for the group */
92     nflg = false,               /* a new name has been specified for the group */
93     pflg = false;               /* new encrypted password */
94
95 /* local function prototypes */
96 static void usage (int status);
97 static void new_grent (struct group *);
98
99 #ifdef SHADOWGRP
100 static void new_sgent (struct sgrp *);
101 #endif
102 static void grp_update (void);
103 static void check_new_gid (void);
104 static void check_new_name (void);
105 static void process_flags (int, char **);
106 static void lock_files (void);
107 static void prepare_failure_reports (void);
108 static void open_files (void);
109 static void close_files (void);
110 static void update_primary_groups (gid_t ogid, gid_t ngid);
111
112 /*
113  * usage - display usage message and exit
114  */
115
116 static void usage (int status)
117 {
118         FILE *usageout = (E_SUCCESS != status) ? stderr : stdout;
119         (void) fprintf (usageout,
120                         _("Usage: %s [options] GROUP\n"
121                           "\n"
122                           "Options:\n"),
123                         Prog);
124         (void) fputs (_("  -g, --gid GID                 change the group ID to GID\n"), usageout);
125         (void) fputs (_("  -h, --help                    display this help message and exit\n"), usageout);
126         (void) fputs (_("  -n, --new-name NEW_GROUP      change the name to NEW_GROUP\n"), usageout);
127         (void) fputs (_("  -o, --non-unique              allow to use a duplicate (non-unique) GID\n"), usageout);
128         (void) fputs (_("  -p, --password PASSWORD       change the password to this (encrypted)\n"
129                         "                                PASSWORD\n"), usageout);
130         (void) fputs ("\n", usageout);
131         exit (status);
132 }
133
134 /*
135  * new_grent - updates the values in a group file entry
136  *
137  *      new_grent() takes all of the values that have been entered and fills
138  *      in a (struct group) with them.
139  */
140 static void new_grent (struct group *grent)
141 {
142         if (nflg) {
143                 grent->gr_name = xstrdup (group_newname);
144         }
145
146         if (gflg) {
147                 grent->gr_gid = group_newid;
148         }
149
150         if (pflg) {
151                 grent->gr_passwd = group_passwd;
152         }
153 }
154
155 #ifdef  SHADOWGRP
156 /*
157  * new_sgent - updates the values in a shadow group file entry
158  *
159  *      new_sgent() takes all of the values that have been entered and fills
160  *      in a (struct sgrp) with them.
161  */
162 static void new_sgent (struct sgrp *sgent)
163 {
164         if (nflg) {
165                 sgent->sg_name = xstrdup (group_newname);
166         }
167
168         if (pflg) {
169                 sgent->sg_passwd = group_passwd;
170         }
171 }
172 #endif                          /* SHADOWGRP */
173
174 /*
175  * grp_update - update group file entries
176  *
177  *      grp_update() updates the new records in the memory databases.
178  */
179 static void grp_update (void)
180 {
181         struct group grp;
182         const struct group *ogrp;
183
184 #ifdef  SHADOWGRP
185         struct sgrp sgrp;
186         const struct sgrp *osgrp = NULL;
187 #endif                          /* SHADOWGRP */
188
189         /*
190          * Get the current settings for this group.
191          */
192         ogrp = gr_locate (group_name);
193         if (!ogrp) {
194                 fprintf (stderr,
195                          _("%s: group '%s' does not exist in %s\n"),
196                          Prog, group_name, gr_dbname ());
197                 exit (E_GRP_UPDATE);
198         }
199         grp = *ogrp;
200         new_grent (&grp);
201 #ifdef  SHADOWGRP
202         if (   is_shadow_grp
203             && (pflg || nflg)) {
204                 osgrp = sgr_locate (group_name);
205                 if (NULL != osgrp) {
206                         sgrp = *osgrp;
207                         new_sgent (&sgrp);
208                         if (pflg) {
209                                 grp.gr_passwd = SHADOW_PASSWD_STRING;
210                         }
211                 }
212         }
213 #endif                          /* SHADOWGRP */
214
215         if (gflg) {
216                 update_primary_groups (ogrp->gr_gid, group_newid);
217         }
218
219         /*
220          * Write out the new group file entry.
221          */
222         if (gr_update (&grp) == 0) {
223                 fprintf (stderr,
224                          _("%s: failed to prepare the new %s entry '%s'\n"),
225                          Prog, gr_dbname (), grp.gr_name);
226                 exit (E_GRP_UPDATE);
227         }
228         if (nflg && (gr_remove (group_name) == 0)) {
229                 fprintf (stderr,
230                          _("%s: cannot remove entry '%s' from %s\n"),
231                          Prog, grp.gr_name, gr_dbname ());
232                 exit (E_GRP_UPDATE);
233         }
234 #ifdef  SHADOWGRP
235
236         /*
237          * Make sure there was a shadow entry to begin with.
238          */
239         if (   (NULL != osgrp)
240             && (pflg || nflg)) {
241                 /*
242                  * Write out the new shadow group entries as well.
243                  */
244                 if (sgr_update (&sgrp) == 0) {
245                         fprintf (stderr,
246                                  _("%s: failed to prepare the new %s entry '%s'\n"),
247                                  Prog, sgr_dbname (), sgrp.sg_name);
248                         exit (E_GRP_UPDATE);
249                 }
250                 if (nflg && (sgr_remove (group_name) == 0)) {
251                         fprintf (stderr,
252                                  _("%s: cannot remove entry '%s' from %s\n"),
253                                  Prog, group_name, sgr_dbname ());
254                         exit (E_GRP_UPDATE);
255                 }
256         }
257 #endif                          /* SHADOWGRP */
258 }
259
260 /*
261  * check_new_gid - check the new GID value for uniqueness
262  *
263  *      check_new_gid() insures that the new GID value is unique.
264  */
265 static void check_new_gid (void)
266 {
267         /*
268          * First, the easy stuff. If the ID can be duplicated, or if the ID
269          * didn't really change, just return. If the ID didn't change, turn
270          * off those flags. No sense doing needless work.
271          */
272         if (group_id == group_newid) {
273                 gflg = 0;
274                 return;
275         }
276
277         if (oflg ||
278             (getgrgid (group_newid) == NULL) /* local, no need for xgetgrgid */
279            ) {
280                 return;
281         }
282
283         /*
284          * Tell the user what they did wrong.
285          */
286         fprintf (stderr,
287                  _("%s: GID '%lu' already exists\n"),
288                  Prog, (unsigned long int) group_newid);
289         exit (E_GID_IN_USE);
290 }
291
292 /*
293  * check_new_name - check the new name for uniqueness
294  *
295  *      check_new_name() insures that the new name does not exist already.
296  *      You can't have the same name twice, period.
297  */
298 static void check_new_name (void)
299 {
300         /*
301          * Make sure they are actually changing the name.
302          */
303         if (strcmp (group_name, group_newname) == 0) {
304                 nflg = 0;
305                 return;
306         }
307
308         if (is_valid_group_name (group_newname)) {
309
310                 /*
311                  * If the entry is found, too bad.
312                  */
313                 /* local, no need for xgetgrnam */
314                 if (getgrnam (group_newname) != NULL) {
315                         fprintf (stderr,
316                                  _("%s: group '%s' already exists\n"),
317                                  Prog, group_newname);
318                         exit (E_NAME_IN_USE);
319                 }
320                 return;
321         }
322
323         /*
324          * All invalid group names land here.
325          */
326
327         fprintf (stderr,
328                  _("%s: invalid group name '%s'\n"),
329                  Prog, group_newname);
330         exit (E_BAD_ARG);
331 }
332
333 /*
334  * process_flags - perform command line argument setting
335  *
336  *      process_flags() interprets the command line arguments and sets the
337  *      values that the user will be created with accordingly. The values
338  *      are checked for sanity.
339  */
340 static void process_flags (int argc, char **argv)
341 {
342         int option_index = 0;
343         int c;
344         static struct option long_options[] = {
345                 {"gid", required_argument, NULL, 'g'},
346                 {"help", no_argument, NULL, 'h'},
347                 {"new-name", required_argument, NULL, 'n'},
348                 {"non-unique", no_argument, NULL, 'o'},
349                 {"password", required_argument, NULL, 'p'},
350                 {NULL, 0, NULL, '\0'}
351         };
352         while ((c =
353                 getopt_long (argc, argv, "g:hn:op:",
354                              long_options, &option_index)) != -1) {
355                 switch (c) {
356                 case 'g':
357                         gflg = true;
358                         if (   (get_gid (optarg, &group_newid) == 0)
359                             || (group_newid == (gid_t)-1)) {
360                                 fprintf (stderr,
361                                          _("%s: invalid group ID '%s'\n"),
362                                          Prog, optarg);
363                                 exit (E_BAD_ARG);
364                         }
365                         break;
366                 case 'h':
367                         usage (E_SUCCESS);
368                         break;
369                 case 'n':
370                         nflg = true;
371                         group_newname = optarg;
372                         break;
373                 case 'o':
374                         oflg = true;
375                         break;
376                 case 'p':
377                         group_passwd = optarg;
378                         pflg = true;
379                         break;
380                 default:
381                         usage (E_USAGE);
382                 }
383         }
384
385         if (oflg && !gflg) {
386                 usage (E_USAGE);
387         }
388
389         if (optind != (argc - 1)) {
390                 usage (E_USAGE);
391         }
392
393         group_name = argv[argc - 1];
394 }
395
396 /*
397  * close_files - close all of the files that were opened
398  *
399  *      close_files() closes all of the files that were opened for this new
400  *      group. This causes any modified entries to be written out.
401  */
402 static void close_files (void)
403 {
404         if (gr_close () == 0) {
405                 fprintf (stderr,
406                          _("%s: failure while writing changes to %s\n"),
407                          Prog, gr_dbname ());
408                 exit (E_GRP_UPDATE);
409         }
410 #ifdef WITH_AUDIT
411         audit_logger (AUDIT_USER_ACCT, Prog,
412                       info_group.audit_msg,
413                       group_name, AUDIT_NO_ID,
414                       SHADOW_AUDIT_SUCCESS);
415 #endif
416         SYSLOG ((LOG_INFO,
417                  "group changed in %s (%s)",
418                  gr_dbname (), info_group.action));
419         del_cleanup (cleanup_report_mod_group);
420
421         cleanup_unlock_group (NULL);
422         del_cleanup (cleanup_unlock_group);
423
424 #ifdef  SHADOWGRP
425         if (   is_shadow_grp
426             && (pflg || nflg)) {
427                 if (sgr_close () == 0) {
428                         fprintf (stderr,
429                                  _("%s: failure while writing changes to %s\n"),
430                                  Prog, sgr_dbname ());
431                         exit (E_GRP_UPDATE);
432                 }
433 #ifdef WITH_AUDIT
434                 audit_logger (AUDIT_USER_ACCT, Prog,
435                               info_gshadow.audit_msg,
436                               group_name, AUDIT_NO_ID,
437                               SHADOW_AUDIT_SUCCESS);
438 #endif
439                 SYSLOG ((LOG_INFO,
440                          "group changed in %s (%s)",
441                          sgr_dbname (), info_gshadow.action));
442                 del_cleanup (cleanup_report_mod_gshadow);
443
444                 cleanup_unlock_gshadow (NULL);
445                 del_cleanup (cleanup_unlock_gshadow);
446         }
447 #endif                          /* SHADOWGRP */
448
449         if (gflg) {
450                 if (pw_close () == 0) {
451                         fprintf (stderr,
452                                  _("%s: failure while writing changes to %s\n"),
453                                  Prog, pw_dbname ());
454                         exit (E_GRP_UPDATE);
455                 }
456 #ifdef WITH_AUDIT
457                 audit_logger (AUDIT_USER_ACCT, Prog,
458                               info_passwd.audit_msg,
459                               group_name, AUDIT_NO_ID,
460                               SHADOW_AUDIT_SUCCESS);
461 #endif
462                 SYSLOG ((LOG_INFO,
463                          "group changed in %s (%s)",
464                          pw_dbname (), info_passwd.action));
465                 del_cleanup (cleanup_report_mod_passwd);
466
467                 cleanup_unlock_passwd (NULL);
468                 del_cleanup (cleanup_unlock_passwd);
469         }
470
471 #ifdef WITH_AUDIT
472         audit_logger (AUDIT_USER_ACCT, Prog,
473                       "modifying group",
474                       group_name, AUDIT_NO_ID,
475                       SHADOW_AUDIT_SUCCESS);
476 #endif
477 }
478
479 /*
480  * prepare_failure_reports - Prepare the cleanup_info structure for logging
481  * of success and failure to syslog or audit.
482  */
483 static void prepare_failure_reports (void)
484 {
485         info_group.name   = group_name;
486 #ifdef  SHADOWGRP
487         info_gshadow.name = group_name;
488 #endif
489         info_passwd.name  = group_name;
490
491         info_group.audit_msg   = xmalloc (512);
492 #ifdef  SHADOWGRP
493         info_gshadow.audit_msg = xmalloc (512);
494 #endif
495         info_passwd.audit_msg  = xmalloc (512);
496
497         snprintf (info_group.audit_msg, 511,
498                   "changing %s; ", gr_dbname ());
499 #ifdef  SHADOWGRP
500         snprintf (info_gshadow.audit_msg, 511,
501                   "changing %s; ", sgr_dbname ());
502 #endif
503         snprintf (info_passwd.audit_msg, 511,
504                   "changing %s; ", pw_dbname ());
505
506         info_group.action   =   info_group.audit_msg
507                               + strlen (info_group.audit_msg);
508 #ifdef  SHADOWGRP
509         info_gshadow.action =   info_gshadow.audit_msg
510                               + strlen (info_gshadow.audit_msg);
511 #endif
512         info_passwd.action  =   info_passwd.audit_msg
513                               + strlen (info_passwd.audit_msg);
514
515         snprintf (info_group.action,   511 - strlen (info_group.audit_msg),
516                   "group %s/%lu", group_name, (unsigned long int) group_id);
517 #ifdef  SHADOWGRP
518         snprintf (info_gshadow.action, 511 - strlen (info_group.audit_msg),
519                   "group %s", group_name);
520 #endif
521         snprintf (info_passwd.action,  511 - strlen (info_group.audit_msg),
522                   "group %s/%lu", group_name, (unsigned long int) group_id);
523
524         if (nflg) {
525                 strncat (info_group.action, ", new name: ",
526                          511 - strlen (info_group.audit_msg));
527                 strncat (info_group.action, group_newname,
528                          511 - strlen (info_group.audit_msg));
529
530 #ifdef  SHADOWGRP
531                 strncat (info_gshadow.action, ", new name: ",
532                          511 - strlen (info_gshadow.audit_msg));
533                 strncat (info_gshadow.action, group_newname,
534                          511 - strlen (info_gshadow.audit_msg));
535 #endif
536
537                 strncat (info_passwd.action, ", new name: ",
538                          511 - strlen (info_passwd.audit_msg));
539                 strncat (info_passwd.action, group_newname,
540                          511 - strlen (info_passwd.audit_msg));
541         }
542         if (pflg) {
543                 strncat (info_group.action, ", new password",
544                          511 - strlen (info_group.audit_msg));
545
546 #ifdef  SHADOWGRP
547                 strncat (info_gshadow.action, ", new password",
548                          511 - strlen (info_gshadow.audit_msg));
549 #endif
550         }
551         if (gflg) {
552                 strncat (info_group.action, ", new gid: ",
553                          511 - strlen (info_group.audit_msg));
554                 snprintf (info_group.action+strlen (info_group.action),
555                           511 - strlen (info_group.audit_msg),
556                           "%lu", (unsigned long int) group_newid);
557
558                 strncat (info_passwd.action, ", new gid: ",
559                          511 - strlen (info_passwd.audit_msg));
560                 snprintf (info_passwd.action+strlen (info_passwd.action),
561                           511 - strlen (info_passwd.audit_msg),
562                           "%lu", (unsigned long int) group_newid);
563         }
564         info_group.audit_msg[511]   = '\0';
565 #ifdef  SHADOWGRP
566         info_gshadow.audit_msg[511] = '\0';
567 #endif
568         info_passwd.audit_msg[511]  = '\0';
569
570 // FIXME: add a system cleanup
571         add_cleanup (cleanup_report_mod_group, &info_group);
572 #ifdef  SHADOWGRP
573         if (   is_shadow_grp
574             && (pflg || nflg)) {
575                 add_cleanup (cleanup_report_mod_gshadow, &info_gshadow);
576         }
577 #endif
578         if (gflg) {
579                 add_cleanup (cleanup_report_mod_passwd, &info_passwd);
580         }
581
582 }
583
584 /*
585  * lock_files - lock the accounts databases
586  *
587  *      lock_files() locks the group, gshadow, and passwd databases.
588  */
589 static void lock_files (void)
590 {
591         if (gr_lock () == 0) {
592                 fprintf (stderr,
593                          _("%s: cannot lock %s; try again later.\n"),
594                          Prog, gr_dbname ());
595                 exit (E_GRP_UPDATE);
596         }
597         add_cleanup (cleanup_unlock_group, NULL);
598
599 #ifdef  SHADOWGRP
600         if (   is_shadow_grp
601             && (pflg || nflg)) {
602                 if (sgr_lock () == 0) {
603                         fprintf (stderr,
604                                  _("%s: cannot lock %s; try again later.\n"),
605                                  Prog, sgr_dbname ());
606                         exit (E_GRP_UPDATE);
607                 }
608                 add_cleanup (cleanup_unlock_gshadow, NULL);
609         }
610 #endif
611
612         if (gflg) {
613                 if (pw_lock () == 0) {
614                         fprintf (stderr,
615                                  _("%s: cannot lock %s; try again later.\n"),
616                                  Prog, pw_dbname ());
617                         exit (E_GRP_UPDATE);
618                 }
619                 add_cleanup (cleanup_unlock_passwd, NULL);
620         }
621 }
622
623
624 /*
625  * open_files - open the accounts databases
626  *
627  *      open_files() opens the group, gshadow, and passwd databases.
628  */
629 static void open_files (void)
630 {
631         if (gr_open (O_RDWR) == 0) {
632                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
633                 SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
634                 exit (E_GRP_UPDATE);
635         }
636
637 #ifdef  SHADOWGRP
638         if (   is_shadow_grp
639             && (pflg || nflg)) {
640                 if (sgr_open (O_RDWR) == 0) {
641                         fprintf (stderr,
642                                  _("%s: cannot open %s\n"),
643                                  Prog, sgr_dbname ());
644                         SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
645                         exit (E_GRP_UPDATE);
646                 }
647         }
648 #endif                          /* SHADOWGRP */
649
650         if (gflg) {
651                 if (pw_open (O_RDWR) == 0) {
652                         fprintf (stderr,
653                                  _("%s: cannot open %s\n"),
654                                  Prog, pw_dbname ());
655                         SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
656                         exit (E_GRP_UPDATE);
657                 }
658         }
659 }
660
661 void update_primary_groups (gid_t ogid, gid_t ngid)
662 {
663         struct passwd *pwd;
664
665         setpwent ();
666         while ((pwd = getpwent ()) != NULL) {
667                 if (pwd->pw_gid == ogid) {
668                         const struct passwd *lpwd;
669                         struct passwd npwd;
670                         lpwd = pw_locate (pwd->pw_name);
671                         if (NULL == lpwd) {
672                                 fprintf (stderr,
673                                          _("%s: user '%s' does not exist in %s\n"),
674                                          Prog, pwd->pw_name, pw_dbname ());
675                                 exit (E_GRP_UPDATE);
676                         } else {
677                                 npwd = *lpwd;
678                                 npwd.pw_gid = ngid;
679                                 if (pw_update (&npwd) == 0) {
680                                         fprintf (stderr,
681                                                  _("%s: failed to prepare the new %s entry '%s'\n"),
682                                                  Prog, pw_dbname (), npwd.pw_name);
683                                         exit (E_GRP_UPDATE);
684                                 }
685                         }
686                 }
687         }
688         endpwent ();
689 }
690
691 /*
692  * main - groupmod command
693  *
694  */
695 int main (int argc, char **argv)
696 {
697 #ifdef ACCT_TOOLS_SETUID
698 #ifdef USE_PAM
699         pam_handle_t *pamh = NULL;
700         int retval;
701 #endif                          /* USE_PAM */
702 #endif                          /* ACCT_TOOLS_SETUID */
703
704 #ifdef WITH_AUDIT
705         audit_help_open ();
706 #endif
707         atexit (do_cleanups);
708
709         /*
710          * Get my name so that I can use it to report errors.
711          */
712         Prog = Basename (argv[0]);
713
714         (void) setlocale (LC_ALL, "");
715         (void) bindtextdomain (PACKAGE, LOCALEDIR);
716         (void) textdomain (PACKAGE);
717
718         process_flags (argc, argv);
719
720         OPENLOG ("groupmod");
721
722 #ifdef ACCT_TOOLS_SETUID
723 #ifdef USE_PAM
724         {
725                 struct passwd *pampw;
726                 pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
727                 if (NULL == pampw) {
728                         fprintf (stderr,
729                                  _("%s: Cannot determine your user name.\n"),
730                                  Prog);
731                         exit (1);
732                 }
733
734                 retval = pam_start ("groupmod", pampw->pw_name, &conv, &pamh);
735         }
736
737         if (PAM_SUCCESS == retval) {
738                 retval = pam_authenticate (pamh, 0);
739         }
740
741         if (PAM_SUCCESS == retval) {
742                 retval = pam_acct_mgmt (pamh, 0);
743         }
744
745         if (NULL != pamh) {
746                 (void) pam_end (pamh, retval);
747         }
748         if (PAM_SUCCESS != retval) {
749                 fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
750                 exit (1);
751         }
752 #endif                          /* USE_PAM */
753 #endif                          /* ACCT_TOOLS_SETUID */
754
755 #ifdef SHADOWGRP
756         is_shadow_grp = sgr_file_present ();
757 #endif
758         {
759                 struct group *grp;
760                 /*
761                  * Start with a quick check to see if the group exists.
762                  */
763                 grp = getgrnam (group_name); /* local, no need for xgetgrnam */
764                 if (NULL == grp) {
765                         fprintf (stderr,
766                                  _("%s: group '%s' does not exist\n"),
767                                  Prog, group_name);
768                         exit (E_NOTFOUND);
769                 } else {
770                         group_id = grp->gr_gid;
771                 }
772         }
773
774 #ifdef  USE_NIS
775         /*
776          * Now make sure it isn't an NIS group.
777          */
778         if (__isgrNIS ()) {
779                 char *nis_domain;
780                 char *nis_master;
781
782                 fprintf (stderr,
783                          _("%s: group %s is a NIS group\n"),
784                          Prog, group_name);
785
786                 if (!yp_get_default_domain (&nis_domain) &&
787                     !yp_master (nis_domain, "group.byname", &nis_master)) {
788                         fprintf (stderr,
789                                  _("%s: %s is the NIS master\n"),
790                                  Prog, nis_master);
791                 }
792                 exit (E_NOTFOUND);
793         }
794 #endif
795
796         if (gflg) {
797                 check_new_gid ();
798         }
799
800         if (nflg) {
801                 check_new_name ();
802         }
803
804         lock_files ();
805
806         /*
807          * Now if the group is not changed, it's our fault.
808          * Make sure failures will be reported.
809          */
810         prepare_failure_reports ();
811
812         /*
813          * Do the hard stuff - open the files, create the group entries,
814          * then close and update the files.
815          */
816         open_files ();
817
818         grp_update ();
819
820         close_files ();
821
822         nscd_flush_cache ("group");
823
824         return E_SUCCESS;
825 }
826