]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - gnu/libexec/uucp/libuuconf/hsinfo.c
$Id$ -> $FreeBSD$
[FreeBSD/FreeBSD.git] / gnu / libexec / uucp / libuuconf / hsinfo.c
1 /* hsinfo.c
2    Get information about a system from the HDB configuration files.
3
4    Copyright (C) 1992, 1993, 1995 Ian Lance Taylor
5
6    This file is part of the Taylor UUCP uuconf library.
7
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Library General Public License
10    as published by the Free Software Foundation; either version 2 of
11    the License, or (at your option) any later version.
12
13    This library 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    Library General Public License for more details.
17
18    You should have received a copy of the GNU Library General Public
19    License along with this library; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
22    The author of the program may be contacted at ian@airs.com or
23    c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
24    */
25
26 #include "uucnfi.h"
27
28 #if USE_RCS_ID
29 const char _uuconf_hsinfo_rcsid[] = "$FreeBSD$";
30 #endif
31
32 #include <errno.h>
33 #include <ctype.h>
34 \f
35 static int ihadd_machine_perm P((struct sglobal *qglobal,
36                                  struct uuconf_system *qsys,
37                                  struct shpermissions *qperm));
38 static int ihadd_logname_perm P((struct sglobal *qglobal,
39                                  struct uuconf_system *qsys,
40                                  struct shpermissions *qperm));
41 \f
42 /* Get the information for a particular system from the HDB
43    configuration files.  This does not make sure that all the default
44    values are set.  */
45
46 int
47 _uuconf_ihdb_system_internal (qglobal, zsystem, qsys)
48      struct sglobal *qglobal;
49      const char *zsystem;
50      struct uuconf_system *qsys;
51 {
52   int iret;
53   struct shpermissions *qperm;
54   char *zline;
55   size_t cline;
56   char **pzsplit;
57   size_t csplit;
58   char **pzcomma;
59   size_t ccomma;
60   pointer pblock;
61   char **pz;
62   boolean ffound_machine, ffound_login;
63   struct shpermissions *qother_machine;
64   struct uuconf_system *qalt;
65
66   if (! qglobal->qprocess->fhdb_read_permissions)
67     {
68       iret = _uuconf_ihread_permissions (qglobal);
69       if (iret != UUCONF_SUCCESS)
70         return iret;
71     }
72
73   /* First look through the Permissions information to see if this is
74      an alias for some system.  I assume that an alias applies to the
75      first name in the corresponding MACHINE entry.  */
76
77   for (qperm = qglobal->qprocess->qhdb_permissions;
78        qperm != NULL;
79        qperm = qperm->qnext)
80     {
81       if (qperm->pzalias == NULL
82           || qperm->pzmachine == NULL
83           || qperm->pzalias == (char **) &_uuconf_unset
84           || qperm->pzmachine == (char **) &_uuconf_unset)
85         continue;
86
87       for (pz = qperm->pzalias; *pz != NULL; pz++)
88         {
89           if (strcmp (*pz, zsystem) == 0)
90             {
91               zsystem = qperm->pzmachine[0];
92               break;
93             }
94         }
95       if (*pz != NULL)
96         break;
97     }
98
99   zline = NULL;
100   cline = 0;
101   pzsplit = NULL;
102   csplit = 0;
103   pzcomma = NULL;
104   ccomma = 0;
105
106   pblock = NULL;
107
108   iret = UUCONF_SUCCESS;
109
110   for (pz = qglobal->qprocess->pzhdb_systems; *pz != NULL; pz++)
111     {
112       FILE *e;
113       int cchars;
114
115       qglobal->ilineno = 0;
116
117       e = fopen (*pz, "r");
118       if (e == NULL)
119         {
120           if (FNO_SUCH_FILE ())
121             continue;
122           qglobal->ierrno = errno;
123           iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO;
124           break;
125         }
126
127       while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0)
128         {
129           int ctoks, ctimes, i;
130           struct uuconf_system *qset;
131           char *z, *zretry;
132           int cretry;
133
134           ++qglobal->ilineno;
135
136           --cchars;
137           if (zline[cchars] == '\n')
138             zline[cchars] = '\0';
139           if (isspace (BUCHAR (zline[0])) || zline[0] == '#')
140             continue;
141
142           ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit);
143           if (ctoks < 0)
144             {
145               qglobal->ierrno = errno;
146               iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
147               break;
148             }
149
150           /* If this isn't the system we're looking for, keep reading
151              the file.  */
152           if (ctoks < 1
153               || strcmp (zsystem, pzsplit[0]) != 0)
154             continue;
155
156           /* If this is the first time we've found the system, we want
157              to set *qsys directly.  Otherwise, we allocate a new
158              alternate.  */
159           if (pblock == NULL)
160             {
161               pblock = uuconf_malloc_block ();
162               if (pblock == NULL)
163                 {
164                   qglobal->ierrno = errno;
165                   iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
166                   break;
167                 }
168               _uuconf_uclear_system (qsys);
169               qsys->uuconf_palloc = pblock;
170               qset = qsys;
171             }
172           else
173             {
174               struct uuconf_system **pq;
175
176               qset = ((struct uuconf_system *)
177                       uuconf_malloc (pblock, sizeof (struct uuconf_system)));
178               if (qset == NULL)
179                 {
180                   qglobal->ierrno = errno;
181                   iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
182                   break;
183                 }
184               _uuconf_uclear_system (qset);
185               for (pq = &qsys->uuconf_qalternate;
186                    *pq != NULL;
187                    pq = &(*pq)->uuconf_qalternate)
188                 ;
189               *pq = qset;
190             }
191
192           /* Add this line to the memory block we are building for the
193              system.  */
194           if (uuconf_add_block (pblock, zline) != 0)
195             {
196               qglobal->ierrno = errno;
197               iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
198               break;
199             }
200
201           zline = NULL;
202           cline = 0;
203
204           /* The format of a line in Systems is
205              system time device speed phone chat
206              For example,
207              airs Any ACU 9600 5551212 ogin: foo pass: bar
208              */
209
210           /* Get the system name.  */
211
212           qset->uuconf_zname = pzsplit[0];
213           qset->uuconf_fcall = TRUE;
214           qset->uuconf_fcalled = FALSE;
215
216           if (ctoks < 2)
217             continue;
218
219           /* A time string is "time/grade,time/grade;retry".  A
220              missing grade is taken as BGRADE_LOW.  */
221           zretry = strchr (pzsplit[1], ';');
222           if (zretry == NULL)
223             cretry = 0;
224           else
225             {
226               *zretry = '\0';
227               cretry = (int) strtol (zretry + 1, (char **) NULL, 10);
228             }
229
230           ctimes = _uuconf_istrsplit (pzsplit[1], ',', &pzcomma, &ccomma);
231           if (ctimes < 0)
232             {
233               qglobal->ierrno = errno;
234               iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
235               break;
236             }
237
238           for (i = 0; i < ctimes; i++)
239             {
240               char *zslash;
241               char bgrade;
242
243               z = pzcomma[i];
244               zslash = strchr (z, '/');
245               if (zslash == NULL)
246                 bgrade = UUCONF_GRADE_LOW;
247               else
248                 {
249                   *zslash = '\0';
250                   bgrade = zslash[1];
251                   if (! UUCONF_GRADE_LEGAL (bgrade))
252                     bgrade = UUCONF_GRADE_LOW;
253                 }
254
255               iret = _uuconf_itime_parse (qglobal, z, (long) bgrade,
256                                           cretry, _uuconf_itime_grade_cmp,
257                                           &qset->uuconf_qtimegrade,
258                                           pblock);
259
260               /* We treat a syntax error in the time field as
261                  equivalent to ``never'', on the assumption that that
262                  is what HDB does.  */
263               if (iret == UUCONF_SYNTAX_ERROR)
264                 iret = UUCONF_SUCCESS;
265
266               if (iret != UUCONF_SUCCESS)
267                 break;
268
269               /* Treat any time/grade setting as both a timegrade and
270                  a call-timegrade.  */
271               if (bgrade != UUCONF_GRADE_LOW)
272                 qset->uuconf_qcalltimegrade = qset->uuconf_qtimegrade;
273             }
274
275           if (iret != UUCONF_SUCCESS)
276             break;
277
278           if (ctoks < 3)
279             continue;
280
281           /* Pick up the device name.  It can be followed by a comma
282              and a list of protocols.  */
283           qset->uuconf_zport = pzsplit[2];
284           z = strchr (pzsplit[2], ',');
285           if (z != NULL)
286             {
287               qset->uuconf_zprotocols = z + 1;
288               *z = '\0';
289             }
290
291           if (ctoks < 4)
292             continue;
293
294           /* The speed entry can be a numeric speed, or a range of
295              speeds, or "Any", or "-".  If it starts with a letter,
296              the initial nonnumeric prefix is a modem class, which
297              gets appended to the port name.  */
298           z = pzsplit[3];
299           if (strcasecmp (z, "Any") != 0
300               && strcmp (z, "-") != 0)
301             {
302               char *zend;
303
304               while (*z != '\0' && ! isdigit (BUCHAR (*z)))
305                 ++z;
306
307               qset->uuconf_ibaud = strtol (z, &zend, 10);
308               if (*zend == '-')
309                 qset->uuconf_ihighbaud = strtol (zend + 1, (char **) NULL,
310                                                  10);
311
312               if (z != pzsplit[3])
313                 {
314                   size_t cport, cclass;
315
316                   cport = strlen (pzsplit[2]);
317                   cclass = z - pzsplit[3];
318                   qset->uuconf_zport = uuconf_malloc (pblock,
319                                                       cport + cclass + 1);
320                   if (qset->uuconf_zport == NULL)
321                     {
322                       qglobal->ierrno = errno;
323                       iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
324                       break;
325                     }
326                   memcpy ((pointer) qset->uuconf_zport, (pointer) pzsplit[2],
327                           cport);
328                   memcpy ((pointer) (qset->uuconf_zport + cport),
329                           (pointer) pzsplit[3], cclass);
330                   qset->uuconf_zport[cport + cclass] = '\0';
331                 }
332             }
333
334           if (ctoks < 5)
335             continue;
336
337           /* Get the phone number.  */
338           qset->uuconf_zphone = pzsplit[4];
339
340           if (ctoks < 6)
341             continue;
342
343           /* Get the chat script.  We just hand this off to the chat
344              script processor, so that it will parse subsend and
345              subexpect strings correctly.  */
346           pzsplit[4] = (char *) "chat";
347           iret = _uuconf_ichat_cmd (qglobal, ctoks - 4, pzsplit + 4,
348                                     &qset->uuconf_schat, pblock);
349           iret &=~ UUCONF_CMDTABRET_KEEP;
350           if (iret != UUCONF_SUCCESS)
351             break;
352         }
353   
354       (void) fclose (e);
355
356       if (iret != UUCONF_SUCCESS)
357         break;
358     }
359
360   if (zline != NULL)
361     free ((pointer) zline);
362   if (pzsplit != NULL)
363     free ((pointer) pzsplit);
364   if (pzcomma != NULL)
365     free ((pointer) pzcomma);
366
367   if (iret != UUCONF_SUCCESS)
368     {
369       qglobal->zfilename = *pz;
370       return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO;
371     }
372
373   if (pblock == NULL)
374     return UUCONF_NOT_FOUND;
375
376   /* Now we have to put in the Permissions information.  The relevant
377      Permissions entries are those with this system in the MACHINE
378      list and (if this system does not have a VALIDATE entry) those
379      with a LOGNAME list but no MACHINE list.  If no entry is found
380      with this system in the MACHINE list, then we must look for an
381      entry with "OTHER" in the MACHINE list.  */
382   ffound_machine = FALSE;
383   ffound_login = FALSE;
384   qother_machine = NULL;
385   for (qperm = qglobal->qprocess->qhdb_permissions;
386        qperm != NULL;
387        qperm = qperm->qnext)
388     {
389       boolean fmachine;
390
391       /* MACHINE=OTHER is recognized specially.  It appears that OTHER
392          need only be recognized by itself, not when combined with
393          other machine names.  */
394       if (qother_machine == NULL
395           && qperm->pzmachine != NULL
396           && qperm->pzmachine != (char **) &_uuconf_unset
397           && qperm->pzmachine[0][0] == 'O'
398           && strcmp (qperm->pzmachine[0], "OTHER") == 0)
399         qother_machine = qperm;
400
401       /* If this system is named in a MACHINE entry, we must add the
402          appropriate information to every alternate that could be used
403          for calling out.  */
404       fmachine = FALSE;
405       if (! ffound_machine
406           && qperm->pzmachine != NULL
407           && qperm->pzmachine != (char **) &_uuconf_unset)
408         {
409           for (pz = qperm->pzmachine; *pz != NULL; pz++)
410             {
411               if ((*pz)[0] == zsystem[0]
412                   && strcmp (*pz, zsystem) == 0)
413                 {
414                   for (qalt = qsys;
415                        qalt != NULL;
416                        qalt = qalt->uuconf_qalternate)
417                     {
418                       if (qalt->uuconf_fcall)
419                         {
420                           iret = ihadd_machine_perm (qglobal, qalt, qperm);
421                           if (iret != UUCONF_SUCCESS)
422                             return iret;
423                         }
424                     }
425
426                   fmachine = TRUE;
427                   ffound_machine = TRUE;
428
429                   break;
430                 }
431             }
432         }
433
434       /* A LOGNAME line applies to this machine if it is listed in the
435          corresponding VALIDATE entry, or if it is not listed in any
436          VALIDATE entry.  On this pass through the Permissions entry
437          we pick up the information if the system appears in a
438          VALIDATE entry; if it does not, we make another pass to put
439          in all the LOGNAME lines.  */
440       if (qperm->pzlogname != NULL
441           && qperm->pzlogname != (char **) &_uuconf_unset
442           && qperm->pzvalidate != NULL
443           && qperm->pzvalidate != (char **) &_uuconf_unset)
444         {
445           for (pz = qperm->pzvalidate; *pz != NULL; ++pz)
446             if ((*pz)[0] == zsystem[0]
447                 && strcmp (*pz, zsystem) == 0)
448               break;
449           if (*pz != NULL)
450             {
451               for (pz = qperm->pzlogname; *pz != NULL; ++pz)
452                 {
453                   /* If this LOGNAME line is also a matching MACHINE
454                      line, we can add the LOGNAME permissions to the
455                      first alternate.  Otherwise, we must create a new
456                      alternate.  We cannot put a LOGNAME line in the
457                      first alternate if MACHINE does not match,
458                      because certain permissions (e.g. READ) may be
459                      specified by both types of lines, and we must use
460                      LOGNAME entries only when accepting calls and
461                      MACHINE entries only when placing calls.  */
462                   if (fmachine
463                       && (qsys->uuconf_zcalled_login == NULL
464                           || (qsys->uuconf_zcalled_login
465                               == (char *) &_uuconf_unset)))
466                     {
467                       qsys->uuconf_zcalled_login = *pz;
468                       iret = ihadd_logname_perm (qglobal, qsys, qperm);
469                     }
470                   else
471                     {
472                       struct uuconf_system *qnew;
473                       struct uuconf_system **pq;
474
475                       qnew = ((struct uuconf_system *)
476                               uuconf_malloc (pblock,
477                                              sizeof (struct uuconf_system)));
478                       if (qnew == NULL)
479                         {
480                           qglobal->ierrno = errno;
481                           return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
482                         }
483
484                       *qnew = *qsys;
485                       qnew->uuconf_qalternate = NULL;
486                       for (pq = &qsys->uuconf_qalternate;
487                            *pq != NULL;
488                            pq = &(*pq)->uuconf_qalternate)
489                         ;
490                       *pq = qnew;
491
492                       qnew->uuconf_zcalled_login = *pz;
493                       qnew->uuconf_fcall = FALSE;
494                       iret = ihadd_logname_perm (qglobal, qnew, qperm);
495                     }
496
497                   if (iret != UUCONF_SUCCESS)
498                     return iret;
499                 }
500
501               ffound_login = TRUE;
502             }
503         }
504     }
505
506   /* If we didn't find an entry for the machine, we must use the
507      MACHINE=OTHER entry, if any.  */
508   if (! ffound_machine && qother_machine != NULL)
509     {
510       for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate)
511         {
512           if (qalt->uuconf_fcall)
513             {
514               iret = ihadd_machine_perm (qglobal, qalt, qother_machine);
515               if (iret != UUCONF_SUCCESS)
516                 return iret;
517             }
518         }
519     }
520
521   /* If this system was not listed in any VALIDATE entry, then we must
522      add a called-login for each LOGNAME entry in Permissions.  */
523   if (! ffound_login)
524     {
525       for (qperm = qglobal->qprocess->qhdb_permissions;
526            qperm != NULL;
527            qperm = qperm->qnext)
528         {
529           if (qperm->pzlogname == NULL
530               || qperm->pzlogname == (char **) &_uuconf_unset)
531             continue;
532
533           for (pz = qperm->pzlogname; *pz != NULL; pz++)
534             {
535               struct uuconf_system *qnew;
536               struct uuconf_system **pq;
537
538               qnew = ((struct uuconf_system *)
539                       uuconf_malloc (pblock,
540                                       sizeof (struct uuconf_system)));
541               if (qnew == NULL)
542                 {
543                   qglobal->ierrno = errno;
544                   return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
545                 }
546
547               *qnew = *qsys;
548               qnew->uuconf_qalternate = NULL;
549               for (pq = &qsys->uuconf_qalternate;
550                    *pq != NULL;
551                    pq = &(*pq)->uuconf_qalternate)
552                 ;
553               *pq = qnew;
554
555               /* We recognize LOGNAME=OTHER specially, although this
556                  appears to be an SCO innovation.  */
557               if (strcmp (*pz, "OTHER") == 0)
558                 qnew->uuconf_zcalled_login = (char *) "ANY";
559               else
560                 qnew->uuconf_zcalled_login = *pz;
561               qnew->uuconf_fcall = FALSE;
562               iret = ihadd_logname_perm (qglobal, qnew, qperm);
563               if (iret != UUCONF_SUCCESS)
564                 return iret;
565             }
566         }
567     }
568
569   /* HDB permits local requests to receive to any directory, which is
570      not the default put in by _uuconf_isystem_basic_default.  We set
571      it here instead.  */
572   for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate)
573     {
574       iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR,
575                                   FALSE, FALSE,
576                                   &qalt->uuconf_pzlocal_receive,
577                                   pblock);
578       if (iret != UUCONF_SUCCESS)
579         return iret;
580     }
581
582   /* HDB does not have a maximum number of retries if a retry time is
583      given in the time field.  */
584   if (qsys->uuconf_qtimegrade != NULL
585       && qsys->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset
586       && qsys->uuconf_qtimegrade->uuconf_cretry > 0)
587     qsys->uuconf_cmax_retries = 0;
588
589   return UUCONF_SUCCESS;
590 }
591 \f
592 /* Add the settings of a MACHINE line in Permissions to a system.  */
593
594 /*ARGSIGNORED*/
595 static int
596 ihadd_machine_perm (qglobal, qsys, qperm)
597      struct sglobal *qglobal;
598      struct uuconf_system *qsys;
599      struct shpermissions *qperm;
600 {
601   if (qperm->frequest >= 0)
602     qsys->uuconf_fsend_request = qperm->frequest;
603   else
604     qsys->uuconf_fsend_request = FALSE;
605   qsys->uuconf_pzremote_send = qperm->pzread;
606   qsys->uuconf_pzremote_receive = qperm->pzwrite;
607   qsys->uuconf_pzcmds = qperm->pzcommands;
608   qsys->uuconf_zlocalname = qperm->zmyname;
609   qsys->uuconf_zpubdir = qperm->zpubdir;
610   qsys->uuconf_pzalias = qperm->pzalias;
611
612   return UUCONF_SUCCESS;
613 }
614
615 /* Add the settings of a LOGNAME line in Permissions to a system.  */
616
617 /*ARGSIGNORED*/
618 static int
619 ihadd_logname_perm (qglobal, qsys, qperm)
620      struct sglobal *qglobal;
621      struct uuconf_system *qsys;
622      struct shpermissions *qperm;
623 {
624   qsys->uuconf_fcalled = TRUE;
625   if (qperm->frequest >= 0)
626     qsys->uuconf_fsend_request = qperm->frequest;
627   else
628     qsys->uuconf_fsend_request = FALSE;
629   qsys->uuconf_fcalled_transfer = qperm->fsendfiles;
630   qsys->uuconf_pzremote_send = qperm->pzread;
631   qsys->uuconf_pzremote_receive = qperm->pzwrite;
632   qsys->uuconf_fcallback = qperm->fcallback;
633   qsys->uuconf_zlocalname = qperm->zmyname;
634   qsys->uuconf_zpubdir = qperm->zpubdir;
635
636   return UUCONF_SUCCESS;
637 }