~ubuntu-branches/ubuntu/quantal/sudo/quantal

« back to all changes in this revision

Viewing changes to plugins/sudoers/parse.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-11-20 12:07:45 UTC
  • mfrom: (1.3.17 sid)
  • Revision ID: package-import@ubuntu.com-20111120120745-o3qpklobmygytndc
Tags: 1.8.3p1-1ubuntu1
* Merge from debian/testing, remaining changes:
  - debian/patches/keep_home_by_default.patch:
    + Set HOME in initial_keepenv_table. (rebased for 1.8.3p1)
  - debian/patches/enable_badpass.patch: turn on "mail_badpass" by default:
    + attempting sudo without knowing a login password is as bad as not
      being listed in the sudoers file, especially if getting the password
      wrong means doing the access-check-email-notification never happens
      (rebased for 1.8.3p1)
  - debian/rules:
    + compile with --without-lecture --with-tty-tickets (Ubuntu specific)
    + install man/man8/sudo_root.8 (Ubuntu specific)
    + install apport hooks
    + The ubuntu-sudo-as-admin-successful.patch was taken upstream by
      Debian however it requires a --enable-admin-flag configure flag to
      actually enable it.
  - debian/sudoers: 
    + grant admin group sudo access
  - debian/sudo-ldap.dirs, debian/sudo.dirs: 
    + add usr/share/apport/package-hooks
  - debian/sudo.preinst:
    + avoid conffile prompt by checking for known default /etc/sudoers
      and if found installing the correct default /etc/sudoers file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2004-2005, 2007-2011 Todd C. Miller <Todd.Miller@courtesan.com>
 
3
 *
 
4
 * Permission to use, copy, modify, and distribute this software for any
 
5
 * purpose with or without fee is hereby granted, provided that the above
 
6
 * copyright notice and this permission notice appear in all copies.
 
7
 *
 
8
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 
9
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 
10
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 
11
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
12
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
13
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 
14
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
15
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
16
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
17
 */
 
18
 
 
19
#include <config.h>
 
20
 
 
21
#include <sys/types.h>
 
22
#include <sys/param.h>
 
23
#include <stdio.h>
 
24
#ifdef STDC_HEADERS
 
25
# include <stdlib.h>
 
26
# include <stddef.h>
 
27
#else
 
28
# ifdef HAVE_STDLIB_H
 
29
#  include <stdlib.h>
 
30
# endif
 
31
#endif /* STDC_HEADERS */
 
32
#ifdef HAVE_STRING_H
 
33
# include <string.h>
 
34
#endif /* HAVE_STRING_H */
 
35
#ifdef HAVE_STRINGS_H
 
36
# include <strings.h>
 
37
#endif /* HAVE_STRINGS_H */
 
38
#ifdef HAVE_UNISTD_H
 
39
# include <unistd.h>
 
40
#endif /* HAVE_UNISTD_H */
 
41
#include <ctype.h>
 
42
#include <pwd.h>
 
43
#include <grp.h>
 
44
 
 
45
#include "sudoers.h"
 
46
#include "parse.h"
 
47
#include "lbuf.h"
 
48
#include <gram.h>
 
49
 
 
50
/* Characters that must be quoted in sudoers */
 
51
#define SUDOERS_QUOTED  ":\\,=#\""
 
52
 
 
53
/* sudoers nsswitch routines */
 
54
struct sudo_nss sudo_nss_file = {
 
55
    &sudo_nss_file,
 
56
    NULL,
 
57
    sudo_file_open,
 
58
    sudo_file_close,
 
59
    sudo_file_parse,
 
60
    sudo_file_setdefs,
 
61
    sudo_file_lookup,
 
62
    sudo_file_display_cmnd,
 
63
    sudo_file_display_defaults,
 
64
    sudo_file_display_bound_defaults,
 
65
    sudo_file_display_privs
 
66
};
 
67
 
 
68
/*
 
69
 * Parser externs.
 
70
 */
 
