[BACK]Return to conf.y CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/conf.y, Revision 1.2

1.1       jfb         1: /*     $OpenBSD$       */
                      2: /*
                      3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  *
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. The name of the author may not be used to endorse or promote products
                     13:  *    derived from this software without specific prior written permission.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     16:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     17:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     18:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     19:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     20:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     21:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     23:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  *
                     26:  */
                     27: /*
                     28:  * Configuration parser for the CVS daemon
1.2     ! jfb        29:  *
        !            30:  * Thanks should go to Henning Brauer for providing insight on some
        !            31:  * questions I had regarding my grammar.
1.1       jfb        32:  */
1.2     ! jfb        33:
        !            34: %{
1.1       jfb        35: #include <sys/types.h>
                     36: #include <sys/queue.h>
                     37:
                     38: #include <errno.h>
1.2     ! jfb        39: #include <ctype.h>
1.1       jfb        40: #include <stdio.h>
                     41: #include <stdlib.h>
                     42: #include <stdarg.h>
                     43: #include <unistd.h>
                     44: #include <string.h>
                     45:
                     46: #include "cvsd.h"
                     47: #include "cvs.h"
                     48: #include "log.h"
1.2     ! jfb        49: #include "file.h"
        !            50:
1.1       jfb        51:
                     52: #define CVS_ACL_MAXRULES     256
                     53:
                     54: #define CVS_ACL_DENY         0
                     55: #define CVS_ACL_ALLOW        1
                     56:
                     57: #define CVS_ACL_LOGOPT    0x01
                     58: #define CVS_ACL_QUICKOPT  0x02
                     59:
                     60:
                     61: struct conf_macro {
                     62:        char  *cm_name;
                     63:        char  *cm_val;
                     64:
                     65:        SIMPLEQ_ENTRY(conf_macro) cm_list;
                     66: };
                     67:
                     68:
                     69: struct acl_user {
                     70:        uid_t  au_uid;
                     71:        SLIST_ENTRY(acl_user) au_list;
                     72: };
                     73:
                     74:
                     75: struct acl_rule {
                     76:        u_int8_t   ar_id;
                     77:        u_int8_t   ar_act;
                     78:        u_int8_t   ar_opts;
                     79:        u_int8_t   ar_op;
                     80:        char      *ar_path;
                     81:        char      *ar_tag;
                     82:
                     83:        SLIST_HEAD(, acl_user) ar_users;
                     84:        TAILQ_ENTRY(acl_rule)  ar_list;
                     85: };
                     86:
                     87:
                     88:
                     89:
                     90:
                     91: typedef struct {
                     92:        union {
                     93:                u_int64_t         num;
                     94:                char             *string;
                     95:                struct acl_rule  *rule;
                     96:                struct acl_user  *user_list;
                     97:                struct cvsd_addr *addr;
                     98:        } v;
                     99:
                    100:        int lineno;
                    101: } YYSTYPE;
                    102:
                    103:
                    104:
                    105:
                    106: int    lgetc    (FILE *);
1.2     ! jfb       107: int    lungetc  (int, FILE *);
1.1       jfb       108:
                    109:
                    110: int    yyerror  (const char *, ...);
                    111: int    yylex    (void);
                    112: int    yyparse  (void);
                    113: int    lookup   (const char *);
                    114: int    kw_cmp   (const void *, const void *);
                    115:
                    116: int         cvs_conf_setmacro (char *, char *);
                    117: const char* cvs_conf_getmacro (const char *);
                    118:
                    119: int    cvs_acl_addrule   (struct acl_rule *);
                    120: u_int  cvs_acl_matchuid  (struct acl_rule *, uid_t);
                    121: u_int  cvs_acl_matchtag  (const char *, const char *);
                    122: u_int  cvs_acl_matchpath (const char *, const char *);
                    123:
                    124:
1.2     ! jfb       125: /* parse buffer for easier macro expansion */
        !           126: static char  *conf_pbuf = NULL;
        !           127: static int    conf_pbind = 0;
        !           128:
        !           129:
        !           130:
1.1       jfb       131: static const char      *conf_file;
                    132: static FILE            *conf_fin;
                    133: static int              conf_lineno = 1;
                    134: static int              conf_errors = 0;
                    135:
                    136: static SIMPLEQ_HEAD(, conf_macro) conf_macros;
                    137:
                    138: /* ACL rules */
                    139: static TAILQ_HEAD(, acl_rule) acl_rules;
                    140: static u_int            acl_nrules = 0;
                    141: static u_int            acl_defact = CVS_ACL_DENY;
                    142:
                    143: %}
                    144:
                    145: %token LISTEN CVSROOT MINCHILD MAXCHILD REQSOCK
                    146: %token ALLOW DENY LOG QUICK ON TAG FROM
                    147: %token  ANY ADD CHECKOUT COMMIT DIFF HISTORY UPDATE
                    148: %token  <v.string>    STRING
                    149: %type   <v.num>       action number options operation
                    150: %type  <v.rule>      aclrule
                    151: %type  <v.addr>      address
                    152: %type   <v.userlist>
                    153: %type   <v.string>    pathspec tagspec
                    154: %%
                    155:
                    156: conf           : /* empty */
                    157:                | conf '\n'
                    158:                | conf cfline '\n'
                    159:                | conf error '\n'       { conf_errors++; }
                    160:                ;
                    161:
                    162: cfline         : macro_assign
                    163:                | directive
                    164:                | aclrule
                    165:                ;
                    166:
                    167: macro_assign   : STRING '=' STRING
                    168:                {
                    169:                        if (cvs_conf_setmacro($1, $3) < 0) {
                    170:                                free($1);
                    171:                                free($3);
                    172:                                YYERROR;
                    173:                        }
                    174:                }
                    175:                ;
                    176:
