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