from sun
[unix-history] / usr / src / usr.bin / passwd / passwd.c
CommitLineData
252e456d
SL
1#ifndef lint
2static char sccsid[] = "@(#)passwd.c 4.1 (Berkeley) %G%";
3#endif
4
5/*
6 * enter a password in the password file
7 * this program should be suid with owner
8 * with an owner with write permission on /etc/passwd
9 */
10#include <sys/file.h>
11
12#include <stdio.h>
13#include <signal.h>
14#include <pwd.h>
15#include <errno.h>
16
17char passwd[] = "/etc/passwd";
18char temp[] = "/etc/ptmp";
19struct passwd *pwd;
20struct passwd *getpwent();
21int endpwent();
22char *strcpy();
23char *crypt();
24char *getpass();
25char *getlogin();
26char *pw;
27char pwbuf[10];
28extern int errno;
29
30main(argc, argv)
31 char *argv[];
32{
33 char *p;
34 int i;
35 char saltc[2];
36 long salt;
37 int u;
38 int insist;
39 int ok, flags;
40 int c, pwlen, fd;
41 FILE *tf;
42 char *uname;
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];
53 while (((pwd = getpwent()) != NULL) && strcmp(pwd->pw_name, uname))
54 ;
55 u = getuid();
56 if (pwd == NULL || (u != 0 && u != pwd->pw_uid)) {
57 printf("Permission denied.\n");
58 exit(1);
59 }
60 endpwent();
61 if (pwd->pw_passwd[0] && u != 0) {
62 strcpy(pwbuf, getpass("Old password:"));
63 pw = crypt(pwbuf, pwd->pw_passwd);
64 if (strcmp(pw, pwd->pw_passwd) != 0) {
65 printf("Sorry.\n");
66 exit(1);
67 }
68 }
69tryagain:
70 strcpy(pwbuf, getpass("New password:"));
71 pwlen = strlen(pwbuf);
72 if (pwlen == 0) {
73 printf("Password unchanged.\n");
74 exit(1);
75 }
76 /*
77 * Insure password is of reasonable length and
78 * composition. If we really wanted to make things
79 * sticky, we could check the dictionary for common
80 * words, but then things would really be slow.
81 */
82 ok = 0;
83 flags = 0;
84 p = pwbuf;
85 while (c = *p++) {
86 if (c >= 'a' && c <= 'z')
87 flags |= 2;
88 else if (c >= 'A' && c <= 'Z')
89 flags |= 4;
90 else if (c >= '0' && c <= '9')
91 flags |= 1;
92 else
93 flags |= 8;
94 }
95 if (flags >= 7 && pwlen >= 4)
96 ok = 1;
97 if ((flags == 2 || flags == 4) && pwlen >= 6)
98 ok = 1;
99 if ((flags == 3 || flags == 5 || flags == 6) && pwlen >= 5)
100 ok = 1;
101 if (!ok && insist < 2) {
102 if (flags == 1)
103 printf("Please use %s.\n", flags == 1 ?
104 "at least one non-numeric character" :
105 "a longer password");
106 insist++;
107 goto tryagain;
108 }
109 if (strcmp(pwbuf, getpass("Retype new password:")) != 0) {
110 printf("Mismatch - password unchanged.\n");
111 exit(1);
112 }
113 time(&salt);
114 salt = 9 * getpid();
115 saltc[0] = salt & 077;
116 saltc[1] = (salt>>6) & 077;
117 for (i = 0; i < 2; i++) {
118 c = saltc[i] + '.';
119 if (c > '9')
120 c += 7;
121 if (c > 'Z')
122 c += 6;
123 saltc[i] = c;
124 }
125 pw = crypt(pwbuf, saltc);
126 signal(SIGHUP, SIG_IGN);
127 signal(SIGINT, SIG_IGN);
128 signal(SIGQUIT, SIG_IGN);
129 /*
130 * The mode here could be 644 except then old versions
131 * of passwd that don't honor the advisory locks might
132 * sneak in and mess things up. If we could believe the
133 * locking were honored, then we could also eliminate the
134 * chmod below after the rename.
135 */
136 fd = open(temp, FWRONLY|FCREATE|FEXLOCK|FNBLOCK, 0600);
137 if (fd < 0) {
138 fprintf(stderr, "passwd: ");
139 if (errno == EBUSY)
140 fprintf(stderr, "password file busy - try again.\n");
141 else
142 perror(temp);
143 exit(1);
144 }
145 signal(SIGTSTP, SIG_IGN);
146 if ((tf = fdopen(fd, "w")) == NULL) {
147 fprintf(stderr, "passwd: fdopen failed?\n");
148 exit(1);
149 }
150 /*
151 * Copy passwd to temp, replacing matching lines
152 * with new password.
153 */
154 while ((pwd = getpwent()) != NULL) {
155 if (strcmp(pwd->pw_name,uname) == 0) {
156 u = getuid();
157 if (u && u != pwd->pw_uid) {
158 fprintf(stderr, "passwd: permission denied.\n");
159 unlink(temp);
160 exit(1);
161 }
162 pwd->pw_passwd = pw;
163 if (pwd->pw_gecos[0] == '*')
164 pwd->pw_gecos++;
165 }
166 fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
167 pwd->pw_name,
168 pwd->pw_passwd,
169 pwd->pw_uid,
170 pwd->pw_gid,
171 pwd->pw_gecos,
172 pwd->pw_dir,
173 pwd->pw_shell);
174 }
175 endpwent();
176 if (rename(temp, passwd) < 0) {
177 fprintf(stderr, "passwd: "); perror("rename");
178 unlink(temp);
179 exit(1);
180 }
181 chmod(passwd, 0644);
182 fclose(tf);
183}