about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-11-04 08:10:48 +0000
committerEric Wong <normalperson@yhbt.net>2009-11-04 00:27:47 -0800
commitc81ed9a7e417e15b3c3e0ac500af52841b3f8575 (patch)
tree115e21a4434c9ef0732ea10fe37391f8dc4f5599 /lib
parente5491062605d1d6bec1c43bfadb5e348c142df8d (diff)
downloadunicorn-c81ed9a7e417e15b3c3e0ac500af52841b3f8575.tar.gz
This must be called in the after_fork hook because there may be
Ruby modules that'll allow things such as CPU affinity and
scheduling class/priority to be set on a per-worker basis.  So
we give the user the ability to change users at any time during
the after_fork hook.
Diffstat (limited to 'lib')
-rw-r--r--lib/unicorn.rb26
-rw-r--r--lib/unicorn/configurator.rb11
2 files changed, 27 insertions, 10 deletions
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index 94be9d2..396b8e3 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
@@ -117,6 +118,31 @@ module Unicorn
       def ==(other_nr)
         self.nr == other_nr
       end
+
+      # Changes the worker process to the specified +user+ and +group+
+      # This is only intended to be called from within the worker
+      # process from the +after_fork+ hook.  This should be called in
+      # the +after_fork+ hook after any priviledged functions need to be
+      # run (e.g. to set per-worker CPU affinity, niceness, etc)
+      #
+      # Any and all errors raised within this method will be propagated
+      # directly back to the caller (usually the +after_fork+ hook.
+      # These errors commonly include ArgumentError for specifying an
+      # invalid user/group and Errno::EPERM for insufficient priviledges
+      def user(user, group = nil)
+        # we do not protect the caller, checking Process.euid == 0 is
+        # insufficient because modern systems have fine-grained
+        # capabilities.  Let the caller handle any and all errors.
+        uid = Etc.getpwnam(user).uid
+        gid = Etc.getgrnam(group).gid if group
+        tmp.chown(uid, gid)
+        if gid && Process.egid != gid
+          Process.initgroups(user, gid)
+          Process::GID.change_privilege(gid)
+        end
+        Process.euid != uid and Process::UID.change_privilege(uid)
+      end
+
     end
 
     # Creates a working server on host:port (strange things happen if
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index aee4605..dcbf39a 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -147,16 +147,7 @@ module Unicorn
     #    # drop permissions to "www-data" in the worker
     #    # generally there's no reason to start Unicorn as a priviledged user
     #    # as it is not recommended to expose Unicorn to public clients.
-    #    uid, gid = Process.euid, Process.egid
-    #    user, group = 'www-data', 'www-data'
-    #    target_uid = Etc.getpwnam(user).uid
-    #    target_gid = Etc.getgrnam(group).gid
-    #    worker.tmp.chown(target_uid, target_gid)
-    #    if uid != target_uid || gid != target_gid
-    #      Process.initgroups(user, target_gid)
-    #      Process::GID.change_privilege(target_gid)
-    #      Process::UID.change_privilege(target_uid)
-    #    end
+    #    worker.user('www-data', 'www-data') if Process.euid == 0
     #  end
     def after_fork(*args, &block)
       set_hook(:after_fork, block_given? ? block : args[0])