1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 #include <stdio.h> 29 #include <sys/types.h> 30 #include <shadow.h> 31 #include <pwd.h> 32 #include <string.h> 33 #include <signal.h> 34 #include <sys/stat.h> 35 #include <errno.h> 36 #include <time.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 #include <locale.h> 40 #include <fcntl.h> 41 #include <secdb.h> 42 #include <user_attr.h> 43 #include <nss.h> 44 45 #define CMT_SIZE (128+1) /* Argument sizes + 1 (for '\0') */ 46 #define DIR_SIZE (256+1) 47 #define SHL_SIZE (256+1) 48 #define ENTRY_LENGTH 512 /* Max length of an /etc/passwd entry */ 49 #define UID_MIN 100 /* Lower bound of default UID */ 50 51 #define M_MASK 01 /* Masks for the optn_mask variable */ 52 #define L_MASK 02 /* It keeps track of which options */ 53 #define C_MASK 04 /* have been entered */ 54 #define H_MASK 010 55 #define U_MASK 020 56 #define G_MASK 040 57 #define S_MASK 0100 58 #define O_MASK 0200 59 #define A_MASK 0400 60 #define D_MASK 01000 61 #define F_MASK 02000 62 #define E_MASK 04000 63 64 #define UATTR_MASK 010000 65 66 /* flags for info_mask */ 67 #define LOGNAME_EXIST 01 /* logname exists */ 68 #define BOTH_FILES 02 /* touch both password files */ 69 #define WRITE_P_ENTRY 04 /* write out password entry */ 70 #define WRITE_S_ENTRY 010 /* write out shadow entry */ 71 #define NEED_DEF_UID 020 /* need default uid */ 72 #define FOUND 040 /* found the entry in password file */ 73 #define LOCKED 0100 /* did we lock the password file */ 74 #define UATTR_FILE 0200 /* touch user_attr file */ 75 #define BAD_ENT_MESSAGE "%s: Bad entry found in /etc/passwd. Run pwconv.\n" 76 77 typedef struct kvopts { 78 const char option; 79 const char *key; 80 char *newvalue; 81 } kvopts_t; 82 83 /* mapping of extensible keywords and options */ 84 kvopts_t ua_opts[] = { 85 { 'A', USERATTR_AUTHS_KW }, 86 { 'P', USERATTR_PROFILES_KW }, 87 { 'R', USERATTR_ROLES_KW }, 88 { 'T', USERATTR_TYPE_KW }, 89 { '\0', USERATTR_DEFAULTPROJ_KW }, 90 { '\0', USERATTR_LIMPRIV_KW }, 91 { '\0', USERATTR_DFLTPRIV_KW }, 92 { '\0', USERATTR_LOCK_AFTER_RETRIES_KW }, 93 { '\0', USERATTR_LABELVIEW }, 94 { '\0', USERATTR_CLEARANCE }, 95 { '\0', USERATTR_MINLABEL }, 96 { '\0', USERATTR_AUDIT_FLAGS_KW }, 97 }; 98 99 #define UA_KEYS (sizeof (ua_opts)/sizeof (kvopts_t)) 100 101 102 char defdir[] = "/home/"; /* default home directory for new user */ 103 char pwdflr[] = "x"; /* password string for /etc/passwd */ 104 char lkstring[] = "*LK*"; /* lock string for shadow password */ 105 char nullstr[] = ""; /* null string */ 106 char *msg; /* pointer to error message */ 107 108 #define DATMSK "DATEMSK=/etc/datemsk" 109 110 #define OUSERATTR_FILENAME "/etc/ouser_attr" 111 #define USERATTR_TEMP "/etc/uatmp" 112 113 struct uid_blk { 114 struct uid_blk *link; 115 uid_t low; /* low bound for this uid block */ 116 uid_t high; /* high bound for this uid block */ 117 }; 118 119 extern userattr_t *fgetuserattr(FILE *); 120 121 122 /* 123 * Declare all functions that do not return integers. This is here 124 * to get rid of some lint messages 125 */ 126 127 void uid_bcom(struct uid_blk *), add_ublk(uid_t, struct uid_blk *), 128 bad_perm(void), 129 bad_usage(char *), bad_arg(char *), bad_uid(void), bad_pasf(void), 130 file_error(void), bad_news(void), no_lock(void), add_uid(uid_t), 131 rid_tmpf(void), ck_p_sz(struct passwd *), ck_s_sz(struct spwd *), 132 bad_name(char *), bad_uattr(void); 133 134 void file_copy(FILE *spf, long NIS_pos); 135 136 static FILE *fp_ptemp, *fp_stemp, *fp_uatemp; 137 static int fd_ptemp, fd_stemp, fd_uatemp; 138 139 /* 140 * The uid_blk structure is used in the search for the default 141 * uid. Each uid_blk represent a range of uid(s) that are currently 142 * used on the system. 143 */ 144 145 146 #ifndef att 147 /* 148 * getspnan routine that ONLY looks at the local shadow file 149 */ 150 struct spwd * 151 local_getspnam(char *name) 152 { 153 FILE *shadf; 154 struct spwd *sp; 155 156 if ((shadf = fopen("/etc/shadow", "r")) == NULL) 157 return (NULL); 158 159 while ((sp = fgetspent(shadf)) != NULL) { 160 if (strcmp(sp->sp_namp, name) == 0) 161 break; 162 } 163 164 fclose(shadf); 165 166 return (sp); 167 } 168 #endif 169 170 static void 171 putuserattrent(userattr_t *user, FILE *f) 172 { 173 int i, j; 174 char *key; 175 char *val; 176 kv_t *kv_pair; 177 178 /* 179 * Avoid trivial entries. Those with no attributes or with 180 * only "type=normal". This retains backward compatibility. 181 */ 182 if (user->attr == NULL) 183 return; 184 185 kv_pair = user->attr->data; 186 187 for (i = j = 0; i < user->attr->length; i++) { 188 key = kv_pair[i].key; 189 val = kv_pair[i].value; 190 if ((key == NULL) || (val == NULL)) 191 break; 192 if (strlen(val) == 0 || 193 (strcmp(key, USERATTR_TYPE_KW) == 0 && 194 strcmp(val, USERATTR_TYPE_NORMAL_KW) == 0)) 195 continue; 196 j++; 197 } 198 if (j == 0) 199 return; 200 201 (void) fprintf(f, "%s:%s:%s:%s:", user->name, user->qualifier, 202 user->res1, user->res2); 203 204 for (i = j = 0; i < user->attr->length; i++) { 205 key = kv_pair[i].key; 206 val = _escape(kv_pair[i].value, KV_SPECIAL); 207 if ((key == NULL) || (val == NULL)) 208 break; 209 if (strlen(val) == 0) 210 continue; 211 if (j > 0) 212 (void) fprintf(f, KV_DELIMITER); 213 (void) fprintf(f, "%s=%s", key, val); 214 j++; 215 } 216 (void) fprintf(f, "\n"); 217 } 218 219 static void 220 assign_attr(userattr_t *user, const char *newkey, char *val) 221 { 222 223 int i; 224 char *key; 225 kv_t *kv_pair; 226 int avail = -1; 227 228 if (user->attr != NULL) { 229 kv_pair = user->attr->data; 230 for (i = 0; i < user->attr->length; i++) { 231 key = kv_pair[i].key; 232 if (key == NULL) { 233 avail = i; 234 continue; 235 } else if (strcmp(key, newkey) == 0) { 236 kv_pair[i].value = strdup(val); 237 return; 238 } 239 } 240 241 if (avail == -1) 242 avail = user->attr->length++; 243 kv_pair[avail].key = strdup(newkey); 244 kv_pair[avail].value = strdup(val); 245 } 246 } 247 248 static void 249 unassign_role(userattr_t *user, char *rolelist, char *role) 250 { 251 252 char *roleptr; 253 char *templist; 254 char *temprole; 255 int length; 256 257 roleptr = rolelist; 258 templist = strdup(roleptr); 259 temprole = strtok(templist, ","); 260 while (temprole) { 261 if (strcmp(temprole, role) == 0) { 262 263 length = strlen(role); 264 roleptr += temprole - templist; 265 266 if (*(roleptr + length) == ',') 267 length++; 268 strcpy(roleptr, roleptr + length); 269 length = strlen(roleptr) - 1; 270 if (*(roleptr + length) == ',') 271 *(roleptr + length) = '\0'; 272 assign_attr(user, USERATTR_ROLES_KW, rolelist); 273 break; 274 } else { 275 temprole = strtok(NULL, ","); 276 } 277 } 278 } 279 280 struct uid_blk *uid_sp; 281 char *prognamp; /* program name */ 282 extern int errno; 283 int optn_mask = 0, info_mask = 0; 284 extern int getdate_err; 285 286 int 287 main(int argc, char **argv) 288 { 289 int c, i; 290 char *lognamp, *char_p; 291 int end_of_file = 0; 292 int error; 293 long date = 0; 294 FILE *pwf, *spf, *uaf; 295 296 struct passwd *pw_ptr1p, passwd_st; 297 struct spwd *sp_ptr1p, shadow_st; 298 userattr_t *ua_ptr1p, userattr_st; 299 static kv_t ua_kv[KV_ADD_KEYS]; 300 kva_t ua_kva; 301 struct stat statbuf; 302 struct tm *tm_ptr; 303 int NIS_entry_seen; /* NIS scanning flag */ 304 /* 305 * NIS start pos, really pointer to first entry AFTER first 306 * NIS-referant entry 307 */ 308 long NIS_pos; 309 long cur_pos; /* Current pos, used with nis-pos above */ 310 311 (void) setlocale(LC_ALL, ""); 312 313 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 314 #define TEXT_DOMAIN "SYS_TEST" 315 #endif 316 (void) textdomain(TEXT_DOMAIN); 317 318 tzset(); 319 /* Get program name */ 320 prognamp = argv[0]; 321 322 /* Check identity */ 323 if (geteuid() != 0) 324 bad_perm(); 325 326 /* Lock the password file(s) */ 327 328 if (lckpwdf() != 0) 329 no_lock(); 330 info_mask |= LOCKED; /* remember we locked */ 331 332 /* initialize the two structures */ 333 334 passwd_st.pw_passwd = pwdflr; /* bogus password */ 335 passwd_st.pw_name = nullstr; /* login name */ 336 passwd_st.pw_uid = -1; /* no uid */ 337 passwd_st.pw_gid = 1; /* default gid */ 338 passwd_st.pw_age = nullstr; /* no aging info. */ 339 passwd_st.pw_comment = nullstr; /* no comments */ 340 passwd_st.pw_gecos = nullstr; /* no comments */ 341 passwd_st.pw_dir = nullstr; /* no default directory */ 342 passwd_st.pw_shell = nullstr; /* no default shell */ 343 344 shadow_st.sp_namp = nullstr; /* no name */ 345 shadow_st.sp_pwdp = lkstring; /* locked password */ 346 shadow_st.sp_lstchg = -1; /* no lastchanged date */ 347 shadow_st.sp_min = -1; /* no min */ 348 shadow_st.sp_max = -1; /* no max */ 349 shadow_st.sp_warn = -1; /* no warn */ 350 shadow_st.sp_inact = -1; /* no inactive */ 351 shadow_st.sp_expire = -1; /* no expire */ 352 shadow_st.sp_flag = 0; /* no flag */ 353 354 userattr_st.name = nullstr; 355 userattr_st.qualifier = nullstr; 356 userattr_st.res1 = nullstr; 357 userattr_st.res2 = nullstr; 358 359 ua_kva.length = 1; 360 ua_kv[0].key = USERATTR_TYPE_KW; 361 ua_kv[0].value = USERATTR_TYPE_NORMAL_KW; 362 ua_kva.data = ua_kv; 363 userattr_st.attr = &ua_kva; 364 365 /* parse the command line */ 366 367 while ((c = getopt(argc, argv, 368 "ml:c:h:u:g:s:f:e:k:A:P:R:T:oadK:")) != -1) { 369 370 switch (c) { 371 case 'm': 372 /* Modify */ 373 374 if ((A_MASK|D_MASK|M_MASK) & optn_mask) 375 bad_usage("Invalid combination of options"); 376 377 optn_mask |= M_MASK; 378 break; 379 380 case 'l' : 381 /* Change logname */ 382 383 if ((A_MASK|D_MASK|L_MASK) & optn_mask) 384 bad_usage("Invalid combination of options"); 385 386 if (strpbrk(optarg, ":\n") || 387 strlen(optarg) == 0) 388 bad_arg("Invalid argument to option -l"); 389 390 optn_mask |= L_MASK; 391 passwd_st.pw_name = optarg; 392 shadow_st.sp_namp = optarg; 393 userattr_st.name = optarg; 394 break; 395 396 case 'f' : 397 /* set inactive */ 398 399 if ((D_MASK|F_MASK) & optn_mask) 400 bad_usage("Invalid combination of options"); 401 if (((shadow_st.sp_inact = 402 strtol(optarg, &char_p, 10)) < (long)0) || 403 (*char_p != '\0') || 404 strlen(optarg) == 0) 405 bad_arg("Invalid argument to option -f"); 406 if (shadow_st.sp_inact == 0) 407 shadow_st.sp_inact = -1; 408 optn_mask |= F_MASK; 409 break; 410 411 case 'e' : 412 /* set expire date */ 413 414 if ((D_MASK|E_MASK) & optn_mask) 415 bad_usage("Invalid combination of options"); 416 417 if ((strlen(optarg)) < (size_t)2) 418 shadow_st.sp_expire = -1; 419 else { 420 putenv(DATMSK); 421 if ((tm_ptr = getdate(optarg)) == NULL) { 422 msg = "Invalid argument to option -e"; 423 bad_arg(msg); 424 } 425 if ((date = mktime(tm_ptr)) < 0) { 426 msg = "Invalid argument to option -e"; 427 bad_arg(msg); 428 } 429 shadow_st.sp_expire = (date / DAY); 430 if (shadow_st.sp_expire <= DAY_NOW) { 431 msg = "Invalid argument to option -e"; 432 bad_arg(msg); 433 } 434 } 435 436 optn_mask |= E_MASK; 437 break; 438 439 case 'c' : 440 /* The comment */ 441 442 if ((D_MASK|C_MASK) & optn_mask) 443 bad_usage("Invalid combination of options"); 444 445 if (strlen(optarg) > (size_t)CMT_SIZE || 446 strpbrk(optarg, ":\n")) 447 bad_arg("Invalid argument to option -c"); 448 449 optn_mask |= C_MASK; 450 passwd_st.pw_comment = optarg; 451 passwd_st.pw_gecos = optarg; 452 break; 453 454 case 'h' : 455 /* The home directory */ 456 457 if ((D_MASK|H_MASK) & optn_mask) 458 bad_usage("Invalid combination of options"); 459 460 if (strlen(optarg) > (size_t)DIR_SIZE || 461 strpbrk(optarg, ":\n")) 462 bad_arg("Invalid argument to option -h"); 463 464 optn_mask |= H_MASK; 465 passwd_st.pw_dir = optarg; 466 break; 467 468 case 'u' : 469 /* The uid */ 470 471 if ((D_MASK|U_MASK) & optn_mask) 472 bad_usage("Invalid combination of options"); 473 474 optn_mask |= U_MASK; 475 passwd_st.pw_uid = (uid_t)strtol(optarg, &char_p, 10); 476 if ((*char_p != '\0') || 477 (passwd_st.pw_uid < 0) || 478 (strlen(optarg) == 0)) 479 bad_arg("Invalid argument to option -u"); 480 481 break; 482 483 case 'g' : 484 /* The gid */ 485 486 if ((D_MASK|G_MASK) & optn_mask) 487 bad_usage("Invalid combination of options"); 488 489 optn_mask |= G_MASK; 490 passwd_st.pw_gid = (gid_t)strtol(optarg, &char_p, 10); 491 492 if ((*char_p != '\0') || (passwd_st.pw_gid < 0) || 493 (strlen(optarg) == 0)) 494 bad_arg("Invalid argument to option -g"); 495 break; 496 497 case 's' : 498 /* The shell */ 499 500 if ((D_MASK|S_MASK) & optn_mask) 501 bad_usage("Invalid combination of options"); 502 503 if (strlen(optarg) > (size_t)SHL_SIZE || 504 strpbrk(optarg, ":\n")) 505 bad_arg("Invalid argument to option -s"); 506 507 optn_mask |= S_MASK; 508 passwd_st.pw_shell = optarg; 509 break; 510 511 case 'o' : 512 /* Override unique uid */ 513 514 if ((D_MASK|O_MASK) & optn_mask) 515 bad_usage("Invalid combination of options"); 516 517 optn_mask |= O_MASK; 518 break; 519 520 case 'a' : 521 /* Add */ 522 523 if ((A_MASK|M_MASK|D_MASK|L_MASK) & optn_mask) 524 bad_usage("Invalid combination of options"); 525 526 optn_mask |= A_MASK; 527 break; 528 529 case 'd' : 530 /* Delete */ 531 532 if ((D_MASK|M_MASK|L_MASK|C_MASK| 533 H_MASK|U_MASK|G_MASK|S_MASK| 534 O_MASK|A_MASK) & optn_mask) 535 bad_usage("Invalid combination of options"); 536 537 optn_mask |= D_MASK; 538 break; 539 540 case 'K': 541 if (D_MASK & optn_mask) 542 bad_usage("Invalid combination of options"); 543 544 char_p = strchr(optarg, '='); 545 if (char_p == NULL) 546 bad_usage("Missing value in -K option"); 547 548 *char_p++ = '\0'; 549 550 for (i = 0; i < UA_KEYS; i++) { 551 if (strcmp(optarg, ua_opts[i].key) == 0) { 552 ua_opts[i].newvalue = 553 _escape(char_p, KV_SPECIAL); 554 assign_attr(&userattr_st, optarg, 555 char_p); 556 break; 557 } 558 } 559 if (i == UA_KEYS) 560 bad_usage("bad key"); 561 optn_mask |= UATTR_MASK; 562 break; 563 564 case '?' : 565 566 bad_usage(""); 567 break; 568 569 default : 570 /* Extended User Attributes */ 571 { 572 int j; 573 574 for (j = 0; j < UA_KEYS; j++) { 575 if (ua_opts[j].option == (char)c) { 576 if ((D_MASK) & optn_mask) 577 bad_usage("Invalid " 578 "combination of " 579 " options"); 580 optn_mask |= UATTR_MASK; 581 assign_attr(&userattr_st, 582 ua_opts[j].key, 583 _escape(optarg, 584 KV_SPECIAL)); 585 ua_opts[j].newvalue = 586 _escape(optarg, KV_SPECIAL); 587 break; 588 } 589 } 590 break; 591 } 592 } 593 } 594 595 /* check command syntax for the following errors */ 596 /* too few or too many arguments */ 597 /* no -a -m or -d option */ 598 /* -o without -u */ 599 /* -m with no other option */ 600 601 if (optind == argc || argc > (optind+1) || 602 !((A_MASK|M_MASK|D_MASK) & optn_mask) || 603 ((optn_mask & O_MASK) && !(optn_mask & U_MASK)) || 604 ((optn_mask & M_MASK) && 605 !(optn_mask & 606 (L_MASK|C_MASK|H_MASK|U_MASK|G_MASK|S_MASK|F_MASK| 607 E_MASK|UATTR_MASK)))) 608 bad_usage("Invalid command syntax"); 609 610 /* null string argument or bad characters ? */ 611 if ((strlen(argv[optind]) == 0) || strpbrk(argv[optind], ":\n")) 612 bad_arg("Invalid name"); 613 614 lognamp = argv [optind]; 615 616 /* 617 * if we are adding a new user or modifying an existing user 618 * (not the logname), then copy logname into the two data 619 * structures 620 */ 621 622 if ((A_MASK & optn_mask) || 623 ((M_MASK & optn_mask) && !(optn_mask & L_MASK))) { 624 passwd_st.pw_name = argv [optind]; 625 shadow_st.sp_namp = argv [optind]; 626 userattr_st.name = argv [optind]; 627 } 628 629 /* Put in directory if we are adding and we need a default */ 630 631 if (!(optn_mask & H_MASK) && (optn_mask & A_MASK)) { 632 if ((passwd_st.pw_dir = malloc((size_t)DIR_SIZE)) == NULL) 633 file_error(); 634 635 *passwd_st.pw_dir = '\0'; 636 (void) strcat(passwd_st.pw_dir, defdir); 637 (void) strcat(passwd_st.pw_dir, lognamp); 638 } 639 640 /* Check the number of password files we are touching */ 641 642 if ((!((M_MASK & optn_mask) && !(L_MASK & optn_mask))) || 643 ((M_MASK & optn_mask) && ((E_MASK & optn_mask) || 644 (F_MASK & optn_mask)))) 645 info_mask |= BOTH_FILES; 646 647 if ((D_MASK|L_MASK|UATTR_MASK) & optn_mask) 648 info_mask |= UATTR_FILE; 649 650 /* Open the temporary file(s) with appropriate permission mask */ 651 /* and the appropriate owner */ 652 653 if (stat(PASSWD, &statbuf) < 0) 654 file_error(); 655 656 fd_ptemp = open(PASSTEMP, O_CREAT|O_EXCL|O_WRONLY, statbuf.st_mode); 657 if (fd_ptemp == -1) { 658 if (errno == EEXIST) { 659 if (unlink(PASSTEMP)) { 660 msg = "%s: warning: cannot unlink %s\n"; 661 (void) fprintf(stderr, gettext(msg), prognamp, 662 PASSTEMP); 663 } 664 fd_ptemp = open(PASSTEMP, O_CREAT|O_EXCL|O_WRONLY, 665 statbuf.st_mode); 666 if (fd_ptemp == -1) { 667 file_error(); 668 } 669 670 } else 671 file_error(); 672 } 673 fp_ptemp = fdopen(fd_ptemp, "w"); 674 if (fp_ptemp == NULL) 675 file_error(); 676 error = fchown(fd_ptemp, statbuf.st_uid, statbuf.st_gid); 677 if (error == 0) 678 error = fchmod(fd_ptemp, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 679 if (error != 0) { 680 (void) fclose(fp_ptemp); 681 if (unlink(PASSTEMP)) { 682 msg = "%s: warning: cannot unlink %s\n"; 683 (void) fprintf(stderr, gettext(msg), prognamp, 684 PASSTEMP); 685 } 686 file_error(); 687 } 688 689 if (info_mask & BOTH_FILES) { 690 if (stat(SHADOW, &statbuf) < 0) { 691 rid_tmpf(); 692 file_error(); 693 } 694 fd_stemp = open(SHADTEMP, O_CREAT|O_EXCL|O_WRONLY, 695 statbuf.st_mode); 696 if (fd_stemp == -1) { 697 if (errno == EEXIST) { 698 if (unlink(SHADTEMP)) { 699 msg = "%s: warning: cannot unlink %s\n"; 700 (void) fprintf(stderr, gettext(msg), 701 prognamp, SHADTEMP); 702 } 703 fd_stemp = open(SHADTEMP, 704 O_CREAT|O_EXCL|O_WRONLY, statbuf.st_mode); 705 if (fd_stemp == -1) { 706 rid_tmpf(); 707 file_error(); 708 } 709 710 } else { 711 rid_tmpf(); 712 file_error(); 713 } 714 } 715 fp_stemp = fdopen(fd_stemp, "w"); 716 if (fp_stemp == NULL) { 717 rid_tmpf(); 718 file_error(); 719 } 720 error = fchown(fd_stemp, statbuf.st_uid, statbuf.st_gid); 721 if (error == 0) 722 error = fchmod(fd_stemp, S_IRUSR); 723 if (error != 0) { 724 rid_tmpf(); 725 file_error(); 726 } 727 } 728 729 if (info_mask & UATTR_FILE) { 730 if (stat(USERATTR_FILENAME, &statbuf) < 0) { 731 rid_tmpf(); 732 file_error(); 733 } 734 fd_uatemp = open(USERATTR_TEMP, O_CREAT|O_EXCL|O_WRONLY, 735 statbuf.st_mode); 736 if (fd_uatemp == -1) { 737 if (errno == EEXIST) { 738 if (unlink(USERATTR_TEMP)) { 739 msg = "%s: warning: cannot unlink %s\n"; 740 (void) fprintf(stderr, gettext(msg), 741 prognamp, USERATTR_TEMP); 742 } 743 fd_uatemp = open(USERATTR_TEMP, 744 O_CREAT|O_EXCL|O_WRONLY, statbuf.st_mode); 745 if (fd_uatemp == -1) { 746 rid_tmpf(); 747 file_error(); 748 } 749 750 } else { 751 rid_tmpf(); 752 file_error(); 753 } 754 } 755 fp_uatemp = fdopen(fd_uatemp, "w"); 756 if (fp_uatemp == NULL) { 757 rid_tmpf(); 758 file_error(); 759 } 760 error = fchown(fd_uatemp, statbuf.st_uid, statbuf.st_gid); 761 if (error == 0) 762 error = fchmod(fd_uatemp, 763 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 764 if (error != 0) { 765 rid_tmpf(); 766 file_error(); 767 } 768 } 769 /* Default uid needed ? */ 770 771 if (!(optn_mask & U_MASK) && (optn_mask & A_MASK)) { 772 /* mark it in the information mask */ 773 info_mask |= NEED_DEF_UID; 774 775 /* create the head of the uid number list */ 776 uid_sp = malloc(sizeof (struct uid_blk)); 777 if (uid_sp == NULL) { 778 rid_tmpf(); 779 file_error(); 780 } 781 782 uid_sp->link = NULL; 783 uid_sp->low = (UID_MIN -1); 784 uid_sp->high = (UID_MIN -1); 785 } 786 787 /* 788 * This next section is modified to allow for NIS passwd file 789 * conventions. In the case where a password entry was being 790 * added to the password file, the original AT&T code read 791 * the entire password file in, noted any information needed, and 792 * copied the entries to a temporary file. Then the new entry 793 * was added to the temporary file, and the temporary file was 794 * moved to be the real password file. 795 * 796 * The problem is, that with NIS compatability, we want to add new 797 * entries BEFORE the first NIS-referrant entry, so as not to have 798 * any surprises. To accomplish this without extensively modifying 799 * the logic of the code below, as soon as a NIS-referrant entry is 800 * found we stop copying entries to the TEMP file and instead we 801 * remember 802 * the first NIS entry and where we found it, scan the rest of the 803 * password file without copying entries, then write the new entry, copy 804 * the stored password entry, then copy the rest of the password file. 805 */ 806 807 808 error = 0; 809 810 if ((pwf = fopen("/etc/passwd", "r")) == NULL) { 811 rid_tmpf(); 812 if (errno == ENOENT) 813 bad_news(); 814 else 815 file_error(); 816 } 817 818 NIS_entry_seen = 0; 819 cur_pos = 0; 820 /* The while loop for reading PASSWD entries */ 821 info_mask |= WRITE_P_ENTRY; 822 823 while (!end_of_file) { 824 pw_ptr1p = fgetpwent(pwf); 825 if (pw_ptr1p == NULL) { 826 if (!feof(pwf)) { 827 /* A real error - report it and exit */ 828 rid_tmpf(); 829 bad_pasf(); 830 } 831 else 832 break; 833 } 834 835 if (!NIS_entry_seen) 836 info_mask |= WRITE_P_ENTRY; 837 else 838 info_mask &= ~WRITE_P_ENTRY; 839 840 /* 841 * Set up the uid usage blocks to find the first 842 * available uid above UID_MIN, if needed 843 */ 844 845 if (info_mask & NEED_DEF_UID) 846 add_uid(pw_ptr1p->pw_uid); 847 848 /* Check for unique UID */ 849 850 if (strcmp(lognamp, pw_ptr1p->pw_name) && 851 (pw_ptr1p->pw_uid == passwd_st.pw_uid) && 852 ((optn_mask & U_MASK) && !(optn_mask & O_MASK))) { 853 rid_tmpf(); /* get rid of temp files */ 854 bad_uid(); 855 } 856 857 /* Check for unique new logname */ 858 859 if (strcmp(lognamp, pw_ptr1p->pw_name) == 0 && 860 optn_mask & L_MASK && 861 strcmp(pw_ptr1p->pw_name, passwd_st.pw_name) == 0) { 862 rid_tmpf(); 863 #ifdef att 864 if (!getspnam(pw_ptr1p->pw_name)) 865 #else 866 if (!local_getspnam(pw_ptr1p->pw_name)) 867 #endif 868 bad_pasf(); 869 else 870 bad_name("logname already exists"); 871 } 872 873 if (strcmp(lognamp, pw_ptr1p->pw_name) == 0) { 874 875 /* no good if we want to add an existing logname */ 876 if (optn_mask & A_MASK) { 877 rid_tmpf(); 878 #ifdef att 879 if (!getspnam(lognamp)) 880 #else 881 if (!local_getspnam(lognamp)) 882 #endif 883 bad_pasf(); 884 else 885 bad_name("name already exists"); 886 } 887 888 /* remember we found it */ 889 info_mask |= FOUND; 890 891 /* Do not write it out on the fly */ 892 if (optn_mask & D_MASK) 893 info_mask &= ~WRITE_P_ENTRY; 894 895 if (optn_mask & M_MASK) { 896 897 #ifdef att 898 if (!getspnam(lognamp)) 899 #else 900 if (!local_getspnam(lognamp)) 901 #endif 902 { 903 rid_tmpf(); 904 bad_pasf(); 905 } 906 if (optn_mask & L_MASK) 907 pw_ptr1p->pw_name = passwd_st.pw_name; 908 909 if (optn_mask & U_MASK) 910 pw_ptr1p->pw_uid = passwd_st.pw_uid; 911 912 if (optn_mask & G_MASK) 913 pw_ptr1p->pw_gid = passwd_st.pw_gid; 914 915 if (optn_mask & C_MASK) { 916 pw_ptr1p->pw_comment = 917 passwd_st.pw_comment; 918 919 pw_ptr1p->pw_gecos = 920 passwd_st.pw_comment; 921 } 922 923 if (optn_mask & H_MASK) 924 pw_ptr1p->pw_dir = passwd_st.pw_dir; 925 926 if (optn_mask & S_MASK) 927 pw_ptr1p->pw_shell = passwd_st.pw_shell; 928 ck_p_sz(pw_ptr1p); /* check entry size */ 929 } 930 } 931 932 if (optn_mask & A_MASK) { 933 if (!NIS_entry_seen) { 934 char *p; 935 p = strchr("+-", pw_ptr1p->pw_name[0]); 936 if (p != NULL) { 937 /* 938 * Found first NIS entry. 939 * so remember it. 940 */ 941 NIS_pos = cur_pos; 942 NIS_entry_seen = 1; 943 info_mask &= ~WRITE_P_ENTRY; 944 } 945 else 946 cur_pos = ftell(pwf); 947 } 948 } 949 950 if (info_mask & WRITE_P_ENTRY) { 951 if (putpwent(pw_ptr1p, fp_ptemp)) { 952 rid_tmpf(); 953 file_error(); 954 } 955 } 956 } /* end-of-while-loop */ 957 958 if (error >= 1) { 959 msg = "%s: Bad entry found in /etc/passwd. Run pwconv.\n"; 960 fprintf(stderr, gettext(msg), prognamp); 961 } 962 963 /* Cannot find the target entry and we are deleting or modifying */ 964 965 if (!(info_mask & FOUND) && (optn_mask & (D_MASK|M_MASK))) { 966 rid_tmpf(); 967 #ifdef att 968 if (getspnam(lognamp) != NULL) 969 #else 970 if (local_getspnam(lognamp) != NULL) 971 #endif 972 bad_pasf(); 973 else 974 bad_name("name does not exist"); 975 } 976 977 /* First available uid above UID_MIN is ... */ 978 979 if (info_mask & NEED_DEF_UID) 980 passwd_st.pw_uid = uid_sp->high + 1; 981 982 /* Write out the added entry now */ 983 984 if (optn_mask & A_MASK) { 985 ck_p_sz(&passwd_st); /* Check entry size */ 986 if (putpwent(&passwd_st, fp_ptemp)) { 987 rid_tmpf(); 988 file_error(); 989 } 990 /* 991 * Now put out the rest of the password file, if needed. 992 */ 993 if (NIS_entry_seen) { 994 int n; 995 char buf[1024]; 996 997 if (fseek(pwf, NIS_pos, SEEK_SET) < 0) { 998 rid_tmpf(); 999 file_error(); 1000 } 1001 while ((n = fread(buf, sizeof (char), 1024, pwf)) > 0) { 1002 if (fwrite(buf, sizeof (char), n, fp_ptemp) 1003 != n) { 1004 rid_tmpf(); 1005 file_error(); 1006 } 1007 } 1008 } 1009 } 1010 1011 (void) fclose(pwf); 1012 1013 /* flush and sync the file before closing it */ 1014 if (fflush(fp_ptemp) != 0 || fsync(fd_ptemp) != 0) 1015 file_error(); 1016 1017 /* Now we are done with PASSWD */ 1018 (void) fclose(fp_ptemp); 1019 1020 /* Do this if we are touching both password files */ 1021 1022 1023 if (info_mask & BOTH_FILES) { 1024 info_mask &= ~FOUND; /* Reset FOUND flag */ 1025 1026 /* The while loop for reading SHADOW entries */ 1027 info_mask |= WRITE_S_ENTRY; 1028 1029 end_of_file = 0; 1030 errno = 0; 1031 error = 0; 1032 1033 NIS_entry_seen = 0; 1034 cur_pos = 0; 1035 1036 if ((spf = fopen("/etc/shadow", "r")) == NULL) { 1037 rid_tmpf(); 1038 file_error(); 1039 } 1040 1041 while (!end_of_file) { 1042 sp_ptr1p = fgetspent(spf); 1043 if (sp_ptr1p == NULL) { 1044 if (!feof(spf)) { 1045 rid_tmpf(); 1046 bad_pasf(); 1047 } 1048 else 1049 break; 1050 } 1051 1052 if (!NIS_entry_seen) 1053 info_mask |= WRITE_S_ENTRY; 1054 else 1055 info_mask &= ~WRITE_S_ENTRY; 1056 1057 /* 1058 * See if the new logname already exist in the 1059 * shadow passwd file 1060 */ 1061 if ((optn_mask & M_MASK) && 1062 strcmp(lognamp, shadow_st.sp_namp) != 0 && 1063 strcmp(sp_ptr1p->sp_namp, shadow_st.sp_namp) == 0) { 1064 rid_tmpf(); 1065 bad_pasf(); 1066 } 1067 1068 if (strcmp(lognamp, sp_ptr1p->sp_namp) == 0) { 1069 info_mask |= FOUND; 1070 if (optn_mask & A_MASK) { 1071 /* password file inconsistent */ 1072 rid_tmpf(); 1073 bad_pasf(); 1074 } 1075 1076 if (optn_mask & M_MASK) { 1077 sp_ptr1p->sp_namp = shadow_st.sp_namp; 1078 if (F_MASK & optn_mask) 1079 sp_ptr1p->sp_inact = 1080 shadow_st.sp_inact; 1081 if (E_MASK & optn_mask) 1082 sp_ptr1p->sp_expire = 1083 shadow_st.sp_expire; 1084 1085 ck_s_sz(sp_ptr1p); 1086 } 1087 1088 if (optn_mask & D_MASK) 1089 info_mask &= ~WRITE_S_ENTRY; 1090 } 1091 1092 if (optn_mask & A_MASK) { 1093 if (!NIS_entry_seen) { 1094 char *p; 1095 p = strchr("+-", sp_ptr1p->sp_namp[0]); 1096 if (p != NULL) { 1097 /* 1098 * Found first NIS entry. 1099 * so remember it. 1100 */ 1101 NIS_pos = cur_pos; 1102 NIS_entry_seen = 1; 1103 info_mask &= ~WRITE_S_ENTRY; 1104 } 1105 else 1106 cur_pos = ftell(spf); 1107 } 1108 } 1109 1110 if (info_mask & WRITE_S_ENTRY) { 1111 if (putspent(sp_ptr1p, fp_stemp)) { 1112 rid_tmpf(); 1113 file_error(); 1114 } 1115 } 1116 1117 } /* end-of-while-loop */ 1118 1119 if (error >= 1) { 1120 1121 msg = BAD_ENT_MESSAGE; 1122 fprintf(stderr, gettext(msg), prognamp); 1123 } 1124 1125 /* 1126 * If we cannot find the entry and we are deleting or 1127 * modifying 1128 */ 1129 1130 if (!(info_mask & FOUND) && (optn_mask & (D_MASK|M_MASK))) { 1131 rid_tmpf(); 1132 bad_pasf(); 1133 } 1134 1135 if (optn_mask & A_MASK) { 1136 ck_s_sz(&shadow_st); 1137 if (putspent(&shadow_st, fp_stemp)) { 1138 rid_tmpf(); 1139 file_error(); 1140 } 1141 1142 /* 1143 * Now put out the rest of the shadow file, if needed. 1144 */ 1145 if (NIS_entry_seen) { 1146 file_copy(spf, NIS_pos); 1147 } 1148 } 1149 1150 /* flush and sync the file before closing it */ 1151 if (fflush(fp_stemp) != 0 || fsync(fd_stemp) != 0) 1152 file_error(); 1153 (void) fclose(fp_stemp); 1154 1155 /* Done with SHADOW */ 1156 (void) fclose(spf); 1157 1158 } /* End of if info_mask */ 1159 1160 if (info_mask & UATTR_FILE) { 1161 info_mask &= ~FOUND; /* Reset FOUND flag */ 1162 1163 /* The while loop for reading USER_ATTR entries */ 1164 info_mask |= WRITE_S_ENTRY; 1165 1166 end_of_file = 0; 1167 errno = 0; 1168 error = 0; 1169 1170 NIS_entry_seen = 0; 1171 cur_pos = 0; 1172 1173 if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) { 1174 rid_tmpf(); 1175 file_error(); 1176 } 1177 1178 while (!end_of_file) { 1179 ua_ptr1p = fgetuserattr(uaf); 1180 if (ua_ptr1p == NULL) { 1181 if (!feof(uaf)) { 1182 rid_tmpf(); 1183 bad_uattr(); 1184 } 1185 else 1186 break; 1187 } 1188 1189 if (ua_ptr1p->name[0] == '#') { 1190 /* 1191 * If this is a comment, write it back as it 1192 * is. 1193 */ 1194 if (ua_ptr1p->qualifier[0] == '\0' && 1195 ua_ptr1p->res1[0] == '\0' && 1196 ua_ptr1p->res2[0] == '\0' && 1197 (ua_ptr1p->attr == NULL || 1198 ua_ptr1p->attr->length == 0)) 1199 (void) fprintf(fp_uatemp, "%s\n", 1200 ua_ptr1p->name); 1201 else 1202 /* 1203 * This is a commented user_attr entry; 1204 * reformat it, and write it back. 1205 */ 1206 putuserattrent(ua_ptr1p, fp_uatemp); 1207 free_userattr(ua_ptr1p); 1208 continue; 1209 } 1210 1211 if (!NIS_entry_seen) 1212 info_mask |= WRITE_S_ENTRY; 1213 else 1214 info_mask &= ~WRITE_S_ENTRY; 1215 1216 /* 1217 * See if the new logname already exist in the 1218 * user_attr file 1219 */ 1220 if ((optn_mask & M_MASK) && 1221 strcmp(lognamp, userattr_st.name) != 0 && 1222 strcmp(ua_ptr1p->name, userattr_st.name) == 0) { 1223 rid_tmpf(); 1224 bad_pasf(); 1225 } 1226 1227 if (strcmp(lognamp, ua_ptr1p->name) == 0) { 1228 info_mask |= FOUND; 1229 if (optn_mask & A_MASK) { 1230 /* password file inconsistent */ 1231 rid_tmpf(); 1232 bad_pasf(); 1233 } 1234 1235 if (optn_mask & M_MASK) { 1236 int j; 1237 char *value; 1238 1239 for (j = 0; j < UA_KEYS; j++) { 1240 if (ua_opts[j].newvalue != NULL) 1241 continue; 1242 value = 1243 kva_match(ua_ptr1p->attr, 1244 (char *)ua_opts[j].key); 1245 if (value == NULL) 1246 continue; 1247 assign_attr(&userattr_st, 1248 ua_opts[j].key, 1249 value); 1250 } 1251 free_userattr(ua_ptr1p); 1252 ua_ptr1p = &userattr_st; 1253 } 1254 1255 if (optn_mask & D_MASK) 1256 info_mask &= ~WRITE_S_ENTRY; 1257 } else if (optn_mask & D_MASK) { 1258 char *rolelist; 1259 1260 rolelist = kva_match(ua_ptr1p->attr, 1261 USERATTR_ROLES_KW); 1262 if (rolelist) { 1263 unassign_role(ua_ptr1p, 1264 rolelist, lognamp); 1265 } 1266 } 1267 1268 if (info_mask & WRITE_S_ENTRY) { 1269 putuserattrent(ua_ptr1p, fp_uatemp); 1270 } 1271 1272 if (!(optn_mask & M_MASK)) 1273 free_userattr(ua_ptr1p); 1274 } /* end-of-while-loop */ 1275 1276 if (error >= 1) { 1277 1278 msg = BAD_ENT_MESSAGE; 1279 fprintf(stderr, gettext(msg), prognamp); 1280 } 1281 1282 /* 1283 * Add entry in user_attr if masks is UATTR_MASK 1284 * We don't need to do anything for L_MASK if there's 1285 * no user_attr entry for the user being modified. 1286 */ 1287 if (!(info_mask & FOUND) && !(L_MASK & optn_mask) && 1288 !(D_MASK & optn_mask)) { 1289 putuserattrent(&userattr_st, fp_uatemp); 1290 } 1291 1292 /* flush and sync the file before closing it */ 1293 if (fflush(fp_uatemp) != 0 || fsync(fd_uatemp) != 0) 1294 file_error(); 1295 (void) fclose(fp_uatemp); 1296 1297 /* Done with USERATTR */ 1298 (void) fclose(uaf); 1299 1300 } /* End of if info_mask */ 1301 /* ignore all signals */ 1302 1303 for (i = 1; i < NSIG; i++) 1304 (void) sigset(i, SIG_IGN); 1305 1306 errno = 0; /* For correcting sigset to SIGKILL */ 1307 1308 if (unlink(OPASSWD) && access(OPASSWD, 0) == 0) 1309 file_error(); 1310 1311 if (link(PASSWD, OPASSWD) == -1) 1312 file_error(); 1313 1314 1315 if (rename(PASSTEMP, PASSWD) == -1) { 1316 if (link(OPASSWD, PASSWD)) 1317 bad_news(); 1318 file_error(); 1319 } 1320 1321 1322 if (info_mask & BOTH_FILES) { 1323 1324 if (unlink(OSHADOW) && access(OSHADOW, 0) == 0) { 1325 if (rec_pwd()) 1326 bad_news(); 1327 else 1328 file_error(); 1329 } 1330 1331 if (link(SHADOW, OSHADOW) == -1) { 1332 if (rec_pwd()) 1333 bad_news(); 1334 else 1335 file_error(); 1336 } 1337 1338 1339 if (rename(SHADTEMP, SHADOW) == -1) { 1340 if (rename(OSHADOW, SHADOW) == -1) 1341 bad_news(); 1342 1343 if (rec_pwd()) 1344 bad_news(); 1345 else 1346 file_error(); 1347 } 1348 1349 } 1350 if (info_mask & UATTR_FILE) { 1351 if (unlink(OUSERATTR_FILENAME) && 1352 access(OUSERATTR_FILENAME, 0) == 0) { 1353 if (rec_pwd()) 1354 bad_news(); 1355 else 1356 file_error(); 1357 } 1358 1359 if (link(USERATTR_FILENAME, OUSERATTR_FILENAME) == -1) { 1360 if (rec_pwd()) 1361 bad_news(); 1362 else 1363 file_error(); 1364 } 1365 1366 1367 if (rename(USERATTR_TEMP, USERATTR_FILENAME) == -1) { 1368 if (rename(OUSERATTR_FILENAME, USERATTR_FILENAME) == -1) 1369 bad_news(); 1370 1371 if (rec_pwd()) 1372 bad_news(); 1373 else 1374 file_error(); 1375 } 1376 1377 } 1378 1379 ulckpwdf(); 1380 1381 /* 1382 * Return 0 status, indicating success 1383 */ 1384 return (0); 1385 1386 } /* end of main */ 1387 1388 /* Try to recover the old password file */ 1389 1390 int 1391 rec_pwd(void) 1392 { 1393 if (unlink(PASSWD) || link(OPASSWD, PASSWD)) 1394 return (-1); 1395 1396 return (0); 1397 } 1398 1399 /* combine two uid_blk's */ 1400 1401 void 1402 uid_bcom(struct uid_blk *uid_p) 1403 { 1404 struct uid_blk *uid_tp; 1405 1406 uid_tp = uid_p->link; 1407 uid_p->high = uid_tp->high; 1408 uid_p->link = uid_tp->link; 1409 1410 free(uid_tp); 1411 } 1412 1413 /* add a new uid_blk */ 1414 1415 void 1416 add_ublk(uid_t num, struct uid_blk *uid_p) 1417 { 1418 struct uid_blk *uid_tp; 1419 1420 uid_tp = malloc(sizeof (struct uid_blk)); 1421 if (uid_tp == NULL) { 1422 rid_tmpf(); 1423 file_error(); 1424 } 1425 1426 uid_tp->high = uid_tp->low = num; 1427 uid_tp->link = uid_p->link; 1428 uid_p->link = uid_tp; 1429 } 1430 1431 /* 1432 * Here we are using a linked list of uid_blk to keep track of all 1433 * the used uids. Each uid_blk represents a range of used uid, 1434 * with low represents the low inclusive end and high represents 1435 * the high inclusive end. In the beginning, we initialize a linked 1436 * list of one uid_blk with low = high = (UID_MIN-1). This was 1437 * done in main(). 1438 * Each time we read in another used uid, we add it onto the linked 1439 * list by either making a new uid_blk, decrementing the low of 1440 * an existing uid_blk, incrementing the high of an existing 1441 * uid_blk, or combining two existing uid_blks. After we finished 1442 * building this linked list, the first available uid above or 1443 * equal to UID_MIN is the high of the first uid_blk in the linked 1444 * list + 1. 1445 */ 1446 /* add_uid() adds uid to the link list of used uids */ 1447 void 1448 add_uid(uid_t uid) 1449 { 1450 struct uid_blk *uid_p; 1451 /* Only keep track of the ones above UID_MIN */ 1452 1453 if (uid >= UID_MIN) { 1454 uid_p = uid_sp; 1455 1456 while (uid_p != NULL) { 1457 1458 if (uid_p->link != NULL) { 1459 1460 if (uid >= uid_p->link->low) 1461 uid_p = uid_p->link; 1462 1463 else if (uid >= uid_p->low && 1464 uid <= uid_p->high) { 1465 uid_p = NULL; 1466 } 1467 1468 else if (uid == (uid_p->high+1)) { 1469 1470 if (++uid_p->high == 1471 (uid_p->link->low - 1)) { 1472 uid_bcom(uid_p); 1473 } 1474 uid_p = NULL; 1475 } 1476 1477 else if (uid == (uid_p->link->low - 1)) { 1478 uid_p->link->low --; 1479 uid_p = NULL; 1480 } 1481 1482 else if (uid < uid_p->link->low) { 1483 add_ublk(uid, uid_p); 1484 uid_p = NULL; 1485 } 1486 } /* if uid_p->link */ 1487 1488 else { 1489 1490 if (uid == (uid_p->high + 1)) { 1491 uid_p->high++; 1492 uid_p = NULL; 1493 } else if (uid >= uid_p->low && 1494 uid <= uid_p->high) { 1495 uid_p = NULL; 1496 } else { 1497 add_ublk(uid, uid_p); 1498 uid_p = NULL; 1499 } 1500 } /* else */ 1501 } /* while uid_p */ 1502 1503 } /* if uid */ 1504 } 1505 1506 void 1507 bad_perm(void) 1508 { 1509 (void) fprintf(stderr, gettext("%s: Permission denied\n"), prognamp); 1510 exit(1); 1511 } 1512 1513 void 1514 bad_usage(char *sp) 1515 { 1516 if (strlen(sp) != 0) 1517 (void) fprintf(stderr, "%s: %s\n", prognamp, gettext(sp)); 1518 (void) fprintf(stderr, gettext("Usage:\n\ 1519 %s -a [-c comment] [-h homedir] [-u uid [-o]] [-g gid] \n\ 1520 [-s shell] [-f inactive] [-e expire] name\n\ 1521 %s -m -c comment | -h homedir | -u uid [-o] | -g gid |\n\ 1522 -s shell | -f inactive | -e expire | -l logname name\n\ 1523 %s -d name\n"), prognamp, prognamp, prognamp); 1524 if (info_mask & LOCKED) 1525 ulckpwdf(); 1526 exit(2); 1527 } 1528 1529 void 1530 bad_arg(char *s) 1531 { 1532 (void) fprintf(stderr, "%s: %s\n", prognamp, gettext(s)); 1533 1534 if (info_mask & LOCKED) 1535 ulckpwdf(); 1536 exit(3); 1537 } 1538 1539 void 1540 bad_name(char *s) 1541 { 1542 (void) fprintf(stderr, "%s: %s\n", prognamp, gettext(s)); 1543 ulckpwdf(); 1544 exit(9); 1545 } 1546 1547 void 1548 bad_uid(void) 1549 { 1550 (void) fprintf(stderr, gettext("%s: UID in use\n"), prognamp); 1551 1552 ulckpwdf(); 1553 exit(4); 1554 } 1555 1556 void 1557 bad_pasf(void) 1558 { 1559 msg = "%s: Inconsistent password files\n"; 1560 (void) fprintf(stderr, gettext(msg), prognamp); 1561 1562 ulckpwdf(); 1563 exit(5); 1564 } 1565 1566 void 1567 bad_uattr(void) 1568 { 1569 msg = "%s: Bad user_attr database\n"; 1570 (void) fprintf(stderr, gettext(msg), prognamp); 1571 1572 ulckpwdf(); 1573 exit(5); 1574 } 1575 1576 void 1577 file_error(void) 1578 { 1579 msg = "%s: Unexpected failure. Password files unchanged\n"; 1580 (void) fprintf(stderr, gettext(msg), prognamp); 1581 1582 ulckpwdf(); 1583 exit(6); 1584 } 1585 1586 void 1587 bad_news(void) 1588 { 1589 msg = "%s: Unexpected failure. Password file(s) missing\n"; 1590 (void) fprintf(stderr, gettext(msg), prognamp); 1591 1592 ulckpwdf(); 1593 exit(7); 1594 } 1595 1596 void 1597 no_lock(void) 1598 { 1599 msg = "%s: Password file(s) busy. Try again later\n"; 1600 (void) fprintf(stderr, gettext(msg), prognamp); 1601 1602 exit(8); 1603 } 1604 1605 /* Check for the size of the whole passwd entry */ 1606 void 1607 ck_p_sz(struct passwd *pwp) 1608 { 1609 char ctp[128]; 1610 1611 /* Ensure that the combined length of the individual */ 1612 /* fields will fit in a passwd entry. The 1 accounts for the */ 1613 /* newline and the 6 accounts for the colons (:'s) */ 1614 if (((int)strlen(pwp->pw_name) + 1 + 1615 sprintf(ctp, "%d", pwp->pw_uid) + 1616 sprintf(ctp, "%d", pwp->pw_gid) + 1617 (int)strlen(pwp->pw_comment) + 1618 (int)strlen(pwp->pw_dir) + 1619 (int)strlen(pwp->pw_shell) + 6) > (ENTRY_LENGTH-1)) { 1620 rid_tmpf(); 1621 bad_arg("New password entry too long"); 1622 } 1623 } 1624 1625 /* Check for the size of the whole passwd entry */ 1626 void 1627 ck_s_sz(struct spwd *ssp) 1628 { 1629 char ctp[128]; 1630 1631 /* Ensure that the combined length of the individual */ 1632 /* fields will fit in a shadow entry. The 1 accounts for the */ 1633 /* newline and the 7 accounts for the colons (:'s) */ 1634 if (((int)strlen(ssp->sp_namp) + 1 + 1635 (int)strlen(ssp->sp_pwdp) + 1636 sprintf(ctp, "%d", ssp->sp_lstchg) + 1637 sprintf(ctp, "%d", ssp->sp_min) + 1638 sprintf(ctp, "%d", ssp->sp_max) + 1639 sprintf(ctp, "%d", ssp->sp_warn) + 1640 sprintf(ctp, "%d", ssp->sp_inact) + 1641 sprintf(ctp, "%d", ssp->sp_expire) + 7) > (ENTRY_LENGTH - 1)) { 1642 rid_tmpf(); 1643 bad_arg("New password entry too long"); 1644 } 1645 } 1646 1647 /* Get rid of the temp files */ 1648 void 1649 rid_tmpf(void) 1650 { 1651 (void) fclose(fp_ptemp); 1652 1653 if (unlink(PASSTEMP)) { 1654 msg = "%s: warning: cannot unlink %s\n"; 1655 (void) fprintf(stderr, gettext(msg), prognamp, PASSTEMP); 1656 } 1657 1658 if (info_mask & BOTH_FILES) { 1659 (void) fclose(fp_stemp); 1660 1661 if (unlink(SHADTEMP)) { 1662 msg = "%s: warning: cannot unlink %s\n"; 1663 (void) fprintf(stderr, gettext(msg), prognamp, 1664 SHADTEMP); 1665 } 1666 } 1667 1668 if (info_mask & UATTR_FILE) { 1669 (void) fclose(fp_uatemp); 1670 1671 if (unlink(USERATTR_TEMP)) { 1672 msg = "%s: warning: cannot unlink %s\n"; 1673 (void) fprintf(stderr, gettext(msg), prognamp, 1674 USERATTR_TEMP); 1675 } 1676 } 1677 } 1678 1679 void 1680 file_copy(FILE *spf, long NIS_pos) 1681 { 1682 int n; 1683 char buf[1024]; 1684 1685 if (fseek(spf, NIS_pos, SEEK_SET) < 0) { 1686 rid_tmpf(); 1687 file_error(); 1688 } 1689 while ((n = fread(buf, sizeof (char), 1024, spf)) > 0) { 1690 if (fwrite(buf, sizeof (char), n, fp_stemp) != n) { 1691 rid_tmpf(); 1692 file_error(); 1693 } 1694 } 1695 } 1696