[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.5

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
1.3       jfb       146: %token ALLOW DENY LOG QUICK ON TAG FROM USER GROUP
1.1       jfb       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:                }
1.3       jfb       187:                | USER STRING
                    188:                {
                    189:                        cvsd_set(CVSD_SET_USER, $2);
                    190:                        free($2);
                    191:                }
                    192:                | GROUP STRING
                    193:                {
                    194:                        cvsd_set(CVSD_SET_GROUP, $2);
                    195:                        free($2);
                    196:                }
1.1       jfb       197:                | MINCHILD number       { cvsd_set(CVSD_SET_CHMIN, $2); }
                    198:                | MAXCHILD number       { cvsd_set(CVSD_SET_CHMAX, $2); }
                    199:                | REQSOCK STRING
                    200:                {
                    201:                        cvsd_set(CVSD_SET_SOCK, $2);
                    202:                        free($2);
                    203:                }
                    204:                ;
                    205:
                    206: address                : STRING
                    207:                {
                    208:                        struct cvsd_addr *adp;
                    209:
                    210:                        adp = (struct cvsd_addr *)malloc(sizeof(*adp));
                    211:                        if (adp == NULL) {
                    212:                                YYERROR;
                    213:                        }
                    214:
                    215:                        $$ = adp;
                    216:                }
                    217:                ;
                    218:
                    219: aclrule                : action options operation pathspec tagspec userspec
                    220:                {
                    221:                        struct acl_rule *arp;
                    222:
                    223:                        arp = (struct acl_rule *)malloc(sizeof(*arp));
                    224:                        if (arp == NULL) {
                    225:                                free($4);
                    226:                                free($5);
                    227:                                YYERROR;
                    228:                        }
                    229:                        arp->ar_act = $1;
                    230:                        arp->ar_opts = $2;
                    231:                        arp->ar_op = $3;
                    232:                        SLIST_INIT(&arp->ar_users);
                    233:                        arp->ar_path = $4;
                    234:                        arp->ar_tag = $5;
                    235:
                    236:                        $$ = arp;
                    237:                }
                    238:                ;
                    239:
                    240: action         : ALLOW         { $$ = CVS_ACL_ALLOW; }
                    241:                | DENY          { $$ = CVS_ACL_DENY;  }
                    242:                ;
                    243:
                    244: options                : /* empty */   { $$ = 0; }
                    245:                | LOG           { $$ = CVS_ACL_LOGOPT; }
                    246:                | QUICK         { $$ = CVS_ACL_QUICKOPT; }
                    247:                | LOG QUICK     { $$ = CVS_ACL_LOGOPT | CVS_ACL_QUICKOPT; }
                    248:                ;
                    249:
                    250: operation      : ADD           { $$ = CVS_OP_ADD; }
                    251:                | ANY           { $$ = CVS_OP_ANY; }
                    252:                | COMMIT        { $$ = CVS_OP_COMMIT; }
                    253:                | TAG           { $$ = CVS_OP_TAG; }
                    254:                ;
                    255:
                    256: pathspec       : /* empty */   { $$ = NULL; }
                    257:                | ON STRING     { $$ = $2;   }
                    258:                ;
                    259:
                    260: tagspec                : /* empty */   { $$ = NULL; }
                    261:                | TAG STRING    { $$ = $2; }
                    262:                ;
                    263:
                    264: userspec       : /* empty */
                    265:                | FROM userlist
                    266:                ;
                    267:
                    268: userlist       : user
                    269:                | userlist ',' user
                    270:                ;
                    271:
                    272: user           : STRING
                    273:                {
                    274:                        uid_t uid;
                    275:                        char *ep;
                    276:                        struct passwd *pw;
                    277:                        struct acl_user *aup;
                    278:
                    279:                        uid = (uid_t)strtol($1, &ep, 10);
                    280:                        if (*ep != '\0')
                    281:                                pw = getpwnam($1);
                    282:                        else
                    283:                                pw = getpwuid(uid);
                    284:                        if (pw == NULL) {
                    285:                                yyerror("invalid username or ID `%s'", $1);
                    286:                                YYERROR;
                    287:                        }
                    288:
                    289:                        aup = (struct acl_user *)malloc(sizeof(*aup));
                    290:                        if (aup == NULL) {
                    291:                                yyerror("failed to allocate ACL user data");
                    292:                                YYERROR;
                    293:                        }
                    294:                        aup->au_uid = pw->pw_uid;
                    295:                }
                    296:                ;
                    297:
                    298: number         : STRING
                    299:                {
                    300:                        char *ep;
                    301:                        long res;
                    302:                        res = strtol($1, &ep, 0);
                    303:                        if ((res == LONG_MIN) || (res == LONG_MAX)) {
                    304:                                yyerror("%sflow while converting number `%s'",
                    305:                                    res == LONG_MIN ? "under" : "over", $1);
                    306:                                free($1);
                    307:                                YYERROR;
                    308:                        }
                    309:                        else if (*ep != '\0') {
                    310:                                yyerror("invalid number `%s'", $1);
                    311:                                free($1);
                    312:                                YYERROR;
                    313:                        }
                    314:
                    315:                        $$ = (u_int64_t)res;
                    316:                        free($1);
                    317:                }
                    318:                ;
                    319:
                    320: %%
                    321:
                    322:
                    323: struct conf_kw {
                    324:        char  *kw_str;
                    325:        u_int  kw_id;
                    326: };
                    327:
                    328:
                    329:
                    330: static const struct conf_kw keywords[] = {
                    331:        { "add",     ADD     },
                    332:        { "allow",   ALLOW   },
                    333:        { "any",     ANY     },
                    334:        { "commit",  COMMIT  },
                    335:        { "cvsroot", CVSROOT },
                    336:        { "deny",    DENY    },
                    337:        { "from",    FROM    },
1.3       jfb       338:        { "group",   GROUP   },
1.1       jfb       339:        { "listen",  LISTEN  },
                    340:        { "log",     LOG     },
                    341:        { "on",      ON      },
                    342:        { "quick",   QUICK   },
                    343:        { "reqsock", REQSOCK },
                    344:        { "tag",     TAG     },
1.3       jfb       345:        { "user",    USER    },
1.1       jfb       346:
                    347: };
                    348:
                    349: int
                    350: kw_cmp(const void *k, const void *e)
                    351: {
                    352:        return (strcmp(k, ((const struct conf_kw *)e)->kw_str));
                    353: }
                    354:
                    355:
                    356: int
                    357: lookup(const char *tstr)
                    358: {
                    359:        int type;
                    360:        const struct conf_kw *kwp;
                    361:
                    362:        kwp = bsearch(tstr, keywords, sizeof(keywords)/sizeof(keywords[0]),
                    363:            sizeof(keywords[0]), kw_cmp);
                    364:        if (kwp != NULL)
                    365:                type = kwp->kw_id;
                    366:        else
                    367:                type = STRING;
                    368:        return (type);
                    369: }
                    370:
                    371:
                    372:
                    373: int
                    374: lgetc(FILE *f)
                    375: {
                    376:        int c;
                    377:
1.2       jfb       378:        /* check if we've got something in the parse buffer first */
                    379:        if (conf_pbuf != NULL) {
                    380:                c = conf_pbuf[conf_pbind++];
                    381:                if (c != '\0')
                    382:                        return (c);
                    383:
                    384:                free(conf_pbuf);
                    385:                conf_pbuf = NULL;
                    386:                conf_pbind = 0;
                    387:        }
                    388:
1.1       jfb       389:        c = getc(f);
                    390:        if ((c == '\t') || (c == ' ')) {
                    391:                do {
                    392:                        c = getc(f);
                    393:                } while ((c == ' ') || (c == '\t'));
1.2       jfb       394:                lungetc(c, f);
1.1       jfb       395:                c = ' ';
                    396:        }
                    397:        else if (c == '\\')
                    398:                c = getc(f);
                    399:
                    400:        return (c);
                    401: }
                    402:
                    403:
                    404: int
