From 5401eb39da23429e3047844f816810244ce024ed Mon Sep 17 00:00:00 2001 From: des Date: Thu, 31 May 2007 12:57:30 +0000 Subject: [PATCH] Add two run-time parameters, "user" and "group", which specify an unprivileged user and group to which the child process will switch immediately after fork() returns, before it starts accepting connections. The default values are "nobody" and "nogroup" (they should probably be tweakable at compile time...) Note that this does not provide full privilege separation, as there are still channels between the parent and child processes which need to be monitored, but it is an improvement on the previous situation. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1482 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/heritage.h | 6 ++ varnish-cache/bin/varnishd/mgt_child.c | 5 ++ varnish-cache/bin/varnishd/mgt_param.c | 77 ++++++++++++++++++++++++++ varnish-cache/bin/varnishd/varnishd.1 | 47 +++++++++++++++- varnish-cache/bin/varnishd/varnishd.c | 14 +++-- 5 files changed, 144 insertions(+), 5 deletions(-) diff --git a/varnish-cache/bin/varnishd/heritage.h b/varnish-cache/bin/varnishd/heritage.h index bac1ff1a..a4cbf1a5 100644 --- a/varnish-cache/bin/varnishd/heritage.h +++ b/varnish-cache/bin/varnishd/heritage.h @@ -66,6 +66,12 @@ struct heritage { struct params { + /* Unprivileged user / group */ + char *user; + uid_t uid; + char *group; + gid_t gid; + /* TTL used for lack of anything better */ unsigned default_ttl; diff --git a/varnish-cache/bin/varnishd/mgt_child.c b/varnish-cache/bin/varnishd/mgt_child.c index 139b41a3..216f2265 100644 --- a/varnish-cache/bin/varnishd/mgt_child.c +++ b/varnish-cache/bin/varnishd/mgt_child.c @@ -177,6 +177,11 @@ start_child(void) if (i < 0) errx(1, "Could not fork child"); if (i == 0) { + if (geteuid() == 0) { + XXXAZ(setgid(params->gid) == -1); + XXXAZ(setuid(params->uid) == -1); + } + /* Redirect stdin/out/err */ AZ(close(0)); i = open("/dev/null", O_RDONLY); diff --git a/varnish-cache/bin/varnishd/mgt_param.c b/varnish-cache/bin/varnishd/mgt_param.c index b90408be..fda73cd0 100644 --- a/varnish-cache/bin/varnishd/mgt_param.c +++ b/varnish-cache/bin/varnishd/mgt_param.c @@ -29,6 +29,10 @@ * $Id$ */ +#include + +#include +#include #include #include #include @@ -133,6 +137,70 @@ tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg, un /*--------------------------------------------------------------------*/ +static void +tweak_user(struct cli *cli, struct parspec *par, const char *arg) +{ + struct passwd *pw; + struct group *gr; + + (void)par; + if (arg != NULL) { + if ((pw = getpwnam(arg)) == NULL) { + cli_out(cli, "Unknown user"); + cli_result(cli, CLIS_PARAM); + return; + } + if (params->user) + free(params->user); + params->user = strdup(pw->pw_name); + AN(params->user); + params->uid = pw->pw_uid; + + /* set group to user's primary group */ + if (params->group) + free(params->group); + if ((gr = getgrgid(pw->pw_gid)) != NULL && + (gr = getgrnam(gr->gr_name)) != NULL && + gr->gr_gid == pw->pw_gid) { + params->group = strdup(gr->gr_name); + AN(params->group); + } + params->gid = pw->pw_gid; + } else if (params->user) { + cli_out(cli, "%s (%d)", params->user, (int)params->uid); + } else { + cli_out(cli, "%d", (int)params->uid); + } +} + +/*--------------------------------------------------------------------*/ + +static void +tweak_group(struct cli *cli, struct parspec *par, const char *arg) +{ + struct group *gr; + + (void)par; + if (arg != NULL) { + if ((gr = getgrnam(arg)) == NULL) { + cli_out(cli, "Unknown group"); + cli_result(cli, CLIS_PARAM); + return; + } + if (params->group) + free(params->group); + params->group = strdup(gr->gr_name); + AN(params->group); + params->gid = gr->gr_gid; + } else if (params->group) { + cli_out(cli, "%s (%d)", params->group, (int)params->gid); + } else { + cli_out(cli, "%d", (int)params->gid); + } +} + +/*--------------------------------------------------------------------*/ + static void tweak_default_ttl(struct cli *cli, struct parspec *par, const char *arg) { @@ -447,6 +515,15 @@ tweak_ping_interval(struct cli *cli, struct parspec *par, const char *arg) * change its default value. */ static struct parspec parspec[] = { + { "user", tweak_user, + "The unprivileged user to run as. Setting this will " + "also set \"group\" to the specified user's primary group.\n" + MUST_RESTART, + "nobody" }, + { "group", tweak_group, + "The unprivileged group to run as.\n" + MUST_RESTART, + "nogroup" }, { "default_ttl", tweak_default_ttl, "The TTL assigned to objects if neither the backend nor " "the VCL code assigns one.\n" diff --git a/varnish-cache/bin/varnishd/varnishd.1 b/varnish-cache/bin/varnishd/varnishd.1 index c7d4fe37..2218399f 100644 --- a/varnish-cache/bin/varnishd/varnishd.1 +++ b/varnish-cache/bin/varnishd/varnishd.1 @@ -28,7 +28,7 @@ .\" .\" $Id$ .\" -.Dd May 16, 2007 +.Dd May 30, 2007 .Dt VARNISHD 1 .Os .Sh NAME @@ -40,12 +40,14 @@ .Op Fl b Ar host Ns Op : Ns Ar port .Op Fl d .Op Fl f Ar config +.Op Fl g Ar group .Op Fl h Ar type Ns Op , Ns Ar options .Op Fl P Ar file .Op Fl p Ar param Ns = Ns Ar value .Op Fl s Ar type Ns Op , Ns Ar options .Op Fl T Ar address Ns Op : Ns Ar port .Op Fl t Ar ttl +.Op Fl u Ar user .Op Fl V .Op Fl w Ar min Ns Op , Ns Ar max Ns Op , Ns Ar timeout .Sh DESCRIPTION @@ -114,6 +116,12 @@ default. See .Xr vcl 7 for details on VCL syntax. +.It Fl g Ar group +Specifies the name of an unprivileged group to which the child process +should switch before it starts accepting connections. +This is a shortcut for specifying the +.Va group +run-time parameter. .It Fl h Ar type Ns Op , Ns Ar options Specifies the hash algorithm. See @@ -148,6 +156,15 @@ Specifies a hard minimum time to live for cached documents. This is a shortcut for specifying the .Va default_ttl run-time parameter. +.It Fl u Ar user +Specifies the name of an unprivileged user to which the child process +should switch before it starts accepting connections. +This is a shortcut for specifying the +.Va user +run-time parameter. +.Pp +If specifying both a user and a group, the user should be specified +first. .It Fl V Display the version number and exit. .It Fl w Ar min Ns Op , Ns Ar max Ns Op , Ns Ar timeout @@ -349,6 +366,20 @@ The default chunk size used when retrieving documents for which the backend server does not specify a content length. .Pp The default is 128 kilobytes. +.It Va group +The name of an unprivileged group to which the child process should +switch before it starts accepting connections. +Note that setting +.Va user +will automatically set +.Va group +to the primary group of the specified user, so if both +.Va user +and +.Va group +are specified, the latter should be specified last. +.Pp +The default is "nogroup". .It Va http_workspace The size of the per-session workspace for HTTP protocol data. For performance reasons, this space is preallocated, so any change to @@ -443,6 +474,20 @@ when the number of worker threads exceeds .Va thread_pool_min . .Pp The default is 120 seconds. +.It Va user +The name of an unprivileged user to which the child process should +switch before it starts accepting connections. +Note that setting +.Va user +will automatically set +.Va group +to the primary group of the specified user, so if both +.Va user +and +.Va group +are specified, the latter should be specified last. +.Pp +The default is "nobody". .It Va vcl_trace Whether to issue log entries for calls to VCL code and their results. Note that this will generate large amounts of log data. diff --git a/varnish-cache/bin/varnishd/varnishd.c b/varnish-cache/bin/varnishd/varnishd.c index b39ab73f..3fbacc12 100644 --- a/varnish-cache/bin/varnishd/varnishd.c +++ b/varnish-cache/bin/varnishd/varnishd.c @@ -401,7 +401,7 @@ main(int argc, char *argv[]) unsigned d_flag = 0; const char *b_arg = NULL; const char *f_arg = NULL; - const char *h_flag = "classic"; + const char *h_arg = "classic"; const char *P_arg = NULL; const char *s_arg = "file"; const char *T_arg = NULL; @@ -441,7 +441,7 @@ main(int argc, char *argv[]) MCF_ParamInit(cli); cli_check(cli); - while ((o = getopt(argc, argv, "a:b:Cdf:h:P:p:s:T:t:Vw:")) != -1) + while ((o = getopt(argc, argv, "a:b:Cdf:g:h:P:p:s:T:t:u:Vw:")) != -1) switch (o) { case 'a': MCF_ParamSet(cli, "listen_address", optarg); @@ -459,8 +459,11 @@ main(int argc, char *argv[]) case 'f': f_arg = optarg; break; + case 'g': + MCF_ParamSet(cli, "group", optarg); + break; case 'h': - h_flag = optarg; + h_arg = optarg; break; case 'P': P_arg = optarg; @@ -483,6 +486,9 @@ main(int argc, char *argv[]) case 'T': T_arg = optarg; break; + case 'u': + MCF_ParamSet(cli, "user", optarg); + break; case 'V': varnish_version("varnishd"); exit(0); @@ -521,7 +527,7 @@ main(int argc, char *argv[]) exit (0); setup_storage(s_arg); - setup_hash(h_flag); + setup_hash(h_arg); VSL_MgtInit(SHMLOG_FILENAME, 8*1024*1024); -- 2.39.5