|
|
1.1 root 1: /*
2: * Rec'd from Lauren Weinstein, 7-16-84.
3: * Passwd - set login password
4: * for a user.
5: */
6:
7: #include <stdio.h>
8: #include <ctype.h>
9: #include <sys/types.h>
10: #include <pwd.h>
11: #include <signal.h>
12: #include <errno.h>
13:
14: #define NSALT 64 /* Size of salt character set */
15: #define NSALTC 2 /* Number of characters in salt */
16: #define NPASSC 32 /* Maximum characters copied into pass. buf */
17: #define AWRITE 2 /* Access for write */
18: #define NLOKOUT 7 /* Maximum number of lockout attempts */
19: #define NPWCHAR 256 /* Number of characters in passwd file line */
20:
21: char notrich[] = "\
22: Password is too easily broken\n\
23: Try again: \
24: ";
25: char pfile[] = "/etc/passwd";
26: char tmpfile[] = "/tmp/passwd";
27:
28: char salttab[NSALT] =
29: "./abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
30:
31: char pwline[NPWCHAR];
32:
33: FILE *lockopen();
34: char *crypt();
35: int cleanup();
36: time_t time();
37:
38: int tmpflag; /* Says tempfile is open */
39:
40: main(argc, argv)
41: char *argv[];
42: {
43: register struct passwd *pwp;
44: register char *pass, *name;
45: char passbuf[NPASSC+1];
46: int myuid;
47: char *myname;
48: extern char *getpass();
49: extern char *getlogin();
50:
51: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
52: signal(SIGINT, cleanup);
53: if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
54: signal(SIGHUP, cleanup);
55: myuid = getuid();
56:
57: umask(077); /* mask out file access by other users */
58:
59: if (argc > 1) { /* By supplied argument */
60: if (argc != 2)
61: usage();
62: if ((pwp = getpwnam(argv[1])) == NULL)
63: perr("%s: bad user name\n", argv[1]);
64: if (myuid!=0 && pwp->pw_uid!=myuid)
65: perr("%s: not allowed to change password\n", argv[1]);
66: name = argv[1]; /* get name for change */
67: } else /* By getlogin from /etc/utmp */
68: if ((myname = getlogin()) != NULL) {
69: if ((pwp = getpwnam(myname)) == NULL)
70: perr("%s: bad login name\n", argv[1]);
71: if (myuid != 0 && pwp->pw_uid != myuid)
72: perr("%s: not allowed to change password\n", argv[1]);
73: name = myname; /* get name for change */
74: } else { /* By user id */
75: if ((pwp = getpwuid(myuid)) == NULL)
76: perr("Error on /etc/passwd\n");
77: while ((pwp = getpwent()) != NULL)
78: if (pwp->pw_uid == myuid)
79: perr("user id is not unique\n");
80: pwp = getpwuid(myuid);
81: name = pwp->pw_name; /* changing our own name */
82: }
83: if (myuid!=0 && pwp->pw_passwd[0]!='\0') {
84: if ((pass = getpass("Old password: ")) == NULL)
85: exit(1);
86: if (!checkpass(pwp->pw_passwd, pass))
87: perr("Sorry\n");
88: }
89: if ((pass = getpass("New password: ")) == NULL)
90: exit(1);
91: if (pass[0] != 0 || (pass[0] == 0 && getuid() != 0))
92: while (!richenough(pass) || !strcmp(pass, pwp->pw_name))
93: if ((pass = getpass(notrich)) == NULL)
94: exit(1);
95: strncpy(passbuf, pass, NPASSC);
96: if ((pass = getpass("Verification: ")) == NULL)
97: exit(1);
98: if (strncmp(pass, passbuf, NPASSC) != 0)
99: perr("No match: password not changed\n");
100: setpass(name, pass);
101: }
102:
103: /*
104: * Tests to see if a password is rich enough
105: * (i.e. not too easy to break by exhaustion).
106: * A password must be 4 characters if the alphabet
107: * is rich enough and 6 characters if it is in a
108: * single case. Perhaps the dictionary should
109: * be searched as well for more security-conscious
110: * systems. We also check (above) to make sure
111: * that the selected password is not the same as the username!
112: */
113: richenough(passwd)
114: char *passwd;
115: {
116: register char *cp;
117: register int uflag=0, lflag=0, oflag=0;
118: register int l;
119:
120: for (cp = passwd; *cp != '\0'; cp++) {
121: if (islower(*cp))
122: lflag = 1;
123: else if (isupper(*cp))
124: uflag = 1;
125: else
126: oflag = 1;
127: }
128: l = cp-passwd;
129: if (l < 4)
130: return (0);
131: if (oflag==0 && lflag^uflag && l<6)
132: return (0);
133: return (1);
134: }
135:
136: /*
137: * Check the passwd in the password file (`rpass')
138: * against the typed-in (`tpass') password.
139: */
140: checkpass(rpass, tpass)
141: register char *rpass, *tpass;
142: {
143: char salt[3];
144:
145: salt[0] = rpass[0];
146: salt[1] = rpass[1];
147: return (strcmp(crypt(tpass, salt), rpass) == 0);
148: }
149:
150: /*
151: * Set password for specified name.
152: */
153: setpass(name, passwd)
154: char *name, *passwd;
155: {
156: char salt[NSALTC+1];
157: char namebuff[NPWCHAR]; /* name buffer */
158: time_t xtime;
159: register char *p1, *p2;
160: register int c;
161: register FILE *pwf;
162: register FILE *tf;
163:
164: /*
165: * Generate the salt for crypt.
166: */
167: time(&xtime);
168: srand((int)xtime);
169: salt[0] = salttab[rand()%NSALT];
170: salt[1] = salttab[rand()%NSALT];
171: salt[2] = '\0';
172: if (*passwd != '\0')
173: passwd = crypt(passwd, salt);
174: /*
175: * Copy password file to tempfile
176: * looking for slot to change.
177: * The format of a passwd entry is:
178: * name:password:uid:...
179: */
180: if ((pwf = fopen(pfile, "r")) == NULL)
181: perr("Cannot open %s\n", pfile);
182: tf = lockopen(tmpfile);
183: while (fgets(pwline, NPWCHAR, pwf) != NULL) {
184: strcpy(namebuff, pwline); /* copy line */
185: p1 = namebuff;
186: while (*p1 != '\0')
187: if (*p1++ == ':')
188: break;
189: *--p1 = '\0'; /* null terminate user name */
190:
191: p1 = pwline;
192: while (*p1 != '\0')
193: if (*p1++ == ':')
194: break;
195: p2 = p1;
196: while (*p2 != '\0')
197: if (*p2++ == ':')
198: break;
199:
200: if (!strcmp(namebuff, name)) { /* check for name match */
201: *p1 = '\0';
202: fputs(pwline, tf);
203: fputs(passwd, tf);
204: putc(':', tf);
205: fputs(p2, tf);
206: break;
207: }
208: fputs(pwline, tf);
209: }
210: while ((c = getc(pwf)) != EOF) /* copy rest of file */
211: putc(c, tf);
212: fclose(pwf);
213: /*
214: * Copy tempfile back to password
215: * file -- this runs protected
216: * from interrupts.
217: */
218: signal(SIGINT, SIG_IGN);
219: signal(SIGHUP, SIG_IGN);
220: signal(SIGQUIT, SIG_IGN);
221: if ((pwf = fopen(pfile, "w")) == NULL)
222: perr("Cannot create %s\n", pfile);
223: fflush(tf);
224: rewind(tf);
225: while ((c = getc(tf)) != EOF)
226: putc(c, pwf);
227: fflush(pwf);
228: unlink(tmpfile);
229: }
230:
231: /*
232: * Open the tempfile waiting
233: * for the tempfile to come free.
234: */
235: FILE *
236: lockopen(file)
237: char *file;
238: {
239: register int n;
240: register FILE *fp;
241: extern int errno;
242:
243: for (n=NLOKOUT; n>0; n--)
244: if (access(file, AWRITE)<0 && errno==ENOENT) {
245: if ((fp=fopen(file, "w")) == NULL
246: || (fp=freopen(file, "r+w", fp)) == NULL)
247: perr("Cannot create tempfile\n");
248: tmpflag = 1;
249: return (fp);
250: }
251: perr("Tempfile busy, try again later\n");
252: }
253:
254: /*
255: * Cleanup the tempfile.
256: */
257: cleanup()
258: {
259: if (tmpflag)
260: unlink(tmpfile);
261: exit (1);
262: }
263:
264: /*
265: * Error routines
266: */
267: usage()
268: {
269: perr("Usage: passwd [name]\n");
270: }
271:
272: perr(x)
273: {
274: fprintf(stderr, "%r", &x);
275: exit(1);
276: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.