1.2       jfb       405: lungetc(int c, FILE *f)
                    406: {
                    407:        if ((conf_pbuf != NULL) && (conf_pbind > 0)) {
                    408:                conf_pbind--;
                    409:                return (0);
                    410:        }
                    411:
                    412:        return ungetc(c, f);
                    413:
                    414:
                    415: }
                    416:
                    417:
                    418:
                    419:
                    420:
                    421: int
1.1       jfb       422: yylex(void)
                    423: {
                    424:        int c;
                    425:        char buf[1024], *bp, *ep;
1.2       jfb       426:        const char *mval;
1.1       jfb       427:
1.2       jfb       428: lex_start:
1.1       jfb       429:        bp = buf;
                    430:        ep = buf + sizeof(buf) - 1;
                    431:
                    432:        yylval.lineno = conf_lineno;
                    433:
                    434:        /* skip whitespace */
                    435:        while ((c = lgetc(conf_fin)) == ' ')
                    436:                ;
                    437:
                    438:        if (c == '#') {
                    439:                do {
                    440:                        c = lgetc(conf_fin);
                    441:                } while ((c != '\n') && (c != EOF));
                    442:        }
1.2       jfb       443:
                    444:        if (c == EOF)
1.1       jfb       445:                c = 0;
                    446:        else if (c == '\n')
1.2       jfb       447:                yylval.lineno = conf_lineno++;
                    448:        else if (c == '$') {
                    449:                c = lgetc(conf_fin);
1.1       jfb       450:                do {
1.2       jfb       451:                        *bp++ = (char)c;
                    452:                        if (bp == ep) {
                    453:                                yyerror("macro name too long");
                    454:                                return (-1);
                    455:                        }
                    456:                        c = lgetc(conf_fin);
                    457:                } while (isalnum(c) || c == '_');
                    458:                lungetc(c, conf_fin);
                    459:                *bp = '\0';
                    460:
                    461:                mval = cvs_conf_getmacro(buf);
                    462:                if (mval == NULL) {
                    463:                        yyerror("undefined macro `%s'", buf);
                    464:                        return (-1);
                    465:                }
                    466:
                    467:                conf_pbuf = strdup(mval);
                    468:                conf_pbind = 0;
                    469:                goto lex_start;
                    470:        }
                    471:        else if ((c == '=') || (c == ','))
                    472:                ; /* nothing */
                    473:        else {
                    474:                do {
                    475:                        *bp++ = (char)c;
1.1       jfb       476:                        if (bp == ep) {
                    477:                                yyerror("string too long");
                    478:                                return (-1);
                    479:                        }
                    480:
                    481:                        c = lgetc(conf_fin);
                    482:                } while ((c != EOF) && (c != ' ') && (c != '\n'));
1.2       jfb       483:                lungetc(c, conf_fin);
1.1       jfb       484:                *bp = '\0';
                    485:                c = lookup(buf);
                    486:                if (c == STRING) {
                    487:                        yylval.v.string = strdup(buf);
                    488:                        if (yylval.v.string == NULL) {
                    489:                                cvs_log(LP_ERRNO,
                    490:                                    "failed to copy token string");
                    491:                                return (-1);
                    492:                        }
                    493:                }
                    494:        }
                    495:
                    496:        return (c);
                    497: }
                    498:
                    499:
                    500:
                    501: int
                    502: yyerror(const char *fmt, ...)
                    503: {
                    504:        char *nfmt;
                    505:        va_list vap;
                    506:
                    507:        if (asprintf(&nfmt, "%s:%d: %s", conf_file, yylval.lineno, fmt) == -1) {
                    508:                cvs_log(LP_ERRNO, "failed to allocate message buffer");
                    509:                return (-1);
                    510:        }
1.5     ! pat       511:
        !           512:        va_start(vap, fmt);
1.1       jfb       513:        cvs_vlog(LP_ERR, nfmt, vap);
1.5     ! pat       514:        va_end(vap);
1.1       jfb       515:
                    516:        free(nfmt);
                    517:        return (0);
                    518:
                    519: }
                    520:
                    521:
                    522: /*
                    523:  * cvs_conf_setmacro()
                    524:  *
                    525:  * Add an entry in the macro list for the macro whose name is <macro> and
                    526:  * whose value is <val>.
                    527:  * Returns 0 on success, or -1 on failure.
                    528:  */
                    529:
                    530: int
                    531: cvs_conf_setmacro(char *macro, char *val)
                    532: {
                    533:        struct conf_macro *cmp;
                    534:
                    535:        cmp = (struct conf_macro *)malloc(sizeof(*cmp));
                    536:        if (cmp == NULL) {
                    537:                cvs_log(LP_ERRNO, "failed to allocate macro");
                    538:                return (-1);
                    539:        }
                    540:
                    541:        /* these strings were already dup'ed by the lexer */
                    542:        cmp->cm_name = macro;
                    543:        cmp->cm_val = val;
                    544:
                    545:        SIMPLEQ_INSERT_TAIL(&conf_macros, cmp, cm_list);
                    546:
                    547:        return (0);
                    548: }
                    549:
                    550:
                    551: /*
                    552:  * cvs_conf_getmacro()
                    553:  *
                    554:  * Get a macro <macro>'s associated value.  Returns the value string on
                    555:  * success, or NULL if no such macro exists.
                    556:  */
                    557:
                    558: const char*
                    559: cvs_conf_getmacro(const char *macro)
                    560: {
                    561:        struct conf_macro *cmp;
                    562:
                    563:        SIMPLEQ_FOREACH(cmp, &conf_macros, cm_list)
                    564:                if (strcmp(cmp->cm_name, macro) == 0)
                    565:                        return (cmp->cm_val);
                    566:
                    567:        return (NULL);
                    568: }
                    569:
                    570:
                    571: /*
                    572:  * cvs_conf_read()
                    573:  *
                    574:  * Parse the contents of the configuration file <conf>.
                    575:  */
                    576:
                    577: int
                    578: cvs_conf_read(const char *conf)
                    579: {
                    580:        struct conf_macro *cmp;
                    581:
                    582:        SIMPLEQ_INIT(&conf_macros);
                    583:        TAILQ_INIT(&acl_rules);
                    584:        acl_nrules = 0;
                    585:
1.3       jfb       586:        cvs_log(LP_INFO, "using configuration file `%s'", conf);
1.1       jfb       587:        conf_file = conf;
                    588:        conf_fin = fopen(conf, "r");
                    589:        if (conf_fin == NULL) {
                    590:                cvs_log(LP_ERRNO, "failed to open configuration `%s'", conf);
                    591:                return (-1);
                    592:        }
                    593:
                    594:        if (yyparse() != 0)
                    595:                conf_lineno = -1;
                    596:
                    597:        (void)fclose(conf_fin);
                    598:
                    599:        /* we can get rid of macros now */
                    600:        while ((cmp = SIMPLEQ_FIRST(&conf_macros)) != NULL) {
                    601:                SIMPLEQ_REMOVE_HEAD(&conf_macros, cm_list);
                    602:                free(cmp->cm_name);
                    603:                free(cmp->cm_val);
                    604:                free(cmp);
                    605:        }
                    606:
                    607:        cvs_log(LP_INFO, "config %s parsed successfully", conf);
                    608:
                    609:        return (conf_lineno);
                    610: }
                    611:
                    612:
                    613: /*
                    614:  * cvs_acl_addrule()
                    615:  *
                    616:  * Add a rule to the currently loaded ACL rules.
                    617:  */
                    618:
                    619: int
                    620: cvs_acl_addrule(struct acl_rule *rule)
                    621: {
                    622:        if (acl_nrules == CVS_ACL_MAXRULES) {
                    623:                cvs_log(LP_ERR, "failed to add ACL rule: Ruleset full");
                    624:                return (-1);
                    625:        }
                    626:
                    627:        TAILQ_INSERT_TAIL(&acl_rules, rule, ar_list);
                    628:        return (0);
                    629: }
                    630:
                    631:
                    632: /*
                    633:  * cvs_acl_eval()
                    634:  *
                    635:  * Evaluate a thingamajimmie against the currently loaded ACL ruleset.
                    636:  * Returns CVS_ACL_ALLOW if the operation is permitted, CVS_ACL_DENY otherwise.
                    637:  */
                    638:
                    639: u_int
                    640: cvs_acl_eval(struct cvs_op *op)
                    641: {
                    642:        u_int res;
1.4       jfb       643:        char fpath[MAXPATHLEN];
1.2       jfb       644:        CVSFILE *cf;
                    645:        struct acl_rule *rule;
1.1       jfb       646:
                    647:        /* deny by default */
                    648:        res = acl_defact;
                    649:
1.2       jfb       650:        TAILQ_FOREACH(rule, &acl_rules, ar_list) {
                    651:                if (((op->co_op != CVS_OP_ANY) && (op->co_op != rule->ar_op)) ||
                    652:                    !cvs_acl_matchuid(rule, op->co_uid) ||
                    653:                    !cvs_acl_matchtag(op->co_tag, rule->ar_tag))
1.1       jfb       654:                        continue;
                    655:
1.2       jfb       656:                /* see if one of the files has a matching path */
1.4       jfb       657:                TAILQ_FOREACH(cf, &(op->co_files), cf_list) {
                    658:                        /* XXX borked */
                    659:                        if (!cvs_acl_matchpath(fpath, rule->ar_path))
1.2       jfb       660:                                continue;
1.4       jfb       661:                }
1.2       jfb       662:
                    663:                res = rule->ar_act;
                    664:
                    665:                if (rule->ar_opts & CVS_ACL_LOGOPT)
                    666:                        cvs_log(LP_WARN, "act=%u, tag=%s, uid=%u",
                    667:                            op->co_op, op->co_tag, op->co_uid);
                    668:                if (rule->ar_opts & CVS_ACL_QUICKOPT)
1.1       jfb       669:                        break;
                    670:        }
                    671:
                    672:        return (res);
                    673: }
                    674:
                    675:
                    676: /*
                    677:  * cvs_acl_matchuid()
                    678:  *
                    679:  * Check if an ACL rule has a UID matching <uid>.  If no user is specified
                    680:  * for a given rule, any UID will match.
                    681:  * Returns 1 if this is the case, 0 otherwise.
                    682:  */
                    683:
                    684: u_int
                    685: cvs_acl_matchuid(struct acl_rule *rule, uid_t uid)
                    686: {
                    687:        struct acl_user *aup;
                    688:
                    689:        if (SLIST_EMPTY(&(rule->ar_users)))
                    690:                return (1);
                    691:
                    692:        SLIST_FOREACH(aup, &(rule->ar_users), au_list)
                    693:                if (aup->au_uid == uid)
                    694:                        return (1);
                    695:        return (0);
                    696: }
                    697:
                    698:
                    699: /*
                    700:  * cvs_acl_matchtag()
                    701:  *
                    702:  * Returns 1 if this is the case, 0 otherwise.
                    703:  */
                    704:
                    705: u_int
                    706: cvs_acl_matchtag(const char *tag1, const char *tag2)
                    707: {
                    708:        if ((tag1 == NULL) && (tag2 == NULL))   /* HEAD */
                    709:                return (1);
                    710:
                    711:        if ((tag1 != NULL) && (tag2 != NULL) &&
                    712:            (strcmp(tag1, tag2) == 0))
                    713:                return (1);
                    714:
                    715:        return (0);
                    716: }
                    717:
                    718:
                    719: /*
                    720:  * cvs_acl_matchpath()
                    721:  *
                    722:  * Check if the path <op_path> is a subpath of <acl_path>.
                    723:  * Returns 1 if this is the case, 0 otherwise.
                    724:  */
                    725:
                    726: u_int
                    727: cvs_acl_matchpath(const char *op_path, const char *acl_path)
                    728: {
                    729:        size_t len;
                    730:        char rop_path[MAXPATHLEN];
                    731:
                    732:        /* if the ACL path is NULL, apply on all paths */
                    733:        if (acl_path == NULL)
                    734:                return (1);
                    735:
                    736:        if (realpath(op_path, rop_path) == NULL) {
                    737:                cvs_log(LP_ERRNO, "failed to convert `%s' to a real path",
                    738:                    op_path);
                    739:                return (0);
                    740:        }
                    741:
                    742:        len = strlen(rop_path);
                    743:
                    744:        if (strncmp(rop_path, acl_path, len) == 0)
                    745:                return (1);
                    746:
                    747:        return (0);
                    748: }