From 158def7ed5c5100456d05150670cfebc3bc2ddd1 Mon Sep 17 00:00:00 2001 From: John Denker Date: Tue, 31 Jul 2012 13:12:26 -0700 Subject: more-or-less secure way to use setuid features --- .gitignore | 2 + tools/fixown.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/makefile | 23 +++++++--- 3 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 tools/fixown.c diff --git a/.gitignore b/.gitignore index b6369d1..05e4638 100644 --- a/.gitignore +++ b/.gitignore @@ -164,3 +164,5 @@ dummy-mail-transfer-agent_all.deb bash-c wripper ltgrey +fixown +fixown2 diff --git a/tools/fixown.c b/tools/fixown.c new file mode 100644 index 0000000..087e7c9 --- /dev/null +++ b/tools/fixown.c @@ -0,0 +1,139 @@ +#include +#include +#include /* for exit(), atoi() */ +#include +#include +#include + +#include /* for stat() */ +#include /* for stat() */ +#include /* for stat() */ +#include /* for getpwnam_r() */ +#include /* for getgrnam_r() */ + +#include "utils.h" /* for basename() */ + +using namespace std; + +class owngroup{ +public: + string owner; + string group; +}; + +#define x(a,b,c) make_pair(a, owngroup({b,c})) + +map allowed({ + x("fixown", "+root", ""), + x("fixown2", "+root", ""), + x("skrewt", "+qmaild", ""), + x("ltgrey", "+qmaild", ""), + x("greylist", "+qmaild", ""), + x("wripper", "", "+daemon"), +}); + +pid_t mypid; +string progname; +string progid; + +int main(int _argc, char** _argv){ + int argc(_argc); + char** argv(_argv); + { + progname = *argv++; argc--; + mypid = getpid(); + stringstream binder; + binder << basename(progname) << "[" << mypid << "]"; + progid = binder.str(); + } + + list todo; + + while (argc > 0) { + string arg = argv[0]; argc--; argv++; + todo.push_back(arg); + } + + for (list::const_iterator ptr = todo.begin(); + ptr != todo.end(); ptr++){ + string file = *ptr; + if (allowed.find(file) == allowed.end()){ + cerr << progid << " not on the allowed list: " << file << endl; + exit(1); + } + struct stat statbuf; + int rslt = stat(file.c_str(), &statbuf); + if (rslt < 0) { + cerr << progid << " stat failed for " + << file << " : "; + perror(0); + exit(1); + } + mode_t mode = statbuf.st_mode; + string own = allowed[file].owner; + string grp = allowed[file].group; + if (0) cout << oct << mode + << " " << own + << " " << grp + << dec << endl; + + if (own[0] == '+') { + own = own.substr(1); + mode |= S_ISUID; + } + if (grp[0] == '+') { + grp = grp.substr(1); + mode |= S_ISGID; + } + //xx cout << oct << mode << dec << endl << endl; + + uid_t own_num = statbuf.st_uid; + gid_t grp_num = statbuf.st_gid; + + if (own.length()){ + struct passwd pw; + struct passwd* ppw; + long int size = sysconf(_SC_GETPW_R_SIZE_MAX); + char scratch[size]; + getpwnam_r(own.c_str(), &pw, + scratch, size, &ppw); + if (ppw == 0) { + cerr << progid << " user not found: " << own << endl; + exit(1); + } + own_num = pw.pw_uid; + } + //xxx cout << own << " --> " << own_num << endl; + + if (grp.length()){ + struct group gr; + struct group* pgr; + long int size = sysconf(_SC_GETPW_R_SIZE_MAX); + char scratch[size]; + getgrnam_r(grp.c_str(), &gr, + scratch, size, &pgr); + if (pgr == 0) { + cerr << progid << " user not found: " << grp << endl; + exit(1); + } + grp_num = gr.gr_gid; + } + //xxx cout << grp << " --> " << grp_num << endl; + + rslt = chown(file.c_str(), own_num, grp_num); + if (rslt < 0) { + cerr << progid << " chown failed for " + << file << " : "; + perror(0); + exit(1); + } + chmod(file.c_str(), mode); + if (rslt < 0) { + cerr << progid << " chmod failed for " + << file << " : "; + perror(0); + exit(1); + } + + } +} diff --git a/tools/makefile b/tools/makefile index 6594ca8..723d756 100644 --- a/tools/makefile +++ b/tools/makefile @@ -1,5 +1,5 @@ -CC= /usr/bin/g++ -Wall -g -I $(HOME)/lib/include - +CC= /usr/bin/g++ +CFLAGS = -std=gnu++0x -Wall -g -I $(HOME)/lib/include #?? exhibits = checkpassword.patch hi-q.c pido.c pop3.conf smtp.conf \ #?? smtp.rules spamc-zap.patch spamd qmail @@ -15,7 +15,7 @@ qmain = pido.c hi-q.c skrewt.c hi-test.c mail-scan.c greylist.c wripper.c qprogs = $(qmain:%.c=%) # sources for other main programs: -moremain = wripper.c bash-c.c ltgrey.c +moremain = wripper.c bash-c.c ltgrey.c fixown.c moreprogs = $(moremain:%.c=%) nonmain = libltgrey.c @@ -32,23 +32,36 @@ beware_other = checkpassword.c spamc.c | sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \ [ -s $@ ] || rm -f $@' -all: $(qprogs) $(moreprogs) +all: $(qprogs) $(moreprogs) fixown2 show: : --- $(qprogs) +++ $(moreprogs) +fixown: fixown.o utils.o + $(CC) $^ -o $@ + chmod o-rwx $@ + ./fixown2 $@ + +fixown2: fixown.o utils.o + $(CC) $^ -o $@ + chmod o-rwx $@ + ./fixown $@ + skrewt: skrewt.o utils.o $(CC) $^ -lboost_filesystem-mt -lboost_system -o $@ + ./fixown $@ greylist: greylist.o utils.o $(CC) $^ -lboost_filesystem-mt -lboost_system -o $@ + ./fixown $@ ltgrey: ltgrey.o utils.o libltgrey.o $(CC) $^ -lboost_filesystem-mt -lboost_system -o $@ + ./fixown $@ wripper: wripper.o $(CC) $^ -o $@ - chgrp daemon $@ && chmod g+s $@ || true + ./fixown $@ mail-scan: mail-scan.o utils.o $(CC) $^ -lboost_regex -o $@ -- cgit v1.2.3