pw_group.c (286150) | pw_group.c (286196) |
---|---|
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 --- 12 unchanged lines hidden (view full) --- 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 27#ifndef lint 28static const char rcsid[] = | 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 --- 12 unchanged lines hidden (view full) --- 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 27#ifndef lint 28static const char rcsid[] = |
29 "$FreeBSD: head/usr.sbin/pw/pw_group.c 286150 2015-08-01 09:55:47Z bapt $"; | 29 "$FreeBSD: head/usr.sbin/pw/pw_group.c 286196 2015-08-02 12:47:50Z bapt $"; |
30#endif /* not lint */ 31 32#include <ctype.h> 33#include <err.h> | 30#endif /* not lint */ 31 32#include <ctype.h> 33#include <err.h> |
34#include <grp.h> |
|
34#include <inttypes.h> | 35#include <inttypes.h> |
35#include <termios.h> | 36#include <libutil.h> 37#include <paths.h> |
36#include <stdbool.h> | 38#include <stdbool.h> |
39#include <termios.h> |
|
37#include <unistd.h> | 40#include <unistd.h> |
38#include <grp.h> 39#include <libutil.h> | |
40 41#include "pw.h" 42#include "bitmap.h" 43 | 41 42#include "pw.h" 43#include "bitmap.h" 44 |
44 | |
45static struct passwd *lookup_pwent(const char *user); 46static void delete_members(struct group *grp, char *list); | 45static struct passwd *lookup_pwent(const char *user); 46static void delete_members(struct group *grp, char *list); |
47static int print_group(struct group * grp); 48static gid_t gr_gidpolicy(struct userconf * cnf, long id); | 47static int print_group(struct group * grp, bool pretty); 48static gid_t gr_gidpolicy(struct userconf * cnf, intmax_t id); |
49 50static void | 49 50static void |
51set_passwd(struct group *grp, bool update) | 51grp_set_passwd(struct group *grp, bool update, int fd, bool precrypted) |
52{ 53 int b; 54 int istty; 55 struct termios t, n; 56 char *p, line[256]; 57 | 52{ 53 int b; 54 int istty; 55 struct termios t, n; 56 char *p, line[256]; 57 |
58 if (conf.fd == '-') { | 58 if (fd == -1) 59 return; 60 61 if (fd == '-') { |
59 grp->gr_passwd = "*"; /* No access */ 60 return; 61 } 62 | 62 grp->gr_passwd = "*"; /* No access */ 63 return; 64 } 65 |
63 if ((istty = isatty(conf.fd))) { | 66 if ((istty = isatty(fd))) { |
64 n = t; 65 /* Disable echo */ 66 n.c_lflag &= ~(ECHO); | 67 n = t; 68 /* Disable echo */ 69 n.c_lflag &= ~(ECHO); |
67 tcsetattr(conf.fd, TCSANOW, &n); | 70 tcsetattr(fd, TCSANOW, &n); |
68 printf("%sassword for group %s:", update ? "New p" : "P", 69 grp->gr_name); 70 fflush(stdout); 71 } | 71 printf("%sassword for group %s:", update ? "New p" : "P", 72 grp->gr_name); 73 fflush(stdout); 74 } |
72 b = read(conf.fd, line, sizeof(line) - 1); | 75 b = read(fd, line, sizeof(line) - 1); |
73 if (istty) { /* Restore state */ | 76 if (istty) { /* Restore state */ |
74 tcsetattr(conf.fd, TCSANOW, &t); | 77 tcsetattr(fd, TCSANOW, &t); |
75 fputc('\n', stdout); 76 fflush(stdout); 77 } 78 if (b < 0) 79 err(EX_OSERR, "-h file descriptor"); 80 line[b] = '\0'; 81 if ((p = strpbrk(line, " \t\r\n")) != NULL) 82 *p = '\0'; 83 if (!*line) 84 errx(EX_DATAERR, "empty password read on file descriptor %d", 85 conf.fd); | 78 fputc('\n', stdout); 79 fflush(stdout); 80 } 81 if (b < 0) 82 err(EX_OSERR, "-h file descriptor"); 83 line[b] = '\0'; 84 if ((p = strpbrk(line, " \t\r\n")) != NULL) 85 *p = '\0'; 86 if (!*line) 87 errx(EX_DATAERR, "empty password read on file descriptor %d", 88 conf.fd); |
86 if (conf.precrypted) { | 89 if (precrypted) { |
87 if (strchr(line, ':') != 0) 88 errx(EX_DATAERR, "wrong encrypted passwrd"); 89 grp->gr_passwd = line; 90 } else 91 grp->gr_passwd = pw_pwcrypt(line); 92} 93 94int 95pw_groupnext(struct userconf *cnf, bool quiet) 96{ 97 gid_t next = gr_gidpolicy(cnf, -1); 98 99 if (quiet) 100 return (next); 101 printf("%ju\n", (uintmax_t)next); 102 103 return (EXIT_SUCCESS); 104} 105 | 90 if (strchr(line, ':') != 0) 91 errx(EX_DATAERR, "wrong encrypted passwrd"); 92 grp->gr_passwd = line; 93 } else 94 grp->gr_passwd = pw_pwcrypt(line); 95} 96 97int 98pw_groupnext(struct userconf *cnf, bool quiet) 99{ 100 gid_t next = gr_gidpolicy(cnf, -1); 101 102 if (quiet) 103 return (next); 104 printf("%ju\n", (uintmax_t)next); 105 106 return (EXIT_SUCCESS); 107} 108 |
106static int 107pw_groupshow(const char *name, long id, struct group *fakegroup) | 109static struct group * 110getgroup(char *name, intmax_t id, bool fatal) |
108{ | 111{ |
109 struct group *grp = NULL; | 112 struct group *grp; |
110 | 113 |
111 if (id < 0 && name == NULL && !conf.all) 112 errx(EX_DATAERR, "groupname or id or '-a' required"); 113 114 if (conf.all) { 115 SETGRENT(); 116 while ((grp = GETGRENT()) != NULL) 117 print_group(grp); 118 ENDGRENT(); 119 120 return (EXIT_SUCCESS); 121 } 122 | 114 if (id < 0 && name == NULL) 115 errx(EX_DATAERR, "groupname or id required"); |
123 grp = (name != NULL) ? GETGRNAM(name) : GETGRGID(id); 124 if (grp == NULL) { | 116 grp = (name != NULL) ? GETGRNAM(name) : GETGRGID(id); 117 if (grp == NULL) { |
125 if (conf.force) { 126 grp = fakegroup; 127 } else { 128 if (name == NULL) 129 errx(EX_DATAERR, "unknown gid `%ld'", id); 130 errx(EX_DATAERR, "unknown group `%s'", name); 131 } 132 } 133 134 return (print_group(grp)); 135} 136 137static int 138pw_groupdel(const char *name, long id) 139{ 140 struct group *grp = NULL; 141 int rc; 142 143 grp = (name != NULL) ? GETGRNAM(name) : GETGRGID(id); 144 if (grp == NULL) { | 118 if (!fatal) 119 return (NULL); |
145 if (name == NULL) | 120 if (name == NULL) |
146 errx(EX_DATAERR, "unknown gid `%ld'", id); | 121 errx(EX_DATAERR, "unknown gid `%ju'", id); |
147 errx(EX_DATAERR, "unknown group `%s'", name); 148 } | 122 errx(EX_DATAERR, "unknown group `%s'", name); 123 } |
149 150 rc = delgrent(grp); 151 if (rc == -1) 152 err(EX_IOERR, "group '%s' not available (NIS?)", name); 153 else if (rc != 0) 154 err(EX_IOERR, "group update"); 155 pw_log(conf.userconf, M_DELETE, W_GROUP, "%s(%ld) removed", name, id); 156 157 return (EXIT_SUCCESS); | 124 return (grp); |
158} 159 | 125} 126 |
160int 161pw_group(int mode, char *name, long id, struct cargs * args) 162{ 163 int rc; 164 struct carg *arg; 165 struct group *grp = NULL; 166 struct userconf *cnf = conf.userconf; 167 168 static struct group fakegroup = 169 { 170 "nogroup", 171 "*", 172 -1, 173 NULL 174 }; 175 176 if (mode == M_NEXT) 177 return (pw_groupnext(cnf, conf.quiet)); 178 179 if (mode == M_PRINT) 180 return (pw_groupshow(name, id, &fakegroup)); 181 182 if (mode == M_DELETE) 183 return (pw_groupdel(name, id)); 184 185 if (mode == M_LOCK || mode == M_UNLOCK) 186 errx(EX_USAGE, "'lock' command is not available for groups"); 187 188 if (id < 0 && name == NULL) 189 errx(EX_DATAERR, "group name or id required"); 190 191 grp = (name != NULL) ? GETGRNAM(name) : GETGRGID(id); 192 193 if (mode == M_UPDATE) { 194 if (name == NULL && grp == NULL) /* Try harder */ 195 grp = GETGRGID(id); 196 197 if (grp == NULL) { 198 if (name == NULL) 199 errx(EX_DATAERR, "unknown group `%s'", name); 200 else 201 errx(EX_DATAERR, "unknown group `%ld'", id); 202 } 203 if (name == NULL) /* Needed later */ 204 name = grp->gr_name; 205 206 if (id > 0) 207 grp->gr_gid = (gid_t) id; 208 209 if (conf.newname != NULL) 210 grp->gr_name = pw_checkname(conf.newname, 0); 211 } else { 212 if (name == NULL) /* Required */ 213 errx(EX_DATAERR, "group name required"); 214 else if (grp != NULL) /* Exists */ 215 errx(EX_DATAERR, "group name `%s' already exists", name); 216 217 grp = &fakegroup; 218 grp->gr_name = pw_checkname(name, 0); 219 grp->gr_passwd = "*"; 220 grp->gr_gid = gr_gidpolicy(cnf, id); 221 grp->gr_mem = NULL; 222 } 223 224 /* 225 * This allows us to set a group password Group passwords is an 226 * antique idea, rarely used and insecure (no secure database) Should 227 * be discouraged, but it is apparently still supported by some 228 * software. 229 */ 230 231 if (conf.which == W_GROUP && conf.fd != -1) 232 set_passwd(grp, mode == M_UPDATE); 233 234 if (((arg = getarg(args, 'M')) != NULL || 235 (arg = getarg(args, 'd')) != NULL || 236 (arg = getarg(args, 'm')) != NULL) && arg->val) { 237 char *p; 238 struct passwd *pwd; 239 240 /* Make sure this is not stay NULL with -M "" */ 241 if (arg->ch == 'd') 242 delete_members(grp, arg->val); 243 else if (arg->ch == 'M') 244 grp->gr_mem = NULL; 245 246 for (p = strtok(arg->val, ", \t"); arg->ch != 'd' && p != NULL; 247 p = strtok(NULL, ", \t")) { 248 int j; 249 250 /* 251 * Check for duplicates 252 */ 253 pwd = lookup_pwent(p); 254 for (j = 0; grp->gr_mem != NULL && grp->gr_mem[j] != NULL; j++) { 255 if (strcmp(grp->gr_mem[j], pwd->pw_name) == 0) 256 break; 257 } 258 if (grp->gr_mem != NULL && grp->gr_mem[j] != NULL) 259 continue; 260 grp = gr_add(grp, pwd->pw_name); 261 } 262 } 263 264 if (conf.dryrun) 265 return print_group(grp); 266 267 if (mode == M_ADD && (rc = addgrent(grp)) != 0) { 268 if (rc == -1) 269 errx(EX_IOERR, "group '%s' already exists", 270 grp->gr_name); 271 else 272 err(EX_IOERR, "group update"); 273 } else if (mode == M_UPDATE && (rc = chggrent(name, grp)) != 0) { 274 if (rc == -1) 275 errx(EX_IOERR, "group '%s' not available (NIS?)", 276 grp->gr_name); 277 else 278 err(EX_IOERR, "group update"); 279 } 280 281 if (conf.newname != NULL) 282 name = conf.newname; 283 /* grp may have been invalidated */ 284 if ((grp = GETGRNAM(name)) == NULL) 285 errx(EX_SOFTWARE, "group disappeared during update"); 286 287 pw_log(cnf, mode, W_GROUP, "%s(%ju)", grp->gr_name, (uintmax_t)grp->gr_gid); 288 289 return EXIT_SUCCESS; 290} 291 292 | |
293/* 294 * Lookup a passwd entry using a name or UID. 295 */ 296static struct passwd * 297lookup_pwent(const char *user) 298{ 299 struct passwd *pwd; 300 --- 26 unchanged lines hidden (view full) --- 327 if (grp->gr_mem[k] == NULL) /* No match */ 328 continue; 329 330 for (; grp->gr_mem[k] != NULL; k++) 331 grp->gr_mem[k] = grp->gr_mem[k+1]; 332 } 333} 334 | 127/* 128 * Lookup a passwd entry using a name or UID. 129 */ 130static struct passwd * 131lookup_pwent(const char *user) 132{ 133 struct passwd *pwd; 134 --- 26 unchanged lines hidden (view full) --- 161 if (grp->gr_mem[k] == NULL) /* No match */ 162 continue; 163 164 for (; grp->gr_mem[k] != NULL; k++) 165 grp->gr_mem[k] = grp->gr_mem[k+1]; 166 } 167} 168 |
335 336static gid_t 337gr_gidpolicy(struct userconf * cnf, long id) | 169static gid_t 170gr_gidpolicy(struct userconf * cnf, intmax_t id) |
338{ 339 struct group *grp; | 171{ 172 struct group *grp; |
173 struct bitmap bm; |
|
340 gid_t gid = (gid_t) - 1; 341 342 /* 343 * Check the given gid, if any 344 */ 345 if (id > 0) { 346 gid = (gid_t) id; 347 348 if ((grp = GETGRGID(gid)) != NULL && conf.checkduplicate) 349 errx(EX_DATAERR, "gid `%ju' has already been allocated", (uintmax_t)grp->gr_gid); | 174 gid_t gid = (gid_t) - 1; 175 176 /* 177 * Check the given gid, if any 178 */ 179 if (id > 0) { 180 gid = (gid_t) id; 181 182 if ((grp = GETGRGID(gid)) != NULL && conf.checkduplicate) 183 errx(EX_DATAERR, "gid `%ju' has already been allocated", (uintmax_t)grp->gr_gid); |
350 } else { 351 struct bitmap bm; | 184 return (gid); 185 } |
352 | 186 |
353 /* 354 * We need to allocate the next available gid under one of 355 * two policies a) Grab the first unused gid b) Grab the 356 * highest possible unused gid 357 */ 358 if (cnf->min_gid >= cnf->max_gid) { /* Sanity claus^H^H^H^Hheck */ 359 cnf->min_gid = 1000; 360 cnf->max_gid = 32000; 361 } 362 bm = bm_alloc(cnf->max_gid - cnf->min_gid + 1); | 187 /* 188 * We need to allocate the next available gid under one of 189 * two policies a) Grab the first unused gid b) Grab the 190 * highest possible unused gid 191 */ 192 if (cnf->min_gid >= cnf->max_gid) { /* Sanity claus^H^H^H^Hheck */ 193 cnf->min_gid = 1000; 194 cnf->max_gid = 32000; 195 } 196 bm = bm_alloc(cnf->max_gid - cnf->min_gid + 1); |
363 | 197 |
364 /* 365 * Now, let's fill the bitmap from the password file 366 */ 367 SETGRENT(); 368 while ((grp = GETGRENT()) != NULL) 369 if ((gid_t)grp->gr_gid >= (gid_t)cnf->min_gid && 370 (gid_t)grp->gr_gid <= (gid_t)cnf->max_gid) 371 bm_setbit(&bm, grp->gr_gid - cnf->min_gid); 372 ENDGRENT(); | 198 /* 199 * Now, let's fill the bitmap from the password file 200 */ 201 SETGRENT(); 202 while ((grp = GETGRENT()) != NULL) 203 if ((gid_t)grp->gr_gid >= (gid_t)cnf->min_gid && 204 (gid_t)grp->gr_gid <= (gid_t)cnf->max_gid) 205 bm_setbit(&bm, grp->gr_gid - cnf->min_gid); 206 ENDGRENT(); |
373 | 207 |
374 /* 375 * Then apply the policy, with fallback to reuse if necessary 376 */ 377 if (cnf->reuse_gids) | 208 /* 209 * Then apply the policy, with fallback to reuse if necessary 210 */ 211 if (cnf->reuse_gids) 212 gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); 213 else { 214 gid = (gid_t) (bm_lastset(&bm) + 1); 215 if (!bm_isset(&bm, gid)) 216 gid += cnf->min_gid; 217 else |
378 gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); | 218 gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); |
379 else { 380 gid = (gid_t) (bm_lastset(&bm) + 1); 381 if (!bm_isset(&bm, gid)) 382 gid += cnf->min_gid; 383 else 384 gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); 385 } 386 387 /* 388 * Another sanity check 389 */ 390 if (gid < cnf->min_gid || gid > cnf->max_gid) 391 errx(EX_SOFTWARE, "unable to allocate a new gid - range fully used"); 392 bm_dealloc(&bm); | |
393 } | 219 } |
394 return gid; | 220 221 /* 222 * Another sanity check 223 */ 224 if (gid < cnf->min_gid || gid > cnf->max_gid) 225 errx(EX_SOFTWARE, "unable to allocate a new gid - range fully used"); 226 bm_dealloc(&bm); 227 return (gid); |
395} 396 | 228} 229 |
397 | |
398static int | 230static int |
399print_group(struct group * grp) | 231print_group(struct group * grp, bool pretty) |
400{ | 232{ |
401 if (!conf.pretty) { 402 char *buf = NULL; | 233 char *buf = NULL; 234 int i; |
403 | 235 |
404 buf = gr_make(grp); 405 printf("%s\n", buf); 406 free(buf); 407 } else { 408 int i; 409 | 236 if (pretty) { |
410 printf("Group Name: %-15s #%lu\n" 411 " Members: ", 412 grp->gr_name, (long) grp->gr_gid); 413 if (grp->gr_mem != NULL) { 414 for (i = 0; grp->gr_mem[i]; i++) 415 printf("%s%s", i ? "," : "", grp->gr_mem[i]); 416 } 417 fputs("\n\n", stdout); | 237 printf("Group Name: %-15s #%lu\n" 238 " Members: ", 239 grp->gr_name, (long) grp->gr_gid); 240 if (grp->gr_mem != NULL) { 241 for (i = 0; grp->gr_mem[i]; i++) 242 printf("%s%s", i ? "," : "", grp->gr_mem[i]); 243 } 244 fputs("\n\n", stdout); |
245 return (EXIT_SUCCESS); |
|
418 } | 246 } |
419 return EXIT_SUCCESS; | 247 248 buf = gr_make(grp); 249 printf("%s\n", buf); 250 free(buf); 251 return (EXIT_SUCCESS); |
420} | 252} |
253 254int 255pw_group_next(int argc, char **argv, char *arg1 __unused) 256{ 257 struct userconf *cnf; 258 const char *cfg = NULL; 259 int ch; 260 bool quiet; 261 262 while ((ch = getopt(argc, argv, "Cq")) != -1) { 263 switch (ch) { 264 case 'C': 265 cfg = optarg; 266 break; 267 case 'q': 268 quiet = true; 269 break; 270 } 271 } 272 273 if (quiet) 274 freopen(_PATH_DEVNULL, "w", stderr); 275 cnf = get_userconfig(cfg); 276 return (pw_groupnext(cnf, quiet)); 277} 278 279int 280pw_group_show(int argc, char **argv, char *arg1) 281{ 282 struct group *grp = NULL; 283 char *name; 284 intmax_t id = -1; 285 int ch; 286 bool all, force, quiet, pretty; 287 288 all = force = quiet = pretty = false; 289 290 struct group fakegroup = { 291 "nogroup", 292 "*", 293 -1, 294 NULL 295 }; 296 297 if (arg1 != NULL) { 298 if (strspn(arg1, "0123456789") == strlen(arg1)) 299 id = pw_checkid(arg1, GID_MAX); 300 else 301 name = arg1; 302 } 303 304 while ((ch = getopt(argc, argv, "C:qn:g:FPa")) != -1) { 305 switch (ch) { 306 case 'C': 307 /* ignore compatibility */ 308 break; 309 case 'q': 310 quiet = true; 311 break; 312 case 'n': 313 name = optarg; 314 break; 315 case 'g': 316 id = pw_checkid(optarg, GID_MAX); 317 break; 318 case 'F': 319 force = true; 320 break; 321 case 'P': 322 pretty = true; 323 break; 324 case 'a': 325 all = true; 326 break; 327 } 328 } 329 330 if (quiet) 331 freopen(_PATH_DEVNULL, "w", stderr); 332 333 if (all) { 334 SETGRENT(); 335 while ((grp = GETGRENT()) != NULL) 336 print_group(grp, pretty); 337 ENDGRENT(); 338 return (EXIT_SUCCESS); 339 } 340 341 grp = getgroup(name, id, !force); 342 if (grp == NULL) 343 grp = &fakegroup; 344 345 return (print_group(grp, pretty)); 346} 347 348int 349pw_group_del(int argc, char **argv, char *arg1) 350{ 351 struct userconf *cnf = NULL; 352 struct group *grp = NULL; 353 char *name; 354 const char *cfg = NULL; 355 intmax_t id = -1; 356 int ch, rc; 357 bool quiet = false; 358 bool nis = false; 359 360 if (arg1 != NULL) { 361 if (strspn(arg1, "0123456789") == strlen(arg1)) 362 id = pw_checkid(arg1, GID_MAX); 363 else 364 name = arg1; 365 } 366 367 while ((ch = getopt(argc, argv, "C:qn:g:Y")) != -1) { 368 switch (ch) { 369 case 'C': 370 cfg = optarg; 371 break; 372 case 'q': 373 quiet = true; 374 break; 375 case 'n': 376 name = optarg; 377 break; 378 case 'g': 379 id = pw_checkid(optarg, GID_MAX); 380 break; 381 case 'Y': 382 nis = true; 383 break; 384 } 385 } 386 387 if (quiet) 388 freopen(_PATH_DEVNULL, "w", stderr); 389 grp = getgroup(name, id, true); 390 cnf = get_userconfig(cfg); 391 rc = delgrent(grp); 392 if (rc == -1) 393 err(EX_IOERR, "group '%s' not available (NIS?)", name); 394 else if (rc != 0) 395 err(EX_IOERR, "group update"); 396 pw_log(cnf, M_DELETE, W_GROUP, "%s(%ju) removed", name, 397 (uintmax_t)id); 398 399 if (nis && nis_update() == 0) 400 pw_log(cnf, M_DELETE, W_GROUP, "NIS maps updated"); 401 402 return (EXIT_SUCCESS); 403} 404 405static bool 406grp_has_member(struct group *grp, const char *name) 407{ 408 int j; 409 410 for (j = 0; grp->gr_mem != NULL && grp->gr_mem[j] != NULL; j++) 411 if (strcmp(grp->gr_mem[j], name) == 0) 412 return (true); 413 return (false); 414} 415 416static void 417grp_add_members(struct group **grp, char *members) 418{ 419 struct passwd *pwd; 420 char *p; 421 char tok[] = ", \t"; 422 423 if (members == NULL) 424 return; 425 for (p = strtok(members, tok); p != NULL; p = strtok(NULL, tok)) { 426 pwd = lookup_pwent(p); 427 if (grp_has_member(*grp, pwd->pw_name)) 428 continue; 429 *grp = gr_add(*grp, pwd->pw_name); 430 } 431} 432 433int 434groupadd(struct userconf *cnf, char *name, gid_t id, char *members, int fd, 435 bool dryrun, bool pretty, bool precrypted) 436{ 437 struct group *grp; 438 int rc; 439 440 struct group fakegroup = { 441 "nogroup", 442 "*", 443 -1, 444 NULL 445 }; 446 447 grp = &fakegroup; 448 grp->gr_name = pw_checkname(name, 0); 449 grp->gr_passwd = "*"; 450 grp->gr_gid = gr_gidpolicy(cnf, id); 451 grp->gr_mem = NULL; 452 453 /* 454 * This allows us to set a group password Group passwords is an 455 * antique idea, rarely used and insecure (no secure database) Should 456 * be discouraged, but it is apparently still supported by some 457 * software. 458 */ 459 grp_set_passwd(grp, false, fd, precrypted); 460 grp_add_members(&grp, members); 461 if (dryrun) 462 return (print_group(grp, pretty)); 463 464 if ((rc = addgrent(grp)) != 0) { 465 if (rc == -1) 466 errx(EX_IOERR, "group '%s' already exists", 467 grp->gr_name); 468 else 469 err(EX_IOERR, "group update"); 470 } 471 472 pw_log(cnf, M_ADD, W_GROUP, "%s(%ju)", grp->gr_name, 473 (uintmax_t)grp->gr_gid); 474 475 return (EXIT_SUCCESS); 476} 477 478int 479pw_group_add(int argc, char **argv, char *arg1) 480{ 481 struct userconf *cnf = NULL; 482 char *name = NULL; 483 char *members = NULL; 484 const char *cfg = NULL; 485 intmax_t id = -1; 486 int ch, rc, fd = -1; 487 bool quiet, precrypted, dryrun, pretty, nis; 488 489 quiet = precrypted = dryrun = pretty = nis = false; 490 491 if (arg1 != NULL) { 492 if (strspn(arg1, "0123456789") == strlen(arg1)) 493 id = pw_checkid(arg1, GID_MAX); 494 else 495 name = arg1; 496 } 497 498 while ((ch = getopt(argc, argv, "C:qn:g:h:H:M:oNPY")) != -1) { 499 switch (ch) { 500 case 'C': 501 cfg = optarg; 502 break; 503 case 'q': 504 quiet = true; 505 break; 506 case 'n': 507 name = optarg; 508 break; 509 case 'g': 510 id = pw_checkid(optarg, GID_MAX); 511 break; 512 case 'H': 513 if (fd != -1) 514 errx(EX_USAGE, "'-h' and '-H' are mutually " 515 "exclusive options"); 516 fd = pw_checkfd(optarg); 517 precrypted = true; 518 if (fd == '-') 519 errx(EX_USAGE, "-H expects a file descriptor"); 520 break; 521 case 'h': 522 if (fd != -1) 523 errx(EX_USAGE, "'-h' and '-H' are mutually " 524 "exclusive options"); 525 fd = pw_checkfd(optarg); 526 break; 527 case 'M': 528 members = optarg; 529 break; 530 case 'o': 531 conf.checkduplicate = false; 532 break; 533 case 'N': 534 dryrun = true; 535 break; 536 case 'P': 537 pretty = true; 538 break; 539 case 'Y': 540 nis = true; 541 break; 542 } 543 } 544 545 if (quiet) 546 freopen(_PATH_DEVNULL, "w", stderr); 547 if (name == NULL) 548 errx(EX_DATAERR, "group name required"); 549 cnf = get_userconfig(cfg); 550 rc = groupadd(cnf, name, gr_gidpolicy(cnf, id), members, fd, dryrun, 551 pretty, precrypted); 552 if (nis && rc == EXIT_SUCCESS && nis_update() == 0) 553 pw_log(cnf, M_ADD, W_GROUP, "NIS maps updated"); 554 555 return (rc); 556} 557 558int 559pw_group_mod(int argc, char **argv, char *arg1) 560{ 561 struct userconf *cnf; 562 struct group *grp = NULL; 563 const char *cfg = NULL; 564 char *oldmembers = NULL; 565 char *members = NULL; 566 char *newmembers = NULL; 567 char *newname = NULL; 568 char *name = NULL; 569 intmax_t id = -1; 570 int ch, rc, fd = -1; 571 bool quiet, pretty, dryrun, nis, precrypted; 572 573 quiet = pretty = dryrun = nis = precrypted = false; 574 575 if (arg1 != NULL) { 576 if (strspn(arg1, "0123456789") == strlen(arg1)) 577 id = pw_checkid(arg1, GID_MAX); 578 else 579 name = arg1; 580 } 581 582 while ((ch = getopt(argc, argv, "C:qn:d:g:l:h:H:M:m:NPY")) != -1) { 583 switch (ch) { 584 case 'C': 585 cfg = optarg; 586 break; 587 case 'q': 588 quiet = true; 589 break; 590 case 'n': 591 name = optarg; 592 break; 593 case 'g': 594 id = pw_checkid(optarg, GID_MAX); 595 break; 596 case 'd': 597 oldmembers = optarg; 598 break; 599 case 'l': 600 newname = optarg; 601 break; 602 case 'H': 603 if (fd != -1) 604 errx(EX_USAGE, "'-h' and '-H' are mutually " 605 "exclusive options"); 606 fd = pw_checkfd(optarg); 607 precrypted = true; 608 if (fd == '-') 609 errx(EX_USAGE, "-H expects a file descriptor"); 610 break; 611 case 'h': 612 if (fd != -1) 613 errx(EX_USAGE, "'-h' and '-H' are mutually " 614 "exclusive options"); 615 fd = pw_checkfd(optarg); 616 break; 617 case 'M': 618 members = optarg; 619 break; 620 case 'm': 621 newmembers = optarg; 622 break; 623 case 'N': 624 dryrun = true; 625 break; 626 case 'P': 627 pretty = true; 628 break; 629 case 'Y': 630 nis = true; 631 break; 632 } 633 } 634 if (quiet) 635 freopen(_PATH_DEVNULL, "w", stderr); 636 cnf = get_userconfig(cfg); 637 grp = getgroup(name, id, true); 638 if (name == NULL) 639 name = grp->gr_name; 640 if (id > 0) 641 grp->gr_gid = id; 642 643 if (newname != NULL) 644 grp->gr_name = pw_checkname(newname, 0); 645 646 grp_set_passwd(grp, true, fd, precrypted); 647 /* 648 * Keep the same logic as old code for now: 649 * if -M is passed, -d and -m are ignored 650 * then id -d, -m is ignored 651 * last is -m 652 */ 653 654 if (members) { 655 grp->gr_mem = NULL; 656 grp_add_members(&grp, members); 657 } else if (oldmembers) { 658 delete_members(grp, oldmembers); 659 } else if (newmembers) { 660 grp_add_members(&grp, newmembers); 661 } 662 663 if ((rc = chggrent(name, grp)) != 0) { 664 if (rc == -1) 665 errx(EX_IOERR, "group '%s' not available (NIS?)", 666 grp->gr_name); 667 else 668 err(EX_IOERR, "group update"); 669 } 670 671 if (newname) 672 name = newname; 673 674 /* grp may have been invalidated */ 675 if ((grp = GETGRNAM(name)) == NULL) 676 errx(EX_SOFTWARE, "group disappeared during update"); 677 678 pw_log(cnf, M_UPDATE, W_GROUP, "%s(%ju)", grp->gr_name, 679 (uintmax_t)grp->gr_gid); 680 681 if (nis && nis_update() == 0) 682 pw_log(cnf, M_UPDATE, W_GROUP, "NIS maps updated"); 683 684 return (EXIT_SUCCESS); 685} |
|