]> err.no Git - varnish/commitdiff
Add two run-time parameters, "user" and "group", which specify an unprivileged
authordes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 31 May 2007 12:57:30 +0000 (12:57 +0000)
committerdes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 31 May 2007 12:57:30 +0000 (12:57 +0000)
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
varnish-cache/bin/varnishd/mgt_child.c
varnish-cache/bin/varnishd/mgt_param.c
varnish-cache/bin/varnishd/varnishd.1
varnish-cache/bin/varnishd/varnishd.c

index bac1ff1a662f8b1a29e41dc6e844c6fde3951a64..a4cbf1a51d50aee015aa44cc8515a33aa59504fd 100644 (file)
@@ -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;
 
index 139b41a38f6de05e6f72136bb6ed638fdda42bf4..216f22656268b8a358ea333dc2559be41ec3e0a9 100644 (file)
@@ -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);
index b90408befcfb87f4cfc9db2432a91917548c7628..fda73cd0e1de8063d40f9b0efd21dc182e98a5ab 100644 (file)
  * $Id$
  */
 
+#include <sys/types.h>
+
+#include <grp.h>
+#include <pwd.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -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"
index c7d4fe37317562b288d9c4ccdbd8cf71e137aa32..2218399fd02a573a439a364e08016d3bf8d96836 100644 (file)
@@ -28,7 +28,7 @@
 .\"
 .\" $Id$
 .\"
-.Dd May 16, 2007
+.Dd May 30, 2007
 .Dt VARNISHD 1
 .Os
 .Sh NAME
 .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.
index b39ab73fda19e2e8dca0f4f8a8ff95bcc356ee07..3fbacc12376a6b7e8e8b469a9ca23673153ca452 100644 (file)
@@ -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);