Move list manipulation macros to list.h and create C versions of
the more complex ones in list.c. The names have been down-cased so they appear more like normal functions.
This commit is contained in:
28
Makefile.in
28
Makefile.in
@@ -113,15 +113,15 @@ AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
|
|||||||
auth/sudo_auth.c
|
auth/sudo_auth.c
|
||||||
|
|
||||||
HDRS = compat.h def_data.h defaults.h error.h ins_2001.h ins_classic.h \
|
HDRS = compat.h def_data.h defaults.h error.h ins_2001.h ins_classic.h \
|
||||||
ins_csops.h ins_goons.h insults.h interfaces.h lbuf.h logging.h parse.h \
|
ins_csops.h ins_goons.h insults.h interfaces.h lbuf.h list.h \
|
||||||
sudo.h gram.h version.h auth/sudo_auth.h emul/fnmatch.h emul/utime.h \
|
logging.h parse.h sudo.h gram.h version.h auth/sudo_auth.h \
|
||||||
redblack.h
|
emul/fnmatch.h emul/utime.h redblack.h
|
||||||
|
|
||||||
AUTH_OBJS = sudo_auth.o @AUTH_OBJS@
|
AUTH_OBJS = sudo_auth.o @AUTH_OBJS@
|
||||||
|
|
||||||
# Note: gram.o must come first here
|
# Note: gram.o must come first here
|
||||||
COMMON_OBJS = gram.o alias.o alloc.o defaults.o error.o match.o toke.o \
|
COMMON_OBJS = gram.o alias.o alloc.o defaults.o error.o list.o match.o \
|
||||||
redblack.o zero_bytes.o
|
toke.o redblack.o zero_bytes.o
|
||||||
|
|
||||||
SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ check.o env.o \
|
SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ check.o env.o \
|
||||||
getspwuid.o gettime.o goodpath.o fileops.o find_path.o \
|
getspwuid.o gettime.o goodpath.o fileops.o find_path.o \
|
||||||
@@ -214,7 +214,7 @@ $(devdir)/toke.c: $(srcdir)/toke.l
|
|||||||
@DEV@ perl $(srcdir)/mkdefaults -o def_data $(srcdir)/def_data.in
|
@DEV@ perl $(srcdir)/mkdefaults -o def_data $(srcdir)/def_data.in
|
||||||
|
|
||||||
# Dependencies (not counting auth functions)
|
# Dependencies (not counting auth functions)
|
||||||
alias.o: $(srcdir)/alias.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/redblack.h
|
alias.o: $(srcdir)/alias.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/redblack.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alias.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alias.c
|
||||||
alloc.o: $(srcdir)/alloc.c $(SUDODEP)
|
alloc.o: $(srcdir)/alloc.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alloc.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alloc.c
|
||||||
@@ -248,17 +248,19 @@ glob.o: $(srcdir)/glob.c $(srcdir)/emul/glob.h $(srcdir)/compat.h config.h
|
|||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/glob.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/glob.c
|
||||||
goodpath.o: $(srcdir)/goodpath.c $(SUDODEP)
|
goodpath.o: $(srcdir)/goodpath.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/goodpath.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/goodpath.c
|
||||||
gram.o: $(devdir)/gram.c $(SUDODEP) $(srcdir)/parse.h $(devdir)/gram.h
|
gram.o: $(devdir)/gram.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/gram.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/gram.c
|
||||||
interfaces.o: $(srcdir)/interfaces.c $(SUDODEP) $(srcdir)/interfaces.h
|
interfaces.o: $(srcdir)/interfaces.c $(SUDODEP) $(srcdir)/interfaces.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/interfaces.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/interfaces.c
|
||||||
ldap.o: $(srcdir)/ldap.c $(SUDODEP) $(srcdir)/parse.h
|
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/ldap.c
|
|
||||||
lbuf.o: $(srcdir)/lbuf.c $(SUDODEP)
|
lbuf.o: $(srcdir)/lbuf.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/lbuf.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/lbuf.c
|
||||||
|
ldap.o: $(srcdir)/ldap.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/ldap.c
|
||||||
|
list.o: $(srcdir)/list.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/list.c
|
||||||
logging.o: $(srcdir)/logging.c $(SUDODEP)
|
logging.o: $(srcdir)/logging.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/logging.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/logging.c
|
||||||
match.o: $(srcdir)/match.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/interfaces.h $(devdir)/gram.h
|
match.o: $(srcdir)/match.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/match.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/match.c
|
||||||
memrchr.o: $(srcdir)/memrchr.c $(SUDODEP)
|
memrchr.o: $(srcdir)/memrchr.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/memrchr.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/memrchr.c
|
||||||
@@ -266,7 +268,7 @@ mkstemp.o: $(srcdir)/mkstemp.c $(SUDODEP)
|
|||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mkstemp.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mkstemp.c
|
||||||
mon_solaris.o: $(srcdir)/mon_solaris.c $(SUDODEP) $(srcdir)/mon_solaris.h
|
mon_solaris.o: $(srcdir)/mon_solaris.c $(SUDODEP) $(srcdir)/mon_solaris.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mon_solaris.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mon_solaris.c
|
||||||
parse.o: $(srcdir)/parse.c $(SUDODEP) $(srcdir)/parse.h $(devdir)/gram.h
|
parse.o: $(srcdir)/parse.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/parse.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/parse.c
|
||||||
pwutil.o: $(srcdir)/pwutil.c $(SUDODEP)
|
pwutil.o: $(srcdir)/pwutil.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/pwutil.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/pwutil.c
|
||||||
@@ -292,11 +294,11 @@ sudo_edit.o: $(srcdir)/sudo_edit.c $(SUDODEP)
|
|||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_edit.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_edit.c
|
||||||
sudo_noexec.o: $(srcdir)/sudo_noexec.c $(srcdir)/compat.h config.h
|
sudo_noexec.o: $(srcdir)/sudo_noexec.c $(srcdir)/compat.h config.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
|
||||||
testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/interfaces.h $(devdir)/gram.h
|
testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c
|
||||||
tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)
|
tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tgetpass.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tgetpass.c
|
||||||
toke.o: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(devdir)/gram.h
|
toke.o: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/toke.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/toke.c
|
||||||
tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(SUDODEP)
|
tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(SUDODEP)
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tsgetgrpw.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tsgetgrpw.c
|
||||||
|
2
alias.c
2
alias.c
@@ -114,7 +114,7 @@ alias_add(name, type, members)
|
|||||||
a = emalloc(sizeof(*a));
|
a = emalloc(sizeof(*a));
|
||||||
a->name = name;
|
a->name = name;
|
||||||
a->type = type;
|
a->type = type;
|
||||||
LIST2HEAD(a->members, members);
|
list2head(&a->members, members);
|
||||||
if (rbinsert(aliases, a)) {
|
if (rbinsert(aliases, a)) {
|
||||||
efree(a);
|
efree(a);
|
||||||
snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name);
|
snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name);
|
||||||
|
@@ -501,7 +501,7 @@ update_defaults(skip_cmnd)
|
|||||||
{
|
{
|
||||||
struct defaults *def;
|
struct defaults *def;
|
||||||
|
|
||||||
LH_FOREACH_FWD(&defaults, def) {
|
lh_foreach_fwd(&defaults, def) {
|
||||||
if (skip_cmnd == (def->type == DEFAULTS_CMND))
|
if (skip_cmnd == (def->type == DEFAULTS_CMND))
|
||||||
continue;
|
continue;
|
||||||
switch (def->type) {
|
switch (def->type) {
|
||||||
|
67
gram.y
67
gram.y
@@ -211,7 +211,7 @@ entry : COMMENT {
|
|||||||
|
|
||||||
defaults_list : defaults_entry
|
defaults_list : defaults_entry
|
||||||
| defaults_list ',' defaults_entry {
|
| defaults_list ',' defaults_entry {
|
||||||
LIST_APPEND($1, $3);
|
list_append($1, $3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -235,7 +235,7 @@ defaults_entry : DEFVAR {
|
|||||||
|
|
||||||
privileges : privilege
|
privileges : privilege
|
||||||
| privileges ':' privilege {
|
| privileges ':' privilege {
|
||||||
LIST_APPEND($1, $3);
|
list_append($1, $3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -248,8 +248,8 @@ privilege : hostlist '=' cmndspeclist {
|
|||||||
/* propagate tags and runas lists */
|
/* propagate tags and runas lists */
|
||||||
tags.nopasswd = tags.noexec = tags.setenv = UNSPEC;
|
tags.nopasswd = tags.noexec = tags.setenv = UNSPEC;
|
||||||
for (cs = $3; cs != NULL; cs = cs->next) {
|
for (cs = $3; cs != NULL; cs = cs->next) {
|
||||||
if (LH_EMPTY(&cs->runaslist) &&
|
if (lh_empty(&cs->runaslist) &&
|
||||||
!LH_EMPTY(&cs->prev->runaslist)) {
|
!lh_empty(&cs->prev->runaslist)) {
|
||||||
memcpy(&cs->runaslist, &cs->prev->runaslist,
|
memcpy(&cs->runaslist, &cs->prev->runaslist,
|
||||||
sizeof(cs->runaslist));
|
sizeof(cs->runaslist));
|
||||||
}
|
}
|
||||||
@@ -261,8 +261,8 @@ privilege : hostlist '=' cmndspeclist {
|
|||||||
cs->tags.setenv = tags.setenv;
|
cs->tags.setenv = tags.setenv;
|
||||||
memcpy(&tags, &cs->tags, sizeof(tags));
|
memcpy(&tags, &cs->tags, sizeof(tags));
|
||||||
}
|
}
|
||||||
LIST2HEAD(p->hostlist, $1);
|
list2head(&p->hostlist, $1);
|
||||||
LIST2HEAD(p->cmndlist, $3);
|
list2head(&p->cmndlist, $3);
|
||||||
p->prev = p;
|
p->prev = p;
|
||||||
p->next = NULL;
|
p->next = NULL;
|
||||||
$$ = p;
|
$$ = p;
|
||||||
@@ -298,14 +298,14 @@ host : ALIAS {
|
|||||||
|
|
||||||
cmndspeclist : cmndspec
|
cmndspeclist : cmndspec
|
||||||
| cmndspeclist ',' cmndspec {
|
| cmndspeclist ',' cmndspec {
|
||||||
LIST_APPEND($1, $3);
|
list_append($1, $3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
cmndspec : runasspec cmndtag opcmnd {
|
cmndspec : runasspec cmndtag opcmnd {
|
||||||
struct cmndspec *cs = emalloc(sizeof(*cs));
|
struct cmndspec *cs = emalloc(sizeof(*cs));
|
||||||
LIST2HEAD(cs->runaslist, $1);
|
list2head(&cs->runaslist, $1);
|
||||||
cs->tags = $2;
|
cs->tags = $2;
|
||||||
cs->cmnd = $3;
|
cs->cmnd = $3;
|
||||||
cs->prev = cs;
|
cs->prev = cs;
|
||||||
@@ -334,7 +334,7 @@ runasspec : /* empty */ {
|
|||||||
|
|
||||||
runaslist : oprunasuser
|
runaslist : oprunasuser
|
||||||
| runaslist ',' oprunasuser {
|
| runaslist ',' oprunasuser {
|
||||||
LIST_APPEND($1, $3);
|
list_append($1, $3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -418,7 +418,7 @@ hostalias : ALIAS '=' hostlist {
|
|||||||
|
|
||||||
hostlist : ophost
|
hostlist : ophost
|
||||||
| hostlist ',' ophost {
|
| hostlist ',' ophost {
|
||||||
LIST_APPEND($1, $3);
|
list_append($1, $3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -438,7 +438,7 @@ cmndalias : ALIAS '=' cmndlist {
|
|||||||
|
|
||||||
cmndlist : opcmnd
|
cmndlist : opcmnd
|
||||||
| cmndlist ',' opcmnd {
|
| cmndlist ',' opcmnd {
|
||||||
LIST_APPEND($1, $3);
|
list_append($1, $3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -471,7 +471,7 @@ useralias : ALIAS '=' userlist {
|
|||||||
|
|
||||||
userlist : opuser
|
userlist : opuser
|
||||||
| userlist ',' opuser {
|
| userlist ',' opuser {
|
||||||
LIST_APPEND($1, $3);
|
list_append($1, $3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -515,7 +515,7 @@ new_default(var, val, op)
|
|||||||
d = emalloc(sizeof(struct defaults));
|
d = emalloc(sizeof(struct defaults));
|
||||||
d->var = var;
|
d->var = var;
|
||||||
d->val = val;
|
d->val = val;
|
||||||
LH_INIT(&d->binding);
|
lh_init(&d->binding);
|
||||||
d->type = 0;
|
d->type = 0;
|
||||||
d->op = op;
|
d->op = op;
|
||||||
d->prev = d;
|
d->prev = d;
|
||||||
@@ -558,9 +558,9 @@ add_defaults(type, binding, defs)
|
|||||||
*/
|
*/
|
||||||
for (d = defs; d != NULL; d = d->next) {
|
for (d = defs; d != NULL; d = d->next) {
|
||||||
d->type = type;
|
d->type = type;
|
||||||
LIST2HEAD(d->binding, binding);
|
list2head(&d->binding, binding);
|
||||||
}
|
}
|
||||||
HEAD_APPEND(defaults, defs);
|
lh_append(&defaults, defs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -575,11 +575,11 @@ add_userspec(members, privs)
|
|||||||
struct userspec *u;
|
struct userspec *u;
|
||||||
|
|
||||||
u = emalloc(sizeof(*u));
|
u = emalloc(sizeof(*u));
|
||||||
LIST2HEAD(u->users, members);
|
list2head(&u->users, members);
|
||||||
LIST2HEAD(u->privileges, privs);
|
list2head(&u->privileges, privs);
|
||||||
u->prev = u;
|
u->prev = u;
|
||||||
u->next = NULL;
|
u->next = NULL;
|
||||||
HEAD_APPEND(userspecs, u);
|
lh_append(&userspecs, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -597,24 +597,18 @@ init_parser(path, quiet)
|
|||||||
struct privilege *priv;
|
struct privilege *priv;
|
||||||
struct cmndspec *cs;
|
struct cmndspec *cs;
|
||||||
|
|
||||||
while ((us = LH_LAST(&userspecs)) != NULL) {
|
while ((us = lh_pop(&userspecs)) != NULL) {
|
||||||
LH_POP(&userspecs);
|
while ((m = lh_pop(&us->users)) != NULL) {
|
||||||
while ((m = LH_LAST(&us->users)) != NULL) {
|
|
||||||
LH_POP(&us->users);
|
|
||||||
efree(m->name);
|
efree(m->name);
|
||||||
efree(m);
|
efree(m);
|
||||||
}
|
}
|
||||||
while ((priv = LH_LAST(&us->privileges)) != NULL) {
|
while ((priv = lh_pop(&us->privileges)) != NULL) {
|
||||||
LH_POP(&us->privileges);
|
while ((m = lh_pop(&priv->hostlist)) != NULL) {
|
||||||
while ((m = LH_LAST(&priv->hostlist)) != NULL) {
|
|
||||||
LH_POP(&priv->hostlist);
|
|
||||||
efree(m->name);
|
efree(m->name);
|
||||||
efree(m);
|
efree(m);
|
||||||
}
|
}
|
||||||
while ((cs = LH_LAST(&priv->cmndlist)) != NULL) {
|
while ((cs = lh_pop(&priv->cmndlist)) != NULL) {
|
||||||
LH_POP(&priv->cmndlist);
|
while ((m = lh_pop(&cs->runaslist)) != NULL) {
|
||||||
while ((m = LH_LAST(&cs->runaslist)) != NULL) {
|
|
||||||
LH_POP(&cs->runaslist);
|
|
||||||
efree(m->name);
|
efree(m->name);
|
||||||
efree(m);
|
efree(m);
|
||||||
}
|
}
|
||||||
@@ -625,15 +619,12 @@ init_parser(path, quiet)
|
|||||||
efree(priv);
|
efree(priv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LH_INIT(&userspecs);
|
lh_init(&userspecs);
|
||||||
|
|
||||||
lastbinding = NULL;
|
lastbinding = NULL;
|
||||||
while ((d = LH_LAST(&defaults)) != NULL) {
|
while ((d = lh_pop(&defaults)) != NULL) {
|
||||||
LH_POP(&defaults);
|
if (lh_pop(&d->binding) != lastbinding) {
|
||||||
if (LH_FIRST(&d->binding) != lastbinding) {
|
while ((m = lh_pop(&d->binding)) != NULL) {
|
||||||
lastbinding = LH_FIRST(&d->binding);
|
|
||||||
while ((m = LH_LAST(&d->binding)) != NULL) {
|
|
||||||
LH_POP(&d->binding);
|
|
||||||
efree(m->name);
|
efree(m->name);
|
||||||
efree(m);
|
efree(m);
|
||||||
}
|
}
|
||||||
@@ -642,7 +633,7 @@ init_parser(path, quiet)
|
|||||||
efree(d->val);
|
efree(d->val);
|
||||||
efree(d);
|
efree(d);
|
||||||
}
|
}
|
||||||
LH_INIT(&defaults);
|
lh_init(&defaults);
|
||||||
|
|
||||||
init_aliases();
|
init_aliases();
|
||||||
|
|
||||||
|
132
list.c
Normal file
132
list.c
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STDLIB_H
|
||||||
|
# include <stdlib.h>
|
||||||
|
# endif
|
||||||
|
#endif /* STDC_HEADERS */
|
||||||
|
|
||||||
|
#include "sudo.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
#ifndef lint
|
||||||
|
__unused static const char rcsid[] = "$Sudo$";
|
||||||
|
#endif /* lint */
|
||||||
|
|
||||||
|
struct list_proto {
|
||||||
|
struct list_proto *prev;
|
||||||
|
struct list_proto *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list_head_proto {
|
||||||
|
struct list_proto *first;
|
||||||
|
struct list_proto *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pop the last element off the end of vh.
|
||||||
|
* Returns the popped element.
|
||||||
|
*/
|
||||||
|
VOID *
|
||||||
|
lh_pop(vh)
|
||||||
|
VOID *vh;
|
||||||
|
{
|
||||||
|
struct list_head_proto *h = (struct list_head_proto *)vh;
|
||||||
|
VOID *last = NULL;
|
||||||
|
|
||||||
|
if (!lh_empty(h)) {
|
||||||
|
last = (VOID *)h->last;
|
||||||
|
if (h->first == h->last) {
|
||||||
|
h->first = NULL;
|
||||||
|
h->last = NULL;
|
||||||
|
} else {
|
||||||
|
h->last = h->last->prev;
|
||||||
|
h->last->next = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (last);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert from a semi-circle queue to normal doubly-linked list
|
||||||
|
* with a head node.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
list2head(vh, vl)
|
||||||
|
VOID *vh;
|
||||||
|
VOID *vl;
|
||||||
|
{
|
||||||
|
struct list_head_proto *h = (struct list_head_proto *)vh;
|
||||||
|
struct list_proto *l = (struct list_proto *)vl;
|
||||||
|
|
||||||
|
if (l != NULL) {
|
||||||
|
h->first = l;
|
||||||
|
h->last = l->prev; /* l->prev points to the last member of l */
|
||||||
|
l->prev = NULL; /* zero last ptr now that we have a head */
|
||||||
|
} else {
|
||||||
|
h->first = NULL;
|
||||||
|
h->last = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append one queue (or single entry) to another using the
|
||||||
|
* circular properties of the prev pointer to simplify the logic.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
list_append(vl1, vl2)
|
||||||
|
VOID *vl1;
|
||||||
|
VOID *vl2;
|
||||||
|
{
|
||||||
|
struct list_proto *l1 = (struct list_proto *)vl1;
|
||||||
|
struct list_proto *l2 = (struct list_proto *)vl2;
|
||||||
|
VOID *tail = l2->prev;
|
||||||
|
|
||||||
|
l1->prev->next = l2;
|
||||||
|
l2->prev = l1->prev;
|
||||||
|
l1->prev = tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append the list of entries to the head node and convert
|
||||||
|
* e from a semi-circle queue to normal doubly-linked list.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lh_append(vh, vl)
|
||||||
|
VOID *vh;
|
||||||
|
VOID *vl;
|
||||||
|
{
|
||||||
|
struct list_head_proto *h = (struct list_head_proto *)vh;
|
||||||
|
struct list_proto *l = (struct list_proto *)vl;
|
||||||
|
VOID *tail = l->prev;
|
||||||
|
|
||||||
|
if (h->first == NULL)
|
||||||
|
h->first = l;
|
||||||
|
else
|
||||||
|
h->last->next = l;
|
||||||
|
l->prev = h->last;
|
||||||
|
h->last = tail;
|
||||||
|
}
|
85
list.h
Normal file
85
list.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* $Sudo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SUDO_LIST_H
|
||||||
|
#define _SUDO_LIST_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience macro for declaring a list head.
|
||||||
|
*/
|
||||||
|
#ifdef __STDC__
|
||||||
|
#define LH_DECLARE(n) \
|
||||||
|
struct n##_list { \
|
||||||
|
struct n *first; \
|
||||||
|
struct n *last; \
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#define LH_DECLARE(n) \
|
||||||
|
struct n/**/_list { \
|
||||||
|
struct n *first; \
|
||||||
|
struct n *last; \
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Foreach loops: forward and reverse
|
||||||
|
*/
|
||||||
|
#undef lh_foreach_fwd
|
||||||
|
#define lh_foreach_fwd(h, v) \
|
||||||
|
for ((v) = (h)->first; (v) != NULL; (v) = (v)->next)
|
||||||
|
|
||||||
|
#undef lh_foreach_rev
|
||||||
|
#define lh_foreach_rev(h, v) \
|
||||||
|
for ((v) = (h)->last; (v) != NULL; (v) = (v)->prev)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init a list head.
|
||||||
|
*/
|
||||||
|
#undef lh_init
|
||||||
|
#define lh_init(h) do { \
|
||||||
|
(h)->first = NULL; \
|
||||||
|
(h)->last = NULL; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple macros to avoid exposing first/last and prev/next.
|
||||||
|
*/
|
||||||
|
#undef lh_empty
|
||||||
|
#define lh_empty(h) ((h)->first == NULL)
|
||||||
|
|
||||||
|
#undef lh_first
|
||||||
|
#define lh_first(h) ((h)->first)
|
||||||
|
|
||||||
|
#undef lh_last
|
||||||
|
#define lh_last(h) ((h)->last)
|
||||||
|
|
||||||
|
#undef list_next
|
||||||
|
#define list_next(e) ((e)->next)
|
||||||
|
|
||||||
|
#undef list_prev
|
||||||
|
#define list_prev(e) ((e)->prev)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes for list.c
|
||||||
|
*/
|
||||||
|
VOID *lh_pop __P((VOID *));
|
||||||
|
void lh_append __P((VOID *, VOID *));
|
||||||
|
void list_append __P((VOID *, VOID *));
|
||||||
|
void list2head __P((VOID *, VOID *));
|
||||||
|
|
||||||
|
#endif /* _SUDO_LIST_H */
|
8
match.c
8
match.c
@@ -111,7 +111,7 @@ userlist_matches(pw, list)
|
|||||||
struct alias *a;
|
struct alias *a;
|
||||||
int rval, matched = UNSPEC;
|
int rval, matched = UNSPEC;
|
||||||
|
|
||||||
LH_FOREACH_REV(list, m) {
|
lh_foreach_rev(list, m) {
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
case ALL:
|
case ALL:
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
@@ -159,7 +159,7 @@ runaslist_matches(list)
|
|||||||
if (list == NULL)
|
if (list == NULL)
|
||||||
return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw));
|
return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw));
|
||||||
|
|
||||||
LH_FOREACH_REV(list, m) {
|
lh_foreach_rev(list, m) {
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
case ALL:
|
case ALL:
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
@@ -203,7 +203,7 @@ hostlist_matches(list)
|
|||||||
struct alias *a;
|
struct alias *a;
|
||||||
int rval, matched = UNSPEC;
|
int rval, matched = UNSPEC;
|
||||||
|
|
||||||
LH_FOREACH_REV(list, m) {
|
lh_foreach_rev(list, m) {
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
case ALL:
|
case ALL:
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
@@ -278,7 +278,7 @@ cmndlist_matches(list)
|
|||||||
struct member *m;
|
struct member *m;
|
||||||
int rval, matched = UNSPEC;
|
int rval, matched = UNSPEC;
|
||||||
|
|
||||||
LH_FOREACH_REV(list, m) {
|
lh_foreach_rev(list, m) {
|
||||||
rval = cmnd_matches(m);
|
rval = cmnd_matches(m);
|
||||||
if (rval != UNSPEC) {
|
if (rval != UNSPEC) {
|
||||||
matched = m->negated ? !rval : rval;
|
matched = m->negated ? !rval : rval;
|
||||||
|
48
parse.c
48
parse.c
@@ -110,13 +110,13 @@ sudoers_lookup(pwflag)
|
|||||||
CLR(validated, FLAG_NO_USER);
|
CLR(validated, FLAG_NO_USER);
|
||||||
CLR(validated, FLAG_NO_HOST);
|
CLR(validated, FLAG_NO_HOST);
|
||||||
match = DENY;
|
match = DENY;
|
||||||
LH_FOREACH_REV(&userspecs, us) {
|
lh_foreach_rev(&userspecs, us) {
|
||||||
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
|
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
LH_FOREACH_REV(&us->privileges, priv) {
|
lh_foreach_rev(&us->privileges, priv) {
|
||||||
if (hostlist_matches(&priv->hostlist) != ALLOW)
|
if (hostlist_matches(&priv->hostlist) != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
LH_FOREACH_REV(&priv->cmndlist, cs) {
|
lh_foreach_rev(&priv->cmndlist, cs) {
|
||||||
/* Only check the command when listing another user. */
|
/* Only check the command when listing another user. */
|
||||||
if (user_uid == 0 || list_pw == NULL ||
|
if (user_uid == 0 || list_pw == NULL ||
|
||||||
user_uid == list_pw->pw_uid ||
|
user_uid == list_pw->pw_uid ||
|
||||||
@@ -147,19 +147,19 @@ sudoers_lookup(pwflag)
|
|||||||
set_perms(PERM_RUNAS);
|
set_perms(PERM_RUNAS);
|
||||||
|
|
||||||
match = UNSPEC;
|
match = UNSPEC;
|
||||||
LH_FOREACH_REV(&userspecs, us) {
|
lh_foreach_rev(&userspecs, us) {
|
||||||
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
|
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
CLR(validated, FLAG_NO_USER);
|
CLR(validated, FLAG_NO_USER);
|
||||||
LH_FOREACH_REV(&us->privileges, priv) {
|
lh_foreach_rev(&us->privileges, priv) {
|
||||||
host_match = hostlist_matches(&priv->hostlist);
|
host_match = hostlist_matches(&priv->hostlist);
|
||||||
if (host_match == ALLOW)
|
if (host_match == ALLOW)
|
||||||
CLR(validated, FLAG_NO_HOST);
|
CLR(validated, FLAG_NO_HOST);
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
runas = NULL;
|
runas = NULL;
|
||||||
LH_FOREACH_REV(&priv->cmndlist, cs) {
|
lh_foreach_rev(&priv->cmndlist, cs) {
|
||||||
if (!LH_EMPTY(&cs->runaslist))
|
if (!lh_empty(&cs->runaslist))
|
||||||
runas = &cs->runaslist;
|
runas = &cs->runaslist;
|
||||||
runas_match = runaslist_matches(runas);
|
runas_match = runaslist_matches(runas);
|
||||||
if (runas_match == ALLOW) {
|
if (runas_match == ALLOW) {
|
||||||
@@ -228,24 +228,24 @@ display_privs(v, pw)
|
|||||||
printf("User %s may run the following commands on this host:\n",
|
printf("User %s may run the following commands on this host:\n",
|
||||||
pw->pw_name);
|
pw->pw_name);
|
||||||
|
|
||||||
LH_FOREACH_FWD(&userspecs, us) {
|
lh_foreach_fwd(&userspecs, us) {
|
||||||
/* XXX - why only check the first privilege here? */
|
/* XXX - why only check the first privilege here? */
|
||||||
if (userlist_matches(pw, &us->users) != ALLOW ||
|
if (userlist_matches(pw, &us->users) != ALLOW ||
|
||||||
hostlist_matches(&us->privileges.first->hostlist) != ALLOW)
|
hostlist_matches(&us->privileges.first->hostlist) != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LH_FOREACH_FWD(&us->privileges, priv) {
|
lh_foreach_fwd(&us->privileges, priv) {
|
||||||
tags.noexec = def_noexec;
|
tags.noexec = def_noexec;
|
||||||
tags.setenv = def_setenv;
|
tags.setenv = def_setenv;
|
||||||
tags.nopasswd = !def_authenticate;
|
tags.nopasswd = !def_authenticate;
|
||||||
lbuf_append(&lbuf, " ", NULL);
|
lbuf_append(&lbuf, " ", NULL);
|
||||||
LH_FOREACH_FWD(&priv->cmndlist, cs) {
|
lh_foreach_fwd(&priv->cmndlist, cs) {
|
||||||
if (cs != LH_FIRST(&priv->cmndlist))
|
if (cs != lh_first(&priv->cmndlist))
|
||||||
lbuf_append(&lbuf, ", ", NULL);
|
lbuf_append(&lbuf, ", ", NULL);
|
||||||
lbuf_append(&lbuf, "(", NULL);
|
lbuf_append(&lbuf, "(", NULL);
|
||||||
if (!LH_EMPTY(&cs->runaslist)) {
|
if (!lh_empty(&cs->runaslist)) {
|
||||||
LH_FOREACH_FWD(&cs->runaslist, m) {
|
lh_foreach_fwd(&cs->runaslist, m) {
|
||||||
if (m != LH_FIRST(&cs->runaslist))
|
if (m != lh_first(&cs->runaslist))
|
||||||
lbuf_append(&lbuf, ", ", NULL);
|
lbuf_append(&lbuf, ", ", NULL);
|
||||||
print_member(&lbuf, m->name, m->type, m->negated,
|
print_member(&lbuf, m->name, m->type, m->negated,
|
||||||
RUNASALIAS);
|
RUNASALIAS);
|
||||||
@@ -298,7 +298,7 @@ display_defaults(pw)
|
|||||||
|
|
||||||
lbuf_init(&lbuf, NULL, 4, 0);
|
lbuf_init(&lbuf, NULL, 4, 0);
|
||||||
|
|
||||||
LH_FOREACH_FWD(&defaults, d) {
|
lh_foreach_fwd(&defaults, d) {
|
||||||
switch (d->type) {
|
switch (d->type) {
|
||||||
case DEFAULTS_HOST:
|
case DEFAULTS_HOST:
|
||||||
if (hostlist_matches(&d->binding) != ALLOW)
|
if (hostlist_matches(&d->binding) != ALLOW)
|
||||||
@@ -385,12 +385,12 @@ display_bound_defaults(dtype)
|
|||||||
}
|
}
|
||||||
lbuf_init(&lbuf, NULL, 4, 0);
|
lbuf_init(&lbuf, NULL, 4, 0);
|
||||||
printf("Per-%s Defaults entries:\n", dname);
|
printf("Per-%s Defaults entries:\n", dname);
|
||||||
LH_FOREACH_FWD(&defaults, d) {
|
lh_foreach_fwd(&defaults, d) {
|
||||||
if (d->type != dtype)
|
if (d->type != dtype)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (binding != LH_FIRST(&d->binding)) {
|
if (binding != lh_first(&d->binding)) {
|
||||||
binding = LH_FIRST(&d->binding);
|
binding = lh_first(&d->binding);
|
||||||
lbuf_append(&lbuf, " Defaults", dsep, NULL);
|
lbuf_append(&lbuf, " Defaults", dsep, NULL);
|
||||||
for (m = binding; m != NULL; m = m->next) {
|
for (m = binding; m != NULL; m = m->next) {
|
||||||
if (m != binding)
|
if (m != binding)
|
||||||
@@ -434,17 +434,17 @@ display_cmnd(v, pw)
|
|||||||
#endif
|
#endif
|
||||||
if (rval != 0 && !def_ignore_local_sudoers) {
|
if (rval != 0 && !def_ignore_local_sudoers) {
|
||||||
match = NULL;
|
match = NULL;
|
||||||
LH_FOREACH_REV(&userspecs, us) {
|
lh_foreach_rev(&userspecs, us) {
|
||||||
if (userlist_matches(pw, &us->users) != ALLOW)
|
if (userlist_matches(pw, &us->users) != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LH_FOREACH_REV(&us->privileges, priv) {
|
lh_foreach_rev(&us->privileges, priv) {
|
||||||
host_match = hostlist_matches(&priv->hostlist);
|
host_match = hostlist_matches(&priv->hostlist);
|
||||||
if (host_match != ALLOW)
|
if (host_match != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
runas = NULL;
|
runas = NULL;
|
||||||
LH_FOREACH_REV(&priv->cmndlist, cs) {
|
lh_foreach_rev(&priv->cmndlist, cs) {
|
||||||
if (!LH_EMPTY(&cs->runaslist) != NULL)
|
if (!lh_empty(&cs->runaslist) != NULL)
|
||||||
runas = &cs->runaslist;
|
runas = &cs->runaslist;
|
||||||
runas_match = runaslist_matches(runas);
|
runas_match = runaslist_matches(runas);
|
||||||
if (runas_match == ALLOW) {
|
if (runas_match == ALLOW) {
|
||||||
@@ -497,8 +497,8 @@ print_member(lbuf, name, type, negated, alias_type)
|
|||||||
break;
|
break;
|
||||||
case ALIAS:
|
case ALIAS:
|
||||||
if ((a = find_alias(name, alias_type)) != NULL) {
|
if ((a = find_alias(name, alias_type)) != NULL) {
|
||||||
LH_FOREACH_FWD(&a->members, m) {
|
lh_foreach_fwd(&a->members, m) {
|
||||||
if (m != LH_FIRST(&a->members))
|
if (m != lh_first(&a->members))
|
||||||
lbuf_append(lbuf, ", ", NULL);
|
lbuf_append(lbuf, ", ", NULL);
|
||||||
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, alias_type);
|
||||||
|
132
parse.h
132
parse.h
@@ -20,6 +20,8 @@
|
|||||||
#ifndef _SUDO_PARSE_H
|
#ifndef _SUDO_PARSE_H
|
||||||
#define _SUDO_PARSE_H
|
#define _SUDO_PARSE_H
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
#undef ALLOW
|
#undef ALLOW
|
||||||
#define ALLOW 1
|
#define ALLOW 1
|
||||||
#undef DENY
|
#undef DENY
|
||||||
@@ -58,72 +60,56 @@ struct cmndtag {
|
|||||||
* to trivally append sub-lists. In addition, the prev pointer is always
|
* to trivally append sub-lists. In addition, the prev pointer is always
|
||||||
* valid (even if it points to itself). Unlike a circle queue, the next
|
* valid (even if it points to itself). Unlike a circle queue, the next
|
||||||
* pointer of the last entry is NULL and does not point back to the head.
|
* pointer of the last entry is NULL and does not point back to the head.
|
||||||
|
*
|
||||||
|
* Note that each list struct must contain a "prev" and "next" pointer as
|
||||||
|
* the first two members of the struct (in that order).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tail queue list head structure.
|
* Tail queue list head structure.
|
||||||
*/
|
*/
|
||||||
struct defaults_list {
|
LH_DECLARE(defaults)
|
||||||
struct defaults *first;
|
LH_DECLARE(userspec)
|
||||||
struct defaults *last;
|
LH_DECLARE(member)
|
||||||
};
|
LH_DECLARE(privilege)
|
||||||
|
LH_DECLARE(cmndspec)
|
||||||
struct userspec_list {
|
|
||||||
struct userspec *first;
|
|
||||||
struct userspec *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct member_list {
|
|
||||||
struct member *first;
|
|
||||||
struct member *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct privilege_list {
|
|
||||||
struct privilege *first;
|
|
||||||
struct privilege *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cmndspec_list {
|
|
||||||
struct cmndspec *first;
|
|
||||||
struct cmndspec *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure describing a user specification and list thereof.
|
* Structure describing a user specification and list thereof.
|
||||||
*/
|
*/
|
||||||
struct userspec {
|
struct userspec {
|
||||||
|
struct userspec *prev, *next;
|
||||||
struct member_list users; /* list of users */
|
struct member_list users; /* list of users */
|
||||||
struct privilege_list privileges; /* list of privileges */
|
struct privilege_list privileges; /* list of privileges */
|
||||||
struct userspec *prev, *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure describing a privilege specification.
|
* Structure describing a privilege specification.
|
||||||
*/
|
*/
|
||||||
struct privilege {
|
struct privilege {
|
||||||
|
struct privilege *prev, *next;
|
||||||
struct member_list hostlist; /* list of hosts */
|
struct member_list hostlist; /* list of hosts */
|
||||||
struct cmndspec_list cmndlist; /* list of Cmnd_Specs */
|
struct cmndspec_list cmndlist; /* list of Cmnd_Specs */
|
||||||
struct privilege *prev, *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure describing a linked list of Cmnd_Specs.
|
* Structure describing a linked list of Cmnd_Specs.
|
||||||
*/
|
*/
|
||||||
struct cmndspec {
|
struct cmndspec {
|
||||||
|
struct cmndspec *prev, *next;
|
||||||
struct member_list runaslist; /* list of runas users */
|
struct member_list runaslist; /* list of runas users */
|
||||||
struct member *cmnd; /* command to allow/deny */
|
struct member *cmnd; /* command to allow/deny */
|
||||||
struct cmndtag tags; /* tag specificaion */
|
struct cmndtag tags; /* tag specificaion */
|
||||||
struct cmndspec *prev, *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic structure to hold users, hosts, commands.
|
* Generic structure to hold users, hosts, commands.
|
||||||
*/
|
*/
|
||||||
struct member {
|
struct member {
|
||||||
|
struct member *prev, *next;
|
||||||
char *name; /* member name */
|
char *name; /* member name */
|
||||||
short type; /* type (see gram.h) */
|
short type; /* type (see gram.h) */
|
||||||
short negated; /* negated via '!'? */
|
short negated; /* negated via '!'? */
|
||||||
struct member *prev, *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -140,102 +126,14 @@ struct alias {
|
|||||||
* Structure describing a Defaults entry and a list thereof.
|
* Structure describing a Defaults entry and a list thereof.
|
||||||
*/
|
*/
|
||||||
struct defaults {
|
struct defaults {
|
||||||
|
struct defaults *prev, *next;
|
||||||
char *var; /* variable name */
|
char *var; /* variable name */
|
||||||
char *val; /* variable value */
|
char *val; /* variable value */
|
||||||
struct member_list binding; /* user/host/runas binding */
|
struct member_list binding; /* user/host/runas binding */
|
||||||
int type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */
|
int type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */
|
||||||
int op; /* TRUE, FALSE, '+', '-' */
|
int op; /* TRUE, FALSE, '+', '-' */
|
||||||
struct defaults *prev, *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Append one queue (or single entry) to another using the
|
|
||||||
* circular properties of the prev pointer to simplify the logic.
|
|
||||||
*/
|
|
||||||
#undef LIST_APPEND
|
|
||||||
#define LIST_APPEND(h, e) do { \
|
|
||||||
void *_tail = (e)->prev; \
|
|
||||||
(h)->prev->next = (e); \
|
|
||||||
(e)->prev = (h)->prev; \
|
|
||||||
(h)->prev = _tail; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Append the list of entries to the head node and convert
|
|
||||||
* e from a semi-circle queue to normal doubly-linked list.
|
|
||||||
*/
|
|
||||||
#undef HEAD_APPEND
|
|
||||||
#define HEAD_APPEND(h, e) do { \
|
|
||||||
void *_tail = (e)->prev; \
|
|
||||||
if ((h).first == NULL) \
|
|
||||||
(h).first = (e); \
|
|
||||||
else \
|
|
||||||
(h).last->next = (e); \
|
|
||||||
(e)->prev = (h).last; \
|
|
||||||
(h).last = _tail; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert from a semi-circle queue to normal doubly-linked list
|
|
||||||
* with a head node.
|
|
||||||
*/
|
|
||||||
#undef LIST2HEAD
|
|
||||||
#define LIST2HEAD(h, e) do { \
|
|
||||||
if ((e) != NULL) { \
|
|
||||||
(h).first = (e); \
|
|
||||||
(h).last = (e)->prev; \
|
|
||||||
(e)->prev = NULL; \
|
|
||||||
} else { \
|
|
||||||
(h).first = NULL; \
|
|
||||||
(h).last = NULL; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#undef LH_FOREACH_FWD
|
|
||||||
#define LH_FOREACH_FWD(h, v) \
|
|
||||||
for ((v) = (h)->first; (v) != NULL; (v) = (v)->next)
|
|
||||||
|
|
||||||
#undef LH_FOREACH_REV
|
|
||||||
#define LH_FOREACH_REV(h, v) \
|
|
||||||
for ((v) = (h)->last; (v) != NULL; (v) = (v)->prev)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pop the last element off the end of h.
|
|
||||||
* XXX - really should return the popped element.
|
|
||||||
*/
|
|
||||||
#undef LH_POP
|
|
||||||
#define LH_POP(h) do { \
|
|
||||||
if (!LH_EMPTY(h)) { \
|
|
||||||
if ((h)->first == (h)->last) \
|
|
||||||
(h)->first = (h)->last = NULL; \
|
|
||||||
else { \
|
|
||||||
(h)->last = (h)->last->prev; \
|
|
||||||
(h)->last->next = NULL; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#undef LH_INIT
|
|
||||||
#define LH_INIT(h) do { \
|
|
||||||
(h)->first = NULL; \
|
|
||||||
(h)->last = NULL; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#undef LH_EMPTY
|
|
||||||
#define LH_EMPTY(h) ((h)->first == NULL)
|
|
||||||
|
|
||||||
#undef LH_FIRST
|
|
||||||
#define LH_FIRST(h) ((h)->first)
|
|
||||||
|
|
||||||
#undef LH_LAST
|
|
||||||
#define LH_LAST(h) ((h)->last)
|
|
||||||
|
|
||||||
#undef LIST_NEXT
|
|
||||||
#define LIST_NEXT(e) ((e)->next)
|
|
||||||
|
|
||||||
#undef LIST_PREV
|
|
||||||
#define LIST_PREV(e) ((e)->prev)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parsed sudoers info.
|
* Parsed sudoers info.
|
||||||
*/
|
*/
|
||||||
|
@@ -269,18 +269,18 @@ main(argc, argv)
|
|||||||
/* This loop must match the one in sudoers_lookup() */
|
/* This loop must match the one in sudoers_lookup() */
|
||||||
printf("\nEntries for user %s:\n", user_name);
|
printf("\nEntries for user %s:\n", user_name);
|
||||||
matched = UNSPEC;
|
matched = UNSPEC;
|
||||||
LH_FOREACH_REV(&userspecs, us) {
|
lh_foreach_rev(&userspecs, us) {
|
||||||
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
|
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
|
||||||
continue;
|
continue;
|
||||||
LH_FOREACH_REV(&us->privileges, priv) {
|
lh_foreach_rev(&us->privileges, priv) {
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
print_privilege(priv); /* XXX */
|
print_privilege(priv); /* XXX */
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
if (hostlist_matches(&priv->hostlist) == ALLOW) {
|
if (hostlist_matches(&priv->hostlist) == ALLOW) {
|
||||||
puts("\thost matched");
|
puts("\thost matched");
|
||||||
runas = NULL;
|
runas = NULL;
|
||||||
LH_FOREACH_REV(&priv->cmndlist, cs) {
|
lh_foreach_rev(&priv->cmndlist, cs) {
|
||||||
if (!LH_EMPTY(&cs->runaslist))
|
if (!lh_empty(&cs->runaslist))
|
||||||
runas = &cs->runaslist;
|
runas = &cs->runaslist;
|
||||||
if (runaslist_matches(runas) == ALLOW) {
|
if (runaslist_matches(runas) == ALLOW) {
|
||||||
puts("\trunas matched");
|
puts("\trunas matched");
|
||||||
@@ -389,7 +389,7 @@ print_defaults()
|
|||||||
struct defaults *d;
|
struct defaults *d;
|
||||||
struct member *m;
|
struct member *m;
|
||||||
|
|
||||||
LH_FOREACH_FWD(&defaults, d) {
|
lh_foreach_fwd(&defaults, d) {
|
||||||
(void) fputs("Defaults", stdout);
|
(void) fputs("Defaults", stdout);
|
||||||
switch (d->type) {
|
switch (d->type) {
|
||||||
case DEFAULTS_HOST:
|
case DEFAULTS_HOST:
|
||||||
@@ -405,8 +405,8 @@ print_defaults()
|
|||||||
putchar('!');
|
putchar('!');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LH_FOREACH_FWD(&d->binding, m) {
|
lh_foreach_fwd(&d->binding, m) {
|
||||||
if (m != LH_FIRST(&d->binding))
|
if (m != lh_first(&d->binding))
|
||||||
putchar(',');
|
putchar(',');
|
||||||
print_member(m);
|
print_member(m);
|
||||||
}
|
}
|
||||||
@@ -440,8 +440,8 @@ print_alias(v1, v2)
|
|||||||
(void) printf("Runas_Alias\t%s = ", a->name);
|
(void) printf("Runas_Alias\t%s = ", a->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LH_FOREACH_FWD(&a->members, m) {
|
lh_foreach_fwd(&a->members, m) {
|
||||||
if (m != LH_FIRST(&a->members))
|
if (m != lh_first(&a->members))
|
||||||
fputs(", ", stdout);
|
fputs(", ", stdout);
|
||||||
if (m->type == COMMAND) {
|
if (m->type == COMMAND) {
|
||||||
c = (struct sudo_command *) m->name;
|
c = (struct sudo_command *) m->name;
|
||||||
@@ -466,20 +466,20 @@ print_privilege(priv)
|
|||||||
for (p = priv; p != NULL; p = p->next) {
|
for (p = priv; p != NULL; p = p->next) {
|
||||||
if (p != priv)
|
if (p != priv)
|
||||||
fputs(" : ", stdout);
|
fputs(" : ", stdout);
|
||||||
LH_FOREACH_FWD(&p->hostlist, m) {
|
lh_foreach_fwd(&p->hostlist, m) {
|
||||||
if (m != LH_FIRST(&p->hostlist))
|
if (m != lh_first(&p->hostlist))
|
||||||
fputs(", ", stdout);
|
fputs(", ", stdout);
|
||||||
print_member(m);
|
print_member(m);
|
||||||
}
|
}
|
||||||
fputs(" = ", stdout);
|
fputs(" = ", stdout);
|
||||||
tags.nopasswd = tags.noexec = UNSPEC;
|
tags.nopasswd = tags.noexec = UNSPEC;
|
||||||
LH_FOREACH_FWD(&p->cmndlist, cs) {
|
lh_foreach_fwd(&p->cmndlist, cs) {
|
||||||
if (cs != LH_FIRST(&p->cmndlist))
|
if (cs != lh_first(&p->cmndlist))
|
||||||
fputs(", ", stdout);
|
fputs(", ", stdout);
|
||||||
if (!LH_EMPTY(&cs->runaslist)) {
|
if (!lh_empty(&cs->runaslist)) {
|
||||||
fputs("(", stdout);
|
fputs("(", stdout);
|
||||||
LH_FOREACH_FWD(&cs->runaslist, m) {
|
lh_foreach_fwd(&cs->runaslist, m) {
|
||||||
if (m != LH_FIRST(&cs->runaslist))
|
if (m != lh_first(&cs->runaslist))
|
||||||
fputs(", ", stdout);
|
fputs(", ", stdout);
|
||||||
print_member(m);
|
print_member(m);
|
||||||
}
|
}
|
||||||
@@ -501,9 +501,9 @@ print_userspecs()
|
|||||||
struct member *m;
|
struct member *m;
|
||||||
struct userspec *us;
|
struct userspec *us;
|
||||||
|
|
||||||
LH_FOREACH_FWD(&userspecs, us) {
|
lh_foreach_fwd(&userspecs, us) {
|
||||||
LH_FOREACH_FWD(&us->users, m) {
|
lh_foreach_fwd(&us->users, m) {
|
||||||
if (m != LH_FIRST(&us->users))
|
if (m != lh_first(&us->users))
|
||||||
fputs(", ", stdout);
|
fputs(", ", stdout);
|
||||||
print_member(m);
|
print_member(m);
|
||||||
}
|
}
|
||||||
|
40
visudo.c
40
visudo.c
@@ -212,8 +212,8 @@ main(argc, argv)
|
|||||||
setup_signals();
|
setup_signals();
|
||||||
|
|
||||||
/* Edit the sudoers file(s) */
|
/* Edit the sudoers file(s) */
|
||||||
LH_FOREACH_FWD(&sudoerslist, sp) {
|
lh_foreach_fwd(&sudoerslist, sp) {
|
||||||
if (sp != LH_FIRST(&sudoerslist)) {
|
if (sp != lh_first(&sudoerslist)) {
|
||||||
printf("press return to edit %s: ", sp->path);
|
printf("press return to edit %s: ", sp->path);
|
||||||
while ((ch = getchar()) != EOF && ch != '\n')
|
while ((ch = getchar()) != EOF && ch != '\n')
|
||||||
continue;
|
continue;
|
||||||
@@ -225,7 +225,7 @@ main(argc, argv)
|
|||||||
reparse_sudoers(editor, args, strict, quiet);
|
reparse_sudoers(editor, args, strict, quiet);
|
||||||
|
|
||||||
/* Install the sudoers temp files. */
|
/* Install the sudoers temp files. */
|
||||||
LH_FOREACH_FWD(&sudoerslist, sp) {
|
lh_foreach_fwd(&sudoerslist, sp) {
|
||||||
if (!sp->modified)
|
if (!sp->modified)
|
||||||
(void) unlink(sp->tpath);
|
(void) unlink(sp->tpath);
|
||||||
else
|
else
|
||||||
@@ -400,8 +400,8 @@ reparse_sudoers(editor, args, strict, quiet)
|
|||||||
* Parse the edited sudoers files and do sanity checking
|
* Parse the edited sudoers files and do sanity checking
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
sp = LH_FIRST(&sudoerslist);
|
sp = lh_first(&sudoerslist);
|
||||||
last = LH_LAST(&sudoerslist);
|
last = lh_last(&sudoerslist);
|
||||||
fp = fopen(sp->tpath, "r+");
|
fp = fopen(sp->tpath, "r+");
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
errorx(1, "can't re-open temporary file (%s), %s unchanged.",
|
errorx(1, "can't re-open temporary file (%s), %s unchanged.",
|
||||||
@@ -437,7 +437,7 @@ reparse_sudoers(editor, args, strict, quiet)
|
|||||||
}
|
}
|
||||||
if (parse_error) {
|
if (parse_error) {
|
||||||
/* Edit file with the parse error */
|
/* Edit file with the parse error */
|
||||||
LH_FOREACH_FWD(&sudoerslist, sp) {
|
lh_foreach_fwd(&sudoerslist, sp) {
|
||||||
if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) {
|
if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) {
|
||||||
edit_sudoers(sp, editor, args, errorlineno);
|
edit_sudoers(sp, editor, args, errorlineno);
|
||||||
break;
|
break;
|
||||||
@@ -708,7 +708,7 @@ open_sudoers(path, keepopen)
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
/* Check for existing entry */
|
/* Check for existing entry */
|
||||||
LH_FOREACH_FWD(&sudoerslist, entry) {
|
lh_foreach_fwd(&sudoerslist, entry) {
|
||||||
if (strcmp(path, entry->path) == 0)
|
if (strcmp(path, entry->path) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -886,8 +886,8 @@ check_aliases(strict)
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
/* Forward check. */
|
/* Forward check. */
|
||||||
LH_FOREACH_FWD(&userspecs, us) {
|
lh_foreach_fwd(&userspecs, us) {
|
||||||
LH_FOREACH_FWD(&us->users, m) {
|
lh_foreach_fwd(&us->users, m) {
|
||||||
if (m->type == USERALIAS) {
|
if (m->type == USERALIAS) {
|
||||||
if (find_alias(m->name, m->type) == NULL) {
|
if (find_alias(m->name, m->type) == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@@ -897,8 +897,8 @@ check_aliases(strict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LH_FOREACH_FWD(&us->privileges, priv) {
|
lh_foreach_fwd(&us->privileges, priv) {
|
||||||
LH_FOREACH_FWD(&priv->hostlist, m) {
|
lh_foreach_fwd(&priv->hostlist, m) {
|
||||||
if (m->type == HOSTALIAS) {
|
if (m->type == HOSTALIAS) {
|
||||||
if (find_alias(m->name, m->type) == NULL) {
|
if (find_alias(m->name, m->type) == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@@ -908,8 +908,8 @@ check_aliases(strict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LH_FOREACH_FWD(&priv->cmndlist, cs) {
|
lh_foreach_fwd(&priv->cmndlist, cs) {
|
||||||
LH_FOREACH_FWD(&cs->runaslist, m) {
|
lh_foreach_fwd(&cs->runaslist, m) {
|
||||||
if (m->type == RUNASALIAS) {
|
if (m->type == RUNASALIAS) {
|
||||||
if (find_alias(m->name, m->type) == NULL) {
|
if (find_alias(m->name, m->type) == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@@ -932,18 +932,18 @@ check_aliases(strict)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Reverse check (destructive) */
|
/* Reverse check (destructive) */
|
||||||
LH_FOREACH_FWD(&userspecs, us) {
|
lh_foreach_fwd(&userspecs, us) {
|
||||||
LH_FOREACH_FWD(&us->users, m) {
|
lh_foreach_fwd(&us->users, m) {
|
||||||
if (m->type == USERALIAS)
|
if (m->type == USERALIAS)
|
||||||
(void) alias_remove(m->name, m->type);
|
(void) alias_remove(m->name, m->type);
|
||||||
}
|
}
|
||||||
LH_FOREACH_FWD(&us->privileges, priv) {
|
lh_foreach_fwd(&us->privileges, priv) {
|
||||||
LH_FOREACH_FWD(&priv->hostlist, m) {
|
lh_foreach_fwd(&priv->hostlist, m) {
|
||||||
if (m->type == HOSTALIAS)
|
if (m->type == HOSTALIAS)
|
||||||
(void) alias_remove(m->name, m->type);
|
(void) alias_remove(m->name, m->type);
|
||||||
}
|
}
|
||||||
LH_FOREACH_FWD(&priv->cmndlist, cs) {
|
lh_foreach_fwd(&priv->cmndlist, cs) {
|
||||||
LH_FOREACH_FWD(&cs->runaslist, m) {
|
lh_foreach_fwd(&cs->runaslist, m) {
|
||||||
if (m->type == RUNASALIAS)
|
if (m->type == RUNASALIAS)
|
||||||
(void) alias_remove(m->name, m->type);
|
(void) alias_remove(m->name, m->type);
|
||||||
}
|
}
|
||||||
@@ -983,7 +983,7 @@ cleanup(gotsignal)
|
|||||||
{
|
{
|
||||||
struct sudoersfile *sp;
|
struct sudoersfile *sp;
|
||||||
|
|
||||||
LH_FOREACH_FWD(&sudoerslist, sp) {
|
lh_foreach_fwd(&sudoerslist, sp) {
|
||||||
if (sp->tpath != NULL)
|
if (sp->tpath != NULL)
|
||||||
(void) unlink(sp->tpath);
|
(void) unlink(sp->tpath);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user