71
extern FILE *yyin;
 
72
extern char *errorfile;
 
73
extern int errorlineno, parse_error;
 
74
 
 
75
/*
 
76
 * Local prototypes.
 
77
 */
 
78
static void print_member(struct lbuf *, char *, int, int, int);
 
79
static int display_bound_defaults(int, struct lbuf *);
 
80
 
 
81
int
 
82
sudo_file_open(struct sudo_nss *nss)
 
83
{
 
84
    if (def_ignore_local_sudoers)
 
85
        return -1;
 
86
    nss->handle = open_sudoers(sudoers_file, FALSE, NULL);
 
87
    return nss->handle ? 0 : -1;
 
88
}
 
89
 
 
90
int
 
91
sudo_file_close(struct sudo_nss *nss)
 
92
{
 
93
    /* Free parser data structures and close sudoers file. */
 
94
    init_parser(NULL, 0);
 
95
    if (nss->handle != NULL) {
 
96
        fclose(nss->handle);
 
97
        nss->handle = NULL;
 
98
        yyin = NULL;
 
99
    }
 
100
    return 0;
 
101
}
 
102
 
 
103
/*
 
104
 * Parse the specified sudoers file.
 
105
 */
 
106
int
 
107
sudo_file_parse(struct sudo_nss *nss)
 
108
{
 
109
    if (nss->handle == NULL)
 
110
        return -1;
 
111
 
 
112
    init_parser(sudoers_file, 0);
 
113
    yyin = nss->handle;
 
114
    if (yyparse() != 0 || parse_error) {
 
115
        log_error(NO_EXIT, _("parse error in %s near line %d"),
 
116
            errorfile, errorlineno);
 
117
        return -1;
 
118
    }
 
119
    return 0;
 
120
}
 
121
 
 
122
/*
 
123
 * Wrapper around update_defaults() for nsswitch code.
 
124
 */
 
125
int
 
126
sudo_file_setdefs(struct sudo_nss *nss)
 
127
{
 
128
    if (nss->handle == NULL)
 
129
        return -1;
 
130
 
 
131
    if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
 
132
        return -1;
 
133
    return 0;
 
134
}
 
135
 
 
136
/*
 
137
 * Look up the user in the parsed sudoers file and check to see if they are
 
138
 * allowed to run the specified command on this host as the target user.
 
139
 */
 
140
int
 
141
sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
 
