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