X-Git-Url: https://git.distorted.org.uk/~mdw/become/blobdiff_plain/59f147b0d9bfb46577cd6f8813589ccdf8bc2a2c..1939e189f903d0b635d90b1f8fbd40df03ce6fba:/src/become.c diff --git a/src/become.c b/src/become.c index 23f69dd..7c7c2aa 100644 --- a/src/become.c +++ b/src/become.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: become.c,v 1.19 1998/06/29 13:10:41 mdw Exp $ + * $Id: become.c,v 1.24 2003/10/15 09:27:06 mdw Exp $ * * Main code for `become' * @@ -29,7 +29,24 @@ /*----- Revision history --------------------------------------------------* * * $Log: become.c,v $ - * Revision 1.19 1998/06/29 13:10:41 mdw + * Revision 1.24 2003/10/15 09:27:06 mdw + * Make sure standard file descriptors are open before starting properly. + * + * Revision 1.23 2003/10/12 10:00:06 mdw + * Fix for daemon mode. Oops. + * + * Revision 1.22 2003/10/12 00:14:55 mdw + * Major overhaul. Now uses DSA signatures rather than the bogus symmetric + * encrypt-and-hope thing. Integrated with mLib and Catacomb. + * + * Revision 1.21 1999/07/28 09:31:01 mdw + * Empty path components are equivalent to `.'. + * + * Revision 1.20 1999/05/04 16:17:11 mdw + * Change to header file name for parser. See log for `parse.h' for + * details. + * + * Revision 1.19 1998/06/29 13:10:41 mdw * Add some commentary regarding an issue in `sudo' which affects `become'; * I'm not fixing it yet because I don't think it's important. * @@ -136,9 +153,19 @@ #include #include #include +#include extern char **environ; +/* --- mLib --- */ + +#include +#include +#include +#include +#include +#include + /* --- Local headers --- */ #include "become.h" @@ -146,12 +173,9 @@ extern char **environ; #include "check.h" #include "daemon.h" #include "lexer.h" -#include "mdwopt.h" #include "name.h" -#include "parser.h" +#include "parse.h" #include "rule.h" -#include "sym.h" -#include "utils.h" #include "userdb.h" /*----- Type definitions --------------------------------------------------*/ @@ -453,11 +477,12 @@ static void bc__help(FILE *fp, int suid) #ifndef NONETWORK "\n" "-d, --daemon Start a daemon\n" +"-n, --nofork In daemon mode, don't fork into background\n" "-p PORT, --port=PORT In daemon mode, listen on PORT\n" "-f FILE, --config-file=FILE In daemon mode, read config from FILE\n" #endif ); -#ifdef TRACING +#ifndef NTRACE bc__write(fp, "\n"); if (!suid) { bc__write(fp, @@ -522,14 +547,13 @@ int main(int argc, char *argv[]) /* --- Definitions for the various flags --- */ - enum { - f_daemon = 1, /* Start up in daemon mode */ - f_duff = 2, /* Fault in arguments */ - f_shell = 4, /* Run a default shell */ - f_dummy = 8, /* Don't actually do anything */ - f_setuid = 16, /* We're running setuid */ - f_havegroup = 32 /* Set a default group */ - }; +#define f_daemon 1u /* Start up in daemon mode */ +#define f_duff 2u /* Fault in arguments */ +#define f_shell 4u /* Run a default shell */ +#define f_dummy 8u /* Don't actually do anything */ +#define f_setuid 16u /* We're running setuid */ +#define f_havegroup 32u /* Set a default group */ +#define f_nofork 64u /* Don't fork into background */ /* --- Set up the program name --- */ @@ -538,12 +562,23 @@ int main(int argc, char *argv[]) if (getuid() != geteuid()) flags |= f_setuid; + /* --- Make sure standard file descriptors are open --- */ + + { + int fd; + do { + if ((fd = open("/dev/null", O_RDWR)) < 0) + die(1, "couldn't open /dev/null: %s", strerror(errno)); + } while (fd <= STDERR_FILENO); + close(fd); + } + /* --- Read the environment into a hashtable --- */ { char **p; - sym_createTable(&bc__env); + sym_create(&bc__env); for (p = environ; *p; p++) bc__putenv(0, *p, 0, 0); } @@ -569,7 +604,7 @@ int main(int argc, char *argv[]) /* --- Group style options --- */ - { "group", gFlag_argReq, 0, 'g' }, + { "group", OPTF_ARGREQ, 0, 'g' }, #ifdef HAVE_SETGROUPS { "keep-groups", 0, 0, 'k' }, { "merge-groups", 0, 0, 'm' }, @@ -578,22 +613,23 @@ int main(int argc, char *argv[]) /* --- Command to run options --- */ - { "command", gFlag_argReq, 0, 'c' }, + { "command", OPTF_ARGREQ, 0, 'c' }, /* --- Server options --- */ #ifndef NONETWORK { "daemon", 0, 0, 'd' }, - { "port", gFlag_argReq, 0, 'p' }, - { "config-file", gFlag_argReq, 0, 'f' }, + { "nofork", 0, 0, 'n' }, + { "port", OPTF_ARGREQ, 0, 'p' }, + { "config-file", OPTF_ARGREQ, 0, 'f' }, #endif /* --- Tracing options --- */ -#ifdef TRACING - { "impersonate", gFlag_argReq, 0, 'I' }, - { "trace", gFlag_argOpt, 0, 'T' }, - { "trace-level", gFlag_argOpt, 0, 'L' }, +#ifndef NTRACE + { "impersonate", OPTF_ARGREQ, 0, 'I' }, + { "trace", OPTF_ARGOPT, 0, 'T' }, + { "trace-level", OPTF_ARGOPT, 0, 'L' }, #endif { 0, 0, 0, 0 } @@ -610,9 +646,9 @@ int main(int argc, char *argv[]) #endif "c:" /* Command to run options */ #ifndef NONETWORK - "dp:f:" /* Server options */ + "dnp:f:" /* Server options */ #endif -#ifdef TRACING +#ifndef NTRACE "I:T::L::" /* Tracing options */ #endif , @@ -657,7 +693,7 @@ int main(int argc, char *argv[]) else { struct group *gr = getgrnam(optarg); if (!gr) - die("unknown group `%s'", optarg); + die(1, "unknown group `%s'", optarg); group = gr->gr_gid; } flags |= f_havegroup; @@ -688,13 +724,16 @@ int main(int argc, char *argv[]) else { struct servent *s = getservbyname(optarg, "udp"); if (!s) - die("unknown service name `%s'", optarg); + die(1, "unknown service name `%s'", optarg); port = s->s_port; } break; case 'd': flags |= f_daemon; break; + case 'n': + flags |= f_nofork; + break; case 'f': conffile = optarg; break; @@ -706,7 +745,7 @@ int main(int argc, char *argv[]) * allow it if we're running setuid. Disable the actual login anyway. */ -#ifdef TRACING +#ifndef NTRACE case 'I': if (flags & f_setuid) @@ -718,7 +757,7 @@ int main(int argc, char *argv[]) else pw = getpwnam(optarg); if (!pw) - die("can't impersonate unknown user `%s'", optarg); + die(1, "can't impersonate unknown user `%s'", optarg); from_pw = userdb_copyUser(pw); rq.from = from_pw->pw_uid; flags |= f_dummy; @@ -733,7 +772,7 @@ int main(int argc, char *argv[]) * to! */ -#ifdef TRACING +#ifndef TRACE case 'T': { FILE *fp; @@ -749,12 +788,12 @@ int main(int argc, char *argv[]) if (seteuid(ru)) #endif { - die("couldn't temporarily give up privileges: %s", + die(1, "couldn't temporarily give up privileges: %s", strerror(errno)); } if ((fp = fopen(optarg, "w")) == 0) { - die("couldn't open trace file `%s' for writing: %s", + die(1, "couldn't open trace file `%s' for writing: %s", optarg, strerror(errno)); } @@ -763,9 +802,9 @@ int main(int argc, char *argv[]) #else if (seteuid(eu)) #endif - die("couldn't regain privileges: %s", strerror(errno)); + die(1, "couldn't regain privileges: %s", strerror(errno)); } - traceon(fp, TRACE_DFL); + trace_on(fp, TRACE_DFL); trace(TRACE_MISC, "become: tracing enabled"); } break; @@ -773,22 +812,13 @@ int main(int argc, char *argv[]) /* --- Setting trace levels --- */ -#ifdef TRACING +#ifndef NTRACE case 'L': { - int sense = 1; - unsigned int lvl = 0, l; - const char *p = optarg; /* --- Table of tracing facilities --- */ - typedef struct tr { - char ch; - unsigned int l; - const char *help; - } tr; - - static tr lvltbl[] = { + static trace_opt lvltbl[] = { { 'm', TRACE_MISC, "miscellaneous messages" }, { 's', TRACE_SETUP, "building the request block" }, { 'r', TRACE_RULE, "ruleset scanning" }, @@ -804,51 +834,11 @@ int main(int argc, char *argv[]) { 'A', TRACE_ALL, "all tracing options" }, { 0, 0, 0 } }; - tr *tp; /* --- Output some help if there's no arguemnt --- */ - if (!optarg) { - bc__banner(stdout); - bc__write(stdout, - "\n" - "Tracing options:\n" - "\n"); - for (tp = lvltbl; tp->l; tp++) { - if ((flags & f_setuid) == 0 || tp->l & ~TRACE_PRIV) - printf("%c -- %s\n", tp->ch, tp->help); - } - bc__write(stdout, -"\n" -"Also, `+' and `-' options are recognised to turn on and off various\n" -"tracing options. For example, `A-r' enables everything except ruleset\n" -"tracing, and `A-D+c' is everything except the defaults, but with request\n" -"check tracing.\n" -); - exit(0); - } - - while (*p) { - if (*p == '+') - sense = 1; - else if (*p == '-') - sense = 0; - else { - for (tp = lvltbl; tp->l && *p != tp->ch; tp++) - ; - l = tp->l; - if (flags & f_setuid) - l &= ~TRACE_PRIV; - if (l) - lvl = sense ? (lvl | l) : (lvl & ~l); - else - moan("unknown trace option `%c'", *p); - } - p++; - } - - tracesetlvl(lvl); - yydebug = ((lvl & TRACE_YACC) != 0); + trace_level(traceopt(lvltbl, optarg, TRACE_DFL, + (flags & f_setuid) ? TRACE_PRIV : 0)); } break; #endif @@ -919,7 +909,7 @@ done_options: #ifndef NONETWORK if (flags & f_daemon) { T( trace(TRACE_MISC, "become: daemon mode requested"); ) - daemon_init(conffile, port); + daemon_init(conffile, port, (flags & f_nofork) ? df_nofork : 0); exit(0); } #endif @@ -943,7 +933,7 @@ done_options: else pw = getpwnam(who); if (!pw) - die("unknown user `%s'", who); + die(1, "unknown user `%s'", who); to_pw = userdb_copyUser(pw); rq.to = pw->pw_uid; } @@ -956,7 +946,7 @@ done_options: rq.from = getuid(); pw = getpwuid(rq.from); if (!pw) - die("who are you? (can't find user %li)", (long)rq.from); + die(1, "who are you? (can't find user %li)", (long)rq.from); from_pw = userdb_copyUser(pw); } @@ -967,7 +957,7 @@ done_options: struct hostent *he; uname(&u); if ((he = gethostbyname(u.nodename)) == 0) - die("who am I? (can't resolve `%s')", u.nodename); + die(1, "who am I? (can't resolve `%s')", u.nodename); memcpy(&rq.host, he->h_addr, sizeof(rq.host)); } @@ -989,7 +979,7 @@ done_options: /* --- Check that it's valid --- */ if (group != from_pw->pw_gid && group != to_pw->pw_gid) - die("invalid default group"); + die(1, "invalid default group"); #else @@ -1048,7 +1038,7 @@ done_options: if (group == to_gr[i]) goto group_ok; } - die("invalid default group"); + die(1, "invalid default group"); group_ok:; } @@ -1321,7 +1311,7 @@ done_options: sz = 0; - for (sym_createIter(&i, &bc__env); (e = sym_next(&i)) != 0; ) { + for (sym_mkiter(&i, &bc__env); (e = sym_next(&i)) != 0; ) { /* --- Login style expunges all unpreserved variables --- */ @@ -1350,7 +1340,7 @@ done_options: env = qq = xmalloc((sz + 1) * sizeof(*qq)); - for (sym_createIter(&i, &bc__env); (e = sym_next(&i)) != 0; ) + for (sym_mkiter(&i, &bc__env); (e = sym_next(&i)) != 0; ) *qq++ = e->val; *qq++ = 0; } @@ -1399,6 +1389,7 @@ done_options: * Bugtraq, as a complaint against sudo.] */ + if (!*p) p = "."; sprintf(rq.cmd, "%s/%s", p, binary); if (stat(rq.cmd, &st) == 0 && /* Check it exists */ st.st_mode & 0111 && /* Check it's executable */ @@ -1407,7 +1398,7 @@ done_options: } if (!p) - die("couldn't find `%s' in path", todo[0]); + die(1, "couldn't find `%s' in path", todo[0]); binary = rq.cmd; free(path); } @@ -1426,7 +1417,7 @@ done_options: q = binary; if (*q != '/') { if (!getcwd(b, sizeof(b))) - die("couldn't read current directory: %s", strerror(errno)); + die(1, "couldn't read current directory: %s", strerror(errno)); p += strlen(p); *p++ = '/'; } @@ -1442,7 +1433,7 @@ done_options: */ if (p >= b + sizeof(b) - 1) - die("internal error: buffer overflow while canonifying path"); + die(1, "internal error: buffer overflow while canonifying path"); /* --- Reduce multiple slashes to just one --- */ @@ -1514,7 +1505,7 @@ done_options: rq.cmd); if (!a) - die("permission denied"); + die(1, "permission denied"); } /* --- Now do the job --- */ @@ -1528,13 +1519,13 @@ done_options: #ifdef HAVE_SETGROUPS if (setgroups(ngroups, groups) < 0) - die("couldn't set groups: %s", strerror(errno)); + die(1, "couldn't set groups: %s", strerror(errno)); #endif if (setgid(group) < 0) - die("couldn't set default group: %s", strerror(errno)); + die(1, "couldn't set default group: %s", strerror(errno)); if (setuid(rq.to) < 0) - die("couldn't set uid: %s", strerror(errno)); + die(1, "couldn't set uid: %s", strerror(errno)); /* --- If this was a login, change current directory --- */ @@ -1550,7 +1541,7 @@ done_options: fflush(0); closelog(); execve(rq.cmd, todo, env); - die("couldn't exec `%s': %s", rq.cmd, strerror(errno)); + die(1, "couldn't exec `%s': %s", rq.cmd, strerror(errno)); return (127); }