142
{
 
143
    int match, host_match, runas_match, cmnd_match;
 
144
    struct cmndspec *cs;
 
145
    struct cmndtag *tags = NULL;
 
146
    struct privilege *priv;
 
147
    struct userspec *us;
 
148
 
 
149
    if (nss->handle == NULL)
 
150
        return validated;
 
151
 
 
152
    /*
 
153
     * Only check the actual command if pwflag is not set.
 
154
     * It is set for the "validate", "list" and "kill" pseudo-commands.
 
155
     * Always check the host and user.
 
156
     */
 
157
    if (pwflag) {
 
158
        int nopass;
 
159
        enum def_tuple pwcheck;
 
160
 
 
161
        pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
 
162
        nopass = (pwcheck == all) ? TRUE : FALSE;
 
163
 
 
164
        if (list_pw == NULL)
 
165
            SET(validated, FLAG_NO_CHECK);
 
166
        CLR(validated, FLAG_NO_USER);
 
167
        CLR(validated, FLAG_NO_HOST);
 
168
        match = DENY;
 
169
        tq_foreach_fwd(&userspecs, us) {
 
170
            if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
 
171
                continue;
 
172
            tq_foreach_fwd(&us->privileges, priv) {
 
173
                if (hostlist_matches(&priv->hostlist) != ALLOW)
 
174
                    continue;
 
175
                tq_foreach_fwd(&priv->cmndlist, cs) {
 
176
                    /* Only check the command when listing another user. */
 
177
                    if (user_uid == 0 || list_pw == NULL ||
 
178
                        user_uid == list_pw->pw_uid ||
 
179
                        cmnd_matches(cs->cmnd) == ALLOW)
 
180
                            match = ALLOW;
 
181
                    if ((pwcheck == any && cs->tags.nopasswd == TRUE) ||
 
182
                        (pwcheck == all && cs->tags.nopasswd != TRUE))
 
183
                        nopass = cs->tags.nopasswd;
 
184
                }
 
185
            }
 
186
        }
 
187
        if (match == ALLOW || user_uid == 0) {
 
188
            /* User has an entry for this host. */
 
189
            SET(validated, VALIDATE_OK);
 
190
        } else if (match == DENY)
 
191
            SET(validated, VALIDATE_NOT_OK);
 
192
        if (pwcheck == always && def_authenticate)
 
193
            SET(validated, FLAG_CHECK_USER);
 
194
        else if (pwcheck == never || nopass == TRUE)
 
195
            def_authenticate = FALSE;
 
196
        return validated;
 
197
    }
 
198
 
 
199
    /* Need to be runas user while stat'ing things. */
 
200
    set_perms(PERM_RUNAS);
 
201
 
 
202
    match = UNSPEC;
 
203
    tq_foreach_rev(&userspecs, us) {
 
204
        if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
 
205
            continue;
 
206
        CLR(validated, FLAG_NO_USER);
 
207
        tq_foreach_rev(&us->privileges, priv) {
 
208
            host_match = hostlist_matches(&priv->hostlist);
 
209
            if (host_match == ALLOW)
 
210
                CLR(validated, FLAG_NO_HOST);
 
211
            else
 
212
                continue;
 
213
            tq_foreach_rev(&priv->cmndlist, cs) {
 
214
                runas_match = runaslist_matches(&cs->runasuserlist,
 
215
                    &cs->runasgrouplist);
 
216
                if (runas_match == ALLOW) {
 
217
                    cmnd_match = cmnd_matches(cs->cmnd);
 
218
                    if (cmnd_match != UNSPEC) {
 
219
                        match = cmnd_match;
 
220
                        tags = &cs->tags;
 
221
#ifdef HAVE_SELINUX
 
222
                        /* Set role and type if not specified on command line. */
 
223
                        if (user_role == NULL)
 
224
                            user_role = cs->role ? estrdup(cs->role) : def_role;
 
225
                        if (user_type == NULL)
 
226
                            user_type = cs->type ? estrdup(cs->type) : def_type;
 
227
#endif /* HAVE_SELINUX */
 
228
                        goto matched2;
 
229
                    }
 
230
                }
 
231
            }
 
232
        }
 
233
    }
 
234
    matched2:
 
235
    if (match == ALLOW) {
 
236
        SET(validated, VALIDATE_OK);
 
237
        CLR(validated, VALIDATE_NOT_OK);
 
238
        if (tags != NULL) {
 
239
            if (tags->nopasswd != UNSPEC)
 
240
                def_authenticate = !tags->nopasswd;
 
241
            if (tags->noexec != UNSPEC)
 
242
                def_noexec = tags->noexec;
 
243
            if (tags->setenv != UNSPEC)
 
244
                def_setenv = tags->setenv;
 
245
            if (tags->log_input != UNSPEC)
 
246
                def_log_input = tags->log_input;
 
247
            if (tags->log_output != UNSPEC)
 
248
                def_log_output = tags->log_output;
 
249
        }
 
250
    } else if (match == DENY) {
 
251
        SET(validated, VALIDATE_NOT_OK);
 
252
        CLR(validated, VALIDATE_OK);
 
253
        if (tags != NULL && tags->nopasswd != UNSPEC)
 
254
            def_authenticate = !tags->nopasswd;
 
255
    }
 
256
    restore_perms();
 
257
    return validated;
 
258
}
 
259
 
 
260
#define TAG_CHANGED(t) \
 
261
        (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t)
 
