[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Cluster-devel] conga/luci/utils luci_admin



CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe 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 at 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)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]