This patch is against 2.0.5 and has been tested on a Linux 2.4.22 box running glibc-2.3.2 and compiled with gcc-3.2.3. The idea is that since the GateKeeper is baring a lot of ports to the public Internet and does not need to run with root privileges, then it should be able to be launched at boot-time as an ordinary user and not as root.
Basically, the GateKeeper looks up a given username and then calls setgid() and setuid(). I have tested these syscalls under Linux to ensure that the GateKeeper cannot later reclaim root privileges.
I do not know how to achieve the same goal under Windows, so the WIN32 versions of my functions are just stubs.
And for interest, did you know that you can remove a chunk of template/inline code bloat by passing g++ the following flags?:
-frepo -fno-implement-inlines
The "-fno-implement-inlines" option tells the compiler not to generate a static or extern version of any inline function, whereas -frepo enables the compiler to eliminate duplicate template functions.
Cheers, Chris
--- gk.cxx.orig Wed Dec 11 07:30:52 2002 +++ gk.cxx Tue Sep 16 23:04:06 2003 @@ -203,6 +203,14 @@ #ifdef WIN32 +inline bool IsPrivilegedProcess() +{ + return false; +} + +inline void SetProcessUser(const PString &username) +{} + BOOL WINAPI WinCtrlHandlerProc(DWORD dwCtrlType) { PTRACE(1, "GK\tGatekeeper shutdown"); @@ -211,6 +219,48 @@ } #else +# include <pwd.h> +# include <cstring> + +inline bool IsPrivilegedProcess() +{ + return (::geteuid() == 0); +} + +static void SetProcessUser(const PString &username) +{ + static const size_t MAX_PASSWORD_BUFSIZE = 256; + + struct passwd userdata; + struct passwd *userptr; + char buffer[MAX_PASSWORD_BUFSIZE]; + + int err = ::getpwnam_r(username, + &userdata, + buffer, + sizeof(buffer), + &userptr); + if (userptr == NULL) { + cerr << "Warning: Bad database entry for \"" + << username + << "\": " + << ::strerror(err) + << endl; + } + else { + err = ::setgid(userptr->pw_gid); + if (err != 0) + cerr << "Failed to set group ID: " + << ::strerror(err) + << endl; + + err = ::setuid(userptr->pw_uid); + if (err != 0) + cerr << "Failed to set user ID: " + << ::strerror(err) + << endl; + } +} void UnixShutdownHandler(int sig) { @@ -259,6 +309,7 @@ "i-interface:" "l-timetolive:" "b-bandwidth:" + "u-user:" #if PTRACING "t-trace." "o-output:" @@ -363,6 +414,7 @@ " -i --interface IP : The IP that the gatekeeper listen to\n" " -l --timetolive n : Time to live for client registration\n" " -b --bandwidth n : Specify the total bandwidth\n" + " -u --user name : Run as this user\n" #if PTRACING " -t --trace : Set trace verbosity\n" " -o --output file : Write trace to this file\n" @@ -394,6 +446,10 @@ { PArgList & args = GetArguments(); args.Parse(GetArgumentsParseString()); + + if (args.HasOption('u') && IsPrivilegedProcess()) { + SetProcessUser(args.GetOptionString('u')); + } PIPSocket::Address GKHome = INADDR_ANY;