1/* rdperm.c
2   Read the HDB Permissions file.
3
4   Copyright (C) 1992, 1993, 2002 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.
23   */
24
25#include "uucnfi.h"
26
27#if USE_RCS_ID
28const char _uuconf_rdperm_rcsid[] = "$Id: rdperm.c,v 1.12 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31#include <errno.h>
32#include <ctype.h>
33
34static int ihcolon P((pointer pglobal, int argc, char **argv, pointer pvar,
35		      pointer pinfo));
36static int ihsendfiles P((pointer pglobal, int argc, char **argv,
37			  pointer pvar, pointer pinfo));
38static int ihunknownperm P((pointer pglobal, int argc, char **argv,
39			    pointer pvar, pointer pinfo));
40static int ihadd_norw P((struct sglobal *qglobal, char ***ppz, char **pzno));
41
42/* These routines reads in the HDB Permissions file.  We store the
43   entries in a linked list of shpermissions structures, so we only
44   have to actually read the file once.  */
45
46/* This command table and static structure are used to parse a line
47   from Permissions.  The entries are parsed as follows:
48
49   Multiple strings separated by colons: LOGNAME, MACHINE, READ,
50   WRITE, NOREAD, NOWRITE, COMMANDS, VALIDATE, ALIAS.
51
52   Boolean values: REQUEST, CALLBACK.
53
54   Simple strings: MYNAME, PUBDIR.
55
56   "Yes" or "call": SENDFILES.
57
58   The NOREAD and NOWRITE entries are merged into the READ and WRITE
59   entries, rather than being permanently stored.  They are handled
60   specially in the uuconf_cmdtab table.  */
61
62static const struct cmdtab_offset asHperm_cmds[] =
63{
64  { "NOREAD", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, ihcolon },
65  { "NOWRITE", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, ihcolon },
66  { "LOGNAME", UUCONF_CMDTABTYPE_FN | 2,
67      offsetof (struct shpermissions, pzlogname), ihcolon },
68  { "MACHINE", UUCONF_CMDTABTYPE_FN | 2,
69      offsetof (struct shpermissions, pzmachine), ihcolon },
70  { "REQUEST", UUCONF_CMDTABTYPE_BOOLEAN,
71      offsetof (struct shpermissions, frequest), NULL },
72  { "SENDFILES", UUCONF_CMDTABTYPE_FN | 2,
73      offsetof (struct shpermissions, fsendfiles), ihsendfiles },
74  { "READ", UUCONF_CMDTABTYPE_FN | 2,
75      offsetof (struct shpermissions, pzread), ihcolon },
76  { "WRITE", UUCONF_CMDTABTYPE_FN | 2,
77      offsetof (struct shpermissions, pzwrite), ihcolon },
78  { "CALLBACK", UUCONF_CMDTABTYPE_BOOLEAN,
79      offsetof (struct shpermissions, fcallback), NULL },
80  { "COMMANDS", UUCONF_CMDTABTYPE_FN | 2,
81      offsetof (struct shpermissions, pzcommands), ihcolon },
82  { "VALIDATE", UUCONF_CMDTABTYPE_FN | 2,
83      offsetof (struct shpermissions, pzvalidate), ihcolon },
84  { "MYNAME", UUCONF_CMDTABTYPE_STRING,
85      offsetof (struct shpermissions, zmyname), NULL },
86  { "PUBDIR", UUCONF_CMDTABTYPE_STRING,
87      offsetof (struct shpermissions, zpubdir), NULL },
88  { "ALIAS", UUCONF_CMDTABTYPE_FN | 2,
89      offsetof (struct shpermissions, pzalias), ihcolon },
90  { NULL, 0, 0, NULL }
91};
92
93#define CHPERM_CMDS (sizeof asHperm_cmds / sizeof asHperm_cmds[0])
94
95/* Actually read the Permissions file into a linked list of
96   structures.  */
97
98int
99_uuconf_ihread_permissions (qglobal)
100     struct sglobal *qglobal;
101{
102  char *zperm;
103  FILE *e;
104  int iret;
105  struct uuconf_cmdtab as[CHPERM_CMDS];
106  char **pznoread, **pznowrite;
107  struct shpermissions shperm;
108  char *zline;
109  size_t cline;
110  char **pzsplit;
111  size_t csplit;
112  int cchars;
113  struct shpermissions *qlist, **pq;
114
115  if (qglobal->qprocess->fhdb_read_permissions)
116    return UUCONF_SUCCESS;
117
118  zperm = (char *) uuconf_malloc (qglobal->pblock,
119				  (sizeof OLDCONFIGLIB
120				   + sizeof HDB_PERMISSIONS - 1));
121  if (zperm == NULL)
122    {
123      qglobal->ierrno = errno;
124      return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
125    }
126
127  memcpy ((pointer) zperm, (pointer) OLDCONFIGLIB,
128	  sizeof OLDCONFIGLIB - 1);
129  memcpy ((pointer) (zperm + sizeof OLDCONFIGLIB - 1),
130	  (pointer) HDB_PERMISSIONS, sizeof HDB_PERMISSIONS);
131
132  e = fopen (zperm, "r");
133  if (e == NULL)
134    {
135      uuconf_free (qglobal->pblock, zperm);
136      qglobal->qprocess->fhdb_read_permissions = TRUE;
137      return UUCONF_SUCCESS;
138    }
139
140  _uuconf_ucmdtab_base (asHperm_cmds, CHPERM_CMDS, (char *) &shperm, as);
141  as[0].uuconf_pvar = (pointer) &pznoread;
142  as[1].uuconf_pvar = (pointer) &pznowrite;
143
144  zline = NULL;
145  cline = 0;
146  pzsplit = NULL;
147  csplit = 0;
148
149  qlist = NULL;
150  pq = &qlist;
151
152  qglobal->ilineno = 0;
153
154  iret = UUCONF_SUCCESS;
155
156  while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0)
157    {
158      int centries;
159      struct shpermissions *qnew;
160      int i;
161
162      ++qglobal->ilineno;
163
164      --cchars;
165      if (zline[cchars] == '\n')
166	zline[cchars] = '\0';
167      if (zline[0] == '#')
168	continue;
169
170      centries = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit);
171      if (centries < 0)
172	{
173	  qglobal->ierrno = errno;
174	  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
175	  break;
176	}
177
178      if (centries == 0)
179	continue;
180
181      shperm.pzlogname = (char **) &_uuconf_unset;
182      shperm.pzmachine = (char **) &_uuconf_unset;
183      shperm.frequest = -1;
184      shperm.fsendfiles = -1;
185      shperm.pzread = (char **) &_uuconf_unset;
186      shperm.pzwrite = (char **) &_uuconf_unset;
187      shperm.fcallback = -1;
188      shperm.pzcommands = (char **) &_uuconf_unset;
189      shperm.pzvalidate = (char **) &_uuconf_unset;
190      shperm.zmyname = (char *) &_uuconf_unset;
191      shperm.zpubdir = (char *) &_uuconf_unset;
192      shperm.pzalias = (char **) &_uuconf_unset;
193      pznoread = (char **) &_uuconf_unset;
194      pznowrite = (char **) &_uuconf_unset;
195
196      for (i = 0; i < centries; i++)
197	{
198	  char *zeq;
199	  char *azargs[2];
200
201	  zeq = strchr (pzsplit[i], '=');
202	  if (zeq == NULL)
203	    {
204	      iret = UUCONF_SYNTAX_ERROR;
205	      qglobal->qprocess->fhdb_read_permissions = TRUE;
206	      break;
207	    }
208	  *zeq = '\0';
209
210	  azargs[0] = pzsplit[i];
211	  azargs[1] = zeq + 1;
212
213	  iret = uuconf_cmd_args (qglobal, 2, azargs, as, (pointer) NULL,
214				  ihunknownperm, 0, qglobal->pblock);
215	  if ((iret & UUCONF_CMDTABRET_KEEP) != 0)
216	    {
217	      iret &=~ UUCONF_CMDTABRET_KEEP;
218
219	      if (uuconf_add_block (qglobal->pblock, zline) != 0)
220		{
221		  qglobal->ierrno = errno;
222		  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
223		  break;
224		}
225
226	      zline = NULL;
227	      cline = 0;
228	    }
229	  if ((iret & UUCONF_CMDTABRET_EXIT) != 0)
230	    {
231	      iret &=~ UUCONF_CMDTABRET_EXIT;
232	      break;
233	    }
234	}
235
236      if (iret != UUCONF_SUCCESS)
237	break;
238
239      if (shperm.pzmachine == (char **) &_uuconf_unset
240	  && shperm.pzlogname == (char **) &_uuconf_unset)
241	{
242	  iret = UUCONF_SYNTAX_ERROR;
243	  qglobal->qprocess->fhdb_read_permissions = TRUE;
244	  break;
245	}
246
247      /* Attach any NOREAD or NOWRITE entries to the corresponding
248	 READ or WRITE entries in the format expected for the
249	 pzlocal_receive, etc., fields in uuconf_system.  */
250      if (pznoread != NULL)
251	{
252	  iret = ihadd_norw (qglobal, &shperm.pzread, pznoread);
253	  if (iret != UUCONF_SUCCESS)
254	    break;
255	  uuconf_free (qglobal->pblock, pznoread);
256	}
257
258      if (pznowrite != NULL)
259	{
260	  iret = ihadd_norw (qglobal, &shperm.pzwrite, pznowrite);
261	  if (iret != UUCONF_SUCCESS)
262	    break;
263	  uuconf_free (qglobal->pblock, pznowrite);
264	}
265
266      qnew = ((struct shpermissions *)
267	      uuconf_malloc (qglobal->pblock,
268			     sizeof (struct shpermissions)));
269      if (qnew == NULL)
270	{
271	  qglobal->ierrno = errno;
272	  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
273	  break;
274	}
275
276      *qnew = shperm;
277      *pq = qnew;
278      pq = &qnew->qnext;
279      *pq = NULL;
280    }
281
282  (void) fclose (e);
283
284  if (zline != NULL)
285    free ((pointer) zline);
286  if (pzsplit != NULL)
287    free ((pointer) pzsplit);
288
289  if (iret == UUCONF_SUCCESS)
290    {
291      qglobal->qprocess->qhdb_permissions = qlist;
292      qglobal->qprocess->fhdb_read_permissions = TRUE;
293    }
294  else
295    {
296      qglobal->zfilename = zperm;
297      iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO;
298    }
299
300  return iret;
301}
302
303/* Split the argument into colon separated strings, and assign a NULL
304   terminated array of strings to pvar.  */
305
306/*ARGSUSED*/
307static int
308ihcolon (pglobal, argc, argv, pvar, pinfo)
309     pointer pglobal;
310     int argc ATTRIBUTE_UNUSED;
311     char **argv;
312     pointer pvar;
313     pointer pinfo ATTRIBUTE_UNUSED;
314{
315  struct sglobal *qglobal = (struct sglobal *) pglobal;
316  char ***ppz = (char ***) pvar;
317  char **pzsplit;
318  size_t csplit;
319  int centries;
320  int i;
321  int iret;
322
323  *ppz = NULL;
324
325  pzsplit = NULL;
326  csplit = 0;
327
328  centries = _uuconf_istrsplit (argv[1], ':', &pzsplit, &csplit);
329  if (centries < 0)
330    {
331      qglobal->ierrno = errno;
332      return (UUCONF_MALLOC_FAILED
333	      | UUCONF_ERROR_ERRNO
334	      | UUCONF_CMDTABRET_EXIT);
335    }
336
337  if (centries == 0)
338    {
339      if (pzsplit != NULL)
340	free ((pointer) pzsplit);
341      return UUCONF_CMDTABRET_CONTINUE;
342    }
343
344  iret = UUCONF_SUCCESS;
345
346  for (i = 0; i < centries; i++)
347    {
348      iret = _uuconf_iadd_string (qglobal, pzsplit[i], FALSE, FALSE,
349				  ppz, qglobal->pblock);
350      if (iret != UUCONF_SUCCESS)
351	{
352	  iret |= UUCONF_CMDTABRET_EXIT;
353	  break;
354	}
355    }
356
357  free ((pointer) pzsplit);
358
359  return UUCONF_CMDTABRET_KEEP;
360}
361
362/* Handle the SENDFILES parameter, which can take "yes" or "call" or
363   "no" as an argument.  The string "call" is equivalent to "no".  */
364
365/*ARGSUSED*/
366static int
367ihsendfiles (pglobal, argc, argv, pvar, pinfo)
368     pointer pglobal ATTRIBUTE_UNUSED;
369     int argc ATTRIBUTE_UNUSED;
370     char **argv;
371     pointer pvar;
372     pointer pinfo ATTRIBUTE_UNUSED;
373{
374  int *pi = (int *) pvar;
375
376  switch (argv[1][0])
377    {
378    case 'C':
379    case 'c':
380    case 'N':
381    case 'n':
382      *pi = FALSE;
383      break;
384    case 'Y':
385    case 'y':
386      *pi = TRUE;
387      break;
388    default:
389      return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
390    }
391
392  return UUCONF_CMDTABRET_CONTINUE;
393}
394
395/* If there is an unknown Permissions entry, return a syntax error.
396   This should probably be more clever.  */
397
398/*ARGSUSED*/
399static int
400ihunknownperm (pglobal, argc, argv, pvar, pinfo)
401     pointer pglobal ATTRIBUTE_UNUSED;
402     int argc ATTRIBUTE_UNUSED;
403     char **argv ATTRIBUTE_UNUSED;
404     pointer pvar ATTRIBUTE_UNUSED;
405     pointer pinfo ATTRIBUTE_UNUSED;
406{
407  return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT;
408}
409
410/* Add a NOREAD or NOWRITE entry to a READ or WRITE entry.  */
411
412static int
413ihadd_norw (qglobal, ppz, pzno)
414     struct sglobal *qglobal;
415     char ***ppz;
416     char **pzno;
417{
418  register char **pz;
419
420  if (pzno == (char **) &_uuconf_unset)
421    return UUCONF_SUCCESS;
422
423  for (pz = pzno; *pz != NULL; pz++)
424    {
425      size_t csize;
426      char *znew;
427      int iret;
428
429      /* Ignore an attempt to say NOREAD or NOWRITE with an empty
430	 string, since it will be interpreted as an attempt to deny
431	 everything.  */
432      if (**pz != '\0')
433	{
434	  csize = strlen (*pz) + 1;
435	  znew = (char *) uuconf_malloc (qglobal->pblock, csize + 1);
436	  if (znew == NULL)
437	    {
438	      qglobal->ierrno = errno;
439	      return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
440	    }
441	  znew[0] = '!';
442	  memcpy ((pointer) (znew + 1), (pointer) *pz, csize);
443	  iret = _uuconf_iadd_string (qglobal, znew, FALSE, FALSE, ppz,
444				      qglobal->pblock);
445	  if (iret != UUCONF_SUCCESS)
446	    return iret;
447	}
448    }
449
450  return UUCONF_SUCCESS;
451}
452