1 /*-
2  * Copyright (c) 1990, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)local_passwd.c	8.3 (Berkeley) 04/02/94";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 
14 #include <ctype.h>
15 #include <err.h>
16 #include <errno.h>
17 #include <pwd.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include <unistd.h>
23 
24 #include <pw_copy.h>
25 #include <pw_util.h>
26 
27 #include "extern.h"
28 
29 static uid_t uid;
30 
31 char   *tempname;
32 
33 static unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
34 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
35 
36 void
37 to64(s, v, n)
38 	char *s;
39 	long v;
40 	int n;
41 {
42 	while (--n >= 0) {
43 		*s++ = itoa64[v&0x3f];
44 		v >>= 6;
45 	}
46 }
47 
48 char *
49 getnewpasswd(pw)
50 	struct passwd *pw;
51 {
52 	int tries;
53 	char *p, *t;
54 	char buf[_PASSWORD_LEN+1], salt[9];
55 
56 	(void)printf("Changing local password for %s.\n", pw->pw_name);
57 
58 	if (uid && pw->pw_passwd[0] &&
59 	    strcmp(crypt(getpass("Old password:"), pw->pw_passwd),
60 	    pw->pw_passwd)) {
61 		errno = EACCES;
62 		pw_error(NULL, 1, 1);
63 	}
64 
65 	for (buf[0] = '\0', tries = 0;;) {
66 		p = getpass("New password:");
67 		if (!*p) {
68 			(void)printf("Password unchanged.\n");
69 			pw_error(NULL, 0, 0);
70 		}
71 		if (strlen(p) <= 5 && (uid != 0 || ++tries < 2)) {
72 			(void)printf("Please enter a longer password.\n");
73 			continue;
74 		}
75 		for (t = p; *t && islower(*t); ++t);
76 		if (!*t && (uid != 0 || ++tries < 2)) {
77 			(void)printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n");
78 			continue;
79 		}
80 		(void)strcpy(buf, p);
81 		if (!strcmp(buf, getpass("Retype new password:")))
82 			break;
83 		(void)printf("Mismatch; try again, EOF to quit.\n");
84 	}
85 	/* grab a random printable character that isn't a colon */
86 	(void)srandom((int)time((time_t *)NULL));
87 #ifdef NEWSALT
88 	salt[0] = _PASSWORD_EFMT1;
89 	to64(&salt[1], (long)(29 * 25), 4);
90 	to64(&salt[5], random(), 4);
91 #else
92 	to64(&salt[0], random(), 2);
93 #endif
94 	return (crypt(buf, salt));
95 }
96 
97 int
98 local_passwd(uname)
99 	char *uname;
100 {
101 	struct passwd *pw;
102 	int pfd, tfd;
103 
104 	if (!(pw = getpwnam(uname)))
105 		errx(1, "unknown user %s", uname);
106 
107 	uid = getuid();
108 	if (uid && uid != pw->pw_uid)
109 		errx(1, "%s", strerror(EACCES));
110 
111 	pw_init();
112 	pfd = pw_lock();
113 	tfd = pw_tmp();
114 
115 	/*
116 	 * Get the new password.  Reset passwd change time to zero; when
117 	 * classes are implemented, go and get the "offset" value for this
118 	 * class and reset the timer.
119 	 */
120 	pw->pw_passwd = getnewpasswd(pw);
121 	pw->pw_change = 0;
122 	pw_copy(pfd, tfd, pw);
123 
124 	if (!pw_mkdb())
125 		pw_error((char *)NULL, 0, 1);
126 	return (0);
127 }
128