blob: 499fe3d7364bcaf96314b5f27c2bdeb15defc72e [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.setuid;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* This LifeCycleListener may be added to a {@link Server} to make a JNI call to set the unix UID.
*
* This can be used to start the server as root so that privileged ports may be accessed and then switch to a non-root user for security. Depending on the value
* of {@link #setStartServerAsPrivileged(boolean)}, either the server will be started and then the UID set; or the {@link Server#getConnectors()} will be opened
* with a call to {@link Connector#open()}, the UID set and then the server is started. The later is the default and avoids any webapplication code being run as
* a privileged user, but will not work if the application code also needs to open privileged ports.
*
* <p>
* The configured umask is set before the server is started and the configured gid/uid is set after the server is started.
* </p>
*
*/
public class SetUIDListener implements LifeCycle.Listener
{
private static final Logger LOG = Log.getLogger(SetUIDListener.class);
private int _uid = 0;
private int _gid = 0;
private int _umask = -1;
private boolean _startServerAsPrivileged;
private RLimit _rlimitNoFiles = null;
public void setUsername(String username)
{
Passwd passwd = SetUID.getpwnam(username);
_uid = passwd.getPwUid();
}
public String getUsername()
{
Passwd passwd = SetUID.getpwuid(_uid);
return passwd.getPwName();
}
public void setGroupname(String groupname)
{
Group group = SetUID.getgrnam(groupname);
_gid = group.getGrGid();
}
public String getGroupname()
{
Group group = SetUID.getgrgid(_gid);
return group.getGrName();
}
public int getUmask()
{
return _umask;
}
public String getUmaskOctal()
{
return Integer.toOctalString(_umask);
}
public void setUmask(int umask)
{
_umask = umask;
}
public void setUmaskOctal(String umask)
{
_umask = Integer.parseInt(umask,8);
}
public int getUid()
{
return _uid;
}
public void setUid(int uid)
{
_uid = uid;
}
public void setGid(int gid)
{
_gid = gid;
}
public int getGid()
{
return _gid;
}
public void setRLimitNoFiles(RLimit rlimit)
{
_rlimitNoFiles = rlimit;
}
public RLimit getRLimitNoFiles()
{
return _rlimitNoFiles;
}
protected void setGidUid()
{
if (_gid != 0)
{
LOG.info("Setting GID=" + _gid);
SetUID.setgid(_gid);
}
if (_uid != 0)
{
LOG.info("Setting UID=" + _uid);
SetUID.setuid(_uid);
Passwd pw = SetUID.getpwuid(_uid);
System.setProperty("user.name",pw.getPwName());
System.setProperty("user.home",pw.getPwDir());
}
}
public void lifeCycleFailure(LifeCycle server, Throwable cause)
{
}
public void lifeCycleStarted(LifeCycle server)
{
if (_startServerAsPrivileged)
setGidUid();
}
public void lifeCycleStarting(LifeCycle lifecycle)
{
String jettyUserEnvVariable = System.getenv("JETTY_USER");
if (jettyUserEnvVariable != null)
LOG.warn("JETTY_USER set to: {}. If JETTY_USER is set, starting jetty as root and using " +
"jetty-setuid to switch user won't work!!!", jettyUserEnvVariable);
if (_umask > -1)
{
LOG.info("Setting umask=0" + Integer.toString(_umask,8));
SetUID.setumask(_umask);
}
if (_rlimitNoFiles != null)
{
LOG.info("Current " + SetUID.getrlimitnofiles());
int success = SetUID.setrlimitnofiles(_rlimitNoFiles);
if (success < 0)
LOG.warn("Failed to set rlimit_nofiles, returned status " + success);
LOG.info("Set " + SetUID.getrlimitnofiles());
}
// If we are starting the server privileged, delay the setuid until started.
if (_startServerAsPrivileged)
return;
// Start the thread pool and connectors
try
{
Server server = (Server)lifecycle;
if (server.getThreadPool() instanceof LifeCycle)
((LifeCycle)server.getThreadPool()).start();
Connector[] connectors = server.getConnectors();
if (connectors!=null)
{
for (Connector connector : connectors)
{
if (connector instanceof NetworkConnector)
{
((NetworkConnector)connector).open();
LOG.info("Opened " +connector);
}
else
connector.start();
}
}
}
catch(Exception e)
{
throw new RuntimeException(e);
}
setGidUid();
}
public void lifeCycleStopped(LifeCycle arg0)
{
}
public void lifeCycleStopping(LifeCycle arg0)
{
}
/* ------------------------------------------------------------ */
/**
* @return the startServerAsPrivileged
*/
public boolean isStartServerAsPrivileged()
{
return _startServerAsPrivileged;
}
/* ------------------------------------------------------------ */
/**
* @param startContextsAsPrivileged
* if true, the server is started and then the process UID is switched. If false, the connectors are opened, the UID is switched and then the
* server is started.
*/
public void setStartServerAsPrivileged(boolean startContextsAsPrivileged)
{
_startServerAsPrivileged = startContextsAsPrivileged;
}
}