source: web/old/remctl-2.14/server/config.c @ f6f3e91

web
Last change on this file since f6f3e91 was f6f3e91, checked in by Jessica B. Hamrick <jhamrick@…>, 15 years ago

Preserve directory hierarchy (not sure what happened to it)

  • Property mode set to 100644
File size: 25.9 KB
Line 
1/*
2 * Configuration parsing.
3 *
4 * These are the functions for parsing the remctld configuration file and
5 * checking access.
6 *
7 * Written by Russ Allbery <rra@stanford.edu>
8 * Based on work by Anton Ushakov
9 * Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
10 *     Board of Trustees, Leland Stanford Jr. University
11 * Copyright 2008 Carnegie Mellon University
12 *
13 * See LICENSE for licensing terms.
14 */
15
16#include <config.h>
17#include <portable/system.h>
18
19#include <ctype.h>
20#include <dirent.h>
21#include <errno.h>
22#include <sys/stat.h>
23
24#include <server/internal.h>
25#include <util/util.h>
26
27/*
28 * acl_gput_file is currently used only by the test suite to point GPUT at a
29 * separate file for testing.  If it becomes available as a configurable
30 * parameter, we'll want to do something other than a local static variable
31 * for it.
32 */
33#ifdef HAVE_GPUT
34# include <gput.h>
35static char *acl_gput_file = NULL;
36#endif
37
38/* Return codes for configuration and ACL parsing. */
39enum config_status {
40    CONFIG_SUCCESS = 0,
41    CONFIG_NOMATCH = -1,
42    CONFIG_ERROR   = -2,
43    CONFIG_DENY    = -3
44};
45
46/* Holds information about parsing configuration options. */
47struct config_option {
48    const char *name;
49    enum config_status (*parse)(struct confline *, char *option,
50                                const char *file, size_t lineno);
51};
52
53/* Holds information about ACL schemes */
54struct acl_scheme {
55    const char *name;
56    enum config_status (*check)(const char *user, const char *data,
57                                const char *file, int lineno);
58};
59
60/*
61 * The following must match the indexes of these schemes in schemes[].
62 * They're used to implement default ACL schemes in particular contexts.
63 */
64#define ACL_SCHEME_FILE  0
65#define ACL_SCHEME_PRINC 1
66
67/* Forward declarations. */
68static enum config_status acl_check(const char *user, const char *entry,
69                                    int def_index, const char *file,
70                                    int lineno);
71
72/*
73 * Check a filename for acceptable characters.  Returns true if the file
74 * consists solely of [a-zA-Z0-9_-] and false otherwise.
75 */
76static bool
77valid_filename(const char *filename)
78{
79    const char *p;
80
81    for (p = filename; *p != '\0'; p++) {
82        if (*p >= 'A' && *p <= 'Z')
83            continue;
84        if (*p >= 'a' && *p <= 'z')
85            continue;
86        if (*p >= '0' && *p <= '9')
87            continue;
88        if (*p == '_' || *p == '-')
89            continue;
90        return false;
91    }
92    return true;
93}
94
95
96/*
97 * Process a request for including a file, either for configuration or for
98 * ACLs.  Called by read_conf_file and acl_check_file.
99 *
100 * Takes the vector that represents the include directive, the current file,
101 * the line number, the function to call for each included file, and a piece
102 * of data to pass to that function.  Handles including either files or
103 * directories.  When used for processing ACL files named in the configuration
104 * file, the current file and line number will be passed as zero.
105 *
106 * If the function returns a value less than -1, return its return code.  If
107 * the file is recursively included or if there is an error in reading a file
108 * or processing an include directory, return CONFIG_ERROR.  Otherwise, return
109 * the greatest of all status codes returned by function, or CONFIG_NOMATCH if
110 * the file was empty.
111 */
112static enum config_status
113handle_include(const char *included, const char *file, int lineno,
114               enum config_status (*function)(void *, const char *),
115               void *data)
116{
117    struct stat st;
118
119    /* Sanity checking. */
120    if (strcmp(included, file) == 0) {
121        warn("%s:%d: %s recursively included", file, lineno, file);
122        return CONFIG_ERROR;
123    }
124    if (stat(included, &st) < 0) {
125        warn("%s:%d: included file %s not found", file, lineno, included);
126        return CONFIG_ERROR;
127    }
128
129    /*
130     * If it's a directory, include everything in the directory whose
131     * filenames contain only the allowed characters.  Otherwise, just include
132     * the one file.
133     */
134    if (!S_ISDIR(st.st_mode)) {
135        return (*function)(data, included);
136    } else {
137        DIR *dir;
138        struct dirent *entry;
139        int status = CONFIG_NOMATCH;
140        int last;
141
142        dir = opendir(included);
143        while ((entry = readdir(dir)) != NULL) {
144            char *path;
145            size_t length;
146
147            if (!valid_filename(entry->d_name))
148                continue;
149            length = strlen(included) + 1 + strlen(entry->d_name) + 1;
150            path = xmalloc(length);
151            snprintf(path, length, "%s/%s", included, entry->d_name);
152            last = (*function)(data, path);
153            free(path);
154            if (last < -1) {
155                closedir(dir);
156                return last;
157            }
158            if (last > status)
159                status = last;
160        }
161        closedir(dir);
162        return status;
163    }
164}
165
166
167/*
168 * Check whether a given string is an option setting.  An option setting must
169 * start with a letter and consists of one or more alphanumerics or hyphen (-)
170 * followed by an equal sign (=) and at least one additional character.
171 */
172static bool
173is_option(const char *option)
174{
175    const char *p;
176
177    if (!isalpha((unsigned int) *option))
178        return false;
179    for (p = option; *p != '\0'; p++) {
180        if (*p == '=' && p > option && p[1] != '\0')
181            return true;
182        if (!isalnum((unsigned int) *p) && *p != '-')
183            return false;
184    }
185    return false;
186}
187
188
189/*
190 * Parse the logmask configuration option.  Verifies the listed argument
191 * numbers, stores them in the configuration line struct, and returns
192 * CONFIG_SUCCESS on success and CONFIG_ERROR on error.
193 */
194static enum config_status
195option_logmask(struct confline *confline, char *value, const char *name,
196               size_t lineno)
197{
198    struct cvector *logmask;
199    size_t i;
200    long arg;
201    char *end;
202
203    logmask = cvector_split(value, ',', NULL);
204    if (confline->logmask != NULL)
205        free(confline->logmask);
206    confline->logmask = xcalloc(logmask->count + 1, sizeof(unsigned int));
207    for (i = 0; i < logmask->count; i++) {
208        errno = 0;
209        arg = strtol(logmask->strings[i], &end, 10);
210        if (errno != 0 || *end != '\0' || arg <= 0) {
211            warn("%s:%lu: invalid logmask parameter %s", name,
212                 (unsigned long) lineno, logmask->strings[i]);
213            free(confline->logmask);
214            confline->logmask = NULL;
215            return CONFIG_ERROR;
216        }
217        confline->logmask[i] = arg;
218    }
219    confline->logmask[i] = 0;
220    cvector_free(logmask);
221    return CONFIG_SUCCESS;
222}
223
224
225/*
226 * Parse the stdin configuration option.  Verifies the argument number or
227 * "last" keyword, stores it in the configuration line struct, and returns
228 * CONFIG_SUCCESS on success and CONFIG_ERROR on error.
229 */
230static enum config_status
231option_stdin(struct confline *confline, char *value, const char *name,
232             size_t lineno)
233{
234    long arg;
235    char *end;
236
237    if (strcmp(value, "last") == 0)
238        confline->stdin_arg = -1;
239    else {
240        errno = 0;
241        arg = strtol(value, &end, 10);
242        if (errno != 0 || *end != '\0' || arg < 2) {
243            warn("%s:%lu: invalid stdin value %s", name,
244                 (unsigned long) lineno, value);
245            return CONFIG_ERROR;
246        }
247        confline->stdin_arg = arg;
248    }
249    return CONFIG_SUCCESS;
250}
251
252
253/*
254 * The table relating configuration option names to functions.
255 */
256static const struct config_option options[] = {
257    { "logmask", option_logmask },
258    { "stdin",   option_stdin   },
259    { NULL,      NULL           }
260};
261
262
263/*
264 * Parse a configuration option.  This is something after the command but
265 * before the ACLs that contains an equal sign.  The configuration option is
266 * the part before the equals and the value is the part afterwards.  Takes the
267 * configuration line, the option string, the file name, and the line number,
268 * and stores data in the configuration line struct as needed.
269 *
270 * Returns CONFIG_SUCCESS on success and CONFIG_ERROR on error, reporting an
271 * error message.
272 */
273static enum config_status
274parse_conf_option(struct confline *confline, char *option, const char *name,
275                  size_t lineno)
276{
277    char *end;
278    size_t length;
279    const struct config_option *handler;
280
281    end = strchr(option, '=');
282    if (end == NULL) {
283        warn("%s:%lu: invalid option %s", name, (unsigned long) lineno,
284             option);
285        return CONFIG_ERROR;
286    }
287    length = end - option;
288    for (handler = options; handler->name != NULL; handler++)
289        if (strlen(handler->name) == length)
290            if (strncmp(handler->name, option, length) == 0)
291                return (handler->parse)(confline, end + 1, name, lineno);
292    warn("%s:%lu: unknown option %s", name, (unsigned long) lineno, option);
293    return CONFIG_ERROR;
294}
295
296
297/*
298 * Reads the configuration file and parses every line, populating a data
299 * structure that will be traversed on each request to translate a command
300 * into an executable path and ACL file.
301 *
302 * config is populated with the parsed configuration file.  Empty lines and
303 * lines beginning with # are ignored.  Each line is divided into fields,
304 * separated by spaces.  The fields are defined by struct confline.  Lines
305 * ending in backslash are continued on the next line.  config is passed in as
306 * a void * so that read_conf_file and acl_check_file can use common include
307 * handling code.
308 *
309 * As a special case, include <file> will call read_conf_file recursively to
310 * parse an included file (or, if <file> is a directory, every file in that
311 * directory that doesn't contain a period).
312 *
313 * Returns CONFIG_SUCCESS on success and CONFIG_ERROR on error, reporting an
314 * error message.
315 */
316static enum config_status
317read_conf_file(void *data, const char *name)
318{
319    struct config *config = data;
320    FILE *file;
321    char *buffer, *p, *option;
322    size_t bufsize, length, size, count, i, arg_i;
323    enum config_status s;
324    struct vector *line = NULL;
325    struct confline *confline = NULL;
326    size_t lineno = 0;
327    DIR *dir = NULL;
328
329    bufsize = 1024;
330    buffer = xmalloc(bufsize);
331    file = fopen(name, "r");
332    if (file == NULL) {
333        free(buffer);
334        syswarn("cannot open config file %s", name);
335        return CONFIG_ERROR;
336    }
337    while (fgets(buffer, bufsize, file) != NULL) {
338        length = strlen(buffer);
339        if (length == 2 && buffer[length - 1] != '\n') {
340            warn("%s:%lu: no final newline", name, (unsigned long) lineno);
341            goto fail;
342        }
343        if (length < 2)
344            continue;
345
346        /*
347         * Allow for long lines and continuation lines.  As long as we've
348         * either filled the buffer or have a line ending in a backslash, we
349         * keep reading more data.  If we filled the buffer, increase it by
350         * another 1KB; otherwise, back up and write over the backslash and
351         * newline.
352         */
353        p = buffer + length - 2;
354        while (length > 2 && (p[1] != '\n' || p[0] == '\\')) {
355            if (p[1] != '\n') {
356                bufsize += 1024;
357                buffer = xrealloc(buffer, bufsize);
358            } else {
359                length -= 2;
360                lineno++;
361            }
362            if (fgets(buffer + length, bufsize - length, file) == NULL) {
363                warn("%s:%lu: no final line or newline", name,
364                     (unsigned long) lineno);
365                goto fail;
366            }
367            length = strlen(buffer);
368            p = buffer + length - 2;
369        }
370        if (length > 0)
371            buffer[length - 1] = '\0';
372        lineno++;
373
374        /*
375         * Skip blank lines or commented-out lines.  Note that because of the
376         * above logic, comments can be continued on the next line, so be
377         * careful.
378         */
379        p = buffer;
380        while (isspace((int) *p))
381            p++;
382        if (*p == '\0' || *p == '#')
383            continue;
384
385        /*
386         * We have a valid configuration line.  Do a quick syntax check and
387         * handle include.
388         */
389        line = vector_split_space(buffer, NULL);
390        if (line->count == 2 && strcmp(line->strings[0], "include") == 0) {
391            s = handle_include(line->strings[1], name, lineno, read_conf_file,
392                               config);
393            if (s < -1)
394                goto fail;
395            vector_free(line);
396            line = NULL;
397            continue;
398        } else if (line->count < 4) {
399            warn("%s:%lu: parse error", name, (unsigned long) lineno);
400            goto fail;
401        }
402
403        /*
404         * Okay, we have a regular configuration line.  Make sure there's
405         * space for it in the config struct and stuff the vector into place.
406         */
407        if (config->count == config->allocated) {
408            if (config->allocated < 4)
409                config->allocated = 4;
410            else
411                config->allocated *= 2;
412            size = config->allocated * sizeof(struct confline *);
413            config->rules = xrealloc(config->rules, size);
414        }
415        confline = xcalloc(1, sizeof(struct confline));
416        confline->line       = line;
417        confline->command    = line->strings[0];
418        confline->subcommand = line->strings[1];
419        confline->program    = line->strings[2];
420
421        /*
422         * Parse config options.
423         */
424        for (arg_i = 3; arg_i < line->count; arg_i++) {
425            option = line->strings[arg_i];
426            if (!is_option(option))
427                break;
428            s = parse_conf_option(confline, option, name, lineno);
429            if (s != CONFIG_SUCCESS)
430                goto fail;
431        }
432
433        /*
434         * One more syntax error possibility here: a line that only has a
435         * logmask setting but no ACL files.
436         */
437        if (line->count <= arg_i) {
438            warn("%s:%lu: config parse error", name, (unsigned long) lineno);
439            goto fail;
440        }
441
442        /* Grab the metadata and list of ACL files. */
443        confline->file = xstrdup(name);
444        confline->lineno = lineno;
445        count = line->count - arg_i + 1;
446        confline->acls = xmalloc(count * sizeof(char *));
447        for (i = 0; i < line->count - arg_i; i++)
448            confline->acls[i] = line->strings[i + arg_i];
449        confline->acls[i] = NULL;
450
451        /* Success.  Put the configuration line in place. */
452        config->rules[config->count] = confline;
453        config->count++;
454        confline = NULL;
455        line = NULL;
456    }
457
458    /* Free allocated memory and return success. */
459    free(buffer);
460    fclose(file);
461    return 0;
462
463    /* Abort with an error. */
464fail:
465    if (dir != NULL)
466        closedir(dir);
467    if (line != NULL)
468        vector_free(line);
469    if (confline != NULL) {
470        if (confline->logmask != NULL)
471            free(confline->logmask);
472        free(confline);
473    }
474    free(buffer);
475    fclose(file);
476    return CONFIG_ERROR;
477}
478
479
480/*
481 * Check to see if a principal is authorized by a given ACL file.
482 *
483 * This function is used to handle included ACL files and only does a simple
484 * check to prevent infinite recursion, so be careful.  The first argument is
485 * the user to check, which is passed in as a void * so that acl_check_file
486 * and read_conf_file can share common include-handling code.
487 *
488 * Returns the result of the first check that returns a result other than
489 * CONFIG_NOMATCH, or CONFIG_NOMATCH if no check returns some other value.
490 * Also returns CONFIG_ERROR on some sort of failure (such as failure to read
491 * a file or a syntax error).
492 */
493static enum config_status
494acl_check_file_internal(void *data, const char *aclfile)
495{
496    const char *user = data;
497    FILE *file = NULL;
498    char buffer[BUFSIZ];
499    char *p;
500    int lineno;
501    enum config_status s;
502    size_t length;
503    struct vector *line = NULL;
504
505    file = fopen(aclfile, "r");
506    if (file == NULL) {
507        syswarn("cannot open ACL file %s", aclfile);
508        return CONFIG_ERROR;
509    }
510    lineno = 0;
511    while (fgets(buffer, sizeof(buffer), file) != NULL) {
512        lineno++;
513        length = strlen(buffer);
514        if (length >= sizeof(buffer) - 1) {
515            warn("%s:%d: ACL file line too long", aclfile, lineno);
516            goto fail;
517        }
518
519        /*
520         * Skip blank lines or commented-out lines and remove trailing
521         * whitespace.
522         */
523        p = buffer + length - 1;
524        while (isspace((int) *p))
525            p--;
526        p[1] = '\0';
527        p = buffer;
528        while (isspace((int) *p))
529            p++;
530        if (*p == '\0' || *p == '#')
531            continue;
532
533        /* Parse the line. */
534        if (strchr(p, ' ') == NULL)
535            s = acl_check(user, p, ACL_SCHEME_PRINC, aclfile, lineno);
536        else {
537            line = vector_split_space(buffer, NULL);
538            if (line->count == 2 && strcmp(line->strings[0], "include") == 0) {
539                s = acl_check(data, line->strings[1], ACL_SCHEME_FILE,
540                              aclfile, lineno);
541                vector_free(line);
542                line = NULL;
543            } else {
544                warn("%s:%d: parse error", aclfile, lineno);
545                goto fail;
546            }
547        }
548        if (s != CONFIG_NOMATCH) {
549            fclose(file);
550            return s;
551        }
552    }
553    return CONFIG_NOMATCH;
554
555fail:
556    if (line != NULL)
557        vector_free(line);
558    if (file != NULL)
559        fclose(file);
560    return CONFIG_ERROR;
561}
562
563
564/*
565 * The ACL check operation for the file method.  Takes the user to check, the
566 * ACL file or directory name, and the referencing file name and line number.
567 *
568 * Conceptually, this returns CONFIG_SUCCESS if the user is authorized,
569 * CONFIG_NOMATCH if they aren't, CONFIG_ERROR on some sort of failure, and
570 * CONFIG_DENY for an explicit deny.  What actually happens is the result of
571 * the interplay between handle_include and acl_check_file_internal:
572 *
573 * - For each file, return the first result other than CONFIG_NOMATCH
574 *   (indicating no match), or CONFIG_NOMATCH if there is no other result.
575 *
576 * - Return the first result from any file less than CONFIG_NOMATCH,
577 *   indicating a failure or an explicit deny.
578 *
579 * - If there is no result less than CONFIG_NOMATCH, return the largest
580 *   remaining result, which should be CONFIG_SUCCESS or CONFIG_NOMATCH.
581 */
582static enum config_status
583acl_check_file(const char *user, const char *aclfile, const char *file,
584               int lineno)
585{
586    return handle_include(aclfile, file, lineno, acl_check_file_internal,
587                          (void *) user);
588}
589
590
591/*
592 * The ACL check operation for the princ method.  Takes the user to check, the
593 * principal name we are checking against, and the referencing file name and
594 * line number.
595 *
596 * Returns CONFIG_SUCCESS if the user is authorized, or CONFIG_NOMATCH if they
597 * aren't.
598 */
599static enum config_status
600acl_check_princ(const char *user, const char *data, const char *file UNUSED,
601                int lineno UNUSED)
602{
603    return (strcmp(user, data) == 0) ? CONFIG_SUCCESS : CONFIG_NOMATCH;
604}
605
606
607/*
608 * The ACL check operation for the deny method.  Takes the user to check, the
609 * scheme:method we are checking against, and the referencing file name and
610 * line number.
611 *
612 * This one is a little unusual:
613 *
614 * - If the recursive check matches (status CONFIG_SUCCESS), it returns
615 *   CONFIG_DENY.  This is treated by handle_include and
616 *   acl_check_file_internal as an error condition, and causes processing to
617 *   be stopped immediately, without doing further checks as would be done for
618 *   a normal CONFIG_NOMATCH "no match" return.
619 *
620 * - If the recursive check does not match (status CONFIG_NOMATCH), it returns
621 *   CONFIG_NOMATCH, which indicates "no match".  This allows processing to
622 *   continue without either granting or denying access.
623 *
624 * - If the recursive check returns CONFIG_DENY, that is treated as a forced
625 *   deny from a recursive call to acl_check_deny, and is returned as
626 *   CONFIG_NOMATCH, indicating "no match".
627 *
628 * Any other result indicates a processing error and is returned as-is.
629 */
630static enum config_status
631acl_check_deny(const char *user, const char *data, const char *file,
632               int lineno)
633{
634    enum config_status s;
635
636    s = acl_check(user, data, ACL_SCHEME_PRINC, file, lineno);
637    switch (s) {
638    case CONFIG_SUCCESS: return CONFIG_DENY;
639    case CONFIG_NOMATCH: return CONFIG_NOMATCH;
640    case CONFIG_DENY:    return CONFIG_NOMATCH;
641    default:             return s;
642    }
643}
644
645
646/*
647 * Sets the GPUT ACL file.  Currently, this function is only used by the test
648 * suite.
649 */
650#ifdef HAVE_GPUT
651void
652server_config_set_gput_file(char *file)
653{
654    acl_gput_file = file;
655}
656#else
657void
658server_config_set_gput_file(char *file UNUSED)
659{
660    return;
661}
662#endif
663
664
665/*
666 * The ACL check operation for the gput method.  Takes the user to check, the
667 * GPUT group name (and optional transform) we are checking against, and the
668 * referencing file name and line number.
669 *
670 * The syntax of the data is "group" or "group[xform]".
671 *
672 * Returns CONFIG_SUCCESS if the user is authorized, CONFIG_NOMATCH if they
673 * aren't, and CONFIG_ERROR on some sort of failure (such as failure to read a
674 * file or a syntax error).
675 */
676#ifdef HAVE_GPUT
677static enum config_status
678acl_check_gput(const char *user, const char *data, const char *file,
679               int lineno)
680{
681    GPUT *G;
682    char *role, *xform, *xform_start, *xform_end;
683    enum config_status s;
684
685    xform_start = strchr(data, '[');
686    if (xform_start != NULL) {
687        xform_end = strchr(xform_start + 1, ']');
688        if (xform_end == NULL) {
689            warn("%s:%d: missing ] in GPUT specification '%s'", file, lineno,
690                 data);
691            return CONFIG_ERROR;
692        }
693        if (xform_end[1] != '\0') {
694            warn("%s:%d: invalid GPUT specification '%s'", file, lineno,
695                 data);
696            return CONFIG_ERROR;
697        }
698        role = xstrndup(data, xform_start - data);
699        xform = xstrndup(xform_start + 1, xform_end - (xform_start + 1));
700    } else {
701        role = (char *) data;
702        xform = NULL;
703    }
704
705    /*
706     * Sigh; apparently I wasn't flexible enough in GPUT error reporting.  You
707     * can direct diagnostics to a file descriptor, but there's not much else
708     * you can do with them.  In a future GPUT version, I'll make it possible
709     * to have diagnostics reported via a callback.
710     */
711    G = gput_open(acl_gput_file, NULL);
712    if (G == NULL)
713        s = CONFIG_ERROR;
714    else {
715        if (gput_check(G, role, (char *) user, xform, NULL))
716            s = CONFIG_SUCCESS;
717        else
718            s = CONFIG_NOMATCH;
719        gput_close(G);
720    }
721    if (xform_start) {
722        free(role);
723        free(xform);
724    }
725    return s;
726}
727#endif /* HAVE_GPUT */
728
729
730/*
731 * The table relating ACL scheme names to functions.  The first two ACL
732 * schemes must remain in their current slots or the index constants set at
733 * the top of the file need to change.
734 */
735static const struct acl_scheme schemes[] = {
736    { "file",  acl_check_file  },
737    { "princ", acl_check_princ },
738    { "deny",  acl_check_deny  },
739#ifdef HAVE_GPUT
740    { "gput",  acl_check_gput  },
741#else
742    { "gput",  NULL            },
743#endif
744    { NULL,    NULL            }
745};
746
747
748/*
749 * The access control check switch.  Takes the user to check, the ACL entry,
750 * default scheme index, and referencing file name and line number.
751 *
752 * Returns CONFIG_SUCCESS if the user is authorized, CONFIG_NOMATCH if they
753 * aren't, CONFIG_ERROR on some sort of failure (such as failure to read a
754 * file or a syntax error), and CONFIG_DENY for an explicit deny.
755 */
756static enum config_status
757acl_check(const char *user, const char *entry, int def_index,
758          const char *file, int lineno)
759{
760    const struct acl_scheme *scheme;
761    char *prefix;
762    const char *data;
763
764    data = strchr(entry, ':');
765    if (data != NULL) {
766        prefix = xstrndup(entry, data - entry);
767        data++;
768        for (scheme = schemes; scheme->name != NULL; scheme++)
769            if (strcmp(prefix, scheme->name) == 0)
770                break;
771        if (scheme->name == NULL) {
772            warn("%s:%d: invalid ACL scheme '%s'", file, lineno, prefix);
773            free(prefix);
774            return CONFIG_ERROR;
775        }
776        free(prefix);
777    } else {
778        /* Use the default scheme. */
779        scheme = schemes + def_index;
780        data = entry;
781    }
782    if (scheme->check == NULL) {
783        warn("%s:%d: ACL scheme '%s' is not supported", file, lineno,
784             scheme->name);
785        return CONFIG_ERROR;
786    }
787    return scheme->check(user, data, file, lineno);
788}
789
790
791/*
792 * Load a configuration file.  Returns a newly allocated config struct if
793 * successful or NULL on failure, logging an appropriate error message.
794 */
795struct config *
796server_config_load(const char *file)
797{
798    struct config *config;
799
800    /* Read the configuration file. */
801    config = xcalloc(1, sizeof(struct config));
802    if (read_conf_file(config, file) != 0) {
803        free(config);
804        return NULL;
805    }
806    return config;
807}
808
809
810/*
811 * Free the config structure created by calling server_config_load.
812 */
813void
814server_config_free(struct config *config)
815{
816    struct confline *rule;
817    size_t i;
818
819    for (i = 0; i < config->count; i++) {
820        rule = config->rules[i];
821        if (rule->logmask != NULL)
822            free(rule->logmask);
823        if (rule->acls != NULL)
824            free(rule->acls);
825        if (rule->line != NULL)
826            vector_free(rule->line);
827        if (rule->file != NULL)
828            free(rule->file);
829    }
830    free(config->rules);
831    free(config);
832}
833
834
835/*
836 * Given the confline corresponding to the command and the principal
837 * requesting access, see if the command is allowed.  Return true if so, false
838 * otherwise.
839 */
840bool
841server_config_acl_permit(struct confline *cline, const char *user)
842{
843    char **acls = cline->acls;
844    size_t i;
845    enum config_status status;
846
847    if (strcmp(acls[0], "ANYUSER") == 0)
848        return true;
849    for (i = 0; acls[i] != NULL; i++) {
850        status = acl_check(user, acls[i], ACL_SCHEME_FILE, cline->file,
851                           cline->lineno);
852        if (status == 0)
853            return true;
854        else if (status < -1)
855            return false;
856    }
857    return false;
858}
Note: See TracBrowser for help on using the repository browser.