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