8321 passmgmt: misleading-indentation
[unleashed.git] / usr / src / cmd / passmgmt / passmgmt.c
blobd2eef294aa5f6225365d7b27b4f8c1d5f25a28df
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <shadow.h>
31 #include <pwd.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <sys/stat.h>
35 #include <errno.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <locale.h>
40 #include <fcntl.h>
41 #include <secdb.h>
42 #include <user_attr.h>
43 #include <nss.h>
45 #define CMT_SIZE (128+1) /* Argument sizes + 1 (for '\0') */
46 #define DIR_SIZE (256+1)
47 #define SHL_SIZE (256+1)
48 #define ENTRY_LENGTH 512 /* Max length of an /etc/passwd entry */
49 #define UID_MIN 100 /* Lower bound of default UID */
51 #define M_MASK 01 /* Masks for the optn_mask variable */
52 #define L_MASK 02 /* It keeps track of which options */
53 #define C_MASK 04 /* have been entered */
54 #define H_MASK 010
55 #define U_MASK 020
56 #define G_MASK 040
57 #define S_MASK 0100
58 #define O_MASK 0200
59 #define A_MASK 0400
60 #define D_MASK 01000
61 #define F_MASK 02000
62 #define E_MASK 04000
64 #define UATTR_MASK 010000
66 /* flags for info_mask */
67 #define LOGNAME_EXIST 01 /* logname exists */
68 #define BOTH_FILES 02 /* touch both password files */
69 #define WRITE_P_ENTRY 04 /* write out password entry */
70 #define WRITE_S_ENTRY 010 /* write out shadow entry */
71 #define NEED_DEF_UID 020 /* need default uid */
72 #define FOUND 040 /* found the entry in password file */
73 #define LOCKED 0100 /* did we lock the password file */
74 #define UATTR_FILE 0200 /* touch user_attr file */
75 #define BAD_ENT_MESSAGE "%s: Bad entry found in /etc/passwd. Run pwconv.\n"
77 typedef struct kvopts {
78 const char option;
79 const char *key;
80 char *newvalue;
81 } kvopts_t;
83 /* mapping of extensible keywords and options */
84 kvopts_t ua_opts[] = {
85 { 'A', USERATTR_AUTHS_KW },
86 { 'P', USERATTR_PROFILES_KW },
87 { 'R', USERATTR_ROLES_KW },
88 { 'T', USERATTR_TYPE_KW },
89 { '\0', USERATTR_DEFAULTPROJ_KW },
90 { '\0', USERATTR_LIMPRIV_KW },
91 { '\0', USERATTR_DFLTPRIV_KW },
92 { '\0', USERATTR_LOCK_AFTER_RETRIES_KW },
93 { '\0', USERATTR_LABELVIEW },
94 { '\0', USERATTR_CLEARANCE },
95 { '\0', USERATTR_MINLABEL },
96 { '\0', USERATTR_IDLECMD_KW },
97 { '\0', USERATTR_IDLETIME_KW },
98 { '\0', USERATTR_AUDIT_FLAGS_KW },
101 #define UA_KEYS (sizeof (ua_opts)/sizeof (kvopts_t))
104 char defdir[] = "/home/"; /* default home directory for new user */
105 char pwdflr[] = "x"; /* password string for /etc/passwd */
106 char lkstring[] = "*LK*"; /* lock string for shadow password */
107 char nullstr[] = ""; /* null string */
108 char *msg; /* pointer to error message */
110 #define DATMSK "DATEMSK=/etc/datemsk"
112 #define OUSERATTR_FILENAME "/etc/ouser_attr"
113 #define USERATTR_TEMP "/etc/uatmp"
115 struct uid_blk {
116 struct uid_blk *link;
117 uid_t low; /* low bound for this uid block */
118 uid_t high; /* high bound for this uid block */
121 extern userattr_t *fgetuserattr(FILE *);
125 * Declare all functions that do not return integers. This is here
126 * to get rid of some lint messages
129 void uid_bcom(struct uid_blk *), add_ublk(uid_t, struct uid_blk *),
130 bad_perm(void),
131 bad_usage(char *), bad_arg(char *), bad_uid(void), bad_pasf(void),
132 file_error(void), bad_news(void), no_lock(void), add_uid(uid_t),
133 rid_tmpf(void), ck_p_sz(struct passwd *), ck_s_sz(struct spwd *),
134 bad_name(char *), bad_uattr(void);
136 void file_copy(FILE *spf, long NIS_pos);
138 static FILE *fp_ptemp, *fp_stemp, *fp_uatemp;
139 static int fd_ptemp, fd_stemp, fd_uatemp;
142 * The uid_blk structure is used in the search for the default
143 * uid. Each uid_blk represent a range of uid(s) that are currently
144 * used on the system.
148 #ifndef att
150 * getspnan routine that ONLY looks at the local shadow file
152 struct spwd *
153 local_getspnam(char *name)
155 FILE *shadf;
156 struct spwd *sp;
158 if ((shadf = fopen("/etc/shadow", "r")) == NULL)
159 return (NULL);
161 while ((sp = fgetspent(shadf)) != NULL) {
162 if (strcmp(sp->sp_namp, name) == 0)
163 break;
166 fclose(shadf);
168 return (sp);
170 #endif
172 static void
173 putuserattrent(userattr_t *user, FILE *f)
175 int i, j;
176 char *key;
177 char *val;
178 kv_t *kv_pair;
181 * Avoid trivial entries. Those with no attributes or with
182 * only "type=normal". This retains backward compatibility.
184 if (user->attr == NULL)
185 return;
187 kv_pair = user->attr->data;
189 for (i = j = 0; i < user->attr->length; i++) {
190 key = kv_pair[i].key;
191 val = kv_pair[i].value;
192 if ((key == NULL) || (val == NULL))
193 break;
194 if (strlen(val) == 0 ||
195 (strcmp(key, USERATTR_TYPE_KW) == 0 &&
196 strcmp(val, USERATTR_TYPE_NORMAL_KW) == 0))
197 continue;
198 j++;
200 if (j == 0)
201 return;
203 (void) fprintf(f, "%s:%s:%s:%s:", user->name, user->qualifier,
204 user->res1, user->res2);
206 for (i = j = 0; i < user->attr->length; i++) {
207 key = kv_pair[i].key;
208 val = _escape(kv_pair[i].value, KV_SPECIAL);
209 if ((key == NULL) || (val == NULL))
210 break;
211 if (strlen(val) == 0)
212 continue;
213 if (j > 0)
214 (void) fprintf(f, KV_DELIMITER);
215 (void) fprintf(f, "%s=%s", key, val);
216 j++;
218 (void) fprintf(f, "\n");
221 static void
222 assign_attr(userattr_t *user, const char *newkey, char *val)
225 int i;
226 char *key;
227 kv_t *kv_pair;
228 int avail = -1;
230 if (user->attr != NULL) {
231 kv_pair = user->attr->data;
232 for (i = 0; i < user->attr->length; i++) {
233 key = kv_pair[i].key;
234 if (key == NULL) {
235 avail = i;
236 continue;
237 } else if (strcmp(key, newkey) == 0) {
238 kv_pair[i].value = strdup(val);
239 return;
243 if (avail == -1)
244 avail = user->attr->length++;
245 kv_pair[avail].key = strdup(newkey);
246 kv_pair[avail].value = strdup(val);
250 static void
251 unassign_role(userattr_t *user, char *rolelist, char *role)
254 char *roleptr;
255 char *templist;
256 char *temprole;
257 int length;
259 roleptr = rolelist;
260 templist = strdup(roleptr);
261 temprole = strtok(templist, ",");
262 while (temprole) {
263 if (strcmp(temprole, role) == 0) {
265 length = strlen(role);
266 roleptr += temprole - templist;
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, ",");
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;
289 main(int argc, char **argv)
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;
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 */
307 * NIS start pos, really pointer to first entry AFTER first
308 * NIS-referant entry
310 long NIS_pos;
311 long cur_pos; /* Current pos, used with nis-pos above */
313 (void) setlocale(LC_ALL, "");
315 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
316 #define TEXT_DOMAIN "SYS_TEST"
317 #endif
318 (void) textdomain(TEXT_DOMAIN);
320 tzset();
321 /* Get program name */
322 prognamp = argv[0];
324 /* Check identity */
325 if (geteuid() != 0)
326 bad_perm();
328 /* Lock the password file(s) */
330 if (lckpwdf() != 0)
331 no_lock();
332 info_mask |= LOCKED; /* remember we locked */
334 /* initialize the two structures */
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 */
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 */
356 userattr_st.name = nullstr;
357 userattr_st.qualifier = nullstr;
358 userattr_st.res1 = nullstr;
359 userattr_st.res2 = nullstr;
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;
367 /* parse the command line */
369 while ((c = getopt(argc, argv,
370 "ml:c:h:u:g:s:f:e:k:A:P:R:T:oadK:")) != -1) {
372 switch (c) {
373 case 'm':
374 /* Modify */
376 if ((A_MASK|D_MASK|M_MASK) & optn_mask)
377 bad_usage("Invalid combination of options");
379 optn_mask |= M_MASK;
380 break;
382 case 'l' :
383 /* Change logname */
385 if ((A_MASK|D_MASK|L_MASK) & optn_mask)
386 bad_usage("Invalid combination of options");
388 if (strpbrk(optarg, ":\n") ||
389 strlen(optarg) == 0)
390 bad_arg("Invalid argument to option -l");
392 optn_mask |= L_MASK;
393 passwd_st.pw_name = optarg;
394 shadow_st.sp_namp = optarg;
395 userattr_st.name = optarg;
396 break;
398 case 'f' :
399 /* set inactive */
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;
413 case 'e' :
414 /* set expire date */
416 if ((D_MASK|E_MASK) & optn_mask)
417 bad_usage("Invalid combination of options");
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);
427 if ((date = mktime(tm_ptr)) < 0) {
428 msg = "Invalid argument to option -e";
429 bad_arg(msg);
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);
438 optn_mask |= E_MASK;
439 break;
441 case 'c' :
442 /* The comment */
444 if ((D_MASK|C_MASK) & optn_mask)
445 bad_usage("Invalid combination of options");
447 if (strlen(optarg) > (size_t)CMT_SIZE ||
448 strpbrk(optarg, ":\n"))
449 bad_arg("Invalid argument to option -c");
451 optn_mask |= C_MASK;
452 passwd_st.pw_comment = optarg;
453 passwd_st.pw_gecos = optarg;
454 break;
456 case 'h' :
457 /* The home directory */
459 if ((D_MASK|H_MASK) & optn_mask)
460 bad_usage("Invalid combination of options");
462 if (strlen(optarg) > (size_t)DIR_SIZE ||
463 strpbrk(optarg, ":\n"))
464 bad_arg("Invalid argument to option -h");
466 optn_mask |= H_MASK;
467 passwd_st.pw_dir = optarg;
468 break;
470 case 'u' :
471 /* The uid */
473 if ((D_MASK|U_MASK) & optn_mask)
474 bad_usage("Invalid combination of options");
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");
483 break;
485 case 'g' :
486 /* The gid */
488 if ((D_MASK|G_MASK) & optn_mask)
489 bad_usage("Invalid combination of options");
491 optn_mask |= G_MASK;
492 passwd_st.pw_gid = (gid_t)strtol(optarg, &char_p, 10);
494 if ((*char_p != '\0') || (passwd_st.pw_gid < 0) ||
495 (strlen(optarg) == 0))
496 bad_arg("Invalid argument to option -g");
497 break;
499 case 's' :
500 /* The shell */
502 if ((D_MASK|S_MASK) & optn_mask)
503 bad_usage("Invalid combination of options");
505 if (strlen(optarg) > (size_t)SHL_SIZE ||
506 strpbrk(optarg, ":\n"))
507 bad_arg("Invalid argument to option -s");
509 optn_mask |= S_MASK;
510 passwd_st.pw_shell = optarg;
511 break;
513 case 'o' :
514 /* Override unique uid */
516 if ((D_MASK|O_MASK) & optn_mask)
517 bad_usage("Invalid combination of options");
519 optn_mask |= O_MASK;
520 break;
522 case 'a' :
523 /* Add */
525 if ((A_MASK|M_MASK|D_MASK|L_MASK) & optn_mask)
526 bad_usage("Invalid combination of options");
528 optn_mask |= A_MASK;
529 break;
531 case 'd' :
532 /* Delete */
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");
539 optn_mask |= D_MASK;
540 break;
542 case 'K':
543 if (D_MASK & optn_mask)
544 bad_usage("Invalid combination of options");
546 char_p = strchr(optarg, '=');
547 if (char_p == NULL)
548 bad_usage("Missing value in -K option");
550 *char_p++ = '\0';
552 for (i = 0; i < UA_KEYS; i++) {
553 if (strcmp(optarg, ua_opts[i].key) == 0) {
554 ua_opts[i].newvalue =
555 _escape(char_p, KV_SPECIAL);
556 assign_attr(&userattr_st, optarg,
557 char_p);
558 break;
561 if (i == UA_KEYS)
562 bad_usage("bad key");
563 optn_mask |= UATTR_MASK;
564 break;
566 case '?' :
568 bad_usage("");
569 break;
571 default :
572 /* Extended User Attributes */
574 int j;
576 for (j = 0; j < UA_KEYS; j++) {
577 if (ua_opts[j].option == (char)c) {
578 if ((D_MASK) & optn_mask)
579 bad_usage("Invalid "
580 "combination of "
581 " options");
582 optn_mask |= UATTR_MASK;
583 assign_attr(&userattr_st,
584 ua_opts[j].key,
585 _escape(optarg,
586 KV_SPECIAL));
587 ua_opts[j].newvalue =
588 _escape(optarg, KV_SPECIAL);
589 break;
592 break;
597 /* check command syntax for the following errors */
598 /* too few or too many arguments */
599 /* no -a -m or -d option */
600 /* -o without -u */
601 /* -m with no other option */
603 if (optind == argc || argc > (optind+1) ||
604 !((A_MASK|M_MASK|D_MASK) & optn_mask) ||
605 ((optn_mask & O_MASK) && !(optn_mask & U_MASK)) ||
606 ((optn_mask & M_MASK) &&
607 !(optn_mask &
608 (L_MASK|C_MASK|H_MASK|U_MASK|G_MASK|S_MASK|F_MASK|
609 E_MASK|UATTR_MASK))))
610 bad_usage("Invalid command syntax");
612 /* null string argument or bad characters ? */
613 if ((strlen(argv[optind]) == 0) || strpbrk(argv[optind], ":\n"))
614 bad_arg("Invalid name");
616 lognamp = argv [optind];
619 * if we are adding a new user or modifying an existing user
620 * (not the logname), then copy logname into the two data
621 * structures
624 if ((A_MASK & optn_mask) ||
625 ((M_MASK & optn_mask) && !(optn_mask & L_MASK))) {
626 passwd_st.pw_name = argv [optind];
627 shadow_st.sp_namp = argv [optind];
628 userattr_st.name = argv [optind];
631 /* Put in directory if we are adding and we need a default */
633 if (!(optn_mask & H_MASK) && (optn_mask & A_MASK)) {
634 if ((passwd_st.pw_dir = malloc((size_t)DIR_SIZE)) == NULL)
635 file_error();
637 *passwd_st.pw_dir = '\0';
638 (void) strcat(passwd_st.pw_dir, defdir);
639 (void) strcat(passwd_st.pw_dir, lognamp);
642 /* Check the number of password files we are touching */
644 if ((!((M_MASK & optn_mask) && !(L_MASK & optn_mask))) ||
645 ((M_MASK & optn_mask) && ((E_MASK & optn_mask) ||
646 (F_MASK & optn_mask))))
647 info_mask |= BOTH_FILES;
649 if ((D_MASK|L_MASK|UATTR_MASK) & optn_mask)
650 info_mask |= UATTR_FILE;
652 /* Open the temporary file(s) with appropriate permission mask */
653 /* and the appropriate owner */
655 if (stat(PASSWD, &statbuf) < 0)
656 file_error();
658 fd_ptemp = open(PASSTEMP, O_CREAT|O_EXCL|O_WRONLY, statbuf.st_mode);
659 if (fd_ptemp == -1) {
660 if (errno == EEXIST) {
661 if (unlink(PASSTEMP)) {
662 msg = "%s: warning: cannot unlink %s\n";
663 (void) fprintf(stderr, gettext(msg), prognamp,
664 PASSTEMP);
666 fd_ptemp = open(PASSTEMP, O_CREAT|O_EXCL|O_WRONLY,
667 statbuf.st_mode);
668 if (fd_ptemp == -1) {
669 file_error();
672 } else
673 file_error();
675 fp_ptemp = fdopen(fd_ptemp, "w");
676 if (fp_ptemp == NULL)
677 file_error();
678 error = fchown(fd_ptemp, statbuf.st_uid, statbuf.st_gid);
679 if (error == 0)
680 error = fchmod(fd_ptemp, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
681 if (error != 0) {
682 (void) fclose(fp_ptemp);
683 if (unlink(PASSTEMP)) {
684 msg = "%s: warning: cannot unlink %s\n";
685 (void) fprintf(stderr, gettext(msg), prognamp,
686 PASSTEMP);
688 file_error();
691 if (info_mask & BOTH_FILES) {
692 if (stat(SHADOW, &statbuf) < 0) {
693 rid_tmpf();
694 file_error();
696 fd_stemp = open(SHADTEMP, O_CREAT|O_EXCL|O_WRONLY,
697 statbuf.st_mode);
698 if (fd_stemp == -1) {
699 if (errno == EEXIST) {
700 if (unlink(SHADTEMP)) {
701 msg = "%s: warning: cannot unlink %s\n";
702 (void) fprintf(stderr, gettext(msg),
703 prognamp, SHADTEMP);
705 fd_stemp = open(SHADTEMP,
706 O_CREAT|O_EXCL|O_WRONLY, statbuf.st_mode);
707 if (fd_stemp == -1) {
708 rid_tmpf();
709 file_error();
712 } else {
713 rid_tmpf();
714 file_error();
717 fp_stemp = fdopen(fd_stemp, "w");
718 if (fp_stemp == NULL) {
719 rid_tmpf();
720 file_error();
722 error = fchown(fd_stemp, statbuf.st_uid, statbuf.st_gid);
723 if (error == 0)
724 error = fchmod(fd_stemp, S_IRUSR);
725 if (error != 0) {
726 rid_tmpf();
727 file_error();
731 if (info_mask & UATTR_FILE) {
732 if (stat(USERATTR_FILENAME, &statbuf) < 0) {
733 rid_tmpf();
734 file_error();
736 fd_uatemp = open(USERATTR_TEMP, O_CREAT|O_EXCL|O_WRONLY,
737 statbuf.st_mode);
738 if (fd_uatemp == -1) {
739 if (errno == EEXIST) {
740 if (unlink(USERATTR_TEMP)) {
741 msg = "%s: warning: cannot unlink %s\n";
742 (void) fprintf(stderr, gettext(msg),
743 prognamp, USERATTR_TEMP);
745 fd_uatemp = open(USERATTR_TEMP,
746 O_CREAT|O_EXCL|O_WRONLY, statbuf.st_mode);
747 if (fd_uatemp == -1) {
748 rid_tmpf();
749 file_error();
752 } else {
753 rid_tmpf();
754 file_error();
757 fp_uatemp = fdopen(fd_uatemp, "w");
758 if (fp_uatemp == NULL) {
759 rid_tmpf();
760 file_error();
762 error = fchown(fd_uatemp, statbuf.st_uid, statbuf.st_gid);
763 if (error == 0)
764 error = fchmod(fd_uatemp,
765 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
766 if (error != 0) {
767 rid_tmpf();
768 file_error();
771 /* Default uid needed ? */
773 if (!(optn_mask & U_MASK) && (optn_mask & A_MASK)) {
774 /* mark it in the information mask */
775 info_mask |= NEED_DEF_UID;
777 /* create the head of the uid number list */
778 uid_sp = malloc(sizeof (struct uid_blk));
779 if (uid_sp == NULL) {
780 rid_tmpf();
781 file_error();
784 uid_sp->link = NULL;
785 uid_sp->low = (UID_MIN -1);
786 uid_sp->high = (UID_MIN -1);
790 * This next section is modified to allow for NIS passwd file
791 * conventions. In the case where a password entry was being
792 * added to the password file, the original AT&T code read
793 * the entire password file in, noted any information needed, and
794 * copied the entries to a temporary file. Then the new entry
795 * was added to the temporary file, and the temporary file was
796 * moved to be the real password file.
798 * The problem is, that with NIS compatability, we want to add new
799 * entries BEFORE the first NIS-referrant entry, so as not to have
800 * any surprises. To accomplish this without extensively modifying
801 * the logic of the code below, as soon as a NIS-referrant entry is
802 * found we stop copying entries to the TEMP file and instead we
803 * remember
804 * the first NIS entry and where we found it, scan the rest of the
805 * password file without copying entries, then write the new entry, copy
806 * the stored password entry, then copy the rest of the password file.
810 error = 0;
812 if ((pwf = fopen("/etc/passwd", "r")) == NULL) {
813 rid_tmpf();
814 if (errno == ENOENT)
815 bad_news();
816 else
817 file_error();
820 NIS_entry_seen = 0;
821 cur_pos = 0;
822 /* The while loop for reading PASSWD entries */
823 info_mask |= WRITE_P_ENTRY;
825 while (!end_of_file) {
826 pw_ptr1p = fgetpwent(pwf);
827 if (pw_ptr1p == NULL) {
828 if (!feof(pwf)) {
829 /* A real error - report it and exit */
830 rid_tmpf();
831 bad_pasf();
833 else
834 break;
837 if (!NIS_entry_seen)
838 info_mask |= WRITE_P_ENTRY;
839 else
840 info_mask &= ~WRITE_P_ENTRY;
843 * Set up the uid usage blocks to find the first
844 * available uid above UID_MIN, if needed
847 if (info_mask & NEED_DEF_UID)
848 add_uid(pw_ptr1p->pw_uid);
850 /* Check for unique UID */
852 if (strcmp(lognamp, pw_ptr1p->pw_name) &&
853 (pw_ptr1p->pw_uid == passwd_st.pw_uid) &&
854 ((optn_mask & U_MASK) && !(optn_mask & O_MASK))) {
855 rid_tmpf(); /* get rid of temp files */
856 bad_uid();
859 /* Check for unique new logname */
861 if (strcmp(lognamp, pw_ptr1p->pw_name) == 0 &&
862 optn_mask & L_MASK &&
863 strcmp(pw_ptr1p->pw_name, passwd_st.pw_name) == 0) {
864 rid_tmpf();
865 #ifdef att
866 if (!getspnam(pw_ptr1p->pw_name))
867 #else
868 if (!local_getspnam(pw_ptr1p->pw_name))
869 #endif
870 bad_pasf();
871 else
872 bad_name("logname already exists");
875 if (strcmp(lognamp, pw_ptr1p->pw_name) == 0) {
877 /* no good if we want to add an existing logname */
878 if (optn_mask & A_MASK) {
879 rid_tmpf();
880 #ifdef att
881 if (!getspnam(lognamp))
882 #else
883 if (!local_getspnam(lognamp))
884 #endif
885 bad_pasf();
886 else
887 bad_name("name already exists");
890 /* remember we found it */
891 info_mask |= FOUND;
893 /* Do not write it out on the fly */
894 if (optn_mask & D_MASK)
895 info_mask &= ~WRITE_P_ENTRY;
897 if (optn_mask & M_MASK) {
899 #ifdef att
900 if (!getspnam(lognamp))
901 #else
902 if (!local_getspnam(lognamp))
903 #endif
905 rid_tmpf();
906 bad_pasf();
908 if (optn_mask & L_MASK)
909 pw_ptr1p->pw_name = passwd_st.pw_name;
911 if (optn_mask & U_MASK)
912 pw_ptr1p->pw_uid = passwd_st.pw_uid;
914 if (optn_mask & G_MASK)
915 pw_ptr1p->pw_gid = passwd_st.pw_gid;
917 if (optn_mask & C_MASK) {
918 pw_ptr1p->pw_comment =
919 passwd_st.pw_comment;
921 pw_ptr1p->pw_gecos =
922 passwd_st.pw_comment;
925 if (optn_mask & H_MASK)
926 pw_ptr1p->pw_dir = passwd_st.pw_dir;
928 if (optn_mask & S_MASK)
929 pw_ptr1p->pw_shell = passwd_st.pw_shell;
930 ck_p_sz(pw_ptr1p); /* check entry size */
934 if (optn_mask & A_MASK) {
935 if (!NIS_entry_seen) {
936 char *p;
937 p = strchr("+-", pw_ptr1p->pw_name[0]);
938 if (p != NULL) {
940 * Found first NIS entry.
941 * so remember it.
943 NIS_pos = cur_pos;
944 NIS_entry_seen = 1;
945 info_mask &= ~WRITE_P_ENTRY;
947 else
948 cur_pos = ftell(pwf);
952 if (info_mask & WRITE_P_ENTRY) {
953 if (putpwent(pw_ptr1p, fp_ptemp)) {
954 rid_tmpf();
955 file_error();
958 } /* end-of-while-loop */
960 if (error >= 1) {
961 msg = "%s: Bad entry found in /etc/passwd. Run pwconv.\n";
962 fprintf(stderr, gettext(msg), prognamp);
965 /* Cannot find the target entry and we are deleting or modifying */
967 if (!(info_mask & FOUND) && (optn_mask & (D_MASK|M_MASK))) {
968 rid_tmpf();
969 #ifdef att
970 if (getspnam(lognamp) != NULL)
971 #else
972 if (local_getspnam(lognamp) != NULL)
973 #endif
974 bad_pasf();
975 else
976 bad_name("name does not exist");
979 /* First available uid above UID_MIN is ... */
981 if (info_mask & NEED_DEF_UID)
982 passwd_st.pw_uid = uid_sp->high + 1;
984 /* Write out the added entry now */
986 if (optn_mask & A_MASK) {
987 ck_p_sz(&passwd_st); /* Check entry size */
988 if (putpwent(&passwd_st, fp_ptemp)) {
989 rid_tmpf();
990 file_error();
993 * Now put out the rest of the password file, if needed.
995 if (NIS_entry_seen) {
996 int n;
997 char buf[1024];
999 if (fseek(pwf, NIS_pos, SEEK_SET) < 0) {
1000 rid_tmpf();
1001 file_error();
1003 while ((n = fread(buf, sizeof (char), 1024, pwf)) > 0) {
1004 if (fwrite(buf, sizeof (char), n, fp_ptemp)
1005 != n) {
1006 rid_tmpf();
1007 file_error();
1013 (void) fclose(pwf);
1015 /* flush and sync the file before closing it */
1016 if (fflush(fp_ptemp) != 0 || fsync(fd_ptemp) != 0)
1017 file_error();
1019 /* Now we are done with PASSWD */
1020 (void) fclose(fp_ptemp);
1022 /* Do this if we are touching both password files */
1025 if (info_mask & BOTH_FILES) {
1026 info_mask &= ~FOUND; /* Reset FOUND flag */
1028 /* The while loop for reading SHADOW entries */
1029 info_mask |= WRITE_S_ENTRY;
1031 end_of_file = 0;
1032 errno = 0;
1033 error = 0;
1035 NIS_entry_seen = 0;
1036 cur_pos = 0;
1038 if ((spf = fopen("/etc/shadow", "r")) == NULL) {
1039 rid_tmpf();
1040 file_error();
1043 while (!end_of_file) {
1044 sp_ptr1p = fgetspent(spf);
1045 if (sp_ptr1p == NULL) {
1046 if (!feof(spf)) {
1047 rid_tmpf();
1048 bad_pasf();
1050 else
1051 break;
1054 if (!NIS_entry_seen)
1055 info_mask |= WRITE_S_ENTRY;
1056 else
1057 info_mask &= ~WRITE_S_ENTRY;
1060 * See if the new logname already exist in the
1061 * shadow passwd file
1063 if ((optn_mask & M_MASK) &&
1064 strcmp(lognamp, shadow_st.sp_namp) != 0 &&
1065 strcmp(sp_ptr1p->sp_namp, shadow_st.sp_namp) == 0) {
1066 rid_tmpf();
1067 bad_pasf();
1070 if (strcmp(lognamp, sp_ptr1p->sp_namp) == 0) {
1071 info_mask |= FOUND;
1072 if (optn_mask & A_MASK) {
1073 /* password file inconsistent */
1074 rid_tmpf();
1075 bad_pasf();
1078 if (optn_mask & M_MASK) {
1079 sp_ptr1p->sp_namp = shadow_st.sp_namp;
1080 if (F_MASK & optn_mask)
1081 sp_ptr1p->sp_inact =
1082 shadow_st.sp_inact;
1083 if (E_MASK & optn_mask)
1084 sp_ptr1p->sp_expire =
1085 shadow_st.sp_expire;
1087 ck_s_sz(sp_ptr1p);
1090 if (optn_mask & D_MASK)
1091 info_mask &= ~WRITE_S_ENTRY;
1094 if (optn_mask & A_MASK) {
1095 if (!NIS_entry_seen) {
1096 char *p;
1097 p = strchr("+-", sp_ptr1p->sp_namp[0]);
1098 if (p != NULL) {
1100 * Found first NIS entry.
1101 * so remember it.
1103 NIS_pos = cur_pos;
1104 NIS_entry_seen = 1;
1105 info_mask &= ~WRITE_S_ENTRY;
1107 else
1108 cur_pos = ftell(spf);
1112 if (info_mask & WRITE_S_ENTRY) {
1113 if (putspent(sp_ptr1p, fp_stemp)) {
1114 rid_tmpf();
1115 file_error();
1119 } /* end-of-while-loop */
1121 if (error >= 1) {
1123 msg = BAD_ENT_MESSAGE;
1124 fprintf(stderr, gettext(msg), prognamp);
1128 * If we cannot find the entry and we are deleting or
1129 * modifying
1132 if (!(info_mask & FOUND) && (optn_mask & (D_MASK|M_MASK))) {
1133 rid_tmpf();
1134 bad_pasf();
1137 if (optn_mask & A_MASK) {
1138 ck_s_sz(&shadow_st);
1139 if (putspent(&shadow_st, fp_stemp)) {
1140 rid_tmpf();
1141 file_error();
1145 * Now put out the rest of the shadow file, if needed.
1147 if (NIS_entry_seen) {
1148 file_copy(spf, NIS_pos);
1152 /* flush and sync the file before closing it */
1153 if (fflush(fp_stemp) != 0 || fsync(fd_stemp) != 0)
1154 file_error();
1155 (void) fclose(fp_stemp);
1157 /* Done with SHADOW */
1158 (void) fclose(spf);
1160 } /* End of if info_mask */
1162 if (info_mask & UATTR_FILE) {
1163 info_mask &= ~FOUND; /* Reset FOUND flag */
1165 /* The while loop for reading USER_ATTR entries */
1166 info_mask |= WRITE_S_ENTRY;
1168 end_of_file = 0;
1169 errno = 0;
1170 error = 0;
1172 NIS_entry_seen = 0;
1173 cur_pos = 0;
1175 if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
1176 rid_tmpf();
1177 file_error();
1180 while (!end_of_file) {
1181 ua_ptr1p = fgetuserattr(uaf);
1182 if (ua_ptr1p == NULL) {
1183 if (!feof(uaf)) {
1184 rid_tmpf();
1185 bad_uattr();
1187 else
1188 break;
1191 if (ua_ptr1p->name[0] == '#') {
1193 * If this is a comment, write it back as it
1194 * is.
1196 if (ua_ptr1p->qualifier[0] == '\0' &&
1197 ua_ptr1p->res1[0] == '\0' &&
1198 ua_ptr1p->res2[0] == '\0' &&
1199 (ua_ptr1p->attr == NULL ||
1200 ua_ptr1p->attr->length == 0))
1201 (void) fprintf(fp_uatemp, "%s\n",
1202 ua_ptr1p->name);
1203 else
1205 * This is a commented user_attr entry;
1206 * reformat it, and write it back.
1208 putuserattrent(ua_ptr1p, fp_uatemp);
1209 free_userattr(ua_ptr1p);
1210 continue;
1213 if (!NIS_entry_seen)
1214 info_mask |= WRITE_S_ENTRY;
1215 else
1216 info_mask &= ~WRITE_S_ENTRY;
1219 * See if the new logname already exist in the
1220 * user_attr file
1222 if ((optn_mask & M_MASK) &&
1223 strcmp(lognamp, userattr_st.name) != 0 &&
1224 strcmp(ua_ptr1p->name, userattr_st.name) == 0) {
1225 rid_tmpf();
1226 bad_pasf();
1229 if (strcmp(lognamp, ua_ptr1p->name) == 0) {
1230 info_mask |= FOUND;
1231 if (optn_mask & A_MASK) {
1232 /* password file inconsistent */
1233 rid_tmpf();
1234 bad_pasf();
1237 if (optn_mask & M_MASK) {
1238 int j;
1239 char *value;
1241 for (j = 0; j < UA_KEYS; j++) {
1242 if (ua_opts[j].newvalue != NULL)
1243 continue;
1244 value =
1245 kva_match(ua_ptr1p->attr,
1246 (char *)ua_opts[j].key);
1247 if (value == NULL)
1248 continue;
1249 assign_attr(&userattr_st,
1250 ua_opts[j].key,
1251 value);
1253 free_userattr(ua_ptr1p);
1254 ua_ptr1p = &userattr_st;
1257 if (optn_mask & D_MASK)
1258 info_mask &= ~WRITE_S_ENTRY;
1259 } else if (optn_mask & D_MASK) {
1260 char *rolelist;
1262 rolelist = kva_match(ua_ptr1p->attr,
1263 USERATTR_ROLES_KW);
1264 if (rolelist) {
1265 unassign_role(ua_ptr1p,
1266 rolelist, lognamp);
1270 if (info_mask & WRITE_S_ENTRY) {
1271 putuserattrent(ua_ptr1p, fp_uatemp);
1274 if (!(optn_mask & M_MASK))
1275 free_userattr(ua_ptr1p);
1276 } /* end-of-while-loop */
1278 if (error >= 1) {
1280 msg = BAD_ENT_MESSAGE;
1281 fprintf(stderr, gettext(msg), prognamp);
1285 * Add entry in user_attr if masks is UATTR_MASK
1286 * We don't need to do anything for L_MASK if there's
1287 * no user_attr entry for the user being modified.
1289 if (!(info_mask & FOUND) && !(L_MASK & optn_mask) &&
1290 !(D_MASK & optn_mask)) {
1291 putuserattrent(&userattr_st, fp_uatemp);
1294 /* flush and sync the file before closing it */
1295 if (fflush(fp_uatemp) != 0 || fsync(fd_uatemp) != 0)
1296 file_error();
1297 (void) fclose(fp_uatemp);
1299 /* Done with USERATTR */
1300 (void) fclose(uaf);
1302 } /* End of if info_mask */
1303 /* ignore all signals */
1305 for (i = 1; i < NSIG; i++)
1306 (void) sigset(i, SIG_IGN);
1308 errno = 0; /* For correcting sigset to SIGKILL */
1310 if (unlink(OPASSWD) && access(OPASSWD, 0) == 0)
1311 file_error();
1313 if (link(PASSWD, OPASSWD) == -1)
1314 file_error();
1317 if (rename(PASSTEMP, PASSWD) == -1) {
1318 if (link(OPASSWD, PASSWD))
1319 bad_news();
1320 file_error();
1324 if (info_mask & BOTH_FILES) {
1326 if (unlink(OSHADOW) && access(OSHADOW, 0) == 0) {
1327 if (rec_pwd())
1328 bad_news();
1329 else
1330 file_error();
1333 if (link(SHADOW, OSHADOW) == -1) {
1334 if (rec_pwd())
1335 bad_news();
1336 else
1337 file_error();
1341 if (rename(SHADTEMP, SHADOW) == -1) {
1342 if (rename(OSHADOW, SHADOW) == -1)
1343 bad_news();
1345 if (rec_pwd())
1346 bad_news();
1347 else
1348 file_error();
1352 if (info_mask & UATTR_FILE) {
1353 if (unlink(OUSERATTR_FILENAME) &&
1354 access(OUSERATTR_FILENAME, 0) == 0) {
1355 if (rec_pwd())
1356 bad_news();
1357 else
1358 file_error();
1361 if (link(USERATTR_FILENAME, OUSERATTR_FILENAME) == -1) {
1362 if (rec_pwd())
1363 bad_news();
1364 else
1365 file_error();
1369 if (rename(USERATTR_TEMP, USERATTR_FILENAME) == -1) {
1370 if (rename(OUSERATTR_FILENAME, USERATTR_FILENAME) == -1)
1371 bad_news();
1373 if (rec_pwd())
1374 bad_news();
1375 else
1376 file_error();
1381 ulckpwdf();
1384 * Return 0 status, indicating success
1386 return (0);
1388 } /* end of main */
1390 /* Try to recover the old password file */
1393 rec_pwd(void)
1395 if (unlink(PASSWD) || link(OPASSWD, PASSWD))
1396 return (-1);
1398 return (0);
1401 /* combine two uid_blk's */
1403 void
1404 uid_bcom(struct uid_blk *uid_p)
1406 struct uid_blk *uid_tp;
1408 uid_tp = uid_p->link;
1409 uid_p->high = uid_tp->high;
1410 uid_p->link = uid_tp->link;
1412 free(uid_tp);
1415 /* add a new uid_blk */
1417 void
1418 add_ublk(uid_t num, struct uid_blk *uid_p)
1420 struct uid_blk *uid_tp;
1422 uid_tp = malloc(sizeof (struct uid_blk));
1423 if (uid_tp == NULL) {
1424 rid_tmpf();
1425 file_error();
1428 uid_tp->high = uid_tp->low = num;
1429 uid_tp->link = uid_p->link;
1430 uid_p->link = uid_tp;
1434 * Here we are using a linked list of uid_blk to keep track of all
1435 * the used uids. Each uid_blk represents a range of used uid,
1436 * with low represents the low inclusive end and high represents
1437 * the high inclusive end. In the beginning, we initialize a linked
1438 * list of one uid_blk with low = high = (UID_MIN-1). This was
1439 * done in main().
1440 * Each time we read in another used uid, we add it onto the linked
1441 * list by either making a new uid_blk, decrementing the low of
1442 * an existing uid_blk, incrementing the high of an existing
1443 * uid_blk, or combining two existing uid_blks. After we finished
1444 * building this linked list, the first available uid above or
1445 * equal to UID_MIN is the high of the first uid_blk in the linked
1446 * list + 1.
1448 /* add_uid() adds uid to the link list of used uids */
1449 void
1450 add_uid(uid_t uid)
1452 struct uid_blk *uid_p;
1453 /* Only keep track of the ones above UID_MIN */
1455 if (uid >= UID_MIN) {
1456 uid_p = uid_sp;
1458 while (uid_p != NULL) {
1460 if (uid_p->link != NULL) {
1462 if (uid >= uid_p->link->low)
1463 uid_p = uid_p->link;
1465 else if (uid >= uid_p->low &&
1466 uid <= uid_p->high) {
1467 uid_p = NULL;
1470 else if (uid == (uid_p->high+1)) {
1472 if (++uid_p->high ==
1473 (uid_p->link->low - 1)) {
1474 uid_bcom(uid_p);
1476 uid_p = NULL;
1479 else if (uid == (uid_p->link->low - 1)) {
1480 uid_p->link->low --;
1481 uid_p = NULL;
1484 else if (uid < uid_p->link->low) {
1485 add_ublk(uid, uid_p);
1486 uid_p = NULL;
1488 } /* if uid_p->link */
1490 else {
1492 if (uid == (uid_p->high + 1)) {
1493 uid_p->high++;
1494 uid_p = NULL;
1495 } else if (uid >= uid_p->low &&
1496 uid <= uid_p->high) {
1497 uid_p = NULL;
1498 } else {
1499 add_ublk(uid, uid_p);
1500 uid_p = NULL;
1502 } /* else */
1503 } /* while uid_p */
1505 } /* if uid */
1508 void
1509 bad_perm(void)
1511 (void) fprintf(stderr, gettext("%s: Permission denied\n"), prognamp);
1512 exit(1);
1515 void
1516 bad_usage(char *sp)
1518 if (strlen(sp) != 0)
1519 (void) fprintf(stderr, "%s: %s\n", prognamp, gettext(sp));
1520 (void) fprintf(stderr, gettext("Usage:\n\
1521 %s -a [-c comment] [-h homedir] [-u uid [-o]] [-g gid] \n\
1522 [-s shell] [-f inactive] [-e expire] name\n\
1523 %s -m -c comment | -h homedir | -u uid [-o] | -g gid |\n\
1524 -s shell | -f inactive | -e expire | -l logname name\n\
1525 %s -d name\n"), prognamp, prognamp, prognamp);
1526 if (info_mask & LOCKED)
1527 ulckpwdf();
1528 exit(2);
1531 void
1532 bad_arg(char *s)
1534 (void) fprintf(stderr, "%s: %s\n", prognamp, gettext(s));
1536 if (info_mask & LOCKED)
1537 ulckpwdf();
1538 exit(3);
1541 void
1542 bad_name(char *s)
1544 (void) fprintf(stderr, "%s: %s\n", prognamp, gettext(s));
1545 ulckpwdf();
1546 exit(9);
1549 void
1550 bad_uid(void)
1552 (void) fprintf(stderr, gettext("%s: UID in use\n"), prognamp);
1554 ulckpwdf();
1555 exit(4);
1558 void
1559 bad_pasf(void)
1561 msg = "%s: Inconsistent password files\n";
1562 (void) fprintf(stderr, gettext(msg), prognamp);
1564 ulckpwdf();
1565 exit(5);
1568 void
1569 bad_uattr(void)
1571 msg = "%s: Bad user_attr database\n";
1572 (void) fprintf(stderr, gettext(msg), prognamp);
1574 ulckpwdf();
1575 exit(5);
1578 void
1579 file_error(void)
1581 msg = "%s: Unexpected failure. Password files unchanged\n";
1582 (void) fprintf(stderr, gettext(msg), prognamp);
1584 ulckpwdf();
1585 exit(6);
1588 void
1589 bad_news(void)
1591 msg = "%s: Unexpected failure. Password file(s) missing\n";
1592 (void) fprintf(stderr, gettext(msg), prognamp);
1594 ulckpwdf();
1595 exit(7);
1598 void
1599 no_lock(void)
1601 msg = "%s: Password file(s) busy. Try again later\n";
1602 (void) fprintf(stderr, gettext(msg), prognamp);
1604 exit(8);
1607 /* Check for the size of the whole passwd entry */
1608 void
1609 ck_p_sz(struct passwd *pwp)
1611 char ctp[128];
1613 /* Ensure that the combined length of the individual */
1614 /* fields will fit in a passwd entry. The 1 accounts for the */
1615 /* newline and the 6 accounts for the colons (:'s) */
1616 if (((int)strlen(pwp->pw_name) + 1 +
1617 sprintf(ctp, "%d", pwp->pw_uid) +
1618 sprintf(ctp, "%d", pwp->pw_gid) +
1619 (int)strlen(pwp->pw_comment) +
1620 (int)strlen(pwp->pw_dir) +
1621 (int)strlen(pwp->pw_shell) + 6) > (ENTRY_LENGTH-1)) {
1622 rid_tmpf();
1623 bad_arg("New password entry too long");
1627 /* Check for the size of the whole passwd entry */
1628 void
1629 ck_s_sz(struct spwd *ssp)
1631 char ctp[128];
1633 /* Ensure that the combined length of the individual */
1634 /* fields will fit in a shadow entry. The 1 accounts for the */
1635 /* newline and the 7 accounts for the colons (:'s) */
1636 if (((int)strlen(ssp->sp_namp) + 1 +
1637 (int)strlen(ssp->sp_pwdp) +
1638 sprintf(ctp, "%d", ssp->sp_lstchg) +
1639 sprintf(ctp, "%d", ssp->sp_min) +
1640 sprintf(ctp, "%d", ssp->sp_max) +
1641 sprintf(ctp, "%d", ssp->sp_warn) +
1642 sprintf(ctp, "%d", ssp->sp_inact) +
1643 sprintf(ctp, "%d", ssp->sp_expire) + 7) > (ENTRY_LENGTH - 1)) {
1644 rid_tmpf();
1645 bad_arg("New password entry too long");
1649 /* Get rid of the temp files */
1650 void
1651 rid_tmpf(void)
1653 (void) fclose(fp_ptemp);
1655 if (unlink(PASSTEMP)) {
1656 msg = "%s: warning: cannot unlink %s\n";
1657 (void) fprintf(stderr, gettext(msg), prognamp, PASSTEMP);
1660 if (info_mask & BOTH_FILES) {
1661 (void) fclose(fp_stemp);
1663 if (unlink(SHADTEMP)) {
1664 msg = "%s: warning: cannot unlink %s\n";
1665 (void) fprintf(stderr, gettext(msg), prognamp,
1666 SHADTEMP);
1670 if (info_mask & UATTR_FILE) {
1671 (void) fclose(fp_uatemp);
1673 if (unlink(USERATTR_TEMP)) {
1674 msg = "%s: warning: cannot unlink %s\n";
1675 (void) fprintf(stderr, gettext(msg), prognamp,
1676 USERATTR_TEMP);
1681 void
1682 file_copy(FILE *spf, long NIS_pos)
1684 int n;
1685 char buf[1024];
1687 if (fseek(spf, NIS_pos, SEEK_SET) < 0) {
1688 rid_tmpf();
1689 file_error();
1691 while ((n = fread(buf, sizeof (char), 1024, spf)) > 0) {
1692 if (fwrite(buf, sizeof (char), n, fp_stemp) != n) {
1693 rid_tmpf();
1694 file_error();