version 1.1.1.3, 2012/10/09 09:29:52
|
version 1.1.1.4, 2013/07/22 10:46:12
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 2004-2005, 2007-2012 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2004-2005, 2007-2013 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
Line 19
|
Line 19
|
#include <config.h> |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
|
#include <stdio.h> |
#include <stdio.h> |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
# include <stdlib.h> |
# include <stdlib.h> |
Line 48
|
Line 47
|
#include <gram.h> |
#include <gram.h> |
|
|
/* Characters that must be quoted in sudoers */ |
/* Characters that must be quoted in sudoers */ |
#define SUDOERS_QUOTED ":\\,=#\"" | #define SUDOERS_QUOTED ":\\,=#\"" |
|
|
/* sudoers nsswitch routines */ |
/* sudoers nsswitch routines */ |
struct sudo_nss sudo_nss_file = { |
struct sudo_nss sudo_nss_file = { |
Line 68 struct sudo_nss sudo_nss_file = {
|
Line 67 struct sudo_nss sudo_nss_file = {
|
/* |
/* |
* Parser externs. |
* Parser externs. |
*/ |
*/ |
extern FILE *yyin; | extern FILE *sudoersin; |
extern char *errorfile; |
extern char *errorfile; |
extern int errorlineno; |
extern int errorlineno; |
extern bool parse_error; |
extern bool parse_error; |
Line 76 extern bool parse_error;
|
Line 75 extern bool parse_error;
|
/* |
/* |
* Local prototypes. |
* Local prototypes. |
*/ |
*/ |
static void print_member(struct lbuf *, char *, int, int, int); | static int display_bound_defaults(int dtype, struct lbuf *lbuf); |
static int display_bound_defaults(int, struct lbuf *); | static void print_member(struct lbuf *lbuf, struct member *m, int alias_type); |
| static void print_member2(struct lbuf *lbuf, struct member *m, |
| const char *separator, int alias_type); |
|
|
int |
int |
sudo_file_open(struct sudo_nss *nss) |
sudo_file_open(struct sudo_nss *nss) |
Line 100 sudo_file_close(struct sudo_nss *nss)
|
Line 101 sudo_file_close(struct sudo_nss *nss)
|
if (nss->handle != NULL) { |
if (nss->handle != NULL) { |
fclose(nss->handle); |
fclose(nss->handle); |
nss->handle = NULL; |
nss->handle = NULL; |
yyin = NULL; | sudoersin = NULL; |
} |
} |
debug_return_int(0); |
debug_return_int(0); |
} |
} |
Line 117 sudo_file_parse(struct sudo_nss *nss)
|
Line 118 sudo_file_parse(struct sudo_nss *nss)
|
debug_return_int(-1); |
debug_return_int(-1); |
|
|
init_parser(sudoers_file, false); |
init_parser(sudoers_file, false); |
yyin = nss->handle; | sudoersin = nss->handle; |
if (yyparse() != 0 || parse_error) { | if (sudoersparse() != 0 || parse_error) { |
if (errorlineno != -1) { |
if (errorlineno != -1) { |
log_error(0, _("parse error in %s near line %d"), | log_warning(0, N_("parse error in %s near line %d"), |
errorfile, errorlineno); |
errorfile, errorlineno); |
} else { |
} else { |
log_error(0, _("parse error in %s"), errorfile); | log_warning(0, N_("parse error in %s"), errorfile); |
} |
} |
debug_return_int(-1); |
debug_return_int(-1); |
} |
} |
Line 290 sudo_file_lookup(struct sudo_nss *nss, int validated,
|
Line 291 sudo_file_lookup(struct sudo_nss *nss, int validated,
|
debug_return_int(validated); |
debug_return_int(validated); |
} |
} |
|
|
|
#define TAG_SET(tt) \ |
|
((tt) != UNSPEC && (tt) != IMPLIED) |
|
|
#define TAG_CHANGED(t) \ |
#define TAG_CHANGED(t) \ |
(cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t) | (TAG_SET(cs->tags.t) && cs->tags.t != tags->t) |
|
|
static void |
static void |
sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags, |
sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags, |
struct lbuf *lbuf) |
struct lbuf *lbuf) |
{ |
{ |
struct member *m; |
|
debug_decl(sudo_file_append_cmnd, SUDO_DEBUG_NSS) |
debug_decl(sudo_file_append_cmnd, SUDO_DEBUG_NSS) |
|
|
#ifdef HAVE_PRIV_SET |
#ifdef HAVE_PRIV_SET |
Line 332 sudo_file_append_cmnd(struct cmndspec *cs, struct cmnd
|
Line 335 sudo_file_append_cmnd(struct cmndspec *cs, struct cmnd
|
lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: "); |
lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: "); |
tags->log_output = cs->tags.log_output; |
tags->log_output = cs->tags.log_output; |
} |
} |
m = cs->cmnd; | print_member(lbuf, cs->cmnd, CMNDALIAS); |
print_member(lbuf, m->name, m->type, m->negated, | |
CMNDALIAS); | |
debug_return; |
debug_return; |
} |
} |
|
|
|
#define RUNAS_CHANGED(cs1, cs2) \ |
|
(cs1 == NULL || cs2 == NULL || \ |
|
cs1->runasuserlist.first != cs2->runasuserlist.first || \ |
|
cs1->runasuserlist.last != cs2->runasuserlist.last || \ |
|
cs1->runasgrouplist.first != cs2->runasgrouplist.first || \ |
|
cs1->runasgrouplist.last != cs2->runasgrouplist.last) |
|
|
static int |
static int |
sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, |
sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, |
struct lbuf *lbuf) |
struct lbuf *lbuf) |
{ |
{ |
struct cmndspec *cs; | struct cmndspec *cs, *prev_cs; |
struct member *m; |
struct member *m; |
struct privilege *priv; |
struct privilege *priv; |
struct cmndtag tags; |
struct cmndtag tags; |
int nfound = 0; |
int nfound = 0; |
debug_decl(sudo_file_display_priv_short, SUDO_DEBUG_NSS) |
debug_decl(sudo_file_display_priv_short, SUDO_DEBUG_NSS) |
|
|
|
/* gcc -Wuninitialized false positive */ |
|
tags.noexec = UNSPEC; |
|
tags.setenv = UNSPEC; |
|
tags.nopasswd = UNSPEC; |
|
tags.log_input = UNSPEC; |
|
tags.log_output = UNSPEC; |
tq_foreach_fwd(&us->privileges, priv) { |
tq_foreach_fwd(&us->privileges, priv) { |
if (hostlist_matches(&priv->hostlist) != ALLOW) |
if (hostlist_matches(&priv->hostlist) != ALLOW) |
continue; |
continue; |
tags.noexec = UNSPEC; | prev_cs = NULL; |
tags.setenv = UNSPEC; | |
tags.nopasswd = UNSPEC; | |
tags.log_input = UNSPEC; | |
tags.log_output = UNSPEC; | |
lbuf_append(lbuf, " "); | |
tq_foreach_fwd(&priv->cmndlist, cs) { |
tq_foreach_fwd(&priv->cmndlist, cs) { |
if (cs != tq_first(&priv->cmndlist)) | if (RUNAS_CHANGED(cs, prev_cs)) { |
lbuf_append(lbuf, ", "); | if (cs != tq_first(&priv->cmndlist)) |
lbuf_append(lbuf, "("); | lbuf_append(lbuf, "\n"); |
if (!tq_empty(&cs->runasuserlist)) { | lbuf_append(lbuf, " ("); |
tq_foreach_fwd(&cs->runasuserlist, m) { | if (!tq_empty(&cs->runasuserlist)) { |
if (m != tq_first(&cs->runasuserlist)) | tq_foreach_fwd(&cs->runasuserlist, m) { |
lbuf_append(lbuf, ", "); | if (m != tq_first(&cs->runasuserlist)) |
print_member(lbuf, m->name, m->type, m->negated, | lbuf_append(lbuf, ", "); |
RUNASALIAS); | print_member(lbuf, m, RUNASALIAS); |
| } |
| } else if (tq_empty(&cs->runasgrouplist)) { |
| lbuf_append(lbuf, "%s", def_runas_default); |
| } else { |
| lbuf_append(lbuf, "%s", pw->pw_name); |
} |
} |
} else if (tq_empty(&cs->runasgrouplist)) { | if (!tq_empty(&cs->runasgrouplist)) { |
lbuf_append(lbuf, "%s", def_runas_default); | lbuf_append(lbuf, " : "); |
} else { | tq_foreach_fwd(&cs->runasgrouplist, m) { |
lbuf_append(lbuf, "%s", pw->pw_name); | if (m != tq_first(&cs->runasgrouplist)) |
} | lbuf_append(lbuf, ", "); |
if (!tq_empty(&cs->runasgrouplist)) { | print_member(lbuf, m, RUNASALIAS); |
lbuf_append(lbuf, " : "); | } |
tq_foreach_fwd(&cs->runasgrouplist, m) { | |
if (m != tq_first(&cs->runasgrouplist)) | |
lbuf_append(lbuf, ", "); | |
print_member(lbuf, m->name, m->type, m->negated, | |
RUNASALIAS); | |
} |
} |
|
lbuf_append(lbuf, ") "); |
|
tags.noexec = UNSPEC; |
|
tags.setenv = UNSPEC; |
|
tags.nopasswd = UNSPEC; |
|
tags.log_input = UNSPEC; |
|
tags.log_output = UNSPEC; |
|
} else if (cs != tq_first(&priv->cmndlist)) { |
|
lbuf_append(lbuf, ", "); |
} |
} |
lbuf_append(lbuf, ") "); |
|
sudo_file_append_cmnd(cs, &tags, lbuf); |
sudo_file_append_cmnd(cs, &tags, lbuf); |
|
prev_cs = cs; |
nfound++; |
nfound++; |
} |
} |
lbuf_append(lbuf, "\n"); |
lbuf_append(lbuf, "\n"); |
Line 392 sudo_file_display_priv_short(struct passwd *pw, struct
|
Line 409 sudo_file_display_priv_short(struct passwd *pw, struct
|
debug_return_int(nfound); |
debug_return_int(nfound); |
} |
} |
|
|
|
#define TAGS_CHANGED(ot, nt) \ |
|
((TAG_SET((nt).setenv) && (nt).setenv != (ot).setenv) || \ |
|
(TAG_SET((nt).noexec) && (nt).noexec != (ot).noexec) || \ |
|
(TAG_SET((nt).nopasswd) && (nt).nopasswd != (ot).nopasswd) || \ |
|
(TAG_SET((nt).log_input) && (nt).log_input != (ot).log_input) || \ |
|
(TAG_SET((nt).log_output) && (nt).log_output != (ot).log_output)) |
|
|
|
/* |
|
* Compare the current cmndspec with the previous one to determine |
|
* whether we need to start a new long entry for "sudo -ll". |
|
* Returns true if we should start a new long entry, else false. |
|
*/ |
|
static bool |
|
new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs) |
|
{ |
|
if (prev_cs == NULL) |
|
return true; |
|
if (RUNAS_CHANGED(cs, prev_cs) || TAGS_CHANGED(cs->tags, prev_cs->tags)) |
|
return true; |
|
#ifdef HAVE_PRIV_SET |
|
if (cs->privs && (!prev_cs->privs || strcmp(cs->privs, prev_cs->privs) != 0)) |
|
return true; |
|
if (cs->limitprivs && (!prev_cs->limitprivs || strcmp(cs->limitprivs, prev_cs->limitprivs) != 0)) |
|
return true; |
|
#endif /* HAVE_PRIV_SET */ |
|
#ifdef HAVE_SELINUX |
|
if (cs->role && (!prev_cs->role || strcmp(cs->role, prev_cs->role) != 0)) |
|
return true; |
|
if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0)) |
|
return true; |
|
#endif /* HAVE_SELINUX */ |
|
return false; |
|
} |
|
|
static int |
static int |
sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, |
sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, |
struct lbuf *lbuf) |
struct lbuf *lbuf) |
{ |
{ |
struct cmndspec *cs; | struct cmndspec *cs, *prev_cs; |
struct member *m; |
struct member *m; |
struct privilege *priv; |
struct privilege *priv; |
struct cmndtag tags; | int nfound = 0, olen; |
int nfound = 0; | |
debug_decl(sudo_file_display_priv_long, SUDO_DEBUG_NSS) |
debug_decl(sudo_file_display_priv_long, SUDO_DEBUG_NSS) |
|
|
tq_foreach_fwd(&us->privileges, priv) { |
tq_foreach_fwd(&us->privileges, priv) { |
if (hostlist_matches(&priv->hostlist) != ALLOW) |
if (hostlist_matches(&priv->hostlist) != ALLOW) |
continue; |
continue; |
tags.noexec = UNSPEC; | prev_cs = NULL; |
tags.setenv = UNSPEC; | |
tags.nopasswd = UNSPEC; | |
tags.log_input = UNSPEC; | |
tags.log_output = UNSPEC; | |
lbuf_append(lbuf, _("\nSudoers entry:\n")); | |
tq_foreach_fwd(&priv->cmndlist, cs) { |
tq_foreach_fwd(&priv->cmndlist, cs) { |
lbuf_append(lbuf, _(" RunAsUsers: ")); | if (new_long_entry(cs, prev_cs)) { |
if (!tq_empty(&cs->runasuserlist)) { | lbuf_append(lbuf, _("\nSudoers entry:\n")); |
tq_foreach_fwd(&cs->runasuserlist, m) { | lbuf_append(lbuf, _(" RunAsUsers: ")); |
if (m != tq_first(&cs->runasuserlist)) | if (!tq_empty(&cs->runasuserlist)) { |
lbuf_append(lbuf, ", "); | tq_foreach_fwd(&cs->runasuserlist, m) { |
print_member(lbuf, m->name, m->type, m->negated, | if (m != tq_first(&cs->runasuserlist)) |
RUNASALIAS); | lbuf_append(lbuf, ", "); |
| print_member(lbuf, m, RUNASALIAS); |
| } |
| } else if (tq_empty(&cs->runasgrouplist)) { |
| lbuf_append(lbuf, "%s", def_runas_default); |
| } else { |
| lbuf_append(lbuf, "%s", pw->pw_name); |
} |
} |
} else if (tq_empty(&cs->runasgrouplist)) { |
|
lbuf_append(lbuf, "%s", def_runas_default); |
|
} else { |
|
lbuf_append(lbuf, "%s", pw->pw_name); |
|
} |
|
lbuf_append(lbuf, "\n"); |
|
if (!tq_empty(&cs->runasgrouplist)) { |
|
lbuf_append(lbuf, _(" RunAsGroups: ")); |
|
tq_foreach_fwd(&cs->runasgrouplist, m) { |
|
if (m != tq_first(&cs->runasgrouplist)) |
|
lbuf_append(lbuf, ", "); |
|
print_member(lbuf, m->name, m->type, m->negated, |
|
RUNASALIAS); |
|
} |
|
lbuf_append(lbuf, "\n"); |
lbuf_append(lbuf, "\n"); |
|
if (!tq_empty(&cs->runasgrouplist)) { |
|
lbuf_append(lbuf, _(" RunAsGroups: ")); |
|
tq_foreach_fwd(&cs->runasgrouplist, m) { |
|
if (m != tq_first(&cs->runasgrouplist)) |
|
lbuf_append(lbuf, ", "); |
|
print_member(lbuf, m, RUNASALIAS); |
|
} |
|
lbuf_append(lbuf, "\n"); |
|
} |
|
olen = lbuf->len; |
|
lbuf_append(lbuf, _(" Options: ")); |
|
if (TAG_SET(cs->tags.setenv)) |
|
lbuf_append(lbuf, "%ssetenv, ", cs->tags.setenv ? "" : "!"); |
|
if (TAG_SET(cs->tags.noexec)) |
|
lbuf_append(lbuf, "%snoexec, ", cs->tags.noexec ? "" : "!"); |
|
if (TAG_SET(cs->tags.nopasswd)) |
|
lbuf_append(lbuf, "%sauthenticate, ", cs->tags.nopasswd ? "!" : ""); |
|
if (TAG_SET(cs->tags.log_input)) |
|
lbuf_append(lbuf, "%slog_input, ", cs->tags.log_input ? "" : "!"); |
|
if (TAG_SET(cs->tags.log_output)) |
|
lbuf_append(lbuf, "%slog_output, ", cs->tags.log_output ? "" : "!"); |
|
if (lbuf->buf[lbuf->len - 2] == ',') { |
|
lbuf->len -= 2; /* remove trailing ", " */ |
|
lbuf_append(lbuf, "\n"); |
|
} else { |
|
lbuf->len = olen; /* no options */ |
|
} |
|
#ifdef HAVE_PRIV_SET |
|
if (cs->privs) |
|
lbuf_append(lbuf, " Privs: %s\n", cs->privs); |
|
if (cs->limitprivs) |
|
lbuf_append(lbuf, " Limitprivs: %s\n", cs->limitprivs); |
|
#endif /* HAVE_PRIV_SET */ |
|
#ifdef HAVE_SELINUX |
|
if (cs->role) |
|
lbuf_append(lbuf, " Role: %s\n", cs->role); |
|
if (cs->type) |
|
lbuf_append(lbuf, " Type: %s\n", cs->type); |
|
#endif /* HAVE_SELINUX */ |
|
lbuf_append(lbuf, _(" Commands:\n")); |
} |
} |
lbuf_append(lbuf, _(" Commands:\n\t")); | lbuf_append(lbuf, "\t"); |
sudo_file_append_cmnd(cs, &tags, lbuf); | print_member2(lbuf, cs->cmnd, "\n\t", CMNDALIAS); |
lbuf_append(lbuf, "\n"); |
lbuf_append(lbuf, "\n"); |
|
prev_cs = cs; |
nfound++; |
nfound++; |
} |
} |
} |
} |
Line 585 display_bound_defaults(int dtype, struct lbuf *lbuf)
|
Line 663 display_bound_defaults(int dtype, struct lbuf *lbuf)
|
for (m = binding; m != NULL; m = m->next) { |
for (m = binding; m != NULL; m = m->next) { |
if (m != binding) |
if (m != binding) |
lbuf_append(lbuf, ","); |
lbuf_append(lbuf, ","); |
print_member(lbuf, m->name, m->type, m->negated, atype); | print_member(lbuf, m, atype); |
lbuf_append(lbuf, " "); |
lbuf_append(lbuf, " "); |
} |
} |
} else |
} else |
Line 651 done:
|
Line 729 done:
|
*/ |
*/ |
static void |
static void |
_print_member(struct lbuf *lbuf, char *name, int type, int negated, |
_print_member(struct lbuf *lbuf, char *name, int type, int negated, |
int alias_type) | const char *separator, int alias_type) |
{ |
{ |
struct alias *a; |
struct alias *a; |
struct member *m; |
struct member *m; |
Line 676 _print_member(struct lbuf *lbuf, char *name, int type,
|
Line 754 _print_member(struct lbuf *lbuf, char *name, int type,
|
} |
} |
break; |
break; |
case ALIAS: |
case ALIAS: |
if ((a = alias_find(name, alias_type)) != NULL) { | if ((a = alias_get(name, alias_type)) != NULL) { |
tq_foreach_fwd(&a->members, m) { |
tq_foreach_fwd(&a->members, m) { |
if (m != tq_first(&a->members)) |
if (m != tq_first(&a->members)) |
lbuf_append(lbuf, ", "); | lbuf_append(lbuf, "%s", separator); |
_print_member(lbuf, m->name, m->type, |
_print_member(lbuf, m->name, m->type, |
negated ? !m->negated : m->negated, alias_type); | negated ? !m->negated : m->negated, separator, |
| alias_type); |
} |
} |
|
alias_put(a); |
break; |
break; |
} |
} |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
Line 694 _print_member(struct lbuf *lbuf, char *name, int type,
|
Line 774 _print_member(struct lbuf *lbuf, char *name, int type,
|
} |
} |
|
|
static void |
static void |
print_member(struct lbuf *lbuf, char *name, int type, int negated, | print_member(struct lbuf *lbuf, struct member *m, int alias_type) |
| { |
| _print_member(lbuf, m->name, m->type, m->negated, ", ", alias_type); |
| } |
| |
| static void |
| print_member2(struct lbuf *lbuf, struct member *m, const char *separator, |
int alias_type) |
int alias_type) |
{ |
{ |
alias_seqno++; | _print_member(lbuf, m->name, m->type, m->negated, separator, alias_type); |
_print_member(lbuf, name, type, negated, alias_type); | |
} |
} |