/*
- * Copyright (c) 1996, 1998-2005, 2007-2011
+ * Copyright (c) 1996, 1998-2005, 2007-2013
* Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
#include <config.h>
-#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_FNMATCH
# include <fnmatch.h>
+#else
+# include "compat/fnmatch.h"
#endif /* HAVE_FNMATCH */
#ifdef HAVE_NETGROUP_H
# include <netgroup.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <netdb.h>
#include "tsgetgrpw.h"
#include "sudoers.h"
#include "interfaces.h"
#include "parse.h"
+#include "sudo_conf.h"
+#include "secure_path.h"
#include <gram.h>
-#ifndef HAVE_FNMATCH
-# include "compat/fnmatch.h"
-#endif /* HAVE_FNMATCH */
-
/*
* Function Prototypes
*/
void print_privilege(struct privilege *);
void print_userspecs(void);
void usage(void) __attribute__((__noreturn__));
-void cleanup(int);
static void set_runaspw(const char *);
static void set_runasgr(const char *);
static int cb_runas_default(const char *);
-static int testsudoers_printf(int msg_type, const char *fmt, ...);
static int testsudoers_print(const char *msg);
extern void setgrfile(const char *);
/*
* Globals
*/
-struct interface *interfaces;
struct sudo_user sudo_user;
struct passwd *list_pw;
static char *runas_group, *runas_user;
-extern int parse_error;
-sudo_printf_t sudo_printf = testsudoers_printf;
+extern int errorlineno;
+extern bool parse_error;
+extern char *errorfile;
/* For getopt(3) */
extern char *optarg;
extern char *malloc_options;
#endif
#ifdef YYDEBUG
-extern int yydebug;
+extern int sudoersdebug;
#endif
+__dso_public int main(int argc, char *argv[]);
+
int
main(int argc, char *argv[])
{
struct privilege *priv;
struct userspec *us;
char *p, *grfile, *pwfile;
- char hbuf[MAXHOSTNAMELEN + 1];
+ char hbuf[HOST_NAME_MAX + 1];
int match, host_match, runas_match, cmnd_match;
- int ch, dflag;
+ int ch, dflag, exitcode = 0;
+ debug_decl(main, SUDO_DEBUG_MAIN)
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
malloc_options = "AFGJPR";
#endif
#ifdef YYDEBUG
- yydebug = 1;
+ sudoersdebug = 1;
#endif
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
setprogname(argc > 0 ? argv[0] : "testsudoers");
#endif
+ sudoers_setlocale(SUDOERS_LOCALE_USER, NULL);
+ bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have own domain */
+ textdomain("sudoers");
+
+ /* Read sudo.conf. */
+ sudo_conf_read(NULL);
+
dflag = 0;
grfile = pwfile = NULL;
- while ((ch = getopt(argc, argv, "dg:G:h:p:tu:")) != -1) {
+ while ((ch = getopt(argc, argv, "dg:G:h:P:p:tu:U:")) != -1) {
switch (ch) {
case 'd':
dflag = 1;
user_host = optarg;
break;
case 'G':
- grfile = optarg;
+ sudoers_gid = (gid_t)atoi(optarg);
break;
case 'g':
runas_group = optarg;
case 'p':
pwfile = optarg;
break;
+ case 'P':
+ grfile = optarg;
+ break;
case 't':
trace_print = testsudoers_print;
break;
+ case 'U':
+ sudoers_uid = (uid_t)atoi(optarg);
+ break;
case 'u':
runas_user = optarg;
break;
if (argc < 2) {
if (!dflag)
usage();
- user_name = "root";
+ user_name = argc ? *argv++ : "root";
user_cmnd = user_base = "true";
+ argc = 0;
} else {
- user_name = *argv;
- user_cmnd = *++argv;
+ user_name = *argv++;
+ user_cmnd = *argv++;
if ((p = strrchr(user_cmnd, '/')) != NULL)
user_base = p + 1;
else
argc -= 2;
}
if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL)
- errorx(1, _("unknown user: %s"), user_name);
+ fatalx(_("unknown user: %s"), user_name);
if (user_host == NULL) {
if (gethostname(hbuf, sizeof(hbuf)) != 0)
- error(1, "gethostname");
+ fatal("gethostname");
hbuf[sizeof(hbuf) - 1] = '\0';
user_host = hbuf;
}
char *to, **from;
size_t size, n;
- for (size = 0, from = argv + 1; *from; from++)
+ for (size = 0, from = argv; *from; from++)
size += strlen(*from) + 1;
user_args = (char *) emalloc(size);
- for (to = user_args, from = argv + 1; *from; from++) {
+ for (to = user_args, from = argv; *from; from++) {
n = strlcpy(to, *from, size - (to - user_args));
if (n >= size - (to - user_args))
- errorx(1, _("internal error, init_vars() overflow"));
+ fatalx(_("internal error, %s overflow"), "init_vars()");
to += n;
*to++ = ' ';
}
set_interfaces(p);
/* Allocate space for data structures in the parser. */
- init_parser("sudoers", 0);
+ init_parser("sudoers", false);
- if (yyparse() != 0 || parse_error) {
- parse_error = TRUE;
- (void) fputs("Does not parse", stdout);
+ if (sudoersparse() != 0 || parse_error) {
+ parse_error = true;
+ if (errorlineno != -1)
+ (void) printf("Parse error in %s near line %d",
+ errorfile, errorlineno);
+ else
+ (void) printf("Parse error in %s", errorfile);
} else {
(void) fputs("Parses OK", stdout);
}
(void) fputs(" (problem with defaults entries)", stdout);
puts(".");
- if (def_group_plugin && group_plugin_load(def_group_plugin) != TRUE)
+ if (def_group_plugin && group_plugin_load(def_group_plugin) != true)
def_group_plugin = NULL;
/*
if (dflag) {
(void) putchar('\n');
dump_sudoers();
- if (argc < 2)
- exit(parse_error ? 1 : 0);
+ if (argc < 2) {
+ exitcode = parse_error ? 1 : 0;
+ goto done;
+ }
}
/* This loop must match the one in sudo_file_lookup() */
puts("\thost matched");
tq_foreach_rev(&priv->cmndlist, cs) {
runas_match = runaslist_matches(&cs->runasuserlist,
- &cs->runasgrouplist);
+ &cs->runasgrouplist, NULL, NULL);
if (runas_match == ALLOW) {
puts("\trunas matched");
cmnd_match = cmnd_matches(cs->cmnd);
* 2 - command not matched
* 3 - command denied
*/
- if (parse_error)
- exit(1);
- exit(match == ALLOW ? 0 : match + 3);
+ exitcode = parse_error ? 1 : (match == ALLOW ? 0 : match + 3);
+done:
+ sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);
+ exit(exitcode);
}
static void
set_runaspw(const char *user)
{
+ debug_decl(main, SUDO_DEBUG_UTIL)
+
if (runas_pw != NULL)
- pw_delref(runas_pw);
+ sudo_pw_delref(runas_pw);
if (*user == '#') {
if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
} else {
if ((runas_pw = sudo_getpwnam(user)) == NULL)
- errorx(1, _("unknown user: %s"), user);
+ fatalx(_("unknown user: %s"), user);
}
+
+ debug_return;
}
static void
set_runasgr(const char *group)
{
+ debug_decl(main, SUDO_DEBUG_UTIL)
+
if (runas_gr != NULL)
- gr_delref(runas_gr);
+ sudo_gr_delref(runas_gr);
if (*group == '#') {
if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
runas_gr = sudo_fakegrnam(group);
} else {
if ((runas_gr = sudo_getgrnam(group)) == NULL)
- errorx(1, _("unknown group: %s"), group);
+ fatalx(_("unknown group: %s"), group);
}
+
+ debug_return;
}
/*
/* Only reset runaspw if user didn't specify one. */
if (!runas_user && !runas_group)
set_runaspw(user);
- return TRUE;
+ return true;
}
void
return;
}
-void
-set_fqdn(void)
-{
- return;
-}
-
FILE *
-open_sudoers(const char *path, int isdir, int *keepopen)
+open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
{
- return fopen(path, "r");
+ struct stat sb;
+ FILE *fp = NULL;
+ char *sudoers_base;
+ debug_decl(open_sudoers, SUDO_DEBUG_UTIL)
+
+ sudoers_base = strrchr(sudoers, '/');
+ if (sudoers_base != NULL)
+ sudoers_base++;
+
+ switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) {
+ case SUDO_PATH_SECURE:
+ fp = fopen(sudoers, "r");
+ break;
+ case SUDO_PATH_MISSING:
+ warning("unable to stat %s", sudoers_base);
+ break;
+ case SUDO_PATH_BAD_TYPE:
+ warningx("%s is not a regular file", sudoers_base);
+ break;
+ case SUDO_PATH_WRONG_OWNER:
+ warningx("%s should be owned by uid %u",
+ sudoers_base, (unsigned int) sudoers_uid);
+ break;
+ case SUDO_PATH_WORLD_WRITABLE:
+ warningx("%s is world writable", sudoers_base);
+ break;
+ case SUDO_PATH_GROUP_WRITABLE:
+ warningx("%s should be owned by gid %u",
+ sudoers_base, (unsigned int) sudoers_gid);
+ break;
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ debug_return_ptr(fp);
}
void
{
}
-void
-cleanup(int gotsignal)
-{
- if (!gotsignal) {
- sudo_endpwent();
- sudo_endgrent();
- }
-}
-
void
print_member(struct member *m)
{
struct sudo_command *c;
+ debug_decl(print_member, SUDO_DEBUG_UTIL)
if (m->negated)
putchar('!');
printf("%s%s%s", c->cmnd, c->args ? " " : "",
c->args ? c->args : "");
}
+
+ debug_return;
}
void
{
struct defaults *d;
struct member *m;
+ debug_decl(print_member, SUDO_DEBUG_UTIL)
tq_foreach_fwd(&defaults, d) {
(void) fputs("Defaults", stdout);
putchar(',');
print_member(m);
}
- printf("\t%s%s", d->op == FALSE ? "!" : "", d->var);
+ printf("\t%s%s", d->op == false ? "!" : "", d->var);
if (d->val != NULL) {
- printf("%c%s", d->op == TRUE ? '=' : d->op, d->val);
+ printf("%c%s", d->op == true ? '=' : d->op, d->val);
}
putchar('\n');
}
+
+ debug_return;
}
int
struct alias *a = (struct alias *)v1;
struct member *m;
struct sudo_command *c;
+ debug_decl(print_alias, SUDO_DEBUG_UTIL)
switch (a->type) {
case HOSTALIAS:
}
}
putchar('\n');
- return 0;
+ debug_return_int(0);
}
void
struct member *m;
struct privilege *p;
struct cmndtag tags;
+ debug_decl(print_privilege, SUDO_DEBUG_UTIL)
for (p = priv; p != NULL; p = p->next) {
if (p != priv)
print_member(m);
}
fputs(" = ", stdout);
- tags.nopasswd = tags.noexec = UNSPEC;
+ tags.nopasswd = UNSPEC;
+ tags.noexec = UNSPEC;
tq_foreach_fwd(&p->cmndlist, cs) {
if (cs != tq_first(&p->cmndlist))
fputs(", ", stdout);
if (cs->type)
printf("TYPE=%s ", cs->type);
#endif /* HAVE_SELINUX */
+#ifdef HAVE_PRIV_SET
+ if (cs->privs)
+ printf("PRIVS=%s ", cs->privs);
+ if (cs->limitprivs)
+ printf("LIMITPRIVS=%s ", cs->limitprivs);
+#endif /* HAVE_PRIV_SET */
if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != tags.nopasswd)
printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : "");
if (cs->tags.noexec != UNSPEC && cs->tags.noexec != tags.noexec)
memcpy(&tags, &cs->tags, sizeof(tags));
}
}
+ debug_return;
}
void
{
struct member *m;
struct userspec *us;
+ debug_decl(print_userspecs, SUDO_DEBUG_UTIL)
tq_foreach_fwd(&userspecs, us) {
tq_foreach_fwd(&us->users, m) {
print_privilege(us->privileges.first); /* XXX */
putchar('\n');
}
-}
-
-static int
-testsudoers_printf(int msg_type, const char *fmt, ...)
-{
- va_list ap;
- FILE *fp;
-
- switch (msg_type) {
- case SUDO_CONV_INFO_MSG:
- fp = stdout;
- break;
- case SUDO_CONV_ERROR_MSG:
- fp = stderr;
- break;
- default:
- errno = EINVAL;
- return -1;
- }
-
- va_start(ap, fmt);
- vfprintf(fp, fmt, ap);
- va_end(ap);
-
- return 0;
+ debug_return;
}
void
dump_sudoers(void)
{
+ debug_decl(dump_sudoers, SUDO_DEBUG_UTIL)
+
print_defaults();
putchar('\n');
putchar('\n');
print_userspecs();
+
+ debug_return;
}
static int testsudoers_print(const char *msg)
void
usage(void)
{
- (void) fprintf(stderr, "usage: %s [-dt] [-G grfile] [-g group] [-h host] [-p pwfile] [-u user] <user> <command> [args]\n", getprogname());
+ (void) fprintf(stderr, "usage: %s [-dt] [-G sudoers_gid] [-g group] [-h host] [-p grfile] [-p pwfile] [-U sudoers_uid] [-u user] <user> <command> [args]\n", getprogname());
exit(1);
}