262
 
 
263
static void
 
264
sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
 
265
    struct lbuf *lbuf)
 
266
{
 
267
    struct member *m;
 
268
 
 
269
#ifdef HAVE_SELINUX
 
270
    if (cs->role)
 
271
        lbuf_append(lbuf, "ROLE=%s ", cs->role);
 
272
    if (cs->type)
 
273
        lbuf_append(lbuf, "TYPE=%s ", cs->type);
 
274
#endif /* HAVE_SELINUX */
 
275
    if (TAG_CHANGED(setenv)) {
 
276
        lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : "NOSETENV: ");
 
277
        tags->setenv = cs->tags.setenv;
 
278
    }
 
279
    if (TAG_CHANGED(noexec)) {
 
280
        lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " : "EXEC: ");
 
281
        tags->noexec = cs->tags.noexec;
 
282
    }
 
283
    if (TAG_CHANGED(nopasswd)) {
 
284
        lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " : "PASSWD: ");
 
285
        tags->nopasswd = cs->tags.nopasswd;
 
286
    }
 
287
    if (TAG_CHANGED(log_input)) {
 
288
        lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " : "NOLOG_INPUT: ");
 
289
        tags->log_input = cs->tags.log_input;
 
290
    }
 
291
    if (TAG_CHANGED(log_output)) {
 
292
        lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: ");
 
293
        tags->log_output = cs->tags.log_output;
 
294
    }
 
295
    m = cs->cmnd;
 
296
    print_member(lbuf, m->name, m->type, m->negated,
 
297
        CMNDALIAS);
 
298
}
 
299
 
 
300
static int
 
301
sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
 
302
    struct lbuf *lbuf)
 
303
{
 
304
    struct cmndspec *cs;
 
305
    struct member *m;
 
306
    struct privilege *priv;
 
307
    struct cmndtag tags;
 
308
    int nfound = 0;
 
309
 
 
310
    tq_foreach_fwd(&us->privileges, priv) {
 
311
        if (hostlist_matches(&priv->hostlist) != ALLOW)
 
312
            continue;
 
313
        tags.noexec = UNSPEC;
 
314
        tags.setenv = UNSPEC;
 
315
        tags.nopasswd = UNSPEC;
 
316
        tags.log_input = UNSPEC;
 
317
        tags.log_output = UNSPEC;
 
318
        lbuf_append(lbuf, "    ");
 
319
        tq_foreach_fwd(&priv->cmndlist, cs) {
 
320
            if (cs != tq_first(&priv->cmndlist))
 
321
                lbuf_append(lbuf, ", ");
 
322
            lbuf_append(lbuf, "(");
 
323
            if (!tq_empty(&cs->runasuserlist)) {
 
324
                tq_foreach_fwd(&cs->runasuserlist, m) {
 
325
                    if (m != tq_first(&cs->runasuserlist))
 
326
                        lbuf_append(lbuf, ", ");
 
327
                    print_member(lbuf, m->name, m->type, m->negated,
 
328
                        RUNASALIAS);
 
329
                }
 
330
            } else if (tq_empty(&cs->runasgrouplist)) {
 
331
                lbuf_append(lbuf, "%s", def_runas_default);
 
332
            } else {
 
333
                lbuf_append(lbuf, "%s", pw->pw_name);
 
334
            }
 
335
            if (!tq_empty(&cs->runasgrouplist)) {
 
336
                lbuf_append(lbuf, " : ");
 
337
                tq_foreach_fwd(&cs->runasgrouplist, m) {
 
338
                    if (m != tq_first(&cs->runasgrouplist))
 
339
                        lbuf_append(lbuf, ", ");
 
340
                    print_member(lbuf, m->name, m->type, m->negated,
 
341
                        RUNASALIAS);
 
342
                }
 
343
            }
 
344
            lbuf_append(lbuf, ") ");
 
345
            sudo_file_append_cmnd(cs, &tags, lbuf);
 
346
            nfound++;
 
347
        }
 
348
        lbuf_append(lbuf, "\n");
 
349
    }
 
350
    return nfound;
 
351
}
 
