]> granicus.if.org Git - pgbouncer/commitdiff
Cmdline option and config param to support user switching.
authorMarko Kreen <markokr@gmail.com>
Tue, 4 Mar 2008 12:43:34 +0000 (12:43 +0000)
committerMarko Kreen <markokr@gmail.com>
Tue, 4 Mar 2008 12:43:34 +0000 (12:43 +0000)
Original patch from Jason Coby, applied with minor modifications.

include/system.h
src/main.c
src/system.c

index 48e45e7f8699800e9139df404db3cc97c848b3fb..6e07e3821a59410d1832b2efaf98acf755094b88 100644 (file)
@@ -144,6 +144,8 @@ int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p) _MUSTCHECK;
 const char *basename(const char *path);
 #endif
 
+void change_user(const char *user);
+
 /*
  * memcpy() optimization - improves hash.c.
  *
index d8b19c927ce09989f580031f86f925d5f972e225..5fcb5bbb69f6e76d229d5bda496f92268c4efbba 100644 (file)
@@ -39,6 +39,7 @@ static const char *usage_str =
 "  -R            Do a online restart\n"
 "  -q            Run quietly\n"
 "  -v            Increase verbosity\n"
+"  -u <username> Assume identity of <username>\n"
 "  -V            Show version\n"
 "  -h            Show this help screen and exit\n";
 
@@ -59,6 +60,7 @@ int cf_pause_mode = P_NONE;
 int cf_shutdown = 0;
 int cf_reboot = 0;
 int cf_syslog = 0;
+char *cf_username = "";
 char *cf_syslog_facility = "daemon";
 static char *cf_config_file;
 
@@ -133,6 +135,7 @@ ConfElem bouncer_params[] = {
 {"default_pool_size",  true, CF_INT, &cf_default_pool_size},
 {"syslog",             true, CF_INT, &cf_syslog},
 {"syslog_facility",    true, CF_STR, &cf_syslog_facility},
+{"user",               false, CF_STR, &cf_username},
 
 {"server_reset_query", true, CF_STR, &cf_server_reset_query},
 {"server_check_query", true, CF_STR, &cf_server_check_query},
@@ -563,9 +566,10 @@ int main(int argc, char *argv[])
 {
        int c;
        bool did_takeover = false;
+       char *arg_username = NULL;
 
        /* parse cmdline */
-       while ((c = getopt(argc, argv, "avhdVR")) != EOF) {
+       while ((c = getopt(argc, argv, "avhdVRu:")) != EOF) {
                switch (c) {
                case 'R':
                        cf_reboot = 1;
@@ -582,6 +586,9 @@ int main(int argc, char *argv[])
                case 'q':
                        cf_quiet = 1;
                        break;
+               case 'u':
+                       arg_username = optarg;
+                       break;
                case 'h':
                        usage(0, argv[0]);
                default:
@@ -597,6 +604,18 @@ int main(int argc, char *argv[])
        init_caches();
        admin_setup();
 
+       /* prefer cmdline over config for username */
+       if (arg_username)
+               cf_username = arg_username;
+
+       /* switch user is needed */
+       if (*cf_username)
+               change_user(cf_username);
+
+       /* disallow running as root */
+       if (getuid() == 0)
+               fatal("PgBouncer should not run as root");
+
        /* need to do that after loading config */
        check_limits();
 
index 51070019744d5564f230b850bf9717c6afd16c27..ce81948968fd47e596d54af5b3cbed86874347bf 100644 (file)
@@ -29,6 +29,8 @@
 #include <sys/ucred.h>
 #endif
 
+#include <pwd.h>
+
 /*
  * Minimal spec-conforming implementations of strlcpy(), strlcat().
  */
@@ -101,3 +103,26 @@ const char *basename(const char *path)
 }
 #endif
 
+void change_user(const char *user)
+{
+       const struct passwd *pw;
+       gid_t gset[1];
+
+       /* check for a valid username */
+       pw = getpwnam(user);
+       if (pw == NULL)
+               fatal("could not find user '%s' to switch to", user);
+       
+       gset[0] = pw->pw_gid;
+       if (getuid() == 0) {
+               if (setgroups(1, gset) < 0)
+                       fatal_perror("failed to reset groups");
+       }
+
+       if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0)
+               fatal_perror("failed to assume identity of user '%s'", user);
+
+       if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
+               fatal("setuid() failed to work");
+}
+