1#ifndef lint 2static char *sccsid = "@(#)chfn.sh 4.2 (Berkeley) 05/03/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 12char passwd[] = "/etc/passwd"; 13char temp[] = "/etc/ptmp"; 14struct passwd *pwd; 15struct passwd *getpwent(), *getpwnam(), *getpwuid(); 16int endpwent(); 17char *crypt(); 18char *getpass(); 19char buf[BUFSIZ]; 20 21#define MAX_STR 52 22main(argc, argv) 23 int argc; 24 char *argv[]; 25{ 26 int user_uid; 27 int num_bytes, fi, fo; 28 char replacement[4*MAX_STR]; 29 FILE *tf; 30 31 if (argc > 2) { 32 printf("Usage: changefinger [user]\n"); 33 exit(1); 34 } 35 /* 36 * Error check to make sure the user (foolishly) typed their own name. 37 */ 38 user_uid = getuid(); 39 if ((argc == 2) && (user_uid != 0)) { 40 pwd = getpwnam(argv[1]); 41 if (pwd == NULL) { 42 printf("%s%s%s%s%s%s%s%s", 43 "There is no account for ", argv[1], 44 " on this machine.\n", 45 "You probably mispelled your login name;\n", 46 "only root is allowed to change another", 47 " person's finger entry.\n", 48 "Note: you do not need to type your login", 49 " name as an argument.\n"); 50 exit(1); 51 } 52 if (pwd->pw_uid != user_uid) { 53 printf("%s%s", 54 "You are not allowed to change another", 55 " person's password entry.\n"); 56 exit(1); 57 } 58 } 59 /* 60 * If root is changing a finger entry, then find the uid that 61 * corresponds to the user's login name. 62 */ 63 if ((argc == 2) && (user_uid == 0)) { 64 pwd = getpwnam(argv[1]); 65 if (pwd == NULL) { 66 printf("There is no account for %s on this machine\n", 67 pwd->pw_name); 68 exit(1); 69 } 70 user_uid = pwd->pw_uid; 71 } 72 /* 73 * Collect name, room number, school phone, and home phone. 74 */ 75 get_info(replacement); 76 /* 77 * Update the entry in the password file. 78 */ 79 while (access(temp, 0) >= 0) { 80 printf("Password file busy -- waiting for it to be free.\n"); 81 sleep(10); 82 } 83 (void) signal(SIGHUP, SIG_IGN); 84 (void) signal(SIGINT, SIG_IGN); 85 (void) signal(SIGQUIT, SIG_IGN); 86 (void) signal(SIGTSTP, SIG_IGN); 87 /* 88 * Race condition -- the locking mechinism is not my idea (ns) 89 */ 90 if(access(temp, 0) >= 0) { 91 printf("It's not your day! Password file is busy again.\n"); 92 printf("Try again later.\n"); 93 exit(1); 94 } 95 if((tf=fopen(temp,"w")) == NULL) { 96 printf("Cannot create temporary file\n"); 97 exit(1); 98 } 99 /* 100 * There is another race condition here: if the passwd file 101 * has changed since the error checking at the beginning of the program, 102 * then user_uid may not be in the file. Of course, the uid might have 103 * been changed, but this is not supposed to happen. 104 */ 105 if (getpwuid(user_uid) == NULL) { 106 printf("%s%d%s\n", "Passwd file has changed. Uid ", user_uid, 107 " is no longer in the file!?"); 108 goto out; 109 } 110 /* 111 * copy passwd to temp, replacing matching line 112 * with new finger entry (gecos field). 113 */ 114 while((pwd=getpwent()) != NULL) { 115 if(pwd->pw_uid == user_uid) { 116 pwd->pw_gecos = replacement; 117 } 118 fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n", 119 pwd->pw_name, 120 pwd->pw_passwd, 121 pwd->pw_uid, 122 pwd->pw_gid, 123 pwd->pw_gecos, 124 pwd->pw_dir, 125 pwd->pw_shell); 126 } 127 (void) endpwent(); 128 (void) fclose(tf); 129 /* 130 * Copy temp back to password file. 131 */ 132 if((fi=open(temp,0)) < 0) { 133 printf("Temp file disappeared!\n"); 134 goto out; 135 } 136 if((fo=creat(passwd, 0644)) < 0) { 137 printf("Cannot recreat passwd file.\n"); 138 goto out; 139 } 140 while((num_bytes=read(fi,buf,sizeof(buf))) > 0) 141 (void) write(fo,buf,num_bytes); 142out: 143 (void) unlink(temp); 144} 145 146/* 147 * Get name, room number, school phone, and home phone. 148 */ 149get_info(answer) 150 char *answer; 151{ 152 char *strcpy(), *strcat(); 153 char in_str[MAX_STR]; 154 answer[0] = '\0'; 155 156 /* 157 * Get name. 158 */ 159 do { 160 printf("\nName: "); 161 (void) fgets(in_str, MAX_STR, stdin); 162 } while (illegal_input(in_str)); 163 (void) strcpy(answer, in_str); 164 /* 165 * Get room number. 166 */ 167 do { 168 printf("Room number (Exs: 597E or 197C): "); 169 (void) fgets(in_str, MAX_STR, stdin); 170 } while (illegal_input(in_str) || illegal_building(in_str)); 171 (void) strcat(strcat(answer, ","), in_str); 172 /* 173 * Get office phone number. 174 * Remove hyphens and 642 or x2 prefixes if present. 175 */ 176 do { 177 printf("Office Phone (Ex: 1632): "); 178 (void) fgets(in_str, MAX_STR, stdin); 179 remove_hyphens(in_str); 180 if ((strlen(in_str) == 8) && (strcmpn(in_str, "642", 3) == 0)) 181 (void) strcpy(in_str, in_str+3); 182 if ((strlen(in_str) == 7) && (strcmpn(in_str, "x2", 2) == 0)) 183 (void) strcpy(in_str, in_str+2); 184 } while ((illegal_input(in_str)) || wrong_length(in_str, 4)); 185 (void) strcat(strcat(answer, ","), in_str); 186 /* 187 * Get home phone number. 188 * Remove hyphens if present. 189 */ 190 do { 191 printf("Home Phone (Ex: 9875432): "); 192 (void) fgets(in_str, MAX_STR, stdin); 193 remove_hyphens(in_str); 194 } while (illegal_input(in_str)); 195 (void) strcat(strcat(answer, ","), in_str); 196} 197 198/* 199 * Prints an error message if a ':' or a newline is found in the string. 200 * A message is also printed if the input string is too long. 201 * The password file uses :'s as seperators, and are not allowed in the "gcos" 202 * field. Newlines serve a delimiters between users in the password file, 203 * and so, those too, are checked for. (I don't think that it is possible to 204 * type them in, but better safe than sorry) 205 * 206 * Returns '1' if a colon or newline is found or the input line is too long. 207 */ 208illegal_input(input_str) 209 char *input_str; 210{ 211 char *index(); 212 char *ptr; 213 int error_flag = 0; 214 int length = strlen(input_str); 215 216 if (index(input_str, ':')) { 217 printf("':' is not allowed.\n"); 218 error_flag = 1; 219 } 220 if (input_str[length-1] != '\n') { 221 /* the newline and the '\0' eat up two characters */ 222 printf("Maximum number of characters allowed is %d\n", 223 MAX_STR-2); 224 /* flush the rest of the input line */ 225 while (getchar() != '\n') 226 /* void */; 227 error_flag = 1; 228 } 229 /* 230 * Delete newline by shortening string by 1. 231 */ 232 input_str[length-1] = '\0'; 233 /* 234 * Don't allow control characters, etc in input string. 235 */ 236 for (ptr=input_str; *ptr != '\0'; ptr++) { 237 if ((int) *ptr < 040) { 238 printf("Control characters are not allowed.\n"); 239 error_flag = 1; 240 break; 241 } 242 } 243 return(error_flag); 244} 245 246/* 247 * Removes '-'s from the input string. 248 */ 249remove_hyphens(str) 250 char *str; 251{ 252 char *hyphen, *index(), *strcpy(); 253 254 while ((hyphen=index(str, '-')) != NULL) { 255 (void) strcpy(hyphen, hyphen+1); 256 } 257} 258 259/* 260 * Returns 1 when the length of the input string is not zero or equal to n. 261 * Prints an error message in this case. 262 */ 263wrong_length(str, n) 264 char *str; 265 int n; 266{ 267 if ((strlen(str) != 0) && (strlen(str) != n)) { 268 printf("The phone number should be %d digits long.\n", n); 269 return(1); 270 } 271 return(0); 272} 273 274/* 275 * Make sure that building is 'E' or 'C'. 276 * Error correction is done if building is 'e', 'c', "evans", or "cory". 277 * Correction changes "str". 278 * The finger program determines the building by looking at the last 279 * character. Currently, finger only allows that character to be 'E' or 'C'. 280 * 281 * Returns 1 if incorrect room format. 282 * 283 * Note: this function assumes that the newline has been removed from str. 284 */ 285illegal_building(str) 286 char *str; 287{ 288 int length = strlen(str); 289 char *last_ch, *ptr; 290 291 /* 292 * Zero length strings are acceptable input. 293 */ 294 if (length == 0) 295 return(0); 296 /* 297 * Delete "vans" and "ory". 298 */ 299 if (strcmpn(str+length-4, "vans", 4) == 0) { 300 length -= 4; 301 str[length] = '\0'; 302 } 303 if (strcmpn(str+length-3, "ory", 3) == 0) { 304 length -= 3; 305 str[length] = '\0'; 306 } 307 last_ch = str+length-1; 308 /* 309 * Now change e to E or c to C. 310 */ 311 if (*last_ch == 'e') 312 *last_ch = 'E'; 313 if (*last_ch == 'c') 314 *last_ch = 'C'; 315 /* 316 * Delete any spaces before the E or C. 317 */ 318 for (ptr=last_ch-1; ptr>str; ptr--) { 319 if (*ptr != ' ') 320 break; 321 } 322 (void) strcpy(ptr+1, last_ch); 323 /* 324 * Make sure building is evans or cory. 325 */ 326 if ((*last_ch != 'E') && (*last_ch != 'C')) { 327 printf("%s%s%s", 328 "The finger program requires that your", 329 " office be in Cory or Evans.\n", 330 "Enter this as (for example) 597E or 197C.\n"); 331 return(1); 332 } 333 return(0); 334} 335