Skip to content

Commit 209027f

Browse files
author
Richard Jones
committed
support setgid and running on port < 1024 (patch [SF#777528])
1 parent c0b8243 commit 209027f

File tree

1 file changed

+26
-106
lines changed

1 file changed

+26
-106
lines changed

roundup/scripts/roundup_server.py

Lines changed: 26 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#
1717
""" HTTP Server that serves roundup.
1818
19-
$Id: roundup_server.py,v 1.28 2003-10-05 23:29:49 richard Exp $
19+
$Id: roundup_server.py,v 1.29 2003-10-10 00:40:16 richard Exp $
2020
"""
2121

2222
# python version check
@@ -122,11 +122,6 @@ def inner_run_cgi(self):
122122

123123
if rest == '/favicon.ico':
124124
raise client.NotFound
125-
# self.send_response(200)
126-
# self.send_header('Content-Type', 'image/x-ico')
127-
# self.end_headers()
128-
# self.wfile.write(favicon)
129-
# return
130125

131126
i = rest.rfind('?')
132127
if i >= 0:
@@ -203,98 +198,6 @@ def address_string(self):
203198
host, port = self.client_address
204199
return socket.getfqdn(host)
205200

206-
try:
207-
import win32serviceutil
208-
except:
209-
RoundupService = None
210-
else:
211-
# allow the win32
212-
import win32service
213-
import win32event
214-
from win32event import *
215-
from win32file import *
216-
217-
SvcShutdown = "ServiceShutdown"
218-
219-
class RoundupService(win32serviceutil.ServiceFramework,
220-
BaseHTTPServer.HTTPServer):
221-
''' A Roundup standalone server for Win32 by Ewout Prangsma
222-
'''
223-
_svc_name_ = "Roundup Bug Tracker"
224-
_svc_display_name_ = "Roundup Bug Tracker"
225-
address = ('', 8888)
226-
def __init__(self, args):
227-
win32serviceutil.ServiceFramework.__init__(self, args)
228-
BaseHTTPServer.HTTPServer.__init__(self, self.address,
229-
RoundupRequestHandler)
230-
231-
# Create the necessary NT Event synchronization objects...
232-
# hevSvcStop is signaled when the SCM sends us a notification
233-
# to shutdown the service.
234-
self.hevSvcStop = win32event.CreateEvent(None, 0, 0, None)
235-
236-
# hevConn is signaled when we have a new incomming connection.
237-
self.hevConn = win32event.CreateEvent(None, 0, 0, None)
238-
239-
# Hang onto this module for other people to use for logging
240-
# purposes.
241-
import servicemanager
242-
self.servicemanager = servicemanager
243-
244-
def SvcStop(self):
245-
# Before we do anything, tell the SCM we are starting the
246-
# stop process.
247-
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
248-
win32event.SetEvent(self.hevSvcStop)
249-
250-
def SvcDoRun(self):
251-
try:
252-
self.serve_forever()
253-
except SvcShutdown:
254-
pass
255-
256-
def get_request(self):
257-
# Call WSAEventSelect to enable self.socket to be waited on.
258-
WSAEventSelect(self.socket, self.hevConn, FD_ACCEPT)
259-
while 1:
260-
try:
261-
rv = self.socket.accept()
262-
except socket.error, why:
263-
if why[0] != WSAEWOULDBLOCK:
264-
raise
265-
# Use WaitForMultipleObjects instead of select() because
266-
# on NT select() is only good for sockets, and not general
267-
# NT synchronization objects.
268-
rc = WaitForMultipleObjects((self.hevSvcStop, self.hevConn),
269-
0, INFINITE)
270-
if rc == WAIT_OBJECT_0:
271-
# self.hevSvcStop was signaled, this means:
272-
# Stop the service!
273-
# So we throw the shutdown exception, which gets
274-
# caught by self.SvcDoRun
275-
raise SvcShutdown
276-
# Otherwise, rc == WAIT_OBJECT_0 + 1 which means
277-
# self.hevConn was signaled, which means when we call
278-
# self.socket.accept(), we'll have our incoming connection
279-
# socket!
280-
# Loop back to the top, and let that accept do its thing...
281-
else:
282-
# yay! we have a connection
283-
# However... the new socket is non-blocking, we need to
284-
# set it back into blocking mode. (The socket that accept()
285-
# returns has the same properties as the listening sockets,
286-
# this includes any properties set by WSAAsyncSelect, or
287-
# WSAEventSelect, and whether its a blocking socket or not.)
288-
#
289-
# So if you yank the following line, the setblocking() call
290-
# will be useless. The socket will still be in non-blocking
291-
# mode.
292-
WSAEventSelect(rv[0], self.hevConn, 0)
293-
rv[0].setblocking(1)
294-
break
295-
return rv
296-
297-
298201
def usage(message=''):
299202
if message:
300203
message = _('Error: %(error)s\n\n')%{'error': message}
@@ -304,6 +207,8 @@ def usage(message=''):
304207
options:
305208
-n: sets the host name
306209
-p: sets the port to listen on
210+
-u: sets the uid to this user after listening on the port
211+
-g: sets the gid to this group after listening on the port
307212
-l: sets a filename to log to (instead of stdout)
308213
-d: sets a filename to write server PID to. This option causes the server
309214
to run in the background. Note: on Windows the PID argument is needed,
@@ -387,17 +292,39 @@ def run():
387292
usage(str(e))
388293

389294
user = ROUNDUP_USER
295+
group = None
390296
for (opt, arg) in optlist:
391297
if opt == '-n': hostname = arg
392298
elif opt == '-p': port = int(arg)
393299
elif opt == '-u': user = arg
300+
elif opt == '-g': group = arg
394301
elif opt == '-d': pidfile = abspath(arg)
395302
elif opt == '-l': logfile = abspath(arg)
396303
elif opt == '-h': usage()
397304
elif opt == '-N': RoundupRequestHandler.LOG_IPADDRESS = 0
398305

399306
if pidfile and not logfile:
400307
raise ValueError, _("logfile *must* be specified if pidfile is")
308+
309+
# obtain server before changing user id - allows to use port <
310+
# 1024 if started as root
311+
address = (hostname, port)
312+
httpd = BaseHTTPServer.HTTPServer(address, RoundupRequestHandler)
313+
314+
if group is not None and hasattr(os, 'getgid'):
315+
# if root, setgid to the running user
316+
if not os.getgid() and user is not None:
317+
try:
318+
import pwd
319+
except ImportError:
320+
raise ValueError, _("Can't change groups - no pwd module")
321+
try:
322+
gid = pwd.getpwnam(user)[3]
323+
except KeyError:
324+
raise ValueError,_("Group %(group)s doesn't exist")%locals()
325+
os.setgid(gid)
326+
elif os.getgid() and user is not None:
327+
print _('WARNING: ignoring "-g" argument, not root')
401328

402329
if hasattr(os, 'getuid'):
403330
# if root, setuid to the running user
@@ -436,15 +363,9 @@ def run():
436363

437364
# we don't want the cgi module interpreting the command-line args ;)
438365
sys.argv = sys.argv[:1]
439-
address = (hostname, port)
440366

441-
# fork?
442367
if pidfile:
443-
if RoundupService:
444-
# don't do any other stuff
445-
RoundupService.address = address
446-
return win32serviceutil.HandleCommandLine(RoundupService)
447-
elif not hasattr(os, 'fork'):
368+
if not hasattr(os, 'fork'):
448369
print "Sorry, you can't run the server as a daemon on this" \
449370
'Operating System'
450371
sys.exit(0)
@@ -456,7 +377,6 @@ def run():
456377
# appending, unbuffered
457378
sys.stdout = sys.stderr = open(logfile, 'a', 0)
458379

459-
httpd = BaseHTTPServer.HTTPServer(address, RoundupRequestHandler)
460380
print _('Roundup server started on %(address)s')%locals()
461381
try:
462382
httpd.serve_forever()

0 commit comments

Comments
 (0)