fix for 596493 from upstream
[debian/sudo] / match.c
1 /*
2  * Copyright (c) 1996, 1998-2005, 2007-2010
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 (tq_empty(user_list) && tq_empty(group_list))
178         return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw));
179
180     if (runas_pw != NULL) {
181         tq_foreach_rev(user_list, m) {
182             switch (m->type) {
183                 case ALL:
184                     user_matched = !m->negated;
185                     break;
186                 case NETGROUP:
187                     if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
188                         user_matched = !m->negated;
189                     break;
190                 case USERGROUP:
191                     if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
192                         user_matched = !m->negated;
193                     break;
194                 case ALIAS:
195                     if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
196                         rval = _runaslist_matches(&a->members, &empty);
197                         if (rval != UNSPEC)
198                             user_matched = m->negated ? !rval : rval;
199                         break;
200                     }
201                     /* FALLTHROUGH */
202                 case WORD:
203                     if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
204                         user_matched = !m->negated;
205                     break;
206             }
207             if (user_matched != UNSPEC)
208                 break;
209         }
210     }
211
212     if (runas_gr != NULL) {
213         if (user_matched == UNSPEC) {
214             if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0)
215                 user_matched = ALLOW;   /* only changing group */
216         }
217         tq_foreach_rev(group_list, m) {
218             switch (m->type) {
219                 case ALL:
220                     group_matched = !m->negated;
221                     break;
222                 case ALIAS:
223                     if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
224                         rval = _runaslist_matches(&a->members, &empty);
225                         if (rval != UNSPEC)
226                             group_matched = m->negated ? !rval : rval;
227                         break;
228                     }
229                     /* FALLTHROUGH */
230                 case WORD:
231                     if (group_matches(m->name, runas_gr))
232                         group_matched = !m->negated;
233                     break;
234             }
235             if (group_matched != UNSPEC)
236                 break;
237         }
238     }
239
240     if (user_matched == DENY || group_matched == DENY)
241         return(DENY);
242     if (user_matched == group_matched || runas_gr == NULL)
243         return(user_matched);
244     return(UNSPEC);
245 }
246
247 int
248 runaslist_matches(user_list, group_list)
249     struct member_list *user_list;
250     struct member_list *group_list;
251 {
252     alias_seqno++;
253     return(_runaslist_matches(user_list ? user_list : &empty,
254         group_list ? group_list : &empty));
255 }
256
257 /*
258  * Check for host and shost in a list of members.
259  * Returns ALLOW, DENY or UNSPEC.
260  */
261 static int
262 _hostlist_matches(list)
263     struct member_list *list;
264 {
265     struct member *m;
266     struct alias *a;
267     int rval, matched = UNSPEC;
268
269     tq_foreach_rev(list, m) {
270         switch (m->type) {
271             case ALL:
272                 matched = !m->negated;
273                 break;
274             case NETGROUP:
275                 if (netgr_matches(m->name, user_host, user_shost, NULL))
276                     matched = !m->negated;
277                 break;
278             case NTWKADDR:
279                 if (addr_matches(m->name))
280                     matched = !m->negated;
281                 break;
282             case ALIAS:
283                 if ((a = alias_find(m->name, HOSTALIAS)) != NULL) {
284                     rval = _hostlist_matches(&a->members);
285                     if (rval != UNSPEC)
286                         matched = m->negated ? !rval : rval;
287                     break;
288                 }
289                 /* FALLTHROUGH */
290             case WORD:
291                 if (hostname_matches(user_shost, user_host, m->name))
292                     matched = !m->negated;
293                 break;
294         }
295         if (matched != UNSPEC)
296             break;
297     }
298     return(matched);
299 }
300
301 int
302 hostlist_matches(list)
303     struct member_list *list;
304 {
305     alias_seqno++;
306     return(_hostlist_matches(list));
307 }
308
309 /*
310  * Check for cmnd and args in a list of members.
311  * Returns ALLOW, DENY or UNSPEC.
312  */
313 static int
314 _cmndlist_matches(list)
315     struct member_list *list;
316 {
317     struct member *m;
318     int matched = UNSPEC;
319
320     tq_foreach_rev(list, m) {
321         matched = cmnd_matches(m);
322         if (matched != UNSPEC)
323             break;
324     }
325     return(matched);
326 }
327
328 int
329 cmndlist_matches(list)
330     struct member_list *list;
331 {
332     alias_seqno++;
333     return(_cmndlist_matches(list));
334 }
335
336 /*
337  * Check cmnd and args.
338  * Returns ALLOW, DENY or UNSPEC.
339  */
340 int
341 cmnd_matches(m)
342     struct member *m;
343 {
344     struct alias *a;
345     struct sudo_command *c;
346     int rval, matched = UNSPEC;
347
348     switch (m->type) {
349         case ALL:
350             matched = !m->negated;
351             break;
352         case ALIAS:
353             alias_seqno++;
354             if ((a = alias_find(m->name, CMNDALIAS)) != NULL) {
355                 rval = _cmndlist_matches(&a->members);
356                 if (rval != UNSPEC)
357                     matched = m->negated ? !rval : rval;
358             }
359             break;
360         case COMMAND:
361             c = (struct sudo_command *)m->name;
362             if (command_matches(c->cmnd, c->args))
363                 matched = !m->negated;
364             break;
365     }
366     return(matched);
367 }
368
369 /*
370  * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
371  * otherwise, return TRUE if user_cmnd names one of the inodes in path.
372  */
373 int
374 command_matches(sudoers_cmnd, sudoers_args)
375     char *sudoers_cmnd;
376     char *sudoers_args;
377 {
378     /* Check for pseudo-commands */
379     if (sudoers_cmnd[0] != '/') {
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
400     if (has_meta(sudoers_cmnd)) {
401         /*
402          * If sudoers_cmnd has meta characters in it, we need to
403          * use glob(3) and/or fnmatch(3) to do the matching.
404          */
405         if (def_fast_glob)
406             return(command_matches_fnmatch(sudoers_cmnd, sudoers_args));
407         return(command_matches_glob(sudoers_cmnd, sudoers_args));
408     }
409     return(command_matches_normal(sudoers_cmnd, sudoers_args));
410 }
411
412 static int
413 command_matches_fnmatch(sudoers_cmnd, sudoers_args)
414     char *sudoers_cmnd;
415     char *sudoers_args;
416 {
417     /*
418      * Return true if fnmatch(3) succeeds AND
419      *  a) there are no args in sudoers OR
420      *  b) there are no args on command line and none required by sudoers OR
421      *  c) there are args in sudoers and on command line and they match
422      * else return false.
423      */
424     if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
425         return(FALSE);
426     if (!sudoers_args ||
427         (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
428         (sudoers_args &&
429          fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
430         if (safe_cmnd)
431             free(safe_cmnd);
432         safe_cmnd = estrdup(user_cmnd);
433         return(TRUE);
434     } else
435         return(FALSE);
436 }
437
438 static int
439 command_matches_glob(sudoers_cmnd, sudoers_args)
440     char *sudoers_cmnd;
441     char *sudoers_args;
442 {
443     struct stat sudoers_stat;
444     size_t dlen;
445     char **ap, *base, *cp;
446     glob_t gl;
447
448     /*
449      * First check to see if we can avoid the call to glob(3).
450      * Short circuit if there are no meta chars in the command itself
451      * and user_base and basename(sudoers_cmnd) don't match.
452      */
453     dlen = strlen(sudoers_cmnd);
454     if (sudoers_cmnd[dlen - 1] != '/') {
455         if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
456             base++;
457             if (!has_meta(base) && strcmp(user_base, base) != 0)
458                 return(FALSE);
459         }
460     }
461     /*
462      * Return true if we find a match in the glob(3) results AND
463      *  a) there are no args in sudoers OR
464      *  b) there are no args on command line and none required by sudoers OR
465      *  c) there are args in sudoers and on command line and they match
466      * else return false.
467      */
468 #define GLOB_FLAGS      (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
469     if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0 || gl.gl_pathc == 0) {
470         globfree(&gl);
471         return(FALSE);
472     }
473     /* For each glob match, compare basename, st_dev and st_ino. */
474     for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
475         /* If it ends in '/' it is a directory spec. */
476         dlen = strlen(cp);
477         if (cp[dlen - 1] == '/') {
478             if (command_matches_dir(cp, dlen))
479                 return(TRUE);
480             continue;
481         }
482
483         /* Only proceed if user_base and basename(cp) match */
484         if ((base = strrchr(cp, '/')) != NULL)
485             base++;
486         else
487             base = cp;
488         if (strcmp(user_base, base) != 0 ||
489             stat(cp, &sudoers_stat) == -1)
490             continue;
491         if (user_stat == NULL ||
492             (user_stat->st_dev == sudoers_stat.st_dev &&
493             user_stat->st_ino == sudoers_stat.st_ino)) {
494             efree(safe_cmnd);
495             safe_cmnd = estrdup(cp);
496             break;
497         }
498     }
499     globfree(&gl);
500     if (cp == NULL)
501         return(FALSE);
502
503     if (!sudoers_args ||
504         (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
505         (sudoers_args &&
506          fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
507         efree(safe_cmnd);
508         safe_cmnd = estrdup(user_cmnd);
509         return(TRUE);
510     }
511     return(FALSE);
512 }
513
514 static int
515 command_matches_normal(sudoers_cmnd, sudoers_args)
516     char *sudoers_cmnd;
517     char *sudoers_args;
518 {
519     struct stat sudoers_stat;
520     char *base;
521     size_t dlen;
522
523     /* If it ends in '/' it is a directory spec. */
524     dlen = strlen(sudoers_cmnd);
525     if (sudoers_cmnd[dlen - 1] == '/')
526         return(command_matches_dir(sudoers_cmnd, dlen));
527
528     /* Only proceed if user_base and basename(sudoers_cmnd) match */
529     if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
530         base = sudoers_cmnd;
531     else
532         base++;
533     if (strcmp(user_base, base) != 0 ||
534         stat(sudoers_cmnd, &sudoers_stat) == -1)
535         return(FALSE);
536
537     /*
538      * Return true if inode/device matches AND
539      *  a) there are no args in sudoers OR
540      *  b) there are no args on command line and none req by sudoers OR
541      *  c) there are args in sudoers and on command line and they match
542      */
543     if (user_stat != NULL &&
544         (user_stat->st_dev != sudoers_stat.st_dev ||
545         user_stat->st_ino != sudoers_stat.st_ino))
546         return(FALSE);
547     if (!sudoers_args ||
548         (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
549         (sudoers_args &&
550          fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
551         efree(safe_cmnd);
552         safe_cmnd = estrdup(sudoers_cmnd);
553         return(TRUE);
554     }
555     return(FALSE);
556 }
557
558 /*
559  * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE.
560  */
561 static int
562 command_matches_dir(sudoers_dir, dlen)
563     char *sudoers_dir;
564     size_t dlen;
565 {
566     struct stat sudoers_stat;
567     struct dirent *dent;
568     char buf[PATH_MAX];
569     DIR *dirp;
570
571     /*
572      * Grot through directory entries, looking for user_base.
573      */
574     dirp = opendir(sudoers_dir);
575     if (dirp == NULL)
576         return(FALSE);
577
578     if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) {
579         closedir(dirp);
580         return(FALSE);
581     }
582     while ((dent = readdir(dirp)) != NULL) {
583         /* ignore paths > PATH_MAX (XXX - log) */
584         buf[dlen] = '\0';
585         if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
586             continue;
587
588         /* only stat if basenames are the same */
589         if (strcmp(user_base, dent->d_name) != 0 ||
590             stat(buf, &sudoers_stat) == -1)
591             continue;
592         if (user_stat->st_dev == sudoers_stat.st_dev &&
593             user_stat->st_ino == sudoers_stat.st_ino) {
594             efree(safe_cmnd);
595             safe_cmnd = estrdup(buf);
596             break;
597         }
598     }
599
600     closedir(dirp);
601     return(dent != NULL);
602 }
603
604 static int
605 addr_matches_if(n)
606     char *n;
607 {
608     int i;
609     union sudo_in_addr_un addr;
610     struct interface *ifp;
611 #ifdef HAVE_IN6_ADDR
612     int j;
613 #endif
614     int family;
615
616 #ifdef HAVE_IN6_ADDR
617     if (inet_pton(AF_INET6, n, &addr.ip6) > 0) {
618         family = AF_INET6;
619     } else
620 #endif
621     {
622         family = AF_INET;
623         addr.ip4.s_addr = inet_addr(n);
624     }
625
626     for (i = 0; i < num_interfaces; i++) {
627         ifp = &interfaces[i];
628         if (ifp->family != family)
629             continue;
630         switch(family) {
631             case AF_INET:
632                 if (ifp->addr.ip4.s_addr == addr.ip4.s_addr ||
633                     (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
634                     == addr.ip4.s_addr)
635                     return(TRUE);
636                 break;
637 #ifdef HAVE_IN6_ADDR
638             case AF_INET6:
639                 if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr,
640                     sizeof(addr.ip6.s6_addr)) == 0)
641                     return(TRUE);
642                 for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
643                     if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
644                         break;
645                 }
646                 if (j == sizeof(addr.ip6.s6_addr))
647                     return(TRUE);
648 #endif
649         }
650     }
651
652     return(FALSE);
653 }
654
655 static int
656 addr_matches_if_netmask(n, m)
657     char *n;
658     char *m;
659 {
660     int i;
661     union sudo_in_addr_un addr, mask;
662     struct interface *ifp;
663 #ifdef HAVE_IN6_ADDR
664     int j;
665 #endif
666     int family;
667
668 #ifdef HAVE_IN6_ADDR
669     if (inet_pton(AF_INET6, n, &addr.ip6) > 0)
670         family = AF_INET6;
671     else
672 #endif
673     {
674         family = AF_INET;
675         addr.ip4.s_addr = inet_addr(n);
676     }
677
678     if (family == AF_INET) {
679         if (strchr(m, '.'))
680             mask.ip4.s_addr = inet_addr(m);
681         else {
682             i = 32 - atoi(m);
683             mask.ip4.s_addr = 0xffffffff;
684             mask.ip4.s_addr >>= i;
685             mask.ip4.s_addr <<= i;
686             mask.ip4.s_addr = htonl(mask.ip4.s_addr);
687         }
688     }
689 #ifdef HAVE_IN6_ADDR
690     else {
691         if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) {
692             j = atoi(m);
693             for (i = 0; i < 16; i++) {
694                 if (j < i * 8)
695                     mask.ip6.s6_addr[i] = 0;
696                 else if (i * 8 + 8 <= j)
697                     mask.ip6.s6_addr[i] = 0xff;
698                 else
699                     mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8);
700             }
701         }
702     }
703 #endif /* HAVE_IN6_ADDR */
704
705     for (i = 0; i < num_interfaces; i++) {
706         ifp = &interfaces[i];
707         if (ifp->family != family)
708             continue;
709         switch(family) {
710             case AF_INET:
711                 if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr)
712                     return(TRUE);
713 #ifdef HAVE_IN6_ADDR
714             case AF_INET6:
715                 for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
716                     if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
717                         break;
718                 }
719                 if (j == sizeof(addr.ip6.s6_addr))
720                     return(TRUE);
721 #endif /* HAVE_IN6_ADDR */
722         }
723     }
724
725     return(FALSE);
726 }
727
728 /*
729  * Returns TRUE if "n" is one of our ip addresses or if
730  * "n" is a network that we are on, else returns FALSE.
731  */
732 int
733 addr_matches(n)
734     char *n;
735 {
736     char *m;
737     int retval;
738
739     /* If there's an explicit netmask, use it. */
740     if ((m = strchr(n, '/'))) {
741         *m++ = '\0';
742         retval = addr_matches_if_netmask(n, m);
743         *(m - 1) = '/';
744     } else
745         retval = addr_matches_if(n);
746
747     return(retval);
748 }
749
750 /*
751  * Returns TRUE if the hostname matches the pattern, else FALSE
752  */
753 int
754 hostname_matches(shost, lhost, pattern)
755     char *shost;
756     char *lhost;
757     char *pattern;
758 {
759     if (has_meta(pattern)) {
760         if (strchr(pattern, '.'))
761             return(!fnmatch(pattern, lhost, FNM_CASEFOLD));
762         else
763             return(!fnmatch(pattern, shost, FNM_CASEFOLD));
764     } else {
765         if (strchr(pattern, '.'))
766             return(!strcasecmp(lhost, pattern));
767         else
768             return(!strcasecmp(shost, pattern));
769     }
770 }
771
772 /*
773  *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
774  *  else returns FALSE.
775  */
776 int
777 userpw_matches(sudoers_user, user, pw)
778     char *sudoers_user;
779     char *user;
780     struct passwd *pw;
781 {
782     if (pw != NULL && *sudoers_user == '#') {
783         uid_t uid = (uid_t) atoi(sudoers_user + 1);
784         if (uid == pw->pw_uid)
785             return(TRUE);
786     }
787     return(strcmp(sudoers_user, user) == 0);
788 }
789
790 /*
791  *  Returns TRUE if the group/gid from sudoers matches the specified group/gid,
792  *  else returns FALSE.
793  */
794 int
795 group_matches(sudoers_group, gr)
796     char *sudoers_group;
797     struct group *gr;
798 {
799     if (*sudoers_group == '#') {
800         gid_t gid = (gid_t) atoi(sudoers_group + 1);
801         if (gid == gr->gr_gid)
802             return(TRUE);
803     }
804     return(strcmp(gr->gr_name, sudoers_group) == 0);
805 }
806
807 /*
808  *  Returns TRUE if the given user belongs to the named group,
809  *  else returns FALSE.
810  */
811 int
812 usergr_matches(group, user, pw)
813     char *group;
814     char *user;
815     struct passwd *pw;
816 {
817     /* make sure we have a valid usergroup, sudo style */
818     if (*group++ != '%')
819         return(FALSE);
820
821 #ifdef USING_NONUNIX_GROUPS
822     if (*group == ':')
823         return(sudo_nonunix_groupcheck(++group, user, pw));   
824 #endif /* USING_NONUNIX_GROUPS */
825
826     /* look up user's primary gid in the passwd file */
827     if (pw == NULL && (pw = sudo_getpwnam(user)) == NULL)
828         return(FALSE);
829
830     if (user_in_group(pw, group))
831         return(TRUE);
832
833 #ifdef USING_NONUNIX_GROUPS
834     /* not a Unix group, could be an AD group */
835     if (sudo_nonunix_groupcheck_available() &&
836         sudo_nonunix_groupcheck(group, user, pw))
837         return(TRUE);
838 #endif /* USING_NONUNIX_GROUPS */
839
840     return(FALSE);
841 }
842
843 /*
844  * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
845  * else return FALSE.  Either of "host", "shost" or "user" may be NULL
846  * in which case that argument is not checked...
847  *
848  * XXX - swap order of host & shost
849  */
850 int
851 netgr_matches(netgr, lhost, shost, user)
852     char *netgr;
853     char *lhost;
854     char *shost;
855     char *user;
856 {
857     static char *domain;
858 #ifdef HAVE_GETDOMAINNAME
859     static int initialized;
860 #endif
861
862     /* make sure we have a valid netgroup, sudo style */
863     if (*netgr++ != '+')
864         return(FALSE);
865
866 #ifdef HAVE_GETDOMAINNAME
867     /* get the domain name (if any) */
868     if (!initialized) {
869         domain = (char *) emalloc(MAXHOSTNAMELEN + 1);
870         if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') {
871             efree(domain);
872             domain = NULL;
873         }
874         initialized = 1;
875     }
876 #endif /* HAVE_GETDOMAINNAME */
877
878 #ifdef HAVE_INNETGR
879     if (innetgr(netgr, lhost, user, domain))
880         return(TRUE);
881     else if (lhost != shost && innetgr(netgr, shost, user, domain))
882         return(TRUE);
883 #endif /* HAVE_INNETGR */
884
885     return(FALSE);
886 }