352
 
 
353
static int
 
354
sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
 
355
    struct lbuf *lbuf)
 
356
{
 
357
    struct cmndspec *cs;
 
358
    struct member *m;
 
359
    struct privilege *priv;
 
360
    struct cmndtag tags;
 
361
    int nfound = 0;
 
362
 
 
363
    tq_foreach_fwd(&us->privileges, priv) {
 
364
        if (hostlist_matches(&priv->hostlist) != ALLOW)
 
365
            continue;
 
366
        tags.noexec = UNSPEC;
 
367
        tags.setenv = UNSPEC;
 
368
        tags.nopasswd = UNSPEC;
 
369
        tags.log_input = UNSPEC;
 
370
        tags.log_output = UNSPEC;
 
371
        lbuf_append(lbuf, _("\nSudoers entry:\n"));
 
372
        tq_foreach_fwd(&priv->cmndlist, cs) {
 
373
            lbuf_append(lbuf, _("    RunAsUsers: "));
 
374
            if (!tq_empty(&cs->runasuserlist)) {
 
375
                tq_foreach_fwd(&cs->runasuserlist, m) {
 
376
                    if (m != tq_first(&cs->runasuserlist))
 
377
                        lbuf_append(lbuf, ", ");
 
378
                    print_member(lbuf, m->name, m->type, m->negated,
 
379
                        RUNASALIAS);
 
380
                }
 
381
            } else if (tq_empty(&cs->runasgrouplist)) {
 
382
                lbuf_append(lbuf, "%s", def_runas_default);
 
383
            } else {
 
384
                lbuf_append(lbuf, "%s", pw->pw_name);
 
385
            }
 
386
            lbuf_append(lbuf, "\n");
 
387
            if (!tq_empty(&cs->runasgrouplist)) {
 
388
                lbuf_append(lbuf, _("    RunAsGroups: "));
 
389
                tq_foreach_fwd(&cs->runasgrouplist, m) {
 
390
                    if (m != tq_first(&cs->runasgrouplist))
 
391
                        lbuf_append(lbuf, ", ");
 
392
                    print_member(lbuf, m->name, m->type, m->negated,
 
393
                        RUNASALIAS);
 
394
                }
 
395
                lbuf_append(lbuf, "\n");
 
396
            }
 
397
            lbuf_append(lbuf, _("    Commands:\n\t"));
 
398
            sudo_file_append_cmnd(cs, &tags, lbuf);
 
399
            lbuf_append(lbuf, "\n");
 
400
            nfound++;
 
401
        }
 
402
    }
 
403
    return nfound;
 
404
}
 
405
 
 
406
int
 
407
sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw,
 
408
    struct lbuf *lbuf)
 
409
{
 
410
    struct userspec *us;
 
411
    int nfound = 0;
 
412
 
 
413
    if (nss->handle == NULL)
 
414
        goto done;
 
415
 
 
416
    tq_foreach_fwd(&userspecs, us) {
 
417
        if (userlist_matches(pw, &us->users) != ALLOW)
 
418
            continue;
 
419
 
 
420
        if (long_list)
 
421
            nfound += sudo_file_display_priv_long(pw, us, lbuf);
 
422
        else
 
423
            nfound += sudo_file_display_priv_short(pw, us, lbuf);
 
424
    }
 
425
done:
 
426
    return nfound;
 
427
}
 
428
 
 
429
/*
 
430
 * Display matching Defaults entries for the given user on this host.
 
431
 */
 
432
int
 
433
sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
 
434
    struct lbuf *lbuf)
 
