From mboxrd@z Thu Jan 1 00:00:00 1970 From: rmccabe@sourceware.org Date: 19 Sep 2007 05:17:33 -0000 Subject: [Cluster-devel] conga/luci/utils luci_admin Message-ID: <20070919051733.1134.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: conga Changes by: rmccabe at sourceware.org 2007-09-19 05:17:33 Modified files: luci/utils : luci_admin Log message: - Fix 277711 (RFE: luci_admin should check that luci is running before asking for the password) - Improve error messages Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/utils/luci_admin.diff?cvsroot=cluster&r1=1.56&r2=1.57 --- conga/luci/utils/luci_admin 2007/08/20 16:31:14 1.56 +++ conga/luci/utils/luci_admin 2007/09/19 05:17:32 1.57 @@ -7,7 +7,8 @@ # GNU General Public License as published by the # Free Software Foundation. -import sys, os, select, pwd +import sys, os, pwd +from select import select from stat import S_ISREG import types import xml @@ -16,33 +17,34 @@ sys.path.extend(( '/usr/lib/luci/zope/lib/python', '/usr/lib/luci/zope/lib/python/Products', - '/usr/lib/zope/lib/python', - '/usr/lib/zope/lib/python/Products' '/usr/lib64/luci/zope/lib/python', '/usr/lib64/luci/zope/lib/python/Products', '/usr/lib64/luci/zope/lib64/python', '/usr/lib64/luci/zope/lib64/python/Products', '/usr/lib64/zope/lib64/python', '/usr/lib64/zope/lib/python', + '/usr/lib/zope/lib/python', '/usr/lib64/zope/lib/python/Products', '/usr/lib64/zope/lib64/python/Products', + '/usr/lib/zope/lib/python/Products' )) from Products import __path__ - -for tmppath in [ +for pdir in [ '/usr/lib/luci/zope/lib/python/Products', '/usr/lib64/luci/zope/lib/python/Products', '/usr/lib64/luci/zope/lib64/python/Products', '/usr/lib64/zope/lib/python/Products', '/usr/lib64/zope/lib64/python/Products', - '/usr/lib/zope/lib/python/Products' -]: - if os.path.isdir(tmppath): - __path__.append(tmppath) + '/usr/lib/zope/lib/python/Products']: + + if os.path.isdir(pdir): + __path__.append(pdir) -LUCI_USER = 'luci' -LUCI_GROUP = 'luci' +LUCI_ADMIN_DEBUG = False + +LUCI_USER = 'luci' +LUCI_GROUP = 'luci' LUCI_HOME_DIR = '/var/lib/luci' LUCI_DB_PATH = '%s/var/Data.fs' % LUCI_HOME_DIR @@ -64,43 +66,50 @@ SSL_HTTPS_PUBKEY_PATH = '%s%s' % (LUCI_CERT_DIR, SSL_HTTPS_PUBKEY_NAME) SSL_KEYCONFIG_PATH = '%s%s' % (LUCI_CERT_DIR, SSL_KEYCONFIG_NAME) +err = sys.stderr + +# only root should run this +if os.getuid() != 0: + err.write('Only the \'root\' user can run %s\n' % sys.argv[0]) + err.write('Try again with root privileges.\n') + sys.exit(2) + ssl_key_data = [ { 'id': SSL_PRIVKEY_PATH, 'name': SSL_PRIVKEY_NAME, 'type': 'private', - 'mode': 0600 }, - { 'id': SSL_HTTPS_PRIVKEY_PATH, + 'mode': 0600 + },{ 'id' : SSL_HTTPS_PRIVKEY_PATH, 'name': SSL_HTTPS_PRIVKEY_NAME, 'type': 'private', - 'mode': 0600 }, - { 'id': SSL_PUBKEY_PATH, + 'mode': 0600 + },{ 'id' : SSL_PUBKEY_PATH, 'name': SSL_PUBKEY_NAME, 'type': 'public', - 'mode': 0644 }, - { 'id': SSL_HTTPS_PUBKEY_PATH, + 'mode': 0644 + },{ 'id' : SSL_HTTPS_PUBKEY_PATH, 'name': SSL_HTTPS_PUBKEY_NAME, 'type': 'public', - 'mode': 0644 }, - { 'id': SSL_KEYCONFIG_PATH, + 'mode': 0644 + },{ 'id' : SSL_KEYCONFIG_PATH, 'name': SSL_KEYCONFIG_NAME, 'type': 'config', - 'mode': 0644 } + 'mode': 0644 + } ] for name in os.listdir(LUCI_PEERS_DIR): - ssl_path = '%s%s' % (LUCI_PEERS_DIR, name) - - if S_ISREG(os.stat(ssl_path).st_mode): + cert_path = '%s%s' % (LUCI_PEERS_DIR, name) + if S_ISREG(os.stat(cert_path).st_mode): ssl_key_data.append({ - 'id': ssl_path, - 'name': ssl_path.lstrip(LUCI_CERT_DIR), + 'id': cert_path, + 'name': cert_path.lstrip(LUCI_CERT_DIR), 'type': 'public', 'mode': 0644 }) -orig_stderr = sys.stderr - if '--debug' in sys.argv or '--verbose' in sys.argv: + LUCI_ADMIN_DEBUG = True try: del sys.argv[sys.argv.index('--debug')] except: @@ -110,6 +119,8 @@ del sys.argv[sys.argv.index('--verbose')] except: pass + +if LUCI_ADMIN_DEBUG is True: verbose = sys.stderr else: verbose = file('/dev/null', 'rwb+', 0) @@ -117,15 +128,33 @@ def get_luci_uid_gid(): luci = pwd.getpwnam(LUCI_USER)[2:4] if not luci: - raise Exception, 'user lookup failed' + raise Exception, 'The user "%s" does not exist' % LUCI_USER + if len(luci) != 2: - raise Exception, 'user lookup failed' + raise Exception, 'Unable to determine the UID and GID of %s' % LUCI_USER return luci def set_default_passwd_reset_flag(): # set flag marking admin password has been set - uid, gid = get_luci_uid_gid() - open(LUCI_ADMIN_SET_PATH, 'w').write('True') + + try: + uid, gid = get_luci_uid_gid() + except Exception, e: + err.write('Unable to find the luci user\'s UID and GID: %s\n' % str(e)) + return False + + try: + open(LUCI_ADMIN_SET_PATH, 'w').write('True') + except IOError, e: + if e[0] != 2: + err.write('Unable to open "%s" for writing: %s\n' \ + % (LUCI_ADMIN_SET_PATH, e[1])) + return False + except Exception, e: + err.write('Unable to open "%s" for writing: %s\n' \ + % (LUCI_ADMIN_SET_PATH, str(e))) + return False + os.chown(LUCI_ADMIN_SET_PATH, uid, gid) os.chmod(LUCI_ADMIN_SET_PATH, 0640) return True @@ -134,8 +163,8 @@ try: return open(LUCI_ADMIN_SET_PATH, 'r').read(16).strip() == 'True' except Exception, e: - verbose.write('Failed to write to "%s": %s\n' \ - % (LUCI_ADMIN_SET_PATH, str(e))) + verbose.write('Error reading %s: %s\n' % (LUCI_ADMIN_SET_PATH, str(e))) + return False return False def read_passwd(prompt, confirm_prompt): @@ -144,51 +173,46 @@ while True: s1 = getpass(prompt) if len(s1) < 6: - sys.stderr.write('Passwords must be at least 6 characters long.\n') + err.write('Password has to be@least 6 characters long\n') continue if ' ' in s1 or '\t' in s1: - sys.stderr.write('Spaces are not allowed in passwords.\n') + err.write('Spaces are not allowed in passwords\n') continue s2 = getpass(confirm_prompt) if s1 != s2: - sys.stderr.write('Passwords don\'t match. Try again.\n') + err.write('Password mismatch, try again\n') continue return s1 def restore_luci_db_fsattr(): uid, gid = -1, -1 + try: uid, gid = get_luci_uid_gid() - except: - sys.stderr.write('Unable to determine the user and group of the luci user "%s"\n' \ - % LUCI_USER) + except Exception, e: + err.write('Unable to find the luci user\'s UID and GID: %s\n' % str(e)) return -1 try: os.chown(LUCI_DB_PATH, uid, gid) os.chmod(LUCI_DB_PATH, 0600) - for ext in [ '.tmp', '.old', '.index', '.lock' ]: - cur_path = '%s%s' % (LUCI_DB_PATH, ext) + for fext in [ '.tmp', '.old', '.index', '.lock' ]: + cur_file = '%s%s' % (LUCI_DB_PATH, fext) try: - os.chown(cur_path, uid, gid) - os.chmod(cur_path, 0600) - except OSError, eieio: - if eieio[0] != 2: - sys.stderr.write('Unable to change ownership of "%s" back to user "%s": %s\n' \ - % (cur_path, LUCI_USER, str(eieio))) - except Exception, ei: - sys.stderr.write('Unable to change ownership of "%s" to user "%s": %s %r\n' \ - % (cur_path, LUCI_USER, str(ei), ei)) + os.chown(cur_file, uid, gid) + os.chmod(cur_file, 0600) + except Exception, e: + verbose.write('Error: %s: %s\n' % (cur_file, str(e))) except Exception, e: - sys.stderr.write('Unable to change ownership of the Luci database "%s" back to user "%s": %s\n' \ - % (LUCI_DB_PATH, LUCI_USER, str(e))) + err.write('Unable to change the ownership of the luci database back to user "%s": %s\n' % (LUCI_USER, str(e))) return -1 def set_zope_passwd(user, passwd): sys.stderr = verbose + from ZODB.FileStorage import FileStorage from ZODB.DB import DB from OFS.Application import AppInitializer @@ -198,43 +222,43 @@ from AccessControl.SecurityManagement import newSecurityManager import transaction import App.ImageFile + # Zope wants to open a www/ok.gif and images/error.gif # when you initialize the application object. This keeps # the AppInitializer(app).initialize() call below from failing. App.ImageFile.__init__ = lambda x, y: None - sys.stderr = orig_stderr + sys.stderr = err try: fs = FileStorage(LUCI_DB_PATH) db = DB(fs) conn = db.open() except IOError, e: if e[0] == 11: - sys.stderr.write('It appears that the luci service is running. You must stop the luci service before using this tool to reset passwords.\n') + err.write('It appears that luci is running. Please stop luci before attempting to reset passwords.\n') return -1 else: - sys.stderr.write('Unable to open the Luci database "%s": %s\n' \ + err.write('Unable to open the luci database "%s": %s\n' \ % (LUCI_DB_PATH, str(e))) return -1 except Exception, e: - sys.stderr.write('Unable to open the Luci database "%s": %s\n' \ + err.write('Unable to open the luci database "%s": %s\n' \ % (LUCI_DB_PATH, str(e))) return -1 try: sys.stderr = verbose tempuser = AccessControl.User.UnrestrictedUser('admin', '', - ('manage', 'Manager', 'Owner', 'View', 'Authenticated'), []) + ('manage','Manager', 'Owner', 'View', 'Authenticated'), []) newSecurityManager(None, tempuser) app = conn.root()['Application'] AppInitializer(app).initialize() - sys.stderr = orig_stderr + sys.stderr = err except Exception, e: - sys.stderr = orig_stderr - sys.stderr.write('An error occurred while setting the password for user "%s": %s\n' \ - % (user, str(e))) + sys.stderr = err + err.write('An error occurred while setting the password for user "%s": %s\n' % (user, str(e))) return -1 ret = -1 @@ -242,15 +266,16 @@ pwd_scheme = SSHADigestScheme pwd_hash = '{SSHA}%s' % pwd_scheme.encrypt(SSHADigestScheme(), passwd) acl_users = app.acl_users.users + if len(acl_users): acl_users._user_passwords[user] = pwd_hash transaction.commit() ret = 0 else: - raise Exception, 'failed to set password' + raise Exception, 'no admin user account exists' except Exception, e: - sys.stderr = orig_stderr - sys.stderr.write('Unable to set the password for user "%s": %s\n' \ + sys.stderr = err + err.write('Unable to set the password for user "%s": %s\n' \ % (user, str(e))) conn.close() @@ -266,33 +291,30 @@ return ret -def luci_restore_certs(path, certList): +def luci_restore_certs(certList): if not certList or len(certList) < 1: - sys.stderr.write('Backup file "%s" contains no certificate data\n' \ - % path) - sys.stderr.write('Please check that your backup file is not corrupt.\n') + err.write('Your backup file contains no certificate data. Please check that your backup file is not corrupt.\n') return -1 certList = certList[0].getElementsByTagName('certificate') if not certList or len(certList) < 1: - sys.stderr.write('Backup file "%s" contains no certificate data\n' \ - % path) - sys.stderr.write('Please check that your backup file is not corrupt.\n') + err.write('Your backup file contains no certificate data. Please check that your backup file is not corrupt.\n') return -1 + uid, gid = -1, -1 try: uid, gid = get_luci_uid_gid() except Exception, e: - verbose.write('Error getting uid: %s' % str(e)) + err.write('Unable to find the luci user\'s UID and GID: %s\n' \ + % str(e)) return -1 for c in certList: - cert_path = c.getAttribute('name') - if not cert_path : - sys.stderr.write('Backup file "%s" is missing the "name" attribute for a certificate.\n' \ - % path) + path = c.getAttribute('name') + if not path: + err.write('Missing "name" field for certificate.\n') return -1 - cert_path = '%s%s' % (LUCI_CERT_DIR, str(cert_path)) + path = '%s%s' % (LUCI_CERT_DIR, str(path)) mode = c.getAttribute('mode') if not mode: @@ -302,40 +324,33 @@ data = c.firstChild if not data or not data.wholeText: - sys.stderr.write('Backup file "%s" contains no certificate data.\n' \ - % path) + err.write('"%s" contains no certificate data.' % path) return -1 # Because .prettyprint() was called to write the backup.. data = data.wholeText.strip() if len(data) < 1: - sys.stderr.write('Backup file "%s" contains no certificate data.\n' \ - % path) + err.write('"%s" contains no certificate data.' % path) return -1 data = str(data) try: - f = file(cert_path, 'wb+') - except Exception, e: - sys.stderr.write('Unable to open certificate file "%s" for writing: %s\n' \ - % (cert_path, str(e))) - return -1 - - try: - os.chown(path, uid, gid) - os.chmod(path, mode) - f.write(data) - f.write('\n') - f.close() + f = file(path, 'wb+') except Exception, e: - sys.stderr.write('Unable to restore certificate file "%s": %s\n' \ - % (cert_path, str(e))) + err.write('Unable to create "%s" for writing: %s\n' \ + % (path, str(e))) return -1 + os.chmod(path, mode) + f.write('%s\n' % data) + os.chown(path, uid, gid) + f.close() return None + def luci_restore(argv): sys.stderr = verbose + from ZODB.FileStorage import FileStorage from ZODB.DB import DB from OFS.Application import AppInitializer @@ -347,7 +362,7 @@ from DateTime import DateTime App.ImageFile.__init__ = lambda x, y: None - sys.stderr = orig_stderr + sys.stderr = err if len(argv) > 0: dbfn = argv[0] @@ -366,38 +381,35 @@ conn = db.open() except IOError, e: if e[0] == 11: - sys.stderr.write('It appears that the luci service is running.\n') - sys.stderr.write('You must stop the luci service before using this tool restore from a backup.\n') + err.write('It appears that luci is running. Please stop luci before attempting to restore your installation.\n') return -1 else: - sys.stderr.write('Unable to open the Luci database "%s": %s\n' \ + err.write('Unable to open the luci database "%s": %s\n' \ % (dbfn, str(e))) return -1 except Exception, e: - sys.stderr.write('Unable to open the Luci database "%s": %s\n' \ + err.write('Unable to open the luci database "%s": %s\n' \ % (dbfn, str(e))) return -1 try: node = xml.dom.minidom.parse(backupfn) except Exception, e: - sys.stderr.write('Unable to parse backup data contained in file "%s": %s\n' \ + err.write('Unable to open the luci backup file "%s": %s\n' \ % (backupfn, str(e))) return -1 node = node.getElementsByTagName('luci') if not node or len(node) < 1: - sys.stderr.write('Backup file "%s" is missing the "luci" XML tag.\n' \ - % backupfn) + err.write('Backup file is missing the "luci" XML tag\n') return -1 node = node[0].getElementsByTagName('backupData') if not node or len(node) < 1: - sys.stderr.write('Backup file "%s" is missing the "backupData" XML tag\n' \ - % backupfn) + err.write('Backup file is missing the "backupData" XML tag\n') return -1 - node = node[0] + try: sys.stderr = verbose tempuser = AccessControl.User.UnrestrictedUser('admin', '', @@ -407,11 +419,10 @@ app = conn.root()['Application'] AppInitializer(app).initialize() - sys.stderr = orig_stderr + sys.stderr = err except Exception, e: - sys.stderr = orig_stderr - sys.stderr.write('An error occurred while restoring from backup file "%s": %s\n' \ - % (backupfn, str(e))) + sys.stderr = err + err.write('An error occurred while initializing the luci installation for restoration from backup: %s\n' % str(e)) return -1 try: @@ -419,59 +430,53 @@ portal_mem = app.luci.portal_membership portal_reg = app.luci.portal_registration if not (acl_users and len(acl_users) and portal_mem and portal_reg): - raise Exception, 'no users are present' + raise Exception, 'no admin user account exists' except Exception, e: - sys.stderr.write('Your Luci installation appears to be corrupt: %s' % str(e)) + err.write('Your luci installation appears to be corrupt: %s\n' % str(e)) return -1 userList = node.getElementsByTagName('userList') if not userList or len(userList) < 1: - sys.stderr.write('Backup file "%s" contains no users.\n' % backupfn) - sys.stderr.write('The admin user must exist.\n') - sys.stderr.write('Please check that your backup file is not corrupt.\n') + err.write('Your backup file contains no users. At the very least, the admin user must exist. Please check that your backup file is not corrupt.\n') return -1 userList = userList[0].getElementsByTagName('user') if not userList or len(userList) < 1: - sys.stderr.write('Backup file "%s" contains no users.\n' % backupfn) - sys.stderr.write('The admin user must exist.\n') - sys.stderr.write('Please check that your backup file is not corrupt.\n') + err.write('Your backup file contains no users. At the very least, the admin user must exist. Please check that your backup file is not corrupt.\n') return -1 for u in userList: - uid = u.getAttribute('id') - if not uid: + id = u.getAttribute('id') + if not id: transaction.abort() - sys.stderr.write('Missing the id attribute for a user in backup file "%s"\n' \ - % backupfn) + err.write('Missing ID for user\n') return -1 - uid = str(uid) + id = str(id) passwd = u.getAttribute('passwd') if not passwd: transaction.abort() - sys.stderr.write('Missing password for user "%s" in backup file "%s"\n' \ - % (uid, backupfn)) + err.write('Missing password for user "%s"\n' % id) return -1 passwd = str(passwd) - if uid == 'admin': + if id == 'admin': try: acl_users._user_passwords['admin'] = passwd except Exception, e: transaction.abort() - sys.stderr.write('Unable to restore admin password from backup file "%s": %s\n' \ - % (backupfn, str(e))) + err.write('Unable to restore admin password: %s\n' \ + % str(e)) return -1 else: email = u.getAttribute('email') if not email: - email = '%s at luci.example.org' % uid + email = '%s@luci.example.org' % id else: email = str(email) props = { - 'username': uid, + 'username': id, 'roles': [ 'Member' ], 'domains': [], 'email': email, @@ -492,38 +497,35 @@ if must_change_passwd == 'True' or '1': props['must_change_password'] = True - portal_reg.addMember(uid, passwd, props) + portal_reg.addMember(id, passwd, props) - member = portal_mem.getMemberById(uid) + member = portal_mem.getMemberById(id) if not member: transaction.abort() - sys.stderr.write('An error occurred while restoring the user "%s" from backup file "%s"\n' \ - % (uid, backupfn)) + err.write('An error occurred while restoring the user "%s"\n' \ + % id) return -1 try: aclu = app.luci.acl_users.source_users if aclu and len(aclu): - aclu._user_passwords[uid] = passwd + aclu._user_passwords[id] = passwd else: - raise Exception, 'unable to set password for %s' % uid + raise Exception, 'unable to set password for %s' % id except Exception, e: transaction.abort() - sys.stderr.write('An error occurred while restoring the password for user "%s" from backup file "%s": %s\n' - % (uid, backupfn, str(e))) + err.write('An error occurred while restoring the password for user "%s": %s\n' % (id, str(e))) return -1 - verbose.write('Added user "%s"' % uid) + verbose.write('Added user "%s"\n' % id) transaction.commit() try: x = app.luci.systems.storage if not x: - raise + raise Exception, 'no storage directory' except Exception, e: transaction.abort() - sys.stderr.write('Cannot find the Luci storage systems directory.\n') - sys.stderr.write('Your Luci installation may be corrupt.\n') - sys.stderr.write('Server error: %s\n' % str(e)) + err.write('Cannot find the luci storage systems directory. Your luci installation may be corrupt.\n') return -1 systemList = node.getElementsByTagName('systemList') @@ -535,58 +537,59 @@ verbose.write('No storage systems to add\n') for s in systemList: - uid = s.getAttribute('id') - if not uid: + id = s.getAttribute('id') + if not id: transaction.abort() - sys.stderr.write('Missing ID for storage system. Your backup may be corrupt.\n') + err.write('Missing ID for storage system. Your backup may be corrupt.\n') return -1 - uid = str(uid) + id = str(id) try: title = str(s.getAttribute('title')) except: - title = '__luci__:system' + title = '' - x.manage_addFolder(uid, title) + x.manage_addFolder(id, title) try: - new_system = app.luci.systems.storage.get(uid) + new_system = app.luci.systems.storage.get(id) + if not new_system: - raise + raise Exception, 'unable to add system %s' % id + new_system.manage_acquiredPermissions([]) - new_system.manage_role('View', [ 'Access contents information', 'View' ]) + new_system.manage_role('View', + [ 'Access contents information', 'View' ]) except Exception, e: transaction.abort() - sys.stderr.write('An error occurred while restoring storage system "%s": %s\n' \ - % (uid, str(e))) + err.write('An error occurred while restoring storage system "%s": %s\n' % (id, str(e))) return -1 userPerms = s.getElementsByTagName('permList') if not userPerms or len(userPerms) < 1: - verbose.write('Added storage system "%s"\n' % uid) + verbose.write('Added storage system "%s"\n' % id) continue + userPerms = userPerms[0].getElementsByTagName('ref') for i in userPerms: newuser = i.getAttribute('name') if not newuser: continue + try: - new_system.manage_setLocalRoles(newuser, ['View']) - verbose.write('Added view permission to storage system "%s" for "%s"\n' \ - % (uid, newuser)) + new_system.manage_setLocalRoles(newuser, [ 'View' ]) + verbose.write('Added view permission to storage system "%s" for "%s"\n' % (id, newuser)) except Exception, e: - sys.stderr.write('An error occurred while restoring permission for storage system "%s" for "%s": %s\n' \ - % (uid, newuser, str(e))) + err.write('An error occurred while restoring permission for system "%s" for user "%s": %s\n' % (id, newuser, str(e))) - verbose.write('Added storage system "%s"\n' % uid) + verbose.write('Added storage system "%s"\n' % id) transaction.commit() try: x = app.luci.systems.cluster if not x: raise - except Exception, e: + except: transaction.abort() - sys.stderr.write('Cannot find the Luci cluster directory. Your Luci installation may be corrupt.\n') - sys.stderr.write('Error reported: %s\n' % str(e)) + err.write('Cannot find the luci cluster directory. Your luci installation may be corrupt.\n') return -1 clusterList = node.getElementsByTagName('clusterList') @@ -598,31 +601,32 @@ verbose.write('No clusters to add\n') for c in clusterList: - uid = c.getAttribute('id') - if not uid: + id = c.getAttribute('id') + if not id: transaction.abort() - sys.stderr.write('Cluster element is missing id attribute\n') + err.write('Cluster element is missing id\n') return -1 - uid = str(id) + id = str(id) title = c.getAttribute('title') if not title: - title = '__luci__:cluster' + title = '' else: title = str(title) try: - x.manage_addFolder(uid, title) - new_cluster = app.luci.systems.cluster.get(uid) + x.manage_addFolder(id, title) + new_cluster = app.luci.systems.cluster.get(id) if not new_cluster: - raise + raise Exception, 'unable to add cluster %s' % id + new_cluster.manage_acquiredPermissions([]) - new_cluster.manage_role('View', [ 'Access contents information', 'View' ]) + new_cluster.manage_role('View', + [ 'Access contents information', 'View' ]) except Exception, e: transaction.abort() - sys.stderr.write('An error occurred while restoring the cluster "%s": %s\n' \ - % (uid, str(e))) + err.write('An error occurred while restoring the cluster "%s": %s\n' % (id, str(e))) return -1 viewperm = list() @@ -637,63 +641,60 @@ newuser = str(newuser) try: - new_cluster.manage_setLocalRoles(newuser, ['View']) - verbose.write('Added view permission to cluster "%s" for "%s"\n' \ - % (uid, newuser)) + new_cluster.manage_setLocalRoles(newuser, [ 'View' ]) + verbose.write('Added view permission to cluster "%s" for "%s"\n' % (id, newuser)) except Exception, e: - sys.stderr.write('An error occurred while restoring permission for cluster "%s" for "%s": %s' \ - % (uid, newuser, str(e))) + err.write('An error occurred while restoring permission for cluster "%s" for user "%s"\n' % (id, newuser)) viewperm.append(newuser) clusterSystems = c.getElementsByTagName('csystemList') if not clusterSystems or len(clusterSystems) < 1: - verbose.write('Cluster "%s" has no storage systems\n' % uid) + verbose.write('Cluster "%s" has no nodes\n' % id) else: clusterSystems = clusterSystems[0].getElementsByTagName('csystem') for i in clusterSystems: newsys = i.getAttribute('id') if not newsys: transaction.abort() - sys.stderr.write('Storage system missing id attribute for cluster "%s"\n' \ - % uid) + err.write('Missing node name for cluster "%s"\n' % id) return -1 newsys = str(newsys) stitle = i.getAttribute('title') if not stitle: - stitle = '__luci__:csystem:%s' % uid + stitle = '' else: stitle = str(stitle) try: new_cluster.manage_addFolder(newsys, stitle) - newcs = app.luci.systems.cluster.get(uid).get(newsys) + newcs = app.luci.systems.cluster.get(id).get(newsys) if not newcs: - raise + raise Exception, 'unable to add node %s to cluster %s' \ + % (newsys, id) + newcs.manage_acquiredPermissions([]) - newcs.manage_role('View', [ 'Access contents information', 'View' ]) + newcs.manage_role('View', + [ 'Access contents information', 'View' ]) except Exception, e: transaction.abort() - sys.stderr.write('An error occurred while restoring the storage system "%s" for cluster "%s": %s' \ - % (newsys, uid, str(e))) + err.write('An error occurred while restoring node "%s" for cluster "%s": %s\n' % (newsys, id, str(e))) return -1 transaction.commit() try: for i in viewperm: - newcs.manage_setLocalRoles(i, ['View']) - verbose.write('Added view permission to cluster system "%s" for "%s"\n' \ - % (newsys, i)) - except: + newcs.manage_setLocalRoles(i, [ 'View' ]) + verbose.write('Added view permission to node "%s" in cluster "%s" for user "%s"\n' % (newsys, id, i)) + except Exception, e: transaction.abort() - sys.stderr.write('An error occurred while restoring permissions for cluster system "%s" in cluster "%s" for user "%s"\n' \ - % (newsys, uid, i)) + err.write('An error occurred while restoring view permission to node "%s" in cluster "%s" for user "%s"\n' % (newsys, id, i)) return -1 - verbose.write('Added storage system "%s" for cluster "%s"\n' \ - % (newsys, uid)) + verbose.write('Added node "%s" to cluster "%s"\n' \ + % (newsys, id)) - verbose.write('Added cluster "%s"\n' % uid) + verbose.write('Added cluster "%s"\n' % id) transaction.commit() transaction.commit() @@ -704,35 +705,34 @@ certList = node.getElementsByTagName('certificateList') if not certList or len(certList) < 1: - sys.stderr.write('Backup file "%s" contains no certificate data.\n' \ - % backupfn) + err.write('No certificate data was found.\n') return -1 - if luci_restore_certs(backupfn, certList): - sys.stderr.write('An error occurred while restoring certificate data.\n') + if luci_restore_certs(certList): + err.write('An error occurred while restoring certificate data.\n') return -1 return 0 # This function's ability to work is dependent -# upon the structure of @ddict -def dataToXML(doc, ddict, tltag): +# upon the structure of @obj_dict +def dataToXML(doc, obj_dict, tltag): node = doc.createElement(tltag) - for i in ddict: - if isinstance(ddict[i], types.DictType): + for i in obj_dict: + if isinstance(obj_dict[i], types.DictType): if i[-4:] == 'List': tagname = i else: tagname = tltag[:-4] - temp = dataToXML(doc, ddict[i], tagname) + temp = dataToXML(doc, obj_dict[i], tagname) node.appendChild(temp) - elif isinstance(ddict[i], types.StringType) or isinstance(ddict[i], types.IntType): - node.setAttribute(i, str(ddict[i])) - elif isinstance(ddict[i], types.ListType): - if len(ddict[i]) < 1: + elif isinstance(obj_dict[i], types.StringType) or isinstance(obj_dict[i], types.IntType): + node.setAttribute(i, str(obj_dict[i])) + elif isinstance(obj_dict[i], types.ListType): + if len(obj_dict[i]) < 1: continue temp = doc.createElement(i) - for x in ddict[i]: + for x in obj_dict[i]: t = doc.createElement('ref') t.setAttribute('name', x) temp.appendChild(t.cloneNode(True)) @@ -741,6 +741,7 @@ def luci_backup(argv): sys.stderr = verbose + from ZODB.FileStorage import FileStorage from ZODB.DB import DB from OFS.Application import AppInitializer @@ -748,10 +749,11 @@ import AccessControl.User from AccessControl.SecurityManagement import newSecurityManager import transaction - import CMFPlone + from CMFPlone.utils import getToolByName import App.ImageFile + App.ImageFile.__init__ = lambda x, y: None - sys.stderr = orig_stderr + sys.stderr = err if len(argv) > 0: dbfn = argv[0] @@ -765,14 +767,14 @@ conn = db.open() except IOError, e: if e[0] == 11: - sys.stderr.write('It appears that Luci is running. Please stop Luci before attempting to backup your installation.\n') + err.write('It appears that luci is running. Please stop luci before attempting to backup your installation.\n') return -1 else: - sys.stderr.write('Unable to open the Luci database "%s: %s\n' \ + err.write('Unable to open the luci database "%s": %s\n' \ % (dbfn, str(e))) return -1 except Exception, e: - sys.stderr.write('Unable to open the Luci database "%s: %s\n' \ + err.write('Unable to open the luci database "%s": %s\n' \ % (dbfn, str(e))) return -1 @@ -785,11 +787,10 @@ app = conn.root()['Application'] AppInitializer(app).initialize() - sys.stderr = orig_stderr + sys.stderr = err except Exception, e: - sys.stderr = orig_stderr - sys.stderr.write('An error occurred while initializing luci for restore from backup: %s\n' \ - % str(e)) + sys.stderr = err + err.write('An error occurred while initializing the luci installation for restoration from backup: %s\n' % str(e)) return -1 app.luci.portal_memberdata.pruneMemberDataContents() @@ -798,10 +799,9 @@ try: acl_users = app.acl_users.users if not (acl_users and len(acl_users)): - raise Exception, 'no luci users exist' + raise Exception, 'no admin user account exists' except Exception, e: - sys.stderr.write('Your Luci installation appears to be corrupt: %s\n' \ - % str(e)) + err.write('Your luci installation appears to be corrupt: %s\n' % str(e)) return -1 users = {} @@ -811,15 +811,15 @@ try: acl_users = app.acl_users.users if len(acl_users) < 1: - raise Exception, 'no users exist' + raise Exception, 'no admin user account exists' users['admin'] = { 'id': 'admin', 'name': 'admin', 'passwd': app.acl_users.users._user_passwords['admin'] } - except: - sys.stderr.write('Unable to find the luci admin user.\n') + except Exception, e: + err.write('Unable to find the admin user account: %s\n' % str(e)) return -1 acl_users = app.luci.acl_users.source_users @@ -833,17 +833,15 @@ } except Exception, e: try: - sys.stderr.write('An error occurred while saving details for user "%s": %s' \ - % (i[0], str(e))) + err.write('An error occurred while saving details for user "%s": %s\n' % (i[0], str(e))) except: - sys.stderr.write('An error occurred while saving user information: %s' \ - % str(e)) + err.write('An error occurred while saving user information.\n') return -1 try: - membertool = CMFPlone.utils.getToolByName(app.luci, 'portal_membership') + membertool = getToolByName(app.luci, 'portal_membership') if not membertool: - raise Exception, 'unable to retrieve luci users' + raise Exception, 'unable to find user list' for mem in membertool.listMembers(): try: @@ -856,14 +854,13 @@ % str(e1)) continue except Exception, e: - verbose.write('Error retrieving luci user data: %s\n' % str(e)) + verbose.write('Error: %s\n' % str(e)) try: storagedir = app.luci.systems.storage clusterdir = app.luci.systems.cluster - except Exception, e: - sys.stderr.write('Your Luci installation appears to be corrupt.\n') - sys.stderr.write('Server error: %s\n' % str(e)) + except: + err.write('Your luci installation appears to be corrupt.') return -1 if storagedir and len(storagedir): @@ -903,7 +900,7 @@ if hasattr(csystem[1], 'title'): csystem_hash['title'] = getattr(csystem[1], 'title') else: - csystem_hash['title'] = '__luci__:csystem:' + cluster_name + csystem_hash['title'] = '__luci__:csystem:%s' % cluster_name clusters[cluster_name]['csystemList'][csystem[0]] = csystem_hash transaction.commit() @@ -912,7 +909,7 @@ db.close() fs.close() - backup = { + backup_data = { 'userList': users, 'systemList': systems, 'clusterList': clusters @@ -921,7 +918,7 @@ doc = xml.dom.minidom.Document() luciData = doc.createElement('luci') doc.appendChild(luciData) - dataNode = dataToXML(doc, backup, 'backupData') + dataNode = dataToXML(doc, backup_data, 'backupData') certList = doc.createElement('certificateList') for i in ssl_key_data: @@ -931,9 +928,11 @@ certfile.close() if len(output) < 1: - raise - except: - sys.stderr.write('Unable to read "%s"\n' % i['id']) + raise Exception, '%s contains no data' % i['id'] + except Exception, e: + err.write('Unable to read certificate data from "%s": %s\n' \ + % (i['id'], str(e))) + # An error backing up anything other than the config # is fatal. if i['type'] != 'config': @@ -944,7 +943,7 @@ certNode.setAttribute('name', i['name']) certNode.setAttribute('type', i['type']) certNode.setAttribute('mode', str(oct(i['mode']))) - textNode = doc.createTextNode('\n' + output) + textNode = doc.createTextNode('\n%s' % output) certNode.appendChild(textNode) certList.appendChild(certNode) @@ -953,9 +952,10 @@ return doc -def _execWithCaptureErrorStatus(command, argv, searchPath = 0, root = '/', stdin = 0, catchfd = 1, catcherrfd = 2, closefd = -1): - if not os.access (root + command, os.X_OK): - raise RuntimeError, '%s%s is not executable' % (root, command) + +def exec_cmd(command, argv, searchPath = 0, root = '/', stdin = 0, catchfd = 1, catcherrfd = 2, closefd = -1): + if not os.access ('%s%s' % (root, command), os.X_OK): + raise RuntimeError, '%s is not executable' % command (read, write) = os.pipe() (read_err, write_err) = os.pipe() @@ -964,7 +964,7 @@ if (not childpid): # child if (root and root != '/'): - os.chroot(root) + os.chroot (root) if isinstance(catchfd, tuple): for fd in catchfd: os.dup2(write, fd) @@ -1001,18 +1001,18 @@ rc_err = "" in_list = [read, read_err] while len(in_list) != 0: - i, o, e = select.select(in_list, [], [], 0.1) + i, o, e = select(in_list, [], [], 0.1) for fd in i: if fd == read: - s = os.read(read, 1024) + s = os.read(read, 4096) if s == '': in_list.remove(read) - rc = rc + s + rc = '%s%s' % (rc, s) if fd == read_err: - s = os.read(read_err, 1024) + s = os.read(read_err, 4096) if s == '': in_list.remove(read_err) - rc_err = rc_err + s + rc_err = '%s%s' % (rc_err, s) os.close(read) os.close(read_err) @@ -1021,7 +1021,7 @@ try: (pid, status) = os.waitpid(childpid, 0) except OSError, (errno, msg): - sys.stderr.write('%s waitpid: %s\n' % (__name__ , msg)) + err.write('%s waitpid: %s\n' % (__name__, msg)) if os.WIFEXITED(status): status = os.WEXITSTATUS(status) @@ -1030,6 +1030,7 @@ return (rc, rc_err, status) + def luci_initialized(): # existence of privkey.pem file and # admin password (not the one Data.fs comes with) @@ -1040,18 +1041,18 @@ def generate_ssl_certs(): command = '/bin/rm' - args = [command, '-f', SSL_PRIVKEY_PATH, SSL_PUBKEY_PATH] - _execWithCaptureErrorStatus(command, args) + args = [ command, '-f', SSL_PRIVKEY_PATH, SSL_PUBKEY_PATH ] + exec_cmd(command, args) # /usr/bin/openssl genrsa -out /var/lib/luci/var/certs/privkey.pem 2048 > /dev/null 2>&1 command = '/usr/bin/openssl' - args = [command, 'genrsa', '-out', SSL_PRIVKEY_PATH, '2048'] - _execWithCaptureErrorStatus(command, args) + args = [ command, 'genrsa', '-out', SSL_PRIVKEY_PATH, '2048' ] + exec_cmd(command, args) # /usr/bin/openssl req -new -x509 -key /var/lib/luci/var/certs/privkey.pem -out /var/lib/luci/var/certs/cacert.pem -days 1825 -config /var/lib/luci/var/certs/cacert.config command = '/usr/bin/openssl' - args = [command, 'req', '-new', '-x509', '-key', SSL_PRIVKEY_PATH, '-out', SSL_PUBKEY_PATH, '-days', '1825', '-config', SSL_KEYCONFIG_PATH] - _execWithCaptureErrorStatus(command, args) + args = [ command, 'req', '-new', '-x509', '-key', SSL_PRIVKEY_PATH, '-out', SSL_PUBKEY_PATH, '-days', '1825', '-config', SSL_KEYCONFIG_PATH ] + exec_cmd(command, args) # take ownership and restrict access try: @@ -1061,92 +1062,96 @@ os.chmod(SSL_PRIVKEY_PATH, 0600) os.chmod(SSL_PUBKEY_PATH, 0644) except Exception, e: - verbose.write('Error setting SSL cert file perms: %s\n' % str(e)) + err.write('Error generating SSL certificates: %s\n' % str(e)) command = '/bin/rm' - args = [command, '-f', SSL_PRIVKEY_PATH, SSL_PUBKEY_PATH] - _execWithCaptureErrorStatus(command, args) + args = [ command, '-f', SSL_PRIVKEY_PATH, SSL_PUBKEY_PATH ] + exec_cmd(command, args) return False return True def restart_message(): - print - print - print 'Restart the Luci server for changes to take effect' - print 'eg. service luci restart' - print - return + print '\n\nYou must restart the luci server for changes to take effect.\n' + print 'Run "service luci restart" to do so\n' def init(argv): if luci_initialized(): - sys.stderr.write('Luci site has been already initialized.\n') - sys.stderr.write('If you want to reset admin password, execute\n') - sys.stderr.write('\t%s password\n' % argv[0]) + err.write('luci site has been already initialized.\n') + err.write('If you want to reset admin password, execute\n') + err.write('\t%s password\n' % argv[0]) sys.exit(1) - print 'Initializing the Luci server\n' - + print 'Initializing the luci server\n' print '\nCreating the \'admin\' user\n' - pwd_str = read_passwd('Enter password: ', 'Confirm password: ') + + new_password = read_passwd('Enter password: ', 'Confirm password: ') + print '\nPlease wait...' - if not set_zope_passwd('admin', pwd_str): + + if not set_zope_passwd('admin', new_password): restore_luci_db_fsattr() print 'The admin password has been successfully set.' else: - sys.stderr.write('Unable to set the admin user\'s password.\n') + err.write('Unable to set the admin user\'s password.\n') sys.exit(1) - print 'Generating SSL certificates...' + print 'Generating SSL certificates... ' if generate_ssl_certs() == False: - sys.stderr.write('failed. exiting ...\n') sys.exit(1) - print 'Luci server has been successfully initialized' + print 'The luci server has been successfully initialized' restart_message() - return - def password(argv): - pwd_str = None + passwd = None + + ret = exec_cmd('/sbin/service', [ 'service', 'luci', 'status' ]) + if ret[2] == 0: + err.write('You must stop the luci server before attempting to set the admin password.\n') + sys.exit(1) + if '--random' in argv: - print 'Setting the admin user\'s password to a random value.\n' + print 'Setting the admin user password to a random string...\n' + try: rand = open('/dev/urandom', 'r') - pwd_str = rand.read(16) + passwd = rand.read(16) rand.close() except Exception, e: - sys.stderr.write('Unable to read from /dev/urandom: %s\n' % str(e)) + err.write('Unable to read from /dev/urandom: %s\n' % str(e)) sys.exit(1) else: if not luci_initialized(): - sys.stderr.write('The Luci site has not been initialized.\n') - sys.stderr.write('To initialize it, execute:\n') - sys.stderr.write('\t%s init\n' % argv[0]) + err.write('The luci site has not been initialized.\n') + err.write('To initialize it, execute\n') + err.write('\t%s init\n' % argv[0]) sys.exit(1) - print 'Resetting the admin user\'s password\n' - pwd_str = read_passwd('Enter new password: ', 'Confirm password: ') + print 'Setting the admin user\'s password\n' + passwd = read_passwd('Enter new password: ', 'Confirm password: ') print '\nPlease wait...' - if not set_zope_passwd('admin', pwd_str): - print 'The admin password has been successfully reset.' + if not set_zope_passwd('admin', passwd): + print 'The admin password has been successfully set.' else: - sys.stderr.write('Unable to set the admin user\'s password.\n') sys.exit(1) restart_message() - return - -def backup_db(argv): +def backup(argv): # If the site hasn't been initialized, there's nothing to # save, and luci_backup() will fail if not luci_initialized(): - print 'The Luci site has not been initialized\n' - print 'Nothing to backup\n' + print 'The luci site has not been initialized\n' + print 'There is nothing to backup\n' sys.exit(0) - print 'Backing up the Luci server...' + ret = exec_cmd('/sbin/service', [ 'service', 'luci', 'status' ]) + if ret[2] == 0: + err.write('You must stop the luci server before backing up the luci database.\n') + sys.exit(1) + + print 'Backing up the luci server...' try: os.umask(077) @@ -1156,7 +1161,7 @@ doc = luci_backup(argv[2:]) restore_luci_db_fsattr() if doc == -1: - sys.stderr.write('The Luci backup failed. Exiting.\n') + err.write('The luci backup failed. Exiting.\n') sys.exit(1) try: @@ -1165,18 +1170,15 @@ # races. os.stat(LUCI_BACKUP_PATH) trynum = 1 - basename = '/luci_backup-' while True: - oldbackup = '%s%s%s.xml' % (LUCI_BACKUP_DIR, basename, str(trynum)) + oldbackup = '%s/luci-backup-%d.xml' % (LUCI_BACKUP_DIR, trynum) if not os.path.exists(oldbackup): try: os.rename(LUCI_BACKUP_PATH, oldbackup) - except Exception, e1: - sys.stderr.write('Unable to rename the existing backup file "%s" to "%s": %s\n' \ - % (LUCI_BACKUP_PATH, oldbackup, str(e1))) - sys.stderr.write('The Luci backup failed.\n') - sys.exit(1) + except Exception, e: + err.write('Unable to rename the existing backup file "%s" to "%s": %s\n' % (LUCI_BACKUP_PATH, oldbackup, str(e))) + err.write('The luci backup failed.\n') break trynum += 1 except OSError, e: @@ -1185,33 +1187,35 @@ try: f = file(LUCI_BACKUP_PATH, 'wb+') - except: - sys.stderr.write('Unable to open the file "%s" to write backup data.\n' - % LUCI_BACKUP_PATH) - sys.stderr.write('The Luci backup failed.\n') + except Exception, e: + err.write('Unable to open "%s" to write the backup: %s\n' \ + % (LUCI_BACKUP_PATH, str(e))) + err.write('The luci backup failed.\n') sys.exit(1) try: os.chmod(LUCI_BACKUP_PATH, 0600) except OSError, e: - sys.stderr.write('An error occurred while setting file permissions on backup file "%s": %s\n' \ - % (LUCI_BACKUP_PATH, str(e))) - sys.stderr.write('Please check that this file is not world-readable.\n') + err.write('An error occurred while setting file system permissions for "%s": %s\n' % (LUCI_BACKUP_PATH, str(e))) + err.write('Please ensure this file is not world-readable.\n') try: f.write(doc.toprettyxml()) f.close() except Exception, e: - sys.stderr.write('An error occurred while writing backup file "%s": %s\n' \ - % (LUCI_BACKUP_PATH, str(e))) - sys.stderr.write('Luci backup failed.\n') + err.write('The luci backup failed: %s\n' % str(e)) sys.exit(1) - print 'The luci backup procedure was successful.' - print 'Backup data is contained in the file "%s"' % LUCI_BACKUP_PATH + print 'The luci backup was successful.\n' + print 'The backup data is contained in the file "%s"\n' % LUCI_BACKUP_PATH + +def restore(argv): + ret = exec_cmd('/sbin/service', [ 'service', 'luci', 'status' ]) + if ret[2] == 0: + err.write('You must stop the luci server before restoring the luci database from backup.\n') + sys.exit(1) -def restore_db(argv): - print 'Restoring the Luci server...' + print 'Restoring the luci server...' try: os.umask(077) @@ -1220,11 +1224,11 @@ if luci_restore(argv[2:]): ret = False - sys.stderr.write('The Luci restore failed. Try reinstalling Luci, then restoring again.\n') + err.write('The luci restore failed. Try reinstalling luci, then restoring again.\n') else: set_default_passwd_reset_flag() ret = True - print 'Restore was successful.' + print 'The luci restore was successful.' restart_message() if restore_luci_db_fsattr(): @@ -1234,15 +1238,13 @@ def luci_help(argv): print 'Usage:' - print argv[0] + ' [init|backup|restore|password|help]' - print - print '\tinit: initialize Luci site' - print '\tpassword: reset admin password' - print '\t\t--random: reset admin password to random value (disable account)' - print '\tbackup: backup Luci site to a file' - print '\trestore: restore Luci site from backup' - print '\thelp: this help message' - print + print '%s [init|backup|restore|password|help]\n' % argv[0] + print '\tinit: initialize the luci server' + print '\tpassword: reset the admin password' + print '\t\t--random: set the admin password to a random value (disable account)' + print '\tbackup: backup the luci database to an XML file' + print '\trestore: restore luci database from a backup' + print '\thelp: display this help message\n' def test_luci_installation(): # perform basic checks @@ -1251,11 +1253,13 @@ # check if luci user and group are present on the system try: get_luci_uid_gid() - except: - sys.stderr.write('There is a problem with luci installation.\n') - sys.stderr.write('Mising luci\'s system account and group.\n') - sys.stderr.write('Recommended action: reinstall luci.\n\n') + except Exception, e: + err.write('There is a problem with your luci installation!\n') + err.write('The luci user\'s UID and GID could not be determined: %s\n' \ + % str(e)) + err.write('Reinstalling luci is recommended\n\n') sys.exit(3) + return True def main(argv): @@ -1263,27 +1267,20 @@ luci_help(argv) sys.exit(1) - # only root should run this - if os.getuid() != 0: - sys.stderr.write('Only "root" can run %s\n' % argv[0]) - sys.stderr.write('Try again with root privileges.\n') - sys.exit(2) - - # test if luci installation is OK test_luci_installation() if 'init' in argv: init(argv) elif 'backup' in argv: - backup_db(argv) + backup(argv) elif 'restore' in argv: - restore_db(argv) + restore(argv) elif 'password' in argv: password(argv) elif 'help' in argv: luci_help(argv) else: - sys.stderr.write('Unknown command\n\n') + err.write('Unknown command\n\n') luci_help(argv) sys.exit(1)