Initial commit for Tizen
[profile/extras/shadow-utils.git] / 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: groupmod.c 3015 2009-06-05 22:16:56Z nekral-guest $"
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 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 (void);
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 (void)
117 {
118         (void) fprintf (stderr,
119                         _("Usage: %s [options] GROUP\n"
120                           "\n"
121                           "Options:\n"),
122                         Prog);
123         (void) fputs (_("  -g, --gid GID                 change the group ID to GID\n"), stderr);
124         (void) fputs (_("  -h, --help                    display this help message and exit\n"), stderr);
125         (void) fputs (_("  -n, --new-name NEW_GROUP      change the name to NEW_GROUP\n"), stderr);
126         (void) fputs (_("  -o, --non-unique              allow to use a duplicate (non-unique) GID\n"), stderr);
127         (void) fputs (_("  -p, --password PASSWORD       change the password to this (encrypted)\n"
128                         "                                PASSWORD\n"), stderr);
129         (void) fputs ("\n", stderr);
130         exit (E_USAGE);
131 }
132
133 /*
134  * new_grent - updates the values in a group file entry
135  *
136  *      new_grent() takes all of the values that have been entered and fills
137  *      in a (struct group) with them.
138  */
139 static void new_grent (struct group *grent)
140 {
141         if (nflg) {
142                 grent->gr_name = xstrdup (group_newname);
143         }
144
145         if (gflg) {
146                 grent->gr_gid = group_newid;
147         }
148
149         if (pflg) {
150                 grent->gr_passwd = group_passwd;
151         }
152 }
153
154 #ifdef  SHADOWGRP
155 /*
156  * new_sgent - updates the values in a shadow group file entry
157  *
158  *      new_sgent() takes all of the values that have been entered and fills
159  *      in a (struct sgrp) with them.
160  */
161 static void new_sgent (struct sgrp *sgent)
162 {
163         if (nflg) {
164                 sgent->sg_name = xstrdup (group_newname);
165         }
166
167         if (pflg) {
168                 sgent->sg_passwd = group_passwd;
169         }
170 }
171 #endif                          /* SHADOWGRP */
172
173 /*
174  * grp_update - update group file entries
175  *
176  *      grp_update() updates the new records in the memory databases.
177  */
178 static void grp_update (void)
179 {
180         struct group grp;
181         const struct group *ogrp;
182
183 #ifdef  SHADOWGRP
184         struct sgrp sgrp;
185         const struct sgrp *osgrp = NULL;
186 #endif                          /* SHADOWGRP */
187
188         /*
189          * Get the current settings for this group.
190          */
191         ogrp = gr_locate (group_name);
192         if (!ogrp) {
193                 fprintf (stderr,
194                          _("%s: group '%s' does not exist in %s\n"),
195                          Prog, group_name, gr_dbname ());
196                 exit (E_GRP_UPDATE);
197         }
198         grp = *ogrp;
199         new_grent (&grp);
200 #ifdef  SHADOWGRP
201         if (   is_shadow_grp
202             && (pflg || nflg)) {
203                 osgrp = sgr_locate (group_name);
204                 if (NULL != osgrp) {
205                         sgrp = *osgrp;
206                         new_sgent (&sgrp);
207                         if (pflg) {
208                                 grp.gr_passwd = SHADOW_PASSWD_STRING;
209                         }
210                 }
211         }
212 #endif                          /* SHADOWGRP */
213
214         if (gflg) {
215                 update_primary_groups (ogrp->gr_gid, group_newid);
216         }
217
218         /*
219          * Write out the new group file entry.
220          */
221         if (gr_update (&grp) == 0) {
222                 fprintf (stderr,
223                          _("%s: failed to prepare the new %s entry '%s'\n"),
224                          Prog, gr_dbname (), grp.gr_name);
225                 exit (E_GRP_UPDATE);
226         }
227         if (nflg && (gr_remove (group_name) == 0)) {
228                 fprintf (stderr,
229                          _("%s: cannot remove entry '%s' from %s\n"),
230                          Prog, grp.gr_name, gr_dbname ());
231                 exit (E_GRP_UPDATE);
232         }
233 #ifdef  SHADOWGRP
234
235         /*
236          * Make sure there was a shadow entry to begin with.
237          */
238         if (   (NULL != osgrp)
239             && (pflg || nflg)) {
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 'n':
366                         nflg = true;
367                         group_newname = optarg;
368                         break;
369                 case 'o':
370                         oflg = true;
371                         break;
372                 case 'p':
373                         group_passwd = optarg;
374                         pflg = true;
375                         break;
376                 default:
377                         usage ();
378                 }
379         }
380
381         if (oflg && !gflg) {
382                 usage ();
383         }
384
385         if (optind != (argc - 1)) {
386                 usage ();
387         }
388
389         group_name = argv[argc - 1];
390 }
391
392 /*
393  * close_files - close all of the files that were opened
394  *
395  *      close_files() closes all of the files that were opened for this new
396  *      group. This causes any modified entries to be written out.
397  */
398 static void close_files (void)
399 {
400         if (gr_close () == 0) {
401                 fprintf (stderr,
402                          _("%s: failure while writing changes to %s\n"),
403                          Prog, gr_dbname ());
404                 exit (E_GRP_UPDATE);
405         }
406 #ifdef WITH_AUDIT
407         audit_logger (AUDIT_USER_ACCT, Prog,
408                       info_group.audit_msg,
409                       group_name, AUDIT_NO_ID,
410                       SHADOW_AUDIT_SUCCESS);
411 #endif
412         SYSLOG ((LOG_INFO,
413                  "group changed in %s (%s)",
414                  gr_dbname (), info_group.action));
415         del_cleanup (cleanup_report_mod_group);
416
417         cleanup_unlock_group (NULL);
418         del_cleanup (cleanup_unlock_group);
419
420 #ifdef  SHADOWGRP
421         if (   is_shadow_grp
422             && (pflg || nflg)) {
423                 if (sgr_close () == 0) {
424                         fprintf (stderr,
425                                  _("%s: failure while writing changes to %s\n"),
426                                  Prog, sgr_dbname ());
427                         exit (E_GRP_UPDATE);
428                 }
429 #ifdef WITH_AUDIT
430                 audit_logger (AUDIT_USER_ACCT, Prog,
431                               info_gshadow.audit_msg,
432                               group_name, AUDIT_NO_ID,
433                               SHADOW_AUDIT_SUCCESS);
434 #endif
435                 SYSLOG ((LOG_INFO,
436                          "group changed in %s (%s)",
437                          sgr_dbname (), info_gshadow.action));
438                 del_cleanup (cleanup_report_mod_gshadow);
439
440                 cleanup_unlock_gshadow (NULL);
441                 del_cleanup (cleanup_unlock_gshadow);
442         }
443 #endif                          /* SHADOWGRP */
444
445         if (gflg) {
446                 if (pw_close () == 0) {
447                         fprintf (stderr,
448                                  _("%s: failure while writing changes to %s\n"),
449                                  Prog, pw_dbname ());
450                         exit (E_GRP_UPDATE);
451                 }
452 #ifdef WITH_AUDIT
453                 audit_logger (AUDIT_USER_ACCT, Prog,
454                               info_passwd.audit_msg,
455                               group_name, AUDIT_NO_ID,
456                               SHADOW_AUDIT_SUCCESS);
457 #endif
458                 SYSLOG ((LOG_INFO,
459                          "group changed in %s (%s)",
460                          pw_dbname (), info_passwd.action));
461                 del_cleanup (cleanup_report_mod_passwd);
462
463                 cleanup_unlock_passwd (NULL);
464                 del_cleanup (cleanup_unlock_passwd);
465         }
466
467 #ifdef WITH_AUDIT
468         audit_logger (AUDIT_USER_ACCT, Prog,
469                       "modifying group",
470                       group_name, AUDIT_NO_ID,
471                       SHADOW_AUDIT_SUCCESS);
472 #endif
473 }
474
475 /*
476  * prepare_failure_reports - Prepare the cleanup_info structure for logging
477  * of success and failure to syslog or audit.
478  */
479 static void prepare_failure_reports (void)
480 {
481         info_group.name   = group_name;
482 #ifdef  SHADOWGRP
483         info_gshadow.name = group_name;
484 #endif
485         info_passwd.name  = group_name;
486
487         info_group.audit_msg   = xmalloc (512);
488 #ifdef  SHADOWGRP
489         info_gshadow.audit_msg = xmalloc (512);
490 #endif
491         info_passwd.audit_msg  = xmalloc (512);
492
493         snprintf (info_group.audit_msg, 511,
494                   "changing %s; ", gr_dbname ());
495 #ifdef  SHADOWGRP
496         snprintf (info_gshadow.audit_msg, 511,
497                   "changing %s; ", sgr_dbname ());
498 #endif
499         snprintf (info_passwd.audit_msg, 511,
500                   "changing %s; ", pw_dbname ());
501
502         info_group.action   =   info_group.audit_msg
503                               + strlen (info_group.audit_msg);
504 #ifdef  SHADOWGRP
505         info_gshadow.action =   info_gshadow.audit_msg
506                               + strlen (info_gshadow.audit_msg);
507 #endif
508         info_passwd.action  =   info_passwd.audit_msg
509                               + strlen (info_passwd.audit_msg);
510
511         snprintf (info_group.action,   511 - strlen (info_group.audit_msg),
512                   "group %s/%lu", group_name, (unsigned long int) group_id);
513 #ifdef  SHADOWGRP
514         snprintf (info_gshadow.action, 511 - strlen (info_group.audit_msg),
515                   "group %s", group_name);
516 #endif
517         snprintf (info_passwd.action,  511 - strlen (info_group.audit_msg),
518                   "group %s/%lu", group_name, (unsigned long int) group_id);
519
520         if (nflg) {
521                 strncat (info_group.action, ", new name: ",
522                          511 - strlen (info_group.audit_msg));
523                 strncat (info_group.action, group_newname,
524                          511 - strlen (info_group.audit_msg));
525
526 #ifdef  SHADOWGRP
527                 strncat (info_gshadow.action, ", new name: ",
528                          511 - strlen (info_gshadow.audit_msg));
529                 strncat (info_gshadow.action, group_newname,
530                          511 - strlen (info_gshadow.audit_msg));
531 #endif
532
533                 strncat (info_passwd.action, ", new name: ",
534                          511 - strlen (info_passwd.audit_msg));
535                 strncat (info_passwd.action, group_newname,
536                          511 - strlen (info_passwd.audit_msg));
537         }
538         if (pflg) {
539                 strncat (info_group.action, ", new password",
540                          511 - strlen (info_group.audit_msg));
541
542 #ifdef  SHADOWGRP
543                 strncat (info_gshadow.action, ", new password",
544                          511 - strlen (info_gshadow.audit_msg));
545 #endif
546         }
547         if (gflg) {
548                 strncat (info_group.action, ", new gid: ",
549                          511 - strlen (info_group.audit_msg));
550                 snprintf (info_group.action+strlen (info_group.action),
551                           511 - strlen (info_group.audit_msg),
552                           "%lu", (unsigned long int) group_newid);
553
554                 strncat (info_passwd.action, ", new gid: ",
555                          511 - strlen (info_passwd.audit_msg));
556                 snprintf (info_passwd.action+strlen (info_passwd.action),
557                           511 - strlen (info_passwd.audit_msg),
558                           "%lu", (unsigned long int) group_newid);
559         }
560         info_group.audit_msg[511]   = '\0';
561 #ifdef  SHADOWGRP
562         info_gshadow.audit_msg[511] = '\0';
563 #endif
564         info_passwd.audit_msg[511]  = '\0';
565
566 // FIXME: add a system cleanup
567         add_cleanup (cleanup_report_mod_group, &info_group);
568 #ifdef  SHADOWGRP
569         if (   is_shadow_grp
570             && (pflg || nflg)) {
571                 add_cleanup (cleanup_report_mod_gshadow, &info_gshadow);
572         }
573 #endif
574         if (gflg) {
575                 add_cleanup (cleanup_report_mod_passwd, &info_passwd);
576         }
577
578 }
579
580 /*
581  * lock_files - lock the accounts databases
582  *
583  *      lock_files() locks the group, gshadow, and passwd databases.
584  */
585 static void lock_files (void)
586 {
587         if (gr_lock () == 0) {
588                 fprintf (stderr,
589                          _("%s: cannot lock %s; try again later.\n"),
590                          Prog, gr_dbname ());
591                 exit (E_GRP_UPDATE);
592         }
593         add_cleanup (cleanup_unlock_group, NULL);
594
595 #ifdef  SHADOWGRP
596         if (   is_shadow_grp
597             && (pflg || nflg)) {
598                 if (sgr_lock () == 0) {
599                         fprintf (stderr,
600                                  _("%s: cannot lock %s; try again later.\n"),
601                                  Prog, sgr_dbname ());
602                         exit (E_GRP_UPDATE);
603                 }
604                 add_cleanup (cleanup_unlock_gshadow, NULL);
605         }
606 #endif
607
608         if (gflg) {
609                 if (pw_lock () == 0) {
610                         fprintf (stderr,
611                                  _("%s: cannot lock %s; try again later.\n"),
612                                  Prog, pw_dbname ());
613                         exit (E_GRP_UPDATE);
614                 }
615                 add_cleanup (cleanup_unlock_passwd, NULL);
616         }
617 }
618
619
620 /*
621  * open_files - open the accounts databases
622  *
623  *      open_files() opens the group, gshadow, and passwd databases.
624  */
625 static void open_files (void)
626 {
627         if (gr_open (O_RDWR) == 0) {
628                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
629                 SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
630                 exit (E_GRP_UPDATE);
631         }
632
633 #ifdef  SHADOWGRP
634         if (   is_shadow_grp
635             && (pflg || nflg)) {
636                 if (sgr_open (O_RDWR) == 0) {
637                         fprintf (stderr,
638                                  _("%s: cannot open %s\n"),
639                                  Prog, sgr_dbname ());
640                         SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
641                         exit (E_GRP_UPDATE);
642                 }
643         }
644 #endif                          /* SHADOWGRP */
645
646         if (gflg) {
647                 if (pw_open (O_RDWR) == 0) {
648                         fprintf (stderr,
649                                  _("%s: cannot open %s\n"),
650                                  Prog, pw_dbname ());
651                         SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
652                         exit (E_GRP_UPDATE);
653                 }
654         }
655 }
656
657 void update_primary_groups (gid_t ogid, gid_t ngid)
658 {
659         struct passwd *pwd;
660
661         setpwent ();
662         while ((pwd = getpwent ()) != NULL) {
663                 if (pwd->pw_gid == ogid) {
664                         const struct passwd *lpwd;
665                         struct passwd npwd;
666                         lpwd = pw_locate (pwd->pw_name);
667                         if (NULL == lpwd) {
668                                 fprintf (stderr,
669                                          _("%s: user '%s' does not exist in %s\n"),
670                                          Prog, pwd->pw_name, pw_dbname ());
671                                 exit (E_GRP_UPDATE);
672                         } else {
673                                 npwd = *lpwd;
674                                 npwd.pw_gid = ngid;
675                                 if (pw_update (&npwd) == 0) {
676                                         fprintf (stderr,
677                                                  _("%s: failed to prepare the new %s entry '%s'\n"),
678                                                  Prog, pw_dbname (), npwd.pw_name);
679                                         exit (E_GRP_UPDATE);
680                                 }
681                         }
682                 }
683         }
684         endpwent ();
685 }
686
687 /*
688  * main - groupmod command
689  *
690  */
691 int main (int argc, char **argv)
692 {
693 #ifdef ACCT_TOOLS_SETUID
694 #ifdef USE_PAM
695         pam_handle_t *pamh = NULL;
696         int retval;
697 #endif                          /* USE_PAM */
698 #endif                          /* ACCT_TOOLS_SETUID */
699
700 #ifdef WITH_AUDIT
701         audit_help_open ();
702 #endif
703         atexit (do_cleanups);
704
705         /*
706          * Get my name so that I can use it to report errors.
707          */
708         Prog = Basename (argv[0]);
709
710         (void) setlocale (LC_ALL, "");
711         (void) bindtextdomain (PACKAGE, LOCALEDIR);
712         (void) textdomain (PACKAGE);
713
714         process_flags (argc, argv);
715
716         OPENLOG ("groupmod");
717
718 #ifdef ACCT_TOOLS_SETUID
719 #ifdef USE_PAM
720         {
721                 struct passwd *pampw;
722                 pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
723                 if (NULL == pamh) {
724                         fprintf (stderr,
725                                  _("%s: Cannot determine your user name.\n"),
726                                  Prog);
727                         exit (1);
728                 }
729
730                 retval = pam_start ("groupmod", pampw->pw_name, &conv, &pamh);
731         }
732
733         if (PAM_SUCCESS == retval) {
734                 retval = pam_authenticate (pamh, 0);
735         }
736
737         if (PAM_SUCCESS == retval) {
738                 retval = pam_acct_mgmt (pamh, 0);
739         }
740
741         if (NULL != pamh) {
742                 (void) pam_end (pamh, retval);
743         }
744         if (PAM_SUCCESS != retval) {
745                 fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
746                 exit (1);
747         }
748 #endif                          /* USE_PAM */
749 #endif                          /* ACCT_TOOLS_SETUID */
750
751 #ifdef SHADOWGRP
752         is_shadow_grp = sgr_file_present ();
753 #endif
754         {
755                 struct group *grp;
756                 /*
757                  * Start with a quick check to see if the group exists.
758                  */
759                 grp = getgrnam (group_name); /* local, no need for xgetgrnam */
760                 if (NULL == grp) {
761                         fprintf (stderr,
762                                  _("%s: group '%s' does not exist\n"),
763                                  Prog, group_name);
764                         exit (E_NOTFOUND);
765                 } else {
766                         group_id = grp->gr_gid;
767                 }
768         }
769
770 #ifdef  USE_NIS
771         /*
772          * Now make sure it isn't an NIS group.
773          */
774         if (__isgrNIS ()) {
775                 char *nis_domain;
776                 char *nis_master;
777
778                 fprintf (stderr,
779                          _("%s: group %s is a NIS group\n"),
780                          Prog, group_name);
781
782                 if (!yp_get_default_domain (&nis_domain) &&
783                     !yp_master (nis_domain, "group.byname", &nis_master)) {
784                         fprintf (stderr,
785                                  _("%s: %s is the NIS master\n"),
786                                  Prog, nis_master);
787                 }
788                 exit (E_NOTFOUND);
789         }
790 #endif
791
792         if (gflg) {
793                 check_new_gid ();
794         }
795
796         if (nflg) {
797                 check_new_name ();
798         }
799
800         lock_files ();
801
802         /*
803          * Now if the group is not changed, it's our fault.
804          * Make sure failures will be reported.
805          */
806         prepare_failure_reports ();
807
808         /*
809          * Do the hard stuff - open the files, create the group entries,
810          * then close and update the files.
811          */
812         open_files ();
813
814         grp_update ();
815
816         close_files ();
817
818         nscd_flush_cache ("group");
819
820         return E_SUCCESS;
821 }
822