about summary refs log tree commit homepage
path: root/lib/unicorn.rb
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/unicorn.rb
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/unicorn.rb')
-rw-r--r--lib/unicorn.rb26
1 files changed, 26 insertions, 0 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