about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-03-01 08:47:40 +0000
committerEric Wong <normalperson@yhbt.net>2010-03-01 08:47:40 +0000
commit45e89c0fed05396652bd3061b9b4f0814dc7d37d (patch)
tree5b7742de6a4702f4d979356e2bb561fce5515c52
parente37d8d0c6355e48fd6d2627313b9003a160f27fc (diff)
downloadunicorn-45e89c0fed05396652bd3061b9b4f0814dc7d37d.tar.gz
Allowing the "user" directive outside of after_fork reduces the
cognitive overhead for folks that do not need the complexity of
*_fork hooks.  Using Worker#user remains supported as it offers
fine-grained control of user switching.
-rw-r--r--lib/unicorn.rb9
-rw-r--r--lib/unicorn/configurator.rb11
2 files changed, 16 insertions, 4 deletions
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index 8c0ff6e..2a2f54e 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -3,6 +3,7 @@
 require 'fcntl'
 require 'unicorn/socket_helper'
 autoload :Rack, 'rack'
+autoload :Etc, 'etc'
 
 # Unicorn module containing all of the classes (include C extensions) for running
 # a Unicorn web server.  It contains a minimalist HTTP server with just enough
@@ -81,7 +82,7 @@ module Unicorn
                                 :before_fork, :after_fork, :before_exec,
                                 :logger, :pid, :listener_opts, :preload_app,
                                 :reexec_pid, :orig_app, :init_listeners,
-                                :master_pid, :config, :ready_pipe)
+                                :master_pid, :config, :ready_pipe, :user)
     include ::Unicorn::SocketHelper
 
     # prevents IO objects in here from being GC-ed
@@ -162,9 +163,7 @@ module Unicorn
     # releases of Unicorn.  You may need to access it in the
     # before_fork/after_fork hooks.  See the Unicorn::Configurator RDoc
     # for examples.
-    class Worker < Struct.new(:nr, :tmp)
-
-      autoload :Etc, 'etc'
+    class Worker < Struct.new(:nr, :tmp, :switched)
 
       # worker objects may be compared to just plain numbers
       def ==(other_nr)
@@ -194,6 +193,7 @@ module Unicorn
           Process::GID.change_privilege(gid)
         end
         Process.euid != uid and Process::UID.change_privilege(uid)
+        self.switched = true
       end
 
     end
@@ -659,6 +659,7 @@ module Unicorn
       LISTENERS.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
       worker.tmp.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
       after_fork.call(self, worker) # can drop perms
+      worker.user(*user) if user.kind_of?(Array) && ! worker.switched
       self.timeout /= 2.0 # halve it for select()
       build_app! unless preload_app
     end
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index b586c67..64a25e3 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -336,6 +336,17 @@ module Unicorn
       HttpServer::START_CTX[:cwd] = ENV["PWD"] = path
     end
 
+    # Runs worker processes as the specified +user+ and +group+.
+    # The master process always stays running as the user who started it.
+    # This switch will occur after calling the after_fork hook, and only
+    # if the Worker#user method is not called in the after_fork hook
+    def user(user, group = nil)
+      # raises ArgumentError on invalid user/group
+      Etc.getpwnam(user)
+      Etc.getgrnam(group) if group
+      set[:user] = [ user, group ]
+    end
+
     # expands "unix:path/to/foo" to a socket relative to the current path
     # expands pathnames of sockets if relative to "~" or "~username"
     # expands "*:port and ":port" to "0.0.0.0:port"