From: Mark Wooding Date: Sun, 13 Apr 2008 17:23:33 +0000 (+0100) Subject: Merge branch 'master' of chiark:src/checkpath X-Git-Tag: 1.2.0~1 X-Git-Url: https://git.distorted.org.uk/~mdw/checkpath/commitdiff_plain/60538794f1efdac9d84632579e36b61ca58c925c?hp=9c42854ddcd101d7c18dbe762afeed91fca5c477 Merge branch 'master' of chiark:src/checkpath * 'master' of chiark:src/checkpath: tmpdir: Allow trusting of particular groups. tmpdir: Introduce option for verbose reporting, for diagnosing problems. Improve formatting before we get too stuck in. Conflicts: tmpdir.c --- diff --git a/checkpath.c b/checkpath.c index a396d14..2047800 100644 --- a/checkpath.c +++ b/checkpath.c @@ -1,7 +1,5 @@ /* -*-c-*- * - * $Id: checkpath.c,v 1.6 2004/04/08 01:36:22 mdw Exp $ - * * Check a path for safety * * (c) 1999 Mark Wooding @@ -154,10 +152,7 @@ static void pop(void) */ static void popall(void) -{ - while (sp->e_link) - pop(); -} + { while (sp->e_link) pop(); } /* --- @push@ --- * * @@ -193,75 +188,82 @@ static void push(struct elt *e) static void report(const struct checkpath *cp, unsigned what, int verbose, const char *p, const char *msg, ...) { + dstr d = DSTR_INIT; + va_list ap; + const char *q = msg; + const char *s; + size_t n; + int e = errno; + uid_t u; + struct passwd *pw; + gid_t g; + struct group *gr; + /* --- Decide whether to bin this message --- */ if (!cp->cp_report || verbose > cp->cp_verbose || !(cp->cp_what & what)) return; + /* --- If no reporting, do the easy thing --- */ + + if (!(cp->cp_what & CP_REPORT)) { + cp->cp_report(what, verbose, p, 0, cp->cp_arg); + return; + } + /* --- Format the message nicely --- */ - if (cp->cp_what & CP_REPORT) { - dstr d = DSTR_INIT; - va_list ap; - const char *q = msg; - size_t n; - int e = errno; - - va_start(ap, msg); - if (verbose > 1) - dstr_puts(&d, "[ "); - if (p) - dstr_putf(&d, "Path: %s: ", p); - while (*q) { - if (*q == '%') { - q++; - switch (*q) { - case 'e': - dstr_puts(&d, strerror(e)); - break; - case 'u': { - uid_t u = (uid_t)va_arg(ap, int); - struct passwd *pw = getpwuid(u); - if (pw) - dstr_putf(&d, "`%s'", pw->pw_name); - else - dstr_putf(&d, "%i", (int)u); - } break; - case 'g': { - gid_t g = (gid_t)va_arg(ap, int); - struct group *gr = getgrgid(g); - if (gr) - dstr_putf(&d, "`%s'", gr->gr_name); - else - dstr_putf(&d, "%i", (int)g); - } break; - case 's': { - const char *s = va_arg(ap, const char *); - dstr_puts(&d, s); - } break; - case '%': - dstr_putc(&d, '%'); - break; - default: - dstr_putc(&d, '%'); - dstr_putc(&d, *q); - break; - } - q++; - } else { - n = strcspn(q, "%"); - DPUTM(&d, q, n); - q += n; + va_start(ap, msg); + if (verbose > 1) + dstr_puts(&d, "[ "); + if (p) + dstr_putf(&d, "Path: %s: ", p); + while (*q) { + if (*q == '%') { + q++; + switch (*q) { + case 'e': + dstr_puts(&d, strerror(e)); + break; + case 'u': + u = (uid_t)va_arg(ap, int); + if ((pw = getpwuid(u)) != 0) + dstr_putf(&d, "`%s'", pw->pw_name); + else + dstr_putf(&d, "%i", (int)u); + break; + case 'g': + g = (gid_t)va_arg(ap, int); + if ((gr = getgrgid(g)) != 0) + dstr_putf(&d, "`%s'", gr->gr_name); + else + dstr_putf(&d, "%i", (int)g); + break; + case 's': + s = va_arg(ap, const char *); + dstr_puts(&d, s); + break; + case '%': + dstr_putc(&d, '%'); + break; + default: + dstr_putc(&d, '%'); + dstr_putc(&d, *q); + break; } + q++; + } else { + n = strcspn(q, "%"); + DPUTM(&d, q, n); + q += n; } - if (verbose > 1) - dstr_puts(&d, " ]"); - DPUTZ(&d); - cp->cp_report(what, verbose, p, d.buf, cp->cp_arg); - dstr_destroy(&d); - va_end(ap); - } else - cp->cp_report(what, verbose, p, 0, cp->cp_arg); + } + if (verbose > 1) + dstr_puts(&d, " ]"); + DPUTZ(&d); + cp->cp_report(what, verbose, p, d.buf, cp->cp_arg); + dstr_destroy(&d); + va_end(ap); } /* --- @sanity@ --- * @@ -281,6 +283,8 @@ static unsigned sanity(const char *p, struct stat *st, { unsigned bad = 0; int stickyok = 0; + int i; + unsigned b; if (S_ISDIR(st->st_mode) && (!(f & f_last) || (cp->cp_what & CP_STICKYOK))) @@ -298,8 +302,7 @@ static unsigned sanity(const char *p, struct stat *st, if ((cp->cp_what & (CP_WRGRP | CP_WROTHGRP)) && (st->st_mode & (0020 | stickyok)) == 0020) { - int i; - unsigned b = CP_WRGRP; + b = CP_WRGRP; if (cp->cp_what & CP_WROTHGRP) { b = CP_WROTHGRP; diff --git a/checkpath.h b/checkpath.h index d52eac9..bd9d256 100644 --- a/checkpath.h +++ b/checkpath.h @@ -1,7 +1,5 @@ /* -*-c-*- * - * $Id: checkpath.h,v 1.4 2004/04/08 01:36:22 mdw Exp $ - * * Check a path for safety * * (c) 1999 Mark Wooding diff --git a/chkpath.c b/chkpath.c index 0751449..65d9390 100644 --- a/chkpath.c +++ b/chkpath.c @@ -1,7 +1,5 @@ /* -*-c-*- * - * $Id: chkpath.c,v 1.4 2004/04/08 01:36:22 mdw Exp $ - * * Check a user's file search path * * (c) 1999 Mark Wooding @@ -45,6 +43,8 @@ /*----- Main code ---------------------------------------------------------*/ +/* --- @report@ --- */ + static void report(unsigned what, int verbose, const char *p, const char *msg, void *arg) diff --git a/tmpdir.1 b/tmpdir.1 index 589c945..05030ba 100644 --- a/tmpdir.1 +++ b/tmpdir.1 @@ -4,8 +4,10 @@ tmpdir \- choose, or check a choice of, temporary directory .SH SYNOPSIS .B tmpdir -.RB [ \-bc ] -.RB [ \-v +.RB [ \-bcv ] +.RB [ \-g +.IR group ] +.RB [ \-C .IR dir ] .SH USAGE The @@ -71,7 +73,15 @@ examine the user's shell and decide which syntax to use based on that. .B "\-c, \-\-cshell" Output an assignment using C shell syntax. .TP -.BI "\-v, --verify " dir +.BI "\-g, \-\-group " group +Trust (the members of) +.IR group : +consider directories they can write to be safe. +.TP +.B "-v, \-\-verbose" +Report problems to standard error. Repeat for more verbosity. +.TP +.BI "\-C, --check " dir Don't try to find a temporary directory; just see whether .I dir is secure, and exit successfully if it is (and unsuccessfully if it diff --git a/tmpdir.c b/tmpdir.c index f7e611b..f0fcb5f 100644 --- a/tmpdir.c +++ b/tmpdir.c @@ -1,7 +1,5 @@ /* -*-c-*- * - * $Id: tmpdir.c,v 1.5 2004/04/08 01:36:22 mdw Exp $ - * * Choose and check temporary directories * * (c) 1999 Mark Wooding @@ -31,6 +29,7 @@ #include "config.h" #include +#include #include #include #include @@ -39,9 +38,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -222,6 +223,13 @@ static char *goodtmp(void) return (0); } +/* --- @report@ --- */ + +static void report(unsigned what, int verbose, + const char *p, const char *msg, + void *arg) + { moan("%s", msg); } + /* --- @usage@ --- */ static void usage(FILE *fp) @@ -254,7 +262,9 @@ Options supported:\n\ \n\ -b, --bourne Output a `TMPDIR' setting for Bourne shell users.\n\ -c, --cshell Output a `TMPDIR' setting for C shell users.\n\ --v, --verify PATH Check whether PATH is good, setting exit status.\n\ +-v, --verbose Report problems to standard error.\n\ +-g, --group NAME Trust group NAME to be honest and true.\n\ +-C, --check PATH Check whether PATH is good, setting exit status.\n\ \n\ The default action is to examine the caller's shell and output a suitable\n\ setting for that shell type.\n\ @@ -262,6 +272,46 @@ setting for that shell type.\n\ fp); } +/* --- @allowgroup@ --- * + * + * Arguments: @const char *gname@ = trust group @gname@ + * + * Returns: --- + * + * Use: Adds the gid corresponding to @gname@ (which may be a number) + * to the list of things we trust. + */ + +static void allowgroup(const char *gname) +{ + struct group *gr; + const char *p; + gid_t g; + + /* --- Check for numeric group spec --- */ + + for (p = gname; *p; p++) { + if (!isdigit((unsigned char)*p)) + goto lookup; + } + g = atoi(gname); + goto insert; + + /* --- Look up a group by name --- */ + +lookup: + if ((gr = getgrnam(gname)) == 0) + die(1, "group %s not found", gname); + g = gr->gr_gid; + + /* --- Insert the group into the table --- */ + +insert: + if (cp.cp_gids >= N(cp.cp_gid)) + die(1, "too many groups"); + cp.cp_gid[cp.cp_gids++] = g; +} + /* --- @main@ --- * * * Arguments: @int argc@ = number of command line arguments @@ -276,6 +326,7 @@ int main(int argc, char *argv[]) { int shell = 0; int duff = 0; + char *p; enum { sh_unknown, @@ -287,10 +338,12 @@ int main(int argc, char *argv[]) ego(argv[0]); me = geteuid(); - cp.cp_what = CP_WRWORLD | CP_WRGRP | CP_WROTHUSR | CP_STICKYOK; + cp.cp_what = (CP_WRWORLD | CP_WROTHGRP | CP_WROTHUSR | + CP_STICKYOK | CP_REPORT); cp.cp_verbose = 0; - cp.cp_report = 0; + cp.cp_report = report; checkpath_setids(&cp); + cp.cp_gids = 0; /* ignore group membership */ pw = getpwuid(me); if (!pw) die(1, "you don't exist"); @@ -304,10 +357,14 @@ int main(int argc, char *argv[]) { "usage", 0, 0, 'u' }, { "bourne", 0, 0, 'b' }, { "cshell", 0, 0, 'c' }, - { "verify", OPTF_ARGREQ, 0, 'v' }, + { "check", OPTF_ARGREQ, 0, 'C' }, + { "verify", OPTF_ARGREQ, 0, 'C' }, + { "verbose", 0, 0, 'v' }, + { "trust-groups", 0, 0, 't' }, + { "group", OPTF_ARGREQ, 0, 'g' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "hVu" "bcv:", opts, 0, 0, 0); + int i = mdwopt(argc, argv, "hVu" "bcvtg:c:", opts, 0, 0, 0); if (i < 0) break; @@ -327,9 +384,15 @@ int main(int argc, char *argv[]) case 'c': shell = sh_csh; break; - case 'v': + case 'C': return (!fullcheck(optarg)); break; + case 'g': + allowgroup(optarg); + break; + case 'v': + cp.cp_verbose++; + break; default: duff = 1; break; @@ -344,7 +407,6 @@ int main(int argc, char *argv[]) /* --- Choose a shell --- */ if (!shell) { - char *p; if (!(p = getenv("SHELL"))) p = pw->pw_shell; if (strstr(p, "csh")) @@ -355,19 +417,16 @@ int main(int argc, char *argv[]) /* --- Start the checking --- */ - { - char *p = goodtmp(); - if (!p) - die(1, "no good tmp directory"); - switch (shell) { - case sh_bourne: - printf("TMPDIR=\"%s\"; export TMPDIR\n", p); - break; - case sh_csh: - printf("setenv TMPDIR \"%s\"\n", p); + if ((p = goodtmp()) == 0) + die(1, "no good tmp directory"); + switch (shell) { + case sh_bourne: + printf("TMPDIR=\"%s\"; export TMPDIR\n", p); + break; + case sh_csh: + printf("setenv TMPDIR \"%s\"\n", p); break; - } - } + } return (0); }