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