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