Imported Upstream version 1.7.4p6
[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 (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 /*
371  * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
372  * otherwise, return TRUE if user_cmnd names one of the inodes in path.
373  */
374 int
375 command_matches(sudoers_cmnd, sudoers_args)
376     char *sudoers_cmnd;
377     char *sudoers_args;
378 {
379     /* Check for pseudo-commands */
380     if (sudoers_cmnd[0] != '/') {
381         /*
382          * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
383          *  a) there are no args in sudoers OR
384          *  b) there are no args on command line and none req by sudoers OR
385          *  c) there are args in sudoers and on command line and they match
386          */
387         if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
388             strcmp(user_cmnd, "sudoedit") != 0)
389             return(FALSE);
390         if (!sudoers_args ||
391             (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
392             (sudoers_args &&
393              fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
394             efree(safe_cmnd);
395             safe_cmnd = estrdup(sudoers_cmnd);
396             return(TRUE);
397         } else
398             return(FALSE);
399     }
400
401     if (has_meta(sudoers_cmnd)) {
402         /*
403          * If sudoers_cmnd has meta characters in it, we need to
404          * use glob(3) and/or fnmatch(3) to do the matching.
405          */
406         if (def_fast_glob)
407             return(command_matches_fnmatch(sudoers_cmnd, sudoers_args));
408         return(command_matches_glob(sudoers_cmnd, sudoers_args));
409     }
410     return(command_matches_normal(sudoers_cmnd, sudoers_args));
411 }
412
413 static int
414 command_matches_fnmatch(sudoers_cmnd, sudoers_args)
415     char *sudoers_cmnd;
416     char *sudoers_args;
417 {
418     /*
419      * Return true if fnmatch(3) succeeds 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     if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
426         return(FALSE);
427     if (!sudoers_args ||
428         (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
429         (sudoers_args &&
430          fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
431         if (safe_cmnd)
432             free(safe_cmnd);
433         safe_cmnd = estrdup(user_cmnd);
434         return(TRUE);
435     } else
436         return(FALSE);
437 }
438
439 static int
440 command_matches_glob(sudoers_cmnd, sudoers_args)
441     char *sudoers_cmnd;
442     char *sudoers_args;
443 {
444     struct stat sudoers_stat;
445     size_t dlen;
446     char **ap, *base, *cp;
447     glob_t gl;
448
449     /*
450      * First check to see if we can avoid the call to glob(3).
451      * Short circuit if there are no meta chars in the command itself
452      * and user_base and basename(sudoers_cmnd) don't match.
453      */
454     dlen = strlen(sudoers_cmnd);
455     if (sudoers_cmnd[dlen - 1] != '/') {
456         if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
457             base++;
458             if (!has_meta(base) && strcmp(user_base, base) != 0)
459                 return(FALSE);
460         }
461     }
462     /*
463      * Return true if we find a match in the glob(3) results AND
464      *  a) there are no args in sudoers OR
465      *  b) there are no args on command line and none required by sudoers OR
466      *  c) there are args in sudoers and on command line and they match
467      * else return false.
468      */
469 #define GLOB_FLAGS      (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
470     if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0 || gl.gl_pathc == 0) {
471         globfree(&gl);
472         return(FALSE);
473     }
474     /* For each glob match, compare basename, st_dev and st_ino. */
475     for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
476         /* If it ends in '/' it is a directory spec. */
477         dlen = strlen(cp);
478         if (cp[dlen - 1] == '/') {
479             if (command_matches_dir(cp, dlen))
480                 return(TRUE);
481             continue;
482         }
483
484         /* Only proceed if user_base and basename(cp) match */
485         if ((base = strrchr(cp, '/')) != NULL)
486             base++;
487         else
488             base = cp;
489         if (strcmp(user_base, base) != 0 ||
490             stat(cp, &sudoers_stat) == -1)
491             continue;
492         if (user_stat == NULL ||
493             (user_stat->st_dev == sudoers_stat.st_dev &&
494             user_stat->st_ino == sudoers_stat.st_ino)) {
495             efree(safe_cmnd);
496             safe_cmnd = estrdup(cp);
497             break;
498         }
499     }
500     globfree(&gl);
501     if (cp == NULL)
502         return(FALSE);
503
504     if (!sudoers_args ||
505         (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
506         (sudoers_args &&
507          fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
508         efree(safe_cmnd);
509         safe_cmnd = estrdup(user_cmnd);
510         return(TRUE);
511     }
512     return(FALSE);
513 }
514
515 static int
516 command_matches_normal(sudoers_cmnd, sudoers_args)
517     char *sudoers_cmnd;
518     char *sudoers_args;
519 {
520     struct stat sudoers_stat;
521     char *base;
522     size_t dlen;
523
524     /* If it ends in '/' it is a directory spec. */
525     dlen = strlen(sudoers_cmnd);
526     if (sudoers_cmnd[dlen - 1] == '/')
527         return(command_matches_dir(sudoers_cmnd, dlen));
528
529     /* Only proceed if user_base and basename(sudoers_cmnd) match */
530     if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
531         base = sudoers_cmnd;
532     else
533         base++;
534     if (strcmp(user_base, base) != 0 ||
535         stat(sudoers_cmnd, &sudoers_stat) == -1)
536         return(FALSE);
537
538     /*
539      * Return true if inode/device matches AND
540      *  a) there are no args in sudoers OR
541      *  b) there are no args on command line and none req by sudoers OR
542      *  c) there are args in sudoers and on command line and they match
543      */
544     if (user_stat != NULL &&
545         (user_stat->st_dev != sudoers_stat.st_dev ||
546         user_stat->st_ino != sudoers_stat.st_ino))
547         return(FALSE);
548     if (!sudoers_args ||
549         (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
550         (sudoers_args &&
551          fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
552         efree(safe_cmnd);
553         safe_cmnd = estrdup(sudoers_cmnd);
554         return(TRUE);
555     }
556     return(FALSE);
557 }
558
559 /*
560  * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE.
561  */
562 static int
563 command_matches_dir(sudoers_dir, dlen)
564     char *sudoers_dir;
565     size_t dlen;
566 {
567     struct stat sudoers_stat;
568     struct dirent *dent;
569     char buf[PATH_MAX];
570     DIR *dirp;
571
572     /*
573      * Grot through directory entries, looking for user_base.
574      */
575     dirp = opendir(sudoers_dir);
576     if (dirp == NULL)
577         return(FALSE);
578
579     if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) {
580         closedir(dirp);
581         return(FALSE);
582     }
583     while ((dent = readdir(dirp)) != NULL) {
584         /* ignore paths > PATH_MAX (XXX - log) */
585         buf[dlen] = '\0';
586         if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
587             continue;
588
589         /* only stat if basenames are the same */
590         if (strcmp(user_base, dent->d_name) != 0 ||
591             stat(buf, &sudoers_stat) == -1)
592             continue;
593         if (user_stat->st_dev == sudoers_stat.st_dev &&
594             user_stat->st_ino == sudoers_stat.st_ino) {
595             efree(safe_cmnd);
596             safe_cmnd = estrdup(buf);
597             break;
598         }
599     }
600
601     closedir(dirp);
602     return(dent != NULL);
603 }
604
605 static int
606 addr_matches_if(n)
607     char *n;
608 {
609     int i;
610     union sudo_in_addr_un addr;
611     struct interface *ifp;
612 #ifdef HAVE_IN6_ADDR
613     int j;
614 #endif
615     int family;
616
617 #ifdef HAVE_IN6_ADDR
618     if (inet_pton(AF_INET6, n, &addr.ip6) > 0) {
619         family = AF_INET6;
620     } else
621 #endif
622     {
623         family = AF_INET;
624         addr.ip4.s_addr = inet_addr(n);
625     }
626
627     for (i = 0; i < num_interfaces; i++) {
628         ifp = &interfaces[i];
629         if (ifp->family != family)
630             continue;
631         switch(family) {
632             case AF_INET:
633                 if (ifp->addr.ip4.s_addr == addr.ip4.s_addr ||
634                     (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
635                     == addr.ip4.s_addr)
636                     return(TRUE);
637                 break;
638 #ifdef HAVE_IN6_ADDR
639             case AF_INET6:
640                 if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr,
641                     sizeof(addr.ip6.s6_addr)) == 0)
642                     return(TRUE);
643                 for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
644                     if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
645                         break;
646                 }
647                 if (j == sizeof(addr.ip6.s6_addr))
648                     return(TRUE);
649 #endif
650         }
651     }
652
653     return(FALSE);
654 }
655
656 static int
657 addr_matches_if_netmask(n, m)
658     char *n;
659     char *m;
660 {
661     int i;
662     union sudo_in_addr_un addr, mask;
663     struct interface *ifp;
664 #ifdef HAVE_IN6_ADDR
665     int j;
666 #endif
667     int family;
668
669 #ifdef HAVE_IN6_ADDR
670     if (inet_pton(AF_INET6, n, &addr.ip6) > 0)
671         family = AF_INET6;
672     else
673 #endif
674     {
675         family = AF_INET;
676         addr.ip4.s_addr = inet_addr(n);
677     }
678
679     if (family == AF_INET) {
680         if (strchr(m, '.'))
681             mask.ip4.s_addr = inet_addr(m);
682         else {
683             i = 32 - atoi(m);
684             mask.ip4.s_addr = 0xffffffff;
685             mask.ip4.s_addr >>= i;
686             mask.ip4.s_addr <<= i;
687             mask.ip4.s_addr = htonl(mask.ip4.s_addr);
688         }
689     }
690 #ifdef HAVE_IN6_ADDR
691     else {
692         if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) {
693             j = atoi(m);
694             for (i = 0; i < 16; i++) {
695                 if (j < i * 8)
696                     mask.ip6.s6_addr[i] = 0;
697                 else if (i * 8 + 8 <= j)
698                     mask.ip6.s6_addr[i] = 0xff;
699                 else
700                     mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8);
701             }
702         }
703     }
704 #endif /* HAVE_IN6_ADDR */
705
706     for (i = 0; i < num_interfaces; i++) {
707         ifp = &interfaces[i];
708         if (ifp->family != family)
709             continue;
710         switch(family) {
711             case AF_INET:
712                 if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr)
713                     return(TRUE);
714 #ifdef HAVE_IN6_ADDR
715             case AF_INET6:
716                 for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
717                     if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
718                         break;
719                 }
720                 if (j == sizeof(addr.ip6.s6_addr))
721                     return(TRUE);
722 #endif /* HAVE_IN6_ADDR */
723         }
724     }
725
726     return(FALSE);
727 }
728
729 /*
730  * Returns TRUE if "n" is one of our ip addresses or if
731  * "n" is a network that we are on, else returns FALSE.
732  */
733 int
734 addr_matches(n)
735     char *n;
736 {
737     char *m;
738     int retval;
739
740     /* If there's an explicit netmask, use it. */
741     if ((m = strchr(n, '/'))) {
742         *m++ = '\0';
743         retval = addr_matches_if_netmask(n, m);
744         *(m - 1) = '/';
745     } else
746         retval = addr_matches_if(n);
747
748     return(retval);
749 }
750
751 /*
752  * Returns TRUE if the hostname matches the pattern, else FALSE
753  */
754 int
755 hostname_matches(shost, lhost, pattern)
756     char *shost;
757     char *lhost;
758     char *pattern;
759 {
760     if (has_meta(pattern)) {
761         if (strchr(pattern, '.'))
762             return(!fnmatch(pattern, lhost, FNM_CASEFOLD));
763         else
764             return(!fnmatch(pattern, shost, FNM_CASEFOLD));
765     } else {
766         if (strchr(pattern, '.'))
767             return(!strcasecmp(lhost, pattern));
768         else
769             return(!strcasecmp(shost, pattern));
770     }
771 }
772
773 /*
774  *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
775  *  else returns FALSE.
776  */
777 int
778 userpw_matches(sudoers_user, user, pw)
779     char *sudoers_user;
780     char *user;
781     struct passwd *pw;
782 {
783     if (pw != NULL && *sudoers_user == '#') {
784         uid_t uid = (uid_t) atoi(sudoers_user + 1);
785         if (uid == pw->pw_uid)
786             return(TRUE);
787     }
788     return(strcmp(sudoers_user, user) == 0);
789 }
790
791 /*
792  *  Returns TRUE if the group/gid from sudoers matches the specified group/gid,
793  *  else returns FALSE.
794  */
795 int
796 group_matches(sudoers_group, gr)
797     char *sudoers_group;
798     struct group *gr;
799 {
800     if (*sudoers_group == '#') {
801         gid_t gid = (gid_t) atoi(sudoers_group + 1);
802         if (gid == gr->gr_gid)
803             return(TRUE);
804     }
805     return(strcmp(gr->gr_name, sudoers_group) == 0);
806 }
807
808 /*
809  *  Returns TRUE if the given user belongs to the named group,
810  *  else returns FALSE.
811  */
812 int
813 usergr_matches(group, user, pw)
814     char *group;
815     char *user;
816     struct passwd *pw;
817 {
818     /* make sure we have a valid usergroup, sudo style */
819     if (*group++ != '%')
820         return(FALSE);
821
822 #ifdef USING_NONUNIX_GROUPS
823     if (*group == ':')
824         return(sudo_nonunix_groupcheck(++group, user, pw));   
825 #endif /* USING_NONUNIX_GROUPS */
826
827     /* look up user's primary gid in the passwd file */
828     if (pw == NULL && (pw = sudo_getpwnam(user)) == NULL)
829         return(FALSE);
830
831     if (user_in_group(pw, group))
832         return(TRUE);
833
834 #ifdef USING_NONUNIX_GROUPS
835     /* not a Unix group, could be an AD group */
836     if (sudo_nonunix_groupcheck_available() &&
837         sudo_nonunix_groupcheck(group, user, pw))
838         return(TRUE);
839 #endif /* USING_NONUNIX_GROUPS */
840
841     return(FALSE);
842 }
843
844 /*
845  * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
846  * else return FALSE.  Either of "host", "shost" or "user" may be NULL
847  * in which case that argument is not checked...
848  *
849  * XXX - swap order of host & shost
850  */
851 int
852 netgr_matches(netgr, lhost, shost, user)
853     char *netgr;
854     char *lhost;
855     char *shost;
856     char *user;
857 {
858     static char *domain;
859 #ifdef HAVE_GETDOMAINNAME
860     static int initialized;
861 #endif
862
863     /* make sure we have a valid netgroup, sudo style */
864     if (*netgr++ != '+')
865         return(FALSE);
866
867 #ifdef HAVE_GETDOMAINNAME
868     /* get the domain name (if any) */
869     if (!initialized) {
870         domain = (char *) emalloc(MAXHOSTNAMELEN + 1);
871         if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') {
872             efree(domain);
873             domain = NULL;
874         }
875         initialized = 1;
876     }
877 #endif /* HAVE_GETDOMAINNAME */
878
879 #ifdef HAVE_INNETGR
880     if (innetgr(netgr, lhost, user, domain))
881         return(TRUE);
882     else if (lhost != shost && innetgr(netgr, shost, user, domain))
883         return(TRUE);
884 #endif /* HAVE_INNETGR */
885
886     return(FALSE);
887 }