xref: /386bsd/usr/src/libexec/uucp/bnu.c (revision a2142627)
1 /* bnu.c
2    Read BNU configuration files.
3 
4    Copyright (C) 1991, 1992 Ian Lance Taylor
5 
6    This file is part of the Taylor UUCP package.
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22    The author of the program may be contacted at ian@airs.com or
23    c/o AIRS, P.O. Box 520, Waltham, MA 02254.
24 
25    $Log: bnu.c,v $
26    Revision 1.35  1992/04/06  19:49:49  ian
27    Erik Forsberg: support multiple character modem classes
28 
29    Revision 1.34  1992/03/15  05:21:12  ian
30    Scott Ballantyne: accept "Any" as a device speed
31 
32    Revision 1.33  1992/03/12  19:56:10  ian
33    Debugging based on types rather than number
34 
35    Revision 1.32  1992/03/11  22:06:37  ian
36    Marty Shannon: added max-uuxqts command
37 
38    Revision 1.31  1992/03/10  21:47:39  ian
39    Added protocol command for ports
40 
41    Revision 1.30  1992/02/24  20:36:27  ian
42    Roberto Biancardi: skip spaces after strtok (NULL, "")
43 
44    Revision 1.29  1992/02/24  04:58:47  ian
45    Only permit files to be received into directories that are world-writeable
46 
47    Revision 1.28  1992/02/24  04:02:45  ian
48    Doug Evans: WRITE only applies to remote requests
49 
50    Revision 1.27  1992/02/23  19:50:50  ian
51    Handle READ and WRITE in Permissions correctly
52 
53    Revision 1.26  1992/02/14  16:45:09  ian
54    This time for sure
55 
56    Revision 1.25  1992/02/14  16:43:07  ian
57    Make the last patch better
58 
59    Revision 1.24  1992/02/14  16:39:31  ian
60    T. William Wells: must xstrdup before calling uadd_validate
61 
62    Revision 1.23  1992/02/08  03:54:18  ian
63    Include <string.h> only in <uucp.h>, added 1992 copyright
64 
65    Revision 1.22  1992/01/30  23:18:59  ian
66    Michael Nolan: stupid error in ubadd_perm
67 
68    Revision 1.21  1992/01/15  07:06:29  ian
69    Set configuration directory in Makefile rather than sysdep.h
70 
71    Revision 1.20  1991/12/28  03:49:23  ian
72    Added HAVE_MEMFNS and HAVE_BFNS; changed uses of memset to bzero
73 
74    Revision 1.19  1991/12/17  23:14:08  ian
75    T. William Wells: allow dialer complete and abort to be chat scripts
76 
77    Revision 1.18  1991/12/16  16:25:57  ian
78    Mike Bernson: ignore lines beginning with whitespace
79 
80    Revision 1.17  1991/12/15  03:42:33  ian
81    Added tprocess_chat_cmd for all chat commands, and added CMDTABTYPE_PREFIX
82 
83    Revision 1.16  1991/12/09  19:20:51  ian
84    Arne Ludwig: devices entry can be followed by list of protocols
85 
86    Revision 1.15  1991/12/03  03:43:36  ian
87    Dave Buck: time strings with grades were not parsed correctly
88 
89    Revision 1.14  1991/12/01  19:35:38  ian
90    David Nugent: read V2 and BNU files by default even with TAYLOR_CONFIG
91 
92    Revision 1.13  1991/12/01  03:10:36  ian
93    Niels Baggesen: accept dialers with no substitutions
94 
95    Revision 1.12  1991/12/01  03:04:20  ian
96    Niels Baggesen: don't free up zline in ubadd_perm; don't even pass it in
97 
98    Revision 1.11  1991/12/01  02:44:12  ian
99    Niels Baggesen: didn't handle combinations of multiple MACHINE/LOGNAME
100 
101    Revision 1.10  1991/12/01  02:31:36  ian
102    Made zread and zwrite fields of sperm structure const char *
103 
104    Revision 1.9  1991/11/30  23:39:37  ian
105    Marty Shannon: allow comments in Sysfiles
106 
107    Revision 1.8  1991/11/30  22:39:39  ian
108    Marty Shannon: don't initialize an auto array
109 
110    Revision 1.7  1991/11/26  01:04:04  ian
111    Marty Shannon: initialize ireliable for BNU and V2 configuration files
112 
113    Revision 1.6  1991/11/13  20:38:00  ian
114    Added TCP port type for connections over TCP
115 
116    Revision 1.5  1991/11/11  23:47:24  ian
117    Added chat-program to run a program to do a chat script
118 
119    Revision 1.4  1991/11/11  16:59:05  ian
120    Eliminate fread_port_info, allow NULL pflock arg to ffind_port
121 
122    Revision 1.3  1991/11/07  18:26:13  ian
123    Chip Salzenberg: can't portably take address of casted value, obviously
124 
125    Revision 1.2  1991/09/19  02:22:44  ian
126    Chip Salzenberg's patch to allow ";retrytime" at the end of a time string
127 
128    Revision 1.1  1991/09/10  19:37:52  ian
129    Initial revision
130 
131    */
132 
133 #include "uucp.h"
134 
135 #if HAVE_BNU_CONFIG
136 
137 #if USE_RCS_ID
138 char bnu_rcsid[] = "$Id: bnu.c,v 1.35 1992/04/06 19:49:49 ian Rel $";
139 #endif
140 
141 #include <ctype.h>
142 
143 #include "port.h"
144 #include "sysdep.h"
145 
146 /* Whether to use BNU configuration files.  */
147 boolean fBnu = TRUE;
148 
149 /* A list of space separated file names to interpret as Systems.  */
150 char *zBnu_systems;
151 
152 /* A list of space separated file names to interpret as Dialers.  */
153 char *zBnu_dialers;
154 
155 /* A list of space separated file names to interpret as Devices.  */
156 char *zBnu_devices;
157 
158 /* Local functions.  */
159 
160 static void ubadd_perm P((int csystems, struct ssysteminfo *passystems,
161 			  boolean **paffound));
162 static void ubadd_perm_alternate P((struct ssysteminfo *q,
163 				    boolean fmachine,
164 				    boolean flogname));
165 
166 /* Read Sysfiles to get the file names to use.  */
167 
168 void
ubnu_read_sysfiles()169 ubnu_read_sysfiles ()
170 {
171   char ab[sizeof OLDCONFIGLIB + sizeof BNU_SYSFILES - 1];
172   FILE *e;
173   char *zline;
174 
175   zBnu_systems = NULL;
176   zBnu_dialers = NULL;
177   zBnu_devices = NULL;
178 
179   sprintf (ab, "%s%s", OLDCONFIGLIB, BNU_SYSFILES);
180   e = fopen (ab, "r");
181   if (e != NULL)
182     {
183       while ((zline = zfgets (e, TRUE)) != NULL)
184 	{
185 	  int inl;
186 	  char *ztok;
187 
188 	  inl = strlen (zline) - 1;
189 	  if (zline[inl] == '\n')
190 	    zline[inl] = '\0';
191 	  if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
192 	    {
193 	      xfree ((pointer) zline);
194 	      continue;
195 	    }
196 
197 	  ztok = strtok (zline, " \t");
198 	  if (ztok == NULL)
199 	    {
200 	      xfree ((pointer) zline);
201 	      continue;
202 	    }
203 	  if (strncmp (ztok, "service=", sizeof "service=" - 1) != 0)
204 	    {
205 	      ulog (LOG_ERROR, "Unrecognized Sysfiles line: %s", ztok);
206 	      xfree ((pointer) zline);
207 	      continue;
208 	    }
209 
210 	  do
211 	    {
212 	      int c;
213 
214 	      c = strcspn (ztok, ":");
215 	      if (c == sizeof "uucico" - 1
216 		  && strncmp (ztok, "uucico", sizeof "uucico" - 1) == 0)
217 		break;
218 	      ztok += c;
219 	      if (*ztok == ':')
220 		++ztok;
221 	    }
222 	  while (*ztok != '\0');
223 
224 	  if (*ztok == '\0')
225 	    {
226 	      xfree ((pointer) zline);
227 	      continue;
228 	    }
229 
230 	  while ((ztok = strtok ((char *) NULL, " \t")) != NULL)
231 	    {
232 	      char **pz;
233 	      char *z;
234 	      boolean fend;
235 
236 	      if (strncmp (ztok, "systems=", sizeof "systems=" - 1) == 0)
237 		{
238 		  pz = &zBnu_systems;
239 		  ztok += sizeof "systems=" - 1;
240 		}
241 	      else if (strncmp (ztok, "dialers=", sizeof "dialers=" - 1) == 0)
242 		{
243 		  pz = &zBnu_dialers;
244 		  ztok += sizeof "dialers=" - 1;
245 		}
246 	      else if (strncmp (ztok, "devices=", sizeof "devices=" - 1) == 0)
247 		{
248 		  pz = &zBnu_devices;
249 		  ztok += sizeof "devices=" - 1;
250 		}
251 	      else
252 		{
253 		  ulog (LOG_ERROR, "Unrecognized Sysfiles command: %s", ztok);
254 		  continue;
255 		}
256 
257 	      /* Stick the configuration file directory in front of each
258 		 file.  */
259 	      z = ztok;
260 	      do
261 		{
262 		  int c;
263 
264 		  c = strcspn (z, ":");
265 		  fend = z[c] == '\0';
266 		  z[c] = '\0';
267 
268 		  /* Looking for a leading '/' is Unix dependent, and
269 		     should be changed.  */
270 		  if (*z == '/')
271 		    uadd_string (pz, z, ' ');
272 		  else
273 		    {
274 		      char *zdir;
275 
276 		      zdir = (char *) xmalloc (sizeof OLDCONFIGLIB
277 					       + strlen (z));
278 		      sprintf (zdir, "%s%s", OLDCONFIGLIB, z);
279 		      uadd_string (pz, zdir, ' ');
280 		      xfree ((pointer) zdir);
281 		    }
282 
283 		  z += c + 1;
284 		}
285 	      while (! fend);
286 	    }
287 
288 	  xfree ((pointer) zline);
289 	}
290 
291       (void) fclose (e);
292     }
293 
294   if (zBnu_systems == NULL)
295     {
296       zBnu_systems = (char *) xmalloc (sizeof OLDCONFIGLIB
297 				       + sizeof BNU_SYSTEMS - 1);
298       sprintf (zBnu_systems, "%s%s", OLDCONFIGLIB, BNU_SYSTEMS);
299     }
300   if (zBnu_dialers == NULL)
301     {
302       zBnu_dialers = (char *) xmalloc (sizeof OLDCONFIGLIB
303 				       + sizeof BNU_DIALERS - 1);
304       sprintf (zBnu_dialers, "%s%s", OLDCONFIGLIB, BNU_DIALERS);
305     }
306   if (zBnu_devices == NULL)
307     {
308       zBnu_devices = (char *) xmalloc (sizeof OLDCONFIGLIB
309 				       + sizeof BNU_DEVICES - 1);
310       sprintf (zBnu_devices, "%s%s", OLDCONFIGLIB, BNU_DEVICES);
311     }
312 
313 #if ! HAVE_TAYLOR_CONFIG
314   /* If we are NOT reading the new configuration files, then look for
315      Maxuuxqts.  It would be more efficient to only read the file in
316      uuxqt.c.  Too bad.  */
317   {
318     char *zmax;
319 
320     zmax = (char *) alloca (sizeof OLDCONFIGLIB +
321 			    sizeof BNU_MAXUUXQTS - 1);
322     sprintf (zmax, "%s%s", OLDCONFIGLIB, BNU_MAXUUXQTS);
323     e = fopen (zmax, "r");
324     if (e != NULL)
325       {
326 	zline = zfgets (e, FALSE);
327 	if (zline != NULL)
328 	  {
329 	    cMaxuuxqts = atoi (zline);
330 	    if (cMaxuuxqts < 0)
331 	      cMaxuuxqts = 0;
332 	    xfree ((pointer) zline);
333 	  }
334 	(void) fclose (e);
335       }
336   }
337 #endif /* ! HAVE_TAYLOR_CONFIG */
338 }
339 
340 /* A little routine to add a grade and a time string to a system.  */
341 
342 static void ubadd_time P((struct ssysteminfo *q, int bgrade,
343 			  const char *ztime, int cretry));
344 
345 static void
ubadd_time(q,bgrade,ztime,cretry)346 ubadd_time (q, bgrade, ztime, cretry)
347      struct ssysteminfo *q;
348      int bgrade;
349      const char *ztime;
350      int cretry;
351 {
352   char *zset;
353 
354   zset = (char *) alloca (strlen (ztime) + 20);
355   if (cretry == 0)
356     sprintf (zset, "%c%s", bgrade, ztime);
357   else
358     sprintf (zset, "%c%s;%d", bgrade, ztime, cretry);
359   uadd_string (&q->ztime, zset, ' ');
360 }
361 
362 /* These structures are used to read the Permissions file.  */
363 
364 static struct sperm
365 {
366   char *zlogname;
367   char *zmachine;
368   boolean frequest;
369   enum { SENDFILES_YES, SENDFILES_CALL, SENDFILES_NO } tsendfiles;
370   const char *zread;
371   const char *zwrite;
372   char *znoread;
373   char *znowrite;
374   boolean fcallback;
375   const char *zcommands;
376   char *zvalidate;
377   char *zmyname;
378   char *zpubdir;
379 } sBperm;
380 
381 static enum tcmdtabret tbsendfiles P((int argc, char **argv,
382 				      pointer pvar, const char *zerr));
383 
384 static struct scmdtab asBperm_cmds[] =
385 {
386   { "LOGNAME", CMDTABTYPE_STRING, (pointer) &sBperm.zlogname, NULL },
387   { "MACHINE", CMDTABTYPE_STRING, (pointer) &sBperm.zmachine, NULL },
388   { "REQUEST", CMDTABTYPE_BOOLEAN, (pointer) &sBperm.frequest, NULL },
389   { "SENDFILES", CMDTABTYPE_FN | 2, NULL, tbsendfiles },
390   { "READ", CMDTABTYPE_STRING, (pointer) &sBperm.zread, NULL },
391   { "WRITE", CMDTABTYPE_STRING, (pointer) &sBperm.zwrite, NULL },
392   { "NOREAD", CMDTABTYPE_STRING, (pointer) &sBperm.znoread, NULL },
393   { "NOWRITE", CMDTABTYPE_STRING, (pointer) &sBperm.znowrite, NULL },
394   { "CALLBACK", CMDTABTYPE_BOOLEAN, (pointer) &sBperm.fcallback, NULL },
395   { "COMMANDS", CMDTABTYPE_STRING, (pointer) &sBperm.zcommands, NULL },
396   { "VALIDATE", CMDTABTYPE_STRING, (pointer) &sBperm.zvalidate, NULL },
397   { "MYNAME", CMDTABTYPE_STRING, (pointer) &sBperm.zmyname, NULL },
398   { "PUBDIR", CMDTABTYPE_STRING, (pointer) &sBperm.zpubdir, NULL },
399   { NULL, 0, NULL, NULL }
400 };
401 
402 static struct spermlist
403 {
404   struct spermlist *qnext;
405   struct sperm sperm;
406 } *qBothers;
407 
408 /* Read BNU system information.  This means reading the Systems file
409    and the Permissions file.  */
410 
411 void
ubnu_read_systems(pc,ppas)412 ubnu_read_systems (pc, ppas)
413      int *pc;
414      struct ssysteminfo **ppas;
415 {
416   int calc;
417   struct smulti_file *qmulti;
418   char *zline;
419 
420   *pc = 0;
421   *ppas = NULL;
422   calc = 0;
423 
424   /* Read the Systems file(s) first.  */
425   qmulti = qmulti_open (zBnu_systems);
426   if (qmulti == NULL)
427     return;
428 
429   while ((zline = zmulti_gets (qmulti, (boolean *) NULL,
430 			       (const char **) NULL, TRUE)) != NULL)
431     {
432       int inl;
433       char *ztok;
434       int i, cretry;
435       struct ssysteminfo *qset;
436       char *zsemi, *zslash;
437 
438       inl = strlen (zline) - 1;
439       if (zline[inl] == '\n')
440 	zline[inl] = '\0';
441       if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
442 	{
443 	  xfree ((pointer) zline);
444 	  continue;
445 	}
446 
447       ztok = strtok (zline, " \t");
448       if (ztok == NULL)
449 	{
450 	  xfree ((pointer) zline);
451 	  continue;
452 	}
453 
454       DEBUG_MESSAGE1 (DEBUG_CONFIG,
455 		      "ubnu_read_systems: Reading system %s", ztok);
456 
457       /* See if we already have information for this system.  */
458       for (i = 0; i < *pc; i++)
459 	if (strcmp ((*ppas)[i].zname, ztok) == 0)
460 	  break;
461       if (i >= *pc)
462 	{
463 	  if (*pc >= calc)
464 	    {
465 	      calc += 10;
466 	      *ppas = ((struct ssysteminfo *)
467 		       xrealloc ((pointer) *ppas,
468 				 calc * sizeof (struct ssysteminfo)));
469 	    }
470 	  qset = &(*ppas)[*pc];
471 	  (*pc)++;
472 	}
473       else
474 	{
475 	  struct ssysteminfo **pq;
476 
477 	  for (pq = &(*ppas)[i].qalternate;
478 	       *pq != NULL;
479 	       pq = &(*pq)->qalternate)
480 	    ;
481 	  *pq = (struct ssysteminfo *) xmalloc (sizeof (struct ssysteminfo));
482 	  qset = *pq;
483 	}
484 
485       uset_system_defaults (qset);
486       qset->zname = ztok;
487 
488       /* Under BNU, a local request is permitted to write into any
489 	 directory that is world writeable.  */
490       qset->zlocal_receive = "/";
491 
492       /* Get the time string.  */
493       ztok = strtok ((char *) NULL, " \t");
494       if (ztok == NULL)
495 	continue;
496 
497       /* The time string is "time/grade,time/grade;retry".  A missing
498 	 grade is taken as 'z'.  */
499 
500       cretry = 0;
501       zsemi = strchr (ztok, ';');
502       if (zsemi != NULL)
503 	{
504 	  *zsemi = '\0';
505 	  cretry = atoi (zsemi + 1);
506 	}
507 
508       qset->ztime = NULL;
509       while (TRUE)
510 	{
511 	  char *zcomma;
512 
513 	  zcomma = strchr (ztok, ',');
514 	  if (zcomma != NULL)
515 	    *zcomma = '\0';
516 
517 	  zslash = strchr (ztok, '/');
518 	  if (zslash == NULL || zslash[1] == '\0')
519 	    ubadd_time (qset, BGRADE_LOW, ztok, cretry);
520 	  else
521 	    {
522 	      *zslash = '\0';
523 	      ubadd_time (qset, zslash[1], ztok, cretry);
524 	    }
525 
526 	  if (zcomma == NULL)
527 	    break;
528 
529 	  ztok = zcomma + 1;
530 	}
531 
532       /* Get the devices entry.  */
533       qset->zport = strtok ((char *) NULL, " \t");
534 
535       /* Get the speed entry.  If it starts with a nondigit, it's a
536 	 modem class.  We append it to the device name, and do the
537 	 same thing when reading the Devices file, since we don't need
538 	 to preserve the ``ACU''.  I've heard that the modem class is
539 	 permitted at either end, but this code doesn't support that.
540 	 A range of speeds is also permitted.  */
541       if (qset->zport != NULL)
542 	{
543 
544 	  /* According to Arne Ludwig, the devices entry can be
545 	     followed by a comma and a list of protocols.  */
546 	  ztok = strrchr (qset->zport, ',');
547 	  if (ztok != NULL && ztok[1] != '\0')
548 	    {
549 	      qset->zprotocols = ztok + 1;
550 	      *ztok = '\0';
551 	    }
552 
553 	  ztok = strtok ((char *) NULL, " \t");
554 	  if (ztok != NULL)
555 	    {
556 	      boolean fany;
557 
558 	      fany = (strcmp (ztok, "Any") == 0
559 		      || strcmp (ztok, "-") == 0);
560 
561 	      if (! isdigit (*ztok) && ! fany)
562 		{
563 		  int clen;
564 		  char *zport, *zset;
565 
566 		  clen = strlen (qset->zport);
567 		  zport = (char *) xmalloc (clen + strlen (ztok) + 1);
568 		  strcpy (zport, qset->zport);
569 		  zset = zport + clen;
570 		  while (*ztok != '\0' && ! isdigit (*ztok))
571 		    *zset++ = *ztok++;
572 		  *zset = '\0';
573 		  qset->zport = zport;
574 		}
575 
576 	      if (fany)
577 		qset->ibaud = 0;
578 	      else
579 		{
580 		  qset->ibaud = strtol (ztok, &ztok, 10);
581 		  if (*ztok == '-')
582 		    qset->ihighbaud = atol (ztok + 1);
583 		}
584 
585 	      /* Get the phone number.  */
586 	      qset->zphone = strtok ((char *) NULL, " \t");
587 
588 	      /* The rest of the line is the login script.  */
589 	      if (qset->zphone != NULL)
590 		{
591 		  qset->schat.zchat = strtok ((char *) NULL, "");
592 		  qset->schat.zchat += strspn (qset->schat.zchat, " \t");
593 		}
594 	    }
595 	}
596     }
597 
598   (void) fmulti_close (qmulti);
599 
600   /* Now we have to read the Permissions file.  */
601 
602   {
603     char abperm[sizeof OLDCONFIGLIB + sizeof BNU_PERMISSIONS - 1];
604     const char * const zpubdir = PUBDIR;
605     FILE *e;
606     boolean *affound;
607 
608     sprintf (abperm, "%s%s", OLDCONFIGLIB, BNU_PERMISSIONS);
609     e = fopen (abperm, "r");
610     if (e == NULL)
611       return;
612 
613     affound = (boolean *) alloca (*pc * sizeof (boolean));
614     bzero (affound, *pc * sizeof (boolean));
615 
616     while ((zline = zfgets (e, TRUE)) != NULL)
617       {
618 	int inl;
619 	char *ztok;
620 	boolean fany;
621 
622 	inl = strlen (zline) - 1;
623 	if (zline[inl] == '\n')
624 	  zline[inl] = '\0';
625 	if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
626 	  {
627 	    xfree ((pointer) zline);
628 	    continue;
629 	  }
630 
631 	sBperm.zlogname = NULL;
632 	sBperm.zmachine = NULL;
633 	sBperm.frequest = FALSE;
634 	sBperm.tsendfiles = SENDFILES_CALL;
635 	sBperm.zread = zpubdir;
636 	sBperm.zwrite = zpubdir;
637 	sBperm.znoread = NULL;
638 	sBperm.znowrite = NULL;
639 	sBperm.fcallback = FALSE;
640 	sBperm.zcommands = "rnews rmail";
641 	sBperm.zvalidate = NULL;
642 	sBperm.zmyname = NULL;
643 	sBperm.zpubdir = NULL;
644 
645 	fany = FALSE;
646 
647 	for (ztok = strtok (zline, " \t");
648 	     ztok != NULL;
649 	     ztok = strtok ((char *) NULL, " \t"))
650 	  {
651 	    char *zeq;
652 	    char *azargs[2];
653 
654 	    fany = TRUE;
655 
656 	    zeq = strchr (ztok, '=');
657 	    if (zeq == NULL)
658 	      {
659 		ulog (LOG_ERROR, "Bad %s entry: %s", BNU_PERMISSIONS,
660 		      ztok);
661 		continue;
662 	      }
663 	    *zeq = '\0';
664 
665 	    azargs[0] = ztok;
666 	    azargs[1] = zeq + 1;
667 	    (void) tprocess_one_cmd (2, azargs, asBperm_cmds,
668 				     BNU_PERMISSIONS, CMDFLAG_WARNUNRECOG);
669 	  }
670 
671 	if (! fany)
672 	  continue;
673 
674 	if (sBperm.zlogname != NULL)
675 	  {
676 	    char *zstart;
677 	    boolean fend;
678 
679 	    /* Process each LOGNAME separately.  */
680 	    zstart = sBperm.zlogname;
681 	    do
682 	      {
683 		int c;
684 
685 		c = strcspn (zstart, ":");
686 		fend = zstart[c] == '\0';
687 		zstart[c] = '\0';
688 
689 		sBperm.zlogname = zstart;
690 		ubadd_perm (*pc, *ppas, &affound);
691 
692 		zstart += c + 1;
693 	      }
694 	    while (! fend);
695 	  }
696 	else if (sBperm.zmachine != NULL)
697 	  ubadd_perm (*pc, *ppas, &affound);
698 	else
699 	  {
700 	    ulog (LOG_ERROR,
701 		  "%s: No MACHINE or LOGNAME entry: \"%s\"",
702 		  BNU_PERMISSIONS, zline);
703 	    xfree ((pointer) zline);
704 	  }
705       }
706 
707     (void) fclose (e);
708 
709     /* If there were any MACHINE=OTHER entry, add the permissions for
710        each machine that was not specified by name.  */
711 
712     while (qBothers != NULL)
713       {
714 	int i;
715 	struct spermlist *qnext;
716 
717 	sBperm = qBothers->sperm;
718 	for (i = 0; i < *pc; i++)
719 	  {
720 	    if (! affound[i])
721 	      {
722 		sBperm.zmachine = xstrdup ((*ppas)[i].zname);
723 		ubadd_perm (*pc, *ppas, &affound);
724 		xfree ((pointer) sBperm.zmachine);
725 	      }
726 	  }
727 
728 	qnext = qBothers->qnext;
729 	xfree ((pointer) qBothers);
730 	qBothers = qnext;
731       }
732   }
733 }
734 
735 /* Look up a machine and attach permissions to it.  */
736 
737 static void
ubadd_perm(csystems,passystems,paffound)738 ubadd_perm (csystems, passystems, paffound)
739      int csystems;
740      struct ssysteminfo *passystems;
741      boolean **paffound;
742 {
743   if (sBperm.zmachine != NULL)
744     {
745       char *zcopy;
746       char *ztok;
747 
748       if (strcmp (sBperm.zmachine, "OTHER") == 0)
749 	{
750 	  struct spermlist *qnew;
751 
752 	  qnew = (struct spermlist *) xmalloc (sizeof (struct spermlist));
753 	  qnew->qnext = qBothers;
754 	  qnew->sperm = sBperm;
755 	  qBothers = qnew;
756 	  return;
757 	}
758 
759       zcopy = (char *) alloca (strlen (sBperm.zmachine) + 1);
760       strcpy (zcopy, sBperm.zmachine);
761 
762       for (ztok = strtok (zcopy, ":");
763 	   ztok != NULL;
764 	   ztok = strtok ((char *) NULL, ":"))
765 	{
766 	  int i;
767 	  struct ssysteminfo *q;
768 
769 	  for (i = 0; i < csystems; i++)
770 	    if (strcmp (passystems[i].zname, ztok) == 0)
771 	      break;
772 	  if (i >= csystems)
773 	    {
774 	      /* We just ignore Permissions entries for unknown
775 		 systems.  */
776 	      continue;
777 	    }
778 
779 	  if ((*paffound)[i])
780 	    {
781 	      struct ssysteminfo **pq;
782 
783 	      /* We have already handled this machine.  Make a copy of
784 		 the first alternate and set the login name to
785 		 whatever this entry wants.  Then put the new entry at
786 		 the end of list of alternates.  This will make
787 		 whatever we saw first the default.  */
788 	      q = ((struct ssysteminfo *)
789 		   xmalloc (sizeof (struct ssysteminfo)));
790 	      *q = passystems[i];
791 	      q->qalternate = NULL;
792 	      for (pq = &passystems[i].qalternate;
793 		   *pq != NULL;
794 		   pq = &(*pq)->qalternate)
795 		;
796 	      *pq = q;
797 	      q->zcalled_login = "ANY";
798 	      ubadd_perm_alternate (q, TRUE, sBperm.zlogname != NULL);
799 	    }
800 	  else
801 	    {
802 	      (*paffound)[i] = TRUE;
803 	      for (q = &passystems[i]; q != NULL; q = q->qalternate)
804 		ubadd_perm_alternate (q, TRUE,
805 				      sBperm.zlogname != NULL);
806 	    }
807 	}
808     }
809   else
810     {
811       int i;
812 
813 #if DEBUG > 0
814       if (sBperm.zlogname == NULL)
815 	ulog (LOG_FATAL, "bnu.c: ubadd_perm: Can't happen");
816 #endif
817 
818       /* There was a LOGNAME= but no MACHINE=.  We must add an
819 	 alternate specifying this LOGNAME to all machines.  */
820 
821       for (i = 0; i < csystems; i++)
822 	{
823 	  struct ssysteminfo *q;
824 
825 	  if (passystems[i].zcalled_login == NULL)
826 	    passystems[i].zcalled_login = "ANY";
827 
828 	  q = (struct ssysteminfo *) xmalloc (sizeof (struct ssysteminfo));
829 	  *q = passystems[i];
830 	  q->qalternate = passystems[i].qalternate;
831 	  passystems[i].qalternate = q;
832 
833 	  ubadd_perm_alternate (q, FALSE, TRUE);
834 	}
835     }
836 }
837 
838 /* Attach permissions to a specific alternate of a machine.  */
839 
840 static void
ubadd_perm_alternate(q,fmachine,flogname)841 ubadd_perm_alternate (q, fmachine, flogname)
842      struct ssysteminfo *q;
843      boolean fmachine;
844      boolean flogname;
845 {
846   char *z, *zset;
847 
848   if (flogname)
849     {
850       if (q->zcalled_login != NULL
851 	  && strcmp (q->zcalled_login, "ANY") != 0)
852 	ulog (LOG_ERROR, "%s: Can't handle two login names for one machine",
853 	      q->zname);
854       else
855 	q->zcalled_login = sBperm.zlogname;
856     }
857   if (fmachine)
858     q->fcall_request = sBperm.frequest;
859   if (flogname)
860     q->fcalled_request = sBperm.frequest;
861   if (flogname)
862     {
863       q->fcall_transfer = (sBperm.tsendfiles == SENDFILES_CALL
864 			   || (sBperm.tsendfiles == SENDFILES_YES));
865       q->fcalled_transfer = sBperm.tsendfiles == SENDFILES_YES;
866     }
867 
868   zset = xstrdup (sBperm.zread);
869   while ((z = strchr (zset, ':')) != NULL)
870     *z = ' ';
871   if (sBperm.znoread != NULL)
872     {
873       char *zstart;
874       boolean fend;
875 
876       zstart = xstrdup (sBperm.znoread);
877       do
878 	{
879 	  char *zalloc;
880 	  int c;
881 
882 	  c = strcspn (zstart, ":");
883 	  fend = zstart[c] == '\0';
884 	  zstart[c] = '\0';
885 
886 	  zalloc = (char *) xmalloc (c + 2);
887 	  sprintf (zalloc, "!%s", zstart);
888 	  uadd_string (&zset, zalloc, ' ');
889 	  xfree ((pointer) zalloc);
890 
891 	  zstart += c + 1;
892 	}
893       while (! fend);
894     }
895   if (fmachine)
896     q->zremote_send = zset;
897   if (flogname)
898     {
899       if (fmachine)
900 	q->zcalled_remote_send = NULL;
901       else
902 	q->zcalled_remote_send = zset;
903     }
904 
905   zset = xstrdup (sBperm.zwrite);
906   while ((z = strchr (zset, ':')) != NULL)
907     *z = ' ';
908   if (sBperm.znowrite != NULL)
909     {
910       char *zstart;
911       boolean fend;
912 
913       zstart = xstrdup (sBperm.znowrite);
914       do
915 	{
916 	  char *zalloc;
917 	  int c;
918 
919 	  c = strcspn (zstart, ":");
920 	  fend = zstart[c] == '\0';
921 	  zstart[c] = '\0';
922 
923 	  zalloc = (char *) xmalloc (c + 2);
924 	  sprintf (zalloc, "!%s", zstart);
925 	  uadd_string (&zset, zalloc, ' ');
926 	  xfree ((pointer) zalloc);
927 
928 	  zstart += c + 1;
929 	}
930       while (! fend);
931     }
932   if (fmachine)
933     q->zremote_receive = zset;
934   if (flogname)
935     {
936       if (fmachine)
937 	q->zcalled_remote_receive = NULL;
938       else
939 	q->zcalled_remote_receive = zset;
940     }
941 
942   if (flogname)
943     q->fcallback = sBperm.fcallback;
944 
945   if (fmachine && sBperm.zcommands != NULL)
946     {
947       q->zcmds = sBperm.zcommands;
948       while ((z = strchr (q->zcmds, ':')) != NULL)
949 	*z = ' ';
950     }
951 
952   if (flogname && sBperm.zvalidate != NULL)
953     {
954       char *zcopy;
955       boolean fend;
956 
957       zcopy = xstrdup (sBperm.zvalidate);
958 
959       do
960 	{
961 	  int c;
962 
963 	  c = strcspn (zcopy, ":");
964 	  fend = zcopy[c] == '\0';
965 	  zcopy[c] = '\0';
966 
967 	  uadd_validate (sBperm.zlogname, 1, (const char **) &zcopy);
968 
969 	  zcopy += c + 1;
970 	}
971       while (! fend);
972     }
973 
974   if (fmachine)
975     q->zlocalname = sBperm.zmyname;
976 
977   /* This isn't quite right, since the BNU Permissions file can
978      specify a different public directory based on whether we are
979      calling out or are being called.  */
980   if (sBperm.zpubdir != NULL)
981     q->zpubdir = sBperm.zpubdir;
982 }
983 
984 /* Handle SENDFILES=string, where string can be YES, NO or CALL.  We
985    actually only switch off on the first letter.  */
986 
987 /*ARGSUSED*/
988 static enum tcmdtabret
tbsendfiles(argc,argv,pvar,zerr)989 tbsendfiles (argc, argv, pvar, zerr)
990      int argc;
991      char **argv;
992      pointer pvar;
993      const char *zerr;
994 {
995   switch (argv[1][0])
996     {
997     case 'C':
998     case 'c':
999       sBperm.tsendfiles = SENDFILES_CALL;
1000       break;
1001     case 'N':
1002     case 'n':
1003       sBperm.tsendfiles = SENDFILES_NO;
1004       break;
1005     case 'Y':
1006     case 'y':
1007       sBperm.tsendfiles = SENDFILES_YES;
1008       break;
1009     default:
1010       ulog (LOG_ERROR, "%s: Unrecognized SENDFILES=%s", zerr, argv[1]);
1011       break;
1012     }
1013 
1014   return CMDTABRET_FREE;
1015 }
1016 
1017 /* Find a port with a given name and baud rate in the Devices file,
1018    and lock it.  If found and locked, fill in the structure pointed at
1019    by qport.  Set *pffound to TRUE if a port was found but could not
1020    be locked.  */
1021 
1022 boolean
fbnu_find_port(zname,ibaud,ihighbaud,qport,pflock,pffound)1023 fbnu_find_port (zname, ibaud, ihighbaud, qport, pflock, pffound)
1024      const char *zname;
1025      long ibaud;
1026      long ihighbaud;
1027      struct sport *qport;
1028      boolean (*pflock) P((struct sport *, boolean fin));
1029      boolean *pffound;
1030 {
1031   struct smulti_file *qmulti;
1032   char *zline;
1033 
1034   qmulti = qmulti_open (zBnu_devices);
1035   if (qmulti == NULL)
1036     return FALSE;
1037 
1038   while ((zline = zmulti_gets (qmulti, (boolean *) NULL,
1039 			       (const char **) NULL, TRUE)) != NULL)
1040     {
1041       int inl;
1042       char *ztok, *zportname, *zprotocols, *zdevice, *zdial_device;
1043       long ilow, ihigh;
1044 
1045       inl = strlen (zline) - 1;
1046       if (zline[inl] == '\n')
1047 	zline[inl] = '\0';
1048       if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
1049 	{
1050 	  xfree ((pointer) zline);
1051 	  continue;
1052 	}
1053 
1054       /* An entry in Devices is type device dial-device baud
1055 	 dialer-token pairs.  */
1056 
1057       /* Get the port type.  */
1058       zportname = strtok (zline, " \t");
1059       if (zportname == NULL)
1060 	{
1061 	  xfree ((pointer) zline);
1062 	  continue;
1063 	}
1064 
1065       /* There may be a comma separated list of protocols following
1066 	 the port name.  */
1067       zprotocols = strchr (zportname, ',');
1068       if (zprotocols != NULL)
1069 	{
1070 	  *zprotocols = '\0';
1071 	  ++zprotocols;
1072 	}
1073 
1074       /* Get the device name.  */
1075       zdevice = strtok ((char *) NULL, " \t");
1076       if (zdevice == NULL)
1077 	{
1078 	  xfree ((pointer) zline);
1079 	  continue;
1080 	}
1081 
1082       /* Some systems seem to permit ,M at the end of the device name;
1083 	 this means to open the port with O_NDELAY and then allow
1084 	 delays later.  We always do this anyhow, so I just ignore the
1085 	 ,M.  There may be portability problems here.  */
1086       zdevice[strcspn (zdevice, ",")] = '\0';
1087 
1088       /* Get the dial-device.  A value of ``-'' means none.  */
1089       zdial_device = strtok ((char *) NULL, " \t");
1090       if (zdial_device == NULL)
1091 	{
1092 	  xfree ((pointer) zline);
1093 	  continue;
1094 	}
1095       if (strcmp (zdial_device, "-") == 0)
1096 	zdial_device = NULL;
1097 
1098       /* Get the speed.  */
1099       ztok = strtok ((char *) NULL, " \t");
1100       if (ztok == NULL)
1101 	{
1102 	  xfree ((pointer) zline);
1103 	  continue;
1104 	}
1105 
1106       /* See whether we match the port name we are looking for.  If
1107 	 the speed starts with a non-digit, it is a modem class (but
1108 	 "-" or "Any" mean any speed).  When reading the Systems file
1109 	 we appended the modem class to the device name, so we must
1110 	 match appropriately.  */
1111       if (isdigit (*ztok)
1112 	  || strcmp (ztok, "-") == 0
1113 	  || strcmp (ztok, "Any") == 0)
1114 	{
1115 	  if (zname != NULL && strcmp (zname, zportname) != 0)
1116 	    {
1117 	      xfree ((pointer) zline);
1118 	      continue;
1119 	    }
1120 	}
1121       else
1122 	{
1123 	  char *zclass, *zset;
1124 
1125 	  zclass = (char *) alloca (strlen (ztok) + 1);
1126 	  zset = zclass;
1127 	  while (*ztok != '\0' && ! isdigit (*ztok))
1128 	    *zset++ = *ztok++;
1129 	  *zset = '\0';
1130 
1131 	  if (zname != NULL)
1132 	    {
1133 	      int clen;
1134 
1135 	      clen = strlen (zportname);
1136 	      if (strncmp (zname, zportname, clen) != 0
1137 		  || strlen (zname) <= clen
1138 		  || strcmp (zname + clen, zclass) != 0)
1139 		{
1140 		  xfree ((pointer) zline);
1141 		  continue;
1142 		}
1143 	    }
1144 	}
1145 
1146       ilow = strtol (ztok, &ztok, 10);
1147       if (ilow == 0)
1148 	ihigh = 38400L;
1149       else
1150 	{
1151 	  if (*ztok == '-')
1152 	    ihigh = atol (ztok + 1);
1153 	  else
1154 	    ihigh = ilow;
1155 	}
1156 
1157       /* Now we must match the range ibaud to ihighbaud against to
1158 	 range ilow to ihigh.  */
1159       if (ibaud != 0
1160 	  && (ihighbaud < ilow || ibaud > ihigh))
1161 	{
1162 	  xfree ((pointer) zline);
1163 	  continue;
1164 	}
1165 
1166       /* We have found a matching port.  We now fill in the sport
1167 	 structure so that we can try to lock it.  */
1168       if (zname != NULL)
1169 	qport->zname = zname;
1170       else
1171 	qport->zname = zportname;
1172       qport->zprotocols = zprotocols;
1173       qport->cproto_params = 0;
1174       qport->qproto_params = NULL;
1175       qport->ireliable = 0;
1176       qport->zlockname = NULL;
1177       if (strcmp (qport->zname, "Direct") == 0)
1178 	{
1179 	  qport->ttype = PORTTYPE_DIRECT;
1180 	  qport->u.sdirect.zdevice = zdevice;
1181 	  qport->u.sdirect.ibaud = ilow;
1182 #ifdef SYSDEP_DIRECT_INIT
1183 	  SYSDEP_DIRECT_INIT (&qport->u.sdirect.s);
1184 #endif
1185 	}
1186 #if HAVE_TCP
1187       else if (strcmp (qport->zname, "TCP") == 0)
1188 	{
1189 	  qport->ttype = PORTTYPE_TCP;
1190 	  qport->ireliable = (RELIABLE_ENDTOEND
1191 			      | RELIABLE_RELIABLE
1192 			      | RELIABLE_EIGHT
1193 			      | RELIABLE_SPECIFIED);
1194 	  qport->u.stcp.o = -1;
1195 	  qport->u.stcp.zport = zdevice;
1196 	}
1197 #endif /* HAVE_TCP */
1198       else
1199 	{
1200 	  qport->ttype = PORTTYPE_MODEM;
1201 	  qport->u.smodem.zdevice = zdevice;
1202 	  qport->u.smodem.zdial_device = zdial_device;
1203 	  if (ilow != ihigh)
1204 	    qport->u.smodem.ibaud = 0;
1205 	  else
1206 	    qport->u.smodem.ibaud = ilow;
1207 	  qport->u.smodem.ilowbaud = ilow;
1208 	  qport->u.smodem.ihighbaud = ihigh;
1209 	  qport->u.smodem.fcarrier = TRUE;
1210 	  qport->u.smodem.zdialer = strtok ((char *) NULL, "");
1211 	  qport->u.smodem.zdialer += strspn (qport->u.smodem.zdialer,
1212 					     " \t");
1213 	  qport->u.smodem.qdialer = NULL;
1214 #ifdef SYSDEP_MODEM_INIT
1215 	  SYSDEP_MODEM_INIT (&qport->u.smodem.s);
1216 #endif
1217 	}
1218 
1219       if (pffound != NULL)
1220 	*pffound = TRUE;
1221 
1222       if (pflock != NULL
1223 	  && ! (*pflock) (qport, FALSE))
1224 	{
1225 	  xfree ((pointer) zline);
1226 	  continue;
1227 	}
1228 
1229       (void) fmulti_close (qmulti);
1230 
1231       return TRUE;
1232     }
1233 
1234   (void) fmulti_close (qmulti);
1235 
1236   return FALSE;
1237 }
1238 
1239 /* Read dialer information from the Dialers file.  */
1240 
1241 boolean
fbnu_read_dialer_info(zdialer,qdialer)1242 fbnu_read_dialer_info (zdialer, qdialer)
1243      const char *zdialer;
1244      struct sdialer *qdialer;
1245 {
1246   struct smulti_file *qmulti;
1247   char *zline;
1248 
1249   qmulti = qmulti_open (zBnu_dialers);
1250   if (qmulti == NULL)
1251     return FALSE;
1252 
1253   while ((zline = zmulti_gets (qmulti, (boolean *) NULL,
1254 			       (const char **) NULL, TRUE)) != NULL)
1255     {
1256       int inl;
1257       char *zname, *zsubs;
1258 
1259       inl = strlen (zline) - 1;
1260       if (zline[inl] == '\n')
1261 	zline[inl] = '\0';
1262       if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
1263 	{
1264 	  xfree ((pointer) zline);
1265 	  continue;
1266 	}
1267 
1268       zname = strtok (zline, " \t");
1269       if (zname == NULL
1270 	  || strcmp (zname, zdialer) != 0)
1271 	{
1272 	  xfree ((pointer) zline);
1273 	  continue;
1274 	}
1275 
1276       /* We found the dialer we want.  Get information from it.  */
1277 
1278       qdialer->zname = zdialer;
1279       INIT_CHAT (&qdialer->schat);
1280       qdialer->zdialtone = ",";
1281       qdialer->zpause = ",";
1282       qdialer->fcarrier = TRUE;
1283       qdialer->ccarrier_wait = 60;
1284       qdialer->fdtr_toggle = FALSE;
1285       qdialer->fdtr_toggle_wait = FALSE;
1286       INIT_CHAT (&qdialer->scomplete);
1287       INIT_CHAT (&qdialer->sabort);
1288       qdialer->cproto_params = 0;
1289       qdialer->qproto_params = NULL;
1290       qdialer->ireliable = 0;
1291 
1292       zsubs = strtok ((char *) NULL, " \t");
1293 
1294       if (zsubs != NULL && strcmp (zsubs, "\"\"") != 0)
1295 	{
1296 	  char bnext;
1297 
1298 	  bnext = *zsubs;
1299 	  while (bnext != '\0')
1300 	    {
1301 	      if (zsubs[1] == '\0')
1302 		break;
1303 	      if (bnext == '=')
1304 		qdialer->zdialtone = zsubs + 1;
1305 	      else if (bnext == '-')
1306 		qdialer->zpause = zsubs + 1;
1307 	      zsubs += 2;
1308 	      bnext = *zsubs;
1309 	      *zsubs = '\0';
1310 	    }
1311 	}
1312 
1313       if (zsubs == NULL)
1314 	qdialer->schat.zchat = NULL;
1315       else
1316 	{
1317 	  qdialer->schat.zchat = strtok ((char *) NULL, "");
1318 	  qdialer->schat.zchat += strspn (qdialer->schat.zchat, " \t");
1319 	}
1320 
1321       (void) fmulti_close (qmulti);
1322 
1323       return TRUE;
1324     }
1325 
1326   (void) fmulti_close (qmulti);
1327 
1328   return FALSE;
1329 }
1330 
1331 #endif /* HAVE_BNU_CONFIG */
1332