1.2     ! jfb       177: directive      : LISTEN address
        !           178:                {
        !           179:                        cvsd_set(CVSD_SET_ADDR, $2);
        !           180:                        free($2);
        !           181:                }
1.1       jfb       182:                | CVSROOT STRING
                    183:                {
                    184:                        cvsd_set(CVSD_SET_ROOT, $2);
                    185:                        free($2);
                    186:                }
                    187:                | MINCHILD number       { cvsd_set(CVSD_SET_CHMIN, $2); }
                    188:                | MAXCHILD number       { cvsd_set(CVSD_SET_CHMAX, $2); }
                    189:                | REQSOCK STRING
                    190:                {
                    191:                        cvsd_set(CVSD_SET_SOCK, $2);
                    192:                        free($2);
                    193:                }
                    194:                ;
                    195:
                    196: address                : STRING
                    197:                {
                    198:                        struct cvsd_addr *adp;
                    199:
                    200:                        adp = (struct cvsd_addr *)malloc(sizeof(*adp));
                    201:                        if (adp == NULL) {
                    202:                                YYERROR;
                    203:                        }
                    204:
                    205:                        $$ = adp;
                    206:                }
                    207:                ;
                    208:
                    209: aclrule                : action options operation pathspec tagspec userspec
                    210:                {
                    211:                        struct acl_rule *arp;
                    212:
                    213:                        arp = (struct acl_rule *)malloc(sizeof(*arp));
                    214:                        if (arp == NULL) {
                    215:                                free($4);
                    216:                                free($5);
                    217:                                YYERROR;
                    218:                        }
                    219:                        arp->ar_act = $1;
                    220:                        arp->ar_opts = $2;
                    221:                        arp->ar_op = $3;
                    222:                        SLIST_INIT(&arp->ar_users);
                    223:                        arp->ar_path = $4;
                    224:                        arp->ar_tag = $5;
                    225:
                    226:                        $$ = arp;
                    227:                }
                    228:                ;
                    229:
                    230: action         : ALLOW         { $$ = CVS_ACL_ALLOW; }
                    231:                | DENY          { $$ = CVS_ACL_DENY;  }
                    232:                ;
                    233:
                    234: options                : /* empty */   { $$ = 0; }
                    235:                | LOG           { $$ = CVS_ACL_LOGOPT; }
                    236:                | QUICK         { $$ = CVS_ACL_QUICKOPT; }
                    237:                | LOG QUICK     { $$ = CVS_ACL_LOGOPT | CVS_ACL_QUICKOPT; }
                    238:                ;
                    239:
                    240: operation      : ADD           { $$ = CVS_OP_ADD; }
                    241:                | ANY           { $$ = CVS_OP_ANY; }
                    242:                | COMMIT        { $$ = CVS_OP_COMMIT; }
                    243:                | TAG           { $$ = CVS_OP_TAG; }
                    244:                ;
                    245:
                    246: pathspec       : /* empty */   { $$ = NULL; }
                    247:                | ON STRING     { $$ = $2;   }
                    248:                ;
                    249:
                    250: tagspec                : /* empty */   { $$ = NULL; }
                    251:                | TAG STRING    { $$ = $2; }
                    252:                ;
                    253:
                    254: userspec       : /* empty */
                    255:                | FROM userlist
                    256:                ;
                    257:
                    258: userlist       : user
                    259:                | userlist ',' user
                    260:                ;
                    261:
                    262: user           : STRING
                    263:                {
                    264:                        uid_t uid;
                    265:                        char *ep;
                    266:                        struct passwd *pw;
                    267:                        struct acl_user *aup;
                    268:
                    269:                        uid = (uid_t)strtol($1, &ep, 10);
                    270:                        if (*ep != '\0')
                    271:                                pw = getpwnam($1);
                    272:                        else
                    273:                                pw = getpwuid(uid);
                    274:                        if (pw == NULL) {
                    275:                                yyerror("invalid username or ID `%s'", $1);
                    276:                                YYERROR;
                    277:                        }
                    278:
                    279:                        aup = (struct acl_user *)malloc(sizeof(*aup));
                    280:                        if (aup == NULL) {
                    281:                                yyerror("failed to allocate ACL user data");
                    282:                                YYERROR;
                    283:                        }
                    284:                        aup->au_uid = pw->pw_uid;
                    285:                }
                    286:                ;
                    287:
                    288: number         : STRING
                    289:                {
                    290:                        char *ep;
                    291:                        long res;
                    292:                        res = strtol($1, &ep, 0);
                    293:                        if ((res == LONG_MIN) || (res == LONG_MAX)) {
                    294:                                yyerror("%sflow while converting number `%s'",
                    295:                                    res == LONG_MIN ? "under" : "over", $1);
                    296:                                free($1);
                    297:                                YYERROR;
                    298:                        }
                    299:                        else if (*ep != '\0') {
                    300:                                yyerror("invalid number `%s'", $1);
                    301:                                free($1);
                    302:                                YYERROR;
                    303:                        }
                    304:
                    305:                        $$ = (u_int64_t)res;
                    306:                        free($1);
                    307:                }
                    308:                ;
                    309:
                    310: %%
                    311:
                    312:
                    313: struct conf_kw {
                    314:        char  *kw_str;
                    315:        u_int  kw_id;
                    316: };
                    317:
                    318:
                    319:
                    320: static const struct conf_kw keywords[] = {
                    321:        { "add",     ADD     },
                    322:        { "allow",   ALLOW   },
                    323:        { "any",     ANY     },
                    324:        { "commit",  COMMIT  },
                    325:        { "cvsroot", CVSROOT },
                    326:        { "deny",    DENY    },
                    327:        { "from",    FROM    },
                    328:        { "listen",  LISTEN  },
                    329:        { "log",     LOG     },
                    330:        { "on",      ON      },
                    331:        { "quick",   QUICK   },
                    332:        { "reqsock", REQSOCK },
                    333:        { "tag",     TAG     },
                    334:
                    335: };
                    336:
                    337: int
                    338: kw_cmp(const void *k, const void *e)
                    339: {
                    340:        return (strcmp(k, ((const struct conf_kw *)e)->kw_str));
                    341: }
                    342:
                    343:
                    344: int
                    345: lookup(const char *tstr)
                    346: {
                    347:        int type;
                    348:        const struct conf_kw *kwp;
                    349:
                    350:        kwp = bsearch(tstr, keywords, sizeof(keywords)/sizeof(keywords[0]),
                    351:            sizeof(keywords[0]), kw_cmp);
                    352:        if (kwp != NULL)
                    353:                type = kwp->kw_id;
                    354:        else
                    355:                type = STRING;
                    356:        return (type);
                    357: }
                    358:
                    359:
                    360:
                    361: int
                    362: lgetc(FILE *f)
                    363: {
                    364:        int c;
                    365:
1.2     ! jfb       366:        /* check if we've got something in the parse buffer first */
        !           367:        if (conf_pbuf != NULL) {
        !           368:                c = conf_pbuf[conf_pbind++];
        !           369:                if (c != '\0')
        !           370:                        return (c);
        !           371:
        !           372:                free(conf_pbuf);
        !           373:                conf_pbuf = NULL;
        !           374:                conf_pbind = 0;
        !           375:        }
        !           376:
1.1       jfb       377:        c = getc(f);
                    378:        if ((c == '\t') || (c == ' ')) {
                    379:                do {
                    380:                        c = getc(f);
                    381:                } while ((c == ' ') || (c == '\t'));
1.2     ! jfb       382:                lungetc(c, f);
1.1       jfb       383:                c = ' ';
                    384:        }
                    385:        else if (c == '\\')
                    386:                c = getc(f);
                    387:
                    388:        return (c);
                    389: }
                    390:
                    391:
                    392: int
