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