|
|
1.1 ! root 1: #ifndef lint ! 2: static char *sccsid = "@@(#)chfn.c 4.6 (Berkeley) 7/10/83"; ! 3: #endif lint ! 4: ! 5: /* ! 6: * changefinger - change finger entries ! 7: */ ! 8: #include <stdio.h> ! 9: #include <signal.h> ! 10: #include <pwd.h> ! 11: #include <sys/time.h> ! 12: #include <sys/resource.h> ! 13: #include <sys/file.h> ! 14: #include <ctype.h> ! 15: ! 16: struct default_values { ! 17: char *name; ! 18: char *office_num; ! 19: char *office_phone; ! 20: char *home_phone; ! 21: }; ! 22: ! 23: char passwd[] = "/etc/passwd"; ! 24: char temp[] = "/etc/ptmp"; ! 25: struct passwd *pwd; ! 26: struct passwd *getpwent(), *getpwnam(), *getpwuid(); ! 27: int endpwent(); ! 28: char *crypt(); ! 29: char *getpass(); ! 30: int hadQ = 0, hadZ = 0; ! 31: ! 32: main(argc, argv) ! 33: int argc; ! 34: char *argv[]; ! 35: { ! 36: int user_uid; ! 37: char replacement[4*BUFSIZ]; ! 38: int fd; ! 39: FILE *tf; ! 40: ! 41: if (argc > 2) { ! 42: printf("Usage: changefinger [user]\n"); ! 43: exit(1); ! 44: } ! 45: /* ! 46: * Error check to make sure the user (foolishly) typed their own name. ! 47: */ ! 48: user_uid = getuid(); ! 49: if ((argc == 2) && (user_uid != 0)) { ! 50: pwd = getpwnam(argv[1]); ! 51: if (pwd == NULL) { ! 52: printf("%s%s%s%s%s%s%s%s", ! 53: "There is no account for ", argv[1], ! 54: " on this machine.\n", ! 55: "You probably mispelled your login name;\n", ! 56: "only root is allowed to change another", ! 57: " person's finger entry.\n", ! 58: "Note: you do not need to type your login", ! 59: " name as an argument.\n"); ! 60: exit(1); ! 61: } ! 62: if (pwd->pw_uid != user_uid) { ! 63: printf("%s%s", ! 64: "You are not allowed to change another", ! 65: " person's finger entry.\n"); ! 66: exit(1); ! 67: } ! 68: } ! 69: /* ! 70: * If root is changing a finger entry, then find the uid that ! 71: * corresponds to the user's login name. ! 72: */ ! 73: if ((argc == 2) && (user_uid == 0)) { ! 74: pwd = getpwnam(argv[1]); ! 75: if (pwd == NULL) { ! 76: printf("There is no account for %s on this machine\n", ! 77: pwd->pw_name); ! 78: exit(1); ! 79: } ! 80: user_uid = pwd->pw_uid; ! 81: } ! 82: if (argc == 1) { ! 83: pwd = getpwuid(user_uid); ! 84: if (pwd == NULL) { ! 85: fprintf(stderr, "No passwd file entry!?\n"); ! 86: exit(1); ! 87: } ! 88: } ! 89: /* ! 90: * Collect name, office number, office phone, and home phone. ! 91: */ ! 92: get_info(pwd->pw_gecos, replacement); ! 93: ! 94: (void) signal(SIGHUP, SIG_IGN); ! 95: (void) signal(SIGINT, SIG_IGN); ! 96: (void) signal(SIGQUIT, SIG_IGN); ! 97: (void) signal(SIGTSTP, SIG_IGN); ! 98: (void) umask(0); ! 99: if ((fd = open(temp, O_CREAT|O_EXCL|O_RDWR, 0644)) < 0) { ! 100: printf("Temporary file busy -- try again\n"); ! 101: exit(1); ! 102: } ! 103: if ((tf = fdopen(fd, "w")) == NULL) { ! 104: printf("Absurd fdopen failure - seek help\n"); ! 105: goto out; ! 106: } ! 107: unlimit(RLIMIT_CPU); ! 108: unlimit(RLIMIT_FSIZE); ! 109: /* ! 110: * Copy passwd to temp, replacing matching lines ! 111: * with new gecos field. ! 112: */ ! 113: while ((pwd = getpwent()) != NULL) { ! 114: if (pwd->pw_uid == user_uid) ! 115: pwd->pw_gecos = replacement; ! 116: fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n", ! 117: pwd->pw_name, ! 118: pwd->pw_passwd, ! 119: pwd->pw_uid, ! 120: pwd->pw_gid, ! 121: pwd->pw_gecos, ! 122: pwd->pw_dir, ! 123: pwd->pw_shell); ! 124: } ! 125: (void) endpwent(); ! 126: if (rename(temp, passwd) < 0) { ! 127: fprintf(stderr, "chfn: "); perror("rename"); ! 128: out: ! 129: (void) unlink(temp); ! 130: exit(1); ! 131: } ! 132: (void) fclose(tf); ! 133: exit(0); ! 134: } ! 135: ! 136: unlimit(lim) ! 137: { ! 138: struct rlimit rlim; ! 139: ! 140: rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; ! 141: (void) setrlimit(lim, &rlim); ! 142: } ! 143: ! 144: /* ! 145: * Get name, office number, office phone, and home phone. ! 146: */ ! 147: get_info(gecos_field, answer) ! 148: char *gecos_field; ! 149: char *answer; ! 150: { ! 151: char *strcpy(), *strcat(); ! 152: char in_str[BUFSIZ]; ! 153: struct default_values *defaults, *get_defaults(); ! 154: int phflag; ! 155: ! 156: answer[0] = '\0'; ! 157: defaults = get_defaults(gecos_field); ! 158: printf("Default values are printed inside of '[]'.\n"); ! 159: printf("Examples are printed inside of '()'.\n"); ! 160: printf("To accept the default, type <return>.\n"); ! 161: printf("To have a blank entry, type the word 'none'.\n"); ! 162: /* ! 163: * Get name. ! 164: */ ! 165: do { ! 166: printf("\nName [%s]: ", defaults->name); ! 167: (void) fgets(in_str, BUFSIZ, stdin); ! 168: if (special_case(in_str, defaults->name)) ! 169: break; ! 170: } while (illegal_input(in_str)); ! 171: (void) strcpy(answer, in_str); ! 172: /* ! 173: * Get office number. ! 174: */ ! 175: again: ! 176: do { ! 177: printf("Office number (Exs: 597E or 197C) [%s]: ", ! 178: defaults->office_num); ! 179: (void) fgets(in_str, BUFSIZ, stdin); ! 180: if (special_case(in_str, defaults->office_num)) { ! 181: if (hadQ) ! 182: if (*in_str != '\0') ! 183: strcat(in_str, "Q"); ! 184: break; ! 185: } ! 186: } while (illegal_input(in_str)); ! 187: if (illegal_building(in_str)) ! 188: strcat(in_str, "Q"); ! 189: if (strlen(in_str) > 10) { ! 190: printf("office number must be no more than 9 characters\n"); ! 191: goto again; ! 192: } ! 193: (void) strcat(strcat(answer, ","), in_str); ! 194: /* ! 195: * Get office phone number. ! 196: * Remove hyphens and 642, x2, or 2 prefixes if present. ! 197: */ ! 198: do { ! 199: printf("Office Phone (Ex: 1632) [%s]: ", ! 200: defaults->office_phone); ! 201: (void) fgets(in_str, BUFSIZ, stdin); ! 202: phflag = 0; ! 203: if (special_case(in_str, defaults->office_phone)) { ! 204: phflag = 1; ! 205: if (hadZ) ! 206: if (*in_str != '\0') ! 207: strcat(in_str, "Z"); ! 208: break; ! 209: } ! 210: remove_hyphens(in_str); ! 211: if ((strlen(in_str) == 8) && (strcmpn(in_str, "642", 3) == 0)) { ! 212: (void) strcpy(in_str, in_str+3); ! 213: phflag = 1; ! 214: } ! 215: if ((strlen(in_str) == 7) && (strcmpn(in_str, "x2", 2) == 0)) { ! 216: (void) strcpy(in_str, in_str+2); ! 217: phflag = 1; ! 218: } ! 219: if ((strlen(in_str) == 6) && (in_str[0] == '2')) { ! 220: (void) strcpy(in_str, in_str+1); ! 221: phflag = 1; ! 222: } ! 223: } while (illegal_input(in_str) || wrong_length(in_str, 7)); ! 224: if (!phflag) ! 225: strcat(in_str, "Z"); ! 226: (void) strcat(strcat(answer, ","), in_str); ! 227: /* ! 228: * Get home phone number. ! 229: * Remove hyphens if present. ! 230: */ ! 231: do { ! 232: printf("Home Phone (Ex: 9875432) [%s]: ", defaults->home_phone); ! 233: (void) fgets(in_str, BUFSIZ, stdin); ! 234: if (special_case(in_str, defaults->home_phone)) ! 235: break; ! 236: remove_hyphens(in_str); ! 237: } while (illegal_input(in_str)); ! 238: (void) strcat(strcat(answer, ","), in_str); ! 239: } ! 240: ! 241: /* ! 242: * Prints an error message if a ':' or a newline is found in the string. ! 243: * A message is also printed if the input string is too long. ! 244: * The password file uses :'s as seperators, and are not allowed in the "gcos" ! 245: * field. Newlines serve as delimiters between users in the password file, ! 246: * and so, those too, are checked for. (I don't think that it is possible to ! 247: * type them in, but better safe than sorry) ! 248: * ! 249: * Returns '1' if a colon or newline is found or the input line is too long. ! 250: */ ! 251: illegal_input(input_str) ! 252: char *input_str; ! 253: { ! 254: char *index(); ! 255: char *ptr; ! 256: int error_flag = 0; ! 257: int length = strlen(input_str); ! 258: ! 259: if (index(input_str, ':')) { ! 260: printf("':' is not allowed.\n"); ! 261: error_flag = 1; ! 262: } ! 263: if (input_str[length-1] != '\n') { ! 264: /* the newline and the '\0' eat up two characters */ ! 265: printf("Maximum number of characters allowed is %d\n", ! 266: BUFSIZ-2); ! 267: /* flush the rest of the input line */ ! 268: while (getchar() != '\n') ! 269: /* void */; ! 270: error_flag = 1; ! 271: } ! 272: /* ! 273: * Delete newline by shortening string by 1. ! 274: */ ! 275: input_str[length-1] = '\0'; ! 276: /* ! 277: * Don't allow control characters, etc in input string. ! 278: */ ! 279: for (ptr=input_str; *ptr != '\0'; ptr++) { ! 280: if ((int) *ptr < 040) { ! 281: printf("Control characters are not allowed.\n"); ! 282: error_flag = 1; ! 283: break; ! 284: } ! 285: } ! 286: return(error_flag); ! 287: } ! 288: ! 289: /* ! 290: * Removes '-'s from the input string. ! 291: */ ! 292: remove_hyphens(str) ! 293: char *str; ! 294: { ! 295: char *hyphen, *index(), *strcpy(); ! 296: ! 297: while ((hyphen=index(str, '-')) != NULL) { ! 298: (void) strcpy(hyphen, hyphen+1); ! 299: } ! 300: } ! 301: ! 302: /* ! 303: * Returns 1 when the length of the input string is not zero and ! 304: * greater than n. ! 305: * Prints an error message in this case. ! 306: */ ! 307: wrong_length(str, n) ! 308: char *str; ! 309: int n; ! 310: { ! 311: ! 312: if ((strlen(str) != 0) && (strlen(str) >= n)) { ! 313: printf("The phone number should be less than %d digits long.\n", ! 314: n); ! 315: return(1); ! 316: } ! 317: return(0); ! 318: } ! 319: ! 320: /* ! 321: * Make sure that building is 'E', 'C' or 'L'. ! 322: * Error correction is done if building is 'e', 'c', 'l', ! 323: * "evans", "cory" or "lbl". ! 324: * Correction changes "str". ! 325: * The finger program determines the building by looking at the last ! 326: * character. Currently, finger only allows that character to be 'E', 'C' ! 327: * or 'L'. ! 328: * ! 329: * Returns 1 if incorrect office format. ! 330: * ! 331: * Note: this function assumes that the newline has been removed from str. ! 332: */ ! 333: illegal_building(str) ! 334: char *str; ! 335: { ! 336: int length = strlen(str); ! 337: char *last_ch, *ptr; ! 338: ! 339: /* ! 340: * Zero length strings are acceptable input. ! 341: */ ! 342: if (length == 0) ! 343: return(0); ! 344: /* ! 345: * Delete "vans", "ory" and "bl". ! 346: */ ! 347: if (strcmpn(str+length-4, "vans", 4) == 0) { ! 348: length -= 4; ! 349: str[length] = '\0'; ! 350: } ! 351: if (strcmpn(str+length-3, "ory", 3) == 0) { ! 352: length -= 3; ! 353: str[length] = '\0'; ! 354: } ! 355: if (strcmpn(str+length-2, "bl", 2) == 0) { ! 356: length -= 2; ! 357: str[length] = '\0'; ! 358: } ! 359: last_ch = str+length-1; ! 360: /* ! 361: * Now change e to E or c to C or l to L. ! 362: */ ! 363: if (*last_ch == 'e') ! 364: *last_ch = 'E'; ! 365: if (*last_ch == 'c') ! 366: *last_ch = 'C'; ! 367: if (*last_ch == 'l') ! 368: *last_ch = 'L'; ! 369: /* ! 370: * Delete any spaces before the E, C or L. ! 371: */ ! 372: for (ptr=last_ch-1; ptr>str; ptr--) { ! 373: if (*ptr != ' ') ! 374: break; ! 375: } ! 376: (void) strcpy(ptr+1, last_ch); ! 377: /* ! 378: * Make sure building is evans, cory or lbl. ! 379: */ ! 380: if ((*last_ch != 'E') && (*last_ch != 'C') && (*last_ch != 'L')) ! 381: return(1); ! 382: return(0); ! 383: } ! 384: ! 385: /* get_defaults picks apart "str" and returns a structure points. ! 386: * "str" contains up to 4 fields separated by commas. ! 387: * Any field that is missing is set to blank. ! 388: */ ! 389: struct default_values ! 390: *get_defaults(str) ! 391: char *str; ! 392: { ! 393: struct default_values *answer; ! 394: char *malloc(), *index(); ! 395: int len; ! 396: ! 397: answer = (struct default_values *) ! 398: malloc((unsigned)sizeof(struct default_values)); ! 399: if (answer == (struct default_values *) NULL) { ! 400: fprintf(stderr, ! 401: "\nUnable to allocate storage in get_defaults!\n"); ! 402: exit(1); ! 403: } ! 404: /* ! 405: * Values if no corresponding string in "str". ! 406: */ ! 407: answer->name = str; ! 408: answer->office_num = ""; ! 409: answer->office_phone = ""; ! 410: answer->home_phone = ""; ! 411: str = index(answer->name, ','); ! 412: if (str == 0) ! 413: return(answer); ! 414: *str = '\0'; ! 415: answer->office_num = str + 1; ! 416: str = index(answer->office_num, ','); ! 417: if (str == 0) { ! 418: len = strlen(answer->office_num); ! 419: if (answer->office_num[len - 1] == 'Q') { ! 420: answer->office_num[len - 1] = '\0'; ! 421: hadQ = 1; ! 422: } ! 423: return(answer); ! 424: } ! 425: *str = '\0'; ! 426: len = strlen(answer->office_num); ! 427: if (answer->office_num[len - 1] == 'Q') { ! 428: answer->office_num[len - 1] = '\0'; ! 429: hadQ = 1; ! 430: } ! 431: answer->office_phone = str + 1; ! 432: str = index(answer->office_phone, ','); ! 433: if (str == 0) { ! 434: len = strlen(answer->office_phone); ! 435: if (answer->office_phone[len - 1] == 'Z') { ! 436: answer->office_phone[len - 1] = '\0'; ! 437: hadZ = 1; ! 438: } ! 439: return(answer); ! 440: } ! 441: *str = '\0'; ! 442: len = strlen(answer->office_phone); ! 443: if (answer->office_phone[len - 1] == 'Z') { ! 444: answer->office_phone[len - 1] = '\0'; ! 445: hadZ = 1; ! 446: } ! 447: answer->home_phone = str + 1; ! 448: return(answer); ! 449: } ! 450: ! 451: /* ! 452: * special_case returns true when either the default is accepted ! 453: * (str = '\n'), or when 'none' is typed. 'none' is accepted in ! 454: * either upper or lower case (or any combination). 'str' is modified ! 455: * in these two cases. ! 456: */ ! 457: int special_case(str,default_str) ! 458: char *str; ! 459: char *default_str; ! 460: { ! 461: static char word[] = "none\n"; ! 462: char *ptr, *wordptr; ! 463: ! 464: /* ! 465: * If the default is accepted, then change the old string do the ! 466: * default string. ! 467: */ ! 468: if (*str == '\n') { ! 469: (void) strcpy(str, default_str); ! 470: return(1); ! 471: } ! 472: /* ! 473: * Check to see if str is 'none'. (It is questionable if case ! 474: * insensitivity is worth the hair). ! 475: */ ! 476: wordptr = word-1; ! 477: for (ptr=str; *ptr != '\0'; ++ptr) { ! 478: ++wordptr; ! 479: if (*wordptr == '\0') /* then words are different sizes */ ! 480: return(0); ! 481: if (*ptr == *wordptr) ! 482: continue; ! 483: if (isupper(*ptr) && (tolower(*ptr) == *wordptr)) ! 484: continue; ! 485: /* ! 486: * At this point we have a mismatch, so we return ! 487: */ ! 488: return(0); ! 489: } ! 490: /* ! 491: * Make sure that words are the same length. ! 492: */ ! 493: if (*(wordptr+1) != '\0') ! 494: return(0); ! 495: /* ! 496: * Change 'str' to be the null string ! 497: */ ! 498: *str = '\0'; ! 499: return(1); ! 500: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.