pw.c (7493058fb6d966132992e03c64a5b5f6fcbb38eb) | pw.c (d2d022b9fdebd6bfe2983bb688818ed8bfc422a6) |
---|---|
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 --- 23 unchanged lines hidden (view full) --- 32#include <err.h> 33#include <fcntl.h> 34#include <locale.h> 35#include <paths.h> 36#include <stdbool.h> 37#include <sys/wait.h> 38#include "pw.h" 39 | 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 --- 23 unchanged lines hidden (view full) --- 32#include <err.h> 33#include <fcntl.h> 34#include <locale.h> 35#include <paths.h> 36#include <stdbool.h> 37#include <sys/wait.h> 38#include "pw.h" 39 |
40#if !defined(_PATH_YP) 41#define _PATH_YP "/var/yp/" 42#endif | |
43const char *Modes[] = { 44 "add", "del", "mod", "show", "next", 45 NULL}; 46const char *Which[] = {"user", "group", NULL}; 47static const char *Combo1[] = { 48 "useradd", "userdel", "usermod", "usershow", "usernext", 49 "lock", "unlock", 50 "groupadd", "groupdel", "groupmod", "groupshow", "groupnext", --- 29 unchanged lines hidden (view full) --- 80 vgetpwnam, 81 vsetgrent, 82 vendgrent, 83 vgetgrent, 84 vgetgrgid, 85 vgetgrnam, 86}; 87 | 40const char *Modes[] = { 41 "add", "del", "mod", "show", "next", 42 NULL}; 43const char *Which[] = {"user", "group", NULL}; 44static const char *Combo1[] = { 45 "useradd", "userdel", "usermod", "usershow", "usernext", 46 "lock", "unlock", 47 "groupadd", "groupdel", "groupmod", "groupshow", "groupnext", --- 29 unchanged lines hidden (view full) --- 77 vgetpwnam, 78 vsetgrent, 79 vendgrent, 80 vgetgrent, 81 vgetgrgid, 82 vgetgrnam, 83}; 84 |
85static int (*cmdfunc[W_NUM][M_NUM])(int argc, char **argv, char *_name) = { 86 { /* user */ 87 pw_user_add, 88 pw_user_del, 89 pw_user_mod, 90 pw_user_show, 91 pw_user_next, 92 pw_user_lock, 93 pw_user_unlock, 94 }, 95 { /* group */ 96 pw_group_add, 97 pw_group_del, 98 pw_group_mod, 99 pw_group_show, 100 pw_group_next, 101 } 102}; 103 |
|
88struct pwconf conf; 89 | 104struct pwconf conf; 105 |
90static struct cargs arglist; | 106static int getindex(const char *words[], const char *word); 107static void cmdhelp(int mode, int which); |
91 | 108 |
92static int getindex(const char *words[], const char *word); 93static void cmdhelp(int mode, int which); 94 95 | |
96int 97main(int argc, char *argv[]) 98{ | 109int 110main(int argc, char *argv[]) 111{ |
99 int ch; 100 int mode = -1; 101 int which = -1; 102 long id = -1; 103 char *config = NULL; | 112 int mode = -1, which = -1, tmp; |
104 struct stat st; | 113 struct stat st; |
105 const char *errstr; 106 char arg, *name; | 114 char arg, *arg1; |
107 bool relocated, nis; 108 | 115 bool relocated, nis; 116 |
109 static const char *opts[W_NUM][M_NUM] = 110 { 111 { /* user */ 112 "R:V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y", 113 "R:V:C:qn:u:rY", 114 "R:V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY", 115 "R:V:C:qn:u:FPa7", 116 "R:V:C:q", 117 "R:V:C:q", 118 "R:V:C:q" 119 }, 120 { /* grp */ 121 "R:V:C:qn:g:h:H:M:opNPY", 122 "R:V:C:qn:g:Y", 123 "R:V:C:qn:d:g:l:h:H:FM:m:NPY", 124 "R:V:C:qn:g:FPa", 125 "R:V:C:q" 126 } 127 }; 128 129 static int (*funcs[W_NUM]) (int _mode, char *_name, long _id, 130 struct cargs * _args) = 131 { /* Request handlers */ 132 pw_user, 133 pw_group 134 }; 135 136 name = NULL; | 117 arg1 = NULL; |
137 relocated = nis = false; 138 memset(&conf, 0, sizeof(conf)); 139 strlcpy(conf.rootdir, "/", sizeof(conf.rootdir)); 140 strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath)); 141 conf.fd = -1; 142 conf.checkduplicate = true; 143 | 118 relocated = nis = false; 119 memset(&conf, 0, sizeof(conf)); 120 strlcpy(conf.rootdir, "/", sizeof(conf.rootdir)); 121 strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath)); 122 conf.fd = -1; 123 conf.checkduplicate = true; 124 |
144 LIST_INIT(&arglist); | 125 setlocale(LC_ALL, ""); |
145 | 126 |
146 (void)setlocale(LC_ALL, ""); 147 | |
148 /* 149 * Break off the first couple of words to determine what exactly 150 * we're being asked to do 151 */ 152 while (argc > 1) { | 127 /* 128 * Break off the first couple of words to determine what exactly 129 * we're being asked to do 130 */ 131 while (argc > 1) { |
153 int tmp; 154 | |
155 if (*argv[1] == '-') { 156 /* 157 * Special case, allow pw -V<dir> <operation> [args] for scripts etc. 158 */ 159 arg = argv[1][1]; 160 if (arg == 'V' || arg == 'R') { 161 if (relocated) 162 errx(EXIT_FAILURE, "Both '-R' and '-V' " --- 29 unchanged lines hidden (view full) --- 192 which = tmp; 193 else if ((mode == -1 && which == -1) && 194 ((tmp = getindex(Combo1, argv[1])) != -1 || 195 (tmp = getindex(Combo2, argv[1])) != -1)) { 196 which = tmp / M_NUM; 197 mode = tmp % M_NUM; 198 } else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL) 199 cmdhelp(mode, which); | 132 if (*argv[1] == '-') { 133 /* 134 * Special case, allow pw -V<dir> <operation> [args] for scripts etc. 135 */ 136 arg = argv[1][1]; 137 if (arg == 'V' || arg == 'R') { 138 if (relocated) 139 errx(EXIT_FAILURE, "Both '-R' and '-V' " --- 29 unchanged lines hidden (view full) --- 169 which = tmp; 170 else if ((mode == -1 && which == -1) && 171 ((tmp = getindex(Combo1, argv[1])) != -1 || 172 (tmp = getindex(Combo2, argv[1])) != -1)) { 173 which = tmp / M_NUM; 174 mode = tmp % M_NUM; 175 } else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL) 176 cmdhelp(mode, which); |
200 else if (which != -1 && mode != -1) { 201 if (strspn(argv[1], "0123456789") == strlen(argv[1])) { 202 id = strtounum(argv[1], 0, UID_MAX, &errstr); 203 if (errstr != NULL) 204 errx(EX_USAGE, "Bad id '%s': %s", 205 argv[1], errstr); 206 } else 207 name = argv[1]; 208 } else | 177 else if (which != -1 && mode != -1) 178 arg1 = argv[1]; 179 else |
209 errx(EX_USAGE, "unknown keyword `%s'", argv[1]); 210 ++argv; 211 --argc; 212 } 213 214 /* 215 * Bail out unless the user is specific! 216 */ 217 if (mode == -1 || which == -1) 218 cmdhelp(mode, which); 219 220 conf.rootfd = open(conf.rootdir, O_DIRECTORY|O_CLOEXEC); 221 if (conf.rootfd == -1) 222 errx(EXIT_FAILURE, "Unable to open '%s'", conf.rootdir); | 180 errx(EX_USAGE, "unknown keyword `%s'", argv[1]); 181 ++argv; 182 --argc; 183 } 184 185 /* 186 * Bail out unless the user is specific! 187 */ 188 if (mode == -1 || which == -1) 189 cmdhelp(mode, which); 190 191 conf.rootfd = open(conf.rootdir, O_DIRECTORY|O_CLOEXEC); 192 if (conf.rootfd == -1) 193 errx(EXIT_FAILURE, "Unable to open '%s'", conf.rootdir); |
223 conf.which = which; 224 /* 225 * We know which mode we're in and what we're about to do, so now 226 * let's dispatch the remaining command line args in a genric way. 227 */ 228 optarg = NULL; | |
229 | 194 |
230 while ((ch = getopt(argc, argv, opts[which][mode])) != -1) { 231 switch (ch) { 232 case '?': 233 errx(EX_USAGE, "unknown switch"); 234 break; 235 case '7': 236 conf.v7 = true; 237 break; 238 case 'C': 239 conf.config = optarg; 240 config = conf.config; 241 break; 242 case 'F': 243 conf.force = true; 244 break; 245 case 'N': 246 conf.dryrun = true; 247 break; 248 case 'l': 249 if (strlen(optarg) >= MAXLOGNAME) 250 errx(EX_USAGE, "new name too long: %s", optarg); 251 conf.newname = optarg; 252 break; 253 case 'P': 254 conf.pretty = true; 255 break; 256 case 'Y': 257 nis = true; 258 break; 259 case 'a': 260 conf.all = true; 261 break; 262 case 'c': 263 conf.gecos = pw_checkname(optarg, 1); 264 break; 265 case 'g': 266 if (which == 0) { /* for user* */ 267 addarg(&arglist, 'g', optarg); 268 break; 269 } 270 if (strspn(optarg, "0123456789") != strlen(optarg)) 271 errx(EX_USAGE, "-g expects a number"); 272 id = strtounum(optarg, 0, GID_MAX, &errstr); 273 if (errstr != NULL) 274 errx(EX_USAGE, "Bad id '%s': %s", optarg, 275 errstr); 276 break; 277 case 'u': 278 if (strspn(optarg, "0123456789,") != strlen(optarg)) 279 errx(EX_USAGE, "-u expects a number"); 280 if (strchr(optarg, ',') != NULL) { 281 addarg(&arglist, 'u', optarg); 282 break; 283 } 284 id = strtounum(optarg, 0, UID_MAX, &errstr); 285 if (errstr != NULL) 286 errx(EX_USAGE, "Bad id '%s': %s", optarg, 287 errstr); 288 break; 289 case 'n': 290 name = optarg; 291 break; 292 case 'H': 293 if (conf.fd != -1) 294 errx(EX_USAGE, "'-h' and '-H' are mutually " 295 "exclusive options"); 296 conf.precrypted = true; 297 if (strspn(optarg, "0123456789") != strlen(optarg)) 298 errx(EX_USAGE, "'-H' expects a file descriptor"); 299 300 conf.fd = strtonum(optarg, 0, INT_MAX, &errstr); 301 if (errstr != NULL) 302 errx(EX_USAGE, "Bad file descriptor '%s': %s", 303 optarg, errstr); 304 break; 305 case 'h': 306 if (conf.fd != -1) 307 errx(EX_USAGE, "'-h' and '-H' are mutually " 308 "exclusive options"); 309 310 if (strcmp(optarg, "-") == 0) 311 conf.fd = '-'; 312 else if (strspn(optarg, "0123456789") == strlen(optarg)) { 313 conf.fd = strtonum(optarg, 0, INT_MAX, &errstr); 314 if (errstr != NULL) 315 errx(EX_USAGE, "'-h' expects a " 316 "file descriptor or '-'"); 317 } else 318 errx(EX_USAGE, "'-h' expects a file " 319 "descriptor or '-'"); 320 break; 321 case 'o': 322 conf.checkduplicate = false; 323 break; 324 case 'q': 325 conf.quiet = true; 326 break; 327 case 'r': 328 conf.deletehome = true; 329 break; 330 default: 331 addarg(&arglist, ch, optarg); 332 break; 333 } 334 optarg = NULL; 335 } 336 337 if (name != NULL && strlen(name) >= MAXLOGNAME) 338 errx(EX_USAGE, "name too long: %s", name); 339 340 /* 341 * Must be root to attempt an update 342 */ 343 if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && !conf.dryrun) 344 errx(EX_NOPERM, "you must be root to run this program"); 345 346 /* 347 * We should immediately look for the -q 'quiet' switch so that we 348 * don't bother with extraneous errors 349 */ 350 if (conf.quiet) 351 freopen(_PATH_DEVNULL, "w", stderr); 352 353 /* 354 * Set our base working path if not overridden 355 */ 356 357 if (config == NULL) { /* Only override config location if -C not specified */ 358 asprintf(&config, "%s/pw.conf", conf.etcpath); 359 if (config == NULL) 360 errx(EX_OSERR, "out of memory"); 361 } 362 363 /* 364 * Now, let's do the common initialisation 365 */ 366 conf.userconf = read_userconfig(config); 367 368 ch = funcs[which] (mode, name, id, &arglist); 369 370 /* 371 * If everything went ok, and we've been asked to update 372 * the NIS maps, then do it now 373 */ 374 if (ch == EXIT_SUCCESS && nis) { 375 pid_t pid; 376 377 fflush(NULL); 378 if (chdir(_PATH_YP) == -1) 379 warn("chdir(" _PATH_YP ")"); 380 else if ((pid = fork()) == -1) 381 warn("fork()"); 382 else if (pid == 0) { 383 /* Is make anywhere else? */ 384 execlp("/usr/bin/make", "make", (char *)NULL); 385 _exit(1); 386 } else { 387 int i; 388 waitpid(pid, &i, 0); 389 if ((i = WEXITSTATUS(i)) != 0) 390 errx(ch, "make exited with status %d", i); 391 else 392 pw_log(conf.userconf, mode, which, "NIS maps updated"); 393 } 394 } 395 return ch; | 195 return (cmdfunc[which][mode](argc, argv, arg1)); |
396} 397 398 399static int 400getindex(const char *words[], const char *word) 401{ | 196} 197 198 199static int 200getindex(const char *words[], const char *word) 201{ |
402 int i = 0; | 202 int i = 0; |
403 404 while (words[i]) { 405 if (strcmp(words[i], word) == 0) | 203 204 while (words[i]) { 205 if (strcmp(words[i], word) == 0) |
406 return i; | 206 return (i); |
407 i++; 408 } | 207 i++; 208 } |
409 return -1; | 209 return (-1); |
410} 411 412 413/* 414 * This is probably an overkill for a cmdline help system, but it reflects 415 * the complexity of the command line. 416 */ 417 --- 33 unchanged lines hidden (view full) --- 451 "\t-L class user class\n" 452 "\t-h fd read password on fd\n" 453 "\t-H fd read encrypted password on fd\n" 454 "\t-Y update NIS maps\n" 455 "\t-N no update\n" 456 " Setting defaults:\n" 457 "\t-V etcdir alternate /etc location\n" 458 "\t-R rootir alternate root directory\n" | 210} 211 212 213/* 214 * This is probably an overkill for a cmdline help system, but it reflects 215 * the complexity of the command line. 216 */ 217 --- 33 unchanged lines hidden (view full) --- 251 "\t-L class user class\n" 252 "\t-h fd read password on fd\n" 253 "\t-H fd read encrypted password on fd\n" 254 "\t-Y update NIS maps\n" 255 "\t-N no update\n" 256 " Setting defaults:\n" 257 "\t-V etcdir alternate /etc location\n" 258 "\t-R rootir alternate root directory\n" |
459 "\t-D set user defaults\n" | 259 "\t-D set user defaults\n" |
460 "\t-b dir default home root dir\n" 461 "\t-e period default expiry period\n" 462 "\t-p period default password change period\n" 463 "\t-g group default group\n" 464 "\t-G grp1,grp2 additional groups\n" 465 "\t-L class default user class\n" 466 "\t-k dir default home skeleton\n" 467 "\t-M mode home directory permissions\n" 468 "\t-u min,max set min,max uids\n" 469 "\t-i min,max set min,max gids\n" 470 "\t-w method set default password method\n" 471 "\t-s shell default shell\n" 472 "\t-y path set NIS passwd file path\n", 473 "usage: pw userdel [uid|name] [switches]\n" 474 "\t-V etcdir alternate /etc location\n" 475 "\t-R rootir alternate root directory\n" 476 "\t-n name login name\n" 477 "\t-u uid user id\n" 478 "\t-Y update NIS maps\n" | 260 "\t-b dir default home root dir\n" 261 "\t-e period default expiry period\n" 262 "\t-p period default password change period\n" 263 "\t-g group default group\n" 264 "\t-G grp1,grp2 additional groups\n" 265 "\t-L class default user class\n" 266 "\t-k dir default home skeleton\n" 267 "\t-M mode home directory permissions\n" 268 "\t-u min,max set min,max uids\n" 269 "\t-i min,max set min,max gids\n" 270 "\t-w method set default password method\n" 271 "\t-s shell default shell\n" 272 "\t-y path set NIS passwd file path\n", 273 "usage: pw userdel [uid|name] [switches]\n" 274 "\t-V etcdir alternate /etc location\n" 275 "\t-R rootir alternate root directory\n" 276 "\t-n name login name\n" 277 "\t-u uid user id\n" 278 "\t-Y update NIS maps\n" |
279 "\t-y path set NIS passwd file path\n" |
|
479 "\t-r remove home & contents\n", 480 "usage: pw usermod [uid|name] [switches]\n" 481 "\t-V etcdir alternate /etc location\n" 482 "\t-R rootir alternate root directory\n" 483 "\t-C config configuration file\n" 484 "\t-q quiet operation\n" 485 "\t-F force add if no user\n" 486 "\t-n name login name\n" --- 8 unchanged lines hidden (view full) --- 495 "\t-L class user class\n" 496 "\t-m [ -k dir ] create and set up home\n" 497 "\t-M mode home directory permissions\n" 498 "\t-s shell name of login shell\n" 499 "\t-w method set new password using method\n" 500 "\t-h fd read password on fd\n" 501 "\t-H fd read encrypted password on fd\n" 502 "\t-Y update NIS maps\n" | 280 "\t-r remove home & contents\n", 281 "usage: pw usermod [uid|name] [switches]\n" 282 "\t-V etcdir alternate /etc location\n" 283 "\t-R rootir alternate root directory\n" 284 "\t-C config configuration file\n" 285 "\t-q quiet operation\n" 286 "\t-F force add if no user\n" 287 "\t-n name login name\n" --- 8 unchanged lines hidden (view full) --- 296 "\t-L class user class\n" 297 "\t-m [ -k dir ] create and set up home\n" 298 "\t-M mode home directory permissions\n" 299 "\t-s shell name of login shell\n" 300 "\t-w method set new password using method\n" 301 "\t-h fd read password on fd\n" 302 "\t-H fd read encrypted password on fd\n" 303 "\t-Y update NIS maps\n" |
304 "\t-y path set NIS passwd file path\n" |
|
503 "\t-N no update\n", 504 "usage: pw usershow [uid|name] [switches]\n" 505 "\t-V etcdir alternate /etc location\n" 506 "\t-R rootir alternate root directory\n" 507 "\t-n name login name\n" 508 "\t-u uid user id\n" 509 "\t-F force print\n" 510 "\t-P prettier format\n" --- 60 unchanged lines hidden (view full) --- 571 "\t-q quiet operation\n" 572 } 573 }; 574 575 fprintf(stderr, "%s", help[which][mode]); 576 } 577 exit(EXIT_FAILURE); 578} | 305 "\t-N no update\n", 306 "usage: pw usershow [uid|name] [switches]\n" 307 "\t-V etcdir alternate /etc location\n" 308 "\t-R rootir alternate root directory\n" 309 "\t-n name login name\n" 310 "\t-u uid user id\n" 311 "\t-F force print\n" 312 "\t-P prettier format\n" --- 60 unchanged lines hidden (view full) --- 373 "\t-q quiet operation\n" 374 } 375 }; 376 377 fprintf(stderr, "%s", help[which][mode]); 378 } 379 exit(EXIT_FAILURE); 380} |
579 580struct carg * 581getarg(struct cargs * _args, int ch) 582{ 583 struct carg *c; 584 585 if (_args == NULL) 586 return (NULL); 587 588 c = LIST_FIRST(_args); 589 590 while (c != NULL && c->ch != ch) 591 c = LIST_NEXT(c, list); 592 return c; 593} 594 595struct carg * 596addarg(struct cargs * _args, int ch, char *argstr) 597{ 598 struct carg *ca = malloc(sizeof(struct carg)); 599 600 if (ca == NULL) 601 errx(EX_OSERR, "out of memory"); 602 ca->ch = ch; 603 ca->val = argstr; 604 LIST_INSERT_HEAD(_args, ca, list); 605 return ca; 606} | |