Commit | Line | Data |
---|---|---|
252e456d | 1 | #ifndef lint |
dfcb5d54 | 2 | static char sccsid[] = "@(#)passwd.c 4.12 (Berkeley) %G%"; |
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; |
844df0cd | 38 | int fd, i, u, dochfn, dochsh; |
252e456d | 39 | FILE *tf; |
9ae20471 | 40 | DBM *dp; |
252e456d | 41 | |
a1b0286d RC |
42 | if ((progname = index(argv[0], '/')) == NULL) |
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 |
844df0cd | 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) | |
103 | cp = getloginshell(pwd, u); | |
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 SL |
112 | if (fd < 0) { |
113 | fprintf(stderr, "passwd: "); | |
9a59f452 | 114 | if (errno == EEXIST) |
252e456d SL |
115 | fprintf(stderr, "password file busy - try again.\n"); |
116 | else | |
117 | perror(temp); | |
118 | exit(1); | |
119 | } | |
252e456d SL |
120 | if ((tf = fdopen(fd, "w")) == NULL) { |
121 | fprintf(stderr, "passwd: fdopen failed?\n"); | |
122 | exit(1); | |
123 | } | |
844df0cd RC |
124 | if ((dp = dbm_open(passwd, O_RDWR, 0644)) == NULL) { |
125 | fprintf(stderr, "Warning: dbm_open failed: "); | |
9ae20471 | 126 | perror(passwd); |
844df0cd | 127 | } else if (flock(dp->dbm_dirf, LOCK_EX) < 0) { |
9ae20471 | 128 | perror("Warning: lock failed"); |
844df0cd | 129 | dbm_close(dp); |
9ae20471 RC |
130 | dp = NULL; |
131 | } | |
844df0cd RC |
132 | unlimit(RLIMIT_CPU); |
133 | unlimit(RLIMIT_FSIZE); | |
252e456d SL |
134 | /* |
135 | * Copy passwd to temp, replacing matching lines | |
136 | * with new password. | |
137 | */ | |
138 | while ((pwd = getpwent()) != NULL) { | |
8d3b95af | 139 | if (strcmp(pwd->pw_name, uname) == 0) { |
252e456d SL |
140 | if (u && u != pwd->pw_uid) { |
141 | fprintf(stderr, "passwd: permission denied.\n"); | |
8d3b95af | 142 | goto out; |
252e456d | 143 | } |
844df0cd RC |
144 | if (dochfn) |
145 | pwd->pw_gecos = cp; | |
146 | else if (dochsh) | |
147 | pwd->pw_shell = cp; | |
148 | else | |
149 | pwd->pw_passwd = cp; | |
150 | if (pwd->pw_gecos[0] == '*') /* ??? */ | |
252e456d | 151 | pwd->pw_gecos++; |
9ae20471 | 152 | replace(dp, pwd); |
252e456d SL |
153 | } |
154 | fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n", | |
155 | pwd->pw_name, | |
156 | pwd->pw_passwd, | |
157 | pwd->pw_uid, | |
158 | pwd->pw_gid, | |
159 | pwd->pw_gecos, | |
160 | pwd->pw_dir, | |
161 | pwd->pw_shell); | |
162 | } | |
163 | endpwent(); | |
9ae20471 | 164 | (void) fclose(tf); |
844df0cd RC |
165 | if (dp != NULL && dbm_error(dp)) |
166 | fprintf(stderr, "Warning: dbm_store failed\n"); | |
167 | dbm_close(dp); | |
9ae20471 | 168 | if (rename(temp, passwd) < 0) { |
8d3b95af | 169 | fprintf(stderr, "passwd: "), perror("rename"); |
9ae20471 RC |
170 | out: |
171 | unlink(temp); | |
172 | exit(1); | |
173 | } | |
174 | exit(0); | |
8d3b95af RC |
175 | } |
176 | ||
844df0cd RC |
177 | unlimit(lim) |
178 | { | |
179 | struct rlimit rlim; | |
180 | ||
181 | rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; | |
182 | (void) setrlimit(lim, &rlim); | |
183 | } | |
184 | ||
9ae20471 RC |
185 | /* |
186 | * Replace the password entry in the dbm data base with pwd. | |
187 | */ | |
188 | replace(dp, pwd) | |
189 | DBM *dp; | |
190 | struct passwd *pwd; | |
8d3b95af | 191 | { |
9ae20471 RC |
192 | datum key, content; |
193 | register char *cp, *tp; | |
194 | char buf[BUFSIZ]; | |
8d3b95af | 195 | |
9ae20471 RC |
196 | if (dp == NULL) |
197 | return; | |
198 | ||
199 | cp = buf; | |
200 | #define COMPACT(e) tp = pwd->pw_/**/e; while (*cp++ = *tp++); | |
201 | COMPACT(name); | |
202 | COMPACT(passwd); | |
3c92851f RC |
203 | bcopy((char *)&pwd->pw_uid, cp, sizeof (int)); |
204 | cp += sizeof (int); | |
205 | bcopy((char *)&pwd->pw_gid, cp, sizeof (int)); | |
206 | cp += sizeof (int); | |
207 | bcopy((char *)&pwd->pw_quota, cp, sizeof (int)); | |
208 | cp += sizeof (int); | |
9ae20471 RC |
209 | COMPACT(comment); |
210 | COMPACT(gecos); | |
211 | COMPACT(dir); | |
212 | COMPACT(shell); | |
213 | content.dptr = buf; | |
214 | content.dsize = cp - buf; | |
215 | key.dptr = pwd->pw_name; | |
216 | key.dsize = strlen(pwd->pw_name); | |
844df0cd | 217 | dbm_store(dp, key, content, DBM_REPLACE); |
9ae20471 RC |
218 | key.dptr = (char *)&pwd->pw_uid; |
219 | key.dsize = sizeof (int); | |
844df0cd RC |
220 | dbm_store(dp, key, content, DBM_REPLACE); |
221 | } | |
222 | ||
223 | char * | |
224 | getnewpasswd(pwd, u) | |
225 | register struct passwd *pwd; | |
226 | int u; | |
227 | { | |
228 | char saltc[2]; | |
229 | time_t salt; | |
230 | int i, insist = 0, ok, flags; | |
231 | int c, pwlen; | |
232 | static char pwbuf[10]; | |
233 | char *crypt(), *pw, *p; | |
234 | ||
235 | if (pwd->pw_passwd[0] && u != 0) { | |
236 | strcpy(pwbuf, getpass("Old password:")); | |
237 | pw = crypt(pwbuf, pwd->pw_passwd); | |
238 | if (strcmp(pw, pwd->pw_passwd) != 0) { | |
239 | printf("Sorry.\n"); | |
240 | exit(1); | |
241 | } | |
242 | } | |
243 | tryagain: | |
244 | strcpy(pwbuf, getpass("New password:")); | |
245 | pwlen = strlen(pwbuf); | |
246 | if (pwlen == 0) { | |
247 | printf("Password unchanged.\n"); | |
248 | exit(1); | |
249 | } | |
250 | /* | |
251 | * Insure password is of reasonable length and | |
252 | * composition. If we really wanted to make things | |
253 | * sticky, we could check the dictionary for common | |
254 | * words, but then things would really be slow. | |
255 | */ | |
256 | ok = 0; | |
257 | flags = 0; | |
258 | p = pwbuf; | |
259 | while (c = *p++) { | |
260 | if (c >= 'a' && c <= 'z') | |
261 | flags |= 2; | |
262 | else if (c >= 'A' && c <= 'Z') | |
263 | flags |= 4; | |
264 | else if (c >= '0' && c <= '9') | |
265 | flags |= 1; | |
266 | else | |
267 | flags |= 8; | |
268 | } | |
269 | if (flags >= 7 && pwlen >= 4) | |
270 | ok = 1; | |
271 | if ((flags == 2 || flags == 4) && pwlen >= 6) | |
272 | ok = 1; | |
273 | if ((flags == 3 || flags == 5 || flags == 6) && pwlen >= 5) | |
274 | ok = 1; | |
275 | if (!ok && insist < 2) { | |
276 | printf("Please use %s.\n", flags == 1 ? | |
277 | "at least one non-numeric character" : | |
278 | "a longer password"); | |
279 | insist++; | |
280 | goto tryagain; | |
281 | } | |
282 | if (strcmp(pwbuf, getpass("Retype new password:")) != 0) { | |
283 | printf("Mismatch - password unchanged.\n"); | |
284 | exit(1); | |
285 | } | |
286 | time(&salt); | |
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 | } | |
298 | return (crypt(pwbuf, saltc)); | |
299 | } | |
300 | ||
301 | #define DEFSHELL okshells[0] | |
302 | char *okshells[] = | |
303 | { "/bin/sh", "/bin/csh", "/bin/oldcsh", "/bin/newcsh", "/usr/new/csh", 0 }; | |
304 | ||
305 | char * | |
306 | getloginshell(pwd, u) | |
307 | struct passwd *pwd; | |
308 | int u; | |
309 | { | |
310 | static char newshell[256]; | |
311 | register char **cpp; | |
312 | char *cp; | |
313 | ||
314 | if (pwd->pw_shell == 0 || *pwd->pw_shell == '\0') | |
315 | pwd->pw_shell = DEFSHELL; | |
316 | printf("Old shell: %s\nNew shell: ", pwd->pw_shell); | |
317 | fgets(newshell, sizeof (newshell) - 1, stdin); | |
318 | cp = index(newshell, '\n'); | |
319 | if (cp) | |
320 | *cp = '\0'; | |
321 | if (newshell[0] == '\0' || strcmp(newshell, pwd->pw_shell) == 0) { | |
322 | printf("Login shell unchanged.\n"); | |
323 | exit(1); | |
324 | } | |
325 | /* | |
326 | * Allow user to give shell name w/o preceding pathname. | |
327 | */ | |
328 | if (*cp != '/' && u != 0) { | |
329 | for (cpp = okshells; *cpp; cpp++) { | |
330 | cp = rindex(*cpp, '/'); | |
331 | if (cp == 0) | |
332 | continue; | |
333 | if (strcmp(cp+1, newshell) == 0) | |
334 | break; | |
335 | } | |
336 | if (*cpp) | |
337 | strcpy(newshell, *cpp); | |
338 | } | |
339 | if (u != 0) { | |
340 | for (cpp = okshells; *cpp; cpp++) | |
341 | if (strcmp(*cpp, newshell) == 0) | |
342 | break; | |
343 | if (*cpp == 0) { | |
344 | printf("%s is unacceptable as a new shell.\n", | |
345 | newshell); | |
346 | exit(1); | |
347 | } | |
348 | } | |
349 | if (access(newshell, X_OK) < 0) { | |
350 | printf("%s is unavailable.\n", newshell); | |
351 | exit(1); | |
352 | } | |
353 | if (strcmp(newshell, DEFSHELL) == 0) | |
354 | newshell[0] = '\0'; | |
355 | return (newshell); | |
356 | } | |
357 | ||
358 | struct default_values { | |
359 | char *name; | |
360 | char *office_num; | |
361 | char *office_phone; | |
362 | char *home_phone; | |
363 | }; | |
364 | ||
365 | /* | |
366 | * Get name, room number, school phone, and home phone. | |
367 | */ | |
368 | char * | |
369 | getfingerinfo(pwd, u) | |
370 | struct passwd *pwd; | |
371 | int u; | |
372 | { | |
373 | char in_str[BUFSIZ]; | |
374 | struct default_values *defaults, *get_defaults(); | |
375 | static char answer[4*BUFSIZ]; | |
376 | ||
377 | answer[0] = '\0'; | |
378 | defaults = get_defaults(pwd->pw_gecos); | |
379 | printf("Default values are printed inside of of '[]'.\n"); | |
380 | printf("To accept the default, type <return>.\n"); | |
381 | printf("To have a blank entry, type the word 'none'.\n"); | |
382 | /* | |
383 | * Get name. | |
384 | */ | |
385 | do { | |
386 | printf("\nName [%s]: ", defaults->name); | |
387 | (void) fgets(in_str, BUFSIZ, stdin); | |
388 | if (special_case(in_str, defaults->name)) | |
389 | break; | |
390 | } while (illegal_input(in_str)); | |
391 | (void) strcpy(answer, in_str); | |
392 | /* | |
393 | * Get room number. | |
394 | */ | |
395 | do { | |
396 | printf("Room number (Exs: 597E or 197C) [%s]: ", | |
397 | defaults->office_num); | |
398 | (void) fgets(in_str, BUFSIZ, stdin); | |
399 | if (special_case(in_str, defaults->office_num)) | |
400 | break; | |
401 | } while (illegal_input(in_str) || illegal_building(in_str)); | |
402 | (void) strcat(strcat(answer, ","), in_str); | |
403 | /* | |
404 | * Get office phone number. | |
405 | * Remove hyphens and 642, x2, or 2 prefixes if present. | |
406 | */ | |
407 | do { | |
408 | printf("Office Phone (Ex: 1632) [%s]: ", | |
409 | defaults->office_phone); | |
410 | (void) fgets(in_str, BUFSIZ, stdin); | |
411 | if (special_case(in_str, defaults->office_phone)) | |
412 | break; | |
413 | remove_hyphens(in_str); | |
414 | if (strlen(in_str) == 8 && strcmpn(in_str, "642", 3) == 0) | |
415 | (void) strcpy(in_str, in_str+3); | |
416 | if (strlen(in_str) == 7 && strcmpn(in_str, "x2", 2) == 0) | |
417 | (void) strcpy(in_str, in_str+2); | |
418 | if (strlen(in_str) == 6 && in_str[0] == '2') | |
419 | (void) strcpy(in_str, in_str+1); | |
420 | } while (illegal_input(in_str) || not_all_digits(in_str) | |
421 | || wrong_length(in_str, 4)); | |
422 | (void) strcat(strcat(answer, ","), in_str); | |
423 | /* | |
424 | * Get home phone number. | |
425 | * Remove hyphens if present. | |
426 | */ | |
427 | do { | |
428 | printf("Home Phone (Ex: 9875432) [%s]: ", defaults->home_phone); | |
429 | (void) fgets(in_str, BUFSIZ, stdin); | |
430 | if (special_case(in_str, defaults->home_phone)) | |
431 | break; | |
432 | remove_hyphens(in_str); | |
433 | } while (illegal_input(in_str) || not_all_digits(in_str)); | |
434 | (void) strcat(strcat(answer, ","), in_str); | |
435 | if (strcmp(answer, pwd->pw_gecos) == 0) { | |
436 | printf("Finger information unchanged.\n"); | |
437 | exit(1); | |
438 | } | |
439 | return (answer); | |
440 | } | |
441 | ||
442 | /* | |
443 | * Prints an error message if a ':' or a newline is found in the string. | |
444 | * A message is also printed if the input string is too long. | |
445 | * The password file uses :'s as seperators, and are not allowed in the "gcos" | |
446 | * field. Newlines serve as delimiters between users in the password file, | |
447 | * and so, those too, are checked for. (I don't think that it is possible to | |
448 | * type them in, but better safe than sorry) | |
449 | * | |
450 | * Returns '1' if a colon or newline is found or the input line is too long. | |
451 | */ | |
452 | illegal_input(input_str) | |
453 | char *input_str; | |
454 | { | |
455 | char *ptr; | |
456 | int error_flag = 0; | |
457 | int length = strlen(input_str); | |
458 | ||
459 | if (index(input_str, ':')) { | |
460 | printf("':' is not allowed.\n"); | |
461 | error_flag = 1; | |
462 | } | |
463 | if (input_str[length-1] != '\n') { | |
464 | /* the newline and the '\0' eat up two characters */ | |
465 | printf("Maximum number of characters allowed is %d\n", | |
466 | BUFSIZ-2); | |
467 | /* flush the rest of the input line */ | |
468 | while (getchar() != '\n') | |
469 | /* void */; | |
470 | error_flag = 1; | |
471 | } | |
472 | /* | |
473 | * Delete newline by shortening string by 1. | |
474 | */ | |
475 | input_str[length-1] = '\0'; | |
476 | /* | |
477 | * Don't allow control characters, etc in input string. | |
478 | */ | |
479 | for (ptr=input_str; *ptr != '\0'; ptr++) { | |
480 | if ((int) *ptr < 040) { | |
481 | printf("Control characters are not allowed.\n"); | |
482 | error_flag = 1; | |
483 | break; | |
484 | } | |
485 | } | |
486 | return (error_flag); | |
487 | } | |
488 | ||
489 | /* | |
490 | * Removes '-'s from the input string. | |
491 | */ | |
492 | remove_hyphens(str) | |
493 | char *str; | |
494 | { | |
495 | char *hyphen; | |
496 | ||
497 | while ((hyphen = index(str, '-')) != NULL) | |
498 | (void) strcpy(hyphen, hyphen+1); | |
499 | } | |
500 | ||
501 | /* | |
502 | * Checks to see if 'str' contains only digits (0-9). If not, then | |
503 | * an error message is printed and '1' is returned. | |
504 | */ | |
505 | not_all_digits(str) | |
506 | char *str; | |
507 | { | |
508 | char *ptr; | |
509 | ||
510 | for (ptr = str; *ptr != '\0'; ++ptr) | |
511 | if (!isdigit(*ptr)) { | |
512 | printf("Phone numbers can only contain digits.\n"); | |
513 | return (1); | |
514 | } | |
515 | return (0); | |
516 | } | |
517 | ||
518 | /* | |
519 | * Returns 1 when the length of the input string is not zero or equal to n. | |
520 | * Prints an error message in this case. | |
521 | */ | |
522 | wrong_length(str, n) | |
523 | char *str; | |
524 | int n; | |
525 | { | |
526 | ||
527 | if (strlen(str) != 0 && strlen(str) != n) { | |
528 | printf("The phone number should be %d digits long.\n", n); | |
529 | return (1); | |
530 | } | |
531 | return (0); | |
532 | } | |
533 | ||
534 | /* | |
535 | * Make sure that building is 'E' or 'C'. | |
536 | * Error correction is done if building is 'e', 'c', "evans", or "cory". | |
537 | * Correction changes "str". | |
538 | * The finger program determines the building by looking at the last | |
539 | * character. Currently, finger only allows that character to be 'E' or 'C'. | |
540 | * | |
541 | * Returns 1 if incorrect room format. | |
542 | * | |
543 | * Note: this function assumes that the newline has been removed from str. | |
544 | */ | |
545 | illegal_building(str) | |
546 | char *str; | |
547 | { | |
548 | int length = strlen(str); | |
549 | char *last_ch, *ptr; | |
550 | ||
551 | /* | |
552 | * Zero length strings are acceptable input. | |
553 | */ | |
554 | if (length == 0) | |
555 | return (0); | |
556 | /* | |
557 | * Delete "vans" and "ory". | |
558 | */ | |
559 | if (strcmpn(str+length-4, "vans", 4) == 0) { | |
560 | length -= 4; | |
561 | str[length] = '\0'; | |
562 | } | |
563 | if (strcmpn(str+length-3, "ory", 3) == 0) { | |
564 | length -= 3; | |
565 | str[length] = '\0'; | |
566 | } | |
567 | last_ch = str+length-1; | |
568 | /* | |
569 | * Now change e to E or c to C. | |
570 | */ | |
571 | if (*last_ch == 'e') | |
572 | *last_ch = 'E'; | |
573 | if (*last_ch == 'c') | |
574 | *last_ch = 'C'; | |
575 | /* | |
576 | * Delete any spaces before the E or C. | |
577 | */ | |
1c8742c7 | 578 | for (ptr = last_ch - 1; ptr > str && *ptr == ' '; ptr--) |
844df0cd RC |
579 | ; |
580 | (void) strcpy(ptr+1, last_ch); | |
581 | /* | |
582 | * Make sure building is evans or cory. | |
583 | */ | |
584 | if (*last_ch != 'E' && *last_ch != 'C') { | |
585 | printf("%s%s%s", | |
586 | "The finger program requires that your", | |
587 | " office be in Cory or Evans.\n", | |
588 | "Enter this as (for example) 597E or 197C.\n"); | |
589 | return (1); | |
590 | } | |
591 | return (0); | |
592 | } | |
593 | ||
594 | /* | |
595 | * get_defaults picks apart "str" and returns a structure points. | |
596 | * "str" contains up to 4 fields separated by commas. | |
597 | * Any field that is missing is set to blank. | |
598 | */ | |
599 | struct default_values * | |
600 | get_defaults(str) | |
601 | char *str; | |
602 | { | |
603 | struct default_values *answer; | |
604 | char *malloc(); | |
605 | ||
606 | answer = (struct default_values *) | |
607 | malloc((unsigned)sizeof(struct default_values)); | |
608 | if (answer == (struct default_values *) NULL) { | |
609 | fprintf(stderr, | |
610 | "\nUnable to allocate storage in get_defaults!\n"); | |
611 | exit(1); | |
612 | } | |
613 | /* | |
614 | * Values if no corresponding string in "str". | |
615 | */ | |
616 | answer->name = str; | |
617 | answer->office_num = ""; | |
618 | answer->office_phone = ""; | |
619 | answer->home_phone = ""; | |
620 | str = index(answer->name, ','); | |
621 | if (str == 0) | |
622 | return (answer); | |
623 | *str = '\0'; | |
624 | answer->office_num = str + 1; | |
625 | str = index(answer->office_num, ','); | |
626 | if (str == 0) | |
627 | return (answer); | |
628 | *str = '\0'; | |
629 | answer->office_phone = str + 1; | |
630 | str = index(answer->office_phone, ','); | |
631 | if (str == 0) | |
632 | return (answer); | |
633 | *str = '\0'; | |
634 | answer->home_phone = str + 1; | |
635 | return (answer); | |
636 | } | |
637 | ||
638 | /* | |
639 | * special_case returns true when either the default is accepted | |
640 | * (str = '\n'), or when 'none' is typed. 'none' is accepted in | |
641 | * either upper or lower case (or any combination). 'str' is modified | |
642 | * in these two cases. | |
643 | */ | |
644 | special_case(str,default_str) | |
645 | char *str, *default_str; | |
646 | { | |
647 | static char word[] = "none\n"; | |
648 | char *ptr, *wordptr; | |
649 | ||
650 | /* | |
651 | * If the default is accepted, then change the old string do the | |
652 | * default string. | |
653 | */ | |
654 | if (*str == '\n') { | |
655 | (void) strcpy(str, default_str); | |
656 | return (1); | |
657 | } | |
658 | /* | |
659 | * Check to see if str is 'none'. (It is questionable if case | |
660 | * insensitivity is worth the hair). | |
661 | */ | |
662 | wordptr = word-1; | |
663 | for (ptr = str; *ptr != '\0'; ++ptr) { | |
664 | ++wordptr; | |
665 | if (*wordptr == '\0') /* then words are different sizes */ | |
666 | return (0); | |
667 | if (*ptr == *wordptr) | |
668 | continue; | |
669 | if (isupper(*ptr) && (tolower(*ptr) == *wordptr)) | |
670 | continue; | |
671 | /* | |
672 | * At this point we have a mismatch, so we return | |
673 | */ | |
674 | return (0); | |
675 | } | |
676 | /* | |
677 | * Make sure that words are the same length. | |
678 | */ | |
679 | if (*(wordptr+1) != '\0') | |
680 | return (0); | |
681 | /* | |
682 | * Change 'str' to be the null string | |
683 | */ | |
684 | *str = '\0'; | |
685 | return (1); | |
252e456d | 686 | } |