]> granicus.if.org Git - shadow/blob - src/groupmod.c
* src/usermod.c (move_home): It is always an error to use -m if
[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 (NULL == 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
235 #ifdef  SHADOWGRP
236         /*
237          * Make sure there was a shadow entry to begin with.
238          */
239         if (NULL != osgrp) {
240                 /*
241                  * Write out the new shadow group entries as well.
242                  */
243                 if (sgr_update (&sgrp) == 0) {
244                         fprintf (stderr,
245                                  _("%s: failed to prepare the new %s entry '%s'\n"),
246                                  Prog, sgr_dbname (), sgrp.sg_name);
247                         exit (E_GRP_UPDATE);
248                 }
249                 if (nflg && (sgr_remove (group_name) == 0)) {
250                         fprintf (stderr,
251                                  _("%s: cannot remove entry '%s' from %s\n"),
252                                  Prog, group_name, sgr_dbname ());
253                         exit (E_GRP_UPDATE);
254                 }
255         }
256 #endif                          /* SHADOWGRP */
257 }
258
259 /*
260  * check_new_gid - check the new GID value for uniqueness
261  *
262  *      check_new_gid() insures that the new GID value is unique.
263  */
264 static void check_new_gid (void)
265 {
266         /*
267          * First, the easy stuff. If the ID can be duplicated, or if the ID
268          * didn't really change, just return. If the ID didn't change, turn
269          * off those flags. No sense doing needless work.
270          */
271         if (group_id == group_newid) {
272                 gflg = 0;
273                 return;
274         }
275
276         if (oflg ||
277             (getgrgid (group_newid) == NULL) /* local, no need for xgetgrgid */
278            ) {
279                 return;
280         }
281
282         /*
283          * Tell the user what they did wrong.
284          */
285         fprintf (stderr,
286                  _("%s: GID '%lu' already exists\n"),
287                  Prog, (unsigned long int) group_newid);
288         exit (E_GID_IN_USE);
289 }
290
291 /*
292  * check_new_name - check the new name for uniqueness
293  *
294  *      check_new_name() insures that the new name does not exist already.
295  *      You can't have the same name twice, period.
296  */
297 static void check_new_name (void)
298 {
299         /*
300          * Make sure they are actually changing the name.
301          */
302         if (strcmp (group_name, group_newname) == 0) {
303                 nflg = 0;
304                 return;
305         }
306
307         if (is_valid_group_name (group_newname)) {
308
309                 /*
310                  * If the entry is found, too bad.
311                  */
312                 /* local, no need for xgetgrnam */
313                 if (getgrnam (group_newname) != NULL) {
314                         fprintf (stderr,
315                                  _("%s: group '%s' already exists\n"),
316                                  Prog, group_newname);
317                         exit (E_NAME_IN_USE);
318                 }
319                 return;
320         }
321
322         /*
323          * All invalid group names land here.
324          */
325
326         fprintf (stderr,
327                  _("%s: invalid group name '%s'\n"),
328                  Prog, group_newname);
329         exit (E_BAD_ARG);
330 }
331
332 /*
333  * process_flags - perform command line argument setting
334  *
335  *      process_flags() interprets the command line arguments and sets the
336  *      values that the user will be created with accordingly. The values
337  *      are checked for sanity.
338  */
339 static void process_flags (int argc, char **argv)
340 {
341         int option_index = 0;
342         int c;
343         static struct option long_options[] = {
344                 {"gid", required_argument, NULL, 'g'},
345                 {"help", no_argument, NULL, 'h'},
346                 {"new-name", required_argument, NULL, 'n'},
347                 {"non-unique", no_argument, NULL, 'o'},
348                 {"password", required_argument, NULL, 'p'},
349                 {NULL, 0, NULL, '\0'}
350         };
351         while ((c =
352                 getopt_long (argc, argv, "g:hn:op:",
353                              long_options, &option_index)) != -1) {
354                 switch (c) {
355                 case 'g':
356                         gflg = true;
357                         if (   (get_gid (optarg, &group_newid) == 0)
358                             || (group_newid == (gid_t)-1)) {
359                                 fprintf (stderr,
360                                          _("%s: invalid group ID '%s'\n"),
361                                          Prog, optarg);
362                                 exit (E_BAD_ARG);
363                         }
364                         break;
365                 case 'h':
366                         usage (E_SUCCESS);
367                         break;
368                 case 'n':
369                         nflg = true;
370                         group_newname = optarg;
371                         break;
372                 case 'o':
373                         oflg = true;
374                         break;
375                 case 'p':
376                         group_passwd = optarg;
377                         pflg = true;
378                         break;
379                 default:
380                         usage (E_USAGE);
381                 }
382         }
383
384         if (oflg && !gflg) {
385                 usage (E_USAGE);
386         }
387
388         if (optind != (argc - 1)) {
389                 usage (E_USAGE);
390         }
391
392         group_name = argv[argc - 1];
393 }
394
395 /*
396  * close_files - close all of the files that were opened
397  *
398  *      close_files() closes all of the files that were opened for this new
399  *      group. This causes any modified entries to be written out.
400  */
401 static void close_files (void)
402 {
403         if (gr_close () == 0) {
404                 fprintf (stderr,
405                          _("%s: failure while writing changes to %s\n"),
406                          Prog, gr_dbname ());
407                 exit (E_GRP_UPDATE);
408         }
409 #ifdef WITH_AUDIT
410         audit_logger (AUDIT_USER_ACCT, Prog,
411                       info_group.audit_msg,
412                       group_name, AUDIT_NO_ID,
413                       SHADOW_AUDIT_SUCCESS);
414 #endif
415         SYSLOG ((LOG_INFO,
416                  "group changed in %s (%s)",
417                  gr_dbname (), info_group.action));
418         del_cleanup (cleanup_report_mod_group);
419
420         cleanup_unlock_group (NULL);
421         del_cleanup (cleanup_unlock_group);
422
423 #ifdef  SHADOWGRP
424         if (   is_shadow_grp
425             && (pflg || nflg)) {
426                 if (sgr_close () == 0) {
427                         fprintf (stderr,
428                                  _("%s: failure while writing changes to %s\n"),
429                                  Prog, sgr_dbname ());
430                         exit (E_GRP_UPDATE);
431                 }
432 #ifdef WITH_AUDIT
433                 audit_logger (AUDIT_USER_ACCT, Prog,
434                               info_gshadow.audit_msg,
435                               group_name, AUDIT_NO_ID,
436                               SHADOW_AUDIT_SUCCESS);
437 #endif
438                 SYSLOG ((LOG_INFO,
439                          "group changed in %s (%s)",
440                          sgr_dbname (), info_gshadow.action));
441                 del_cleanup (cleanup_report_mod_gshadow);
442
443                 cleanup_unlock_gshadow (NULL);
444                 del_cleanup (cleanup_unlock_gshadow);
445         }
446 #endif                          /* SHADOWGRP */
447
448         if (gflg) {
449                 if (pw_close () == 0) {
450                         fprintf (stderr,
451                                  _("%s: failure while writing changes to %s\n"),
452                                  Prog, pw_dbname ());
453                         exit (E_GRP_UPDATE);
454                 }
455 #ifdef WITH_AUDIT
456                 audit_logger (AUDIT_USER_ACCT, Prog,
457                               info_passwd.audit_msg,
458                               group_name, AUDIT_NO_ID,
459                               SHADOW_AUDIT_SUCCESS);
460 #endif
461                 SYSLOG ((LOG_INFO,
462                          "group changed in %s (%s)",
463                          pw_dbname (), info_passwd.action));
464                 del_cleanup (cleanup_report_mod_passwd);
465
466                 cleanup_unlock_passwd (NULL);
467                 del_cleanup (cleanup_unlock_passwd);
468         }
469
470 #ifdef WITH_AUDIT
471         audit_logger (AUDIT_USER_ACCT, Prog,
472                       "modifying group",
473                       group_name, AUDIT_NO_ID,
474                       SHADOW_AUDIT_SUCCESS);
475 #endif
476 }
477
478 /*
479  * prepare_failure_reports - Prepare the cleanup_info structure for logging
480  * of success and failure to syslog or audit.
481  */
482 static void prepare_failure_reports (void)
483 {
484         info_group.name   = group_name;
485 #ifdef  SHADOWGRP
486         info_gshadow.name = group_name;
487 #endif
488         info_passwd.name  = group_name;
489
490         info_group.audit_msg   = xmalloc (512);
491 #ifdef  SHADOWGRP
492         info_gshadow.audit_msg = xmalloc (512);
493 #endif
494         info_passwd.audit_msg  = xmalloc (512);
495
496         snprintf (info_group.audit_msg, 511,
497                   "changing %s; ", gr_dbname ());
498 #ifdef  SHADOWGRP
499         snprintf (info_gshadow.audit_msg, 511,
500                   "changing %s; ", sgr_dbname ());
501 #endif
502         snprintf (info_passwd.audit_msg, 511,
503                   "changing %s; ", pw_dbname ());
504
505         info_group.action   =   info_group.audit_msg
506                               + strlen (info_group.audit_msg);
507 #ifdef  SHADOWGRP
508         info_gshadow.action =   info_gshadow.audit_msg
509                               + strlen (info_gshadow.audit_msg);
510 #endif
511         info_passwd.action  =   info_passwd.audit_msg
512                               + strlen (info_passwd.audit_msg);
513
514         snprintf (info_group.action,   511 - strlen (info_group.audit_msg),
515                   "group %s/%lu", group_name, (unsigned long int) group_id);
516 #ifdef  SHADOWGRP
517         snprintf (info_gshadow.action, 511 - strlen (info_group.audit_msg),
518                   "group %s", group_name);
519 #endif
520         snprintf (info_passwd.action,  511 - strlen (info_group.audit_msg),
521                   "group %s/%lu", group_name, (unsigned long int) group_id);
522
523         if (nflg) {
524                 strncat (info_group.action, ", new name: ",
525                          511 - strlen (info_group.audit_msg));
526                 strncat (info_group.action, group_newname,
527                          511 - strlen (info_group.audit_msg));
528
529 #ifdef  SHADOWGRP
530                 strncat (info_gshadow.action, ", new name: ",
531                          511 - strlen (info_gshadow.audit_msg));
532                 strncat (info_gshadow.action, group_newname,
533                          511 - strlen (info_gshadow.audit_msg));
534 #endif
535
536                 strncat (info_passwd.action, ", new name: ",
537                          511 - strlen (info_passwd.audit_msg));
538                 strncat (info_passwd.action, group_newname,
539                          511 - strlen (info_passwd.audit_msg));
540         }
541         if (pflg) {
542                 strncat (info_group.action, ", new password",
543                          511 - strlen (info_group.audit_msg));
544
545 #ifdef  SHADOWGRP
546                 strncat (info_gshadow.action, ", new password",
547                          511 - strlen (info_gshadow.audit_msg));
548 #endif
549         }
550         if (gflg) {
551                 strncat (info_group.action, ", new gid: ",
552                          511 - strlen (info_group.audit_msg));
553                 snprintf (info_group.action+strlen (info_group.action),
554                           511 - strlen (info_group.audit_msg),
555                           "%lu", (unsigned long int) group_newid);
556
557                 strncat (info_passwd.action, ", new gid: ",
558                          511 - strlen (info_passwd.audit_msg));
559                 snprintf (info_passwd.action+strlen (info_passwd.action),
560                           511 - strlen (info_passwd.audit_msg),
561                           "%lu", (unsigned long int) group_newid);
562         }
563         info_group.audit_msg[511]   = '\0';
564 #ifdef  SHADOWGRP
565         info_gshadow.audit_msg[511] = '\0';
566 #endif
567         info_passwd.audit_msg[511]  = '\0';
568
569 // FIXME: add a system cleanup
570         add_cleanup (cleanup_report_mod_group, &info_group);
571 #ifdef  SHADOWGRP
572         if (   is_shadow_grp
573             && (pflg || nflg)) {
574                 add_cleanup (cleanup_report_mod_gshadow, &info_gshadow);
575         }
576 #endif
577         if (gflg) {
578                 add_cleanup (cleanup_report_mod_passwd, &info_passwd);
579         }
580
581 }
582
583 /*
584  * lock_files - lock the accounts databases
585  *
586  *      lock_files() locks the group, gshadow, and passwd databases.
587  */
588 static void lock_files (void)
589 {
590         if (gr_lock () == 0) {
591                 fprintf (stderr,
592                          _("%s: cannot lock %s; try again later.\n"),
593                          Prog, gr_dbname ());
594                 exit (E_GRP_UPDATE);
595         }
596         add_cleanup (cleanup_unlock_group, NULL);
597
598 #ifdef  SHADOWGRP
599         if (   is_shadow_grp
600             && (pflg || nflg)) {
601                 if (sgr_lock () == 0) {
602                         fprintf (stderr,
603                                  _("%s: cannot lock %s; try again later.\n"),
604                                  Prog, sgr_dbname ());
605                         exit (E_GRP_UPDATE);
606                 }
607                 add_cleanup (cleanup_unlock_gshadow, NULL);
608         }
609 #endif
610
611         if (gflg) {
612                 if (pw_lock () == 0) {
613                         fprintf (stderr,
614                                  _("%s: cannot lock %s; try again later.\n"),
615                                  Prog, pw_dbname ());
616                         exit (E_GRP_UPDATE);
617                 }
618                 add_cleanup (cleanup_unlock_passwd, NULL);
619         }
620 }
621
622
623 /*
624  * open_files - open the accounts databases
625  *
626  *      open_files() opens the group, gshadow, and passwd databases.
627  */
628 static void open_files (void)
629 {
630         if (gr_open (O_RDWR) == 0) {
631                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
632                 SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
633                 exit (E_GRP_UPDATE);
634         }
635
636 #ifdef  SHADOWGRP
637         if (   is_shadow_grp
638             && (pflg || nflg)) {
639                 if (sgr_open (O_RDWR) == 0) {
640                         fprintf (stderr,
641                                  _("%s: cannot open %s\n"),
642                                  Prog, sgr_dbname ());
643                         SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
644                         exit (E_GRP_UPDATE);
645                 }
646         }
647 #endif                          /* SHADOWGRP */
648
649         if (gflg) {
650                 if (pw_open (O_RDWR) == 0) {
651                         fprintf (stderr,
652                                  _("%s: cannot open %s\n"),
653                                  Prog, pw_dbname ());
654                         SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
655                         exit (E_GRP_UPDATE);
656                 }
657         }
658 }
659
660 void update_primary_groups (gid_t ogid, gid_t ngid)
661 {
662         struct passwd *pwd;
663
664         setpwent ();
665         while ((pwd = getpwent ()) != NULL) {
666                 if (pwd->pw_gid == ogid) {
667                         const struct passwd *lpwd;
668                         struct passwd npwd;
669                         lpwd = pw_locate (pwd->pw_name);
670                         if (NULL == lpwd) {
671                                 fprintf (stderr,
672                                          _("%s: user '%s' does not exist in %s\n"),
673                                          Prog, pwd->pw_name, pw_dbname ());
674                                 exit (E_GRP_UPDATE);
675                         } else {
676                                 npwd = *lpwd;
677                                 npwd.pw_gid = ngid;
678                                 if (pw_update (&npwd) == 0) {
679                                         fprintf (stderr,
680                                                  _("%s: failed to prepare the new %s entry '%s'\n"),
681                                                  Prog, pw_dbname (), npwd.pw_name);
682                                         exit (E_GRP_UPDATE);
683                                 }
684                         }
685                 }
686         }
687         endpwent ();
688 }
689
690 /*
691  * main - groupmod command
692  *
693  */
694 int main (int argc, char **argv)
695 {
696 #ifdef ACCT_TOOLS_SETUID
697 #ifdef USE_PAM
698         pam_handle_t *pamh = NULL;
699         int retval;
700 #endif                          /* USE_PAM */
701 #endif                          /* ACCT_TOOLS_SETUID */
702
703 #ifdef WITH_AUDIT
704         audit_help_open ();
705 #endif
706         atexit (do_cleanups);
707
708         /*
709          * Get my name so that I can use it to report errors.
710          */
711         Prog = Basename (argv[0]);
712
713         (void) setlocale (LC_ALL, "");
714         (void) bindtextdomain (PACKAGE, LOCALEDIR);
715         (void) textdomain (PACKAGE);
716
717         process_flags (argc, argv);
718
719         OPENLOG ("groupmod");
720
721 #ifdef ACCT_TOOLS_SETUID
722 #ifdef USE_PAM
723         {
724                 struct passwd *pampw;
725                 pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
726                 if (NULL == pampw) {
727                         fprintf (stderr,
728                                  _("%s: Cannot determine your user name.\n"),
729                                  Prog);
730                         exit (1);
731                 }
732
733                 retval = pam_start ("groupmod", pampw->pw_name, &conv, &pamh);
734         }
735
736         if (PAM_SUCCESS == retval) {
737                 retval = pam_authenticate (pamh, 0);
738         }
739
740         if (PAM_SUCCESS == retval) {
741                 retval = pam_acct_mgmt (pamh, 0);
742         }
743
744         if (NULL != pamh) {
745                 (void) pam_end (pamh, retval);
746         }
747         if (PAM_SUCCESS != retval) {
748                 fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
749                 exit (1);
750         }
751 #endif                          /* USE_PAM */
752 #endif                          /* ACCT_TOOLS_SETUID */
753
754 #ifdef SHADOWGRP
755         is_shadow_grp = sgr_file_present ();
756 #endif
757         {
758                 struct group *grp;
759                 /*
760                  * Start with a quick check to see if the group exists.
761                  */
762                 grp = getgrnam (group_name); /* local, no need for xgetgrnam */
763                 if (NULL == grp) {
764                         fprintf (stderr,
765                                  _("%s: group '%s' does not exist\n"),
766                                  Prog, group_name);
767                         exit (E_NOTFOUND);
768                 } else {
769                         group_id = grp->gr_gid;
770                 }
771         }
772
773 #ifdef  USE_NIS
774         /*
775          * Now make sure it isn't an NIS group.
776          */
777         if (__isgrNIS ()) {
778                 char *nis_domain;
779                 char *nis_master;
780
781                 fprintf (stderr,
782                          _("%s: group %s is a NIS group\n"),
783                          Prog, group_name);
784
785                 if (!yp_get_default_domain (&nis_domain) &&
786                     !yp_master (nis_domain, "group.byname", &nis_master)) {
787                         fprintf (stderr,
788                                  _("%s: %s is the NIS master\n"),
789                                  Prog, nis_master);
790                 }
791                 exit (E_NOTFOUND);
792         }
793 #endif
794
795         if (gflg) {
796                 check_new_gid ();
797         }
798
799         if (nflg) {
800                 check_new_name ();
801         }
802
803         lock_files ();
804
805         /*
806          * Now if the group is not changed, it's our fault.
807          * Make sure failures will be reported.
808          */
809         prepare_failure_reports ();
810
811         /*
812          * Do the hard stuff - open the files, create the group entries,
813          * then close and update the files.
814          */
815         open_files ();
816
817         grp_update ();
818
819         close_files ();
820
821         nscd_flush_cache ("group");
822
823         return E_SUCCESS;
824 }
825