|
|
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.