Annotation of embedaddon/sudo/plugins/sudoers/match.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 1996, 1998-2005, 2007-2011
                      3:  *     Todd C. Miller <Todd.Miller@courtesan.com>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     17:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     18:  *
                     19:  * Sponsored in part by the Defense Advanced Research Projects
                     20:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
                     21:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
                     22:  */
                     23: 
                     24: #include <config.h>
                     25: 
                     26: #include <sys/types.h>
                     27: #include <sys/param.h>
                     28: #include <sys/stat.h>
                     29: #include <stdio.h>
                     30: #ifdef STDC_HEADERS
                     31: # include <stdlib.h>
                     32: # include <stddef.h>
                     33: #else
                     34: # ifdef HAVE_STDLIB_H
                     35: #  include <stdlib.h>
                     36: # endif
                     37: #endif /* STDC_HEADERS */
                     38: #ifdef HAVE_STRING_H
                     39: # include <string.h>
                     40: #endif /* HAVE_STRING_H */
                     41: #ifdef HAVE_STRINGS_H
                     42: # include <strings.h>
                     43: #endif /* HAVE_STRINGS_H */
                     44: #ifdef HAVE_UNISTD_H
                     45: # include <unistd.h>
                     46: #endif /* HAVE_UNISTD_H */
                     47: #ifdef HAVE_FNMATCH
                     48: # include <fnmatch.h>
                     49: #endif /* HAVE_FNMATCH */
                     50: #ifdef HAVE_EXTENDED_GLOB
                     51: # include <glob.h>
                     52: #endif /* HAVE_EXTENDED_GLOB */
                     53: #ifdef HAVE_NETGROUP_H
                     54: # include <netgroup.h>
                     55: #endif /* HAVE_NETGROUP_H */
                     56: #include <ctype.h>
                     57: #include <pwd.h>
                     58: #include <grp.h>
                     59: #include <netdb.h>
                     60: #ifdef HAVE_DIRENT_H
                     61: # include <dirent.h>
                     62: # define NAMLEN(dirent) strlen((dirent)->d_name)
                     63: #else
                     64: # define dirent direct
                     65: # define NAMLEN(dirent) (dirent)->d_namlen
                     66: # ifdef HAVE_SYS_NDIR_H
                     67: #  include <sys/ndir.h>
                     68: # endif
                     69: # ifdef HAVE_SYS_DIR_H
                     70: #  include <sys/dir.h>
                     71: # endif
                     72: # ifdef HAVE_NDIR_H
                     73: #  include <ndir.h>
                     74: # endif
                     75: #endif
                     76: 
                     77: #include "sudoers.h"
                     78: #include "parse.h"
                     79: #include <gram.h>
                     80: 
                     81: #ifndef HAVE_FNMATCH
                     82: # include "compat/fnmatch.h"
                     83: #endif /* HAVE_FNMATCH */
                     84: #ifndef HAVE_EXTENDED_GLOB
                     85: # include "compat/glob.h"
                     86: #endif /* HAVE_EXTENDED_GLOB */
                     87: 
                     88: static struct member_list empty;
                     89: 
                     90: static int command_matches_dir(char *, size_t);
                     91: static int command_matches_glob(char *, char *);
                     92: static int command_matches_fnmatch(char *, char *);
                     93: static int command_matches_normal(char *, char *);
                     94: 
                     95: /*
                     96:  * Returns TRUE if string 's' contains meta characters.
                     97:  */
                     98: #define has_meta(s)    (strpbrk(s, "\\?*[]") != NULL)
                     99: 
                    100: /*
                    101:  * Check for user described by pw in a list of members.
                    102:  * Returns ALLOW, DENY or UNSPEC.
                    103:  */
                    104: static int
                    105: _userlist_matches(struct passwd *pw, struct member_list *list)
                    106: {
                    107:     struct member *m;
                    108:     struct alias *a;
                    109:     int rval, matched = UNSPEC;
                    110: 
                    111:     tq_foreach_rev(list, m) {
                    112:        switch (m->type) {
                    113:            case ALL:
                    114:                matched = !m->negated;
                    115:                break;
                    116:            case NETGROUP:
                    117:                if (netgr_matches(m->name, NULL, NULL, pw->pw_name))
                    118:                    matched = !m->negated;
                    119:                break;
                    120:            case USERGROUP:
                    121:                if (usergr_matches(m->name, pw->pw_name, pw))
                    122:                    matched = !m->negated;
                    123:                break;
                    124:            case ALIAS:
                    125:                if ((a = alias_find(m->name, USERALIAS)) != NULL) {
                    126:                    rval = _userlist_matches(pw, &a->members);
                    127:                    if (rval != UNSPEC)
                    128:                        matched = m->negated ? !rval : rval;
                    129:                    break;
                    130:                }
                    131:                /* FALLTHROUGH */
                    132:            case WORD:
                    133:                if (userpw_matches(m->name, pw->pw_name, pw))
                    134:                    matched = !m->negated;
                    135:                break;
                    136:        }
                    137:        if (matched != UNSPEC)
                    138:            break;
                    139:     }
                    140:     return matched;
                    141: }
                    142: 
                    143: int
                    144: userlist_matches(struct passwd *pw, struct member_list *list)
                    145: {
                    146:     alias_seqno++;
                    147:     return _userlist_matches(pw, list);
                    148: }
                    149: 
                    150: /*
                    151:  * Check for user described by pw in a list of members.
                    152:  * If both lists are empty compare against def_runas_default.
                    153:  * Returns ALLOW, DENY or UNSPEC.
                    154:  */
                    155: static int
                    156: _runaslist_matches(struct member_list *user_list, struct member_list *group_list)
                    157: {
                    158:     struct member *m;
                    159:     struct alias *a;
                    160:     int rval;
                    161:     int user_matched = UNSPEC;
                    162:     int group_matched = UNSPEC;
                    163: 
                    164:     if (runas_pw != NULL) {
                    165:        /* If no runas user or runas group listed in sudoers, use default. */
                    166:        if (tq_empty(user_list) && tq_empty(group_list))
                    167:            return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
                    168: 
                    169:        tq_foreach_rev(user_list, m) {
                    170:            switch (m->type) {
                    171:                case ALL:
                    172:                    user_matched = !m->negated;
                    173:                    break;
                    174:                case NETGROUP:
                    175:                    if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
                    176:                        user_matched = !m->negated;
                    177:                    break;
                    178:                case USERGROUP:
                    179:                    if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
                    180:                        user_matched = !m->negated;
                    181:                    break;
                    182:                case ALIAS:
                    183:                    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
                    184:                        rval = _runaslist_matches(&a->members, &empty);
                    185:                        if (rval != UNSPEC)
                    186:                            user_matched = m->negated ? !rval : rval;
                    187:                        break;
                    188:                    }
                    189:                    /* FALLTHROUGH */
                    190:                case WORD:
                    191:                    if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
                    192:                        user_matched = !m->negated;
                    193:                    break;
                    194:            }
                    195:            if (user_matched != UNSPEC)
                    196:                break;
                    197:        }
                    198:     }
                    199: 
                    200:     if (runas_gr != NULL) {
                    201:        if (user_matched == UNSPEC) {
                    202:            if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0)
                    203:                user_matched = ALLOW;   /* only changing group */
                    204:        }
                    205:        tq_foreach_rev(group_list, m) {
                    206:            switch (m->type) {
                    207:                case ALL:
                    208:                    group_matched = !m->negated;
                    209:                    break;
                    210:                case ALIAS:
                    211:                    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
                    212:                        rval = _runaslist_matches(&empty, &a->members);
                    213:                        if (rval != UNSPEC)
                    214:                            group_matched = m->negated ? !rval : rval;
                    215:                        break;
                    216:                    }
                    217:                    /* FALLTHROUGH */
                    218:                case WORD:
                    219:                    if (group_matches(m->name, runas_gr))
                    220:                        group_matched = !m->negated;
                    221:                    break;
                    222:            }
                    223:            if (group_matched != UNSPEC)
                    224:                break;
                    225:        }
                    226:        if (group_matched == UNSPEC) {
                    227:            if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid)
                    228:                group_matched = ALLOW;  /* runas group matches passwd db */
                    229:        }
                    230:     }
                    231: 
                    232:     if (user_matched == DENY || group_matched == DENY)
                    233:        return DENY;
                    234:     if (user_matched == group_matched || runas_gr == NULL)
                    235:        return user_matched;
                    236:     return UNSPEC;
                    237: }
                    238: 
                    239: int
                    240: runaslist_matches(struct member_list *user_list, struct member_list *group_list)
                    241: {
                    242:     alias_seqno++;
                    243:     return _runaslist_matches(user_list ? user_list : &empty,
                    244:        group_list ? group_list : &empty);
                    245: }
                    246: 
                    247: /*
                    248:  * Check for host and shost in a list of members.
                    249:  * Returns ALLOW, DENY or UNSPEC.
                    250:  */
                    251: static int
                    252: _hostlist_matches(struct member_list *list)
                    253: {
                    254:     struct member *m;
                    255:     struct alias *a;
                    256:     int rval, matched = UNSPEC;
                    257: 
                    258:     tq_foreach_rev(list, m) {
                    259:        switch (m->type) {
                    260:            case ALL:
                    261:                matched = !m->negated;
                    262:                break;
                    263:            case NETGROUP:
                    264:                if (netgr_matches(m->name, user_host, user_shost, NULL))
                    265:                    matched = !m->negated;
                    266:                break;
                    267:            case NTWKADDR:
                    268:                if (addr_matches(m->name))
                    269:                    matched = !m->negated;
                    270:                break;
                    271:            case ALIAS:
                    272:                if ((a = alias_find(m->name, HOSTALIAS)) != NULL) {
                    273:                    rval = _hostlist_matches(&a->members);
                    274:                    if (rval != UNSPEC)
                    275:                        matched = m->negated ? !rval : rval;
                    276:                    break;
                    277:                }
                    278:                /* FALLTHROUGH */
                    279:            case WORD:
                    280:                if (hostname_matches(user_shost, user_host, m->name))
                    281:                    matched = !m->negated;
                    282:                break;
                    283:        }
                    284:        if (matched != UNSPEC)
                    285:            break;
                    286:     }
                    287:     return matched;
                    288: }
                    289: 
                    290: int
                    291: hostlist_matches(struct member_list *list)
                    292: {
                    293:     alias_seqno++;
                    294:     return _hostlist_matches(list);
                    295: }
                    296: 
                    297: /*
                    298:  * Check for cmnd and args in a list of members.
                    299:  * Returns ALLOW, DENY or UNSPEC.
                    300:  */
                    301: static int
                    302: _cmndlist_matches(struct member_list *list)
                    303: {
                    304:     struct member *m;
                    305:     int matched = UNSPEC;
                    306: 
                    307:     tq_foreach_rev(list, m) {
                    308:        matched = cmnd_matches(m);
                    309:        if (matched != UNSPEC)
                    310:            break;
                    311:     }
                    312:     return matched;
                    313: }
                    314: 
                    315: int
                    316: cmndlist_matches(struct member_list *list)
                    317: {
                    318:     alias_seqno++;
                    319:     return _cmndlist_matches(list);
                    320: }
                    321: 
                    322: /*
                    323:  * Check cmnd and args.
                    324:  * Returns ALLOW, DENY or UNSPEC.
                    325:  */
                    326: int
                    327: cmnd_matches(struct member *m)
                    328: {
                    329:     struct alias *a;
                    330:     struct sudo_command *c;
                    331:     int rval, matched = UNSPEC;
                    332: 
                    333:     switch (m->type) {
                    334:        case ALL:
                    335:            matched = !m->negated;
                    336:            break;
                    337:        case ALIAS:
                    338:            alias_seqno++;
                    339:            if ((a = alias_find(m->name, CMNDALIAS)) != NULL) {
                    340:                rval = _cmndlist_matches(&a->members);
                    341:                if (rval != UNSPEC)
                    342:                    matched = m->negated ? !rval : rval;
                    343:            }
                    344:            break;
                    345:        case COMMAND:
                    346:            c = (struct sudo_command *)m->name;
                    347:            if (command_matches(c->cmnd, c->args))
                    348:                matched = !m->negated;
                    349:            break;
                    350:     }
                    351:     return matched;
                    352: }
                    353: 
                    354: static int
                    355: command_args_match(sudoers_cmnd, sudoers_args)
                    356:     char *sudoers_cmnd;
                    357:     char *sudoers_args;
                    358: {
                    359:     int flags = 0;
                    360: 
                    361:     /*
                    362:      * If no args specified in sudoers, any user args are allowed.
                    363:      * If the empty string is specified in sudoers, no user args are allowed.
                    364:      */
                    365:     if (!sudoers_args ||
                    366:        (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)))
                    367:        return TRUE;
                    368:     /*
                    369:      * If args are specified in sudoers, they must match the user args.
                    370:      * If running as sudoedit, all args are assumed to be paths.
                    371:      */
                    372:     if (sudoers_args) {
                    373:        /* For sudoedit, all args are assumed to be pathnames. */
                    374:        if (strcmp(sudoers_cmnd, "sudoedit") == 0)
                    375:            flags = FNM_PATHNAME;
                    376:        if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0)
                    377:            return TRUE;
                    378:     }
                    379:     return FALSE;
                    380: }
                    381: 
                    382: /*
                    383:  * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
                    384:  * otherwise, return TRUE if user_cmnd names one of the inodes in path.
                    385:  */
                    386: int
                    387: command_matches(char *sudoers_cmnd, char *sudoers_args)
                    388: {
                    389:     /* Check for pseudo-commands */
                    390:     if (sudoers_cmnd[0] != '/') {
                    391:        /*
                    392:         * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
                    393:         *  a) there are no args in sudoers OR
                    394:         *  b) there are no args on command line and none req by sudoers OR
                    395:         *  c) there are args in sudoers and on command line and they match
                    396:         */
                    397:        if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
                    398:            strcmp(user_cmnd, "sudoedit") != 0)
                    399:            return FALSE;
                    400:        if (command_args_match(sudoers_cmnd, sudoers_args)) {
                    401:            efree(safe_cmnd);
                    402:            safe_cmnd = estrdup(sudoers_cmnd);
                    403:            return TRUE;
                    404:        } else
                    405:            return FALSE;
                    406:     }
                    407: 
                    408:     if (has_meta(sudoers_cmnd)) {
                    409:        /*
                    410:         * If sudoers_cmnd has meta characters in it, we need to
                    411:         * use glob(3) and/or fnmatch(3) to do the matching.
                    412:         */
                    413:        if (def_fast_glob)
                    414:            return command_matches_fnmatch(sudoers_cmnd, sudoers_args);
                    415:        return command_matches_glob(sudoers_cmnd, sudoers_args);
                    416:     }
                    417:     return command_matches_normal(sudoers_cmnd, sudoers_args);
                    418: }
                    419: 
                    420: static int
                    421: command_matches_fnmatch(char *sudoers_cmnd, char *sudoers_args)
                    422: {
                    423:     /*
                    424:      * Return true if fnmatch(3) succeeds AND
                    425:      *  a) there are no args in sudoers OR
                    426:      *  b) there are no args on command line and none required by sudoers OR
                    427:      *  c) there are args in sudoers and on command line and they match
                    428:      * else return false.
                    429:      */
                    430:     if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
                    431:        return FALSE;
                    432:     if (command_args_match(sudoers_cmnd, sudoers_args)) {
                    433:        if (safe_cmnd)
                    434:            free(safe_cmnd);
                    435:        safe_cmnd = estrdup(user_cmnd);
                    436:        return TRUE;
                    437:     } else
                    438:        return FALSE;
                    439: }
                    440: 
                    441: static int
                    442: command_matches_glob(char *sudoers_cmnd, char *sudoers_args)
                    443: {
                    444:     struct stat sudoers_stat;
                    445:     size_t dlen;
                    446:     char **ap, *base, *cp;
                    447:     glob_t gl;
                    448: 
                    449:     /*
                    450:      * First check to see if we can avoid the call to glob(3).
                    451:      * Short circuit if there are no meta chars in the command itself
                    452:      * and user_base and basename(sudoers_cmnd) don't match.
                    453:      */
                    454:     dlen = strlen(sudoers_cmnd);
                    455:     if (sudoers_cmnd[dlen - 1] != '/') {
                    456:        if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
                    457:            base++;
                    458:            if (!has_meta(base) && strcmp(user_base, base) != 0)
                    459:                return FALSE;
                    460:        }
                    461:     }
                    462:     /*
                    463:      * Return true if we find a match in the glob(3) results AND
                    464:      *  a) there are no args in sudoers OR
                    465:      *  b) there are no args on command line and none required by sudoers OR
                    466:      *  c) there are args in sudoers and on command line and they match
                    467:      * else return false.
                    468:      */
                    469: #define GLOB_FLAGS     (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
                    470:     if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0 || gl.gl_pathc == 0) {
                    471:        globfree(&gl);
                    472:        return FALSE;
                    473:     }
                    474:     /* For each glob match, compare basename, st_dev and st_ino. */
                    475:     for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
                    476:        /* If it ends in '/' it is a directory spec. */
                    477:        dlen = strlen(cp);
                    478:        if (cp[dlen - 1] == '/') {
                    479:            if (command_matches_dir(cp, dlen))
                    480:                return TRUE;
                    481:            continue;
                    482:        }
                    483: 
                    484:        /* Only proceed if user_base and basename(cp) match */
                    485:        if ((base = strrchr(cp, '/')) != NULL)
                    486:            base++;
                    487:        else
                    488:            base = cp;
                    489:        if (strcmp(user_base, base) != 0 ||
                    490:            stat(cp, &sudoers_stat) == -1)
                    491:            continue;
                    492:        if (user_stat == NULL ||
                    493:            (user_stat->st_dev == sudoers_stat.st_dev &&
                    494:            user_stat->st_ino == sudoers_stat.st_ino)) {
                    495:            efree(safe_cmnd);
                    496:            safe_cmnd = estrdup(cp);
                    497:            break;
                    498:        }
                    499:     }
                    500:     globfree(&gl);
                    501:     if (cp == NULL)
                    502:        return FALSE;
                    503: 
                    504:     if (command_args_match(sudoers_cmnd, sudoers_args)) {
                    505:        efree(safe_cmnd);
                    506:        safe_cmnd = estrdup(user_cmnd);
                    507:        return TRUE;
                    508:     }
                    509:     return FALSE;
                    510: }
                    511: 
                    512: static int
                    513: command_matches_normal(char *sudoers_cmnd, char *sudoers_args)
                    514: {
                    515:     struct stat sudoers_stat;
                    516:     char *base;
                    517:     size_t dlen;
                    518: 
                    519:     /* If it ends in '/' it is a directory spec. */
                    520:     dlen = strlen(sudoers_cmnd);
                    521:     if (sudoers_cmnd[dlen - 1] == '/')
                    522:        return command_matches_dir(sudoers_cmnd, dlen);
                    523: 
                    524:     /* Only proceed if user_base and basename(sudoers_cmnd) match */
                    525:     if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
                    526:        base = sudoers_cmnd;
                    527:     else
                    528:        base++;
                    529:     if (strcmp(user_base, base) != 0 ||
                    530:        stat(sudoers_cmnd, &sudoers_stat) == -1)
                    531:        return FALSE;
                    532: 
                    533:     /*
                    534:      * Return true if inode/device matches AND
                    535:      *  a) there are no args in sudoers OR
                    536:      *  b) there are no args on command line and none req by sudoers OR
                    537:      *  c) there are args in sudoers and on command line and they match
                    538:      */
                    539:     if (user_stat != NULL &&
                    540:        (user_stat->st_dev != sudoers_stat.st_dev ||
                    541:        user_stat->st_ino != sudoers_stat.st_ino))
                    542:        return FALSE;
                    543:     if (command_args_match(sudoers_cmnd, sudoers_args)) {
                    544:        efree(safe_cmnd);
                    545:        safe_cmnd = estrdup(sudoers_cmnd);
                    546:        return TRUE;
                    547:     }
                    548:     return FALSE;
                    549: }
                    550: 
                    551: /*
                    552:  * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE.
                    553:  */
                    554: static int
                    555: command_matches_dir(char *sudoers_dir, size_t dlen)
                    556: {
                    557:     struct stat sudoers_stat;
                    558:     struct dirent *dent;
                    559:     char buf[PATH_MAX];
                    560:     DIR *dirp;
                    561: 
                    562:     /*
                    563:      * Grot through directory entries, looking for user_base.
                    564:      */
                    565:     dirp = opendir(sudoers_dir);
                    566:     if (dirp == NULL)
                    567:        return FALSE;
                    568: 
                    569:     if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) {
                    570:        closedir(dirp);
                    571:        return FALSE;
                    572:     }
                    573:     while ((dent = readdir(dirp)) != NULL) {
                    574:        /* ignore paths > PATH_MAX (XXX - log) */
                    575:        buf[dlen] = '\0';
                    576:        if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
                    577:            continue;
                    578: 
                    579:        /* only stat if basenames are the same */
                    580:        if (strcmp(user_base, dent->d_name) != 0 ||
                    581:            stat(buf, &sudoers_stat) == -1)
                    582:            continue;
                    583:        if (user_stat == NULL ||
                    584:            (user_stat->st_dev == sudoers_stat.st_dev &&
                    585:            user_stat->st_ino == sudoers_stat.st_ino)) {
                    586:            efree(safe_cmnd);
                    587:            safe_cmnd = estrdup(buf);
                    588:            break;
                    589:        }
                    590:     }
                    591: 
                    592:     closedir(dirp);
                    593:     return dent != NULL;
                    594: }
                    595: 
                    596: /*
                    597:  * Returns TRUE if the hostname matches the pattern, else FALSE
                    598:  */
                    599: int
                    600: hostname_matches(char *shost, char *lhost, char *pattern)
                    601: {
                    602:     if (has_meta(pattern)) {
                    603:        if (strchr(pattern, '.'))
                    604:            return !fnmatch(pattern, lhost, FNM_CASEFOLD);
                    605:        else
                    606:            return !fnmatch(pattern, shost, FNM_CASEFOLD);
                    607:     } else {
                    608:        if (strchr(pattern, '.'))
                    609:            return !strcasecmp(lhost, pattern);
                    610:        else
                    611:            return !strcasecmp(shost, pattern);
                    612:     }
                    613: }
                    614: 
                    615: /*
                    616:  *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
                    617:  *  else returns FALSE.
                    618:  */
                    619: int
                    620: userpw_matches(char *sudoers_user, char *user, struct passwd *pw)
                    621: {
                    622:     if (pw != NULL && *sudoers_user == '#') {
                    623:        uid_t uid = (uid_t) atoi(sudoers_user + 1);
                    624:        if (uid == pw->pw_uid)
                    625:            return TRUE;
                    626:     }
                    627:     return strcmp(sudoers_user, user) == 0;
                    628: }
                    629: 
                    630: /*
                    631:  *  Returns TRUE if the group/gid from sudoers matches the specified group/gid,
                    632:  *  else returns FALSE.
                    633:  */
                    634: int
                    635: group_matches(char *sudoers_group, struct group *gr)
                    636: {
                    637:     if (*sudoers_group == '#') {
                    638:        gid_t gid = (gid_t) atoi(sudoers_group + 1);
                    639:        if (gid == gr->gr_gid)
                    640:            return TRUE;
                    641:     }
                    642:     return strcmp(gr->gr_name, sudoers_group) == 0;
                    643: }
                    644: 
                    645: /*
                    646:  *  Returns TRUE if the given user belongs to the named group,
                    647:  *  else returns FALSE.
                    648:  */
                    649: int
                    650: usergr_matches(char *group, char *user, struct passwd *pw)
                    651: {
                    652:     int matched = FALSE;
                    653:     struct passwd *pw0 = NULL;
                    654: 
                    655:     /* make sure we have a valid usergroup, sudo style */
                    656:     if (*group++ != '%')
                    657:        goto done;
                    658: 
                    659:     if (*group == ':' && def_group_plugin) {
                    660:        matched = group_plugin_query(user, group + 1, pw);
                    661:        goto done;
                    662:     }
                    663: 
                    664:     /* look up user's primary gid in the passwd file */
                    665:     if (pw == NULL) {
                    666:        if ((pw0 = sudo_getpwnam(user)) == NULL)
                    667:            goto done;
                    668:        pw = pw0;
                    669:     }
                    670: 
                    671:     if (user_in_group(pw, group)) {
                    672:        matched = TRUE;
                    673:        goto done;
                    674:     }
                    675: 
                    676:     /* not a Unix group, could be an external group */
                    677:     if (def_group_plugin && group_plugin_query(user, group, pw)) {
                    678:        matched = TRUE;
                    679:        goto done;
                    680:     }
                    681: 
                    682: done:
                    683:     if (pw0 != NULL)
                    684:        pw_delref(pw0);
                    685: 
                    686:     return matched;
                    687: }
                    688: 
                    689: /*
                    690:  * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
                    691:  * else return FALSE.  Either of "host", "shost" or "user" may be NULL
                    692:  * in which case that argument is not checked...
                    693:  *
                    694:  * XXX - swap order of host & shost
                    695:  */
                    696: int
                    697: netgr_matches(char *netgr, char *lhost, char *shost, char *user)
                    698: {
                    699:     static char *domain;
                    700: #ifdef HAVE_GETDOMAINNAME
                    701:     static int initialized;
                    702: #endif
                    703: 
                    704:     /* make sure we have a valid netgroup, sudo style */
                    705:     if (*netgr++ != '+')
                    706:        return FALSE;
                    707: 
                    708: #ifdef HAVE_GETDOMAINNAME
                    709:     /* get the domain name (if any) */
                    710:     if (!initialized) {
                    711:        domain = (char *) emalloc(MAXHOSTNAMELEN + 1);
                    712:        if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') {
                    713:            efree(domain);
                    714:            domain = NULL;
                    715:        }
                    716:        initialized = 1;
                    717:     }
                    718: #endif /* HAVE_GETDOMAINNAME */
                    719: 
                    720: #ifdef HAVE_INNETGR
                    721:     if (innetgr(netgr, lhost, user, domain))
                    722:        return TRUE;
                    723:     else if (lhost != shost && innetgr(netgr, shost, user, domain))
                    724:        return TRUE;
                    725: #endif /* HAVE_INNETGR */
                    726: 
                    727:     return FALSE;
                    728: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>