]> granicus.if.org Git - shadow/blob - src/groupadd.c
remove unused fn commonio_next
[shadow] / src / groupadd.c
1 /*
2  * Copyright (c) 1991 - 1993, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2000 - 2006, Tomasz Kłoczko
5  * Copyright (c) 2007 - 2011, Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 #ident "$Id$"
36
37 #include <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 "getdef.h"
52 #include "groupio.h"
53 #include "nscd.h"
54 #include "sssd.h"
55 #include "prototypes.h"
56 #ifdef  SHADOWGRP
57 #include "sgroupio.h"
58 #endif
59
60 /*
61  * exit status values
62  */
63 /*@-exitarg@*/
64 #define E_SUCCESS       0       /* success */
65 #define E_USAGE         2       /* invalid command syntax */
66 #define E_BAD_ARG       3       /* invalid argument to option */
67 #define E_GID_IN_USE    4       /* gid not unique (when -o not used) */
68 #define E_NAME_IN_USE   9       /* group name not unique */
69 #define E_GRP_UPDATE    10      /* can't update group file */
70
71 /*
72  * Global variables
73  */
74 const char *Prog;
75
76 static /*@null@*/char *group_name;
77 static gid_t group_id;
78 static /*@null@*/char *group_passwd;
79 static /*@null@*/char *empty_list = NULL;
80
81 static const char *prefix = "";
82
83 static bool oflg = false;       /* permit non-unique group ID to be specified with -g */
84 static bool gflg = false;       /* ID value for the new group */
85 static bool fflg = false;       /* if group already exists, do nothing and exit(0) */
86 static bool rflg = false;       /* create a system account */
87 static bool pflg = false;       /* new encrypted password */
88
89 #ifdef SHADOWGRP
90 static bool is_shadow_grp;
91 #endif
92
93 /* local function prototypes */
94 static /*@noreturn@*/void usage (int status);
95 static void new_grent (struct group *grent);
96
97 #ifdef SHADOWGRP
98 static void new_sgent (struct sgrp *sgent);
99 #endif
100 static void grp_update (void);
101 static void check_new_name (void);
102 static void close_files (void);
103 static void open_files (void);
104 static void process_flags (int argc, char **argv);
105 static void check_flags (void);
106 static void check_perms (void);
107
108 /*
109  * usage - display usage message and exit
110  */
111 static /*@noreturn@*/void usage (int status)
112 {
113         FILE *usageout = (E_SUCCESS != status) ? stderr : stdout;
114         (void) fprintf (usageout,
115                         _("Usage: %s [options] GROUP\n"
116                           "\n"
117                           "Options:\n"),
118                         Prog);
119         (void) fputs (_("  -f, --force                   exit successfully if the group already exists,\n"
120                         "                                and cancel -g if the GID is already used\n"), usageout);
121         (void) fputs (_("  -g, --gid GID                 use GID for the new group\n"), usageout);
122         (void) fputs (_("  -h, --help                    display this help message and exit\n"), usageout);
123         (void) fputs (_("  -K, --key KEY=VALUE           override /etc/login.defs defaults\n"), usageout);
124         (void) fputs (_("  -o, --non-unique              allow to create groups with duplicate\n"
125                         "                                (non-unique) GID\n"), usageout);
126         (void) fputs (_("  -p, --password PASSWORD       use this encrypted password for the new group\n"), usageout);
127         (void) fputs (_("  -r, --system                  create a system account\n"), usageout);
128         (void) fputs (_("  -R, --root CHROOT_DIR         directory to chroot into\n"), usageout);
129         (void) fputs (_("  -P, --prefix PREFIX_DIR       directory prefix\n"), usageout);
130         (void) fputs ("\n", usageout);
131         exit (status);
132 }
133
134 /*
135  * new_grent - initialize 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         memzero (grent, sizeof *grent);
143         grent->gr_name = group_name;
144         if (pflg) {
145                 grent->gr_passwd = group_passwd;
146         } else {
147                 grent->gr_passwd = SHADOW_PASSWD_STRING;        /* XXX warning: const */
148         }
149         grent->gr_gid = group_id;
150         grent->gr_mem = &empty_list;
151 }
152
153 #ifdef  SHADOWGRP
154 /*
155  * new_sgent - initialize the values in a shadow group file entry
156  *
157  *      new_sgent() takes all of the values that have been entered and fills
158  *      in a (struct sgrp) with them.
159  */
160 static void new_sgent (struct sgrp *sgent)
161 {
162         memzero (sgent, sizeof *sgent);
163         sgent->sg_name = group_name;
164         if (pflg) {
165                 sgent->sg_passwd = group_passwd;
166         } else {
167                 sgent->sg_passwd = "!"; /* XXX warning: const */
168         }
169         sgent->sg_adm = &empty_list;
170         sgent->sg_mem = &empty_list;
171 }
172 #endif                          /* SHADOWGRP */
173
174 /*
175  * grp_update - add new group file entries
176  *
177  *      grp_update() writes the new records to the group files.
178  */
179 static void grp_update (void)
180 {
181         struct group grp;
182
183 #ifdef  SHADOWGRP
184         struct sgrp sgrp;
185 #endif                          /* SHADOWGRP */
186
187         /*
188          * To add the group, we need to update /etc/group.
189          * Make sure failures will be reported.
190          */
191         add_cleanup (cleanup_report_add_group_group, group_name);
192 #ifdef  SHADOWGRP
193         if (is_shadow_grp) {
194                 /* We also need to update /etc/gshadow */
195                 add_cleanup (cleanup_report_add_group_gshadow, group_name);
196         }
197 #endif
198
199         /*
200          * Create the initial entries for this new group.
201          */
202         new_grent (&grp);
203 #ifdef  SHADOWGRP
204         new_sgent (&sgrp);
205         if (is_shadow_grp && pflg) {
206                 grp.gr_passwd = SHADOW_PASSWD_STRING;   /* XXX warning: const */
207         }
208 #endif                          /* SHADOWGRP */
209
210         /*
211          * Write out the new group file entry.
212          */
213         if (gr_update (&grp) == 0) {
214                 fprintf (stderr,
215                          _("%s: failed to prepare the new %s entry '%s'\n"),
216                          Prog, gr_dbname (), grp.gr_name);
217                 exit (E_GRP_UPDATE);
218         }
219 #ifdef  SHADOWGRP
220         /*
221          * Write out the new shadow group entries as well.
222          */
223         if (is_shadow_grp && (sgr_update (&sgrp) == 0)) {
224                 fprintf (stderr,
225                          _("%s: failed to prepare the new %s entry '%s'\n"),
226                          Prog, sgr_dbname (), sgrp.sg_name);
227                 exit (E_GRP_UPDATE);
228         }
229 #endif                          /* SHADOWGRP */
230 }
231
232 /*
233  * check_new_name - check the new name for validity
234  *
235  *      check_new_name() insures that the new name doesn't contain any
236  *      illegal characters.
237  */
238 static void check_new_name (void)
239 {
240         if (is_valid_group_name (group_name)) {
241                 return;
242         }
243
244         /*
245          * All invalid group names land here.
246          */
247
248         fprintf (stderr, _("%s: '%s' is not a valid group name\n"),
249                  Prog, group_name);
250
251         exit (E_BAD_ARG);
252 }
253
254 /*
255  * close_files - close all of the files that were opened
256  *
257  *      close_files() closes all of the files that were opened for this new
258  *      group. This causes any modified entries to be written out.
259  */
260 static void close_files (void)
261 {
262         /* First, write the changes in the regular group database */
263         if (gr_close () == 0) {
264                 fprintf (stderr,
265                          _("%s: failure while writing changes to %s\n"),
266                          Prog, gr_dbname ());
267                 exit (E_GRP_UPDATE);
268         }
269 #ifdef WITH_AUDIT
270         audit_logger (AUDIT_ADD_GROUP, Prog,
271                       "adding group to /etc/group",
272                       group_name, (unsigned int) group_id,
273                       SHADOW_AUDIT_SUCCESS);
274 #endif
275         SYSLOG ((LOG_INFO, "group added to %s: name=%s, GID=%u",
276                  gr_dbname (), group_name, (unsigned int) group_id));
277         del_cleanup (cleanup_report_add_group_group);
278
279         cleanup_unlock_group (NULL);
280         del_cleanup (cleanup_unlock_group);
281
282         /* Now, write the changes in the shadow database */
283 #ifdef  SHADOWGRP
284         if (is_shadow_grp) {
285                 if (sgr_close () == 0) {
286                         fprintf (stderr,
287                                  _("%s: failure while writing changes to %s\n"),
288                                  Prog, sgr_dbname ());
289                         exit (E_GRP_UPDATE);
290                 }
291 #ifdef WITH_AUDIT
292                 audit_logger (AUDIT_ADD_GROUP, Prog,
293                               "adding group to /etc/gshadow",
294                               group_name, (unsigned int) group_id,
295                               SHADOW_AUDIT_SUCCESS);
296 #endif
297                 SYSLOG ((LOG_INFO, "group added to %s: name=%s",
298                          sgr_dbname (), group_name));
299                 del_cleanup (cleanup_report_add_group_gshadow);
300
301                 cleanup_unlock_gshadow (NULL);
302                 del_cleanup (cleanup_unlock_gshadow);
303         }
304 #endif                          /* SHADOWGRP */
305
306         /* Report success at the system level */
307 #ifdef WITH_AUDIT
308         audit_logger (AUDIT_ADD_GROUP, Prog,
309                       "",
310                       group_name, (unsigned int) group_id,
311                       SHADOW_AUDIT_SUCCESS);
312 #endif
313         SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u",
314                  group_name, (unsigned int) group_id));
315         del_cleanup (cleanup_report_add_group);
316 }
317
318 /*
319  * open_files - lock and open the group files
320  *
321  *      open_files() opens the two group files.
322  */
323 static void open_files (void)
324 {
325         /* First, lock the databases */
326         if (gr_lock () == 0) {
327                 fprintf (stderr,
328                          _("%s: cannot lock %s; try again later.\n"),
329                          Prog, gr_dbname ());
330                 exit (E_GRP_UPDATE);
331         }
332         add_cleanup (cleanup_unlock_group, NULL);
333
334 #ifdef  SHADOWGRP
335         if (is_shadow_grp) {
336                 if (sgr_lock () == 0) {
337                         fprintf (stderr,
338                                  _("%s: cannot lock %s; try again later.\n"),
339                                  Prog, sgr_dbname ());
340                         exit (E_GRP_UPDATE);
341                 }
342                 add_cleanup (cleanup_unlock_gshadow, NULL);
343         }
344 #endif                          /* SHADOWGRP */
345
346         /*
347          * Now if the group is not added, it's our fault.
348          * Make sure failures will be reported.
349          */
350         add_cleanup (cleanup_report_add_group, group_name);
351
352         /* And now open the databases */
353         if (gr_open (O_CREAT | O_RDWR) == 0) {
354                 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
355                 SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
356                 exit (E_GRP_UPDATE);
357         }
358
359 #ifdef  SHADOWGRP
360         if (is_shadow_grp) {
361                 if (sgr_open (O_CREAT | O_RDWR) == 0) {
362                         fprintf (stderr,
363                                  _("%s: cannot open %s\n"),
364                                  Prog, sgr_dbname ());
365                         SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
366                         exit (E_GRP_UPDATE);
367                 }
368         }
369 #endif                          /* SHADOWGRP */
370 }
371
372 /*
373  * process_flags - parse the command line options
374  *
375  *      It will not return if an error is encountered.
376  */
377 static void process_flags (int argc, char **argv)
378 {
379         /*
380          * Parse the command line options.
381          */
382         char *cp;
383         int c;
384         static struct option long_options[] = {
385                 {"force",      no_argument,       NULL, 'f'},
386                 {"gid",        required_argument, NULL, 'g'},
387                 {"help",       no_argument,       NULL, 'h'},
388                 {"key",        required_argument, NULL, 'K'},
389                 {"non-unique", no_argument,       NULL, 'o'},
390                 {"password",   required_argument, NULL, 'p'},
391                 {"system",     no_argument,       NULL, 'r'},
392                 {"root",       required_argument, NULL, 'R'},
393                 {"prefix",     required_argument, NULL, 'P'},
394                 {NULL, 0, NULL, '\0'}
395         };
396
397         while ((c = getopt_long (argc, argv, "fg:hK:op:rR:P:",
398                                  long_options, NULL)) != -1) {
399                 switch (c) {
400                 case 'f':
401                         /*
402                          * "force" - do nothing, just exit(0), if the
403                          * specified group already exists. With -g, if
404                          * specified gid already exists, choose another
405                          * (unique) gid (turn off -g). Based on the RedHat's
406                          * patch from shadow-utils-970616-9.
407                          */
408                         fflg = true;
409                         break;
410                 case 'g':
411                         gflg = true;
412                         if (   (get_gid (optarg, &group_id) == 0)
413                             || (group_id == (gid_t)-1)) {
414                                 fprintf (stderr,
415                                          _("%s: invalid group ID '%s'\n"),
416                                          Prog, optarg);
417                                 exit (E_BAD_ARG);
418                         }
419                         break;
420                 case 'h':
421                         usage (E_SUCCESS);
422                         /*@notreached@*/break;
423                 case 'K':
424                         /*
425                          * override login.defs defaults (-K name=value)
426                          * example: -K GID_MIN=100 -K GID_MAX=499
427                          * note: -K GID_MIN=10,GID_MAX=499 doesn't work yet
428                          */
429                         cp = strchr (optarg, '=');
430                         if (NULL == cp) {
431                                 fprintf (stderr,
432                                          _("%s: -K requires KEY=VALUE\n"),
433                                          Prog);
434                                 exit (E_BAD_ARG);
435                         }
436                         /* terminate name, point to value */
437                         *cp++ = '\0';
438                         if (putdef_str (optarg, cp) < 0) {
439                                 exit (E_BAD_ARG);
440                         }
441                         break;
442                 case 'o':
443                         oflg = true;
444                         break;
445                 case 'p':
446                         pflg = true;
447                         group_passwd = optarg;
448                         break;
449                 case 'r':
450                         rflg = true;
451                         break;
452                 case 'R': /* no-op, handled in process_root_flag () */
453                         break;
454                 case 'P': /* no-op, handled in process_prefix_flag () */
455                         break;
456                 default:
457                         usage (E_USAGE);
458                 }
459         }
460
461         /*
462          * Check the flags consistency
463          */
464         if (optind != argc - 1) {
465                 usage (E_USAGE);
466         }
467         group_name = argv[optind];
468
469         check_flags ();
470 }
471
472 /*
473  * check_flags - check flags and parameters consistency
474  *
475  *      It will not return if an error is encountered.
476  */
477 static void check_flags (void)
478 {
479         /* -o does not make sense without -g */
480         if (oflg && !gflg) {
481                 usage (E_USAGE);
482         }
483
484         check_new_name ();
485
486         /*
487          * Check if the group already exist.
488          */
489         /* local, no need for xgetgrnam */
490         if (prefix_getgrnam (group_name) != NULL) {
491                 /* The group already exist */
492                 if (fflg) {
493                         /* OK, no need to do anything */
494                         exit (E_SUCCESS);
495                 }
496                 fprintf (stderr,
497                          _("%s: group '%s' already exists\n"),
498                          Prog, group_name);
499                 exit (E_NAME_IN_USE);
500         }
501
502         if (gflg && (prefix_getgrgid (group_id) != NULL)) {
503                 /* A GID was specified, and a group already exist with that GID
504                  *  - either we will use this GID anyway (-o)
505                  *  - either we ignore the specified GID and
506                  *    we will use another one (-f)
507                  *  - either it is a failure
508                  */
509                 if (oflg) {
510                         /* Continue with this GID */
511                 } else if (fflg) {
512                         /* Turn off -g, we can use any GID */
513                         gflg = false;
514                 } else {
515                         fprintf (stderr,
516                                  _("%s: GID '%lu' already exists\n"),
517                                  Prog, (unsigned long int) group_id);
518                         exit (E_GID_IN_USE);
519                 }
520         }
521 }
522
523 /*
524  * check_perms - check if the caller is allowed to add a group
525  *
526  *      With PAM support, the setuid bit can be set on groupadd to allow
527  *      non-root users to groups.
528  *      Without PAM support, only users who can write in the group databases
529  *      can add groups.
530  *
531  *      It will not return if the user is not allowed.
532  */
533 static void check_perms (void)
534 {
535 #ifdef ACCT_TOOLS_SETUID
536 #ifdef USE_PAM
537         pam_handle_t *pamh = NULL;
538         int retval;
539         struct passwd *pampw;
540
541         pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
542         if (NULL == pampw) {
543                 fprintf (stderr,
544                          _("%s: Cannot determine your user name.\n"),
545                          Prog);
546                 exit (1);
547         }
548
549         retval = pam_start ("groupadd", pampw->pw_name, &conv, &pamh);
550
551         if (PAM_SUCCESS == retval) {
552                 retval = pam_authenticate (pamh, 0);
553         }
554
555         if (PAM_SUCCESS == retval) {
556                 retval = pam_acct_mgmt (pamh, 0);
557         }
558
559         if (PAM_SUCCESS != retval) {
560                 fprintf (stderr, _("%s: PAM: %s\n"),
561                          Prog, pam_strerror (pamh, retval));
562                 SYSLOG((LOG_ERR, "%s", pam_strerror (pamh, retval)));
563                 if (NULL != pamh) {
564                         (void) pam_end (pamh, retval);
565                 }
566                 exit (1);
567         }
568         (void) pam_end (pamh, retval);
569 #endif                          /* USE_PAM */
570 #endif                          /* ACCT_TOOLS_SETUID */
571 }
572
573 /*
574  * main - groupadd command
575  */
576 int main (int argc, char **argv)
577 {
578         /*
579          * Get my name so that I can use it to report errors.
580          */
581         Prog = Basename (argv[0]);
582
583         (void) setlocale (LC_ALL, "");
584         (void) bindtextdomain (PACKAGE, LOCALEDIR);
585         (void) textdomain (PACKAGE);
586
587         process_root_flag ("-R", argc, argv);
588         prefix = process_prefix_flag ("-P", argc, argv);
589
590         OPENLOG ("groupadd");
591 #ifdef WITH_AUDIT
592         audit_help_open ();
593 #endif
594
595         if (atexit (do_cleanups) != 0) {
596                 fprintf (stderr,
597                          _("%s: Cannot setup cleanup service.\n"),
598                          Prog);
599                 exit (1);
600         }
601
602         /*
603          * Parse the command line options.
604          */
605         process_flags (argc, argv);
606
607         check_perms ();
608
609 #ifdef SHADOWGRP
610         is_shadow_grp = sgr_file_present ();
611 #endif
612
613         /*
614          * Do the hard stuff - open the files, create the group entries,
615          * then close and update the files.
616          */
617         open_files ();
618
619         if (!gflg) {
620                 if (find_new_gid (rflg, &group_id, NULL) < 0) {
621                         exit (E_GID_IN_USE);
622                 }
623         }
624
625         grp_update ();
626         close_files ();
627
628         nscd_flush_cache ("group");
629         sssd_flush_cache (SSSD_DB_GROUP);
630
631         return E_SUCCESS;
632 }
633