]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
ixfrdist: Implement priv-dropping 6269/head
authorPieter Lexis <pieter.lexis@powerdns.com>
Wed, 14 Feb 2018 15:42:49 +0000 (16:42 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Wed, 14 Feb 2018 15:43:06 +0000 (16:43 +0100)
Closes #6265

docs/manpages/ixfrdist.1.rst
pdns/ixfrdist.cc

index 4f19d920d62e16a7c413080f1590277a4d34dc76..7b7136f2d4e9876ad4662f674b0fedcaa4f6d2a2 100644 (file)
@@ -17,6 +17,8 @@ When a SOA query comes in on the address(es) set with **--listen-address**, :pro
 This query can be followed up with an IXFR or AXFR query, which will then be served.
 Should an IXFR be served, :program:`ixfrdist` will condense the diff into the IXFR.
 
+When using **--uid** or **--gid** the **--work-dir** directory will be accessed (and potentially created) as the proved user/group.
+
 Options
 -------
 
@@ -34,6 +36,8 @@ Options
                                 By default, this is the current working directory.
 --keep <NUM>                    Keep at most *NUM* versions of any zone.
                                 By default, 20 versions are kept.
+--uid <UID>                     Drop effective user-id to *UID* after binding the listen sockets
+--gid <GID>                     Drop effective group-id to *GID* after binding the listen sockets
 
 See also
 --------
index a0465633e7dc634bf4deaca13fa91b6cbac85ee3..aaaa2164859f3670945e24384567857afea40bcf 100644 (file)
@@ -23,6 +23,9 @@
 #include "config.h"
 #endif
 #include <boost/program_options.hpp>
+#include <sys/types.h>
+#include <grp.h>
+#include <pwd.h>
 #include <sys/stat.h>
 #include <mutex>
 #include <thread>
@@ -702,6 +705,8 @@ int main(int argc, char** argv) {
       ("version", "Display the version of ixfrdist")
       ("verbose", "Be verbose")
       ("debug", "Be even more verbose")
+      ("uid", po::value<string>(), "Drop privileges to this user after binding the listen sockets")
+      ("gid", po::value<string>(), "Drop privileges to this group after binding the listen sockets")
       ("listen-address", po::value< vector< string>>(), "IP Address(es) to listen on")
       ("acl", po::value<vector<string>>(), "IP Address masks that are allowed access, by default only loopback addresses are allowed")
       ("server-address", po::value<string>()->default_value("127.0.0.1:5300"), "server address")
@@ -828,6 +833,64 @@ int main(int argc, char** argv) {
 
   g_workdir = g_vm["work-dir"].as<string>();
 
+  int newgid = 0;
+
+  if (g_vm.count("gid") > 0) {
+    string gid = g_vm["gid"].as<string>();
+    if (!(newgid = atoi(gid.c_str()))) {
+      struct group *gr = getgrnam(gid.c_str());
+      if (gr == nullptr) {
+        cerr<<"[ERROR] Can not determine group-id for gid "<<gid<<endl;
+        had_error = true;
+      } else {
+        newgid = gr->gr_gid;
+      }
+    }
+    if(g_verbose) {
+      cerr<<"[INFO] Dropping effective group-id to "<<newgid<<endl;
+    }
+    if (setgid(newgid) < 0) {
+      cerr<<"[ERROR] Could not set group id to "<<newgid<<": "<<stringerror()<<endl;
+      had_error = true;
+    }
+  }
+
+  int newuid = 0;
+
+  if (g_vm.count("uid") > 0) {
+    string uid = g_vm["uid"].as<string>();
+    if (!(newuid = atoi(uid.c_str()))) {
+      struct passwd *pw = getpwnam(uid.c_str());
+      if (pw == nullptr) {
+        cerr<<"[ERROR] Can not determine user-id for uid "<<uid<<endl;
+        had_error = true;
+      } else {
+        newuid = pw->pw_uid;
+      }
+    }
+
+    struct passwd *pw = getpwuid(newuid);
+    if (pw == nullptr) {
+      if (setgroups(0, nullptr) < 0) {
+        cerr<<"[ERROR] Unable to drop supplementary gids: "<<stringerror()<<endl;
+        had_error = true;
+      }
+    } else {
+      if (initgroups(pw->pw_name, newgid) < 0) {
+        cerr<<"[ERROR] Unable to set supplementary groups: "<<stringerror()<<endl;
+        had_error = true;
+      }
+    }
+
+    if(g_verbose) {
+      cerr<<"[INFO] Dropping effective user-id to "<<newuid<<endl;
+    }
+    if (setuid(pw->pw_uid) < 0) {
+      cerr<<"[ERROR] Could not set user id to "<<newuid<<": "<<stringerror()<<endl;
+      had_error = true;
+    }
+  }
+
   if (had_error) {
     // We have already sent the errors to stderr, just die
     return EXIT_FAILURE;