Changeset 240 in openpam for trunk/lib


Ignore:
Timestamp:
May 25, 2003, 6:34:31 PM (17 years ago)
Author:
Dag-Erling Smørgrav
Message:

Overhaul the configuration parser. This adds support for continuation
lines and policy inclusion.

Location:
trunk/lib
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/Makefile

    r226 r240  
    3232# SUCH DAMAGE.
    3333#
    34 # $P4: //depot/projects/openpam/lib/Makefile#19 $
     34# $P4: //depot/projects/openpam/lib/Makefile#20 $
    3535#
    3636
     
    5858SRCS            += openpam_log.c
    5959SRCS            += openpam_nullconv.c
     60SRCS            += openpam_readline.c
    6061SRCS            += openpam_restore_cred.c
    6162SRCS            += openpam_set_option.c
  • trunk/lib/openpam_configure.c

    r232 r240  
    11/*-
    2  * Copyright (c) 2002 Networks Associates Technology, Inc.
     2 * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
    33 * All rights reserved.
    44 *
     
    3232 * SUCH DAMAGE.
    3333 *
    34  * $P4: //depot/projects/openpam/lib/openpam_configure.c#7 $
     34 * $P4: //depot/projects/openpam/lib/openpam_configure.c#8 $
    3535 */
    3636
     
    4545#include "openpam_impl.h"
    4646
    47 #define PAM_CONF_STYLE  0
    48 #define PAM_D_STYLE     1
    49 #define MAX_LINE_LEN    1024
    50 #define MAX_OPTIONS     256
    51 
     47static int openpam_load_chain(pam_chain_t **, const char *, const char *);
     48
     49/*
     50 * Matches a word against the first one in a string.
     51 * Returns non-zero if they match.
     52 */
    5253static int
    53 openpam_read_policy_file(pam_chain_t *policy[],
     54match_word(const char *str, const char *word)
     55{
     56
     57        while (*str && *str == *word)
     58                ++str, ++word;
     59        return (*str == ' ' && *word == '\0');
     60}
     61
     62/*
     63 * Return a pointer to the next word (or the final NUL) in a string.
     64 */
     65static const char *
     66next_word(const char *str)
     67{
     68
     69        /* skip current word */
     70        while (*str && !isspace(*str))
     71                ++str;
     72        /* skip whitespace */
     73        while (isspace(*str))
     74                ++str;
     75        return (str);
     76}
     77
     78/*
     79 * Return a malloc()ed copy of the first word in a string.
     80 */
     81static char *
     82dup_word(const char *str)
     83{
     84        const char *end;
     85        char *word;
     86
     87        for (end = str; *end && !isspace(*end); ++end)
     88                /* nothing */ ;
     89        if (asprintf(&word, "%.*s", (int)(end - str), str) < 0)
     90                return (NULL);
     91        return (word);
     92}
     93
     94typedef enum { pam_conf_style, pam_d_style } openpam_style_t;
     95
     96/*
     97 * Extracts a given chain from a policy file.
     98 */
     99static int
     100openpam_read_chain(pam_chain_t **chain,
    54101        const char *service,
     102        const char *facility,
    55103        const char *filename,
    56         int style)
    57 {
    58         char buf[MAX_LINE_LEN], *p, *q;
    59         const char *optv[MAX_OPTIONS + 1];
    60         int ch, chain, flag, line, optc, n, r;
    61         size_t len;
     104        openpam_style_t style)
     105{
     106        pam_chain_t *this, **next;
     107        const char *p, *q;
     108        int count, i, ret;
     109        char *line, *name;
    62110        FILE *f;
    63111
    64         n = 0;
    65 
    66112        if ((f = fopen(filename, "r")) == NULL) {
    67                 openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_NOTICE,
     113                openpam_log(errno == ENOENT ? PAM_LOG_NOTICE : PAM_LOG_ERROR,
    68114                    "%s: %m", filename);
    69115                return (0);
    70116        }
    71         openpam_log(PAM_LOG_DEBUG, "looking for '%s' in %s",
    72             service, filename);
    73 
    74         for (line = 1; fgets(buf, MAX_LINE_LEN, f) != NULL; ++line) {
    75                 if ((len = strlen(buf)) == 0)
     117        next = chain;
     118        this = *next = NULL;
     119        count = 0;
     120        while ((line = openpam_readline(f, NULL)) != NULL) {
     121                p = line;
     122
     123                /* match service name */
     124                if (style == pam_conf_style) {
     125                        if (!match_word(p, service)) {
     126                                FREE(line);
     127                                continue;
     128                        }
     129                        p = next_word(p);
     130                }
     131
     132                /* match facility name */
     133                if (!match_word(p, facility)) {
     134                        FREE(line);
    76135                        continue;
    77 
    78                 /* check for overflow */
    79                 if (buf[--len] != '\n' && !feof(f)) {
    80                         openpam_log(PAM_LOG_ERROR, "%s: line %d too long",
    81                             filename, line);
    82                         openpam_log(PAM_LOG_ERROR, "%s: ignoring line %d",
    83                             filename, line);
    84                         while ((ch = fgetc(f)) != EOF)
    85                                 if (ch == '\n')
    86                                         break;
     136                }
     137                p = next_word(p);
     138
     139                /* include other chain */
     140                if (match_word(p, "include")) {
     141                        p = next_word(p);
     142                        if (*next_word(p) != '\0')
     143                                openpam_log(PAM_LOG_NOTICE,
     144                                    "%s: garbage at end of 'include' line",
     145                                    filename);
     146                        if ((name = dup_word(p)) == NULL)
     147                                goto syserr;
     148                        ret = openpam_load_chain(next, name, facility);
     149                        FREE(name);
     150                        while (*next != NULL) {
     151                                next = &(*next)->next;
     152                                ++count;
     153                        }
     154                        FREE(line);
     155                        if (ret < 0)
     156                                goto fail;
    87157                        continue;
    88158                }
    89159
    90                 /* strip comments and trailing whitespace */
    91                 if ((p = strchr(buf, '#')) != NULL)
    92                         len = p - buf ? p - buf - 1 : p - buf;
    93                 while (len > 0 && isspace(buf[len - 1]))
    94                         --len;
    95                 if (len == 0)
    96                         continue;
    97                 buf[len] = '\0';
    98                 p = q = buf;
    99 
    100                 /* check service name */
    101                 if (style == PAM_CONF_STYLE) {
    102                         for (q = p = buf; *q != '\0' && !isspace(*q); ++q)
    103                                 /* nothing */;
    104                         if (*q == '\0')
    105                                 goto syntax_error;
    106                         *q++ = '\0';
    107                         if (strcmp(p, service) != 0)
    108                                 continue;
    109                         openpam_log(PAM_LOG_DEBUG, "%s: line %d matches '%s'",
    110                             filename, line, service);
    111                 }
    112 
    113 
    114                 /* get module type */
    115                 for (p = q; isspace(*p); ++p)
    116                         /* nothing */;
    117                 for (q = p; *q != '\0' && !isspace(*q); ++q)
    118                         /* nothing */;
    119                 if (q == p || *q == '\0')
    120                         goto syntax_error;
    121                 *q++ = '\0';
    122                 if (strcmp(p, "auth") == 0) {
    123                         chain = PAM_AUTH;
    124                 } else if (strcmp(p, "account") == 0) {
    125                         chain = PAM_ACCOUNT;
    126                 } else if (strcmp(p, "session") == 0) {
    127                         chain = PAM_SESSION;
    128                 } else if (strcmp(p, "password") == 0) {
    129                         chain = PAM_PASSWORD;
     160                /* allocate new entry */
     161                if ((this = calloc(1, sizeof *this)) == NULL)
     162                        goto syserr;
     163
     164                /* control flag */
     165                if (match_word(p, "required")) {
     166                        this->flag = PAM_REQUIRED;
     167                } else if (match_word(p, "requisite")) {
     168                        this->flag = PAM_REQUISITE;
     169                } else if (match_word(p, "sufficient")) {
     170                        this->flag = PAM_SUFFICIENT;
     171                } else if (match_word(p, "optional")) {
     172                        this->flag = PAM_OPTIONAL;
     173                } else if (match_word(p, "binding")) {
     174                        this->flag = PAM_BINDING;
    130175                } else {
     176                        q = next_word(p);
    131177                        openpam_log(PAM_LOG_ERROR,
    132                             "%s: invalid module type on line %d: '%s'",
    133                             filename, line, p);
    134                         continue;
    135                 }
    136 
    137                 /* get control flag */
    138                 for (p = q; isspace(*p); ++p)
    139                         /* nothing */;
    140                 for (q = p; *q != '\0' && !isspace(*q); ++q)
    141                         /* nothing */;
    142                 if (q == p || *q == '\0')
    143                         goto syntax_error;
    144                 *q++ = '\0';
    145                 if (strcmp(p, "required") == 0) {
    146                         flag = PAM_REQUIRED;
    147                 } else if (strcmp(p, "requisite") == 0) {
    148                         flag = PAM_REQUISITE;
    149                 } else if (strcmp(p, "sufficient") == 0) {
    150                         flag = PAM_SUFFICIENT;
    151                 } else if (strcmp(p, "optional") == 0) {
    152                         flag = PAM_OPTIONAL;
    153                 } else if (strcmp(p, "binding") == 0) {
    154                         flag = PAM_BINDING;
    155                 } else {
     178                            "%s: invalid control flag '%.*s'",
     179                            filename, (int)(q - p), p);
     180                        goto fail;
     181                }
     182
     183                /* module name */
     184                p = next_word(p);
     185                q = next_word(p);
     186                if (*p == '\0') {
    156187                        openpam_log(PAM_LOG_ERROR,
    157                             "%s: invalid control flag on line %d: '%s'",
    158                             filename, line, p);
    159                         continue;
    160                 }
    161 
    162                 /* get module name */
    163                 for (p = q; isspace(*p); ++p)
    164                         /* nothing */;
    165                 for (q = p; *q != '\0' && !isspace(*q); ++q)
    166                         /* nothing */;
    167                 if (q == p)
    168                         goto syntax_error;
    169 
    170                 /* get options */
    171                 for (optc = 0; *q != '\0' && optc < MAX_OPTIONS; ++optc) {
    172                         *q++ = '\0';
    173                         while (isspace(*q))
    174                                 ++q;
    175                         optv[optc] = q;
    176                         while (*q != '\0' && !isspace(*q))
    177                                 ++q;
    178                 }
    179                 optv[optc] = NULL;
    180                 if (*q != '\0') {
    181                         *q = '\0';
    182                         openpam_log(PAM_LOG_ERROR,
    183                             "%s: too many options on line %d",
    184                             filename, line);
    185                 }
    186 
    187                 /*
    188                  * Finally, add the module at the end of the
    189                  * appropriate chain and bump the counter.
    190                  */
    191                 r = openpam_add_module(policy, chain, flag, p, optc, optv);
    192                 if (r != PAM_SUCCESS)
    193                         return (-r);
    194                 ++n;
    195                 continue;
    196  syntax_error:
    197                 openpam_log(PAM_LOG_ERROR, "%s: syntax error on line %d",
    198                     filename, line);
    199                 openpam_log(PAM_LOG_DEBUG, "%s: line %d: [%s]",
    200                     filename, line, q);
    201                 openpam_log(PAM_LOG_ERROR, "%s: ignoring line %d",
    202                     filename, line);
     188                            "%s: missing module name", filename);
     189                        goto fail;
     190                }
     191                if ((name = dup_word(p)) == NULL)
     192                        goto syserr;
     193                this->module = openpam_load_module(name);
     194                FREE(name);
     195                if (this->module == NULL)
     196                        goto fail;
     197
     198                /* module options */
     199                while (*q != '\0') {
     200                        ++this->optc;
     201                        q = next_word(q);
     202                }
     203                this->optv = calloc(this->optc + 1, sizeof(char *));
     204                if (this->optv == NULL)
     205                        goto syserr;
     206                for (i = 0; i < this->optc; ++i) {
     207                        p = next_word(p);
     208                        if ((this->optv[i] = dup_word(p)) == NULL)
     209                                goto syserr;
     210                }
     211
     212                /* hook it up */
     213                *next = this;
     214                next = &this->next;
     215                this = NULL;
     216                ++count;
     217
     218                /* next please... */
     219                FREE(line);
    203220        }
    204 
    205         if (ferror(f))
    206                 openpam_log(PAM_LOG_ERROR, "%s: %m", filename);
    207 
     221        if (!feof(f))
     222                goto syserr;
    208223        fclose(f);
    209         return (n);
     224        return (count);
     225 syserr:
     226        openpam_log(PAM_LOG_ERROR, "%s: %m", filename);
     227 fail:
     228        FREE(this);
     229        FREE(line);
     230        fclose(f);
     231        return (-1);
    210232}
    211233
     
    218240};
    219241
     242/*
     243 * Locates the policy file for a given service and reads the given chain
     244 * from it.
     245 */
    220246static int
    221 openpam_load_policy(pam_chain_t *policy[],
    222         const char *service)
     247openpam_load_chain(pam_chain_t **chain,
     248        const char *service,
     249        const char *facility)
    223250{
    224251        const char **path;
     
    230257                len = strlen(*path);
    231258                if ((*path)[len - 1] == '/') {
    232                         filename = malloc(len + strlen(service) + 1);
    233                         if (filename == NULL) {
    234                                 openpam_log(PAM_LOG_ERROR, "malloc(): %m");
     259                        if (asprintf(&filename, "%s%s", *path, service) < 0) {
     260                                openpam_log(PAM_LOG_ERROR, "asprintf(): %m");
    235261                                return (-PAM_BUF_ERR);
    236262                        }
    237                         strcpy(filename, *path);
    238                         strcat(filename, service);
    239                         r = openpam_read_policy_file(policy,
    240                             service, filename, PAM_D_STYLE);
     263                        r = openpam_read_chain(chain, service, facility,
     264                            filename, pam_d_style);
    241265                        FREE(filename);
    242266                } else {
    243                         r = openpam_read_policy_file(policy,
    244                             service, *path, PAM_CONF_STYLE);
     267                        r = openpam_read_chain(chain, service, facility,
     268                            *path, pam_conf_style);
    245269                }
    246270                if (r != 0)
    247271                        return (r);
    248272        }
    249 
    250273        return (0);
    251274}
     275
     276const char *_pam_chain_name[PAM_NUM_CHAINS] = {
     277        [PAM_AUTH] = "auth",
     278        [PAM_ACCOUNT] = "account",
     279        [PAM_SESSION] = "session",
     280        [PAM_PASSWORD] = "password"
     281};
    252282
    253283/*
     
    261291        const char *service)
    262292{
    263         pam_chain_t *other[PAM_NUM_CHAINS] = { 0 };
    264         int i, n, r;
    265 
    266         /* try own configuration first */
    267         r = openpam_load_policy(pamh->chains, service);
    268         if (r < 0)
    269                 return (-r);
    270         for (i = n = 0; i < PAM_NUM_CHAINS; ++i) {
    271                 if (pamh->chains[i] != NULL)
    272                         ++n;
     293        int i, ret;
     294
     295        for (i = 0; i < PAM_NUM_CHAINS; ++i) {
     296                ret = openpam_load_chain(&pamh->chains[i],
     297                    service, _pam_chain_name[i]);
     298                if (ret == 0)
     299                        ret = openpam_load_chain(&pamh->chains[i],
     300                            PAM_OTHER, _pam_chain_name[i]);
     301                if (ret < 0) {
     302                        openpam_clear_chains(pamh->chains);
     303                        return (PAM_SYSTEM_ERR);
     304                }
    273305        }
    274         if (n == PAM_NUM_CHAINS)
    275                 return (PAM_SUCCESS);
    276 
    277         /* fill in the blanks with "other" */
    278         openpam_load_policy(other, PAM_OTHER);
    279         if (r < 0)
    280                 return (-r);
    281         for (i = n = 0; i < PAM_NUM_CHAINS; ++i) {
    282                 if (pamh->chains[i] == NULL) {
    283                         pamh->chains[i] = other[i];
    284                         other[i] = NULL;
    285                 }
    286                 if (pamh->chains[i] != NULL)
    287                         ++n;
    288         }
    289         openpam_clear_chains(other);
    290         return (n > 0 ? PAM_SUCCESS : PAM_SYSTEM_ERR);
     306        return (PAM_SUCCESS);
    291307}
    292308
     
    296312 * Error codes:
    297313 *      PAM_SYSTEM_ERR
    298  *      PAM_BUF_ERR
    299  */
     314 */
  • trunk/lib/openpam_impl.h

    r236 r240  
    3232 * SUCH DAMAGE.
    3333 *
    34  * $P4: //depot/projects/openpam/lib/openpam_impl.h#24 $
     34 * $P4: //depot/projects/openpam/lib/openpam_impl.h#25 $
    3535 */
    3636
     
    113113#define PAM_OTHER       "other"
    114114
    115 int             openpam_configure(pam_handle_t *, const char *);
    116 int             openpam_dispatch(pam_handle_t *, int, int);
    117 int             openpam_findenv(pam_handle_t *, const char *, size_t);
    118 int             openpam_add_module(pam_chain_t **, int, int,
    119                                    const char *, int, const char **);
    120 void            openpam_clear_chains(pam_chain_t **);
     115int              openpam_configure(pam_handle_t *, const char *);
     116int              openpam_dispatch(pam_handle_t *, int, int);
     117int              openpam_findenv(pam_handle_t *, const char *, size_t);
     118pam_module_t    *openpam_load_module(const char *);
     119void             openpam_clear_chains(pam_chain_t **);
    121120
    122121#ifdef OPENPAM_STATIC_MODULES
    123 pam_module_t   *openpam_static(const char *);
     122pam_module_t    *openpam_static(const char *);
    124123#endif
    125 pam_module_t   *openpam_dynamic(const char *);
     124pam_module_t    *openpam_dynamic(const char *);
    126125
    127126#define FREE(p) do { free((p)); (p) = NULL; } while (0)
  • trunk/lib/openpam_load.c

    r232 r240  
    3232 * SUCH DAMAGE.
    3333 *
    34  * $P4: //depot/projects/openpam/lib/openpam_load.c#16 $
     34 * $P4: //depot/projects/openpam/lib/openpam_load.c#17 $
    3535 */
    3636
     
    6868 */
    6969
    70 static pam_module_t *
     70pam_module_t *
    7171openpam_load_module(const char *path)
    7272{
     
    161161}
    162162
    163 /*
    164  * Add a module to a chain.
    165  */
    166 
    167 int
    168 openpam_add_module(pam_chain_t *policy[],
    169         int chain,
    170         int flag,
    171         const char *modpath,
    172         int optc,
    173         const char *optv[])
    174 {
    175         pam_chain_t *new, *iterator;
    176 
    177         if ((new = calloc(1, sizeof *new)) == NULL)
    178                 goto buf_err;
    179         if ((new->optv = malloc(sizeof(char *) * (optc + 1))) == NULL)
    180                 goto buf_err;
    181         while (optc--)
    182                 if ((new->optv[new->optc++] = strdup(*optv++)) == NULL)
    183                         goto buf_err;
    184         new->optv[new->optc] = NULL;
    185         new->flag = flag;
    186         if ((new->module = openpam_load_module(modpath)) == NULL) {
    187                 openpam_destroy_chain(new);
    188                 return (PAM_OPEN_ERR);
    189         }
    190         if ((iterator = policy[chain]) != NULL) {
    191                 while (iterator->next != NULL)
    192                         iterator = iterator->next;
    193                 iterator->next = new;
    194         } else {
    195                 policy[chain] = new;
    196         }
    197         return (PAM_SUCCESS);
    198 
    199  buf_err:
    200         openpam_log(PAM_LOG_ERROR, "%m");
    201         openpam_destroy_chain(new);
    202         return (PAM_BUF_ERR);
    203 }
    204 
    205163
    206164/*
Note: See TracChangeset for help on using the changeset viewer.