From b4e8bb4725066a979276997ffd3cbf055f14f85b Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Tue, 4 Mar 2008 12:43:34 +0000 Subject: [PATCH] Cmdline option and config param to support user switching. Original patch from Jason Coby, applied with minor modifications. --- include/system.h | 2 ++ src/main.c | 21 ++++++++++++++++++++- src/system.c | 25 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/include/system.h b/include/system.h index 48e45e7..6e07e38 100644 --- a/include/system.h +++ b/include/system.h @@ -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. * diff --git a/src/main.c b/src/main.c index d8b19c9..5fcb5bb 100644 --- a/src/main.c +++ b/src/main.c @@ -39,6 +39,7 @@ static const char *usage_str = " -R Do a online restart\n" " -q Run quietly\n" " -v Increase verbosity\n" +" -u Assume identity of \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(); diff --git a/src/system.c b/src/system.c index 5107001..ce81948 100644 --- a/src/system.c +++ b/src/system.c @@ -29,6 +29,8 @@ #include #endif +#include + /* * 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"); +} + -- 2.40.0