|
|
1.1 root 1: /*
2: * enter a password in the password file
3: * this program should be suid with owner
4: * with an owner with write permission on /etc/passwd
5: */
6: #include <stdio.h>
7: #include <signal.h>
8: #include <pwd.h>
9: #include <errno.h>
10: #include <ctype.h>
11:
12: char passwd[] = "/etc/passwd";
13: char npasswd[] = "/etc/npasswd";
14: char tpasswd[] = "/etc/pwXXXXXX";
15: char stdprof[] = "/etc/stdprofile";
16: int newmode = 0755;
17: char *tempfile;
18: struct passwd *pwd;
19: long time();
20: char *mktemp();
21: char *readpasswd();
22: struct passwd *getpwent();
23: int endpwent();
24: char *strcpy();
25: char *crypt();
26: char *getpass();
27: char *getlogin();
28: extern int optind;
29: extern int errno;
30: int newuser;
31: int alter;
32: char *username;
33: struct passwd pw;
34:
35: char *getstring();
36: char *newstr();
37: int rootid = 0;
38:
39: main(argc, argv)
40: char *argv[];
41: {
42: char *pwp;
43: int c, u, maxuid;
44: FILE *tf;
45:
46: while ((c = getopt(argc, argv, "na")) != EOF) {
47: switch(c) {
48: case 'n':
49: newuser++;
50: break;
51:
52: case 'a':
53: alter++;
54: break;
55:
56: default:
57: exit(1);
58: }
59: }
60: if (optind >= argc) {
61: if (newuser==0) {
62: if ((username = getlogin()) == NULL) {
63: printf ("Usage: passwd [-na] [user]\n");
64: exit(1);
65: } else
66: printf("Changing password for %s\n", username);
67: }
68: } else
69: username = argv[optind];
70: if (username==NULL) {
71: username = getstring("User: ");
72: if (username==NULL || *username=='\0') {
73: printf("Cannot default user\n");
74: exit(1);
75: }
76: }
77: maxuid = -1;
78: while ((pwd = getpwent()) != NULL) {
79: if (strcmp(pwd->pw_name, username) == 0) {
80: pw.pw_name = username;
81: pw.pw_passwd = newstr(pwd->pw_passwd);
82: pw.pw_uid = pwd->pw_uid;
83: pw.pw_gid = pwd->pw_gid;
84: pw.pw_gecos = newstr(pwd->pw_gecos);
85: pw.pw_dir = newstr(pwd->pw_dir);
86: pw.pw_shell = newstr(pwd->pw_shell);
87: }
88: if (pwd->pw_uid > maxuid)
89: maxuid = pwd->pw_uid;
90: }
91: endpwent();
92: if (pw.pw_name==NULL && newuser==0) {
93: printf("Cannot find password entry for %s\n", username);
94: exit(1);
95: }
96: if (newuser) {
97: if (pw.pw_name) {
98: printf("user %s already exists\n", username);
99: exit(1);
100: }
101: pw.pw_name = username;
102: }
103: u = getuid();
104: if (u!=rootid && (newuser || pw.pw_uid!=u)) {
105: printf("Permission denied.\n");
106: exit(1);
107: }
108: pwp = readpasswd(u, pw.pw_passwd);
109: if (pwp==NULL) {
110: if (newuser==0) {
111: printf("Password unchanged.\n");
112: if (alter==0)
113: exit(0);
114: pwp = pw.pw_passwd;
115: } else
116: pwp = "";
117: }
118: pw.pw_passwd = pwp;
119: if (alter!=0 || newuser!=0)
120: otherfields(maxuid+1);
121: signal(SIGHUP, SIG_IGN);
122: signal(SIGINT, SIG_IGN);
123: signal(SIGQUIT, SIG_IGN);
124: tempfile = mktemp(tpasswd);
125: if((tf=fopen(tempfile,"w")) == NULL) {
126: printf("Cannot create temporary file\n");
127: exit(1);
128: }
129: chmod(tempfile, 0644);
130: while((pwd=getpwent()) != NULL) {
131: if(strcmp(pwd->pw_name,username) == 0)
132: pwd = &pw;
133: fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
134: pwd->pw_name,
135: pwd->pw_passwd,
136: pwd->pw_uid,
137: pwd->pw_gid,
138: pwd->pw_gecos,
139: pwd->pw_dir,
140: pwd->pw_shell);
141: }
142: endpwent();
143: if (newuser) {
144: pwd = &pw;
145: fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
146: pwd->pw_name,
147: pwd->pw_passwd,
148: pwd->pw_uid,
149: pwd->pw_gid,
150: pwd->pw_gecos,
151: pwd->pw_dir,
152: pwd->pw_shell);
153: }
154: fclose(tf);
155: /*
156: * move temp back to passwd file
157: * (carefully)
158: */
159: while (link(tempfile, npasswd) < 0) {
160: if (errno == EEXIST) {
161: printf("Password file busy... shall I wait?");
162: if (*getstring() == 'y')
163: sleep(5);
164: else
165: exit(1);
166: } else {
167: printf("Cannot link to temp\n");
168: exit(1);
169: }
170: }
171: if (unlink(passwd) < 0) {
172: printf("Cannot unlink old passwd\n");
173: exit(1);
174: }
175: if (link(npasswd, passwd) < 0) {
176: printf("Cannot link in new passwd.\n");
177: exit(1);
178: }
179: unlink(npasswd);
180: unlink(tempfile);
181: return 0;
182: }
183:
184: char *
185: readpasswd(uid, opass)
186: char *opass;
187: {
188: static char minlen[] =
189: { 8, 8, 6, 5, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4};
190: register char *p, *npass;
191: register c, flags;
192: int ok, tries, pwlen;
193: long salt;
194: char saltc[2];
195: char *rev(), *multi();
196: register i;
197:
198: if (uid!=0 && opass && *opass) {
199: npass = getpass("Old password:");
200: if (strcmp(crypt(npass, opass), opass)) {
201: printf("Sorry.\n");
202: exit(1);
203: }
204: }
205: opass = NULL;
206: for (ok=0, tries=0;;) {
207: if (ok==0 && tries) {
208: printf("Password too simple. Try again.\n");
209: opass = 0;
210: }
211: npass = newstr(getpass(ok?"Reconfirm password:":"New password:"));
212: if (opass && strcmp(opass, npass)) {
213: printf("Password mismatch.\n");
214: exit(1);
215: }
216: if (strcmp(npass, "sorry")==0 && (alter || newuser) && tries==0) {
217: if (*getstring("You want an unusable password, right? ") == 'y')
218: return("sorry");
219: }
220: if (ok)
221: break;
222: pwlen = strlen(npass);
223: if (pwlen == 0)
224: return(NULL);
225: flags = 0;
226: p = npass;
227: while (c = *p++) {
228: if (islower(c))
229: flags |= 02;
230: else if (isupper(c))
231: flags |= 04;
232: else if (isdigit(c))
233: flags |= 01;
234: else
235: flags |= 010;
236: }
237: if (tries>2 || pwlen>=minlen[flags])
238: ok++;
239: tries++;
240:
241: if((strcmp(npass, pw.pw_name) == 0)
242: || (strcmp(npass, rev(pw.pw_name)) == 0)
243: || (strcmp(npass, multi(pw.pw_name)) == 0)){
244:
245: ok = 0;
246: tries = 1;
247: }
248:
249:
250: opass = npass;
251: }
252: time(&salt);
253: salt += getpid();
254: saltc[0] = salt & 077;
255: saltc[1] = (salt>>6) & 077;
256: for(i=0; i<2; i++) {
257: c = saltc[i] + '.';
258: if(c>'9') c += 7;
259: if(c>'Z') c += 6;
260: saltc[i] = c;
261: }
262: return(newstr(crypt(npass, saltc)));
263: }
264:
265: char *
266: getstring(mesg)
267: char *mesg;
268: {
269: char buf[128], *fgets();
270:
271: printf("%s", mesg);
272: if (fgets(buf, 128, stdin) == NULL)
273: exit(1);
274: buf[strlen(buf)-1] = '\0';
275: return(newstr(buf));
276: }
277:
278: char *
279: newstr(s)
280: char *s;
281: {
282: char *strcpy();
283: return(strcpy(malloc(strlen(s)+1), s));
284: }
285:
286: otherfields(uid)
287: {
288: char *s;
289: int id;
290:
291: if (newuser) {
292: s = getstring("UID: ");
293: while (!isnum(s)) {
294: printf ("Not numeric\n");
295: s = getstring ("Enter numeric user ID: ");
296: }
297: if (*s != '\0')
298: uid = atoi (s);
299: pw.pw_uid = uid;
300: pw.pw_gid = 1;
301: }
302: if (newuser || alter) {
303: s = getstring("GCOS acct,box: ");
304: if (*s)
305: pw.pw_gecos = s;
306: if (pw.pw_gecos==NULL)
307: pw.pw_gecos = "";
308: s = getstring("Directory: ");
309: if (*s)
310: pw.pw_dir = s;
311: if (pw.pw_dir==NULL) {
312: char db[128];
313: strcpy(db, "/usr/");
314: strcat(db, pw.pw_name);
315: pw.pw_dir = newstr(db);
316: }
317: if (newuser) {
318: mkdir(pw.pw_dir);
319: chown(pw.pw_dir, pw.pw_uid, pw.pw_gid);
320: chmod(pw.pw_dir, newmode);
321: }
322: s = getstring("Shell: ");
323: if (*s)
324: pw.pw_shell = s;
325: if (pw.pw_shell == NULL)
326: pw.pw_shell = "";
327:
328: /* Create .profile for the new user */
329: if (newuser) {
330: FILE *inf, *outf;
331:
332: for (;;) {
333: s = getstring("Profile: ");
334: if (*s == '\0')
335: s = stdprof;
336: inf = fopen (s, "r");
337: if (inf != NULL || s == stdprof)
338: break;
339: printf ("Can't open %s\n", s);
340: }
341: if (inf != NULL) {
342: char pname[128];
343: register int c;
344:
345: (void) strcpy (pname, pw.pw_dir);
346: (void) strcat (pname, "/.profile");
347: outf = fopen (pname, "w");
348: if (outf == NULL) {
349: printf ("can't create %s\n", pname);
350: exit(1);
351: }
352: (void) chown (pname, pw.pw_uid, pw.pw_gid);
353: (void) chmod (pname, newmode);
354:
355: /*
356: * copy the profile file to the new
357: * user's .profile, transforming \N into
358: * the user's name, \D into his home
359: * directory, and \\ into \.
360: */
361: while ((c = getc (inf)) != EOF) {
362: if (c == '\\') {
363: c = getc (inf);
364: switch (c) {
365:
366: case 'D':
367: fputs (pw.pw_dir, outf);
368: break;
369:
370: case 'N':
371: fputs (pw.pw_name,outf);
372: break;
373:
374: case EOF:
375: break;
376:
377: default:
378: putc ('\\', outf);
379: /* No break */
380: case '\\':
381: putc (c, outf);
382: break;
383: }
384: } else
385: putc (c, outf);
386: }
387: if (ferror (inf) || ferror (outf))
388: printf ("I/O error copying %s to %s\n",
389: s, pname);
390: (void) fclose (inf);
391: (void) fclose (outf);
392: }
393: }
394: }
395: }
396:
397:
398: int
399: mkdir(d)
400: register char *d;
401: {
402: register int pid, w;
403: int status;
404:
405: switch (pid=fork()) {
406:
407: case 0:
408: execl ("/bin/mkdir", "mkdir", d, 0);
409: execl ("/usr/bin/mkdir", "mkdir", d, 0);
410: /* No break */
411: case -1:
412: return 1;
413:
414: default:
415: do w = wait (&status);
416: while (w != pid && w > 0);
417: if (w == pid)
418: return status;
419: return w;
420: }
421: }
422:
423: int
424: isnum(s)
425: register char *s;
426: {
427: while (*s)
428: if (!isdigit(*s++))
429: return 0;
430: return 1;
431: }
432: char *rev(s)
433: char *s;
434: {
435:
436: static char t[200];
437: char *p, *q;
438:
439: p = s;
440: q = &t[199];
441: *q-- = '\0';
442:
443: while(*q-- = *p++);
444:
445: return q+2;
446: }
447: char *multi(s)
448: char *s;
449: {
450:
451: int i, x;
452: char *p=s;
453: static char w[9];
454:
455: while(*p++); x = p-s-1;
456:
457: if(x > 4) return "password";
458:
459: *w = '\0';
460:
461: for(i=0;i<2*x*x-(x*x*x+47*x)/6+12;i++)
462:
463: strcat(w,s);
464:
465: return w;
466: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.