]> git.cameronkatri.com Git - pw-darwin.git/blob - pw/pw_group.c
Remove duplicated #include.
[pw-darwin.git] / pw / pw_group.c
1 /*-
2 * Copyright (C) 1996
3 * David L. Nugent. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: pw_group.c,v 1.2 1996/12/19 15:22:44 davidn Exp $
27 */
28
29 #include <unistd.h>
30 #include <ctype.h>
31 #include <termios.h>
32
33 #include "pw.h"
34 #include "bitmap.h"
35 #include "pwupd.h"
36
37
38 static int print_group(struct group * grp, int pretty);
39 static gid_t gr_gidpolicy(struct userconf * cnf, struct cargs * args);
40
41 int
42 pw_group(struct userconf * cnf, int mode, struct cargs * args)
43 {
44 struct carg *a_name = getarg(args, 'n');
45 struct carg *a_gid = getarg(args, 'g');
46 struct carg *arg;
47 struct group *grp = NULL;
48 int grmembers = 0;
49 char **members = NULL;
50
51 static struct group fakegroup =
52 {
53 "nogroup",
54 "*",
55 -1,
56 NULL
57 };
58
59 /*
60 * With M_NEXT, we only need to return the
61 * next gid to stdout
62 */
63 if (mode == M_NEXT)
64 {
65 gid_t next = gr_gidpolicy(cnf, args);
66 if (getarg(args, 'q'))
67 return next;
68 printf("%ld\n", (long)next);
69 return EXIT_SUCCESS;
70 }
71
72 if (mode == M_PRINT && getarg(args, 'a')) {
73 int pretty = getarg(args, 'P') != NULL;
74
75 setgrent();
76 while ((grp = getgrent()) != NULL)
77 print_group(grp, pretty);
78 endgrent();
79 return EXIT_SUCCESS;
80 }
81 if (a_gid == NULL) {
82 if (a_name == NULL)
83 cmderr(EX_DATAERR, "group name or id required\n");
84
85 if (mode != M_ADD && grp == NULL && isdigit(*a_name->val)) {
86 (a_gid = a_name)->ch = 'g';
87 a_name = NULL;
88 }
89 }
90 grp = (a_name != NULL) ? getgrnam(a_name->val) : getgrgid((gid_t) atoi(a_gid->val));
91
92 if (mode == M_UPDATE || mode == M_DELETE || mode == M_PRINT) {
93 if (a_name == NULL && grp == NULL) /* Try harder */
94 grp = getgrgid(atoi(a_gid->val));
95
96 if (grp == NULL) {
97 if (mode == M_PRINT && getarg(args, 'F')) {
98 char *fmems[1];
99 fmems[0] = NULL;
100 fakegroup.gr_name = a_name ? a_name->val : "nogroup";
101 fakegroup.gr_gid = a_gid ? (gid_t) atol(a_gid->val) : -1;
102 fakegroup.gr_mem = fmems;
103 return print_group(&fakegroup, getarg(args, 'P') != NULL);
104 }
105 cmderr(EX_DATAERR, "unknown group `%s'\n", a_name ? a_name->val : a_gid->val);
106 }
107 if (a_name == NULL) /* Needed later */
108 a_name = addarg(args, 'n', grp->gr_name);
109
110 /*
111 * Handle deletions now
112 */
113 if (mode == M_DELETE) {
114 gid_t gid = grp->gr_gid;
115
116 if (delgrent(grp) == -1)
117 cmderr(EX_IOERR, "Error updating group file: %s\n", strerror(errno));
118 pw_log(cnf, mode, W_GROUP, "%s(%ld) removed", a_name->val, (long) gid);
119 return EXIT_SUCCESS;
120 } else if (mode == M_PRINT)
121 return print_group(grp, getarg(args, 'P') != NULL);
122
123 if (a_gid)
124 grp->gr_gid = (gid_t) atoi(a_gid->val);
125
126 if ((arg = getarg(args, 'l')) != NULL)
127 grp->gr_name = pw_checkname((u_char *)arg->val, 0);
128 } else {
129 if (a_name == NULL) /* Required */
130 cmderr(EX_DATAERR, "group name required\n");
131 else if (grp != NULL) /* Exists */
132 cmderr(EX_DATAERR, "group name `%s' already exists\n", a_name->val);
133
134 extendarray(&members, &grmembers, 200);
135 members[0] = NULL;
136 grp = &fakegroup;
137 grp->gr_name = pw_checkname((u_char *)a_name->val, 0);
138 grp->gr_passwd = "*";
139 grp->gr_gid = gr_gidpolicy(cnf, args);
140 grp->gr_mem = members;
141 }
142
143 /*
144 * This allows us to set a group password Group passwords is an
145 * antique idea, rarely used and insecure (no secure database) Should
146 * be discouraged, but it is apparently still supported by some
147 * software.
148 */
149
150 if ((arg = getarg(args, 'h')) != NULL) {
151 if (strcmp(arg->val, "-") == 0)
152 grp->gr_passwd = "*"; /* No access */
153 else {
154 int fd = atoi(arg->val);
155 int b;
156 int istty = isatty(fd);
157 struct termios t;
158 char *p, line[256];
159
160 if (istty) {
161 if (tcgetattr(fd, &t) == -1)
162 istty = 0;
163 else {
164 struct termios n = t;
165
166 /* Disable echo */
167 n.c_lflag &= ~(ECHO);
168 tcsetattr(fd, TCSANOW, &n);
169 printf("%sassword for group %s:", (mode == M_UPDATE) ? "New p" : "P", grp->gr_name);
170 fflush(stdout);
171 }
172 }
173 b = read(fd, line, sizeof(line) - 1);
174 if (istty) { /* Restore state */
175 tcsetattr(fd, TCSANOW, &t);
176 fputc('\n', stdout);
177 fflush(stdout);
178 }
179 if (b < 0) {
180 perror("-h file descriptor");
181 return EX_OSERR;
182 }
183 line[b] = '\0';
184 if ((p = strpbrk(line, " \t\r\n")) != NULL)
185 *p = '\0';
186 if (!*line)
187 cmderr(EX_DATAERR, "empty password read on file descriptor %d\n", fd);
188 grp->gr_passwd = pw_pwcrypt(line);
189 }
190 }
191
192 if (((arg = getarg(args, 'M')) != NULL || (arg = getarg(args, 'm')) != NULL) && arg->val) {
193 int i = 0;
194 char *p;
195 struct passwd *pwd;
196
197 /* Make sure this is not stay NULL with -M "" */
198 extendarray(&members, &grmembers, 200);
199 if (arg->ch == 'm') {
200 int k = 0;
201
202 while (grp->gr_mem[k] != NULL) {
203 if (extendarray(&members, &grmembers, i + 2) != -1) {
204 members[i++] = grp->gr_mem[k];
205 }
206 k++;
207 }
208 }
209 for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
210 int j;
211 if ((pwd = getpwnam(p)) == NULL) {
212 if (!isdigit(*p) || (pwd = getpwuid((uid_t) atoi(p))) == NULL)
213 cmderr(EX_NOUSER, "user `%s' does not exist\n", p);
214 }
215 /*
216 * Check for duplicates
217 */
218 for (j = 0; j < i && strcmp(members[j], pwd->pw_name)!=0; j++)
219 ;
220 if (j == i && extendarray(&members, &grmembers, i + 2) != -1)
221 members[i++] = newstr(pwd->pw_name);
222 }
223 while (i < grmembers)
224 members[i++] = NULL;
225 grp->gr_mem = members;
226 }
227
228 if (getarg(args, 'N') != NULL)
229 return print_group(grp, getarg(args, 'P') != NULL);
230
231 if ((mode == M_ADD && !addgrent(grp)) || (mode == M_UPDATE && !chggrent(a_name->val, grp))) {
232 perror("group update");
233 return EX_IOERR;
234 }
235 /* grp may have been invalidated */
236 if ((grp = getgrnam(a_name->val)) == NULL)
237 cmderr(EX_SOFTWARE, "group disappeared during update\n");
238
239 pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid);
240
241 if (members)
242 free(members);
243
244 return EXIT_SUCCESS;
245 }
246
247
248 static gid_t
249 gr_gidpolicy(struct userconf * cnf, struct cargs * args)
250 {
251 struct group *grp;
252 gid_t gid = (gid_t) - 1;
253 struct carg *a_gid = getarg(args, 'g');
254
255 /*
256 * Check the given gid, if any
257 */
258 if (a_gid != NULL) {
259 gid = (gid_t) atol(a_gid->val);
260
261 if ((grp = getgrgid(gid)) != NULL && getarg(args, 'o') == NULL)
262 cmderr(EX_DATAERR, "gid `%ld' has already been allocated\n", (long) grp->gr_gid);
263 } else {
264 struct bitmap bm;
265
266 /*
267 * We need to allocate the next available gid under one of
268 * two policies a) Grab the first unused gid b) Grab the
269 * highest possible unused gid
270 */
271 if (cnf->min_gid >= cnf->max_gid) { /* Sanity claus^H^H^H^Hheck */
272 cnf->min_gid = 1000;
273 cnf->max_gid = 32000;
274 }
275 bm = bm_alloc(cnf->max_gid - cnf->min_gid + 1);
276
277 /*
278 * Now, let's fill the bitmap from the password file
279 */
280 setgrent();
281 while ((grp = getgrent()) != NULL)
282 if (grp->gr_gid >= (int) cnf->min_gid && grp->gr_gid <= (int) cnf->max_gid)
283 bm_setbit(&bm, grp->gr_gid - cnf->min_gid);
284 endgrent();
285
286 /*
287 * Then apply the policy, with fallback to reuse if necessary
288 */
289 if (cnf->reuse_gids)
290 gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid);
291 else {
292 gid = (gid_t) (bm_lastset(&bm) + 1);
293 if (!bm_isset(&bm, gid))
294 gid += cnf->min_gid;
295 else
296 gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid);
297 }
298
299 /*
300 * Another sanity check
301 */
302 if (gid < cnf->min_gid || gid > cnf->max_gid)
303 cmderr(EX_SOFTWARE, "unable to allocate a new gid - range fully used\n");
304 bm_dealloc(&bm);
305 }
306 return gid;
307 }
308
309
310 static int
311 print_group(struct group * grp, int pretty)
312 {
313 if (!pretty) {
314 int buflen = 0;
315 char *buf = NULL;
316
317 fmtgrent(&buf, &buflen, grp);
318 fputs(buf, stdout);
319 free(buf);
320 } else {
321 int i;
322
323 printf("Group Name: %-10s #%lu\n"
324 " Members: ",
325 grp->gr_name, (long) grp->gr_gid);
326 for (i = 0; grp->gr_mem[i]; i++)
327 printf("%s%s", i ? "," : "", grp->gr_mem[i]);
328 fputs("\n\n", stdout);
329 }
330 return EXIT_SUCCESS;
331 }