standardize sccs keyword lines
[unix-history] / usr / src / usr.bin / passwd / chfn.sh
CommitLineData
9e2ead69 1#ifndef lint
fb8f0ff2 2static char *sccsid = "@(#)chfn.sh 4.6 (Berkeley) %G%";
9e2ead69
KM
3#endif lint
4
64504187 5/*
9e2ead69 6 * changefinger - change finger entries
64504187
BJ
7 */
8#include <stdio.h>
9#include <signal.h>
10#include <pwd.h>
840fc587
SL
11#include <sys/time.h>
12#include <sys/resource.h>
9f52e30a 13#include <sys/file.h>
f1ad9148
KM
14#include <ctype.h>
15
16struct default_values {
17 char *name;
18 char *office_num;
19 char *office_phone;
20 char *home_phone;
21};
64504187
BJ
22
23char passwd[] = "/etc/passwd";
24char temp[] = "/etc/ptmp";
25struct passwd *pwd;
9e2ead69 26struct passwd *getpwent(), *getpwnam(), *getpwuid();
64504187
BJ
27int endpwent();
28char *crypt();
29char *getpass();
64504187
BJ
30
31main(argc, argv)
9e2ead69
KM
32 int argc;
33 char *argv[];
64504187 34{
9e2ead69 35 int user_uid;
f1ad9148 36 char replacement[4*BUFSIZ];
9f52e30a 37 int fd;
64504187
BJ
38 FILE *tf;
39
9e2ead69
KM
40 if (argc > 2) {
41 printf("Usage: changefinger [user]\n");
64504187
BJ
42 exit(1);
43 }
9e2ead69
KM
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);
64504187 60 }
9e2ead69
KM
61 if (pwd->pw_uid != user_uid) {
62 printf("%s%s",
63 "You are not allowed to change another",
f1ad9148 64 " person's finger entry.\n");
9e2ead69
KM
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 }
f1ad9148
KM
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 }
9e2ead69
KM
88 /*
89 * Collect name, room number, school phone, and home phone.
90 */
f1ad9148
KM
91 get_info(pwd->pw_gecos, replacement);
92
9e2ead69
KM
93 (void) signal(SIGHUP, SIG_IGN);
94 (void) signal(SIGINT, SIG_IGN);
95 (void) signal(SIGQUIT, SIG_IGN);
96 (void) signal(SIGTSTP, SIG_IGN);
fb8f0ff2 97 (void) umask(0);
9f52e30a
SL
98 if ((fd = open(temp, O_CREAT|O_EXCL|O_RDWR, 0644)) < 0) {
99 printf("Temporary file busy -- try again\n");
9e2ead69 100 exit(1);
64504187 101 }
9f52e30a
SL
102 if ((tf = fdopen(fd, "w")) == NULL) {
103 printf("Absurd fdopen failure - seek help\n");
9e2ead69
KM
104 goto out;
105 }
9f52e30a
SL
106 unlimit(RLIMIT_CPU);
107 unlimit(RLIMIT_FSIZE);
9e2ead69 108 /*
9f52e30a
SL
109 * Copy passwd to temp, replacing matching lines
110 * with new gecos field.
9e2ead69 111 */
9f52e30a
SL
112 while ((pwd = getpwent()) != NULL) {
113 if (pwd->pw_uid == user_uid)
9e2ead69 114 pwd->pw_gecos = replacement;
64504187
BJ
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 }
9e2ead69 124 (void) endpwent();
9f52e30a
SL
125 if (rename(temp, passwd) < 0) {
126 fprintf(stderr, "chfn: "); perror("rename");
127 out:
128 (void) unlink(temp);
129 exit(1);
64504187 130 }
9f52e30a
SL
131 (void) fclose(tf);
132 exit(0);
133}
134
135unlimit(lim)
136{
137 struct rlimit rlim;
138
139 rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
140 (void) setrlimit(lim, &rlim);
9e2ead69 141}
f1ad9148 142
9e2ead69
KM
143/*
144 * Get name, room number, school phone, and home phone.
145 */
f1ad9148
KM
146get_info(gecos_field, answer)
147 char *gecos_field;
9e2ead69
KM
148 char *answer;
149{
150 char *strcpy(), *strcat();
f1ad9148
KM
151 char in_str[BUFSIZ];
152 struct default_values *defaults, *get_defaults();
9e2ead69 153
f1ad9148
KM
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");
9e2ead69
KM
159 /*
160 * Get name.
161 */
162 do {
f1ad9148
KM
163 printf("\nName [%s]: ", defaults->name);
164 (void) fgets(in_str, BUFSIZ, stdin);
165 if (special_case(in_str, defaults->name))
166 break;
9e2ead69
KM
167 } while (illegal_input(in_str));
168 (void) strcpy(answer, in_str);
169 /*
170 * Get room number.
171 */
172 do {
f1ad9148
KM
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;
9e2ead69
KM
178 } while (illegal_input(in_str) || illegal_building(in_str));
179 (void) strcat(strcat(answer, ","), in_str);
180 /*
181 * Get office phone number.
f1ad9148 182 * Remove hyphens and 642, x2, or 2 prefixes if present.
9e2ead69
KM
183 */
184 do {
f1ad9148
KM
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;
9e2ead69
KM
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);
f1ad9148
KM
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));
9e2ead69
KM
199 (void) strcat(strcat(answer, ","), in_str);
200 /*
201 * Get home phone number.
202 * Remove hyphens if present.
203 */
204 do {
f1ad9148
KM
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;
9e2ead69 209 remove_hyphens(in_str);
f1ad9148 210 } while (illegal_input(in_str) || not_all_digits(in_str));
9e2ead69
KM
211 (void) strcat(strcat(answer, ","), in_str);
212}
f1ad9148 213
9e2ead69
KM
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"
f1ad9148 218 * field. Newlines serve as delimiters between users in the password file,
9e2ead69
KM
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 */
224illegal_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",
f1ad9148 239 BUFSIZ-2);
9e2ead69
KM
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 */
265remove_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}
64504187 274
f1ad9148
KM
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 */
279not_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
9e2ead69
KM
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 */
297wrong_length(str, n)
298 char *str;
299 int n;
300{
f1ad9148 301
9e2ead69
KM
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 */
320illegal_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);
64504187 369}
f1ad9148
KM
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 */
375struct 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 */
420int 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}