httpd: speed up httpd.conf at the cost of 49 bytes of code
[oweals/busybox.git] / loginutils / addgroup.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * addgroup - add groups to /etc/group and /etc/gshadow
4  *
5  * Copyright (C) 1999 by Lineo, inc. and John Beppu
6  * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7  * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
8  *
9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10  *
11  */
12 #include "libbb.h"
13
14 #define OPT_GID                       (1 << 0)
15 #define OPT_SYSTEM_ACCOUNT            (1 << 1)
16
17 /* We assume GID_T_MAX == INT_MAX */
18 static void xgroup_study(struct group *g)
19 {
20         unsigned max = INT_MAX;
21
22         /* Make sure gr_name is unused */
23         if (getgrnam(g->gr_name)) {
24                 bb_error_msg_and_die("%s '%s' in use", "group", g->gr_name);
25                 /* these format strings are reused in adduser and addgroup */
26         }
27
28         /* if a specific gid is requested, the --system switch and */
29         /* min and max values are overriden, and the range of valid */
30         /* gid values is set to [0, INT_MAX] */
31         if (!(option_mask32 & OPT_GID)) {
32                 if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
33                         g->gr_gid = 100; /* FIRST_SYSTEM_GID */
34                         max = 999;       /* LAST_SYSTEM_GID */
35                 } else {
36                         g->gr_gid = 1000; /* FIRST_GID */
37                         max = 64999;      /* LAST_GID */
38                 }
39         }
40         /* Check if the desired gid is free
41          * or find the first free one */
42         while (1) {
43                 if (!getgrgid(g->gr_gid)) {
44                         return; /* found free group: return */
45                 }
46                 if (option_mask32 & OPT_GID) {
47                         /* -g N, cannot pick gid other than N: error */
48                         bb_error_msg_and_die("%s '%s' in use", "gid", itoa(g->gr_gid));
49                         /* this format strings is reused in adduser and addgroup */
50                 }
51                 if (g->gr_gid == max) {
52                         /* overflowed: error */
53                         bb_error_msg_and_die("no %cids left", 'g');
54                         /* this format string is reused in adduser and addgroup */
55                 }
56                 g->gr_gid++;
57         }
58 }
59
60 /* append a new user to the passwd file */
61 static void new_group(char *group, gid_t gid)
62 {
63         struct group gr;
64         char *p;
65
66         /* make sure gid and group haven't already been allocated */
67         gr.gr_gid = gid;
68         gr.gr_name = group;
69         xgroup_study(&gr);
70
71         /* add entry to group */
72         p = xasprintf("x:%u:", (unsigned) gr.gr_gid);
73         if (update_passwd(bb_path_group_file, group, p, NULL) < 0)
74                 exit(EXIT_FAILURE);
75         if (ENABLE_FEATURE_CLEAN_UP)
76                 free(p);
77 #if ENABLE_FEATURE_SHADOWPASSWDS
78         /* Ignore errors: if file is missing we suppose admin doesn't want it */
79         update_passwd(bb_path_gshadow_file, group, "!::", NULL);
80 #endif
81 }
82
83 #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
84 static const char addgroup_longopts[] ALIGN1 =
85                 "gid\0"                 Required_argument "g"
86                 "system\0"              No_argument       "S"
87                 ;
88 #endif
89
90 /*
91  * addgroup will take a login_name as its first parameter.
92  *
93  * gid can be customized via command-line parameters.
94  * If called with two non-option arguments, addgroup
95  * will add an existing user to an existing group.
96  */
97 int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
98 int addgroup_main(int argc UNUSED_PARAM, char **argv)
99 {
100         unsigned opts;
101         unsigned gid = 0;
102
103         /* need to be root */
104         if (geteuid()) {
105                 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
106         }
107 #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
108         applet_long_options = addgroup_longopts;
109 #endif
110         /* Syntax:
111          *  addgroup group
112          *  addgroup -g num group
113          *  addgroup user group
114          * Check for min, max and missing args */
115         opt_complementary = "-1:?2:g+";
116         opts = getopt32(argv, "g:S", &gid);
117         /* move past the commandline options */
118         argv += optind;
119         //argc -= optind;
120
121 #if ENABLE_FEATURE_ADDUSER_TO_GROUP
122         if (argv[1]) {
123                 struct group *gr;
124
125                 if (opts & OPT_GID) {
126                         /* -g was there, but "addgroup -g num user group"
127                          * is a no-no */
128                         bb_show_usage();
129                 }
130
131                 /* check if group and user exist */
132                 xuname2uid(argv[0]); /* unknown user: exit */
133                 gr = xgetgrnam(argv[1]); /* unknown group: exit */
134                 /* check if user is already in this group */
135                 for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) {
136                         if (!strcmp(argv[0], *(gr->gr_mem))) {
137                                 /* user is already in group: do nothing */
138                                 return EXIT_SUCCESS;
139                         }
140                 }
141                 if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) {
142                         return EXIT_FAILURE;
143                 }
144 # if ENABLE_FEATURE_SHADOWPASSWDS
145                 update_passwd(bb_path_gshadow_file, argv[1], NULL, argv[0]);
146 # endif
147         } else
148 #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */
149         {
150                 die_if_bad_username(argv[0]);
151                 new_group(argv[0], gid);
152
153         }
154         /* Reached only on success */
155         return EXIT_SUCCESS;
156 }