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