Commit | Line | Data |
---|---|---|
1f978f4c KM |
1 | /* |
2 | * Copyright (c) 1983 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
8 | char copyright[] = | |
9 | "@(#) Copyright (c) 1983 Regents of the University of California.\n\ | |
10 | All rights reserved.\n"; | |
11 | #endif not lint | |
12 | ||
252e456d | 13 | #ifndef lint |
163e5fbf | 14 | static char sccsid[] = "@(#)passwd.c 4.32 (Berkeley) %G%"; |
1f978f4c | 15 | #endif not lint |
252e456d SL |
16 | |
17 | /* | |
868cd94a KB |
18 | * Modify a field in the password file (either password, login shell, or |
19 | * gecos field). This program should be suid with an owner with write | |
20 | * permission on /etc/passwd. | |
252e456d | 21 | */ |
6afaba66 | 22 | #include <sys/types.h> |
252e456d | 23 | #include <sys/file.h> |
868cd94a | 24 | #include <sys/stat.h> |
844df0cd RC |
25 | #include <sys/time.h> |
26 | #include <sys/resource.h> | |
252e456d SL |
27 | |
28 | #include <stdio.h> | |
29 | #include <signal.h> | |
30 | #include <pwd.h> | |
9ae20471 | 31 | #include <ndbm.h> |
252e456d | 32 | #include <errno.h> |
844df0cd RC |
33 | #include <strings.h> |
34 | #include <ctype.h> | |
252e456d | 35 | |
6afaba66 KM |
36 | /* |
37 | * This should be the first thing returned from a getloginshells() | |
38 | * but too many programs know that it is /bin/sh. | |
39 | */ | |
868cd94a KB |
40 | #define DEFSHELL "/bin/sh" |
41 | ||
42 | #define DICT "/usr/dict/words" | |
43 | #define PASSWD "/etc/passwd" | |
44 | #define PTEMP "/etc/ptmp" | |
45 | ||
46 | #define EOS '\0'; | |
252e456d SL |
47 | |
48 | main(argc, argv) | |
868cd94a KB |
49 | int argc; |
50 | char **argv; | |
252e456d | 51 | { |
868cd94a KB |
52 | extern char *optarg; |
53 | extern int errno, optind; | |
54 | struct passwd *pwd; | |
55 | FILE *tf; | |
56 | DBM *dp; | |
57 | uid_t uid, getuid(); | |
58 | int ch, fd, dochfn, dochsh; | |
59 | char *cp, *uname, *progname, *umsg, | |
60 | *getfingerinfo(), *getloginshell(), *getnewpasswd(), *malloc(); | |
61 | ||
62 | progname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; | |
63 | dochfn = dochsh = 0; | |
64 | if (!strcmp(progname, "chfn")) { | |
65 | dochfn = 1; | |
66 | umsg = "usage: chfn [username]\n"; | |
67 | } | |
68 | else if (!strcmp(progname, "chsh")) { | |
69 | dochsh = 1; | |
70 | umsg = "usage: chsh [username]\n"; | |
71 | } | |
a1b0286d | 72 | else |
868cd94a | 73 | umsg = "usage: passwd [-fs] [username]\n"; |
844df0cd | 74 | |
868cd94a KB |
75 | while ((ch = getopt(argc, argv, "fs")) != EOF) |
76 | switch((char)ch) { | |
844df0cd RC |
77 | case 'f': |
78 | if (dochsh) | |
868cd94a | 79 | goto usage; |
844df0cd RC |
80 | dochfn = 1; |
81 | break; | |
844df0cd | 82 | case 's': |
868cd94a KB |
83 | if (dochfn) |
84 | goto usage; | |
844df0cd RC |
85 | dochsh = 1; |
86 | break; | |
868cd94a | 87 | case '?': |
844df0cd | 88 | default: |
868cd94a | 89 | usage: fputs(umsg, stderr); |
844df0cd RC |
90 | exit(1); |
91 | } | |
868cd94a KB |
92 | |
93 | uid = getuid(); | |
94 | if (argc - optind < 1) { | |
95 | if (!(pwd = getpwuid(uid))) { | |
96 | fprintf(stderr, "%s: %u: unknown user uid.\n", progname, uid); | |
97 | exit(1); | |
98 | } | |
99 | if (!(uname = malloc((u_int)(strlen(pwd->pw_name) + 1)))) { | |
100 | fprintf(stderr, "%s: out of space.\n", progname); | |
101 | exit(1); | |
102 | } | |
103 | (void)strcpy(uname, pwd->pw_name); | |
bc9b6b15 | 104 | } |
868cd94a KB |
105 | else { |
106 | uname = *(argv + optind); | |
107 | if (!(pwd = getpwnam(uname))) { | |
108 | fprintf(stderr, "%s: %s: unknown user.\n", progname, uname); | |
109 | exit(1); | |
110 | } | |
05e78391 | 111 | } |
868cd94a KB |
112 | if (uid && uid != pwd->pw_uid) { |
113 | fputs("Permission denied.\n", stderr); | |
252e456d SL |
114 | exit(1); |
115 | } | |
868cd94a | 116 | printf("Changing %s for %s.\n", dochfn ? "finger information" : dochsh ? "login shell" : "password", uname); |
844df0cd | 117 | if (dochfn) |
bd94915c | 118 | cp = getfingerinfo(pwd); |
844df0cd | 119 | else if (dochsh) |
868cd94a | 120 | cp = getloginshell(pwd, uid); |
844df0cd | 121 | else |
868cd94a | 122 | cp = getnewpasswd(pwd, uid); |
bd94915c KM |
123 | (void) signal(SIGHUP, SIG_IGN); |
124 | (void) signal(SIGINT, SIG_IGN); | |
125 | (void) signal(SIGQUIT, SIG_IGN); | |
126 | (void) signal(SIGTSTP, SIG_IGN); | |
643bb829 | 127 | (void) umask(0); |
868cd94a KB |
128 | if ((fd = open(PTEMP, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { |
129 | if (errno == EEXIST) | |
130 | fprintf(stderr, "%s: password file busy - try again.\n", progname); | |
ba9597f7 | 131 | else { |
868cd94a KB |
132 | fprintf(stderr, "%s: %s: ", progname, PTEMP); |
133 | perror((char *)NULL); | |
ba9597f7 | 134 | } |
252e456d SL |
135 | exit(1); |
136 | } | |
252e456d | 137 | if ((tf = fdopen(fd, "w")) == NULL) { |
868cd94a | 138 | fprintf(stderr, "%s: fdopen failed.\n", progname); |
252e456d SL |
139 | exit(1); |
140 | } | |
868cd94a KB |
141 | if ((dp = dbm_open(PASSWD, O_RDWR, 0644)) == NULL) { |
142 | fprintf(stderr, "Warning: dbm_open failed: %s: ", PASSWD); | |
143 | perror((char *)NULL); | |
144 | } | |
145 | else if (flock(dp->dbm_dirf, LOCK_EX) < 0) { | |
9ae20471 | 146 | perror("Warning: lock failed"); |
844df0cd | 147 | dbm_close(dp); |
9ae20471 RC |
148 | dp = NULL; |
149 | } | |
844df0cd RC |
150 | unlimit(RLIMIT_CPU); |
151 | unlimit(RLIMIT_FSIZE); | |
252e456d SL |
152 | /* |
153 | * Copy passwd to temp, replacing matching lines | |
154 | * with new password. | |
155 | */ | |
156 | while ((pwd = getpwent()) != NULL) { | |
868cd94a KB |
157 | if (!strcmp(pwd->pw_name, uname)) { |
158 | if (uid && uid != pwd->pw_uid) { | |
159 | fprintf(stderr, "%s: permission denied.\n", progname); | |
8d3b95af | 160 | goto out; |
252e456d | 161 | } |
844df0cd RC |
162 | if (dochfn) |
163 | pwd->pw_gecos = cp; | |
164 | else if (dochsh) | |
165 | pwd->pw_shell = cp; | |
166 | else | |
167 | pwd->pw_passwd = cp; | |
168 | if (pwd->pw_gecos[0] == '*') /* ??? */ | |
252e456d | 169 | pwd->pw_gecos++; |
9ae20471 | 170 | replace(dp, pwd); |
252e456d | 171 | } |
868cd94a | 172 | fprintf(tf, "%s:%s:%d:%d:%s:%s:%s\n", |
252e456d SL |
173 | pwd->pw_name, |
174 | pwd->pw_passwd, | |
175 | pwd->pw_uid, | |
176 | pwd->pw_gid, | |
177 | pwd->pw_gecos, | |
178 | pwd->pw_dir, | |
179 | pwd->pw_shell); | |
180 | } | |
181 | endpwent(); | |
868cd94a KB |
182 | if (dp && dbm_error(dp)) |
183 | fputs("Warning: dbm_store failed.\n", stderr); | |
bd94915c | 184 | (void) fflush(tf); |
183d82a9 | 185 | if (ferror(tf)) { |
868cd94a KB |
186 | fprintf(stderr, "Warning: %s write error, %s not updated.\n", |
187 | PTEMP, PASSWD); | |
183d82a9 RE |
188 | goto out; |
189 | } | |
868cd94a | 190 | (void)fclose(tf); |
eb635a62 KM |
191 | if (dp != NULL) |
192 | dbm_close(dp); | |
868cd94a KB |
193 | if (rename(PTEMP, PASSWD) < 0) { |
194 | perror(progname); | |
9ae20471 | 195 | out: |
868cd94a | 196 | (void)unlink(PTEMP); |
9ae20471 RC |
197 | exit(1); |
198 | } | |
199 | exit(0); | |
8d3b95af RC |
200 | } |
201 | ||
844df0cd | 202 | unlimit(lim) |
868cd94a | 203 | int lim; |
844df0cd RC |
204 | { |
205 | struct rlimit rlim; | |
206 | ||
207 | rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; | |
868cd94a | 208 | (void)setrlimit(lim, &rlim); |
844df0cd RC |
209 | } |
210 | ||
9ae20471 RC |
211 | /* |
212 | * Replace the password entry in the dbm data base with pwd. | |
213 | */ | |
214 | replace(dp, pwd) | |
215 | DBM *dp; | |
216 | struct passwd *pwd; | |
8d3b95af | 217 | { |
9ae20471 RC |
218 | datum key, content; |
219 | register char *cp, *tp; | |
220 | char buf[BUFSIZ]; | |
8d3b95af | 221 | |
9ae20471 RC |
222 | if (dp == NULL) |
223 | return; | |
224 | ||
225 | cp = buf; | |
a59237a4 KB |
226 | #define COMPACT(e) tp = pwd->e; while (*cp++ = *tp++); |
227 | COMPACT(pw_name); | |
228 | COMPACT(pw_passwd); | |
3c92851f RC |
229 | bcopy((char *)&pwd->pw_uid, cp, sizeof (int)); |
230 | cp += sizeof (int); | |
231 | bcopy((char *)&pwd->pw_gid, cp, sizeof (int)); | |
232 | cp += sizeof (int); | |
233 | bcopy((char *)&pwd->pw_quota, cp, sizeof (int)); | |
234 | cp += sizeof (int); | |
a59237a4 KB |
235 | COMPACT(pw_comment); |
236 | COMPACT(pw_gecos); | |
237 | COMPACT(pw_dir); | |
238 | COMPACT(pw_shell); | |
9ae20471 RC |
239 | content.dptr = buf; |
240 | content.dsize = cp - buf; | |
241 | key.dptr = pwd->pw_name; | |
242 | key.dsize = strlen(pwd->pw_name); | |
844df0cd | 243 | dbm_store(dp, key, content, DBM_REPLACE); |
9ae20471 RC |
244 | key.dptr = (char *)&pwd->pw_uid; |
245 | key.dsize = sizeof (int); | |
844df0cd RC |
246 | dbm_store(dp, key, content, DBM_REPLACE); |
247 | } | |
248 | ||
249 | char * | |
250 | getnewpasswd(pwd, u) | |
251 | register struct passwd *pwd; | |
868cd94a | 252 | uid_t u; |
844df0cd | 253 | { |
868cd94a KB |
254 | time_t salt, time(); |
255 | int c, i, insist; | |
256 | char *pw, pwbuf[10], pwcopy[10], saltc[2], | |
257 | *crypt(), *getpass(); | |
844df0cd RC |
258 | |
259 | if (pwd->pw_passwd[0] && u != 0) { | |
868cd94a | 260 | (void)strcpy(pwbuf, getpass("Old password:")); |
844df0cd RC |
261 | pw = crypt(pwbuf, pwd->pw_passwd); |
262 | if (strcmp(pw, pwd->pw_passwd) != 0) { | |
868cd94a | 263 | puts("Sorry."); |
844df0cd RC |
264 | exit(1); |
265 | } | |
266 | } | |
868cd94a KB |
267 | for(;;) { |
268 | (void)strcpy(pwbuf, getpass("New password:")); | |
269 | if (!*pwbuf) { | |
270 | puts("Password unchanged."); | |
271 | exit(1); | |
272 | } | |
273 | if (strcmp(pwbuf, pwcopy)) { | |
274 | insist = 1; | |
275 | (void)strcpy(pwcopy, pwbuf); | |
276 | } | |
277 | else if (++insist == 4) | |
278 | break; | |
bce52146 KB |
279 | if (strlen(pwbuf) <= 4) |
280 | puts("Please enter a longer password."); | |
163e5fbf KB |
281 | else { |
282 | for (pw = pwbuf; *pw && islower(*pw); ++pw); | |
283 | if (*pw) | |
284 | break; | |
285 | puts("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested."); | |
286 | } | |
844df0cd | 287 | } |
bce52146 | 288 | if (strcmp(pwbuf, getpass("Retype new password:"))) { |
868cd94a | 289 | puts("Mismatch - password unchanged."); |
844df0cd RC |
290 | exit(1); |
291 | } | |
868cd94a | 292 | (void)time(&salt); |
844df0cd RC |
293 | salt = 9 * getpid(); |
294 | saltc[0] = salt & 077; | |
295 | saltc[1] = (salt>>6) & 077; | |
296 | for (i = 0; i < 2; i++) { | |
297 | c = saltc[i] + '.'; | |
298 | if (c > '9') | |
299 | c += 7; | |
300 | if (c > 'Z') | |
301 | c += 6; | |
302 | saltc[i] = c; | |
303 | } | |
868cd94a | 304 | return(crypt(pwbuf, saltc)); |
844df0cd RC |
305 | } |
306 | ||
844df0cd | 307 | char * |
868cd94a | 308 | getloginshell(pwd, u) |
844df0cd | 309 | struct passwd *pwd; |
868cd94a | 310 | uid_t u; |
844df0cd | 311 | { |
6afaba66 KM |
312 | static char newshell[BUFSIZ]; |
313 | char *cp, *valid, *getusershell(); | |
844df0cd RC |
314 | |
315 | if (pwd->pw_shell == 0 || *pwd->pw_shell == '\0') | |
316 | pwd->pw_shell = DEFSHELL; | |
7bffa124 | 317 | if (u != 0) { |
920e234e KB |
318 | do { |
319 | valid = getusershell(); | |
320 | if (valid == NULL) { | |
321 | printf("Cannot change from restricted shell %s\n", | |
322 | pwd->pw_shell); | |
323 | exit(1); | |
324 | } | |
325 | } while (strcmp(pwd->pw_shell, valid) != 0); | |
7bffa124 | 326 | } |
868cd94a KB |
327 | printf("Old shell: %s\nNew shell: ", pwd->pw_shell); |
328 | (void)fgets(newshell, sizeof (newshell) - 1, stdin); | |
329 | cp = index(newshell, '\n'); | |
330 | if (cp) | |
331 | *cp = '\0'; | |
332 | if (newshell[0] == 0) { | |
333 | puts("Login shell unchanged."); | |
334 | exit(1); | |
844df0cd RC |
335 | } |
336 | /* | |
337 | * Allow user to give shell name w/o preceding pathname. | |
338 | */ | |
920e234e KB |
339 | if (u != 0 || newshell[0] != '/') { |
340 | endusershell(); | |
341 | do { | |
342 | valid = getusershell(); | |
343 | if (valid == 0) { | |
344 | if (u == 0) { | |
345 | valid = newshell; | |
346 | break; | |
347 | } | |
348 | printf("%s is unacceptable as a new shell.\n", | |
349 | newshell); | |
350 | exit(1); | |
351 | } | |
6afaba66 KM |
352 | if (newshell[0] == '/') { |
353 | cp = valid; | |
354 | } else { | |
355 | cp = rindex(valid, '/'); | |
356 | if (cp == 0) | |
357 | cp = valid; | |
358 | else | |
359 | cp++; | |
360 | } | |
920e234e | 361 | } while (strcmp(newshell, cp) != 0); |
844df0cd | 362 | } |
868cd94a KB |
363 | else |
364 | valid = newshell; | |
920e234e KB |
365 | if (strcmp(valid, pwd->pw_shell) == 0) { |
366 | puts("Login shell unchanged."); | |
844df0cd RC |
367 | exit(1); |
368 | } | |
6afaba66 KM |
369 | if (access(valid, X_OK) < 0) { |
370 | printf("%s is unavailable.\n", valid); | |
371 | exit(1); | |
bd94915c | 372 | } |
6afaba66 KM |
373 | if (strcmp(valid, DEFSHELL) == 0) |
374 | valid[0] = '\0'; | |
375 | return (valid); | |
bd94915c | 376 | } |
844df0cd RC |
377 | |
378 | struct default_values { | |
379 | char *name; | |
380 | char *office_num; | |
381 | char *office_phone; | |
382 | char *home_phone; | |
383 | }; | |
384 | ||
385 | /* | |
386 | * Get name, room number, school phone, and home phone. | |
387 | */ | |
388 | char * | |
bd94915c | 389 | getfingerinfo(pwd) |
844df0cd | 390 | struct passwd *pwd; |
844df0cd RC |
391 | { |
392 | char in_str[BUFSIZ]; | |
393 | struct default_values *defaults, *get_defaults(); | |
394 | static char answer[4*BUFSIZ]; | |
395 | ||
396 | answer[0] = '\0'; | |
397 | defaults = get_defaults(pwd->pw_gecos); | |
868cd94a KB |
398 | puts("Default values are printed inside of '[]'."); |
399 | puts("To accept the default, type <return>."); | |
400 | puts("To have a blank entry, type the word 'none'."); | |
844df0cd RC |
401 | /* |
402 | * Get name. | |
403 | */ | |
404 | do { | |
405 | printf("\nName [%s]: ", defaults->name); | |
868cd94a | 406 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
407 | if (special_case(in_str, defaults->name)) |
408 | break; | |
409 | } while (illegal_input(in_str)); | |
410 | (void) strcpy(answer, in_str); | |
411 | /* | |
412 | * Get room number. | |
413 | */ | |
414 | do { | |
415 | printf("Room number (Exs: 597E or 197C) [%s]: ", | |
416 | defaults->office_num); | |
868cd94a | 417 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
418 | if (special_case(in_str, defaults->office_num)) |
419 | break; | |
420 | } while (illegal_input(in_str) || illegal_building(in_str)); | |
421 | (void) strcat(strcat(answer, ","), in_str); | |
422 | /* | |
423 | * Get office phone number. | |
008e3485 | 424 | * Remove hyphens. |
844df0cd RC |
425 | */ |
426 | do { | |
008e3485 | 427 | printf("Office Phone (Ex: 6426000) [%s]: ", |
844df0cd | 428 | defaults->office_phone); |
868cd94a | 429 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
430 | if (special_case(in_str, defaults->office_phone)) |
431 | break; | |
432 | remove_hyphens(in_str); | |
008e3485 | 433 | } while (illegal_input(in_str) || not_all_digits(in_str)); |
844df0cd RC |
434 | (void) strcat(strcat(answer, ","), in_str); |
435 | /* | |
436 | * Get home phone number. | |
437 | * Remove hyphens if present. | |
438 | */ | |
439 | do { | |
440 | printf("Home Phone (Ex: 9875432) [%s]: ", defaults->home_phone); | |
868cd94a | 441 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
442 | if (special_case(in_str, defaults->home_phone)) |
443 | break; | |
444 | remove_hyphens(in_str); | |
445 | } while (illegal_input(in_str) || not_all_digits(in_str)); | |
446 | (void) strcat(strcat(answer, ","), in_str); | |
447 | if (strcmp(answer, pwd->pw_gecos) == 0) { | |
868cd94a | 448 | puts("Finger information unchanged."); |
844df0cd RC |
449 | exit(1); |
450 | } | |
451 | return (answer); | |
452 | } | |
453 | ||
454 | /* | |
c61abc2b KB |
455 | * Prints an error message if a ':', ',' or a newline is found in the string. |
456 | * A message is also printed if the input string is too long. The password | |
457 | * file uses :'s as separators, and are not allowed in the "gcos" field; | |
458 | * commas are used as separators in the gcos field, so are disallowed. | |
459 | * Newlines serve as delimiters between users in the password file, and so, | |
460 | * those too, are checked for. (I don't think that it is possible to | |
844df0cd RC |
461 | * type them in, but better safe than sorry) |
462 | * | |
c61abc2b KB |
463 | * Returns '1' if a colon, comma or newline is found or the input line is |
464 | * too long. | |
844df0cd RC |
465 | */ |
466 | illegal_input(input_str) | |
467 | char *input_str; | |
468 | { | |
469 | char *ptr; | |
470 | int error_flag = 0; | |
471 | int length = strlen(input_str); | |
472 | ||
c61abc2b KB |
473 | if (strpbrk(input_str, ",:")) { |
474 | puts("':' and ',' are not allowed."); | |
844df0cd RC |
475 | error_flag = 1; |
476 | } | |
477 | if (input_str[length-1] != '\n') { | |
478 | /* the newline and the '\0' eat up two characters */ | |
479 | printf("Maximum number of characters allowed is %d\n", | |
480 | BUFSIZ-2); | |
481 | /* flush the rest of the input line */ | |
482 | while (getchar() != '\n') | |
483 | /* void */; | |
484 | error_flag = 1; | |
485 | } | |
486 | /* | |
487 | * Delete newline by shortening string by 1. | |
488 | */ | |
489 | input_str[length-1] = '\0'; | |
490 | /* | |
491 | * Don't allow control characters, etc in input string. | |
492 | */ | |
868cd94a KB |
493 | for (ptr = input_str; *ptr; ptr++) |
494 | if (!isprint(*ptr)) { | |
495 | puts("Control characters are not allowed."); | |
844df0cd RC |
496 | error_flag = 1; |
497 | break; | |
498 | } | |
844df0cd RC |
499 | return (error_flag); |
500 | } | |
501 | ||
502 | /* | |
503 | * Removes '-'s from the input string. | |
504 | */ | |
505 | remove_hyphens(str) | |
506 | char *str; | |
507 | { | |
508 | char *hyphen; | |
509 | ||
510 | while ((hyphen = index(str, '-')) != NULL) | |
511 | (void) strcpy(hyphen, hyphen+1); | |
512 | } | |
513 | ||
514 | /* | |
515 | * Checks to see if 'str' contains only digits (0-9). If not, then | |
516 | * an error message is printed and '1' is returned. | |
517 | */ | |
518 | not_all_digits(str) | |
868cd94a | 519 | register char *str; |
844df0cd | 520 | { |
868cd94a KB |
521 | for (; *str; ++str) |
522 | if (!isdigit(*str)) { | |
523 | puts("Phone numbers may only contain digits."); | |
524 | return(1); | |
844df0cd | 525 | } |
868cd94a | 526 | return(0); |
844df0cd RC |
527 | } |
528 | ||
844df0cd | 529 | /* |
5700acfe | 530 | * Deal with Berkeley buildings. Abbreviating Cory to C and Evans to E. |
844df0cd | 531 | * Correction changes "str". |
844df0cd RC |
532 | * |
533 | * Returns 1 if incorrect room format. | |
534 | * | |
535 | * Note: this function assumes that the newline has been removed from str. | |
536 | */ | |
537 | illegal_building(str) | |
5700acfe | 538 | register char *str; |
844df0cd RC |
539 | { |
540 | int length = strlen(str); | |
5700acfe | 541 | register char *ptr; |
844df0cd RC |
542 | |
543 | /* | |
5700acfe EW |
544 | * If the string is [Ee]vans or [Cc]ory or ends in |
545 | * [ \t0-9][Ee]vans or [ \t0-9M][Cc]ory, then contract the name | |
546 | * into 'E' or 'C', as the case may be, and delete leading blanks. | |
844df0cd | 547 | */ |
5700acfe EW |
548 | if (length >= 5 && strcmp(ptr = str + length - 4, "vans") == 0 && |
549 | (*--ptr == 'e' || *ptr == 'E') && | |
550 | (--ptr < str || isspace(*ptr) || isdigit(*ptr))) { | |
551 | for (; ptr > str && isspace(*ptr); ptr--) | |
552 | ; | |
553 | ptr++; | |
554 | *ptr++ = 'E'; | |
555 | *ptr = '\0'; | |
556 | } else | |
557 | if (length >= 4 && strcmp(ptr = str + length - 3, "ory") == 0 && | |
558 | (*--ptr == 'c' || *ptr == 'C') && | |
559 | (--ptr < str || *ptr == 'M' || isspace(*ptr) || isdigit(*ptr))) { | |
560 | for (; ptr > str && isspace(*ptr); ptr--) | |
561 | ; | |
562 | ptr++; | |
563 | *ptr++ = 'C'; | |
564 | *ptr = '\0'; | |
844df0cd RC |
565 | } |
566 | return (0); | |
567 | } | |
568 | ||
569 | /* | |
570 | * get_defaults picks apart "str" and returns a structure points. | |
571 | * "str" contains up to 4 fields separated by commas. | |
572 | * Any field that is missing is set to blank. | |
573 | */ | |
574 | struct default_values * | |
575 | get_defaults(str) | |
576 | char *str; | |
577 | { | |
578 | struct default_values *answer; | |
868cd94a | 579 | char *malloc(); |
844df0cd RC |
580 | |
581 | answer = (struct default_values *) | |
582 | malloc((unsigned)sizeof(struct default_values)); | |
583 | if (answer == (struct default_values *) NULL) { | |
868cd94a | 584 | fputs("\nUnable to allocate storage in get_defaults!\n", stderr); |
844df0cd RC |
585 | exit(1); |
586 | } | |
587 | /* | |
588 | * Values if no corresponding string in "str". | |
589 | */ | |
590 | answer->name = str; | |
591 | answer->office_num = ""; | |
592 | answer->office_phone = ""; | |
593 | answer->home_phone = ""; | |
594 | str = index(answer->name, ','); | |
595 | if (str == 0) | |
596 | return (answer); | |
597 | *str = '\0'; | |
598 | answer->office_num = str + 1; | |
599 | str = index(answer->office_num, ','); | |
600 | if (str == 0) | |
601 | return (answer); | |
602 | *str = '\0'; | |
603 | answer->office_phone = str + 1; | |
604 | str = index(answer->office_phone, ','); | |
605 | if (str == 0) | |
606 | return (answer); | |
607 | *str = '\0'; | |
608 | answer->home_phone = str + 1; | |
609 | return (answer); | |
610 | } | |
611 | ||
612 | /* | |
613 | * special_case returns true when either the default is accepted | |
614 | * (str = '\n'), or when 'none' is typed. 'none' is accepted in | |
615 | * either upper or lower case (or any combination). 'str' is modified | |
616 | * in these two cases. | |
617 | */ | |
618 | special_case(str,default_str) | |
619 | char *str, *default_str; | |
620 | { | |
621 | static char word[] = "none\n"; | |
622 | char *ptr, *wordptr; | |
623 | ||
624 | /* | |
625 | * If the default is accepted, then change the old string do the | |
626 | * default string. | |
627 | */ | |
628 | if (*str == '\n') { | |
629 | (void) strcpy(str, default_str); | |
630 | return (1); | |
631 | } | |
632 | /* | |
633 | * Check to see if str is 'none'. (It is questionable if case | |
634 | * insensitivity is worth the hair). | |
635 | */ | |
636 | wordptr = word-1; | |
637 | for (ptr = str; *ptr != '\0'; ++ptr) { | |
638 | ++wordptr; | |
639 | if (*wordptr == '\0') /* then words are different sizes */ | |
640 | return (0); | |
641 | if (*ptr == *wordptr) | |
642 | continue; | |
643 | if (isupper(*ptr) && (tolower(*ptr) == *wordptr)) | |
644 | continue; | |
645 | /* | |
646 | * At this point we have a mismatch, so we return | |
647 | */ | |
648 | return (0); | |
649 | } | |
650 | /* | |
651 | * Make sure that words are the same length. | |
652 | */ | |
653 | if (*(wordptr+1) != '\0') | |
654 | return (0); | |
655 | /* | |
656 | * Change 'str' to be the null string | |
657 | */ | |
658 | *str = '\0'; | |
659 | return (1); | |
252e456d | 660 | } |