source: trunk/athena/lib/locker/conf.c @ 13171

Revision 13171, 15.1 KB checked in by danw, 26 years ago (diff)
Rework locker__canonicalize_path and locker__build_mountpoint to deal with the possibility that a UFS/NFS mountpoint directory might already exist. Gets rid of "Directory should not exist" errors on some machines that have crufty directories lying around before taking 8.3.
Line 
1/* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16/* This file is part of liblocker. It implements reading attach.conf. */
17
18static const char rcsid[] = "$Id: conf.c,v 1.3 1999-06-04 14:06:40 danw Exp $";
19
20#include <ctype.h>
21#include <errno.h>
22#include <pwd.h>
23#include <stdarg.h>
24#include <stddef.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <com_err.h>
30#include <hesiod.h>
31#include <zephyr/zephyr.h>
32
33#include "locker.h"
34#include "locker_private.h"
35
36extern struct locker_ops locker__err_ops, locker__mul_ops, locker__afs_ops;
37extern struct locker_ops locker__nfs_ops, locker__ufs_ops;
38
39#define LOCKER_ALL_FSTYPES (-1L)
40
41static void free_regexp_list(struct locker__regexp_list lst, int strings);
42
43static int parse_bool(locker_context context, char *line, void *val);
44static int parse_string(locker_context context, char *line, void *val);
45static int parse_trusted_list(locker_context context, char *line, void *val);
46static int parse_regex_list_yes(locker_context context, char *line, void *val);
47static int parse_regex_list_no(locker_context context, char *line, void *val);
48static int parse_regex_list(locker_context context, char *line,
49                            struct locker__regexp_list *val, int flag);
50static int parse_fs_list(locker_context context, char *line, void *val);
51static int add_regexp(locker_context context, struct locker__regexp_list *val,
52                      char *regexp);
53static int parse_obsolete(locker_context context, char *line, void *val);
54
55static struct opt_def {
56  char *name;
57  int (*parse)(locker_context, char *, void *);
58  size_t offset;
59} conf_options[] = {
60  /* Boolean options */
61  { "explicit", parse_bool, offsetof(struct locker_context, exp_desc) },
62  { "explicit-mntpt", parse_bool, offsetof(struct locker_context, exp_mountpoint) },
63  { "keep-mount", parse_bool, offsetof(struct locker_context, keep_mount) },
64  { "nfs-root-hack", parse_bool, offsetof(struct locker_context, nfs_root_hack) },
65  { "ownercheck", parse_bool, offsetof(struct locker_context, ownercheck) },
66
67  /* String options */
68  { "afs-mount-dir", parse_string, offsetof(struct locker_context, afs_mount_dir) },
69  { "attachtab", parse_string, offsetof(struct locker_context, attachtab) },
70  { "nfs-mount-dir", parse_string, offsetof(struct locker_context, nfs_mount_dir) },
71
72  /* Trusted user list */
73  { "trusted", parse_trusted_list, offsetof(struct locker_context, trusted) },
74
75  /* Regexp list options */
76  { "allow", parse_regex_list_yes, offsetof(struct locker_context, allow) },
77  { "noallow", parse_regex_list_no, offsetof(struct locker_context, allow) },
78  { "mountpoint", parse_regex_list_yes, offsetof(struct locker_context, mountpoint) },
79  { "nomountpoint", parse_regex_list_no, offsetof(struct locker_context, mountpoint) },
80  { "setuid", parse_regex_list_yes, offsetof(struct locker_context, setuid) },
81  { "suid", parse_regex_list_yes, offsetof(struct locker_context, setuid) },
82  { "nosetuid", parse_regex_list_no, offsetof(struct locker_context, setuid) },
83  { "nosuid", parse_regex_list_no, offsetof(struct locker_context, setuid) },
84
85  /* Filesystem regexp and argument options */
86  { "allowoptions", parse_fs_list, offsetof(struct locker_context, allowopts) },
87  { "defoptions", parse_fs_list, offsetof(struct locker_context, defopts) },
88  { "filesystem", parse_fs_list, offsetof(struct locker_context, filesystem) },
89  { "options", parse_fs_list, offsetof(struct locker_context, reqopts) },
90
91  /* Obsolete options */
92  { "aklog", parse_obsolete, 0 },
93  { "debug", parse_obsolete, 0 },
94  { "fsck", parse_obsolete, 0 },
95  { "mtab", parse_obsolete, 0 },
96  { "ownerlist", parse_obsolete, 0 },
97  { "verbose", parse_obsolete, 0 },
98};
99
100static int noptions = sizeof(conf_options) / sizeof(struct opt_def);
101
102int locker_init(locker_context *contextp, uid_t user,
103                locker_error_fun errfun, void *errdata)
104{
105  locker_context context;
106  FILE *fp;
107  char *buf = NULL, *p, *q;
108  int i, size, status;
109
110  context = *contextp = malloc(sizeof(struct locker_context));
111  if (!context)
112    {
113      locker__error(context, "Out of memory reading attach.conf.\n");
114      return LOCKER_ENOMEM;
115    }
116
117  /* Set defaults. */
118  memset(context, 0, sizeof(struct locker_context));
119  if (errfun)
120    {
121      context->errfun = errfun;
122      context->errdata = errdata;
123    }
124  else
125    context->errfun = NULL;
126  context->nfs_root_hack = context->exp_desc = context->exp_mountpoint = 1;
127  context->afs_mount_dir = strdup(LOCKER_AFS_MOUNT_DIR);
128  context->attachtab = strdup(LOCKER_PATH_ATTACHTAB);
129  if (!context->afs_mount_dir || !context->attachtab)
130    {
131      locker__error(context, "Out of memory reading attach.conf.\n");
132      locker_end(context);
133      return LOCKER_ENOMEM;
134    }
135  context->nfs_mount_dir = NULL;
136  context->user = user;
137  if (context->user == 0)
138    context->trusted = 1;
139  context->zsubs = NULL;
140
141  context->setuid.tab = NULL;
142  context->setuid.defflag = 1;
143  context->allow.tab = NULL;
144  context->allow.defflag = 1;
145  context->mountpoint.tab = NULL;
146  context->mountpoint.defflag = 1;
147  context->filesystem.tab = NULL;
148  context->reqopts.tab = NULL;
149  context->defopts.tab = NULL;
150  context->allowopts.tab = NULL;
151
152  /* Filesystem defaults. */
153  context->nfstypes = 5;
154  context->fstype = malloc(context->nfstypes * sizeof(struct locker_ops *));
155  if (!context->fstype)
156    {
157      locker__error(context, "Out of memory reading attach.conf.\n");
158      locker_end(context);
159      return LOCKER_ENOMEM;
160    }
161  context->fstype[0] = &locker__err_ops;
162  context->fstype[1] = &locker__mul_ops;
163  context->fstype[2] = &locker__afs_ops;
164  context->fstype[3] = &locker__nfs_ops;
165  context->fstype[4] = &locker__ufs_ops;
166  for (i = 0; i < context->nfstypes; i++)
167    context->fstype[i]->id = 1 << i;
168
169  fp = fopen(LOCKER_PATH_ATTACH_CONF, "r");
170  if (!fp)
171    {
172      locker__error(context, "%s while trying to open attach.conf.\n",
173                    strerror(errno));
174      locker_end(context);
175      return LOCKER_EATTACHCONF;
176    }
177
178  while ((status = locker__read_line(fp, &buf, &size)) == 0)
179    {
180      if (!buf[0] || buf[0] == '#')
181        continue;
182
183      p = buf;
184      while (isspace(*p))
185        p++;
186      q = p;
187      while (*q && !isspace(*q))
188        q++;
189
190      for (i = 0; i < noptions; i++)
191        {
192          if (!strncmp(conf_options[i].name, p, q - p) &&
193              !conf_options[i].name[q - p])
194            break;
195        }
196      if (i == noptions)
197        {
198          locker__error(context, "Unrecognized attach.conf line:\n%s\n", buf);
199          locker_end(context);
200          free(buf);
201          fclose(fp);
202          return LOCKER_EATTACHCONF;
203        }
204      else
205        {
206          while (*q && isspace(*q))
207            q++;
208          status = conf_options[i].parse(context, q,
209                                         ((char *)context +
210                                          conf_options[i].offset));
211        }
212
213      if (status)
214        break;
215    }
216
217  free(buf);
218  fclose(fp);
219
220  if (status && status != LOCKER_EOF)
221    {
222      if (status == LOCKER_ENOMEM)
223        locker__error(context, "Out of memory reading attach.conf.\n");
224      else if (status == LOCKER_EFILE)
225        {
226          locker__error(context, "Error reading attach.conf:\n%s\n",
227                        strerror(errno));
228          status = LOCKER_EATTACHCONF;
229        }
230      else
231        locker__error(context, "Bad attach.conf line: \"%s\"\n", buf);
232
233      locker_end(context);
234      return status;
235    }
236
237  status = locker__canonicalize_path(context, LOCKER_CANON_CHECK_NONE,
238                                     &context->attachtab, NULL);
239  if (status)
240    {
241      locker_end(context);
242      return status;
243    }
244
245  /* Initialize Hesiod. */
246  if (hesiod_init(&context->hes_context) != 0)
247    {
248      locker__error(context, "Could not create locker context:\n"
249                    "%s while initializing Hesiod.\n", strerror(errno));
250      locker_end(context);
251      return LOCKER_EHESIOD;
252    }
253
254  return LOCKER_SUCCESS;
255}
256
257void locker_end(locker_context context)
258{
259  free(context->afs_mount_dir);
260  free(context->attachtab);
261  free(context->nfs_mount_dir);
262  free(context->fstype);
263  free_regexp_list(context->setuid, 0);
264  free_regexp_list(context->allow, 0);
265  free_regexp_list(context->mountpoint, 0);
266  free_regexp_list(context->filesystem, 1);
267  free_regexp_list(context->reqopts, 1);
268  free_regexp_list(context->defopts, 1);
269  free_regexp_list(context->allowopts, 1);
270
271  if (context->hes_context)
272    hesiod_end(context->hes_context);
273  locker__free_zsubs(context);
274
275  free(context);
276}
277
278static void free_regexp_list(struct locker__regexp_list lst, int strings)
279{
280  int i;
281
282  for (i = 0; i < lst.num; i++)
283    {
284      regfree(&(lst.tab[i].pattern));
285      if (strings)
286        free(lst.tab[i].data.string);
287    }
288  free(lst.tab);
289}
290
291static int parse_bool(locker_context context, char *line, void *val)
292{
293  int *boolval = val;
294
295  /* Nothing = yes */
296  if (!*line)
297    {
298      *boolval = 1;
299      return LOCKER_SUCCESS;
300    }
301
302  if (!strcmp(line, "on"))
303    *boolval = 1;
304  else if (!strcmp(line, "off"))
305    *boolval = 0;
306  else
307    {
308      locker__error(context, "Unrecognized boolean value \"%s\".\n", line);
309      return LOCKER_EATTACHCONF;
310    }
311  return LOCKER_SUCCESS;
312}
313
314static int parse_string(locker_context context, char *line, void *val)
315{
316  char **strval = val;
317
318  free(*strval);
319  *strval = strdup(line);
320
321  if (!*strval)
322    return LOCKER_ENOMEM;
323  return LOCKER_SUCCESS;
324}
325
326static int parse_trusted_list(locker_context context, char *line, void *val)
327{
328  int *trusted = val;
329  char *lasts = NULL;
330
331  for (line = strtok_r(line, " \t", &lasts); line;
332       line = strtok_r(NULL, " \t", &lasts))
333    {
334      if (isdigit(*line) && context->user == atoi(line))
335        *trusted = 1;
336      else
337        {
338          struct passwd *pw;
339
340          pw = getpwnam(line);
341          if (!pw)
342            continue;
343          if (pw->pw_uid == context->user)
344            *trusted = 1;
345        }
346    }
347  return LOCKER_SUCCESS;
348}
349
350static int parse_regex_list_yes(locker_context context, char *line, void *val)
351{
352  return parse_regex_list(context, line, val, 1);
353}
354
355static int parse_regex_list_no(locker_context context, char *line, void *val)
356{
357  return parse_regex_list(context, line, val, 0);
358}
359
360static int parse_regex_list(locker_context context, char *line,
361                            struct locker__regexp_list *val, int flag)
362{
363  int status = LOCKER_SUCCESS;
364  char *data, *dup = strdup(line), *lasts = NULL;
365
366  if (!dup)
367    return LOCKER_ENOMEM;
368  for (data = strtok_r(dup, " \t", &lasts); data && !status;
369       data = strtok_r(NULL, " \t", &lasts))
370    {
371      status = add_regexp(context, val, data);
372      if (status == LOCKER_SUCCESS)
373        val->tab[val->num++].data.flag = flag;
374    }
375  free(dup);
376  return status;
377}
378
379static int parse_fs_list(locker_context context, char *line, void *val)
380{
381  int status;
382  char *data = strdup(line), *lasts = NULL;
383  struct locker__regexp_list *lst = val;
384
385  if (!data)
386    return LOCKER_ENOMEM;
387
388  line = strtok_r(data, " \t", &lasts);
389  if (!line)
390    return LOCKER_EATTACHCONF;
391  line = strtok_r(NULL, " \t", &lasts);
392  if (!line)
393    return LOCKER_EATTACHCONF;
394
395  status = add_regexp(context, lst, data);
396  if (status == LOCKER_SUCCESS)
397    {
398      lst->tab[lst->num].data.string = strdup(line);
399      if (!lst->tab[lst->num++].data.string)
400        status = LOCKER_ENOMEM;
401    }
402  free(data);
403  return status;
404}
405
406static int add_regexp(locker_context context, struct locker__regexp_list *lst,
407                      char *regexp)
408{
409  int i, len, status;
410
411  /* Extend the array if we ran out of slots. */
412  if (lst->num >= lst->size - 1)
413    {
414      struct locker__regexp *new;
415      int nsize;
416
417      if (lst->size)
418        nsize = 2 * lst->size;
419      else
420        nsize = 5;
421      new = realloc(lst->tab, nsize * sizeof(struct locker__regexp));
422      if (!new)
423        return LOCKER_ENOMEM;
424      /* Zero out the newly-allocated parts, but not the old parts. */
425      memset(new + lst->size, 0,
426             (nsize - lst->size) * sizeof(struct locker__regexp));
427      lst->size = nsize;
428      lst->tab = new;
429    }
430
431  /* Check for {[-+]?^?fstype,fstype,...}: prefix. */
432  if (*regexp == '{')
433    {
434      int invert = 0;
435
436      if (*++regexp == '+')
437        {
438          regexp++;
439          lst->tab[lst->num].explicit = LOCKER_EXPLICIT;
440        }
441      else if (*regexp == '-')
442        {
443          regexp++;
444          lst->tab[lst->num].explicit = LOCKER_NOEXPLICIT;
445        }
446      else if (*regexp == '^')
447        {
448          regexp++;
449          invert = 1;
450        }
451
452      while (*regexp != '}')
453        {
454          for (i = 0; i < context->nfstypes; i++)
455            {
456              len = strlen(context->fstype[i]->name);
457              if (!strncasecmp(regexp, context->fstype[i]->name, len) &&
458                  (regexp[len] == ',' || regexp[len] == '}'))
459                break;
460            }
461          if (i == context->nfstypes)
462            {
463              len = strcspn(regexp, " ,}");
464              locker__error(context, "Unrecognized filesystem type "
465                            "\"%.*s\".\n", len, regexp);
466              return LOCKER_EATTACHCONF;
467            }
468
469          lst->tab[lst->num].fstypes |= context->fstype[i]->id;
470          regexp += len;
471        }
472      if (invert)
473        lst->tab[lst->num].fstypes ^= LOCKER_ALL_FSTYPES;
474
475      /* Skip "}" or "}:". */
476      regexp++;
477      if (*regexp == ':')
478        regexp++;
479    }
480  else
481    lst->tab[lst->num].fstypes = LOCKER_ALL_FSTYPES;
482
483  /* Now compile the normal regexp part. */
484  status = regcomp(&(lst->tab[lst->num].pattern), regexp, REG_NOSUB);
485  if (status)
486    {
487      char *errbuf;
488      int size = regerror(status, &(lst->tab[lst->num].pattern), NULL, 0);
489      errbuf = malloc(size);
490      if (!errbuf)
491        return LOCKER_ENOMEM;
492      else
493        {
494          regerror(status, &(lst->tab[lst->num].pattern), errbuf, size);
495          locker__error(context, "Could not parse regular expression "
496                        "\"%s\":%s.\n", regexp, errbuf);
497          return LOCKER_EATTACHCONF;
498        }
499    }
500
501  return LOCKER_SUCCESS;
502}
503
504static int parse_obsolete(locker_context context, char *line, void *val)
505{
506  locker__error(context, "Ignoring obsolete attach.conf option: %s\n",
507                line);
508  return LOCKER_SUCCESS;
509}
510
511void locker__error(locker_context context, char *fmt, ...)
512{
513  va_list ap;
514
515  va_start(ap, fmt);
516  if (context && context->errfun)
517    context->errfun(context->errdata, fmt, ap);
518  else
519    vfprintf(stderr, fmt, ap);
520  va_end(ap);
521}
522
523int locker__fs_ok(locker_context context, struct locker__regexp_list list,
524                  struct locker_ops *fs, char *filesystem)
525{
526  int i;
527
528  for (i = 0; i < list.num; i++)
529    {
530      if (fs && !(list.tab[i].fstypes & fs->id))
531        continue;
532
533      if (regexec(&(list.tab[i].pattern), filesystem, 0, NULL, 0) == 0)
534        return list.tab[i].data.flag;
535    }
536
537  return list.defflag;
538}
539
540char *locker__fs_data(locker_context context, struct locker__regexp_list list,
541                      struct locker_ops *fs, char *filesystem)
542{
543  int i;
544
545  for (i = 0; i < list.num; i++)
546    {
547      if (fs && !(list.tab[i].fstypes & fs->id))
548        continue;
549
550      if (regexec(&(list.tab[i].pattern), filesystem, 0, NULL, 0) == 0)
551        return list.tab[i].data.string;
552    }
553
554  return NULL;
555}
556
557struct locker_ops *locker__get_fstype(locker_context context, char *type)
558{
559  int i, len;
560
561  for (i = 0; i < context->nfstypes; i++)
562    {
563      len = strlen(context->fstype[i]->name);
564      if (!strncasecmp(type, context->fstype[i]->name, len) &&
565          (!type[len] || isspace(type[len])))
566        return context->fstype[i];
567    }
568  return NULL;
569}
Note: See TracBrowser for help on using the repository browser.