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