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