pw_group.c revision 286196
1270631Sjfv/*- 2270631Sjfv * Copyright (C) 1996 3292095Ssmh * David L. Nugent. All rights reserved. 4270631Sjfv * 5270631Sjfv * Redistribution and use in source and binary forms, with or without 6270631Sjfv * modification, are permitted provided that the following conditions 7270631Sjfv * are met: 8270631Sjfv * 1. Redistributions of source code must retain the above copyright 9270631Sjfv * notice, this list of conditions and the following disclaimer. 10270631Sjfv * 2. Redistributions in binary form must reproduce the above copyright 11270631Sjfv * notice, this list of conditions and the following disclaimer in the 12270631Sjfv * documentation and/or other materials provided with the distribution. 13270631Sjfv * 14270631Sjfv * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 15270631Sjfv * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16270631Sjfv * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17270631Sjfv * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 18270631Sjfv * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19270631Sjfv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20270631Sjfv * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21270631Sjfv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22270631Sjfv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23270631Sjfv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24270631Sjfv * SUCH DAMAGE. 25270631Sjfv */ 26270631Sjfv 27270631Sjfv#ifndef lint 28270631Sjfvstatic const char rcsid[] = 29270631Sjfv "$FreeBSD: head/usr.sbin/pw/pw_group.c 286196 2015-08-02 12:47:50Z bapt $"; 30270631Sjfv#endif /* not lint */ 31270631Sjfv 32270631Sjfv#include <ctype.h> 33270631Sjfv#include <err.h> 34270631Sjfv#include <grp.h> 35270631Sjfv#include <inttypes.h> 36270631Sjfv#include <libutil.h> 37270631Sjfv#include <paths.h> 38270631Sjfv#include <stdbool.h> 39270631Sjfv#include <termios.h> 40270631Sjfv#include <unistd.h> 41270631Sjfv 42270631Sjfv#include "pw.h" 43270631Sjfv#include "bitmap.h" 44270631Sjfv 45270631Sjfvstatic struct passwd *lookup_pwent(const char *user); 46270631Sjfvstatic void delete_members(struct group *grp, char *list); 47270631Sjfvstatic int print_group(struct group * grp, bool pretty); 48270631Sjfvstatic gid_t gr_gidpolicy(struct userconf * cnf, intmax_t id); 49270631Sjfv 50270919Sjfvstatic void 51270631Sjfvgrp_set_passwd(struct group *grp, bool update, int fd, bool precrypted) 52270631Sjfv{ 53270919Sjfv int b; 54270631Sjfv int istty; 55270631Sjfv struct termios t, n; 56270631Sjfv char *p, line[256]; 57270631Sjfv 58270631Sjfv if (fd == -1) 59270631Sjfv return; 60270631Sjfv 61270631Sjfv if (fd == '-') { 62270631Sjfv grp->gr_passwd = "*"; /* No access */ 63270631Sjfv return; 64270631Sjfv } 65270631Sjfv 66270631Sjfv if ((istty = isatty(fd))) { 67270631Sjfv n = t; 68270631Sjfv /* Disable echo */ 69270631Sjfv n.c_lflag &= ~(ECHO); 70270631Sjfv tcsetattr(fd, TCSANOW, &n); 71270631Sjfv printf("%sassword for group %s:", update ? "New p" : "P", 72270631Sjfv grp->gr_name); 73270631Sjfv fflush(stdout); 74270631Sjfv } 75270631Sjfv b = read(fd, line, sizeof(line) - 1); 76270631Sjfv if (istty) { /* Restore state */ 77270631Sjfv tcsetattr(fd, TCSANOW, &t); 78270631Sjfv fputc('\n', stdout); 79270631Sjfv fflush(stdout); 80270631Sjfv } 81270631Sjfv if (b < 0) 82270631Sjfv err(EX_OSERR, "-h file descriptor"); 83270631Sjfv line[b] = '\0'; 84270631Sjfv if ((p = strpbrk(line, " \t\r\n")) != NULL) 85270631Sjfv *p = '\0'; 86270631Sjfv if (!*line) 87270631Sjfv errx(EX_DATAERR, "empty password read on file descriptor %d", 88270631Sjfv conf.fd); 89270631Sjfv if (precrypted) { 90270631Sjfv if (strchr(line, ':') != 0) 91270631Sjfv errx(EX_DATAERR, "wrong encrypted passwrd"); 92270631Sjfv grp->gr_passwd = line; 93292097Ssmh } else 94292097Ssmh grp->gr_passwd = pw_pwcrypt(line); 95292097Ssmh} 96292097Ssmh 97292097Ssmhint 98270631Sjfvpw_groupnext(struct userconf *cnf, bool quiet) 99270631Sjfv{ 100270631Sjfv gid_t next = gr_gidpolicy(cnf, -1); 101292094Ssmh 102270631Sjfv if (quiet) 103270631Sjfv return (next); 104270631Sjfv printf("%ju\n", (uintmax_t)next); 105270631Sjfv 106270631Sjfv return (EXIT_SUCCESS); 107270631Sjfv} 108270631Sjfv 109292094Ssmhstatic struct group * 110270631Sjfvgetgroup(char *name, intmax_t id, bool fatal) 111292094Ssmh{ 112292094Ssmh struct group *grp; 113292094Ssmh 114292094Ssmh if (id < 0 && name == NULL) 115292094Ssmh errx(EX_DATAERR, "groupname or id required"); 116270631Sjfv grp = (name != NULL) ? GETGRNAM(name) : GETGRGID(id); 117270631Sjfv if (grp == NULL) { 118270631Sjfv if (!fatal) 119270631Sjfv return (NULL); 120270631Sjfv if (name == NULL) 121270631Sjfv errx(EX_DATAERR, "unknown gid `%ju'", id); 122270631Sjfv errx(EX_DATAERR, "unknown group `%s'", name); 123270631Sjfv } 124270631Sjfv return (grp); 125270631Sjfv} 126270631Sjfv 127270631Sjfv/* 128270631Sjfv * Lookup a passwd entry using a name or UID. 129270631Sjfv */ 130270631Sjfvstatic struct passwd * 131270631Sjfvlookup_pwent(const char *user) 132270631Sjfv{ 133270631Sjfv struct passwd *pwd; 134270631Sjfv 135270631Sjfv if ((pwd = GETPWNAM(user)) == NULL && 136270631Sjfv (!isdigit((unsigned char)*user) || 137270631Sjfv (pwd = getpwuid((uid_t) atoi(user))) == NULL)) 138270631Sjfv errx(EX_NOUSER, "user `%s' does not exist", user); 139270631Sjfv 140270631Sjfv return (pwd); 141270631Sjfv} 142292094Ssmh 143270631Sjfv 144270631Sjfv/* 145270631Sjfv * Delete requested members from a group. 146270631Sjfv */ 147270631Sjfvstatic void 148270631Sjfvdelete_members(struct group *grp, char *list) 149270631Sjfv{ 150270631Sjfv char *p; 151270631Sjfv int k; 152270631Sjfv 153270631Sjfv if (grp->gr_mem == NULL) 154270631Sjfv return; 155270631Sjfv 156270631Sjfv for (p = strtok(list, ", \t"); p != NULL; p = strtok(NULL, ", \t")) { 157270631Sjfv for (k = 0; grp->gr_mem[k] != NULL; k++) { 158292094Ssmh if (strcmp(grp->gr_mem[k], p) == 0) 159270631Sjfv break; 160270631Sjfv } 161270631Sjfv if (grp->gr_mem[k] == NULL) /* No match */ 162270631Sjfv continue; 163270631Sjfv 164270631Sjfv for (; grp->gr_mem[k] != NULL; k++) 165270631Sjfv grp->gr_mem[k] = grp->gr_mem[k+1]; 166270631Sjfv } 167270631Sjfv} 168270631Sjfv 169270631Sjfvstatic gid_t 170270631Sjfvgr_gidpolicy(struct userconf * cnf, intmax_t id) 171270631Sjfv{ 172270631Sjfv struct group *grp; 173270631Sjfv struct bitmap bm; 174270631Sjfv gid_t gid = (gid_t) - 1; 175270631Sjfv 176274360Sjfv /* 177274360Sjfv * Check the given gid, if any 178274360Sjfv */ 179270631Sjfv if (id > 0) { 180270631Sjfv gid = (gid_t) id; 181270631Sjfv 182270631Sjfv if ((grp = GETGRGID(gid)) != NULL && conf.checkduplicate) 183270631Sjfv errx(EX_DATAERR, "gid `%ju' has already been allocated", (uintmax_t)grp->gr_gid); 184270631Sjfv return (gid); 185270631Sjfv } 186270631Sjfv 187270631Sjfv /* 188270631Sjfv * We need to allocate the next available gid under one of 189270631Sjfv * two policies a) Grab the first unused gid b) Grab the 190270631Sjfv * highest possible unused gid 191270631Sjfv */ 192270631Sjfv if (cnf->min_gid >= cnf->max_gid) { /* Sanity claus^H^H^H^Hheck */ 193270631Sjfv cnf->min_gid = 1000; 194270631Sjfv cnf->max_gid = 32000; 195270631Sjfv } 196270631Sjfv bm = bm_alloc(cnf->max_gid - cnf->min_gid + 1); 197270631Sjfv 198270631Sjfv /* 199270631Sjfv * Now, let's fill the bitmap from the password file 200270631Sjfv */ 201270631Sjfv SETGRENT(); 202270631Sjfv while ((grp = GETGRENT()) != NULL) 203270631Sjfv if ((gid_t)grp->gr_gid >= (gid_t)cnf->min_gid && 204270631Sjfv (gid_t)grp->gr_gid <= (gid_t)cnf->max_gid) 205270631Sjfv bm_setbit(&bm, grp->gr_gid - cnf->min_gid); 206270631Sjfv ENDGRENT(); 207270631Sjfv 208270631Sjfv /* 209270631Sjfv * Then apply the policy, with fallback to reuse if necessary 210274360Sjfv */ 211270631Sjfv if (cnf->reuse_gids) 212270631Sjfv gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); 213270631Sjfv else { 214270631Sjfv gid = (gid_t) (bm_lastset(&bm) + 1); 215270631Sjfv if (!bm_isset(&bm, gid)) 216292095Ssmh gid += cnf->min_gid; 217270631Sjfv else 218292095Ssmh gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); 219270631Sjfv } 220270631Sjfv 221270631Sjfv /* 222270631Sjfv * Another sanity check 223270631Sjfv */ 224270631Sjfv if (gid < cnf->min_gid || gid > cnf->max_gid) 225270631Sjfv errx(EX_SOFTWARE, "unable to allocate a new gid - range fully used"); 226274360Sjfv bm_dealloc(&bm); 227270631Sjfv return (gid); 228270631Sjfv} 229270631Sjfv 230292094Ssmhstatic int 231270631Sjfvprint_group(struct group * grp, bool pretty) 232292097Ssmh{ 233292097Ssmh char *buf = NULL; 234292097Ssmh int i; 235292097Ssmh 236270631Sjfv if (pretty) { 237270631Sjfv printf("Group Name: %-15s #%lu\n" 238270631Sjfv " Members: ", 239270631Sjfv grp->gr_name, (long) grp->gr_gid); 240270631Sjfv if (grp->gr_mem != NULL) { 241270631Sjfv for (i = 0; grp->gr_mem[i]; i++) 242270631Sjfv printf("%s%s", i ? "," : "", grp->gr_mem[i]); 243270631Sjfv } 244270631Sjfv fputs("\n\n", stdout); 245270631Sjfv return (EXIT_SUCCESS); 246270631Sjfv } 247270631Sjfv 248270631Sjfv buf = gr_make(grp); 249270631Sjfv printf("%s\n", buf); 250270631Sjfv free(buf); 251270631Sjfv return (EXIT_SUCCESS); 252270631Sjfv} 253270631Sjfv 254270631Sjfvint 255270631Sjfvpw_group_next(int argc, char **argv, char *arg1 __unused) 256270631Sjfv{ 257270631Sjfv struct userconf *cnf; 258270631Sjfv const char *cfg = NULL; 259270631Sjfv int ch; 260270631Sjfv bool quiet; 261270631Sjfv 262270631Sjfv while ((ch = getopt(argc, argv, "Cq")) != -1) { 263270631Sjfv switch (ch) { 264270631Sjfv case 'C': 265270631Sjfv cfg = optarg; 266270631Sjfv break; 267270631Sjfv case 'q': 268270631Sjfv quiet = true; 269270631Sjfv break; 270270631Sjfv } 271270631Sjfv } 272270631Sjfv 273270631Sjfv if (quiet) 274270631Sjfv freopen(_PATH_DEVNULL, "w", stderr); 275270631Sjfv cnf = get_userconfig(cfg); 276270631Sjfv return (pw_groupnext(cnf, quiet)); 277292097Ssmh} 278292097Ssmh 279292097Ssmhint 280292097Ssmhpw_group_show(int argc, char **argv, char *arg1) 281292097Ssmh{ 282292097Ssmh struct group *grp = NULL; 283292097Ssmh char *name; 284292097Ssmh intmax_t id = -1; 285292097Ssmh int ch; 286292097Ssmh bool all, force, quiet, pretty; 287292097Ssmh 288292097Ssmh all = force = quiet = pretty = false; 289292097Ssmh 290292097Ssmh struct group fakegroup = { 291292097Ssmh "nogroup", 292292097Ssmh "*", 293292097Ssmh -1, 294292097Ssmh NULL 295292097Ssmh }; 296292097Ssmh 297292097Ssmh if (arg1 != NULL) { 298292097Ssmh if (strspn(arg1, "0123456789") == strlen(arg1)) 299292097Ssmh id = pw_checkid(arg1, GID_MAX); 300292097Ssmh else 301292097Ssmh name = arg1; 302292097Ssmh } 303292097Ssmh 304292097Ssmh while ((ch = getopt(argc, argv, "C:qn:g:FPa")) != -1) { 305292097Ssmh switch (ch) { 306270631Sjfv case 'C': 307270631Sjfv /* ignore compatibility */ 308270631Sjfv break; 309270631Sjfv case 'q': 310270631Sjfv quiet = true; 311270631Sjfv break; 312270631Sjfv case 'n': 313270631Sjfv name = optarg; 314270631Sjfv break; 315270631Sjfv case 'g': 316292095Ssmh id = pw_checkid(optarg, GID_MAX); 317274360Sjfv break; 318274360Sjfv case 'F': 319274360Sjfv force = true; 320274360Sjfv break; 321274360Sjfv case 'P': 322274360Sjfv pretty = true; 323274360Sjfv break; 324274360Sjfv case 'a': 325274360Sjfv all = true; 326274360Sjfv break; 327274360Sjfv } 328274360Sjfv } 329274360Sjfv 330274360Sjfv if (quiet) 331274360Sjfv freopen(_PATH_DEVNULL, "w", stderr); 332274360Sjfv 333274360Sjfv if (all) { 334274360Sjfv SETGRENT(); 335274360Sjfv while ((grp = GETGRENT()) != NULL) 336274360Sjfv print_group(grp, pretty); 337274360Sjfv ENDGRENT(); 338274360Sjfv return (EXIT_SUCCESS); 339274360Sjfv } 340274360Sjfv 341274360Sjfv grp = getgroup(name, id, !force); 342274360Sjfv if (grp == NULL) 343274360Sjfv grp = &fakegroup; 344270631Sjfv 345270631Sjfv return (print_group(grp, pretty)); 346270631Sjfv} 347270631Sjfv 348270631Sjfvint 349270631Sjfvpw_group_del(int argc, char **argv, char *arg1) 350270631Sjfv{ 351270631Sjfv struct userconf *cnf = NULL; 352270631Sjfv struct group *grp = NULL; 353270631Sjfv char *name; 354270631Sjfv const char *cfg = NULL; 355270631Sjfv intmax_t id = -1; 356270631Sjfv int ch, rc; 357270631Sjfv bool quiet = false; 358270631Sjfv bool nis = false; 359270631Sjfv 360270631Sjfv if (arg1 != NULL) { 361270631Sjfv if (strspn(arg1, "0123456789") == strlen(arg1)) 362270631Sjfv id = pw_checkid(arg1, GID_MAX); 363270631Sjfv else 364270631Sjfv name = arg1; 365270631Sjfv } 366270631Sjfv 367270631Sjfv while ((ch = getopt(argc, argv, "C:qn:g:Y")) != -1) { 368270631Sjfv switch (ch) { 369270631Sjfv case 'C': 370270631Sjfv cfg = optarg; 371270631Sjfv break; 372270631Sjfv case 'q': 373270631Sjfv quiet = true; 374270631Sjfv break; 375270631Sjfv case 'n': 376270631Sjfv name = optarg; 377270631Sjfv break; 378270631Sjfv case 'g': 379270631Sjfv id = pw_checkid(optarg, GID_MAX); 380270631Sjfv break; 381270631Sjfv case 'Y': 382270631Sjfv nis = true; 383270631Sjfv break; 384270631Sjfv } 385270631Sjfv } 386270631Sjfv 387270631Sjfv if (quiet) 388270631Sjfv freopen(_PATH_DEVNULL, "w", stderr); 389270631Sjfv grp = getgroup(name, id, true); 390270631Sjfv cnf = get_userconfig(cfg); 391270631Sjfv rc = delgrent(grp); 392270631Sjfv if (rc == -1) 393270631Sjfv err(EX_IOERR, "group '%s' not available (NIS?)", name); 394270631Sjfv else if (rc != 0) 395270631Sjfv err(EX_IOERR, "group update"); 396270631Sjfv pw_log(cnf, M_DELETE, W_GROUP, "%s(%ju) removed", name, 397270631Sjfv (uintmax_t)id); 398270631Sjfv 399270631Sjfv if (nis && nis_update() == 0) 400270631Sjfv pw_log(cnf, M_DELETE, W_GROUP, "NIS maps updated"); 401270631Sjfv 402270631Sjfv return (EXIT_SUCCESS); 403270631Sjfv} 404270631Sjfv 405270631Sjfvstatic bool 406270631Sjfvgrp_has_member(struct group *grp, const char *name) 407270631Sjfv{ 408270631Sjfv int j; 409270631Sjfv 410270631Sjfv for (j = 0; grp->gr_mem != NULL && grp->gr_mem[j] != NULL; j++) 411270631Sjfv if (strcmp(grp->gr_mem[j], name) == 0) 412270631Sjfv return (true); 413270631Sjfv return (false); 414270631Sjfv} 415270631Sjfv 416270631Sjfvstatic void 417270631Sjfvgrp_add_members(struct group **grp, char *members) 418270631Sjfv{ 419270631Sjfv struct passwd *pwd; 420270631Sjfv char *p; 421270631Sjfv char tok[] = ", \t"; 422270631Sjfv 423270631Sjfv if (members == NULL) 424270631Sjfv return; 425270631Sjfv for (p = strtok(members, tok); p != NULL; p = strtok(NULL, tok)) { 426270631Sjfv pwd = lookup_pwent(p); 427270631Sjfv if (grp_has_member(*grp, pwd->pw_name)) 428270631Sjfv continue; 429270631Sjfv *grp = gr_add(*grp, pwd->pw_name); 430270631Sjfv } 431270631Sjfv} 432270631Sjfv 433270631Sjfvint 434270631Sjfvgroupadd(struct userconf *cnf, char *name, gid_t id, char *members, int fd, 435270631Sjfv bool dryrun, bool pretty, bool precrypted) 436270631Sjfv{ 437270631Sjfv struct group *grp; 438270631Sjfv int rc; 439270631Sjfv 440270631Sjfv struct group fakegroup = { 441270631Sjfv "nogroup", 442270631Sjfv "*", 443270631Sjfv -1, 444270631Sjfv NULL 445270631Sjfv }; 446270631Sjfv 447270631Sjfv grp = &fakegroup; 448270631Sjfv grp->gr_name = pw_checkname(name, 0); 449270631Sjfv grp->gr_passwd = "*"; 450270631Sjfv grp->gr_gid = gr_gidpolicy(cnf, id); 451270631Sjfv grp->gr_mem = NULL; 452270631Sjfv 453270631Sjfv /* 454270631Sjfv * This allows us to set a group password Group passwords is an 455270631Sjfv * antique idea, rarely used and insecure (no secure database) Should 456270631Sjfv * be discouraged, but it is apparently still supported by some 457270631Sjfv * software. 458270631Sjfv */ 459270631Sjfv grp_set_passwd(grp, false, fd, precrypted); 460270631Sjfv grp_add_members(&grp, members); 461270631Sjfv if (dryrun) 462270631Sjfv return (print_group(grp, pretty)); 463270631Sjfv 464270631Sjfv if ((rc = addgrent(grp)) != 0) { 465270631Sjfv if (rc == -1) 466270631Sjfv errx(EX_IOERR, "group '%s' already exists", 467270631Sjfv grp->gr_name); 468270631Sjfv else 469270631Sjfv err(EX_IOERR, "group update"); 470270631Sjfv } 471270631Sjfv 472270631Sjfv pw_log(cnf, M_ADD, W_GROUP, "%s(%ju)", grp->gr_name, 473270631Sjfv (uintmax_t)grp->gr_gid); 474270631Sjfv 475270631Sjfv return (EXIT_SUCCESS); 476270631Sjfv} 477270631Sjfv 478270631Sjfvint 479270631Sjfvpw_group_add(int argc, char **argv, char *arg1) 480270631Sjfv{ 481270631Sjfv struct userconf *cnf = NULL; 482270631Sjfv char *name = NULL; 483270631Sjfv char *members = NULL; 484270631Sjfv const char *cfg = NULL; 485270631Sjfv intmax_t id = -1; 486270631Sjfv int ch, rc, fd = -1; 487270631Sjfv bool quiet, precrypted, dryrun, pretty, nis; 488270631Sjfv 489270631Sjfv quiet = precrypted = dryrun = pretty = nis = false; 490270631Sjfv 491270631Sjfv if (arg1 != NULL) { 492270631Sjfv if (strspn(arg1, "0123456789") == strlen(arg1)) 493270631Sjfv id = pw_checkid(arg1, GID_MAX); 494270631Sjfv else 495270631Sjfv name = arg1; 496270631Sjfv } 497270631Sjfv 498270631Sjfv while ((ch = getopt(argc, argv, "C:qn:g:h:H:M:oNPY")) != -1) { 499270631Sjfv switch (ch) { 500270631Sjfv case 'C': 501270631Sjfv cfg = optarg; 502292097Ssmh break; 503270631Sjfv case 'q': 504292097Ssmh quiet = true; 505270631Sjfv break; 506270631Sjfv case 'n': 507270631Sjfv name = optarg; 508270631Sjfv break; 509270631Sjfv case 'g': 510270631Sjfv id = pw_checkid(optarg, GID_MAX); 511292097Ssmh break; 512292097Ssmh case 'H': 513270631Sjfv if (fd != -1) 514270631Sjfv errx(EX_USAGE, "'-h' and '-H' are mutually " 515270631Sjfv "exclusive options"); 516270631Sjfv fd = pw_checkfd(optarg); 517292097Ssmh precrypted = true; 518270631Sjfv if (fd == '-') 519270631Sjfv errx(EX_USAGE, "-H expects a file descriptor"); 520270631Sjfv break; 521270631Sjfv case 'h': 522270631Sjfv if (fd != -1) 523270631Sjfv errx(EX_USAGE, "'-h' and '-H' are mutually " 524270631Sjfv "exclusive options"); 525270631Sjfv fd = pw_checkfd(optarg); 526270631Sjfv break; 527270631Sjfv case 'M': 528270631Sjfv members = optarg; 529274360Sjfv break; 530274360Sjfv case 'o': 531274360Sjfv conf.checkduplicate = false; 532274360Sjfv break; 533274360Sjfv case 'N': 534274360Sjfv dryrun = true; 535274360Sjfv break; 536274360Sjfv case 'P': 537274360Sjfv pretty = true; 538274360Sjfv break; 539274360Sjfv case 'Y': 540274360Sjfv nis = true; 541270631Sjfv break; 542270631Sjfv } 543270631Sjfv } 544270631Sjfv 545270631Sjfv if (quiet) 546270631Sjfv freopen(_PATH_DEVNULL, "w", stderr); 547270631Sjfv if (name == NULL) 548270631Sjfv errx(EX_DATAERR, "group name required"); 549292097Ssmh cnf = get_userconfig(cfg); 550270631Sjfv rc = groupadd(cnf, name, gr_gidpolicy(cnf, id), members, fd, dryrun, 551270631Sjfv pretty, precrypted); 552270631Sjfv if (nis && rc == EXIT_SUCCESS && nis_update() == 0) 553270631Sjfv pw_log(cnf, M_ADD, W_GROUP, "NIS maps updated"); 554270631Sjfv 555270631Sjfv return (rc); 556270631Sjfv} 557270631Sjfv 558270631Sjfvint 559270631Sjfvpw_group_mod(int argc, char **argv, char *arg1) 560270631Sjfv{ 561270631Sjfv struct userconf *cnf; 562270631Sjfv struct group *grp = NULL; 563270631Sjfv const char *cfg = NULL; 564270631Sjfv char *oldmembers = NULL; 565270631Sjfv char *members = NULL; 566270631Sjfv char *newmembers = NULL; 567270631Sjfv char *newname = NULL; 568270631Sjfv char *name = NULL; 569270631Sjfv intmax_t id = -1; 570270631Sjfv int ch, rc, fd = -1; 571270631Sjfv bool quiet, pretty, dryrun, nis, precrypted; 572270631Sjfv 573270631Sjfv quiet = pretty = dryrun = nis = precrypted = false; 574270631Sjfv 575270631Sjfv if (arg1 != NULL) { 576270631Sjfv if (strspn(arg1, "0123456789") == strlen(arg1)) 577270631Sjfv id = pw_checkid(arg1, GID_MAX); 578274360Sjfv else 579274360Sjfv name = arg1; 580270631Sjfv } 581270631Sjfv 582270631Sjfv while ((ch = getopt(argc, argv, "C:qn:d:g:l:h:H:M:m:NPY")) != -1) { 583270631Sjfv switch (ch) { 584270631Sjfv case 'C': 585270631Sjfv cfg = optarg; 586270631Sjfv break; 587270631Sjfv case 'q': 588292097Ssmh quiet = true; 589270631Sjfv break; 590270631Sjfv case 'n': 591270631Sjfv name = optarg; 592270631Sjfv break; 593270631Sjfv case 'g': 594270631Sjfv id = pw_checkid(optarg, GID_MAX); 595270631Sjfv break; 596270631Sjfv case 'd': 597270631Sjfv oldmembers = optarg; 598270631Sjfv break; 599270631Sjfv case 'l': 600270631Sjfv newname = optarg; 601270631Sjfv break; 602270631Sjfv case 'H': 603270631Sjfv if (fd != -1) 604270631Sjfv errx(EX_USAGE, "'-h' and '-H' are mutually " 605270631Sjfv "exclusive options"); 606270631Sjfv fd = pw_checkfd(optarg); 607270631Sjfv precrypted = true; 608270631Sjfv if (fd == '-') 609270631Sjfv errx(EX_USAGE, "-H expects a file descriptor"); 610270631Sjfv break; 611270631Sjfv case 'h': 612270631Sjfv if (fd != -1) 613270631Sjfv errx(EX_USAGE, "'-h' and '-H' are mutually " 614270631Sjfv "exclusive options"); 615270631Sjfv fd = pw_checkfd(optarg); 616270631Sjfv break; 617270631Sjfv case 'M': 618270631Sjfv members = optarg; 619270631Sjfv break; 620270631Sjfv case 'm': 621270631Sjfv newmembers = optarg; 622270631Sjfv break; 623270631Sjfv case 'N': 624270631Sjfv dryrun = true; 625270631Sjfv break; 626270631Sjfv case 'P': 627270631Sjfv pretty = true; 628270631Sjfv break; 629270631Sjfv case 'Y': 630270631Sjfv nis = true; 631270631Sjfv break; 632270631Sjfv } 633270631Sjfv } 634270631Sjfv if (quiet) 635270631Sjfv freopen(_PATH_DEVNULL, "w", stderr); 636270631Sjfv cnf = get_userconfig(cfg); 637270631Sjfv grp = getgroup(name, id, true); 638270631Sjfv if (name == NULL) 639270631Sjfv name = grp->gr_name; 640270631Sjfv if (id > 0) 641270631Sjfv grp->gr_gid = id; 642270631Sjfv 643270631Sjfv if (newname != NULL) 644270631Sjfv grp->gr_name = pw_checkname(newname, 0); 645270631Sjfv 646270631Sjfv grp_set_passwd(grp, true, fd, precrypted); 647270631Sjfv /* 648270631Sjfv * Keep the same logic as old code for now: 649270631Sjfv * if -M is passed, -d and -m are ignored 650274360Sjfv * then id -d, -m is ignored 651274360Sjfv * last is -m 652274360Sjfv */ 653270631Sjfv 654270631Sjfv 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} 686