date and time created 83/02/11 15:45:10 by rrh
[unix-history] / usr / src / usr.bin / passwd / passwd.c
CommitLineData
252e456d 1#ifndef lint
09a58956 2static char sccsid[] = "@(#)passwd.c 4.2 (Berkeley) %G%";
252e456d
SL
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) {
252e456d
SL
102 printf("Please use %s.\n", flags == 1 ?
103 "at least one non-numeric character" :
104 "a longer password");
105 insist++;
106 goto tryagain;
107 }
108 if (strcmp(pwbuf, getpass("Retype new password:")) != 0) {
109 printf("Mismatch - password unchanged.\n");
110 exit(1);
111 }
112 time(&salt);
113 salt = 9 * getpid();
114 saltc[0] = salt & 077;
115 saltc[1] = (salt>>6) & 077;
116 for (i = 0; i < 2; i++) {
117 c = saltc[i] + '.';
118 if (c > '9')
119 c += 7;
120 if (c > 'Z')
121 c += 6;
122 saltc[i] = c;
123 }
124 pw = crypt(pwbuf, saltc);
125 signal(SIGHUP, SIG_IGN);
126 signal(SIGINT, SIG_IGN);
127 signal(SIGQUIT, SIG_IGN);
128 /*
129 * The mode here could be 644 except then old versions
130 * of passwd that don't honor the advisory locks might
131 * sneak in and mess things up. If we could believe the
132 * locking were honored, then we could also eliminate the
133 * chmod below after the rename.
134 */
135 fd = open(temp, FWRONLY|FCREATE|FEXLOCK|FNBLOCK, 0600);
136 if (fd < 0) {
137 fprintf(stderr, "passwd: ");
138 if (errno == EBUSY)
139 fprintf(stderr, "password file busy - try again.\n");
140 else
141 perror(temp);
142 exit(1);
143 }
144 signal(SIGTSTP, SIG_IGN);
145 if ((tf = fdopen(fd, "w")) == NULL) {
146 fprintf(stderr, "passwd: fdopen failed?\n");
147 exit(1);
148 }
149 /*
150 * Copy passwd to temp, replacing matching lines
151 * with new password.
152 */
153 while ((pwd = getpwent()) != NULL) {
154 if (strcmp(pwd->pw_name,uname) == 0) {
155 u = getuid();
156 if (u && u != pwd->pw_uid) {
157 fprintf(stderr, "passwd: permission denied.\n");
158 unlink(temp);
159 exit(1);
160 }
161 pwd->pw_passwd = pw;
162 if (pwd->pw_gecos[0] == '*')
163 pwd->pw_gecos++;
164 }
165 fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
166 pwd->pw_name,
167 pwd->pw_passwd,
168 pwd->pw_uid,
169 pwd->pw_gid,
170 pwd->pw_gecos,
171 pwd->pw_dir,
172 pwd->pw_shell);
173 }
174 endpwent();
175 if (rename(temp, passwd) < 0) {
176 fprintf(stderr, "passwd: "); perror("rename");
177 unlink(temp);
178 exit(1);
179 }
180 chmod(passwd, 0644);
181 fclose(tf);
182}