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 |
868cd94a | 14 | static char sccsid[] = "@(#)passwd.c 4.28 (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; | |
226 | #define COMPACT(e) tp = pwd->pw_/**/e; while (*cp++ = *tp++); | |
227 | COMPACT(name); | |
228 | COMPACT(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); | |
9ae20471 RC |
235 | COMPACT(comment); |
236 | COMPACT(gecos); | |
237 | COMPACT(dir); | |
238 | COMPACT(shell); | |
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; | |
279 | if (checkpass(pwbuf)) | |
280 | break; | |
844df0cd RC |
281 | } |
282 | if (strcmp(pwbuf, getpass("Retype new password:")) != 0) { | |
868cd94a | 283 | puts("Mismatch - password unchanged."); |
844df0cd RC |
284 | exit(1); |
285 | } | |
868cd94a | 286 | (void)time(&salt); |
844df0cd RC |
287 | salt = 9 * getpid(); |
288 | saltc[0] = salt & 077; | |
289 | saltc[1] = (salt>>6) & 077; | |
290 | for (i = 0; i < 2; i++) { | |
291 | c = saltc[i] + '.'; | |
292 | if (c > '9') | |
293 | c += 7; | |
294 | if (c > 'Z') | |
295 | c += 6; | |
296 | saltc[i] = c; | |
297 | } | |
868cd94a | 298 | return(crypt(pwbuf, saltc)); |
844df0cd RC |
299 | } |
300 | ||
844df0cd | 301 | char * |
868cd94a | 302 | getloginshell(pwd, u) |
844df0cd | 303 | struct passwd *pwd; |
868cd94a | 304 | uid_t u; |
844df0cd | 305 | { |
6afaba66 KM |
306 | static char newshell[BUFSIZ]; |
307 | char *cp, *valid, *getusershell(); | |
844df0cd RC |
308 | |
309 | if (pwd->pw_shell == 0 || *pwd->pw_shell == '\0') | |
310 | pwd->pw_shell = DEFSHELL; | |
7bffa124 | 311 | if (u != 0) { |
920e234e KB |
312 | do { |
313 | valid = getusershell(); | |
314 | if (valid == NULL) { | |
315 | printf("Cannot change from restricted shell %s\n", | |
316 | pwd->pw_shell); | |
317 | exit(1); | |
318 | } | |
319 | } while (strcmp(pwd->pw_shell, valid) != 0); | |
7bffa124 | 320 | } |
868cd94a KB |
321 | printf("Old shell: %s\nNew shell: ", pwd->pw_shell); |
322 | (void)fgets(newshell, sizeof (newshell) - 1, stdin); | |
323 | cp = index(newshell, '\n'); | |
324 | if (cp) | |
325 | *cp = '\0'; | |
326 | if (newshell[0] == 0) { | |
327 | puts("Login shell unchanged."); | |
328 | exit(1); | |
844df0cd RC |
329 | } |
330 | /* | |
331 | * Allow user to give shell name w/o preceding pathname. | |
332 | */ | |
920e234e KB |
333 | if (u != 0 || newshell[0] != '/') { |
334 | endusershell(); | |
335 | do { | |
336 | valid = getusershell(); | |
337 | if (valid == 0) { | |
338 | if (u == 0) { | |
339 | valid = newshell; | |
340 | break; | |
341 | } | |
342 | printf("%s is unacceptable as a new shell.\n", | |
343 | newshell); | |
344 | exit(1); | |
345 | } | |
6afaba66 KM |
346 | if (newshell[0] == '/') { |
347 | cp = valid; | |
348 | } else { | |
349 | cp = rindex(valid, '/'); | |
350 | if (cp == 0) | |
351 | cp = valid; | |
352 | else | |
353 | cp++; | |
354 | } | |
920e234e | 355 | } while (strcmp(newshell, cp) != 0); |
844df0cd | 356 | } |
868cd94a KB |
357 | else |
358 | valid = newshell; | |
920e234e KB |
359 | if (strcmp(valid, pwd->pw_shell) == 0) { |
360 | puts("Login shell unchanged."); | |
844df0cd RC |
361 | exit(1); |
362 | } | |
6afaba66 KM |
363 | if (access(valid, X_OK) < 0) { |
364 | printf("%s is unavailable.\n", valid); | |
365 | exit(1); | |
bd94915c | 366 | } |
6afaba66 KM |
367 | if (strcmp(valid, DEFSHELL) == 0) |
368 | valid[0] = '\0'; | |
369 | return (valid); | |
bd94915c | 370 | } |
844df0cd RC |
371 | |
372 | struct default_values { | |
373 | char *name; | |
374 | char *office_num; | |
375 | char *office_phone; | |
376 | char *home_phone; | |
377 | }; | |
378 | ||
379 | /* | |
380 | * Get name, room number, school phone, and home phone. | |
381 | */ | |
382 | char * | |
bd94915c | 383 | getfingerinfo(pwd) |
844df0cd | 384 | struct passwd *pwd; |
844df0cd RC |
385 | { |
386 | char in_str[BUFSIZ]; | |
387 | struct default_values *defaults, *get_defaults(); | |
388 | static char answer[4*BUFSIZ]; | |
389 | ||
390 | answer[0] = '\0'; | |
391 | defaults = get_defaults(pwd->pw_gecos); | |
868cd94a KB |
392 | puts("Default values are printed inside of '[]'."); |
393 | puts("To accept the default, type <return>."); | |
394 | puts("To have a blank entry, type the word 'none'."); | |
844df0cd RC |
395 | /* |
396 | * Get name. | |
397 | */ | |
398 | do { | |
399 | printf("\nName [%s]: ", defaults->name); | |
868cd94a | 400 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
401 | if (special_case(in_str, defaults->name)) |
402 | break; | |
403 | } while (illegal_input(in_str)); | |
404 | (void) strcpy(answer, in_str); | |
405 | /* | |
406 | * Get room number. | |
407 | */ | |
408 | do { | |
409 | printf("Room number (Exs: 597E or 197C) [%s]: ", | |
410 | defaults->office_num); | |
868cd94a | 411 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
412 | if (special_case(in_str, defaults->office_num)) |
413 | break; | |
414 | } while (illegal_input(in_str) || illegal_building(in_str)); | |
415 | (void) strcat(strcat(answer, ","), in_str); | |
416 | /* | |
417 | * Get office phone number. | |
008e3485 | 418 | * Remove hyphens. |
844df0cd RC |
419 | */ |
420 | do { | |
008e3485 | 421 | printf("Office Phone (Ex: 6426000) [%s]: ", |
844df0cd | 422 | defaults->office_phone); |
868cd94a | 423 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
424 | if (special_case(in_str, defaults->office_phone)) |
425 | break; | |
426 | remove_hyphens(in_str); | |
008e3485 | 427 | } while (illegal_input(in_str) || not_all_digits(in_str)); |
844df0cd RC |
428 | (void) strcat(strcat(answer, ","), in_str); |
429 | /* | |
430 | * Get home phone number. | |
431 | * Remove hyphens if present. | |
432 | */ | |
433 | do { | |
434 | printf("Home Phone (Ex: 9875432) [%s]: ", defaults->home_phone); | |
868cd94a | 435 | (void) fgets(in_str, BUFSIZ - 1, stdin); |
844df0cd RC |
436 | if (special_case(in_str, defaults->home_phone)) |
437 | break; | |
438 | remove_hyphens(in_str); | |
439 | } while (illegal_input(in_str) || not_all_digits(in_str)); | |
440 | (void) strcat(strcat(answer, ","), in_str); | |
441 | if (strcmp(answer, pwd->pw_gecos) == 0) { | |
868cd94a | 442 | puts("Finger information unchanged."); |
844df0cd RC |
443 | exit(1); |
444 | } | |
445 | return (answer); | |
446 | } | |
447 | ||
448 | /* | |
449 | * Prints an error message if a ':' or a newline is found in the string. | |
450 | * A message is also printed if the input string is too long. | |
451 | * The password file uses :'s as seperators, and are not allowed in the "gcos" | |
452 | * field. Newlines serve as delimiters between users in the password file, | |
453 | * and so, those too, are checked for. (I don't think that it is possible to | |
454 | * type them in, but better safe than sorry) | |
455 | * | |
456 | * Returns '1' if a colon or newline is found or the input line is too long. | |
457 | */ | |
458 | illegal_input(input_str) | |
459 | char *input_str; | |
460 | { | |
461 | char *ptr; | |
462 | int error_flag = 0; | |
463 | int length = strlen(input_str); | |
464 | ||
465 | if (index(input_str, ':')) { | |
868cd94a | 466 | puts("':' is not allowed."); |
844df0cd RC |
467 | error_flag = 1; |
468 | } | |
469 | if (input_str[length-1] != '\n') { | |
470 | /* the newline and the '\0' eat up two characters */ | |
471 | printf("Maximum number of characters allowed is %d\n", | |
472 | BUFSIZ-2); | |
473 | /* flush the rest of the input line */ | |
474 | while (getchar() != '\n') | |
475 | /* void */; | |
476 | error_flag = 1; | |
477 | } | |
478 | /* | |
479 | * Delete newline by shortening string by 1. | |
480 | */ | |
481 | input_str[length-1] = '\0'; | |
482 | /* | |
483 | * Don't allow control characters, etc in input string. | |
484 | */ | |
868cd94a KB |
485 | for (ptr = input_str; *ptr; ptr++) |
486 | if (!isprint(*ptr)) { | |
487 | puts("Control characters are not allowed."); | |
844df0cd RC |
488 | error_flag = 1; |
489 | break; | |
490 | } | |
844df0cd RC |
491 | return (error_flag); |
492 | } | |
493 | ||
494 | /* | |
495 | * Removes '-'s from the input string. | |
496 | */ | |
497 | remove_hyphens(str) | |
498 | char *str; | |
499 | { | |
500 | char *hyphen; | |
501 | ||
502 | while ((hyphen = index(str, '-')) != NULL) | |
503 | (void) strcpy(hyphen, hyphen+1); | |
504 | } | |
505 | ||
506 | /* | |
507 | * Checks to see if 'str' contains only digits (0-9). If not, then | |
508 | * an error message is printed and '1' is returned. | |
509 | */ | |
510 | not_all_digits(str) | |
868cd94a | 511 | register char *str; |
844df0cd | 512 | { |
868cd94a KB |
513 | for (; *str; ++str) |
514 | if (!isdigit(*str)) { | |
515 | puts("Phone numbers may only contain digits."); | |
516 | return(1); | |
844df0cd | 517 | } |
868cd94a | 518 | return(0); |
844df0cd RC |
519 | } |
520 | ||
844df0cd | 521 | /* |
5700acfe | 522 | * Deal with Berkeley buildings. Abbreviating Cory to C and Evans to E. |
844df0cd | 523 | * Correction changes "str". |
844df0cd RC |
524 | * |
525 | * Returns 1 if incorrect room format. | |
526 | * | |
527 | * Note: this function assumes that the newline has been removed from str. | |
528 | */ | |
529 | illegal_building(str) | |
5700acfe | 530 | register char *str; |
844df0cd RC |
531 | { |
532 | int length = strlen(str); | |
5700acfe | 533 | register char *ptr; |
844df0cd RC |
534 | |
535 | /* | |
5700acfe EW |
536 | * If the string is [Ee]vans or [Cc]ory or ends in |
537 | * [ \t0-9][Ee]vans or [ \t0-9M][Cc]ory, then contract the name | |
538 | * into 'E' or 'C', as the case may be, and delete leading blanks. | |
844df0cd | 539 | */ |
5700acfe EW |
540 | if (length >= 5 && strcmp(ptr = str + length - 4, "vans") == 0 && |
541 | (*--ptr == 'e' || *ptr == 'E') && | |
542 | (--ptr < str || isspace(*ptr) || isdigit(*ptr))) { | |
543 | for (; ptr > str && isspace(*ptr); ptr--) | |
544 | ; | |
545 | ptr++; | |
546 | *ptr++ = 'E'; | |
547 | *ptr = '\0'; | |
548 | } else | |
549 | if (length >= 4 && strcmp(ptr = str + length - 3, "ory") == 0 && | |
550 | (*--ptr == 'c' || *ptr == 'C') && | |
551 | (--ptr < str || *ptr == 'M' || isspace(*ptr) || isdigit(*ptr))) { | |
552 | for (; ptr > str && isspace(*ptr); ptr--) | |
553 | ; | |
554 | ptr++; | |
555 | *ptr++ = 'C'; | |
556 | *ptr = '\0'; | |
844df0cd RC |
557 | } |
558 | return (0); | |
559 | } | |
560 | ||
561 | /* | |
562 | * get_defaults picks apart "str" and returns a structure points. | |
563 | * "str" contains up to 4 fields separated by commas. | |
564 | * Any field that is missing is set to blank. | |
565 | */ | |
566 | struct default_values * | |
567 | get_defaults(str) | |
568 | char *str; | |
569 | { | |
570 | struct default_values *answer; | |
868cd94a | 571 | char *malloc(); |
844df0cd RC |
572 | |
573 | answer = (struct default_values *) | |
574 | malloc((unsigned)sizeof(struct default_values)); | |
575 | if (answer == (struct default_values *) NULL) { | |
868cd94a | 576 | fputs("\nUnable to allocate storage in get_defaults!\n", stderr); |
844df0cd RC |
577 | exit(1); |
578 | } | |
579 | /* | |
580 | * Values if no corresponding string in "str". | |
581 | */ | |
582 | answer->name = str; | |
583 | answer->office_num = ""; | |
584 | answer->office_phone = ""; | |
585 | answer->home_phone = ""; | |
586 | str = index(answer->name, ','); | |
587 | if (str == 0) | |
588 | return (answer); | |
589 | *str = '\0'; | |
590 | answer->office_num = str + 1; | |
591 | str = index(answer->office_num, ','); | |
592 | if (str == 0) | |
593 | return (answer); | |
594 | *str = '\0'; | |
595 | answer->office_phone = str + 1; | |
596 | str = index(answer->office_phone, ','); | |
597 | if (str == 0) | |
598 | return (answer); | |
599 | *str = '\0'; | |
600 | answer->home_phone = str + 1; | |
601 | return (answer); | |
602 | } | |
603 | ||
604 | /* | |
605 | * special_case returns true when either the default is accepted | |
606 | * (str = '\n'), or when 'none' is typed. 'none' is accepted in | |
607 | * either upper or lower case (or any combination). 'str' is modified | |
608 | * in these two cases. | |
609 | */ | |
610 | special_case(str,default_str) | |
611 | char *str, *default_str; | |
612 | { | |
613 | static char word[] = "none\n"; | |
614 | char *ptr, *wordptr; | |
615 | ||
616 | /* | |
617 | * If the default is accepted, then change the old string do the | |
618 | * default string. | |
619 | */ | |
620 | if (*str == '\n') { | |
621 | (void) strcpy(str, default_str); | |
622 | return (1); | |
623 | } | |
624 | /* | |
625 | * Check to see if str is 'none'. (It is questionable if case | |
626 | * insensitivity is worth the hair). | |
627 | */ | |
628 | wordptr = word-1; | |
629 | for (ptr = str; *ptr != '\0'; ++ptr) { | |
630 | ++wordptr; | |
631 | if (*wordptr == '\0') /* then words are different sizes */ | |
632 | return (0); | |
633 | if (*ptr == *wordptr) | |
634 | continue; | |
635 | if (isupper(*ptr) && (tolower(*ptr) == *wordptr)) | |
636 | continue; | |
637 | /* | |
638 | * At this point we have a mismatch, so we return | |
639 | */ | |
640 | return (0); | |
641 | } | |
642 | /* | |
643 | * Make sure that words are the same length. | |
644 | */ | |
645 | if (*(wordptr+1) != '\0') | |
646 | return (0); | |
647 | /* | |
648 | * Change 'str' to be the null string | |
649 | */ | |
650 | *str = '\0'; | |
651 | return (1); | |
252e456d | 652 | } |