1 //========================================================================
2 //Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.
3 //------------------------------------------------------------------------
4 //Licensed under the Apache License, Version 2.0 (the "License");
5 //you may not use this file except in compliance with the License.
6 //You may obtain a copy of the License at
7 //http://www.apache.org/licenses/LICENSE-2.0
8 //Unless required by applicable law or agreed to in writing, software
9 //distributed under the License is distributed on an "AS IS" BASIS,
10 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 //See the License for the specific language governing permissions and
12 //limitations under the License.
13 //========================================================================
14
15 package org.mortbay.setuid;
16
17 import org.mortbay.jetty.Connector;
18 import org.mortbay.jetty.Server;
19 import org.mortbay.log.Log;
20
21 /**
22 * This extension of {@link Server} will make a JNI call to set the unix UID.
23 *
24 * This can be used to start the server as root so that privileged ports may
25 * be accessed and then switch to a non-root user for security.
26 * Depending on the value of {@link #setStartServerAsPrivileged(boolean)}, either the
27 * server will be started and then the UID set; or the {@link Server#getConnectors()} will be
28 * opened with a call to {@link Connector#open()}, the UID set and then the server is started.
29 * The later is the default and avoids any webapplication code being run as a privileged user,
30 * but will not work if the application code also needs to open privileged ports.
31 *
32 *<p>
33 * The configured umask is set before the server is started and the configured
34 * uid is set after the server is started.
35 * </p>
36 * @author gregw
37 *
38 */
39 public class SetUIDServer extends Server
40 {
41 private int _uid=0;
42 private int _gid=0;
43 private int _umask=0;
44 private boolean _startServerAsPrivileged;
45 private RLimit _rlimitNoFiles = null;
46
47 public void setUsername(String username)
48 {
49 Passwd passwd = SetUID.getpwnam(username);
50 _uid = passwd.getPwUid();
51 }
52
53 public String getUsername()
54 {
55 Passwd passwd = SetUID.getpwuid(_uid);
56 return passwd.getPwName();
57 }
58
59 public void setGroupname(String groupname)
60 {
61 Group group = SetUID.getgrnam(groupname);
62 _gid = group.getGrGid();
63 }
64
65 public String getGroupname()
66 {
67 Group group = SetUID.getgrgid(_gid);
68 return group.getGrName();
69 }
70
71
72 public int getUmask ()
73 {
74 return _umask;
75 }
76
77 public void setUmask(int umask)
78 {
79 _umask=umask;
80 }
81
82 public int getUid()
83 {
84 return _uid;
85 }
86
87 public void setUid(int uid)
88 {
89 _uid=uid;
90 }
91
92 public void setGid(int gid)
93 {
94 _gid=gid;
95 }
96
97 public int getGid()
98 {
99 return _gid;
100 }
101
102 public void setRLimitNoFiles(RLimit rlimit)
103 {
104 _rlimitNoFiles = rlimit;
105 }
106
107 public RLimit getRLimitNoFiles ()
108 {
109 return _rlimitNoFiles;
110 }
111
112 protected void doStart() throws Exception
113 {
114 if (_umask!=0)
115 {
116 Log.info("Setting umask=0"+Integer.toString(_umask,8));
117 SetUID.setumask(_umask);
118 }
119
120 if (_rlimitNoFiles != null)
121 {
122 Log.info("Current "+SetUID.getrlimitnofiles());
123 int success = SetUID.setrlimitnofiles(_rlimitNoFiles);
124 if (success < 0)
125 Log.warn("Failed to set rlimit_nofiles, returned status "+success);
126 Log.info("Set "+SetUID.getrlimitnofiles());
127 }
128
129 if (_startServerAsPrivileged)
130 {
131 super.doStart();
132 if (_gid!=0)
133 {
134 Log.info("Setting GID="+_gid);
135 SetUID.setgid(_gid);
136 }
137 if (_uid!=0)
138 {
139 Log.info("Setting UID="+_uid);
140 SetUID.setuid(_uid);
141 }
142 }
143 else
144 {
145 Connector[] connectors = getConnectors();
146 for (int i=0;connectors!=null && i<connectors.length;i++)
147 connectors[i].open();
148 if (_gid!=0)
149 {
150 Log.info("Setting GID="+_gid);
151 SetUID.setgid(_gid);
152 }
153 if (_uid!=0)
154 {
155 Log.info("Setting UID="+_uid);
156 SetUID.setuid(_uid);
157 }
158 super.doStart();
159 }
160 }
161
162 /* ------------------------------------------------------------ */
163 /**
164 * @return the startServerAsPrivileged
165 */
166 public boolean isStartServerAsPrivileged()
167 {
168 return _startServerAsPrivileged;
169 }
170
171 /* ------------------------------------------------------------ */
172 /**
173 * @see {@link Connector#open()}
174 * @param startServerAsPrivileged 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.
175 */
176 public void setStartServerAsPrivileged(boolean startContextsAsPrivileged)
177 {
178 _startServerAsPrivileged=startContextsAsPrivileged;
179 }
180
181 }