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=-c 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 --- 60538794f1efdac9d84632579e36b61ca58c925c diff --combined checkpath.c index a396d14,85c4b09..2047800 --- a/checkpath.c +++ b/checkpath.c @@@ -1,13 -1,11 +1,11 @@@ /* -*-c-*- * - * $Id: checkpath.c,v 1.6 2004/04/08 01:36:22 mdw Exp $ - * * Check a path for safety * * (c) 1999 Mark Wooding */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of chkpath. * @@@ -15,12 -13,12 +13,12 @@@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * chkpath is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with chkpath; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@@ -28,8 -26,6 +26,8 @@@ /*----- Header files ------------------------------------------------------*/ +#include "config.h" + #include #include #include @@@ -154,10 -150,7 +152,7 @@@ static void pop(void */ static void popall(void) - { - while (sp->e_link) - pop(); - } + { while (sp->e_link) pop(); } /* --- @push@ --- * * @@@ -193,75 -186,82 +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 -281,8 +283,8 @@@ static unsigned sanity(const char *p, s { 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 -300,7 +302,7 @@@ 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; @@@ -501,7 -502,7 +504,7 @@@ void checkpath_setids(struct checkpath cp->cp_uid = getuid(); n = getgroups(sizeof(cp->cp_gid) / sizeof(cp->cp_gid[0]), cp->cp_gid); - + for (i = 0; i < n; i++) { if (cp->cp_gid[i] == g) goto gid_ok; diff --combined checkpath.h index d52eac9,e2f6385..bd9d256 --- a/checkpath.h +++ b/checkpath.h @@@ -1,13 -1,11 +1,11 @@@ /* -*-c-*- * - * $Id: checkpath.h,v 1.4 2004/04/08 01:36:22 mdw Exp $ - * * Check a path for safety * * (c) 1999 Mark Wooding */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of chkpath. * @@@ -15,12 -13,12 +13,12 @@@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * chkpath is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with chkpath; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. diff --combined chkpath.c index 0751449,4230637..65d9390 --- a/chkpath.c +++ b/chkpath.c @@@ -1,13 -1,11 +1,11 @@@ /* -*-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 */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of chkpath. * @@@ -15,12 -13,12 +13,12 @@@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * chkpath is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with chkpath; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@@ -28,8 -26,6 +26,8 @@@ /*----- Header files ------------------------------------------------------*/ +#include "config.h" + #include #include #include @@@ -45,6 -41,8 +43,8 @@@ /*----- Main code ---------------------------------------------------------*/ + /* --- @report@ --- */ + static void report(unsigned what, int verbose, const char *p, const char *msg, void *arg) @@@ -126,7 -124,7 +126,7 @@@ int main(int argc, char *argv[] { "print", 0, 0, 'p' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "hVu vqstp", opts, 0, 0, 0); + int i = mdwopt(argc, argv, "hVu" "vqstp", opts, 0, 0, 0); if (i < 0) break; diff --combined tmpdir.1 index 589c945,4023ed9..05030ba --- a/tmpdir.1 +++ b/tmpdir.1 @@@ -4,14 -4,16 +4,16 @@@ 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 .B tmpdir program creates a secure place for temporary files to be stored, and -outputs an assignment to the +outputs an assignment to the .B TMPDIR variable suitable for execution by a shell. .PP @@@ -71,7 -73,15 +73,15 @@@ examine the user's shell and decide whi .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 --combined tmpdir.c index f7e611b,e4cdde5..f0fcb5f --- a/tmpdir.c +++ b/tmpdir.c @@@ -1,13 -1,11 +1,11 @@@ /* -*-c-*- * - * $Id: tmpdir.c,v 1.5 2004/04/08 01:36:22 mdw Exp $ - * * Choose and check temporary directories * * (c) 1999 Mark Wooding */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of chkpath. * @@@ -15,12 -13,12 +13,12 @@@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * chkpath is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with chkpath; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@@ -28,9 -26,8 +26,10 @@@ /*----- Header files ------------------------------------------------------*/ +#include "config.h" + #include + #include #include #include #include @@@ -39,9 -36,11 +38,11 @@@ #include #include #include + #include #include #include + #include #include #include #include @@@ -182,7 -181,9 +183,7 @@@ good */ static int fullcheck(const char *p) -{ - return (checkpath(p, &cp) == 0 && ok(p, 0)); -} + { return (checkpath(p, &cp) == 0 && ok(p, 0)); } /* --- @goodtmp@ --- * * @@@ -205,12 -206,16 +206,12 @@@ static char *goodtmp(void /* --- Try making a directory in `/tmp' --- */ - if (!(q = getenv("USER")) && !(q = getenv("LOGNAME"))) - q = pw->pw_name; - if ((q = trytmp("/tmp", q)) != 0) + if ((q = trytmp("/tmp", pw->pw_name)) != 0) return (q); /* --- That failed: try a directory in the user's home --- */ - if (!(q = getenv("HOME"))) - q = pw->pw_dir; - if ((q = trytmp(q, "tmp")) != 0) + if ((q = trytmp(pw->pw_dir, "tmp")) != 0) return (q); /* --- Still no joy: give up --- * @@@ -222,6 -227,13 +223,13 @@@ 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 -266,9 +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 -276,46 +272,46 @@@ 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 -330,7 +326,7 @@@ int main(int argc, char *argv[] { int shell = 0; int duff = 0; + char *p; enum { sh_unknown, @@@ -286,11 -341,13 +337,13 @@@ /* --- Initialize variables --- */ ego(argv[0]); - me = getuid(); + 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 -361,14 +357,14 @@@ { "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); ++ int i = mdwopt(argc, argv, "hVu" "bcvtg:c:", opts, 0, 0, 0); if (i < 0) break; @@@ -327,9 -388,15 +384,15 @@@ 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 -411,6 +407,6 @@@ /* --- Choose a shell --- */ if (!shell) { - char *p; if (!(p = getenv("SHELL"))) p = pw->pw_shell; if (strstr(p, "csh")) @@@ -355,19 -421,16 +417,16 @@@ /* --- 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); }