XO-Server can now drop priviledges.

This commit is contained in:
Julien Fontanet 2013-12-27 12:04:54 +01:00
parent ad5e68091f
commit 774b4051bc
5 changed files with 92 additions and 19 deletions

View File

@ -1,5 +1,35 @@
# Note: Relative paths will be resolved from XO-Server's directory.
#=====================================================================
# It may be necessary to run XO-Server as a priviledged user (e.g.
# `root`) for instance to allow the HTTP server to listen on a
# [priviledged ports](http://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html).
#
# To avoid security issues, XO-Server can drop its priviledges by
# changing the user and the group is running with.
#
# Note: XO-Server will change them just after reading the
# configuration.
# User to run XO-Server as.
#
# Note: The user can be specified using either its name or its numeric
# identifier.
#
# Default: undefined
#user: 'nobody'
# Group to run XO-Server as.
#
# Note: The group can be specified using either its name or its
# numeric identifier.
#
# Default: undefined
#group: 'nogroup'
#=====================================================================
# Configuration of the embedded HTTP server.
http:
@ -52,6 +82,8 @@ http:
mounts:
#'/': '/path/to/xo-web/dist/'
#=====================================================================
# Connection to the Redis server.
redis:
# Syntax: tcp://[db[:password]@]hostname[:port]

View File

@ -21,7 +21,8 @@ $sleep = (ms) ->
setTimeout (-> fiber.run()), ms
$fiber.yield()
# Makes an asynchrouneous function synchrouneous (in a fiber).
# Makes an Node like asynchrouneous function synchrouneous (in a
# fiber).
$synchronize = (fn, ctx) ->
fn = ctx[fn] if $_.isString fn
@ -33,22 +34,46 @@ $synchronize = (fn, ctx) ->
fiber.throwInto error
else
fiber.run result
result = fn.apply ctx, args
# A promise can only be detected once the function has been
# called.
if $isPromise result
result.then(
(result) -> fiber.run result
(error) -> fiber.throwInto error
)
fn.apply ctx, args
$fiber.yield()
# Waits for an event.
#
# Note: if the *error* event is emitted, this function will throw.
$waitEvent = (emitter, event) ->
fiber = $fiber.current
errorHandler = null
handler = (args...) ->
emitter.removeListener 'error', errorHandler
fiber.run args
errorHandler = (error) ->
emitter.removeListener event, handler
fiber.throwInto error
emitter.once event, handler
emitter.once 'error', errorHandler
$fiber.yield()
# Waits for a promise to be fulfilled or broken.
$waitPromise = (promise) ->
fiber = $fiber.current
promise.then(
(result) -> fiber.run result
(error) -> fiber.throwInto error
)
$fiber.yield()
#=====================================================================
module.exports = {
$fiberize
$sleep
$synchronize
$waitEvent
$waitPromise
}

View File

@ -25,7 +25,7 @@ $Session = require './session'
$XO = require './xo'
# Helpers for dealing with fibers.
{$fiberize, $synchronize} = require './fibers-utils'
{$fiberize, $synchronize, $waitEvent} = require './fibers-utils'
# HTTP/HTTPS server which can listen on multiple ports.
$WebServer = require './web-server'
@ -112,6 +112,20 @@ do $fiberize ->
if $nconf.get entry
console.warn "[Warn] `#{entry}` configuration is deprecated."
# Creates the web server according to the configuration.
webServer = new $WebServer()
webServer.listen options for options in $nconf.get 'http:listen'
# Waits for the web server to start listening to drop priviledges.
$waitEvent webServer, 'listening'
try
if (group = $nconf.get 'group')?
process.setgid group
if (user = $nconf.get 'user')?
process.setuid user
catch error
console.warn "[WARN] Failed to change the user or group: #{error.message}"
# Creates the main object which will connects to Xen servers and
# manages all the models.
xo = new $XO()
@ -123,10 +137,6 @@ do $fiberize ->
}
}
# Creates the web server according to the configuration.
webServer = new $WebServer()
webServer.listen options for options in $nconf.get 'http:listen'
# Static file serving (e.g. for XO-Web).
connect = $connect()
for urlPath, filePaths of $nconf.get 'http:mounts'

View File

@ -42,6 +42,7 @@ class $WebServer extends $EventEmitter
constructor: ->
@_servers = []
@_notYetListening = 0
close: ->
server.close() for server in @_servers
@ -65,8 +66,10 @@ class $WebServer extends $EventEmitter
else
server.listen port, host
++@_notYetListening
# Helpful message.
server.once 'listening', ->
server.once 'listening', =>
address = server.address()
if $_.isObject address
{address, port} = address
@ -74,6 +77,10 @@ class $WebServer extends $EventEmitter
console.log "WebServer listening on #{address}"
# If the web server is listening on all addresses, fire the
# `listening` event.
@emit 'listening' unless --@_notYetListening
# Forwards events to this object.
$_.each $events, (event) =>
server.on event, (args...) => @emit event, args...

View File

@ -28,7 +28,7 @@ $Model = require './model'
$XAPI = require './xapi'
# Helpers for dealing with fibers.
{$fiberize, $synchronize} = require './fibers-utils'
{$fiberize, $synchronize, $waitPromise} = require './fibers-utils'
#=====================================================================
@ -266,8 +266,7 @@ class $XO
throw error unless error[0] is 'SESSION_NOT_REGISTERED'
# Connects to existing servers.
getServers = $synchronize 'get', @servers
connect server for server in getServers()
connect server for server in $waitPromise @servers.get()
# Automatically connects to new servers.
@servers.on 'add', (servers) ->