435
{
 
436
    struct defaults *d;
 
437
    char *prefix;
 
438
    int nfound = 0;
 
439
 
 
440
    if (nss->handle == NULL)
 
441
        goto done;
 
442
 
 
443
    if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
 
444
        prefix = "    ";
 
445
    else
 
446
        prefix = ", ";
 
447
 
 
448
    tq_foreach_fwd(&defaults, d) {
 
449
        switch (d->type) {
 
450
            case DEFAULTS_HOST:
 
451
                if (hostlist_matches(&d->binding) != ALLOW)
 
452
                    continue;
 
453
                break;
 
454
            case DEFAULTS_USER:
 
455
                if (userlist_matches(pw, &d->binding) != ALLOW)
 
456
                    continue;
 
457
                break;
 
458
            case DEFAULTS_RUNAS:
 
459
            case DEFAULTS_CMND:
 
460
                continue;
 
461
        }
 
462
        if (d->val != NULL) {
 
463
            lbuf_append(lbuf, "%s%s%s", prefix, d->var,
 
464
                d->op == '+' ? "+=" : d->op == '-' ? "-=" : "=");
 
465
            if (strpbrk(d->val, " \t") != NULL) {
 
466
                lbuf_append(lbuf, "\"");
 
467
                lbuf_append_quoted(lbuf, "\"", "%s", d->val);
 
468
                lbuf_append(lbuf, "\"");
 
469
            } else
 
470
                lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", d->val);
 
471
        } else
 
472
            lbuf_append(lbuf, "%s%s%s", prefix,
 
473
                d->op == FALSE ? "!" : "", d->var);
 
474
        prefix = ", ";
 
475
        nfound++;
 
476
    }
 
477
done:
 
478
    return nfound;
 
479
}
 
480
 
 
481
/*
 
482
 * Display Defaults entries that are per-runas or per-command
 
483
 */
 
484
int
 
485
sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
 
486
    struct lbuf *lbuf)
 
487
{
 
488
    int nfound = 0;
 
489
 
 
490
    /* XXX - should only print ones that match what the user can do. */
 
491
    nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf);
 
492
    nfound += display_bound_defaults(DEFAULTS_CMND, lbuf);
 
493
 
 
494
    return nfound;
 
495
}
 
496
 
 
497
/*
 
498
 * Display Defaults entries of the given type.
 
499
 */
 
500
static int
 
501
display_bound_defaults(int dtype, struct lbuf *lbuf)
 
502
{
 
503
    struct defaults *d;
 
504
    struct member *m, *binding = NULL;
 
505
    char *dsep;
 
506
    int atype, nfound = 0;
 
507
 
 
508
    switch (dtype) {
 
509
        case DEFAULTS_HOST:
 
510
            atype = HOSTALIAS;
 
511
            dsep = "@";
 
512
            break;
 
513
        case DEFAULTS_USER:
 
514
            atype = USERALIAS;
 
515
            dsep = ":";
 
516
            break;
 
517
        case DEFAULTS_RUNAS:
 
518
            atype = RUNASALIAS;
 
519
            dsep = ">";
 
520
            break;
 
521
        case DEFAULTS_CMND:
 
522
            atype = CMNDALIAS;
 
523
            dsep = "!";
 
524
            break;
 
525
        default:
 
526
            return -1;
 
527
    }
 
528
    tq_foreach_fwd(&defaults, d) {
 
529
        if (d->type != dtype)
 
530
            continue;
 
531
 
 
532
        nfound++;
 
533
        if (binding != tq_first(&d->binding)) {
 
534
            binding = tq_first(&d->binding);
 
535
            if (nfound != 1)
 
536
                lbuf_append(lbuf, "\n");
 
537
            lbuf_append(lbuf, "    Defaults%s", dsep);
 
538
            for (m = binding; m != NULL; m = m->next) {
 
539
                if (m != binding)
 
540
                    lbuf_append(lbuf, ",");
 
541
                print_member(lbuf, m->name, m->type, m->negated, atype);
 
542
                lbuf_append(lbuf, " ");
 
543
            }
 
544
        } else
 
545
            lbuf_append(lbuf, ", ");
 
546
        if (d->val != NULL) {
 
547
            lbuf_append(lbuf, "%s%s%s", d->var, d->op == '+' ? "+=" :
 
548
                d->op == '-' ? "-=" : "=", d->val);
 
549
        } else
 
550
            lbuf_append(lbuf, "%s%s", d->op == FALSE ? "!" : "", d->var);
 
551
    }
 
552
 
 
553
    return nfound;
 
554
}
 
