[BACK]Return to match.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/match.c, Revision 1.1

1.1     ! millert     1: /*
        !             2:  * Copyright (c) 1996, 1998-2005, 2007-2008
        !             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/socket.h>
        !            29: #include <sys/stat.h>
        !            30: #include <stdio.h>
        !            31: #ifdef STDC_HEADERS
        !            32: # include <stdlib.h>
        !            33: # include <stddef.h>
        !            34: #else
        !            35: # ifdef HAVE_STDLIB_H
        !            36: #  include <stdlib.h>
        !            37: # endif
        !            38: #endif /* STDC_HEADERS */
        !            39: #ifdef HAVE_STRING_H
        !            40: # include <string.h>
        !            41: #else
        !            42: # ifdef HAVE_STRINGS_H
        !            43: #  include <strings.h>
        !            44: # endif
        !            45: #endif /* HAVE_STRING_H */
        !            46: #ifdef HAVE_UNISTD_H
        !            47: # include <unistd.h>
        !            48: #endif /* HAVE_UNISTD_H */
        !            49: #ifdef HAVE_FNMATCH
        !            50: # include <fnmatch.h>
        !            51: #endif /* HAVE_FNMATCH */
        !            52: #ifdef HAVE_EXTENDED_GLOB
        !            53: # include <glob.h>
        !            54: #endif /* HAVE_EXTENDED_GLOB */
        !            55: #ifdef HAVE_NETGROUP_H
        !            56: # include <netgroup.h>
        !            57: #endif /* HAVE_NETGROUP_H */
        !            58: #include <ctype.h>
        !            59: #include <pwd.h>
        !            60: #include <grp.h>
        !            61: #include <netinet/in.h>
        !            62: #include <arpa/inet.h>
        !            63: #include <netdb.h>
        !            64: #ifdef HAVE_DIRENT_H
        !            65: # include <dirent.h>
        !            66: # define NAMLEN(dirent) strlen((dirent)->d_name)
        !            67: #else
        !            68: # define dirent direct
        !            69: # define NAMLEN(dirent) (dirent)->d_namlen
        !            70: # ifdef HAVE_SYS_NDIR_H
        !            71: #  include <sys/ndir.h>
        !            72: # endif
        !            73: # ifdef HAVE_SYS_DIR_H
        !            74: #  include <sys/dir.h>
        !            75: # endif
        !            76: # ifdef HAVE_NDIR_H
        !            77: #  include <ndir.h>
        !            78: # endif
        !            79: #endif
        !            80:
        !            81: #include "sudo.h"
        !            82: #include "interfaces.h"
        !            83: #include "parse.h"
        !            84: #include <gram.h>
        !            85:
        !            86: #ifndef HAVE_FNMATCH
        !            87: # include "emul/fnmatch.h"
        !            88: #endif /* HAVE_FNMATCH */
        !            89: #ifndef HAVE_EXTENDED_GLOB
        !            90: # include "emul/glob.h"
        !            91: #endif /* HAVE_EXTENDED_GLOB */
        !            92:
        !            93: #ifndef lint
        !            94: __unused static const char rcsid[] = "$Sudo: match.c,v 1.38 2008/11/02 14:35:37 millert Exp $";
        !            95: #endif /* lint */
        !            96:
        !            97: static struct member_list empty;
        !            98:
        !            99: static int command_matches_dir __P((char *, size_t));
        !           100:
        !           101: /*
        !           102:  * Returns TRUE if string 's' contains meta characters.
        !           103:  */
        !           104: #define has_meta(s)    (strpbrk(s, "\\?*[]") != NULL)
        !           105:
        !           106: /*
        !           107:  * Check for user described by pw in a list of members.
        !           108:  * Returns ALLOW, DENY or UNSPEC.
        !           109:  */
        !           110: static int
        !           111: _userlist_matches(pw, list)
        !           112:     struct passwd *pw;
        !           113:     struct member_list *list;
        !           114: {
        !           115:     struct member *m;
        !           116:     struct alias *a;
        !           117:     int rval, matched = UNSPEC;
        !           118:
        !           119:     tq_foreach_rev(list, m) {
        !           120:        switch (m->type) {
        !           121:            case ALL:
        !           122:                matched = !m->negated;
        !           123:                break;
        !           124:            case NETGROUP:
        !           125:                if (netgr_matches(m->name, NULL, NULL, pw->pw_name))
        !           126:                    matched = !m->negated;
        !           127:                break;
        !           128:            case USERGROUP:
        !           129:                if (usergr_matches(m->name, pw->pw_name, pw))
        !           130:                    matched = !m->negated;
        !           131:                break;
        !           132:            case ALIAS:
        !           133:                if ((a = find_alias(m->name, USERALIAS)) != NULL) {
        !           134:                    rval = _userlist_matches(pw, &a->members);
        !           135:                    if (rval != UNSPEC)
        !           136:                        matched = m->negated ? !rval : rval;
        !           137:                    break;
        !           138:                }
        !           139:                /* FALLTHROUGH */
        !           140:            case WORD:
        !           141:                if (userpw_matches(m->name, pw->pw_name, pw))
        !           142:                    matched = !m->negated;
        !           143:                break;
        !           144:        }
        !           145:        if (matched != UNSPEC)
        !           146:            break;
        !           147:     }
        !           148:     return(matched);
        !           149: }
        !           150:
        !           151: int
        !           152: userlist_matches(pw, list)
        !           153:     struct passwd *pw;
        !           154:     struct member_list *list;
        !           155: {
        !           156:     alias_seqno++;
        !           157:     return(_userlist_matches(pw, list));
        !           158: }
        !           159:
        !           160: /*
        !           161:  * Check for user described by pw in a list of members.
        !           162:  * If both lists are empty compare against def_runas_default.
        !           163:  * Returns ALLOW, DENY or UNSPEC.
        !           164:  */
        !           165: static int
        !           166: _runaslist_matches(user_list, group_list)
        !           167:     struct member_list *user_list;
        !           168:     struct member_list *group_list;
        !           169: {
        !           170:     struct member *m;
        !           171:     struct alias *a;
        !           172:     int rval, matched = UNSPEC;
        !           173:
        !           174:     /* Deny if user specified a group but there is no group in sudoers */
        !           175:     if (runas_gr != NULL && tq_empty(group_list))
        !           176:        return(DENY);
        !           177:
        !           178:     if (tq_empty(user_list) && tq_empty(group_list))
        !           179:        return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw));
        !           180:
        !           181:     if (runas_pw != NULL) {
        !           182:        tq_foreach_rev(user_list, m) {
        !           183:            switch (m->type) {
        !           184:                case ALL:
        !           185:                    matched = !m->negated;
        !           186:                    break;
        !           187:                case NETGROUP:
        !           188:                    if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
        !           189:                        matched = !m->negated;
        !           190:                    break;
        !           191:                case USERGROUP:
        !           192:                    if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
        !           193:                        matched = !m->negated;
        !           194:                    break;
        !           195:                case ALIAS:
        !           196:                    if ((a = find_alias(m->name, RUNASALIAS)) != NULL) {
        !           197:                        rval = _runaslist_matches(&a->members, &empty);
        !           198:                        if (rval != UNSPEC)
        !           199:                            matched = m->negated ? !rval : rval;
        !           200:                        break;
        !           201:                    }
        !           202:                    /* FALLTHROUGH */
        !           203:                case WORD:
        !           204:                    if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
        !           205:                        matched = !m->negated;
        !           206:                    break;
        !           207:            }
        !           208:            if (matched != UNSPEC)
        !           209:                break;
        !           210:        }
        !           211:     }
        !           212:
        !           213:     if (runas_gr != NULL) {
        !           214:        tq_foreach_rev(group_list, m) {
        !           215:            switch (m->type) {
        !           216:                case ALL:
        !           217:                    matched = !m->negated;
        !           218:                    break;
        !           219:                case ALIAS:
        !           220:                    if ((a = find_alias(m->name, RUNASALIAS)) != NULL) {
        !           221:                        rval = _runaslist_matches(&a->members, &empty);
        !           222:                        if (rval != UNSPEC)
        !           223:                            matched = m->negated ? !rval : rval;
        !           224:                        break;
        !           225:                    }
        !           226:                    /* FALLTHROUGH */
        !           227:                case WORD:
        !           228:                    if (group_matches(m->name, runas_gr))
        !           229:                        matched = !m->negated;
        !           230:                    break;
        !           231:            }
        !           232:            if (matched != UNSPEC)
        !           233:                break;
        !           234:        }
        !           235:     }
        !           236:
        !           237:     return(matched);
        !           238: }
        !           239:
        !           240: int
        !           241: runaslist_matches(user_list, group_list)
        !           242:     struct member_list *user_list;
        !           243:     struct member_list *group_list;
        !           244: {
        !           245:     alias_seqno++;
        !           246:     return(_runaslist_matches(user_list ? user_list : &empty,
        !           247:        group_list ? group_list : &empty));
        !           248: }
        !           249:
        !           250: /*
        !           251:  * Check for host and shost in a list of members.
        !           252:  * Returns ALLOW, DENY or UNSPEC.
        !           253:  */
        !           254: static int
        !           255: _hostlist_matches(list)
        !           256:     struct member_list *list;
        !           257: {
        !           258:     struct member *m;
        !           259:     struct alias *a;
        !           260:     int rval, matched = UNSPEC;
        !           261:
        !           262:     tq_foreach_rev(list, m) {
        !           263:        switch (m->type) {
        !           264:            case ALL:
        !           265:                matched = !m->negated;
        !           266:                break;
        !           267:            case NETGROUP:
        !           268:                if (netgr_matches(m->name, user_host, user_shost, NULL))
        !           269:                    matched = !m->negated;
        !           270:                break;
        !           271:            case NTWKADDR:
        !           272:                if (addr_matches(m->name))
        !           273:                    matched = !m->negated;
        !           274:                break;
        !           275:            case ALIAS:
        !           276:                if ((a = find_alias(m->name, HOSTALIAS)) != NULL) {
        !           277:                    rval = _hostlist_matches(&a->members);
        !           278:                    if (rval != UNSPEC)
        !           279:                        matched = m->negated ? !rval : rval;
        !           280:                    break;
        !           281:                }
        !           282:                /* FALLTHROUGH */
        !           283:            case WORD:
        !           284:                if (hostname_matches(user_shost, user_host, m->name))
        !           285:                    matched = !m->negated;
        !           286:                break;
        !           287:        }
        !           288:        if (matched != UNSPEC)
        !           289:            break;
        !           290:     }
        !           291:     return(matched);
        !           292: }
        !           293:
        !           294: int
        !           295: hostlist_matches(list)
        !           296:     struct member_list *list;
        !           297: {
        !           298:     alias_seqno++;
        !           299:     return(_hostlist_matches(list));
        !           300: }
        !           301:
        !           302: /*
        !           303:  * Check for cmnd and args in a list of members.
        !           304:  * Returns ALLOW, DENY or UNSPEC.
        !           305:  */
        !           306: static int
        !           307: _cmndlist_matches(list)
        !           308:     struct member_list *list;
        !           309: {
        !           310:     struct member *m;
        !           311:     int rval, matched = UNSPEC;
        !           312:
        !           313:     tq_foreach_rev(list, m) {
        !           314:        rval = cmnd_matches(m);
        !           315:        if (rval != UNSPEC) {
        !           316:            matched = m->negated ? !rval : rval;
        !           317:            break;
        !           318:        }
        !           319:     }
        !           320:     return(matched);
        !           321: }
        !           322:
        !           323: int
        !           324: cmndlist_matches(list)
        !           325:     struct member_list *list;
        !           326: {
        !           327:     alias_seqno++;
        !           328:     return(_cmndlist_matches(list));
        !           329: }
        !           330:
        !           331: /*
        !           332:  * Check cmnd and args.
        !           333:  * Returns ALLOW, DENY or UNSPEC.
        !           334:  */
        !           335: int
        !           336: cmnd_matches(m)
        !           337:     struct member *m;
        !           338: {
        !           339:     struct alias *a;
        !           340:     struct sudo_command *c;
        !           341:     int rval, matched = UNSPEC;
        !           342:
        !           343:     switch (m->type) {
        !           344:        case ALL:
        !           345:            matched = !m->negated;
        !           346:            break;
        !           347:        case ALIAS:
        !           348:            alias_seqno++;
        !           349:            if ((a = find_alias(m->name, CMNDALIAS)) != NULL) {
        !           350:                rval = _cmndlist_matches(&a->members);
        !           351:                if (rval != UNSPEC)
        !           352:                    matched = m->negated ? !rval : rval;
        !           353:            }
        !           354:            break;
        !           355:        case COMMAND:
        !           356:            c = (struct sudo_command *)m->name;
        !           357:            if (command_matches(c->cmnd, c->args))
        !           358:                matched = !m->negated;
        !           359:            break;
        !           360:     }
        !           361:     return(matched);
        !           362: }
        !           363:
        !           364: /*
        !           365:  * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
        !           366:  * otherwise, return TRUE if user_cmnd names one of the inodes in path.
        !           367:  */
        !           368: int
        !           369: command_matches(sudoers_cmnd, sudoers_args)
        !           370:     char *sudoers_cmnd;
        !           371:     char *sudoers_args;
        !           372: {
        !           373:     struct stat sudoers_stat;
        !           374:     char **ap, *base, *cp;
        !           375:     glob_t gl;
        !           376:     size_t dlen;
        !           377:
        !           378:     /* Check for pseudo-commands */
        !           379:     if (strchr(user_cmnd, '/') == NULL) {
        !           380:        /*
        !           381:         * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
        !           382:         *  a) there are no args in sudoers OR
        !           383:         *  b) there are no args on command line and none req by sudoers OR
        !           384:         *  c) there are args in sudoers and on command line and they match
        !           385:         */
        !           386:        if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
        !           387:            strcmp(user_cmnd, "sudoedit") != 0)
        !           388:            return(FALSE);
        !           389:        if (!sudoers_args ||
        !           390:            (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
        !           391:            (sudoers_args &&
        !           392:             fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
        !           393:            efree(safe_cmnd);
        !           394:            safe_cmnd = estrdup(sudoers_cmnd);
        !           395:            return(TRUE);
        !           396:        } else
        !           397:            return(FALSE);
        !           398:     }
        !           399:     dlen = strlen(sudoers_cmnd);
        !           400:
        !           401:     /*
        !           402:      * If sudoers_cmnd has meta characters in it, we may need to
        !           403:      * use glob(3) and fnmatch(3) to do the matching.
        !           404:      */
        !           405:     if (has_meta(sudoers_cmnd)) {
        !           406:        /*
        !           407:         * First check to see if we can avoid the call to glob(3).
        !           408:         * Short circuit if there are no meta chars in the command itself
        !           409:         * and user_base and basename(sudoers_cmnd) don't match.
        !           410:         */
        !           411:        if (sudoers_cmnd[dlen - 1] != '/') {
        !           412:            if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
        !           413:                base++;
        !           414:                if (!has_meta(base) && strcmp(user_base, base) != 0)
        !           415:                    return(FALSE);
        !           416:            }
        !           417:        }
        !           418:        /*
        !           419:         * Return true if we find a match in the glob(3) results AND
        !           420:         *  a) there are no args in sudoers OR
        !           421:         *  b) there are no args on command line and none required by sudoers OR
        !           422:         *  c) there are args in sudoers and on command line and they match
        !           423:         * else return false.
        !           424:         */
        !           425: #define GLOB_FLAGS     (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
        !           426:        if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0) {
        !           427:            globfree(&gl);
        !           428:            return(FALSE);
        !           429:        }
        !           430:        /* For each glob match, compare basename, st_dev and st_ino. */
        !           431:        for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
        !           432:            /* If it ends in '/' it is a directory spec. */
        !           433:            dlen = strlen(cp);
        !           434:            if (cp[dlen - 1] == '/') {
        !           435:                if (command_matches_dir(cp, dlen))
        !           436:                    return(TRUE);
        !           437:                continue;
        !           438:            }
        !           439:
        !           440:            /* Only proceed if user_base and basename(cp) match */
        !           441:            if ((base = strrchr(cp, '/')) != NULL)
        !           442:                base++;
        !           443:            else
        !           444:                base = cp;
        !           445:            if (strcmp(user_base, base) != 0 ||
        !           446:                stat(cp, &sudoers_stat) == -1)
        !           447:                continue;
        !           448:            if (user_stat == NULL ||
        !           449:                (user_stat->st_dev == sudoers_stat.st_dev &&
        !           450:                user_stat->st_ino == sudoers_stat.st_ino)) {
        !           451:                efree(safe_cmnd);
        !           452:                safe_cmnd = estrdup(cp);
        !           453:                break;
        !           454:            }
        !           455:        }
        !           456:        globfree(&gl);
        !           457:        if (cp == NULL)
        !           458:            return(FALSE);
        !           459:
        !           460:        if (!sudoers_args ||
        !           461:            (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
        !           462:            (sudoers_args &&
        !           463:             fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
        !           464:            efree(safe_cmnd);
        !           465:            safe_cmnd = estrdup(user_cmnd);
        !           466:            return(TRUE);
        !           467:        }
        !           468:        return(FALSE);
        !           469:     } else {
        !           470:        /* If it ends in '/' it is a directory spec. */
        !           471:        if (sudoers_cmnd[dlen - 1] == '/')
        !           472:            return(command_matches_dir(sudoers_cmnd, dlen));
        !           473:
        !           474:        /* Only proceed if user_base and basename(sudoers_cmnd) match */
        !           475:        if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
        !           476:            base = sudoers_cmnd;
        !           477:        else
        !           478:            base++;
        !           479:        if (strcmp(user_base, base) != 0 ||
        !           480:            stat(sudoers_cmnd, &sudoers_stat) == -1)
        !           481:            return(FALSE);
        !           482:
        !           483:        /*
        !           484:         * Return true if inode/device matches AND
        !           485:         *  a) there are no args in sudoers OR
        !           486:         *  b) there are no args on command line and none req by sudoers OR
        !           487:         *  c) there are args in sudoers and on command line and they match
        !           488:         */
        !           489:        if (user_stat != NULL &&
        !           490:            (user_stat->st_dev != sudoers_stat.st_dev ||
        !           491:            user_stat->st_ino != sudoers_stat.st_ino))
        !           492:            return(FALSE);
        !           493:        if (!sudoers_args ||
        !           494:            (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
        !           495:            (sudoers_args &&
        !           496:             fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
        !           497:            efree(safe_cmnd);
        !           498:            safe_cmnd = estrdup(sudoers_cmnd);
        !           499:            return(TRUE);
        !           500:        }
        !           501:        return(FALSE);
        !           502:     }
        !           503: }
        !           504:
        !           505: /*
        !           506:  * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE.
        !           507:  */
        !           508: static int
        !           509: command_matches_dir(sudoers_dir, dlen)
        !           510:     char *sudoers_dir;
        !           511:     size_t dlen;
        !           512: {
        !           513:     struct stat sudoers_stat;
        !           514:     struct dirent *dent;
        !           515:     char buf[PATH_MAX];
        !           516:     DIR *dirp;
        !           517:
        !           518:     /*
        !           519:      * Grot through directory entries, looking for user_base.
        !           520:      */
        !           521:     dirp = opendir(sudoers_dir);
        !           522:     if (dirp == NULL)
        !           523:        return(FALSE);
        !           524:
        !           525:     if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf))
        !           526:        return(FALSE);
        !           527:     while ((dent = readdir(dirp)) != NULL) {
        !           528:        /* ignore paths > PATH_MAX (XXX - log) */
        !           529:        buf[dlen] = '\0';
        !           530:        if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
        !           531:            continue;
        !           532:
        !           533:        /* only stat if basenames are the same */
        !           534:        if (strcmp(user_base, dent->d_name) != 0 ||
        !           535:            stat(buf, &sudoers_stat) == -1)
        !           536:            continue;
        !           537:        if (user_stat->st_dev == sudoers_stat.st_dev &&
        !           538:            user_stat->st_ino == sudoers_stat.st_ino) {
        !           539:            efree(safe_cmnd);
        !           540:            safe_cmnd = estrdup(buf);
        !           541:            break;
        !           542:        }
        !           543:     }
        !           544:
        !           545:     closedir(dirp);
        !           546:     return(dent != NULL);
        !           547: }
        !           548:
        !           549: static int
        !           550: addr_matches_if(n)
        !           551:     char *n;
        !           552: {
        !           553:     int i;
        !           554:     struct in_addr addr;
        !           555:     struct interface *ifp;
        !           556: #ifdef HAVE_IN6_ADDR
        !           557:     struct in6_addr addr6;
        !           558:     int j;
        !           559: #endif
        !           560:     int family;
        !           561:
        !           562: #ifdef HAVE_IN6_ADDR
        !           563:     if (inet_pton(AF_INET6, n, &addr6) > 0) {
        !           564:        family = AF_INET6;
        !           565:     } else
        !           566: #endif
        !           567:     {
        !           568:        family = AF_INET;
        !           569:        addr.s_addr = inet_addr(n);
        !           570:     }
        !           571:
        !           572:     for (i = 0; i < num_interfaces; i++) {
        !           573:        ifp = &interfaces[i];
        !           574:        if (ifp->family != family)
        !           575:            continue;
        !           576:        switch(family) {
        !           577:            case AF_INET:
        !           578:                if (ifp->addr.ip4.s_addr == addr.s_addr ||
        !           579:                    (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
        !           580:                    == addr.s_addr)
        !           581:                    return(TRUE);
        !           582:                break;
        !           583: #ifdef HAVE_IN6_ADDR
        !           584:            case AF_INET6:
        !           585:                if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
        !           586:                    sizeof(addr6.s6_addr)) == 0)
        !           587:                    return(TRUE);
        !           588:                for (j = 0; j < sizeof(addr6.s6_addr); j++) {
        !           589:                    if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
        !           590:                        break;
        !           591:                }
        !           592:                if (j == sizeof(addr6.s6_addr))
        !           593:                    return(TRUE);
        !           594: #endif
        !           595:        }
        !           596:     }
        !           597:
        !           598:     return(FALSE);
        !           599: }
        !           600:
        !           601: static int
        !           602: addr_matches_if_netmask(n, m)
        !           603:     char *n;
        !           604:     char *m;
        !           605: {
        !           606:     int i;
        !           607:     struct in_addr addr, mask;
        !           608:     struct interface *ifp;
        !           609: #ifdef HAVE_IN6_ADDR
        !           610:     struct in6_addr addr6, mask6;
        !           611:     int j;
        !           612: #endif
        !           613:     int family;
        !           614:
        !           615: #ifdef HAVE_IN6_ADDR
        !           616:     if (inet_pton(AF_INET6, n, &addr6) > 0)
        !           617:        family = AF_INET6;
        !           618:     else
        !           619: #endif
        !           620:     {
        !           621:        family = AF_INET;
        !           622:        addr.s_addr = inet_addr(n);
        !           623:     }
        !           624:
        !           625:     if (family == AF_INET) {
        !           626:        if (strchr(m, '.'))
        !           627:            mask.s_addr = inet_addr(m);
        !           628:        else {
        !           629:            i = 32 - atoi(m);
        !           630:            mask.s_addr = 0xffffffff;
        !           631:            mask.s_addr >>= i;
        !           632:            mask.s_addr <<= i;
        !           633:            mask.s_addr = htonl(mask.s_addr);
        !           634:        }
        !           635:     }
        !           636: #ifdef HAVE_IN6_ADDR
        !           637:     else {
        !           638:        if (inet_pton(AF_INET6, m, &mask6) <= 0) {
        !           639:            j = atoi(m);
        !           640:            for (i = 0; i < 16; i++) {
        !           641:                if (j < i * 8)
        !           642:                    mask6.s6_addr[i] = 0;
        !           643:                else if (i * 8 + 8 <= j)
        !           644:                    mask6.s6_addr[i] = 0xff;
        !           645:                else
        !           646:                    mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
        !           647:            }
        !           648:        }
        !           649:     }
        !           650: #endif /* HAVE_IN6_ADDR */
        !           651:
        !           652:     for (i = 0; i < num_interfaces; i++) {
        !           653:        ifp = &interfaces[i];
        !           654:        if (ifp->family != family)
        !           655:            continue;
        !           656:        switch(family) {
        !           657:            case AF_INET:
        !           658:                if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
        !           659:                    return(TRUE);
        !           660: #ifdef HAVE_IN6_ADDR
        !           661:            case AF_INET6:
        !           662:                for (j = 0; j < sizeof(addr6.s6_addr); j++) {
        !           663:                    if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
        !           664:                        break;
        !           665:                }
        !           666:                if (j == sizeof(addr6.s6_addr))
        !           667:                    return(TRUE);
        !           668: #endif /* HAVE_IN6_ADDR */
        !           669:        }
        !           670:     }
        !           671:
        !           672:     return(FALSE);
        !           673: }
        !           674:
        !           675: /*
        !           676:  * Returns TRUE if "n" is one of our ip addresses or if
        !           677:  * "n" is a network that we are on, else returns FALSE.
        !           678:  */
        !           679: int
        !           680: addr_matches(n)
        !           681:     char *n;
        !           682: {
        !           683:     char *m;
        !           684:     int retval;
        !           685:
        !           686:     /* If there's an explicit netmask, use it. */
        !           687:     if ((m = strchr(n, '/'))) {
        !           688:        *m++ = '\0';
        !           689:        retval = addr_matches_if_netmask(n, m);
        !           690:        *(m - 1) = '/';
        !           691:     } else
        !           692:        retval = addr_matches_if(n);
        !           693:
        !           694:     return(retval);
        !           695: }
        !           696:
        !           697: /*
        !           698:  * Returns TRUE if the hostname matches the pattern, else FALSE
        !           699:  */
        !           700: int
        !           701: hostname_matches(shost, lhost, pattern)
        !           702:     char *shost;
        !           703:     char *lhost;
        !           704:     char *pattern;
        !           705: {
        !           706:     if (has_meta(pattern)) {
        !           707:        if (strchr(pattern, '.'))
        !           708:            return(!fnmatch(pattern, lhost, FNM_CASEFOLD));
        !           709:        else
        !           710:            return(!fnmatch(pattern, shost, FNM_CASEFOLD));
        !           711:     } else {
        !           712:        if (strchr(pattern, '.'))
        !           713:            return(!strcasecmp(lhost, pattern));
        !           714:        else
        !           715:            return(!strcasecmp(shost, pattern));
        !           716:     }
        !           717: }
        !           718:
        !           719: /*
        !           720:  *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
        !           721:  *  else returns FALSE.
        !           722:  */
        !           723: int
        !           724: userpw_matches(sudoers_user, user, pw)
        !           725:     char *sudoers_user;
        !           726:     char *user;
        !           727:     struct passwd *pw;
        !           728: {
        !           729:     if (pw != NULL && *sudoers_user == '#') {
        !           730:        uid_t uid = (uid_t) atoi(sudoers_user + 1);
        !           731:        if (uid == pw->pw_uid)
        !           732:            return(TRUE);
        !           733:     }
        !           734:     return(strcmp(sudoers_user, user) == 0);
        !           735: }
        !           736:
        !           737: /*
        !           738:  *  Returns TRUE if the group/gid from sudoers matches the specified group/gid,
        !           739:  *  else returns FALSE.
        !           740:  */
        !           741: int
        !           742: group_matches(sudoers_group, gr)
        !           743:     char *sudoers_group;
        !           744:     struct group *gr;
        !           745: {
        !           746:     if (*sudoers_group == '#') {
        !           747:        gid_t gid = (gid_t) atoi(sudoers_group + 1);
        !           748:        if (gid == gr->gr_gid)
        !           749:            return(TRUE);
        !           750:     }
        !           751:     return(strcmp(gr->gr_name, sudoers_group) == 0);
        !           752: }
        !           753:
        !           754: /*
        !           755:  *  Returns TRUE if the given user belongs to the named group,
        !           756:  *  else returns FALSE.
        !           757:  *  XXX - reduce the number of group lookups
        !           758:  */
        !           759: int
        !           760: usergr_matches(group, user, pw)
        !           761:     char *group;
        !           762:     char *user;
        !           763:     struct passwd *pw;
        !           764: {
        !           765:     struct group *grp;
        !           766:     char **cur;
        !           767:     int i;
        !           768:
        !           769:     /* make sure we have a valid usergroup, sudo style */
        !           770:     if (*group++ != '%')
        !           771:        return(FALSE);
        !           772:
        !           773:     /* look up user's primary gid in the passwd file */
        !           774:     if (pw == NULL && (pw = sudo_getpwnam(user)) == NULL)
        !           775:        return(FALSE);
        !           776:
        !           777:     if ((grp = sudo_getgrnam(group)) == NULL)
        !           778:        return(FALSE);
        !           779:
        !           780:     /* check against user's primary (passwd file) gid */
        !           781:     if (grp->gr_gid == pw->pw_gid)
        !           782:        return(TRUE);
        !           783:
        !           784:     /*
        !           785:      * If we are matching the invoking or list user and that user has a
        !           786:      * supplementary group vector, check it first.
        !           787:      */
        !           788:     if (strcmp(user, list_pw ? list_pw->pw_name : user_name) == 0) {
        !           789:        for (i = 0; i < user_ngroups; i++)
        !           790:            if (grp->gr_gid == user_groups[i])
        !           791:                return(TRUE);
        !           792:     }
        !           793:     if (grp->gr_mem != NULL) {
        !           794:        for (cur = grp->gr_mem; *cur; cur++)
        !           795:            if (strcmp(*cur, user) == 0)
        !           796:                return(TRUE);
        !           797:     }
        !           798:
        !           799:     return(FALSE);
        !           800: }
        !           801:
        !           802: /*
        !           803:  * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
        !           804:  * else return FALSE.  Either of "host", "shost" or "user" may be NULL
        !           805:  * in which case that argument is not checked...
        !           806:  *
        !           807:  * XXX - swap order of host & shost
        !           808:  */
        !           809: int
        !           810: netgr_matches(netgr, lhost, shost, user)
        !           811:     char *netgr;
        !           812:     char *lhost;
        !           813:     char *shost;
        !           814:     char *user;
        !           815: {
        !           816:     static char *domain;
        !           817: #ifdef HAVE_GETDOMAINNAME
        !           818:     static int initialized;
        !           819: #endif
        !           820:
        !           821:     /* make sure we have a valid netgroup, sudo style */
        !           822:     if (*netgr++ != '+')
        !           823:        return(FALSE);
        !           824:
        !           825: #ifdef HAVE_GETDOMAINNAME
        !           826:     /* get the domain name (if any) */
        !           827:     if (!initialized) {
        !           828:        domain = (char *) emalloc(MAXHOSTNAMELEN + 1);
        !           829:        if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') {
        !           830:            efree(domain);
        !           831:            domain = NULL;
        !           832:        }
        !           833:        initialized = 1;
        !           834:     }
        !           835: #endif /* HAVE_GETDOMAINNAME */
        !           836:
        !           837: #ifdef HAVE_INNETGR
        !           838:     if (innetgr(netgr, lhost, user, domain))
        !           839:        return(TRUE);
        !           840:     else if (lhost != shost && innetgr(netgr, shost, user, domain))
        !           841:        return(TRUE);
        !           842: #endif /* HAVE_INNETGR */
        !           843:
        !           844:     return(FALSE);
        !           845: }