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