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-
298201def usage (message = '' ):
299202 if message :
300203 message = _ ('Error: %(error)s\n \n ' )% {'error' : message }
@@ -304,6 +207,8 @@ def usage(message=''):
304207options:
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