555
 
 
556
int
 
557
sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
 
558
{
 
559
    struct cmndspec *cs;
 
560
    struct member *match;
 
561
    struct privilege *priv;
 
562
    struct userspec *us;
 
563
    int rval = 1;
 
564
    int host_match, runas_match, cmnd_match;
 
565
 
 
566
    if (nss->handle == NULL)
 
567
        goto done;
 
568
 
 
569
    match = NULL;
 
570
    tq_foreach_rev(&userspecs, us) {
 
571
        if (userlist_matches(pw, &us->users) != ALLOW)
 
572
            continue;
 
573
 
 
574
        tq_foreach_rev(&us->privileges, priv) {
 
575
            host_match = hostlist_matches(&priv->hostlist);
 
576
            if (host_match != ALLOW)
 
577
                continue;
 
578
            tq_foreach_rev(&priv->cmndlist, cs) {
 
579
                runas_match = runaslist_matches(&cs->runasuserlist,
 
580
                    &cs->runasgrouplist);
 
581
                if (runas_match == ALLOW) {
 
582
                    cmnd_match = cmnd_matches(cs->cmnd);
 
583
                    if (cmnd_match != UNSPEC) {
 
584
                        match = host_match && runas_match ? cs->cmnd : NULL;
 
585
                        goto matched;
 
586
                    }
 
587
                }
 
588
            }
 
589
        }
 
590
    }
 
591
    matched:
 
592
    if (match != NULL && !match->negated) {
 
593
        sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
 
594
            safe_cmnd, user_args ? " " : "", user_args ? user_args : "");
 
595
        rval = 0;
 
596
    }
 
597
done:
 
598
    return rval;
 
599
}
 
600
 
 
601
/*
 
602
 * Print the contents of a struct member to stdout
 
603
 */
 
604
static void
 
605
_print_member(struct lbuf *lbuf, char *name, int type, int negated,
 
606
    int alias_type)
 
607
{
 
608
    struct alias *a;
 
609
    struct member *m;
 
610
    struct sudo_command *c;
 
611
 
 
612
    switch (type) {
 
613
        case ALL:
 
614
            lbuf_append(lbuf, "%sALL", negated ? "!" : "");
 
615
            break;
 
616
        case COMMAND:
 
617
            c = (struct sudo_command *) name;
 
618
            if (negated)
 
619
                lbuf_append(lbuf, "!");
 
620
            lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->cmnd);
 
621
            if (c->args) {
 
622
                lbuf_append(lbuf, " ");
 
623
                lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->args);
 
624
            }
 
625
            break;
 
626
        case ALIAS:
 
627
            if ((a = alias_find(name, alias_type)) != NULL) {
 
628
                tq_foreach_fwd(&a->members, m) {
 
629
                    if (m != tq_first(&a->members))
 
630
                        lbuf_append(lbuf, ", ");
 
631
                    _print_member(lbuf, m->name, m->type,
 
632
                        negated ? !m->negated : m->negated, alias_type);
 
633
                }
 
634
                break;
 
635
            }
 
636
            /* FALLTHROUGH */
 
637
        default:
 
638
            lbuf_append(lbuf, "%s%s", negated ? "!" : "", name);
 
639
            break;
 
640
    }
 
641
}
 
642
 
 
643
static void
 
644
print_member(struct lbuf *lbuf, char *name, int type, int negated,
 
645
    int alias_type)
 
646
{
 
647
    alias_seqno++;
 
648
    _print_member(lbuf, name, type, negated, alias_type);
 
649
}