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