|
|
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 && 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: char defdir[128];
304:
305: strcpy (defdir, "/usr/");
306: strcat (defdir, pw.pw_name);
307:
308: s = getstring("GCOS acct,box: ");
309: if (*s)
310: pw.pw_gecos = s;
311: if (pw.pw_gecos==NULL)
312: pw.pw_gecos = "";
313: s = getstring("Directory: ");
314: if (*s)
315: pw.pw_dir = s;
316: if (pw.pw_dir==NULL)
317: pw.pw_dir = newstr(defdir);
318: if (newuser) {
319: char *realdir;
320: realdir = pw.pw_dir;
321: if (realdir[0] == '*') {
322: realdir++;
323: if (realdir[0] != '/') {
324: char x[256];
325: strcpy (x, "/");
326: strcat (x, realdir);
327: strcat (x, "/");
328: strcat (x, pw.pw_name);
329: realdir = newstr (x);
330: }
331: pw.pw_dir = newstr(defdir);
332: symlink (realdir, defdir);
333: }
334: mkdir(realdir);
335: chown(realdir, pw.pw_uid, pw.pw_gid);
336: chmod(realdir, newmode);
337: }
338: s = getstring("Shell: ");
339: if (*s)
340: pw.pw_shell = s;
341: if (pw.pw_shell == NULL)
342: pw.pw_shell = "";
343:
344: /* Create .profile for the new user */
345: if (newuser) {
346: FILE *inf, *outf;
347:
348: for (;;) {
349: s = getstring("Profile: ");
350: if (*s == '\0')
351: s = stdprof;
352: inf = fopen (s, "r");
353: if (inf != NULL || s == stdprof)
354: break;
355: printf ("Can't open %s\n", s);
356: }
357: if (inf != NULL) {
358: char pname[128];
359: register int c;
360:
361: (void) strcpy (pname, pw.pw_dir);
362: (void) strcat (pname, "/.profile");
363: outf = fopen (pname, "w");
364: if (outf == NULL) {
365: printf ("can't create %s\n", pname);
366: exit(1);
367: }
368: (void) chown (pname, pw.pw_uid, pw.pw_gid);
369: (void) chmod (pname, newmode);
370:
371: /*
372: * copy the profile file to the new
373: * user's .profile, transforming \N into
374: * the user's name, \D into his home
375: * directory, and \\ into \.
376: */
377: while ((c = getc (inf)) != EOF) {
378: if (c == '\\') {
379: c = getc (inf);
380: switch (c) {
381:
382: case 'D':
383: fputs (pw.pw_dir, outf);
384: break;
385:
386: case 'N':
387: fputs (pw.pw_name,outf);
388: break;
389:
390: case EOF:
391: break;
392:
393: default:
394: putc ('\\', outf);
395: /* No break */
396: case '\\':
397: putc (c, outf);
398: break;
399: }
400: } else
401: putc (c, outf);
402: }
403: if (ferror (inf) || ferror (outf))
404: printf ("I/O error copying %s to %s\n",
405: s, pname);
406: (void) fclose (inf);
407: (void) fclose (outf);
408: }
409: }
410: }
411: }
412:
413:
414: int
415: mkdir(d)
416: register char *d;
417: {
418: register int pid, w;
419: int status;
420:
421: switch (pid=fork()) {
422:
423: case 0:
424: execl ("/bin/mkdir", "mkdir", d, 0);
425: execl ("/usr/bin/mkdir", "mkdir", d, 0);
426: /* No break */
427: case -1:
428: return 1;
429:
430: default:
431: do w = wait (&status);
432: while (w != pid && w > 0);
433: if (w == pid)
434: return status;
435: return w;
436: }
437: }
438:
439: int
440: isnum(s)
441: register char *s;
442: {
443: while (*s)
444: if (!isdigit(*s++))
445: return 0;
446: return 1;
447: }
448: char *rev(s)
449: char *s;
450: {
451:
452: static char t[200];
453: char *p, *q;
454:
455: p = s;
456: q = &t[199];
457: *q-- = '\0';
458:
459: while(*q-- = *p++);
460:
461: return q+2;
462: }
463: char *multi(s)
464: char *s;
465: {
466:
467: int i, x;
468: char *p=s;
469: static char w[9];
470:
471: while(*p++); x = p-s-1;
472:
473: if(x > 4) return "password";
474:
475: *w = '\0';
476:
477: for(i=0;i<2*x*x-(x*x*x+47*x)/6+12;i++)
478:
479: strcat(w,s);
480:
481: return w;
482: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.