1: #ifndef lint
   2: static char *sccsid = "@(#)chfn.c	4.3 (Berkeley) 5/18/83";
   3: #endif lint
   4: 
   5: /*
   6:  *	 changefinger - change finger entries
   7:  */
   8: #include <whoami.h>
   9: #include <stdio.h>
  10: #include <signal.h>
  11: #include <pwd.h>
  12: #include <ctype.h>
  13: #include <sys/types.h>
  14: 
  15: struct default_values {
  16:     char *name;
  17:     char *office_num;
  18:     char *office_phone;
  19:     char *home_phone;
  20: };
  21: 
  22: char    passwd[] = "/etc/passwd";
  23: char    temp[]   = "/etc/ptmp";
  24: struct  passwd *pwd;
  25: struct  passwd *getpwent(), *getpwnam(), *getpwuid();
  26: int endpwent();
  27: char    *crypt();
  28: char    *getpass();
  29: char    buf[BUFSIZ];
  30: 
  31: main(argc, argv)
  32:     int argc;
  33:     char *argv[];
  34: {
  35:     int user_uid;
  36:     unsigned num_bytes;
  37:     int fi, fo;
  38:     char replacement[4*BUFSIZ];
  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, room number, school phone, and home phone.
  91: 	 */
  92:     get_info(pwd->pw_gecos, replacement);
  93: 
  94:     /*
  95: 	 * Update the entry in the password file.
  96: 	 */
  97:     while (access(temp, 0) >= 0) {
  98:         printf("Password file busy -- waiting for it to be free.\n");
  99:         sleep(10);
 100:     }
 101:     (void) signal(SIGHUP, SIG_IGN);
 102:     (void) signal(SIGINT, SIG_IGN);
 103:     (void) signal(SIGQUIT, SIG_IGN);
 104: #ifdef  MENLO_JCL
 105:     (void) signal(SIGTSTP, SIG_IGN);
 106: #endif
 107:     /*
 108: 	 * Race condition -- the locking mechinism is not my idea (ns)
 109: 	 */
 110:     if (access(temp, 0) >= 0) {
 111:         printf("It's not your day!  Password file is busy again.\n");
 112:         printf("Try again later.\n");
 113:         exit(1);
 114:     }
 115:     if ((tf=fopen(temp,"w")) == NULL) {
 116:         printf("Cannot create temporary file\n");
 117:         exit(1);
 118:     }
 119:     /*
 120: 	 * There is another race condition here:  if the passwd file
 121: 	 * has changed since the error checking at the beginning of the program,
 122: 	 * then user_uid may not be in the file.  Of course, the uid might have
 123: 	 * been changed, but this is not supposed to happen.
 124: 	 */
 125:     if (getpwuid(user_uid) == NULL) {
 126:         printf("%s%d%s\n", "Passwd file has changed. Uid ", user_uid,
 127:             " is no longer in the file!?");
 128:         goto out;
 129:     }
 130:     /*
 131: 	 * copy passwd to temp, replacing matching line
 132: 	 * with new finger entry (gecos field).
 133: 	 */
 134:     while ((pwd=getpwent()) != NULL) {
 135:         if (pwd->pw_uid == user_uid) {
 136:             pwd->pw_gecos = replacement;
 137:         }
 138:         fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
 139:             pwd->pw_name,
 140:             pwd->pw_passwd,
 141:             pwd->pw_uid,
 142:             pwd->pw_gid,
 143:             pwd->pw_gecos,
 144:             pwd->pw_dir,
 145:             pwd->pw_shell);
 146:     }
 147:     (void) endpwent();
 148:     (void) fclose(tf);
 149:     /*
 150: 	 * Copy temp back to password file.
 151: 	 */
 152:     if((fi=open(temp,0)) < 0) {
 153:         printf("Temp file disappeared!\n");
 154:         goto out;
 155:     }
 156:     if((fo=creat(passwd, 0644)) < 0) {
 157:         printf("Cannot recreat passwd file.\n");
 158:         goto out;
 159:     }
 160:     while((num_bytes=read(fi,buf,sizeof(buf))) > 0)
 161:         (void) write(fo,buf,num_bytes);
 162: out:
 163:     (void) unlink(temp);
 164: }
 165: 
 166: /*
 167:  * Get name, room number, school phone, and home phone.
 168:  */
 169: get_info(gecos_field, answer)
 170:     char *gecos_field;
 171:     char *answer;
 172: {
 173:     char *strcpy(), *strcat();
 174:     char in_str[BUFSIZ];
 175:     struct default_values *defaults, *get_defaults();
 176: 
 177:     answer[0] = '\0';
 178:     defaults = get_defaults(gecos_field);
 179:     printf("Default values are printed inside of of '[]'.\n");
 180:     printf("To accept the default, type <return>.\n");
 181:     printf("To have a blank entry, type the word 'none'.\n");
 182:     /*
 183: 	 * Get name.
 184: 	 */
 185:     do {
 186:         printf("\nName [%s]: ", defaults->name);
 187:         (void) fgets(in_str, BUFSIZ, stdin);
 188:         if (special_case(in_str, defaults->name))
 189:             break;
 190:     } while (ill_input(in_str));
 191:     (void) strcpy(answer, in_str);
 192:     /*
 193: 	 * Get room number.
 194: 	 */
 195:     do {
 196:         printf("Room number (Exs: 597E or 197C) [%s]: ",
 197:             defaults->office_num);
 198:         (void) fgets(in_str, BUFSIZ, stdin);
 199:         if (special_case(in_str, defaults->office_num))
 200:             break;
 201:     } while (ill_input(in_str) || ill_building(in_str));
 202:     (void) strcat(strcat(answer, ","), in_str);
 203:     /*
 204: 	 * Get office phone number.
 205: 	 * Remove hyphens and 642, x2, or 2 prefixes if present.
 206: 	 */
 207:     do {
 208:         printf("Office Phone (Ex: 1632) [%s]: ",
 209:             defaults->office_phone);
 210:         (void) fgets(in_str, BUFSIZ, stdin);
 211:         if (special_case(in_str, defaults->office_phone))
 212:             break;
 213:         remove_hyphens(in_str);
 214:         if ((strlen(in_str) == 8) && (strncmp(in_str, "642", 3) == 0))
 215:             (void) strcpy(in_str, in_str+3);
 216:         if ((strlen(in_str) == 7) && (strncmp(in_str, "x2", 2) == 0))
 217:             (void) strcpy(in_str, in_str+2);
 218:         if ((strlen(in_str) == 6) && (in_str[0] == '2'))
 219:             (void) strcpy(in_str, in_str+1);
 220:     } while (ill_input(in_str) || not_all_digits(in_str)
 221:          || wrong_length(in_str, 4));
 222:     (void) strcat(strcat(answer, ","), in_str);
 223:     /*
 224: 	 * Get home phone number.
 225: 	 * Remove hyphens if present.
 226: 	 */
 227:     do {
 228:         printf("Home Phone (Ex: 9875432) [%s]: ", defaults->home_phone);
 229:         (void) fgets(in_str, BUFSIZ, stdin);
 230:         if (special_case(in_str, defaults->home_phone))
 231:             break;
 232:         remove_hyphens(in_str);
 233:     } while (ill_input(in_str) || not_all_digits(in_str));
 234:     (void) strcat(strcat(answer, ","), in_str);
 235: }
 236: 
 237: /*
 238:  * Prints an error message if a ':' or a newline is found in the string.
 239:  * A message is also printed if the input string is too long.
 240:  * The password file uses :'s as seperators, and are not allowed in the "gcos"
 241:  * field.  Newlines serve as delimiters between users in the password file,
 242:  * and so, those too, are checked for.  (I don't think that it is possible to
 243:  * type them in, but better safe than sorry)
 244:  *
 245:  * Returns '1' if a colon or newline is found or the input line is too long.
 246:  */
 247: ill_input(input_str)
 248:     char *input_str;
 249: {
 250:     char *index();
 251:     char *ptr;
 252:     int error_flag = 0;
 253:     int length = strlen(input_str);
 254: 
 255:     if (index(input_str, ':')) {
 256:         printf("':' is not allowed.\n");
 257:         error_flag = 1;
 258:     }
 259:     if (input_str[length-1] != '\n') {
 260:         /* the newline and the '\0' eat up two characters */
 261:         printf("Maximum number of characters allowed is %d\n",
 262:             BUFSIZ-2);
 263:         /* flush the rest of the input line */
 264:         while (getchar() != '\n')
 265:             /* void */;
 266:         error_flag = 1;
 267:     }
 268:     /*
 269: 	 * Delete newline by shortening string by 1.
 270: 	 */
 271:     input_str[length-1] = '\0';
 272:     /*
 273: 	 * Don't allow control characters, etc in input string.
 274: 	 */
 275:     for (ptr=input_str; *ptr != '\0'; ptr++) {
 276:         if ((int) *ptr < 040) {
 277:             printf("Control characters are not allowed.\n");
 278:             error_flag = 1;
 279:             break;
 280:         }
 281:     }
 282:     return(error_flag);
 283: }
 284: 
 285: /*
 286:  * Removes '-'s from the input string.
 287:  */
 288: remove_hyphens(str)
 289:     char *str;
 290: {
 291:     char *hyphen, *index(), *strcpy();
 292: 
 293:     while ((hyphen=index(str, '-')) != NULL) {
 294:         (void) strcpy(hyphen, hyphen+1);
 295:     }
 296: }
 297: 
 298: /*
 299:  *  Checks to see if 'str' contains only digits (0-9).  If not, then
 300:  *  an error message is printed and '1' is returned.
 301:  */
 302: not_all_digits(str)
 303:     char *str;
 304: {
 305:     char *ptr;
 306: 
 307:     for (ptr=str; *ptr != '\0'; ++ptr) {
 308:         if (!isdigit(*ptr)) {
 309:             printf("Phone numbers can only contain digits.\n");
 310:             return(1);
 311:         }
 312:     }
 313:     return(0);
 314: }
 315: 
 316: /*
 317:  * Returns 1 when the length of the input string is not zero or equal to n.
 318:  * Prints an error message in this case.
 319:  */
 320: wrong_length(str, n)
 321:     char *str;
 322:     int n;
 323: {
 324: 
 325:     if ((strlen(str) != 0) && (strlen(str) != n)) {
 326:         printf("The phone number should be %d digits long.\n", n);
 327:         return(1);
 328:     }
 329:     return(0);
 330: }
 331: 
 332: /*
 333:  * Make sure that building is 'E' or 'C'.
 334:  * Error correction is done if building is 'e', 'c', "evans", or "cory".
 335:  * Correction changes "str".
 336:  * The finger program determines the building by looking at the last
 337:  * character.  Currently, finger only allows that character to be 'E' or 'C'.
 338:  *
 339:  * Returns 1 if incorrect room format.
 340:  *
 341:  * Note: this function assumes that the newline has been removed from str.
 342:  */
 343: ill_building(str)
 344:     char *str;
 345: {
 346:     int length = strlen(str);
 347:     char *last_ch, *ptr;
 348: 
 349:     /*
 350: 	 * Zero length strings are acceptable input.
 351: 	 */
 352:     if (length == 0)
 353:         return(0);
 354:     /*
 355: 	 * Delete "vans" and "ory".
 356: 	 */
 357:     if (strncmp(str+length-4, "vans", 4) == 0) {
 358:         length -= 4;
 359:         str[length] = '\0';
 360:     }
 361:     if (strncmp(str+length-3, "ory", 3) == 0) {
 362:         length -= 3;
 363:         str[length] = '\0';
 364:     }
 365:     last_ch = str+length-1;
 366:     /*
 367: 	 * Now change e to E or c to C.
 368: 	 */
 369:     if (*last_ch == 'e')
 370:         *last_ch = 'E';
 371:     if (*last_ch == 'c')
 372:         *last_ch = 'C';
 373:     /*
 374: 	 * Delete any spaces before the E or C.
 375: 	 */
 376:     for (ptr=last_ch-1; ptr>str; ptr--) {
 377:         if (*ptr != ' ')
 378:             break;
 379:     }
 380:     (void) strcpy(ptr+1, last_ch);
 381:     /*
 382: 	 * Make sure building is evans or cory.
 383: 	 */
 384:     if ((*last_ch != 'E') && (*last_ch != 'C')) {
 385:         printf("%s%s%s",
 386:             "The finger program requires that your",
 387:             " office be in Cory or Evans.\n",
 388:             "Enter this as (for example) 597E or 197C.\n");
 389:         return(1);
 390:     }
 391:     return(0);
 392: }
 393: 
 394: /* get_defaults picks apart "str" and returns a structure points.
 395:  * "str" contains up to 4 fields separated by commas.
 396:  * Any field that is missing is set to blank.
 397:  */
 398: struct default_values
 399: *get_defaults(str)
 400:     char *str;
 401: {
 402:     struct default_values *answer;
 403:     char *malloc(), *index();
 404: 
 405:     answer = (struct default_values *)
 406:         malloc((unsigned)sizeof(struct default_values));
 407:     if (answer == (struct default_values *) NULL) {
 408:         fprintf(stderr,
 409:             "\nUnable to allocate storage in get_defaults!\n");
 410:         exit(1);
 411:     }
 412:     /*
 413: 	 * Values if no corresponding string in "str".
 414: 	 */
 415:     answer->name = str;
 416:     answer->office_num = "";
 417:     answer->office_phone = "";
 418:     answer->home_phone = "";
 419:     str = index(answer->name, ',');
 420:     if (str == 0)
 421:         return(answer);
 422:     *str = '\0';
 423:     answer->office_num = str + 1;
 424:     str = index(answer->office_num, ',');
 425:     if (str == 0)
 426:         return(answer);
 427:     *str = '\0';
 428:     answer->office_phone = str + 1;
 429:     str = index(answer->office_phone, ',');
 430:     if (str == 0)
 431:         return(answer);
 432:     *str = '\0';
 433:     answer->home_phone = str + 1;
 434:     return(answer);
 435: }
 436: 
 437: /*
 438:  *  special_case returns true when either the default is accepted
 439:  *  (str = '\n'), or when 'none' is typed.  'none' is accepted in
 440:  *  either upper or lower case (or any combination).  'str' is modified
 441:  *  in these two cases.
 442:  */
 443: int special_case(str,default_str)
 444:     char *str;
 445:     char *default_str;
 446: {
 447:     static char word[] = "none\n";
 448:     char *ptr, *wordptr;
 449: 
 450:     /*
 451: 	 *  If the default is accepted, then change the old string do the
 452: 	 *  default string.
 453: 	 */
 454:     if (*str == '\n') {
 455:         (void) strcpy(str, default_str);
 456:         return(1);
 457:     }
 458:     /*
 459: 	 *  Check to see if str is 'none'.  (It is questionable if case
 460: 	 *  insensitivity is worth the hair).
 461: 	 */
 462:     wordptr = word-1;
 463:     for (ptr=str; *ptr != '\0'; ++ptr) {
 464:         ++wordptr;
 465:         if (*wordptr == '\0')   /* then words are different sizes */
 466:             return(0);
 467:         if (*ptr == *wordptr)
 468:             continue;
 469:         if (isupper(*ptr) && (tolower(*ptr) == *wordptr))
 470:             continue;
 471:         /*
 472: 		 * At this point we have a mismatch, so we return
 473: 		 */
 474:         return(0);
 475:     }
 476:     /*
 477: 	 * Make sure that words are the same length.
 478: 	 */
 479:     if (*(wordptr+1) != '\0')
 480:         return(0);
 481:     /*
 482: 	 * Change 'str' to be the null string
 483: 	 */
 484:     *str = '\0';
 485:     return(1);
 486: }

Defined functions

get_defaults defined in line 398; used 2 times
get_info defined in line 169; used 1 times
  • in line 92
ill_building defined in line 343; used 1 times
ill_input defined in line 247; used 4 times
main defined in line 31; never used
not_all_digits defined in line 302; used 2 times
remove_hyphens defined in line 288; used 2 times
special_case defined in line 443; used 4 times
wrong_length defined in line 320; used 1 times

Defined variables

buf defined in line 29; used 3 times
passwd defined in line 22; used 1 times
pwd defined in line 24; used 20 times
sccsid defined in line 2; never used
temp defined in line 23; used 5 times

Defined struct's

default_values defined in line 15; used 12 times
Last modified: 1983-06-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 982
Valid CSS Valid XHTML 1.0 Strict