From: rmccabe@sourceware.org <rmccabe@sourceware.org>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] conga/luci/utils luci_admin
Date: 26 Jun 2006 20:01:42 -0000 [thread overview]
Message-ID: <20060626200142.30244.qmail@sourceware.org> (raw)
CVSROOT: /cvs/cluster
Module name: conga
Changes by: rmccabe at sourceware.org 2006-06-26 20:01:40
Modified files:
luci/utils : luci_admin
Log message:
fix certificate backup and restore, and some other cleanups.
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/utils/luci_admin.diff?cvsroot=cluster&r1=1.18&r2=1.19
--- conga/luci/utils/luci_admin 2006/06/21 23:06:28 1.18
+++ conga/luci/utils/luci_admin 2006/06/26 20:01:40 1.19
@@ -19,16 +19,34 @@
LUCI_USER='luci'
LUCI_GROUP='luci'
-SSL_PRIVKEY_PATH='/var/lib/luci/var/certs/privkey.pem'
-SSL_PUBKEY_PATH='/var/lib/luci/var/certs/cacert.pem'
-SSL_KEYCONFIG_PATH='/var/lib/luci/var/certs/cacert.config'
LUCI_BACKUP_DIR='/var/lib/luci/var'
+LUCI_CERT_DIR='/var/lib/luci/var/certs/'
LUCI_BACKUP_PATH=LUCI_BACKUP_DIR + '/luci_backup.xml'
LUCI_DB_PATH='/var/lib/luci/var/Data.fs'
LUCI_TEMP='/var/lib/luci/var/temp/'
INITUSER_FILE_PATH = '/var/lib/luci/inituser'
+SSL_PRIVKEY_NAME = 'privkey.pem'
+SSL_PUBKEY_NAME = 'cacert.pem'
+SSL_HTTPS_PRIVKEY_NAME = 'https.key.pem'
+SSL_HTTPS_PUBKEY_NAME = 'https.pem'
+SSL_KEYCONFIG_NAME = 'cacert.config'
+
+SSL_PRIVKEY_PATH = LUCI_CERT_DIR + SSL_PRIVKEY_NAME
+SSL_PUBKEY_PATH = LUCI_CERT_DIR + SSL_HTTPS_PRIVKEY_NAME
+SSL_HTTPS_PRIVKEY_PATH = LUCI_CERT_DIR + SSL_HTTPS_PRIVKEY_NAME
+SSL_HTTPS_PUBKEY_PATH = LUCI_CERT_DIR + SSL_HTTPS_PUBKEY_NAME
+SSL_KEYCONFIG_PATH = LUCI_CERT_DIR + SSL_KEYCONFIG_NAME
+
+ssl_key_data = [
+ { 'id': SSL_PRIVKEY_PATH, 'name': SSL_PRIVKEY_NAME, 'type': 'private', 'mode': 0600 },
+ { 'id': SSL_HTTPS_PRIVKEY_PATH, 'name': SSL_HTTPS_PRIVKEY_NAME, 'type': 'private', 'mode': 0600 },
+ { 'id': SSL_PUBKEY_PATH, 'name': SSL_PUBKEY_NAME, 'type': 'public', 'mode': 0644 },
+ { 'id': SSL_HTTPS_PUBKEY_PATH, 'name': SSL_HTTPS_PUBKEY_NAME, 'type': 'public', 'mode': 0644 },
+ { 'id': SSL_KEYCONFIG_PATH, 'name': SSL_KEYCONFIG_NAME, 'type': 'config', 'mode': 0644 }
+]
+
null = file(os.devnull, 'rwb+', 0)
orig_stderr = sys.stderr
@@ -56,6 +74,60 @@
except:
return -1
+def luci_restore_certs(certList):
+ if not certList or len(certList) < 1:
+ sys.stderr.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('Your backup file contains no certificate data. Please check that your backup file is not corrupt.\n')
+ return -1
+ try:
+ luci = pwd.getpwnam(LUCI_USER)[2:4]
+ if not luci or len(luci) != 2:
+ raise
+ except:
+ sys.stderr.write('Cannot find the \"' + LUCI_USER + '\" user.\n')
+ return -1
+
+ for c in certList:
+ path = c.getAttribute('name')
+ if not path:
+ sys.stderr.write('Missing \"name\" field for certificate.\n')
+ return -1
+ path = LUCI_CERT_DIR + str(path)
+
+ mode = c.getAttribute('mode')
+ if not mode:
+ mode = 0600
+ else:
+ mode = int(mode, 8)
+
+ data = c.firstChild
+ if not data or not data.wholeText:
+ sys.stderr.write('\"' + path + '\" has no certificate data.')
+ return -1
+
+ # Because .prettyprint() was called to write the backup..
+ data = data.wholeText.strip()
+ if len(data) < 1:
+ sys.stderr.write('\"' + path + '\" has no certificate data.')
+ return -1
+ data = str(data)
+
+ try:
+ f = file(path, 'wb+')
+ except:
+ sys.stderr.write('Unable to create \" ' + path + '\" for writing.\n')
+ return -1
+
+ os.chmod(path, mode)
+ f.write(data + '\n')
+ os.chown(path, luci[0], luci[1])
+ f.close()
+ return None
+
def luci_restore(argv):
import ZODB
from ZODB.FileStorage import FileStorage
@@ -349,6 +421,16 @@
db.pack()
db.close()
fs.close()
+
+ certList = node.getElementsByTagName('certificateList')
+ if not certList or len(certList) < 1:
+ sys.stderr.write('No certificate data was found.\n')
+ return -1
+
+ if luci_restore_certs(certList):
+ sys.stderr.write('An error occurred while restoring certificate data.\n')
+ return -1
+
return 0
# This function's ability to work is dependent
@@ -539,69 +621,43 @@
doc.appendChild(luciData)
dataNode = dataToXML(doc, backup, 'backupData')
- try:
- certfile = file(SSL_PRIVKEY_PATH, 'rb')
- output = certfile.read()
-
- # should be at least some length greater than one
- # TODO: find out what the min length of a valid keyfile is.
- if len(output) < 1:
- raise
-
- certNode = doc.createElement('certificate')
- certNode.setAttribute('name', SSL_PRIVKEY_PATH)
- certNode.setAttribute('data', output)
- dataNode.appendChild(certNode.cloneNode(True))
- certfile.close()
- except False:
- sys.stderr.write('Unable to read ' + SSL_PRIVKEY_PATH + '\n')
- return None
-
- try:
- certfile = file(SSL_PUBKEY_PATH, 'rb')
- output = certfile.read()
+ certList = doc.createElement('certificateList')
+ for i in ssl_key_data:
+ try:
+ certfile = file(i['id'], 'rb')
+ output = certfile.read()
+ certfile.close()
- # should be at least some length greater than one
- # TODO: find out what the min length of a valid keyfile is.
- if len(output) < 1:
- raise
+ if len(output) < 1:
+ raise
+ except:
+ sys.stderr.write('Unable to read \"' + i['id'] + '\"\n')
+ # An error backing up anything other than the config
+ # is fatal.
+ if i['type'] != 'config':
+ return None
certNode = doc.createElement('certificate')
- certNode.setAttribute('name', SSL_PUBKEY_PATH)
- certNode.setAttribute('data', output)
- dataNode.appendChild(certNode.cloneNode(True))
- certfile.close()
- except:
- sys.stderr.write('Unable to read ' + SSL_PUBKEY_PATH + '\n')
- return None
-
- try:
- certfile = file(SSL_KEYCONFIG_PATH, 'rb')
- output = certfile.read()
-
- # should be at least some length greater than one
- # TODO: find out what the min length of a valid key conf is.
- if len(output) < 1:
- raise
-
- certNode = document.createElement('certificateConfig')
- certNode.setAttribute('name', SSL_KEYCONFIG_PATH)
- certNode.setAttribute('data', output)
- dataNode.appendChild(certNode.cloneNode(TRUE))
- certfile.close()
- except:
- sys.stderr.write('Unable to read ' + SSL_KEYCONFIG_PATH + '\n')
+ certNode.setAttribute('id', i['id'])
+ certNode.setAttribute('name', i['name'])
+ certNode.setAttribute('type', i['type'])
+ certNode.setAttribute('mode', str(oct(i['mode'])))
+ textNode = doc.createTextNode('\n' + output)
+ certNode.appendChild(textNode)
+ certList.appendChild(certNode)
+ dataNode.appendChild(certList.cloneNode(True))
luciData.appendChild(dataNode)
+
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, command + " can not be run"
-
+
(read, write) = os.pipe()
(read_err,write_err) = os.pipe()
-
+
childpid = os.fork()
if (not childpid):
# child
@@ -613,7 +669,7 @@
os.dup2(write, catchfd)
os.close(write)
os.close(read)
-
+
if isinstance(catcherrfd, tuple):
for fd in catcherrfd:
os.dup2(write_err, fd)
@@ -621,23 +677,23 @@
os.dup2(write_err, catcherrfd)
os.close(write_err)
os.close(read_err)
-
+
if closefd != -1:
os.close(closefd)
-
+
if stdin:
os.dup2(stdin, 0)
os.close(stdin)
-
+
if (searchPath):
os.execvp(command, argv)
else:
os.execv(command, argv)
# will never come here
-
+
os.close(write)
os.close(write_err)
-
+
rc = ""
rc_err = ""
in_list = [read, read_err]
@@ -654,21 +710,21 @@
if s == '':
in_list.remove(read_err)
rc_err = rc_err + s
-
+
os.close(read)
os.close(read_err)
-
+
status = -1
try:
(pid, status) = os.waitpid(childpid, 0)
except OSError, (errno, msg):
print __name__, "waitpid:", msg
-
+
if os.WIFEXITED(status):
status = os.WEXITSTATUS(status)
else:
status = -1
-
+
return (rc, rc_err, status)
@@ -688,31 +744,31 @@
command = '/usr/bin/openssl'
args = [command, 'genrsa', '-out', SSL_PRIVKEY_PATH, '2048']
_execWithCaptureErrorStatus(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 1095 -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', '1095', '-config', SSL_KEYCONFIG_PATH]
_execWithCaptureErrorStatus(command, args)
-
+
# /bin/chown -R zope:zope /var/lib/luci/var/certs/*
command = '/bin/chown'
args = [command, LUCI_USER + ':' + LUCI_GROUP, SSL_PRIVKEY_PATH, SSL_PUBKEY_PATH]
_execWithCaptureErrorStatus(command, args)
-
+
# /bin/chmod 644 /var/lib/luci/var/certs/*
command = '/bin/chmod'
args = [command, '644', SSL_PUBKEY_PATH]
o, e, s = _execWithCaptureErrorStatus(command, args)
if s != 0:
return False
-
+
# /bin/chmod 400 /var/lib/luci/var/certs/privkey.pem
command = '/bin/chmod'
args = [command, '600', SSL_PRIVKEY_PATH]
o, e, s = _execWithCaptureErrorStatus(command, args)
if s != 0:
return False
-
+
return True
@@ -734,7 +790,7 @@
print 'Restart the Luci server for changes to take effect'
print 'eg. service luci restart'
print
- return
+ return
@@ -753,14 +809,14 @@
if generate_ssl_certs() == False:
print 'failed. exiting ...'
sys.exit(1)
-
+
print
print 'Creating \'admin\' user'
save_password('admin', generate_password())
print 'Luci server has been successfully initialized'
-
+
restart_message()
-
+
return
@@ -771,14 +827,14 @@
print argv[0] + ' init'
sys.exit(1)
pass
-
+
print 'Reseting admin password'
print
save_password('admin', generate_password())
print 'admin password has been successfully reset'
-
+
restart_message()
-
+
return
@@ -788,18 +844,25 @@
print 'To initialize it, execute'
print argv[0] + ' init'
sys.exit(1)
-
+
print 'Backing up the Luci server...'
try: os.umask(077)
except: pass
doc = luci_backup(argv[2:])
- if not doc:
- sys.stderr.write('The Luci backup failed.\n')
- sys.exit(1)
try:
+ luci = pwd.getpwnam(LUCI_USER)[2:4]
+ os.chown(LUCI_DB_PATH, luci[0], luci[1])
+ os.chmod(LUCI_DB_PATH, 0600)
+ except:
+ sys.stderr.write('Unable to change ownership of the Luci database back to user \"' + LUCI_USER + '\"\n')
+
+ try:
+ # The LUCI_BACKUP_DIR must not be world-writable
+ # as the code below is obviously not safe against
+ # races.
stat = os.stat(LUCI_BACKUP_PATH)
trynum = 1
basename = '/luci_backup-'
@@ -816,46 +879,41 @@
except OSError, e:
#if e[0] == 2:
pass
-
- try:
- f = file(LUCI_BACKUP_PATH, 'w')
- except:
- sys.stderr.write('Unable to open \"' + LUCI_BACKUP_PATH + '\" to write backup.\n')
- return -1
-
- f.write(doc.toprettyxml())
- f.flush()
- f.close()
-
- print 'Backup was successful. The backup file is',LUCI_BACKUP_PATH
try:
- luci = pwd.getpwnam(LUCI_USER)[2:4]
- os.chown(LUCI_DB_PATH, luci[0], luci[1])
- os.chmod(LUCI_DB_PATH, 0600)
+ f = file(LUCI_BACKUP_PATH, 'wb+')
except:
- sys.stderr.write('Unable to change ownership of the Luci database back to user \"' + LUCI_USER + '\"\n')
+ sys.stderr.write('Unable to open \"' + LUCI_BACKUP_PATH + '\" to write backup.\n')
+ return -1
try:
os.chmod(LUCI_BACKUP_PATH, 0600)
except OSError, e:
print "An error occurred while making",LUCI_BACKUP_PATH,"read-only:",e
print "Please check that this file is not world-readable."
+ if not doc:
+ sys.stderr.write('The Luci backup failed.\n')
+ sys.exit(1)
+ f.write(doc.toprettyxml())
+ f.flush()
+ f.close()
def restore(argv):
print 'Restoring the Luci server...'
-
+
+ try: os.umask(077)
+ except: pass
+
# for reasons that make no sense, zope/plone will fall
# on its face if www/ok.gif and images/version.gif don't
# exist and have@least something in them.
try:
os.makedirs(LUCI_TEMP + 'www')
os.makedirs(LUCI_TEMP + 'images')
- except:pass
+ except: pass
try:
- os.chdir(LUCI_TEMP)
f = file(LUCI_TEMP + 'www/ok.gif', 'w')
f.write('luci\n')
f.close()
@@ -864,12 +922,18 @@
f.write('luci\n')
f.close()
except:
- os.unlink(LUCI_TEMP + 'www/ok.gif')
- os.unlink(LUCI_TEMP + 'images/version.gif')
- os.removedirs(LUCI_TEMP)
+ try:
+ os.unlink(LUCI_TEMP + 'www/ok.gif')
+ os.unlink(LUCI_TEMP + 'images/version.gif')
+ os.rmdir(LUCI_TEMP + 'www')
+ os.rmdir(LUCI_TEMP + 'images')
+ os.rmdir(LUCI_TEMP)
+ except: pass
print 'Unable to initialize restore.'
sys.exit(1)
+ os.chdir(LUCI_TEMP)
+
ret = True
if luci_restore(argv[2:]):
print 'The Luci restore failed. Try reinstalling Luci, then restoring again.'
@@ -878,6 +942,15 @@
print 'Restore was successful.'
restart_message()
+ os.chdir(LUCI_BACKUP_DIR)
+ try:
+ os.unlink(LUCI_TEMP + 'www/ok.gif')
+ os.unlink(LUCI_TEMP + 'images/version.gif')
+ os.rmdir(LUCI_TEMP + 'www')
+ os.rmdir(LUCI_TEMP + 'images')
+ os.rmdir(LUCI_TEMP)
+ except: pass
+
try:
luci = pwd.getpwnam(LUCI_USER)[2:4]
os.chown(LUCI_DB_PATH, luci[0], luci[1])
@@ -885,12 +958,6 @@
except:
sys.stderr.write('Unable to change ownership of the Luci database back to user \"' + LUCI_USER + '\"\n')
- try:
- os.unlink(LUCI_TEMP + 'www/ok.gif')
- os.unlink(LUCI_TEMP + 'images/version.gif')
- os.removedirs(LUCI_TEMP)
- except: pass
-
return ret
@@ -904,7 +971,7 @@
print '\tpassword: reset admin password'
print '\thelp: this help message'
print
-
+
def main(argv):
@@ -912,16 +979,16 @@
luci_help(argv)
sys.exit(1)
pass
-
-
+
+
# only root can modify Luci server
if os.getuid() != 0:
print 'Only root can modify Luci server.'
print 'Try again with root privileges.'
sys.exit(2)
pass
-
-
+
+
if 'init' in argv:
init(argv)
elif 'backup' in argv:
@@ -938,7 +1005,7 @@
luci_help(argv)
sys.exit(1)
-
+
# If called from the command line
if __name__ == '__main__':
main(sys.argv)
next reply other threads:[~2006-06-26 20:01 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-06-26 20:01 rmccabe [this message]
-- strict thread matches above, loose matches on Subject: below --
2011-03-25 20:14 [Cluster-devel] conga/luci/utils luci_admin rmccabe
2007-09-19 5:17 rmccabe
2007-08-10 18:36 rmccabe
2007-08-10 18:33 rmccabe
2007-08-10 18:32 rmccabe
2007-08-07 20:22 rmccabe
2006-10-13 6:56 kupcevic
2006-08-18 18:03 rmccabe
2006-08-04 19:19 rmccabe
2006-08-04 18:37 rmccabe
2006-08-03 22:58 kupcevic
2006-08-03 21:19 rmccabe
2006-08-03 21:11 rmccabe
2006-08-03 16:32 rmccabe
2006-08-03 15:55 rmccabe
2006-08-03 12:26 rmccabe
2006-08-03 3:58 rmccabe
2006-08-03 3:30 rmccabe
2006-08-02 23:29 rmccabe
2006-08-02 20:52 rmccabe
2006-08-02 20:45 rmccabe
2006-07-26 1:17 rmccabe
2006-07-25 22:36 rmccabe
2006-07-11 18:46 rmccabe
2006-07-11 14:51 rmccabe
2006-06-29 18:04 rmccabe
2006-06-29 17:51 rmccabe
2006-06-27 19:50 rmccabe
2006-06-27 19:40 rmccabe
2006-06-27 18:19 rmccabe
2006-06-26 22:30 rmccabe
2006-06-21 23:06 rmccabe
2006-06-21 17:41 rmccabe
2006-06-21 17:06 rmccabe
2006-06-18 15:02 rmccabe
2006-06-18 12:50 rmccabe
2006-06-18 3:26 rmccabe
2006-06-16 23:19 rmccabe
2006-06-16 19:35 rmccabe
2006-06-16 18:17 rmccabe
2006-06-16 17:44 rmccabe
2006-06-16 5:35 rmccabe
2006-06-13 18:42 rmccabe
2006-06-13 17:36 rmccabe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060626200142.30244.qmail@sourceware.org \
--to=rmccabe@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).