1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include "mt.h"
30 #include "uucp.h"
31
32 #include <unistd.h>
33 #include <string.h>
34 #include "sysfiles.h"
35 #include <sys/stropts.h>
36
37 /*
38 * manage systems files (Systems, Devices, and Dialcodes families).
39 *
40 * also manage new file Devconfig, allows per-device setup.
41 * present use is to specify what streams modules to push/pop for
42 * AT&T TLI/streams network.
43 *
44 * TODO:
45 * call bsfix()?
46 * combine the 3 versions of everything (sys, dev, and dial) into one.
47 * allow arbitrary classes of service.
48 * need verifysys() for uucheck.
49 * nameserver interface?
50 * pass sysname (or 0) to getsysline(). (might want reg. exp. or
51 * NS processing)
52 */
53
54 /* private variables */
55 static void tokenize(void);
56 static void nameparse(void);
57 static void setfile(char **, char *);
58 static void setioctl(char **, char *);
59 static void scansys(const char *);
60 static void scancfg(char *, char *);
61 static void setconfig(void);
62 static int namematch(const char *label, char *line, const char *name);
63 static int nextdialers(void);
64 static int nextdevices(void);
65 static int nextsystems(void);
66 static int getaline(FILE *, char *);
67
68 /* pointer arrays might be dynamically allocated */
69 static char *Systems[64]; /* list of Systems files */
70 static char *Devices[64]; /* list of Devices files */
71 static char *Dialers[64]; /* list of Dialers files */
72 static char *Pops[64]; /* list of STREAMS modules to be popped */
73 static char *Pushes[64]; /* list of STREAMS modules to be pushed */
74
75 static int nsystems; /* index into list of Systems files */
76 static int ndevices; /* index into list of Devices files */
77 static int ndialers; /* index into list of Dialers files */
78 static int npops; /* index into list of STREAMS modules */
79 /* to be popped */
80 static int npushes; /* index into list of STREAMS modules */
81 /* to be pushed */
82
83 static unsigned connecttime, expecttime;
84
85 static FILE *fsystems;
86 static FILE *fdevices;
87 static FILE *fdialers;
88
89 /* this might be dynamically allocated */
90 #define NTOKENS 16
91 static char *tokens[NTOKENS], **tokptr;
92
93 /* export these */
94 static void setservice(const char *service);
95 static void sysreset(void);
96 static void devreset(void);
97 static void dialreset(void);
98 static void setdevcfg(char *, char *);
99 static void setservice(const char *);
100
101 /* import these */
102 extern char *strsave(const char *);
103 static int eaccess(char *, mode_t);
104
105 /*
106 * setservice init's Systems, Devices, Dialers lists from Sysfiles
107 */
108 static void
setservice(const char * service)109 setservice(const char *service)
110 {
111 setconfig();
112 scansys(service);
113 }
114
115 /*
116 * setdevcfg init's Pops, Pushes lists from Devconfig
117 */
118
119 static void
setdevcfg(char * service,char * device)120 setdevcfg(char *service, char *device)
121 {
122 scancfg(service, device);
123 }
124
125 /* administrative files access */
126 static int
sysaccess(int type)127 sysaccess(int type)
128 {
129 char errformat[BUFSIZ];
130
131 switch (type) {
132 case ACCESS_SYSTEMS:
133 return (access(Systems[nsystems], R_OK));
134 case ACCESS_DEVICES:
135 return (access(Devices[ndevices], R_OK));
136 case ACCESS_DIALERS:
137 return (access(Dialers[ndialers], R_OK));
138 case EACCESS_SYSTEMS:
139 return (eaccess(Systems[nsystems], R_OK));
140 case EACCESS_DEVICES:
141 return (eaccess(Devices[ndevices], R_OK));
142 case EACCESS_DIALERS:
143 return (eaccess(Dialers[ndialers], R_OK));
144 }
145 (void) sprintf(errformat, "bad access type %d", type);
146 logent(errformat, "sysaccess");
147 return (FAIL);
148 }
149
150
151 /*
152 * read Sysfiles, set up lists of Systems/Devices/Dialers file names.
153 * allow multiple entries for a given service, allow a service
154 * type to describe resources more than once, e.g., systems=foo:baz systems=bar.
155 */
156 static void
scansys(const char * service)157 scansys(const char *service)
158 { FILE *f;
159 char *tok, buf[BUFSIZ];
160 char **tptr;
161
162 /*
163 * Release and Initialize previously allocated memory
164 * for Systems, Devices and Dialers.
165 */
166 nsystems = 0;
167 tptr = Systems;
168 while (*tptr) {
169 free(*tptr);
170 *tptr = NULL;
171 tptr++;
172 }
173
174 ndevices = 0;
175 tptr = Devices;
176 while (*tptr) {
177 free(*tptr);
178 *tptr = NULL;
179 tptr++;
180 }
181
182 ndialers = 0;
183 tptr = Dialers;
184 while (*tptr) {
185 free(*tptr);
186 *tptr = NULL;
187 tptr++;
188 }
189
190 if ((f = fopen(SYSFILES, "rF")) != 0) {
191 while (getaline(f, buf) > 0) {
192 /* got a (logical) line from Sysfiles */
193 /* strtok's of this buf continue in tokenize() */
194 tok = strtok(buf, " \t");
195 if (namematch("service=", tok, service)) {
196 tokenize();
197 nameparse();
198 }
199 }
200 (void) fclose(f);
201 }
202
203 /* if didn't find entries in Sysfiles, use defaults */
204 if (Systems[0] == NULL) {
205 Systems[0] = strsave(SYSTEMS);
206 ASSERT(Systems[0] != NULL, "Ct_ALLOCATE", "scansys: Systems",
207 0);
208 Systems[1] = NULL;
209 }
210 if (Devices[0] == NULL) {
211 Devices[0] = strsave(DEVICES);
212 ASSERT(Devices[0] != NULL, "Ct_ALLOCATE", "scansys: Devices",
213 0);
214 Devices[1] = NULL;
215 }
216 if (Dialers[0] == NULL) {
217 Dialers[0] = strsave(DIALERS);
218 ASSERT(Dialers[0] != NULL, "Ct_ALLOCATE", "scansys: Dialers",
219 0);
220 Dialers[1] = NULL;
221 }
222 }
223
224
225 /*
226 * read Devconfig. allow multiple entries for a given service, allow a service
227 * type to describe resources more than once, e.g., push=foo:baz push=bar.
228 */
229 static void
scancfg(char * service,char * device)230 scancfg(char *service, char *device)
231 { FILE *f;
232 char *tok, buf[BUFSIZ];
233
234 /* (re)initialize device-specific information */
235 npops = npushes = 0;
236 Pops[0] = Pushes[0] = NULL;
237 connecttime = CONNECTTIME;
238 expecttime = EXPECTTIME;
239
240 if ((f = fopen(DEVCONFIG, "rF")) != 0) {
241 while (getaline(f, buf) > 0) {
242 /* got a (logical) line from Devconfig */
243 /* strtok's of this buf continue in tokenize() */
244 tok = strtok(buf, " \t");
245 if (namematch("service=", tok, service)) {
246 tok = strtok((char *)0, " \t");
247 if (namematch("device=", tok, device)) {
248 tokenize();
249 nameparse();
250 }
251 }
252 }
253 (void) fclose(f);
254 }
255 return;
256
257 }
258
259 /*
260 * given a file pointer and buffer, construct logical line in buffer
261 * (i.e., concatenate lines ending in '\'). return length of line
262 * ASSUMES that buffer is BUFSIZ long!
263 */
264
265 static int
getaline(FILE * f,char * line)266 getaline(FILE *f, char *line)
267 { char *lptr, *lend;
268
269 lptr = line;
270 while (fgets(lptr, (line + BUFSIZ) - lptr, f) != NULL) {
271 lend = lptr + strlen(lptr);
272 if (lend == lptr || lend[-1] != '\n')
273 /* empty buf or line too long! */
274 break;
275 *--lend = '\0'; /* lop off ending '\n' */
276 if (lend == line) /* empty line - ignore */
277 continue;
278 lptr = lend;
279 if (lend[-1] != '\\')
280 break;
281 /* continuation */
282 lend[-1] = ' ';
283 }
284 return (lptr - line);
285 }
286
287 /*
288 * given a label (e.g., "service=", "device="), a name ("cu", "uucico"),
289 * and a line: if line begins with the label and if the name appears
290 * in a colon-separated list of names following the label, return true;
291 * else return false
292 */
293 static int
namematch(const char * label,char * line,const char * name)294 namematch(const char *label, char *line, const char *name)
295 {
296 char *lend;
297
298 if (strncmp(label, line, strlen(label)) != SAME)
299 return (FALSE); /* probably a comment line */
300 line += strlen(label);
301 if (*line == '\0')
302 return (FALSE);
303 /*
304 * can't use strtok() in the following because scansys(),
305 * scancfg() do an initializing call to strtok() before
306 * coming here and then CONTINUE calling strtok() in tokenize(),
307 * after returning from namematch().
308 */
309 while ((lend = strchr(line, ':')) != NULL) {
310 *lend = '\0';
311 if (strcmp(line, name) == SAME)
312 return (TRUE);
313 line = lend+1;
314 }
315 return (strcmp(line, name) == SAME);
316 }
317
318 /*
319 * tokenize() continues pulling tokens out of a buffer -- the
320 * initializing call to strtok must have been made before calling
321 * tokenize() -- and starts stuffing 'em into tokptr.
322 */
323 static void
tokenize(void)324 tokenize(void)
325 {
326 char *tok;
327
328 tokptr = tokens;
329 while ((tok = strtok(NULL, " \t")) != NULL) {
330 *tokptr++ = tok;
331 if (tokptr - tokens >= NTOKENS)
332 break;
333 }
334 *tokptr = NULL;
335 }
336
337 /*
338 * look at top token in array: should be line of the form
339 * name=item1:item2:item3...
340 * if name is one we recognize, then call set[file|ioctl] to set up
341 * corresponding list. otherwise, log bad name.
342 */
343 static void
nameparse(void)344 nameparse(void)
345 {
346 char **line, *equals;
347 int temp;
348
349 #define setuint(a, b, c) a = (((temp = atoi(b)) <= 0) ? (c) : temp)
350
351 for (line = tokens; (line - tokens) < NTOKENS && *line; line++) {
352 equals = strchr(*line, '=');
353 if (equals == NULL)
354 continue; /* may be meaningful someday? */
355 *equals = '\0';
356 /* ignore entry with empty rhs */
357 if (*++equals == '\0')
358 continue;
359 if (strcmp(*line, "systems") == SAME)
360 setfile(Systems, equals);
361 else if (strcmp(*line, "devices") == SAME)
362 setfile(Devices, equals);
363 else if (strcmp(*line, "dialers") == SAME)
364 setfile(Dialers, equals);
365 else if (strcmp(*line, "pop") == SAME)
366 setioctl(Pops, equals);
367 else if (strcmp(*line, "push") == SAME)
368 setioctl(Pushes, equals);
369 else if (strcmp(*line, "connecttime") == SAME)
370 setuint(connecttime, equals, CONNECTTIME);
371 else if (strcmp(*line, "expecttime") == SAME)
372 setuint(expecttime, equals, EXPECTTIME);
373 else if (strcmp(*line, "msgtime") == SAME)
374 continue;
375 else {
376 char errformat[BUFSIZ];
377
378 (void) snprintf(errformat, sizeof (errformat),
379 "unrecognized label %s", *line);
380 logent(errformat, "Sysfiles|Devconfig");
381 }
382 }
383 }
384
385 /*
386 * given the list for a particular type (systems, devices,...)
387 * and a line of colon-separated files, add 'em to list
388 */
389
390 static void
setfile(char ** type,char * line)391 setfile(char **type, char *line)
392 {
393 char **tptr, *tok;
394 char expandpath[BUFSIZ];
395
396 if (*line == 0)
397 return;
398 tptr = type;
399 while (*tptr) /* skip over existing entries to */
400 tptr++; /* concatenate multiple entries */
401
402 for (tok = strtok(line, ":"); tok != NULL; tok = strtok(NULL, ":")) {
403 expandpath[0] = '\0';
404 if (*tok != '/')
405 /* by default, file names are relative to SYSDIR */
406 (void) snprintf(expandpath, sizeof (expandpath),
407 "%s/", SYSDIR);
408 (void) strcat(expandpath, tok);
409 if (eaccess(expandpath, R_OK) != 0)
410 /* if we can't read it, no point in adding to list */
411 continue;
412 *tptr = strsave(expandpath);
413 ASSERT(*tptr != NULL, "Ct_ALLOCATE", "setfile: tptr", 0);
414 tptr++;
415 }
416 *tptr = NULL;
417 }
418
419 /*
420 * given the list for a particular ioctl (push, pop)
421 * and a line of colon-separated modules, add 'em to list
422 */
423
424 static void
setioctl(char ** type,char * line)425 setioctl(char **type, char *line)
426 {
427 char **tptr, *tok;
428
429 if (*line == 0)
430 return;
431 tptr = type;
432 while (*tptr) /* skip over existing entries to */
433 tptr++; /* concatenate multiple entries */
434 for (tok = strtok(line, ":"); tok != NULL; tok = strtok(NULL, ":")) {
435 *tptr = strsave(tok);
436 ASSERT(*tptr != NULL, "Ct_ALLOCATE", "setioctl: tptr", 0);
437 tptr++;
438 }
439 }
440
441 /*
442 * reset Systems files
443 */
444 static void
sysreset(void)445 sysreset(void)
446 {
447 if (fsystems)
448 (void) fclose(fsystems);
449 fsystems = NULL;
450 nsystems = 0;
451 devreset();
452 }
453
454 /*
455 * reset Devices files
456 */
457 static void
devreset(void)458 devreset(void)
459 {
460 if (fdevices)
461 (void) fclose(fdevices);
462 fdevices = NULL;
463 ndevices = 0;
464 dialreset();
465 }
466
467 /*
468 * reset Dialers files
469 */
470 static void
dialreset(void)471 dialreset(void)
472 {
473 if (fdialers)
474 (void) fclose(fdialers);
475 fdialers = NULL;
476 ndialers = 0;
477 }
478
479 /*
480 * get next line from Systems file
481 * return TRUE if successful, FALSE if not
482 */
483 static int
getsysline(char * buf,int len)484 getsysline(char *buf, int len)
485 {
486 if (Systems[0] == NULL)
487 /* not initialized via setservice() - use default */
488 setservice("uucico");
489
490 /* initialize devices and dialers whenever a new line is read */
491 /* from systems */
492 devreset();
493 if (fsystems == NULL)
494 if (nextsystems() == FALSE)
495 return (FALSE);
496
497 for (;;) {
498 while (fgets(buf, len, fsystems) != NULL)
499 if ((*buf != '#') && (*buf != ' ') &&
500 (*buf != '\t') && (*buf != '\n'))
501 return (TRUE);
502 if (nextsystems() == FALSE)
503 return (FALSE);
504 }
505 }
506
507 /*
508 * move to next systems file. return TRUE if successful, FALSE if not
509 */
510 static int
nextsystems(void)511 nextsystems(void)
512 {
513 devreset();
514
515 if (fsystems != NULL) {
516 (void) fclose(fsystems);
517 nsystems++;
518 } else {
519 nsystems = 0;
520 }
521 for (; Systems[nsystems] != NULL; nsystems++)
522 if ((fsystems = fopen(Systems[nsystems], "rF")) != NULL)
523 return (TRUE);
524 return (FALSE);
525 }
526
527 /*
528 * get next line from Devices file
529 * return TRUE if successful, FALSE if not
530 */
531 static int
getdevline(char * buf,int len)532 getdevline(char *buf, int len)
533 {
534 if (Devices[0] == NULL)
535 /* not initialized via setservice() - use default */
536 setservice("uucico");
537
538 if (fdevices == NULL)
539 if (nextdevices() == FALSE)
540 return (FALSE);
541 for (;;) {
542 if (fgets(buf, len, fdevices) != NULL)
543 return (TRUE);
544 if (nextdevices() == FALSE)
545 return (FALSE);
546 }
547 }
548
549 /*
550 * move to next devices file. return TRUE if successful, FALSE if not
551 */
552 static int
nextdevices(void)553 nextdevices(void)
554 {
555 if (fdevices != NULL) {
556 (void) fclose(fdevices);
557 ndevices++;
558 } else {
559 ndevices = 0;
560 }
561 for (; Devices[ndevices] != NULL; ndevices++)
562 if ((fdevices = fopen(Devices[ndevices], "rF")) != NULL)
563 return (TRUE);
564 return (FALSE);
565 }
566
567
568 /*
569 * get next line from Dialers file
570 * return TRUE if successful, FALSE if not
571 */
572
573 static int
getdialline(char * buf,int len)574 getdialline(char *buf, int len)
575 {
576 if (Dialers[0] == NULL)
577 /* not initialized via setservice() - use default */
578 setservice("uucico");
579
580 if (fdialers == NULL)
581 if (nextdialers() == FALSE)
582 return (FALSE);
583 for (;;) {
584 if (fgets(buf, len, fdialers) != NULL)
585 return (TRUE);
586 if (nextdialers() == FALSE)
587 return (FALSE);
588 }
589 }
590
591 /*
592 * move to next dialers file. return TRUE if successful, FALSE if not
593 */
594 static int
nextdialers(void)595 nextdialers(void)
596 {
597 if (fdialers) {
598 (void) fclose(fdialers);
599 ndialers++;
600 } else {
601 ndialers = 0;
602 }
603
604 for (; Dialers[ndialers] != NULL; ndialers++)
605 if ((fdialers = fopen(Dialers[ndialers], "rF")) != NULL)
606 return (TRUE);
607 return (FALSE);
608 }
609
610 /*
611 * get next module to be popped
612 * return TRUE if successful, FALSE if not
613 */
614 static int
getpop(char * buf,size_t len,int * optional)615 getpop(char *buf, size_t len, int *optional)
616 {
617 int slen;
618
619 if (Pops[0] == NULL || Pops[npops] == NULL)
620 return (FALSE);
621
622 /* if the module name is enclosed in parentheses, */
623 /* is optional. set flag & strip parens */
624 slen = strlen(Pops[npops]) - 1;
625 if (Pops[npops][0] == '(' && Pops[npops][slen] == ')') {
626 *optional = 1;
627 len = (slen < len ? slen : len);
628 (void) strncpy(buf, &(Pops[npops++][1]), len);
629 } else {
630 *optional = 0;
631 (void) strncpy(buf, Pops[npops++], len);
632 }
633 buf[len-1] = '\0';
634 return (TRUE);
635 }
636
637 /*
638 * get next module to be pushed
639 * return TRUE if successful, FALSE if not
640 */
641 static int
getpush(char * buf,size_t len)642 getpush(char *buf, size_t len)
643 {
644 if (Pushes[0] == NULL || Pushes[npushes] == NULL)
645 return (FALSE);
646 (void) strncpy(buf, Pushes[npushes++], len);
647 return (TRUE);
648 }
649
650 /*
651 * pop/push requested modules
652 * return TRUE if successful, FALSE if not
653 */
654 static int
pop_push(int fd)655 pop_push(int fd)
656 {
657 char strmod[FMNAMESZ], onstream[FMNAMESZ];
658 int optional;
659
660 /* check for streams modules to pop */
661 while (getpop(strmod, sizeof (strmod), &optional)) {
662 DEBUG(5, (optional ?
663 (const char *)"pop_push: optionally POPing %s\n" :
664 (const char *)"pop_push: POPing %s\n"), strmod);
665 if (ioctl(fd, I_LOOK, onstream) == -1) {
666 DEBUG(5, "pop_push: I_LOOK on fd %d failed ", fd);
667 DEBUG(5, "errno %d\n", errno);
668 return (FALSE);
669 }
670 if (strcmp(strmod, onstream) != SAME) {
671 if (optional)
672 continue;
673 DEBUG(5, "pop_push: I_POP: %s not there\n", strmod);
674 return (FALSE);
675 }
676 if (ioctl(fd, I_POP, 0) == -1) {
677 DEBUG(5, "pop_push: I_POP on fd %d failed ", fd);
678 DEBUG(5, "errno %d\n", errno);
679 return (FALSE);
680 }
681 }
682
683 /* check for streams modules to push */
684 while (getpush(strmod, sizeof (strmod))) {
685 DEBUG(5, "pop_push: PUSHing %s\n", strmod);
686 if (ioctl(fd, I_PUSH, strmod) == -1) {
687 DEBUG(5, "pop_push: I_PUSH on fd %d failed ", fd);
688 DEBUG(5, "errno %d\n", errno);
689 return (FALSE);
690 }
691 }
692 return (TRUE);
693 }
694
695 #ifndef SMALL
696 /*
697 * return name of currently open Systems file
698 */
699 static char *
currsys(void)700 currsys(void)
701 {
702 return (Systems[nsystems]);
703 }
704
705 /*
706 * return name of currently open Devices file
707 */
708 static char *
currdev(void)709 currdev(void)
710 {
711 return (Devices[ndevices]);
712 }
713
714 /*
715 * return name of currently open Dialers file
716 */
717 static char *
currdial(void)718 currdial(void)
719 {
720 return (Dialers[ndialers]);
721 }
722 #endif
723
724 /*
725 * set configuration parameters provided in Config file
726 */
727 static void
setconfig(void)728 setconfig(void)
729 {
730 FILE *f;
731 char buf[BUFSIZ];
732 char *tok;
733 extern char _ProtoCfg[];
734
735 if ((f = fopen(CONFIG, "rF")) != 0) {
736 while (getaline(f, buf) > 0) {
737 /* got a (logical) line from Config file */
738 tok = strtok(buf, " \t");
739 if ((tok != NULL) && (*tok != '#')) {
740 /* got a token */
741 /*
742 * this probably should be table driven when
743 * the list of configurable parameters grows.
744 */
745 if (strncmp("Protocol=", tok, strlen("Protocol=")) ==
746 SAME) {
747 tok += strlen("Protocol=");
748 if (*tok != '\0') {
749 if (_ProtoCfg[0] != '\0') {
750 /*EMPTY*/
751 DEBUG(7, "Protocol string %s ",
752 tok);
753 DEBUG(7, "overrides %s\n",
754 _ProtoCfg);
755 }
756 (void) strcpy(_ProtoCfg, tok);
757 }
758 } else {
759 /*EMPTY*/
760 DEBUG(7, "Unknown configuration parameter %s\n",
761 tok);
762 }
763 }
764 }
765 (void) fclose(f);
766 }
767 }
768