diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-client b/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-client index 4d826e3..be33987 100755 --- a/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-client +++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-client @@ -1,10 +1,9 @@ #!/usr/bin/python2.6 # -*- coding: utf-8 -*- # -# Univention Admin Modules -# the command line client program +"""Univention Directory Manager command line client program""" # -# Copyright 2004-2012 Univention GmbH +# Copyright 2004-2013 Univention GmbH # # http://www.univention.de/ # @@ -31,130 +30,148 @@ # /usr/share/common-licenses/AGPL-3; if not, see # . - import locale import socket import time import os import sys -import string -import codecs from univention.config_registry import ConfigRegistry -socket_dir='/tmp/admincli_%s/' % os.getuid() -socket_filename='sock' -socket_path=(socket_dir+socket_filename) - -s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -cmd='' -data='' -output=[] -logfile='' - -pos = 0 -for arg in sys.argv: - pos += 1 - if '--logfile' == arg[:9]: - if len(arg) > 10 and arg[9] == "=": - logfile = arg[10:] - else: +def get_logfile(): + """Extract logfile from command line arguments.""" + logfile = '' + for pos, arg in enumerate(sys.argv): + if arg.startswith('--logfile='): + logfile = arg[len('--logfile='):] + elif arg.startswith('--logfile'): try: - logfile=sys.argv[pos] - except: - print "E: Option --logfile requires an argument" + logfile = sys.argv[pos + 1] + except IndexError: + print >> sys.stderr, "E: Option --logfile requires an argument" sys.exit(1) - -try: - s.connect(socket_path) -except: - pid=os.fork() - if not pid: - null = os.open('/dev/null', os.O_RDWR) + return logfile + + +def fork_server(sock, socket_path): + """Fork UDM command line server.""" + # start new server + pid = os.fork() + if pid == 0: # child + null = os.open(os.path.devnull, os.O_RDWR) os.dup2(null, sys.stdin.fileno()) os.dup2(null, sys.stdout.fileno()) os.dup2(null, sys.stderr.fileno()) - if len(logfile) >0: - os.execv('/usr/share/univention-directory-manager-tools/univention-cli-server', ['univention-cli-server', logfile]) - else: - os.execv('/usr/share/univention-directory-manager-tools/univention-cli-server', ['univention-cli-server']) - else: + argv = ['univention-cli-server'] + logfile = get_logfile() + if logfile: + argv.append(logfile) + os.execv( + '/usr/share/univention-directory-manager-tools/univention-cli-server', + argv + ) + else: # parent os.waitpid(pid, os.P_NOWAIT) ucr = ConfigRegistry() ucr.load() - socket_timeout = int(ucr.get('directory/manager/cmd/sockettimeout', '50')) - stime=int(time.time()) - while not os.path.exists('%s' % socket_path): + socket_timeout = float(ucr.get('directory/manager/cmd/sockettimeout', 50)) + stime = time.time() + socket_timeout + while not os.path.exists(socket_path): time.sleep(0.1) - if int(time.time()) > stime+socket_timeout: - print 'E: Can`t find running daemon after %s Seconds. (No socketfile)' % socket_timeout + if time.time() > stime: + print >> sys.stderr, \ + 'E: Can`t find running daemon after %s seconds. (No socketfile)' % \ + socket_timeout sys.exit(1) - - connection_timeout=30 # this took a long time if getfqdn(host) was used in cli-server - stime=int(time.time()) - socking=0 - while socking == 0: + + # this takes a long time if getfqdn(host) is used in cli-server + connection_timeout = 30 + stime = time.time() + connection_timeout + while True: try: - s.connect(socket_path) - socking=1 - except: + sock.connect(socket_path) + break + except socket.error: time.sleep(0.1) - if int(time.time()) > stime+connection_timeout: - print 'E: Can`t connect daemon after %s seconds.' % connection_timeout + if time.time() > stime: + print >> sys.stderr, \ + 'E: Can`t connect daemon after %s seconds.' % \ + connection_timeout sys.exit(1) - - #sys.exit(1) - -cmdfile=os.path.basename(sys.argv[0]) -if cmdfile == 'univention-passwd': - pwd1='x' - pwd2='y' - while pwd1 != pwd2: - pwd1=raw_input('New password ') - pwd2=raw_input('Re-enter new password ') - if pwd1 != pwd2: - print 'password missmatch' - sys.argv.append('--pwd') - sys.argv.append(pwd1) - - - -s.send(repr(sys.argv)+'\0') - -while 1: - buf = s.recv(1024) - if len(buf) <= 0: - print 'E: Daemon died.' - sys.exit(1) - elif buf[-1] == '\0': - buf = buf[0:-1] - data += buf - break - else: - data += buf - -rc=0 -output = eval(data) -s.close() -if cmdfile == 'univention-passwd': - for line in output: - if line.startswith('passwd error: '): - print line + + +def get_password(): + """Query for interactive password.""" + while True: + pwd1 = raw_input('New password ') + pwd2 = raw_input('Re-enter new password ') + if pwd1 == pwd2: + return pwd1 + print >> sys.stderr, 'password missmatch' + + +def receive_answer(sock): + """Receive complete answer from server.""" + data = '' + while True: + buf = sock.recv(1024) + if len(buf) == 0: + print >> sys.stderr, 'E: Daemon died.' + sys.exit(1) + elif buf[-1] == '\0': + buf = buf[0:-1] + data += buf + break + else: + data += buf + return data + + +def process_output(output, cmdfile): + """Print output and check for errors.""" + result = 0 + if cmdfile == 'univention-passwd': + for line in output: if line == 'passwd error: password alreay used': - rc=1 + result = 1 elif line.startswith('passwd error: The password is to short'): - rc=2 - else: + result = 2 print line -else: - if output[-1] == "OPERATION FAILED": - rc = 3 - output = output [:-1] - for i in output: - if type(i) is unicode: - print i.encode(locale.getpreferredencoding(), 'replace') - else: - print i + else: + if output[-1] == "OPERATION FAILED": + result = 3 + output = output [:-1] + for line in output: + if isinstance(line, unicode): + line = line.encode(locale.getpreferredencoding(), 'replace') + print line + return result + + +def main(): + """Forward request to udm-cli-server.""" + socket_path = '/tmp/admincli_%d/sock' % os.getuid() + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + # connect to already running server + sock.connect(socket_path) + except socket.error: + fork_server(sock, socket_path) + + cmdfile = os.path.basename(sys.argv[0]) + if cmdfile == 'univention-passwd': + password = get_password() + sys.argv += ['--pwd', password] + + sock.send(repr(sys.argv) + '\0') + data = receive_answer(sock) + sock.close() + + output = eval(data) + result = process_output(output, cmdfile) + sys.exit(result) + -sys.exit(rc) +if __name__ == '__main__': + main() diff --git a/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-server b/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-server index 99ef547..edf0896 100755 --- a/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-server +++ b/branches/ucs-3.1/ucs-3.1-1/management/univention-directory-manager-modules/univention-cli-server @@ -1,10 +1,9 @@ #!/usr/bin/python2.6 # -*- coding: utf-8 -*- # -# Univention Admin Modules -# the comannd line server +"""Univention Directory Manager command line server""" # -# Copyright 2004-2012 Univention GmbH +# Copyright 2004-2013 Univention GmbH # # http://www.univention.de/ # @@ -31,262 +30,224 @@ # /usr/share/common-licenses/AGPL-3; if not, see # . - import SocketServer import socket -import select +from select import select import os import sys import traceback -import univention.config_registry -import univention.debug +from univention.config_registry import ConfigRegistry +import univention.debug as ud import univention.admincli.adduser import univention.admincli.admin import univention.admincli.passwd +import signal try: import univention.admincli.license_check - licenseImportError=False + licenseImportError = False except ImportError: - licenseImportError=True + licenseImportError = True -logfile='' +logfile = '' -class myRequestHandler(SocketServer.BaseRequestHandler): +class MyRequestHandler(SocketServer.BaseRequestHandler): + """Handle request on listeneing socket to open new connection.""" def handle(self): - univention.debug.debug(univention.debug.ADMIN, univention.debug.INFO, 'daemon [%s] new connection [%s]' % (os.getppid(), os.getpid())) - sarglist='' - while 1: + ud.debug(ud.ADMIN, ud.INFO, 'daemon [%s] new connection [%s]' % (os.getppid(), os.getpid())) + sarglist = '' + while True: buf = self.request.recv(1024) if buf[-1] == '\0': - buf = buf[0:-1] + buf = buf[:-1] sarglist += buf break else: sarglist += buf doit(sarglist, self.request) - univention.debug.debug(univention.debug.ADMIN, univention.debug.INFO, 'daemon [%s] connection closed [%s]' % (os.getppid(), os.getpid())) - + ud.debug(ud.ADMIN, ud.INFO, 'daemon [%s] connection closed [%s]' % (os.getppid(), os.getpid())) def finish(self): pass -class ForkingTCPServer(SocketServer.ForkingTCPServer): - address_family=socket.AF_UNIX +class ForkingTCPServer(SocketServer.ForkingTCPServer): + """UDM server listening on UNIX socket.""" + address_family = socket.AF_UNIX allow_reuse_address = 1 def server_bind(self): SocketServer.TCPServer.server_bind(self) - host, port = self.socket.getsockname()[:2] + _host, port = self.socket.getsockname()[:2] self.server_name = 'localhost' #socket.getfqdn(host) self.server_port = port + def main(): + """UDM command line server.""" global logfile - logfile='' - if len(sys.argv) < 2: - logfile='/var/log/univention/directory-manager-cmd.log' - else: - logfile=sys.argv[1] + try: + logfile = sys.argv[1] + except IndexError: + logfile = '/var/log/univention/directory-manager-cmd.log' - socket_dir='/tmp/admincli_%s/' % os.getuid() - socket_filename='sock' - socket_path=(socket_dir+socket_filename) + socket_dir = '/tmp/admincli_%s/' % os.getuid() + socket_filename = 'sock' + socket_path = (socket_dir+socket_filename) - univention.debug.init(logfile, 1, 0) + ud.init(logfile, ud.FLUSH, ud.NO_FUNCTION) - if os.path.isfile('%s.run' % socket_path): - runs=1 - runfile=open('%s.run' % socket_path, 'r') - line=runfile.readlines() - runfile.close() + runfilename = '%s.run' % socket_path + if os.path.isfile(runfilename): try: - pid=line[0] - except: - pid='' - if len(pid)>0 and pid[-1:] == '\n': - pid = pid[:-1] - if pid: - try: - os.kill(int(pid), 18) - except OSError: - pid='' + with open(runfilename, 'r') as runfile: + line = runfile.readline().strip() + pid = int(line) + os.kill(pid, signal.SIGCONT) + except (ValueError, OSError): + pid = 0 if not pid: # no pid found or no server running - runs=0 os.unlink(socket_path) - os.unlink('%s.run' % socket_path) + os.unlink(runfilename) os.rmdir(socket_dir) - if not runs==0: - print 'E: Server already running [Pid: %s]' % pid + else: + print >> sys.stderr, 'E: Server already running [Pid: %s]' % pid sys.exit(1) - configRegistry=univention.config_registry.ConfigRegistry() + configRegistry = ConfigRegistry() configRegistry.load() - if configRegistry.has_key('directory/manager/cmd/debug/level'): - debug_level=configRegistry['directory/manager/cmd/debug/level'] - else: - debug_level=1 - univention.debug.set_level(univention.debug.ADMIN, int(debug_level)) - univention.debug.debug(univention.debug.ADMIN, univention.debug.INFO, 'daemon [%s] forked to background' % os.getpid()) + debug_level = configRegistry.get('directory/manager/cmd/debug/level', 1) + ud.set_level(ud.ADMIN, int(debug_level)) + ud.debug(ud.ADMIN, ud.INFO, 'daemon [%s] forked to background' % os.getpid()) try: os.mkdir(socket_dir) os.chmod(socket_dir, 0700) except: - print 'E: Socket directory exists (%s)' % socket_dir + print >> sys.stderr, 'E: socket directory exists (%s)' % socket_dir - if configRegistry.has_key('directory/manager/cmd/timeout'): - timeout=configRegistry['directory/manager/cmd/timeout'] + timeout = configRegistry.get('directory/manager/cmd/timeout') + if timeout: if int(timeout) > 2147483647: - timeout=2147483647 + timeout = 2147483647 else: - timeout=300 - univention.debug.debug(univention.debug.ADMIN, univention.debug.WARN, 'daemon [%s] baseconfig key directory/manager/cmd/timeout not set, setting to default (%s seconds)' % (os.getpid(), timeout)) + timeout = 300 + ud.debug(ud.ADMIN, ud.WARN, 'daemon [%s] baseconfig key directory/manager/cmd/timeout not set, setting to default (%s seconds)' % (os.getpid(), timeout)) + try: - s=ForkingTCPServer(socket_path, myRequestHandler) + sock = ForkingTCPServer(socket_path, MyRequestHandler) os.chmod(socket_path, 0600) except: - print 'E: Failed creating socket (%s). Daemon stopped.' % socket_path - univention.debug.debug(univention.debug.ADMIN, univention.debug.ERROR, 'daemon [%s] Failed creating socket (%s). Daemon stopped.' % - (os.getpid(), socket_filename)) + print >> sys.stderr, 'E: Failed creating socket (%s). Daemon stopped.' % socket_path + ud.debug(ud.ADMIN, ud.ERROR, 'daemon [%s] Failed creating socket (%s). Daemon stopped.' % (os.getpid(), socket_filename)) sys.exit(1) - #s.listen(2) + #sock.listen(2) try: - runfile=open('%s.run' % socket_path, 'w') + runfile = open(runfilename, 'w') + runfile.write(str(os.getpid())) + runfile.close() except IOError: - print 'E: Can`t write runfile' + print >> sys.stderr, 'E: Can`t write runfile' - runfile.write(str(os.getpid())) - runfile.close() try: - while 1: - input=[] - output=[] - exc=[] - input, output, exc = select.select([s],[],[],float(timeout)) - for handler in input: + while True: + rlist, _wlist, _xlist = select([sock], [], [], float(timeout)) + for handler in rlist: handler.handle_request() - if not input: - univention.debug.debug(univention.debug.ADMIN, univention.debug.INFO, 'daemon [%s] stopped after %s seconds idle' % (os.getpid(), timeout)) + if not rlist: + ud.debug(ud.ADMIN, ud.INFO, 'daemon [%s] stopped after %s seconds idle' % (os.getpid(), timeout)) sys.exit(0) finally: os.unlink(socket_path) - os.unlink('%s.run' % socket_path) + os.unlink(runfilename) os.rmdir(socket_dir) - univention.debug.exit() + ud.exit() def doit(sarglist, conn): + """Process single UDM request.""" - def sendMessage(output): - back=u'' - back=repr(output) - conn.send(back+'\0') + def send_message(output): + """Send answer back.""" + back = repr(output) + conn.send(back + '\0') conn.close() global logfile - arglist=eval(sarglist) - - l=0 - b=0 - h=0 - lsf=1 - oldlogfile=logfile - for i in arglist: - if l == 1: - logfile=i - l=0 - if i[:9] == '--logfile': - if len(i) > 10 and i[9] == "=": - logfile=i[10:] - else: - l=1 - if i[:8] == '--binddn': - b=1 - if i[:6] == '--help': - h=1 - if i[:2] == '-h': - h=1 - if i[:2] == '-?': - h=1 - if i[:9] == '--version': - h=1 - - if b == 0: - try: - ls=open('/etc/ldap.secret', 'r') - except IOError: + arglist = eval(sarglist) + + next_is_logfile = False + secret = False + show_help = False + oldlogfile = logfile + for arg in arglist: + if next_is_logfile == 1: + logfile = arg + next_is_logfile = False + continue + if arg.startswith('--logfile='): + logfile = arg[len('--logfile='):] + elif arg.startswith('--logfile'): + next_is_logfile = True + secret |= arg == '--binddn' + show_help |= arg in ('--help', '-h', '-?', '--version') + + if not secret: + for filename in ('/etc/ldap.secret', '/etc/machine.secret'): try: - ls=open('/etc/machine.secret', 'r') + open(filename, 'r').close() + secret = True + break except IOError: - lsf=0 - if h == 0: - sendMessage(["E: Permission denied, try --logfile, --binddn and --bindpwd"]) - sys.exit(1) + continue + else: + if not show_help: + send_message(["E: Permission denied, try --logfile, --binddn and --bindpwd"]) + sys.exit(1) - if logfile!=oldlogfile: - univention.debug.exit() - univention.debug.init(logfile, 1, 0) + if logfile != oldlogfile: + ud.exit() + ud.init(logfile, ud.FLUSH, ud.NO_FUNCTION) - cmdfile=os.path.basename(arglist[0]) - if cmdfile == 'univention-admin' or cmdfile == 'univention-directory-manager' or cmdfile == 'udm': - univention.debug.debug(univention.debug.ADMIN, univention.debug.PROCESS, 'daemon [%s] [%s] Calling univention-directory-manager' % (os.getppid(), os.getpid())) - univention.debug.debug(univention.debug.ADMIN, univention.debug.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) - try: + cmdfile = os.path.basename(arglist[0]) + try: + if cmdfile in ('univention-admin', 'univention-directory-manager', 'udm'): + ud.debug(ud.ADMIN, ud.PROCESS, 'daemon [%s] [%s] Calling univention-directory-manager' % (os.getppid(), os.getpid())) + ud.debug(ud.ADMIN, ud.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) output = univention.admincli.admin.doit(arglist) - except: - info = sys.exc_info() - output = apply(traceback.format_exception, info) - output = [line[:-1] for line in output] - output.append("OPERATION FAILED") - - elif cmdfile == 'univention-passwd': - univention.debug.debug(univention.debug.ADMIN, univention.debug.PROCESS, 'daemon [%s] [%s] Calling univention-passwd' % (os.getppid(), os.getpid())) - univention.debug.debug(univention.debug.ADMIN, univention.debug.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) - try: + elif cmdfile == 'univention-passwd': + ud.debug(ud.ADMIN, ud.PROCESS, 'daemon [%s] [%s] Calling univention-passwd' % (os.getppid(), os.getpid())) + ud.debug(ud.ADMIN, ud.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) output = univention.admincli.passwd.doit(arglist) - except: - info = sys.exc_info() - output = apply(traceback.format_exception, info) - output = [line[:-1] for line in output] - output.append("OPERATION FAILED") - elif cmdfile == 'univention-license-check': - if licenseImportError: - output=['The license check is disabled. You are using the GPL version without any support or maintenance by Univention.'] - else: - univention.debug.debug(univention.debug.ADMIN, univention.debug.PROCESS, 'daemon [%s] [%s] Calling univention-license-check' % (os.getppid(), os.getpid())) - univention.debug.debug(univention.debug.ADMIN, univention.debug.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) - try: + elif cmdfile == 'univention-license-check': + if licenseImportError: + output = ['The license check is disabled. You are using the GPL version without any support or maintenance by Univention.'] + else: + ud.debug(ud.ADMIN, ud.PROCESS, 'daemon [%s] [%s] Calling univention-license-check' % (os.getppid(), os.getpid())) + ud.debug(ud.ADMIN, ud.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) output = univention.admincli.license_check.doit(arglist) - except: - info = sys.exc_info() - output = apply(traceback.format_exception, info) - output = [line[:-1] for line in output] - output.append("OPERATION FAILED") - else: - univention.debug.debug(univention.debug.ADMIN, univention.debug.PROCESS, 'daemon [%s] [%s] Calling univention-adduser' % (os.getppid(), os.getpid())) - univention.debug.debug(univention.debug.ADMIN, univention.debug.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) - try: + else: + ud.debug(ud.ADMIN, ud.PROCESS, 'daemon [%s] [%s] Calling univention-adduser' % (os.getppid(), os.getpid())) + ud.debug(ud.ADMIN, ud.ALL, 'daemon [%s] [%s] arglist: %s' % (os.getppid(), os.getpid(), arglist)) output = univention.admincli.adduser.doit(arglist) - except: - info = sys.exc_info() - output = apply(traceback.format_exception, info) - output = [line[:-1] for line in output] - output.append("OPERATION FAILED") + except: + ext, exv, extb = sys.exc_info() + output = traceback.format_exception(ext, exv, extb) + output = [line[:-1] for line in output] + output.append("OPERATION FAILED") - sendMessage(output) + send_message(output) - if h == 1 and b == 0 and lsf == 0: - univention.debug.debug(univention.debug.ADMIN, univention.debug.INFO, 'daemon [%s] [%s] stopped, because User has no read/write permissions' % (os.getppid(), os.getpid())) + if show_help and not secret: + ud.debug(ud.ADMIN, ud.INFO, 'daemon [%s] [%s] stopped, because User has no read/write permissions' % (os.getppid(), os.getpid())) sys.exit(0) if __name__ == "__main__": pid = os.fork() - if not pid: + if pid == 0: # child os.setsid() main() sys.exit(0) - else: - os.waitpid(pid,os.P_NOWAIT) + else: # parent + os.waitpid(pid, os.P_NOWAIT)