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