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

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