1.2     ! jfb       393: lungetc(int c, FILE *f)
        !           394: {
        !           395:        if ((conf_pbuf != NULL) && (conf_pbind > 0)) {
        !           396:                conf_pbind--;
        !           397:                return (0);
        !           398:        }
        !           399:
        !           400:        return ungetc(c, f);
        !           401:
        !           402:
        !           403: }
        !           404:
        !           405:
        !           406:
        !           407:
        !           408:
        !           409: int
1.1       jfb       410: yylex(void)
                    411: {
                    412:        int c;
                    413:        char buf[1024], *bp, *ep;
1.2     ! jfb       414:        const char *mval;
1.1       jfb       415:
1.2     ! jfb       416: lex_start:
1.1       jfb       417:        bp = buf;
                    418:        ep = buf + sizeof(buf) - 1;
                    419:
                    420:        yylval.lineno = conf_lineno;
                    421:
                    422:        /* skip whitespace */
                    423:        while ((c = lgetc(conf_fin)) == ' ')
                    424:                ;
                    425:
                    426:        if (c == '#') {
                    427:                do {
                    428:                        c = lgetc(conf_fin);
                    429:                } while ((c != '\n') && (c != EOF));
                    430:        }
1.2     ! jfb       431:
        !           432:        if (c == EOF)
1.1       jfb       433:                c = 0;
                    434:        else if (c == '\n')
1.2     ! jfb       435:                yylval.lineno = conf_lineno++;
        !           436:        else if (c == '$') {
        !           437:                c = lgetc(conf_fin);
1.1       jfb       438:                do {
1.2     ! jfb       439:                        *bp++ = (char)c;
        !           440:                        if (bp == ep) {
        !           441:                                yyerror("macro name too long");
        !           442:                                return (-1);
        !           443:                        }
        !           444:                        c = lgetc(conf_fin);
        !           445:                } while (isalnum(c) || c == '_');
        !           446:                lungetc(c, conf_fin);
        !           447:                *bp = '\0';
        !           448:
        !           449:                mval = cvs_conf_getmacro(buf);
        !           450:                if (mval == NULL) {
        !           451:                        yyerror("undefined macro `%s'", buf);
        !           452:                        return (-1);
        !           453:                }
        !           454:
        !           455:                conf_pbuf = strdup(mval);
        !           456:                conf_pbind = 0;
        !           457:                goto lex_start;
        !           458:        }
        !           459:        else if ((c == '=') || (c == ','))
        !           460:                ; /* nothing */
        !           461:        else {
        !           462:                do {
        !           463:                        *bp++ = (char)c;
1.1       jfb       464:                        if (bp == ep) {
                    465:                                yyerror("string too long");
                    466:                                return (-1);
                    467:                        }
                    468:
                    469:                        c = lgetc(conf_fin);
                    470:                } while ((c != EOF) && (c != ' ') && (c != '\n'));
1.2     ! jfb       471:                lungetc(c, conf_fin);
1.1       jfb       472:                *bp = '\0';
                    473:                c = lookup(buf);
                    474:                if (c == STRING) {
                    475:                        yylval.v.string = strdup(buf);
                    476:                        if (yylval.v.string == NULL) {
                    477:                                cvs_log(LP_ERRNO,
                    478:                                    "failed to copy token string");
                    479:                                return (-1);
                    480:                        }
                    481:                }
                    482:        }
                    483:
                    484:        return (c);
                    485: }
                    486:
                    487:
                    488:
                    489: int
                    490: yyerror(const char *fmt, ...)
                    491: {
                    492:        char *nfmt;
                    493:        va_list vap;
                    494:
                    495:        va_start(vap, fmt);
                    496:
                    497:        if (asprintf(&nfmt, "%s:%d: %s", conf_file, yylval.lineno, fmt) == -1) {
                    498:                cvs_log(LP_ERRNO, "failed to allocate message buffer");
                    499:                return (-1);
                    500:        }
                    501:        cvs_vlog(LP_ERR, nfmt, vap);
                    502:
                    503:        free(nfmt);
                    504:        va_end(vap);
                    505:        return (0);
                    506:
                    507: }
                    508:
                    509:
                    510: /*
                    511:  * cvs_conf_setmacro()
                    512:  *
                    513:  * Add an entry in the macro list for the macro whose name is <macro> and
                    514:  * whose value is <val>.
                    515:  * Returns 0 on success, or -1 on failure.
                    516:  */
                    517:
                    518: int
                    519: cvs_conf_setmacro(char *macro, char *val)
                    520: {
                    521:        struct conf_macro *cmp;
                    522:
                    523:        cmp = (struct conf_macro *)malloc(sizeof(*cmp));
                    524:        if (cmp == NULL) {
                    525:                cvs_log(LP_ERRNO, "failed to allocate macro");
                    526:                return (-1);
                    527:        }
                    528:
                    529:        /* these strings were already dup'ed by the lexer */
                    530:        cmp->cm_name = macro;
                    531:        cmp->cm_val = val;
                    532:
                    533:        SIMPLEQ_INSERT_TAIL(&conf_macros, cmp, cm_list);
                    534:
                    535:        return (0);
                    536: }
                    537:
                    538:
                    539: /*
                    540:  * cvs_conf_getmacro()
                    541:  *
                    542:  * Get a macro <macro>'s associated value.  Returns the value string on
                    543:  * success, or NULL if no such macro exists.
                    544:  */
                    545:
                    546: const char*
                    547: cvs_conf_getmacro(const char *macro)
                    548: {
                    549:        struct conf_macro *cmp;
                    550:
                    551:        SIMPLEQ_FOREACH(cmp, &conf_macros, cm_list)
                    552:                if (strcmp(cmp->cm_name, macro) == 0)
                    553:                        return (cmp->cm_val);
                    554:
                    555:        return (NULL);
                    556: }
                    557:
                    558:
                    559: /*
                    560:  * cvs_conf_read()
                    561:  *
                    562:  * Parse the contents of the configuration file <conf>.
                    563:  */
                    564:
                    565: int
                    566: cvs_conf_read(const char *conf)
                    567: {
                    568:        struct conf_macro *cmp;
                    569:
                    570:        SIMPLEQ_INIT(&conf_macros);
                    571:        TAILQ_INIT(&acl_rules);
                    572:        acl_nrules = 0;
                    573:
                    574:        conf_file = conf;
                    575:        conf_fin = fopen(conf, "r");
                    576:        if (conf_fin == NULL) {
                    577:                cvs_log(LP_ERRNO, "failed to open configuration `%s'", conf);
                    578:                return (-1);
                    579:        }
                    580:
                    581:        if (yyparse() != 0)
                    582:                conf_lineno = -1;
                    583:
                    584:        (void)fclose(conf_fin);
                    585:
                    586:        /* we can get rid of macros now */
                    587:        while ((cmp = SIMPLEQ_FIRST(&conf_macros)) != NULL) {
                    588:                SIMPLEQ_REMOVE_HEAD(&conf_macros, cm_list);
                    589:                free(cmp->cm_name);
                    590:                free(cmp->cm_val);
                    591:                free(cmp);
                    592:        }
                    593:
                    594:        cvs_log(LP_INFO, "config %s parsed successfully", conf);
                    595:
                    596:        return (conf_lineno);
                    597: }
                    598:
                    599:
                    600: /*
                    601:  * cvs_acl_addrule()
                    602:  *
                    603:  * Add a rule to the currently loaded ACL rules.
                    604:  */
                    605:
                    606: int
                    607: cvs_acl_addrule(struct acl_rule *rule)
                    608: {
                    609:        if (acl_nrules == CVS_ACL_MAXRULES) {
                    610:                cvs_log(LP_ERR, "failed to add ACL rule: Ruleset full");
                    611:                return (-1);
                    612:        }
                    613:
                    614:        TAILQ_INSERT_TAIL(&acl_rules, rule, ar_list);
                    615:        return (0);
                    616: }
                    617:
                    618:
                    619: /*
                    620:  * cvs_acl_eval()
                    621:  *
                    622:  * Evaluate a thingamajimmie against the currently loaded ACL ruleset.
                    623:  * Returns CVS_ACL_ALLOW if the operation is permitted, CVS_ACL_DENY otherwise.
                    624:  */
                    625:
                    626: u_int
                    627: cvs_acl_eval(struct cvs_op *op)
                    628: {
                    629:        u_int res;
1.2     ! jfb       630:        CVSFILE *cf;
        !           631:        struct acl_rule *rule;
1.1       jfb       632:
                    633:        /* deny by default */
                    634:        res = acl_defact;
                    635:
1.2     ! jfb       636:        TAILQ_FOREACH(rule, &acl_rules, ar_list) {
        !           637:                if (((op->co_op != CVS_OP_ANY) && (op->co_op != rule->ar_op)) ||
        !           638:                    !cvs_acl_matchuid(rule, op->co_uid) ||
        !           639:                    !cvs_acl_matchtag(op->co_tag, rule->ar_tag))
1.1       jfb       640:                        continue;
                    641:
1.2     ! jfb       642:                /* see if one of the files has a matching path */
        !           643:                TAILQ_FOREACH(cf, &(op->co_files), cf_list)
        !           644:                        if (!cvs_acl_matchpath(cf->cf_path, rule->ar_path))
        !           645:                                continue;
        !           646:
        !           647:                res = rule->ar_act;
        !           648:
        !           649:                if (rule->ar_opts & CVS_ACL_LOGOPT)
        !           650:                        cvs_log(LP_WARN, "act=%u, tag=%s, uid=%u",
        !           651:                            op->co_op, op->co_tag, op->co_uid);
        !           652:                if (rule->ar_opts & CVS_ACL_QUICKOPT)
1.1       jfb       653:                        break;
                    654:        }
                    655:
                    656:        return (res);
                    657: }
                    658:
                    659:
                    660: /*
                    661:  * cvs_acl_matchuid()
                    662:  *
                    663:  * Check if an ACL rule has a UID matching <uid>.  If no user is specified
                    664:  * for a given rule, any UID will match.
                    665:  * Returns 1 if this is the case, 0 otherwise.
                    666:  */
                    667:
                    668: u_int
                    669: cvs_acl_matchuid(struct acl_rule *rule, uid_t uid)
                    670: {
                    671:        struct acl_user *aup;
                    672:
                    673:        if (SLIST_EMPTY(&(rule->ar_users)))
                    674:                return (1);
                    675:
                    676:        SLIST_FOREACH(aup, &(rule->ar_users), au_list)
                    677:                if (aup->au_uid == uid)
                    678:                        return (1);
                    679:        return (0);
                    680: }
                    681:
                    682:
                    683: /*
                    684:  * cvs_acl_matchtag()
                    685:  *
                    686:  * Returns 1 if this is the case, 0 otherwise.
                    687:  */
                    688:
                    689: u_int
                    690: cvs_acl_matchtag(const char *tag1, const char *tag2)
                    691: {
                    692:        if ((tag1 == NULL) && (tag2 == NULL))   /* HEAD */
                    693:                return (1);
                    694:
                    695:        if ((tag1 != NULL) && (tag2 != NULL) &&
                    696:            (strcmp(tag1, tag2) == 0))
                    697:                return (1);
                    698:
                    699:        return (0);
                    700: }
                    701:
                    702:
                    703: /*
                    704:  * cvs_acl_matchpath()
                    705:  *
                    706:  * Check if the path <op_path> is a subpath of <acl_path>.
                    707:  * Returns 1 if this is the case, 0 otherwise.
                    708:  */
                    709:
                    710: u_int
                    711: cvs_acl_matchpath(const char *op_path, const char *acl_path)
                    712: {
                    713:        size_t len;
                    714:        char rop_path[MAXPATHLEN];
                    715:
                    716:        /* if the ACL path is NULL, apply on all paths */
                    717:        if (acl_path == NULL)
                    718:                return (1);
                    719:
                    720:        if (realpath(op_path, rop_path) == NULL) {
                    721:                cvs_log(LP_ERRNO, "failed to convert `%s' to a real path",
                    722:                    op_path);
                    723:                return (0);
                    724:        }
                    725:
                    726:        len = strlen(rop_path);
                    727:
                    728:        if (strncmp(rop_path, acl_path, len) == 0)
                    729:                return (1);
                    730:
                    731:        return (0);
                    732: }