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
28 const char _uuconf_rdperm_rcsid[] = "$FreeBSD$";
29 #endif
30 
31 #include <errno.h>
32 #include <ctype.h>
33 
34 static int ihcolon P((pointer pglobal, int argc, char **argv, pointer pvar,
35 		      pointer pinfo));
36 static int ihsendfiles P((pointer pglobal, int argc, char **argv,
37 			  pointer pvar, pointer pinfo));
38 static int ihunknownperm P((pointer pglobal, int argc, char **argv,
39 			    pointer pvar, pointer pinfo));
40 static 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 
62 static 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 
98 int
_uuconf_ihread_permissions(qglobal)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*/
307 static int
ihcolon(pglobal,argc,argv,pvar,pinfo)308 ihcolon (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*/
366 static int
ihsendfiles(pglobal,argc,argv,pvar,pinfo)367 ihsendfiles (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*/
399 static int
ihunknownperm(pglobal,argc,argv,pvar,pinfo)400 ihunknownperm (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 
412 static int
ihadd_norw(qglobal,ppz,pzno)413 ihadd_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