summaryrefslogtreecommitdiff
path: root/tools/fixown.c
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2012-07-31 20:12:26 (GMT)
committerJohn Denker <jsd@av8n.com>2012-07-31 21:34:25 (GMT)
commit158def7ed5c5100456d05150670cfebc3bc2ddd1 (patch)
treed7ccefab5c44dd705e977e7bdd8f4bccd490b9da /tools/fixown.c
parent6b22bf70dbdffb38b58e6b69421d432651680a71 (diff)
more-or-less secure way to use setuid features
Diffstat (limited to 'tools/fixown.c')
-rw-r--r--tools/fixown.c139
1 files changed, 139 insertions, 0 deletions
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 <iostream>
+#include <iomanip>
+#include <stdlib.h> /* for exit(), atoi() */
+#include <list>
+#include <map>
+#include <sstream>
+
+#include <sys/types.h> /* for stat() */
+#include <sys/stat.h> /* for stat() */
+#include <unistd.h> /* for stat() */
+#include <pwd.h> /* for getpwnam_r() */
+#include <grp.h> /* 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<string,owngroup> 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<string> todo;
+
+ while (argc > 0) {
+ string arg = argv[0]; argc--; argv++;
+ todo.push_back(arg);
+ }
+
+ for (list<string>::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);
+ }
+
+ }
+}