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