Add spl's around queue manipulation
[unix-history] / usr / src / usr.bin / passwd / passwd.c
CommitLineData
252e456d 1#ifndef lint
9ae20471 2static char sccsid[] = "@(#)passwd.c 4.6 (Berkeley) %G%";
252e456d
SL
3#endif
4
5/*
9a59f452
SL
6 * Enter a password in the password file.
7 * This program should be suid with an owner
8 * with write permission on /etc/passwd.
252e456d
SL
9 */
10#include <sys/file.h>
11
12#include <stdio.h>
13#include <signal.h>
14#include <pwd.h>
9ae20471 15#include <ndbm.h>
252e456d
SL
16#include <errno.h>
17
8d3b95af 18char temp[] = "/etc/ptmp";
252e456d 19char passwd[] = "/etc/passwd";
252e456d 20struct passwd *pwd;
252e456d
SL
21char *strcpy();
22char *crypt();
23char *getpass();
24char *getlogin();
25char *pw;
26char pwbuf[10];
27extern int errno;
28
29main(argc, argv)
30 char *argv[];
31{
32 char *p;
33 int i;
34 char saltc[2];
35 long salt;
36 int u;
37 int insist;
38 int ok, flags;
39 int c, pwlen, fd;
40 FILE *tf;
41 char *uname;
9ae20471 42 DBM *dp;
252e456d
SL
43
44 insist = 0;
45 if (argc < 2) {
46 if ((uname = getlogin()) == NULL) {
47 printf ("Usage: passwd user\n");
48 exit(1);
49 }
50 printf("Changing password for %s\n", uname);
51 } else
52 uname = argv[1];
8d3b95af 53 pwd = getpwnam(uname);
252e456d
SL
54 u = getuid();
55 if (pwd == NULL || (u != 0 && u != pwd->pw_uid)) {
56 printf("Permission denied.\n");
57 exit(1);
58 }
252e456d
SL
59 if (pwd->pw_passwd[0] && u != 0) {
60 strcpy(pwbuf, getpass("Old password:"));
61 pw = crypt(pwbuf, pwd->pw_passwd);
62 if (strcmp(pw, pwd->pw_passwd) != 0) {
63 printf("Sorry.\n");
64 exit(1);
65 }
66 }
67tryagain:
68 strcpy(pwbuf, getpass("New password:"));
69 pwlen = strlen(pwbuf);
70 if (pwlen == 0) {
71 printf("Password unchanged.\n");
72 exit(1);
73 }
74 /*
75 * Insure password is of reasonable length and
76 * composition. If we really wanted to make things
77 * sticky, we could check the dictionary for common
78 * words, but then things would really be slow.
79 */
80 ok = 0;
81 flags = 0;
82 p = pwbuf;
83 while (c = *p++) {
84 if (c >= 'a' && c <= 'z')
85 flags |= 2;
86 else if (c >= 'A' && c <= 'Z')
87 flags |= 4;
88 else if (c >= '0' && c <= '9')
89 flags |= 1;
90 else
91 flags |= 8;
92 }
93 if (flags >= 7 && pwlen >= 4)
94 ok = 1;
95 if ((flags == 2 || flags == 4) && pwlen >= 6)
96 ok = 1;
97 if ((flags == 3 || flags == 5 || flags == 6) && pwlen >= 5)
98 ok = 1;
99 if (!ok && insist < 2) {
252e456d
SL
100 printf("Please use %s.\n", flags == 1 ?
101 "at least one non-numeric character" :
102 "a longer password");
103 insist++;
104 goto tryagain;
105 }
106 if (strcmp(pwbuf, getpass("Retype new password:")) != 0) {
107 printf("Mismatch - password unchanged.\n");
108 exit(1);
109 }
110 time(&salt);
111 salt = 9 * getpid();
112 saltc[0] = salt & 077;
113 saltc[1] = (salt>>6) & 077;
114 for (i = 0; i < 2; i++) {
115 c = saltc[i] + '.';
116 if (c > '9')
117 c += 7;
118 if (c > 'Z')
119 c += 6;
120 saltc[i] = c;
121 }
122 pw = crypt(pwbuf, saltc);
123 signal(SIGHUP, SIG_IGN);
124 signal(SIGINT, SIG_IGN);
125 signal(SIGQUIT, SIG_IGN);
643bb829 126 (void) umask(0);
9a59f452 127 fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644);
252e456d
SL
128 if (fd < 0) {
129 fprintf(stderr, "passwd: ");
9a59f452 130 if (errno == EEXIST)
252e456d
SL
131 fprintf(stderr, "password file busy - try again.\n");
132 else
133 perror(temp);
134 exit(1);
135 }
136 signal(SIGTSTP, SIG_IGN);
137 if ((tf = fdopen(fd, "w")) == NULL) {
138 fprintf(stderr, "passwd: fdopen failed?\n");
139 exit(1);
140 }
9ae20471
RC
141 if ((dp = ndbmopen(passwd, O_RDWR, 0644)) == NULL) {
142 fprintf(stderr, "Warning: dbminit failed: ");
143 perror(passwd);
144 } else if (flock(dp->db_dirf, LOCK_EX) < 0) {
145 perror("Warning: lock failed");
146 ndbmclose(dp);
147 dp = NULL;
148 }
252e456d
SL
149 /*
150 * Copy passwd to temp, replacing matching lines
151 * with new password.
152 */
153 while ((pwd = getpwent()) != NULL) {
8d3b95af 154 if (strcmp(pwd->pw_name, uname) == 0) {
252e456d
SL
155 if (u && u != pwd->pw_uid) {
156 fprintf(stderr, "passwd: permission denied.\n");
8d3b95af 157 goto out;
252e456d
SL
158 }
159 pwd->pw_passwd = pw;
160 if (pwd->pw_gecos[0] == '*')
161 pwd->pw_gecos++;
9ae20471 162 replace(dp, pwd);
252e456d
SL
163 }
164 fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
165 pwd->pw_name,
166 pwd->pw_passwd,
167 pwd->pw_uid,
168 pwd->pw_gid,
169 pwd->pw_gecos,
170 pwd->pw_dir,
171 pwd->pw_shell);
172 }
173 endpwent();
9ae20471
RC
174 (void) fclose(tf);
175 ndbmclose(dp);
176 if (rename(temp, passwd) < 0) {
8d3b95af 177 fprintf(stderr, "passwd: "), perror("rename");
9ae20471
RC
178 out:
179 unlink(temp);
180 exit(1);
181 }
182 exit(0);
8d3b95af
RC
183}
184
9ae20471
RC
185/*
186 * Replace the password entry in the dbm data base with pwd.
187 */
188replace(dp, pwd)
189 DBM *dp;
190 struct passwd *pwd;
8d3b95af 191{
9ae20471
RC
192 datum key, content;
193 register char *cp, *tp;
194 char buf[BUFSIZ];
8d3b95af 195
9ae20471
RC
196 if (dp == NULL)
197 return;
198
199 cp = buf;
200#define COMPACT(e) tp = pwd->pw_/**/e; while (*cp++ = *tp++);
201 COMPACT(name);
202 COMPACT(passwd);
203 *(int *)cp = pwd->pw_uid; cp += sizeof (int);
204 *(int *)cp = pwd->pw_gid; cp += sizeof (int);
205 *(int *)cp = pwd->pw_quota; cp += sizeof (int);
206 COMPACT(comment);
207 COMPACT(gecos);
208 COMPACT(dir);
209 COMPACT(shell);
210 content.dptr = buf;
211 content.dsize = cp - buf;
212 key.dptr = pwd->pw_name;
213 key.dsize = strlen(pwd->pw_name);
214 dbmstore(dp, key, content, DB_REPLACE);
215 key.dptr = (char *)&pwd->pw_uid;
216 key.dsize = sizeof (int);
217 dbmstore(dp, key, content, DB_REPLACE);
252e456d 218}