1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)passwd.c	4.24 (Berkeley) 5/28/86";
  15: #endif not lint
  16: 
  17: /*
  18:  * Modify a field in the password file (either
  19:  * password, login shell, or gecos field).
  20:  * This program should be suid with an owner
  21:  * with write permission on /etc/passwd.
  22:  */
  23: #include <sys/types.h>
  24: #include <sys/file.h>
  25: #include <sys/time.h>
  26: #include <sys/resource.h>
  27: 
  28: #include <stdio.h>
  29: #include <signal.h>
  30: #include <pwd.h>
  31: #include <ndbm.h>
  32: #include <errno.h>
  33: #include <strings.h>
  34: #include <ctype.h>
  35: 
  36: /*
  37:  * This should be the first thing returned from a getloginshells()
  38:  * but too many programs know that it is /bin/sh.
  39:  */
  40: #define DEFSHELL "/bin/sh"
  41: 
  42: char    temp[] = "/etc/ptmp";
  43: char    passwd[] = "/etc/passwd";
  44: char    *getpass();
  45: char    *getlogin();
  46: char    *getfingerinfo();
  47: char    *getloginshell();
  48: char    *getnewpasswd();
  49: char    *malloc();
  50: char    *getusershell();
  51: extern  int errno;
  52: 
  53: main(argc, argv)
  54:     char *argv[];
  55: {
  56:     struct passwd *pwd;
  57:     char *cp, *uname, *progname;
  58:     int fd, u, dochfn, dochsh, err;
  59:     FILE *tf;
  60:     DBM *dp;
  61: 
  62:     if ((progname = rindex(argv[0], '/')) == NULL)
  63:         progname = argv[0];
  64:     else
  65:         progname++;
  66:     dochfn = 0, dochsh = 0;
  67:     argc--, argv++;
  68:     while (argc > 0 && argv[0][0] == '-') {
  69:         for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
  70: 
  71:         case 'f':
  72:             if (dochsh)
  73:                 goto bad;
  74:             dochfn = 1;
  75:             break;
  76: 
  77:         case 's':
  78:             if (dochfn) {
  79:         bad:
  80:                 fprintf(stderr,
  81:                    "passwd: Only one of -f and -s allowed.\n");
  82:                 exit(1);
  83:             }
  84:             dochsh = 1;
  85:             break;
  86: 
  87:         default:
  88:             fprintf(stderr, "passwd: -%c: unknown option.\n", *cp);
  89:             exit(1);
  90:         }
  91:         argc--, argv++;
  92:     }
  93:     if (!dochfn && !dochsh) {
  94:         if (strcmp(progname, "chfn") == 0)
  95:             dochfn = 1;
  96:         else if (strcmp(progname, "chsh") == 0)
  97:             dochsh = 1;
  98:     }
  99:     if (argc < 1) {
 100:         if ((uname = getlogin()) == NULL) {
 101:             fprintf(stderr, "Usage: %s [-f] [-s] [user]\n", progname);
 102:             exit(1);
 103:         }
 104:         printf("Changing %s for %s.\n",
 105:             dochfn ? "finger information" :
 106:             dochsh ? "login shell" : "password",
 107:             uname);
 108:     } else
 109:         uname = *argv++;
 110:     pwd = getpwnam(uname);
 111:     if (pwd == NULL) {
 112:         fprintf(stderr, "passwd: %s: unknown user.\n", uname);
 113:         exit(1);
 114:     }
 115:     u = getuid();
 116:     if (u != 0 && u != pwd->pw_uid) {
 117:         printf("Permission denied.\n");
 118:         exit(1);
 119:     }
 120:     if (dochfn)
 121:         cp = getfingerinfo(pwd);
 122:     else if (dochsh)
 123:         cp = getloginshell(pwd, u, *argv);
 124:     else
 125:         cp = getnewpasswd(pwd, u);
 126:     (void) signal(SIGHUP, SIG_IGN);
 127:     (void) signal(SIGINT, SIG_IGN);
 128:     (void) signal(SIGQUIT, SIG_IGN);
 129:     (void) signal(SIGTSTP, SIG_IGN);
 130:     (void) umask(0);
 131:     fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644);
 132:     if (fd < 0) {
 133:         err = errno;
 134: 
 135:         fprintf(stderr, "passwd: ");
 136:         if (err == EEXIST)
 137:             fprintf(stderr, "password file busy - try again.\n");
 138:         else {
 139:             errno = err;
 140:             perror(temp);
 141:         }
 142:         exit(1);
 143:     }
 144:     if ((tf = fdopen(fd, "w")) == NULL) {
 145:         fprintf(stderr, "passwd: fdopen failed?\n");
 146:         exit(1);
 147:     }
 148:     if ((dp = dbm_open(passwd, O_RDWR, 0644)) == NULL) {
 149:         err = errno;
 150:         fprintf(stderr, "Warning: dbm_open failed: ");
 151:         errno = err;
 152:         perror(passwd);
 153:     } else if (flock(dp->dbm_dirf, LOCK_EX) < 0) {
 154:         perror("Warning: lock failed");
 155:         dbm_close(dp);
 156:         dp = NULL;
 157:     }
 158:     unlimit(RLIMIT_CPU);
 159:     unlimit(RLIMIT_FSIZE);
 160:     /*
 161: 	 * Copy passwd to temp, replacing matching lines
 162: 	 * with new password.
 163: 	 */
 164:     while ((pwd = getpwent()) != NULL) {
 165:         if (strcmp(pwd->pw_name, uname) == 0) {
 166:             if (u && u != pwd->pw_uid) {
 167:                 fprintf(stderr, "passwd: permission denied.\n");
 168:                 goto out;
 169:             }
 170:             if (dochfn)
 171:                 pwd->pw_gecos = cp;
 172:             else if (dochsh)
 173:                 pwd->pw_shell = cp;
 174:             else
 175:                 pwd->pw_passwd = cp;
 176:             if (pwd->pw_gecos[0] == '*')    /* ??? */
 177:                 pwd->pw_gecos++;
 178:             replace(dp, pwd);
 179:         }
 180:         fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
 181:             pwd->pw_name,
 182:             pwd->pw_passwd,
 183:             pwd->pw_uid,
 184:             pwd->pw_gid,
 185:             pwd->pw_gecos,
 186:             pwd->pw_dir,
 187:             pwd->pw_shell);
 188:     }
 189:     endpwent();
 190:     if (dp != NULL && dbm_error(dp))
 191:         fprintf(stderr, "Warning: dbm_store failed\n");
 192:     (void) fflush(tf);
 193:     if (ferror(tf)) {
 194:         fprintf(stderr, "Warning: %s write error, %s not updated\n",
 195:             temp, passwd);
 196:         goto out;
 197:     }
 198:     (void) fclose(tf);
 199:     if (dp != NULL)
 200:         dbm_close(dp);
 201:     if (rename(temp, passwd) < 0) {
 202:         perror("passwd: rename");
 203:     out:
 204:         (void) unlink(temp);
 205:         exit(1);
 206:     }
 207:     exit(0);
 208: }
 209: 
 210: unlimit(lim)
 211: {
 212:     struct rlimit rlim;
 213: 
 214:     rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
 215:     (void) setrlimit(lim, &rlim);
 216: }
 217: 
 218: /*
 219:  * Replace the password entry in the dbm data base with pwd.
 220:  */
 221: replace(dp, pwd)
 222:     DBM *dp;
 223:     struct passwd *pwd;
 224: {
 225:     datum key, content;
 226:     register char *cp, *tp;
 227:     char buf[BUFSIZ];
 228: 
 229:     if (dp == NULL)
 230:         return;
 231: 
 232:     cp = buf;
 233: #define COMPACT(e)  tp = pwd->pw_/**/e; while (*cp++ = *tp++);
 234:     COMPACT(name);
 235:     COMPACT(passwd);
 236:     bcopy((char *)&pwd->pw_uid, cp, sizeof (int));
 237:     cp += sizeof (int);
 238:     bcopy((char *)&pwd->pw_gid, cp, sizeof (int));
 239:     cp += sizeof (int);
 240:     bcopy((char *)&pwd->pw_quota, cp, sizeof (int));
 241:     cp += sizeof (int);
 242:     COMPACT(comment);
 243:     COMPACT(gecos);
 244:     COMPACT(dir);
 245:     COMPACT(shell);
 246:     content.dptr = buf;
 247:     content.dsize = cp - buf;
 248:     key.dptr = pwd->pw_name;
 249:     key.dsize = strlen(pwd->pw_name);
 250:     dbm_store(dp, key, content, DBM_REPLACE);
 251:     key.dptr = (char *)&pwd->pw_uid;
 252:     key.dsize = sizeof (int);
 253:     dbm_store(dp, key, content, DBM_REPLACE);
 254: }
 255: 
 256: char *
 257: getnewpasswd(pwd, u)
 258:     register struct passwd *pwd;
 259:     int u;
 260: {
 261:     char saltc[2];
 262:     long salt;
 263:     int i, insist = 0, ok, flags;
 264:     int c, pwlen;
 265:     static char pwbuf[10];
 266:     long time();
 267:     char *crypt(), *pw, *p;
 268: 
 269:     if (pwd->pw_passwd[0] && u != 0) {
 270:         (void) strcpy(pwbuf, getpass("Old password:"));
 271:         pw = crypt(pwbuf, pwd->pw_passwd);
 272:         if (strcmp(pw, pwd->pw_passwd) != 0) {
 273:             printf("Sorry.\n");
 274:             exit(1);
 275:         }
 276:     }
 277: tryagain:
 278:     (void) strcpy(pwbuf, getpass("New password:"));
 279:     pwlen = strlen(pwbuf);
 280:     if (pwlen == 0) {
 281:         printf("Password unchanged.\n");
 282:         exit(1);
 283:     }
 284:     /*
 285: 	 * Insure password is of reasonable length and
 286: 	 * composition.  If we really wanted to make things
 287: 	 * sticky, we could check the dictionary for common
 288: 	 * words, but then things would really be slow.
 289: 	 */
 290:     ok = 0;
 291:     flags = 0;
 292:     p = pwbuf;
 293:     while (c = *p++) {
 294:         if (c >= 'a' && c <= 'z')
 295:             flags |= 2;
 296:         else if (c >= 'A' && c <= 'Z')
 297:             flags |= 4;
 298:         else if (c >= '0' && c <= '9')
 299:             flags |= 1;
 300:         else
 301:             flags |= 8;
 302:     }
 303:     if (flags >= 7 && pwlen >= 4)
 304:         ok = 1;
 305:     if ((flags == 2 || flags == 4) && pwlen >= 6)
 306:         ok = 1;
 307:     if ((flags == 3 || flags == 5 || flags == 6) && pwlen >= 5)
 308:         ok = 1;
 309:     if (!ok && insist < 2) {
 310:         printf("Please use %s.\n", flags == 1 ?
 311:             "at least one non-numeric character" :
 312:             "a longer password");
 313:         insist++;
 314:         goto tryagain;
 315:     }
 316:     if (strcmp(pwbuf, getpass("Retype new password:")) != 0) {
 317:         printf("Mismatch - password unchanged.\n");
 318:         exit(1);
 319:     }
 320:     (void) time(&salt);
 321:     salt = 9 * getpid();
 322:     saltc[0] = salt & 077;
 323:     saltc[1] = (salt>>6) & 077;
 324:     for (i = 0; i < 2; i++) {
 325:         c = saltc[i] + '.';
 326:         if (c > '9')
 327:             c += 7;
 328:         if (c > 'Z')
 329:             c += 6;
 330:         saltc[i] = c;
 331:     }
 332:     return (crypt(pwbuf, saltc));
 333: }
 334: 
 335: char *
 336: getloginshell(pwd, u, arg)
 337:     struct passwd *pwd;
 338:     int u;
 339:     char *arg;
 340: {
 341:     static char newshell[BUFSIZ];
 342:     char *cp, *valid, *getusershell();
 343: 
 344:     if (pwd->pw_shell == 0 || *pwd->pw_shell == '\0')
 345:         pwd->pw_shell = DEFSHELL;
 346:     if (u != 0) {
 347:         for (valid = getusershell(); valid; valid = getusershell())
 348:             if (strcmp(pwd->pw_shell, valid) == 0)
 349:                 break;
 350:         if (valid == NULL) {
 351:             printf("Cannot change from restricted shell %s\n",
 352:                 pwd->pw_shell);
 353:             exit(1);
 354:         }
 355:     }
 356:     if (arg != 0) {
 357:         (void) strncpy(newshell, arg, sizeof newshell - 1);
 358:         newshell[sizeof newshell - 1] = 0;
 359:     } else {
 360:         printf("Old shell: %s\nNew shell: ", pwd->pw_shell);
 361:         (void)fgets(newshell, sizeof (newshell) - 1, stdin);
 362:         cp = index(newshell, '\n');
 363:         if (cp)
 364:             *cp = '\0';
 365:     }
 366:     if (newshell[0] == '\0' || strcmp(newshell, pwd->pw_shell) == 0) {
 367:         printf("Login shell unchanged.\n");
 368:         exit(1);
 369:     }
 370:     /*
 371: 	 * Allow user to give shell name w/o preceding pathname.
 372: 	 */
 373:     if (u == 0) {
 374:         valid = newshell;
 375:     } else {
 376:         for (valid = getusershell(); valid; valid = getusershell()) {
 377:             if (newshell[0] == '/') {
 378:                 cp = valid;
 379:             } else {
 380:                 cp = rindex(valid, '/');
 381:                 if (cp == 0)
 382:                     cp = valid;
 383:                 else
 384:                     cp++;
 385:             }
 386:             if (strcmp(newshell, cp) == 0)
 387:                 break;
 388:         }
 389:     }
 390:     if (valid == 0) {
 391:         printf("%s is unacceptable as a new shell.\n",
 392:             newshell);
 393:         exit(1);
 394:     }
 395:     if (access(valid, X_OK) < 0) {
 396:         printf("%s is unavailable.\n", valid);
 397:         exit(1);
 398:     }
 399:     if (strcmp(valid, DEFSHELL) == 0)
 400:         valid[0] = '\0';
 401:     return (valid);
 402: }
 403: 
 404: struct default_values {
 405:     char *name;
 406:     char *office_num;
 407:     char *office_phone;
 408:     char *home_phone;
 409: };
 410: 
 411: /*
 412:  * Get name, room number, school phone, and home phone.
 413:  */
 414: char *
 415: getfingerinfo(pwd)
 416:     struct passwd *pwd;
 417: {
 418:     char in_str[BUFSIZ];
 419:     struct default_values *defaults, *get_defaults();
 420:     static char answer[4*BUFSIZ];
 421: 
 422:     answer[0] = '\0';
 423:     defaults = get_defaults(pwd->pw_gecos);
 424:     printf("Default values are printed inside of '[]'.\n");
 425:     printf("To accept the default, type <return>.\n");
 426:     printf("To have a blank entry, type the word 'none'.\n");
 427:     /*
 428: 	 * Get name.
 429: 	 */
 430:     do {
 431:         printf("\nName [%s]: ", defaults->name);
 432:         (void) fgets(in_str, BUFSIZ, stdin);
 433:         if (special_case(in_str, defaults->name))
 434:             break;
 435:     } while (illegal_input(in_str));
 436:     (void) strcpy(answer, in_str);
 437:     /*
 438: 	 * Get room number.
 439: 	 */
 440:     do {
 441:         printf("Room number (Exs: 597E or 197C) [%s]: ",
 442:             defaults->office_num);
 443:         (void) fgets(in_str, BUFSIZ, stdin);
 444:         if (special_case(in_str, defaults->office_num))
 445:             break;
 446:     } while (illegal_input(in_str) || illegal_building(in_str));
 447:     (void) strcat(strcat(answer, ","), in_str);
 448:     /*
 449: 	 * Get office phone number.
 450: 	 * Remove hyphens.
 451: 	 */
 452:     do {
 453:         printf("Office Phone (Ex: 6426000) [%s]: ",
 454:             defaults->office_phone);
 455:         (void) fgets(in_str, BUFSIZ, stdin);
 456:         if (special_case(in_str, defaults->office_phone))
 457:             break;
 458:         remove_hyphens(in_str);
 459:     } while (illegal_input(in_str) || not_all_digits(in_str));
 460:     (void) strcat(strcat(answer, ","), in_str);
 461:     /*
 462: 	 * Get home phone number.
 463: 	 * Remove hyphens if present.
 464: 	 */
 465:     do {
 466:         printf("Home Phone (Ex: 9875432) [%s]: ", defaults->home_phone);
 467:         (void) fgets(in_str, BUFSIZ, stdin);
 468:         if (special_case(in_str, defaults->home_phone))
 469:             break;
 470:         remove_hyphens(in_str);
 471:     } while (illegal_input(in_str) || not_all_digits(in_str));
 472:     (void) strcat(strcat(answer, ","), in_str);
 473:     if (strcmp(answer, pwd->pw_gecos) == 0) {
 474:         printf("Finger information unchanged.\n");
 475:         exit(1);
 476:     }
 477:     return (answer);
 478: }
 479: 
 480: /*
 481:  * Prints an error message if a ':' or a newline is found in the string.
 482:  * A message is also printed if the input string is too long.
 483:  * The password file uses :'s as seperators, and are not allowed in the "gcos"
 484:  * field.  Newlines serve as delimiters between users in the password file,
 485:  * and so, those too, are checked for.  (I don't think that it is possible to
 486:  * type them in, but better safe than sorry)
 487:  *
 488:  * Returns '1' if a colon or newline is found or the input line is too long.
 489:  */
 490: illegal_input(input_str)
 491:     char *input_str;
 492: {
 493:     char *ptr;
 494:     int error_flag = 0;
 495:     int length = strlen(input_str);
 496: 
 497:     if (index(input_str, ':')) {
 498:         printf("':' is not allowed.\n");
 499:         error_flag = 1;
 500:     }
 501:     if (input_str[length-1] != '\n') {
 502:         /* the newline and the '\0' eat up two characters */
 503:         printf("Maximum number of characters allowed is %d\n",
 504:             BUFSIZ-2);
 505:         /* flush the rest of the input line */
 506:         while (getchar() != '\n')
 507:             /* void */;
 508:         error_flag = 1;
 509:     }
 510:     /*
 511: 	 * Delete newline by shortening string by 1.
 512: 	 */
 513:     input_str[length-1] = '\0';
 514:     /*
 515: 	 * Don't allow control characters, etc in input string.
 516: 	 */
 517:     for (ptr=input_str; *ptr != '\0'; ptr++) {
 518:         if ((int) *ptr < 040) {
 519:             printf("Control characters are not allowed.\n");
 520:             error_flag = 1;
 521:             break;
 522:         }
 523:     }
 524:     return (error_flag);
 525: }
 526: 
 527: /*
 528:  * Removes '-'s from the input string.
 529:  */
 530: remove_hyphens(str)
 531:     char *str;
 532: {
 533:     char *hyphen;
 534: 
 535:     while ((hyphen = index(str, '-')) != NULL)
 536:         (void) strcpy(hyphen, hyphen+1);
 537: }
 538: 
 539: /*
 540:  *  Checks to see if 'str' contains only digits (0-9).  If not, then
 541:  *  an error message is printed and '1' is returned.
 542:  */
 543: not_all_digits(str)
 544:     char *str;
 545: {
 546:     char *ptr;
 547: 
 548:     for (ptr = str; *ptr != '\0'; ++ptr)
 549:         if (!isdigit(*ptr)) {
 550:             printf("Phone numbers can only contain digits.\n");
 551:             return (1);
 552:         }
 553:     return (0);
 554: }
 555: 
 556: /*
 557:  * Deal with Berkeley buildings.  Abbreviating Cory to C and Evans to E.
 558:  * Correction changes "str".
 559:  *
 560:  * Returns 1 if incorrect room format.
 561:  *
 562:  * Note: this function assumes that the newline has been removed from str.
 563:  */
 564: illegal_building(str)
 565:     register char *str;
 566: {
 567:     int length = strlen(str);
 568:     register char *ptr;
 569: 
 570:     /*
 571: 	 * If the string is [Ee]vans or [Cc]ory or ends in
 572: 	 * [ \t0-9][Ee]vans or [ \t0-9M][Cc]ory, then contract the name
 573: 	 * into 'E' or 'C', as the case may be, and delete leading blanks.
 574: 	 */
 575:     if (length >= 5 && strcmp(ptr = str + length - 4, "vans") == 0 &&
 576:         (*--ptr == 'e' || *ptr == 'E') &&
 577:         (--ptr < str || isspace(*ptr) || isdigit(*ptr))) {
 578:         for (; ptr > str && isspace(*ptr); ptr--)
 579:             ;
 580:         ptr++;
 581:         *ptr++ = 'E';
 582:         *ptr = '\0';
 583:     } else
 584:     if (length >= 4 && strcmp(ptr = str + length - 3, "ory") == 0 &&
 585:         (*--ptr == 'c' || *ptr == 'C') &&
 586:         (--ptr < str || *ptr == 'M' || isspace(*ptr) || isdigit(*ptr))) {
 587:         for (; ptr > str && isspace(*ptr); ptr--)
 588:             ;
 589:         ptr++;
 590:         *ptr++ = 'C';
 591:         *ptr = '\0';
 592:     }
 593:     return (0);
 594: }
 595: 
 596: /*
 597:  * get_defaults picks apart "str" and returns a structure points.
 598:  * "str" contains up to 4 fields separated by commas.
 599:  * Any field that is missing is set to blank.
 600:  */
 601: struct default_values *
 602: get_defaults(str)
 603:     char *str;
 604: {
 605:     struct default_values *answer;
 606: 
 607:     answer = (struct default_values *)
 608:         malloc((unsigned)sizeof(struct default_values));
 609:     if (answer == (struct default_values *) NULL) {
 610:         fprintf(stderr,
 611:             "\nUnable to allocate storage in get_defaults!\n");
 612:         exit(1);
 613:     }
 614:     /*
 615: 	 * Values if no corresponding string in "str".
 616: 	 */
 617:     answer->name = str;
 618:     answer->office_num = "";
 619:     answer->office_phone = "";
 620:     answer->home_phone = "";
 621:     str = index(answer->name, ',');
 622:     if (str == 0)
 623:         return (answer);
 624:     *str = '\0';
 625:     answer->office_num = str + 1;
 626:     str = index(answer->office_num, ',');
 627:     if (str == 0)
 628:         return (answer);
 629:     *str = '\0';
 630:     answer->office_phone = str + 1;
 631:     str = index(answer->office_phone, ',');
 632:     if (str == 0)
 633:         return (answer);
 634:     *str = '\0';
 635:     answer->home_phone = str + 1;
 636:     return (answer);
 637: }
 638: 
 639: /*
 640:  *  special_case returns true when either the default is accepted
 641:  *  (str = '\n'), or when 'none' is typed.  'none' is accepted in
 642:  *  either upper or lower case (or any combination).  'str' is modified
 643:  *  in these two cases.
 644:  */
 645: special_case(str,default_str)
 646:     char *str, *default_str;
 647: {
 648:     static char word[] = "none\n";
 649:     char *ptr, *wordptr;
 650: 
 651:     /*
 652: 	 *  If the default is accepted, then change the old string do the
 653: 	 *  default string.
 654: 	 */
 655:     if (*str == '\n') {
 656:         (void) strcpy(str, default_str);
 657:         return (1);
 658:     }
 659:     /*
 660: 	 *  Check to see if str is 'none'.  (It is questionable if case
 661: 	 *  insensitivity is worth the hair).
 662: 	 */
 663:     wordptr = word-1;
 664:     for (ptr = str; *ptr != '\0'; ++ptr) {
 665:         ++wordptr;
 666:         if (*wordptr == '\0')   /* then words are different sizes */
 667:             return (0);
 668:         if (*ptr == *wordptr)
 669:             continue;
 670:         if (isupper(*ptr) && (tolower(*ptr) == *wordptr))
 671:             continue;
 672:         /*
 673: 		 * At this point we have a mismatch, so we return
 674: 		 */
 675:         return (0);
 676:     }
 677:     /*
 678: 	 * Make sure that words are the same length.
 679: 	 */
 680:     if (*(wordptr+1) != '\0')
 681:         return (0);
 682:     /*
 683: 	 * Change 'str' to be the null string
 684: 	 */
 685:     *str = '\0';
 686:     return (1);
 687: }

Defined functions

get_defaults defined in line 601; used 2 times
getfingerinfo defined in line 414; used 2 times
getloginshell defined in line 335; used 2 times
getnewpasswd defined in line 256; used 2 times
illegal_building defined in line 564; used 1 times
illegal_input defined in line 490; used 4 times
main defined in line 53; never used
not_all_digits defined in line 543; used 2 times
remove_hyphens defined in line 530; used 2 times
replace defined in line 221; used 1 times
special_case defined in line 645; used 4 times
unlimit defined in line 210; used 2 times

Defined variables

copyright defined in line 8; never used
passwd defined in line 43; used 5 times
sccsid defined in line 14; never used
temp defined in line 42; used 5 times

Defined struct's

default_values defined in line 404; used 12 times

Defined macros

COMPACT defined in line 233; used 6 times
DEFSHELL defined in line 40; used 2 times
Last modified: 1986-05-29
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1960
Valid CSS Valid XHTML 1.0 Strict