~ubuntu-branches/ubuntu/oneiric/sudo/oneiric-security

« back to all changes in this revision

Viewing changes to .pc/CVE-2012-2337.patch/match.c

  • Committer: Package Import Robot
  • Author(s): Tyler Hicks
  • Date: 2012-05-15 23:28:04 UTC
  • Revision ID: package-import@ubuntu.com-20120515232804-2rd0d4k222la647h
Tags: 1.7.4p6-1ubuntu2.1
* SECURITY UPDATE: Properly handle multiple netmasks in sudoers Host and
  Host_List values
  - debian/patches/CVE-2012-2337.patch: Don't perform IPv6 checks on IPv4
    addresses. Based on upstream patch.
  - CVE-2012-2337

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}