[Cluster-devel] conga ./conga.spec.in.in luci/Makefile luci/si ...

kupcevic at sourceware.org kupcevic at sourceware.org
Fri Dec 8 18:27:36 UTC 2006


CVSROOT:	/cvs/cluster
Module name:	conga
Branch: 	RHEL5
Changes by:	kupcevic at sourceware.org	2006-12-08 18:27:32

Modified files:
	.              : conga.spec.in.in 
	luci           : Makefile 
	luci/site      : Makefile 
	luci/site/luci/Extensions: HelperFunctions.py StorageReport.py 
	                           ricci_communicator.py 
	                           storage_adapters.py 
	luci/storage   : form-macros 
	ricci/ricci    : SSLInstance.cpp 
Added files:
	luci/conga_ssl : Makefile SSLClient.cpp SSLClient.h 
	                 conga_ssl_lib.cpp setup.py 
	luci/site/luci/Extensions: conga_ssl.py 

Log message:
	Improved bz201394: luci doesn't verify ricci's SSL cert against trusted list (part 1 - backend)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/conga.spec.in.in.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.45.2.8&r2=1.45.2.9
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/Makefile.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.20.2.1&r2=1.20.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/conga_ssl/Makefile.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=NONE&r2=1.1.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/conga_ssl/SSLClient.cpp.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=NONE&r2=1.1.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/conga_ssl/SSLClient.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=NONE&r2=1.1.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/conga_ssl/conga_ssl_lib.cpp.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=NONE&r2=1.1.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/conga_ssl/setup.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=NONE&r2=1.1.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/Makefile.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.11&r2=1.11.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_ssl.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=NONE&r2=1.1.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/HelperFunctions.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4.2.1&r2=1.4.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/StorageReport.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.20.2.1&r2=1.20.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ricci_communicator.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.9.2.6&r2=1.9.2.7
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/storage_adapters.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.7.2.1&r2=1.7.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/form-macros.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.17.2.3&r2=1.17.2.4
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/SSLInstance.cpp.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5.2.1&r2=1.5.2.2

--- conga/conga.spec.in.in	2006/11/29 22:33:50	1.45.2.8
+++ conga/conga.spec.in.in	2006/12/08 18:27:31	1.45.2.9
@@ -126,10 +126,11 @@
 				%{_sbindir}/luci_admin
 				%{_docdir}/luci-%{version}/
 %defattr(-,luci,luci)
+				%{_localstatedir}/lib/luci
+				%{_libdir}/luci/ssl
 %if "%{include_zope_and_plone}" == "yes"
-				%{_libdir}/luci/
+				%{_libdir}/luci/zope
 %endif
-				%{_localstatedir}/lib/luci
 
 %pre -n luci
 if ! /bin/grep luci\:x /etc/group 2>&1 >/dev/null; then
@@ -283,14 +284,14 @@
 
 %changelog
 
-* day month date 2006 Stanko Kupcevic <kupcevic at redhat.com> 0.8-26
+* Fri Dec 08 2006 Stanko Kupcevic <kupcevic at redhat.com> 0.8-26
 
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 XXXXXXXXXXXXXXXXXXX UPDATE NOT RELEASED YET XXXXXXXXXXXXXXXXXXX
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
 - luci storage: fix bytes->TB conversion
-
+- Improved bz201394: luci doesn't verify ricci's SSL cert against trusted list (part 1 - backend)
 
 
 * Thu Nov 16 2006 Stanko Kupcevic <kupcevic at redhat.com> 0.8-25
--- conga/luci/Makefile	2006/11/16 19:34:52	1.20.2.1
+++ conga/luci/Makefile	2006/12/08 18:27:32	1.20.2.2
@@ -18,6 +18,7 @@
 
 luci:
 	make -C site
+	make -C conga_ssl
 	make -C utils
 	make -C init.d
 	make -C sysconfig
@@ -46,6 +47,7 @@
 
 	install -d -m 700 ${DESTDIR}/var/lib/luci
 	make -C site install
+	make -C conga_ssl install
 	make -C utils install
 	make -C init.d install
 	make -C sysconfig install
/cvs/cluster/conga/luci/conga_ssl/Makefile,v  -->  standard output
revision 1.1.2.1
--- conga/luci/conga_ssl/Makefile
+++ -	2006-12-08 18:27:33.432667000 +0000
@@ -0,0 +1,21 @@
+
+include ../../make/version.in
+include ../make/defines.mk
+
+
+.PHONY: build
+
+build:
+	python setup.py build
+
+clean:
+	rm -rf build
+	rm -rf ricci
+
+install:
+	install -d ${libdir}/luci
+	install -d ${libdir}/luci/ssl
+	install -m 644 build/lib*/conga_ssl_lib.so ${libdir}/luci/ssl
+
+rebuild: clean build
+
/cvs/cluster/conga/luci/conga_ssl/SSLClient.cpp,v  -->  standard output
revision 1.1.2.1
--- conga/luci/conga_ssl/SSLClient.cpp
+++ -	2006-12-08 18:27:33.797469000 +0000
@@ -0,0 +1,552 @@
+/*
+  Copyright Red Hat, Inc. 2005
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+/*
+ * Author: Stanko Kupcevic <kupcevic at redhat.com>
+ */
+
+
+#include "SSLClient.h"
+#include "Mutex.h"
+#include "Time.h"
+#include "Random.h"
+#include "utils.h"
+#include "File.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <list>
+#include <set>
+
+
+
+#include <openssl/err.h>
+
+
+
+using namespace std;
+
+
+
+static Mutex global_lock;
+static bool ssl_inited = false;
+static SSL_CTX* ctx = 0;
+static vector<counting_auto_ptr<Mutex> > ssl_locks;
+
+class file_cert
+{
+public:
+  file_cert(const String& file, const String& cert) :
+    file(file),
+    cert(cert) {}
+  
+  String file;
+  String cert;
+};
+static list<file_cert> trusted_certs;
+
+
+
+static int 
+verify_cert_callback(int preverify_ok, X509_STORE_CTX *ctx)
+{
+  return 1;
+}
+static void 
+load_peer_certs()
+{
+  MutexLocker l(global_lock);
+  
+  // load trusted CAs
+  if (!SSL_CTX_load_verify_locations(ctx, 
+				     _trust_CAs, 
+				     NULL))
+    cout << "failed to load trusted CAs" << endl;
+  
+  STACK_OF(X509_NAME) *cert_names = 
+    SSL_load_client_CA_file(_trust_CAs);
+  if (cert_names)
+    SSL_CTX_set_client_CA_list(ctx, cert_names);
+  else
+    cout << "failed to load trusted CAs" << endl;
+  
+  // load saved certs
+  
+  set<String> files;
+  String dir_path(_certs_store_dir);
+  DIR* d = opendir(dir_path.c_str());
+  if (d == NULL)
+    throw String("unable to open directory ") + dir_path;
+  try {
+    while (true) {
+      struct dirent* ent = readdir(d);
+      if (ent == NULL) {
+	closedir(d);
+	break;
+      }
+      String kid_path = ent->d_name;
+      if (kid_path == "." || kid_path == "..")
+	continue;
+      kid_path = dir_path + "/" + kid_path;
+      struct stat st;
+      if (stat(kid_path.c_str(), &st))
+	continue;
+      if (S_ISREG(st.st_mode))
+	files.insert(kid_path);
+    }
+  } catch ( ... ) {
+    closedir(d);
+    throw;
+  }
+  
+  trusted_certs.clear();
+  
+  for (set<String>::const_iterator iter = files.begin();
+       iter != files.end();
+       iter++) {
+    try {
+      String cert(File::open(*iter).read());
+      if (cert.size() && cert.size() < 10 * 1024)
+	trusted_certs.push_back(file_cert(*iter, cert));
+    } catch ( ... ) {}
+  }
+}
+static void 
+ssl_mutex_callback(int mode, 
+		   int n, 
+		   const char *file, 
+		   int line)
+{
+  if (mode & CRYPTO_LOCK)
+    ssl_locks[n]->lock();
+  else
+    ssl_locks[n]->unlock();
+}
+static pthread_t
+ssl_id_callback(void)
+{
+  return pthread_self();
+}
+
+
+
+
+// ##### class SSLClient #####
+
+
+SSLClient::SSLClient(ClientSocket sock) :
+  _sock(sock), 
+  _connected(false)
+{
+  {
+    MutexLocker l(global_lock);
+    if (!ssl_inited) {
+      // init library
+      
+      SSL_library_init();
+      // TODO: random number generator,
+      // not on systems with /dev/urandom (eg. Linux)
+      
+      // thread support
+      ssl_locks.clear();
+      for (int i=0; i<CRYPTO_num_locks()+1; i++)
+	ssl_locks.push_back(counting_auto_ptr<Mutex>(new Mutex()));
+      CRYPTO_set_locking_callback(ssl_mutex_callback);
+      CRYPTO_set_id_callback(ssl_id_callback);
+      
+      // create context
+      if (!ctx)
+	ctx = SSL_CTX_new(SSLv23_client_method());
+      if (!ctx)
+	throw String("SSL context creation failed");
+      // set verify_callback() function
+      SSL_CTX_set_verify(ctx, 
+			 SSL_VERIFY_PEER, 
+			 verify_cert_callback);
+      // set mode
+      SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
+      SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+      
+      // load key
+      if (!SSL_CTX_use_PrivateKey_file(ctx, 
+				       _privkey, 
+				       SSL_FILETYPE_PEM))
+	throw String("error importing cert key file");
+      // load cert
+      if (!SSL_CTX_use_certificate_file(ctx, 
+					_pubkey, 
+					SSL_FILETYPE_PEM))
+	throw String("error importing cert file");
+      // load peers' certs
+      load_peer_certs();
+      
+      ssl_inited = true;
+    }
+    
+    // create SSL object, giving it context
+    _ssl = SSL_new(ctx);
+    if (!_ssl)
+      throw String("creation of ssl object failed");
+  }
+  
+  // make socket non-blocking
+  try {
+    _sock.nonblocking(true);
+  } catch ( ... ) {
+    SSL_free(_ssl);
+    throw;
+  }
+  
+  // assign fd to _ssl
+  if (!SSL_set_fd(_ssl, _sock.get_sock())) {
+    SSL_free(_ssl);
+    throw String("fd assignment to ssl_obj failed");
+  }
+}
+
+SSLClient::~SSLClient()
+{
+  SSL_shutdown(_ssl);
+  SSL_free(_ssl);
+}
+
+
+bool 
+SSLClient::connect(unsigned int timeout)
+{
+  if (_connected)
+    return _connected;
+  
+  unsigned int beg = time_mil();
+  while (time_mil() < beg + timeout) {
+    int ret = SSL_connect(_ssl);
+    if (ret == 1) {
+      _connected = true;
+      break;
+    } else {
+      bool want_read, want_write;
+      check_error(ret, want_read, want_write);
+      socket().ready(want_read, want_write, 250);
+    }
+  }
+  
+  return _connected;
+}
+
+String 
+SSLClient::send(const String& msg,
+		unsigned int timeout)
+{
+  if (!_connected)
+    throw String("cannot send, yet: SSL connection not connected");
+  
+  if (msg.empty())
+    return msg;
+  
+  unsigned int beg = time_mil();
+  while (time_mil() < beg + timeout) {
+    int ret = SSL_write(_ssl, msg.c_str(), msg.size());
+    if (ret > 0) {
+      return msg.substr(ret);
+    } else {
+      bool want_read, want_write;
+      check_error(ret, want_read, want_write);
+      socket().ready(want_read, want_write, 250);
+    }
+  }
+  
+  return msg;
+}
+
+String 
+SSLClient::recv(unsigned int timeout)
+{
+  if (!_connected)
+    throw String("cannot receive, yet: SSL connection not connected");
+  
+  char buff[1024];
+  
+  unsigned int beg = time_mil();
+  while (time_mil() < beg + timeout) {
+    int ret = SSL_read(_ssl, buff, sizeof(buff));
+    if (ret > 0) {
+      String data(buff, ret);
+      shred(buff, sizeof(buff));
+      return data;
+    } else {
+      bool want_read, want_write;
+      check_error(ret, want_read, want_write);
+      socket().ready(want_read, want_write, 250);
+    }
+  }
+  
+  return "";
+}
+
+bool 
+SSLClient::peer_has_cert()
+{
+  if (!_connected)
+    throw String("cannot determine if peer has certificate: SSL connection not connected");
+  
+  if (_cert_pem.size())
+    return true;
+  
+  X509* cert = SSL_get_peer_certificate(_ssl);
+  if (!cert) 
+    return false;
+  
+  // load cert into _cert_pem
+  FILE* f = NULL;
+  try {
+    if (!(f = tmpfile()))
+      throw String("unable to open temp file");
+    if (!PEM_write_X509(f, cert))
+      throw String("unable to write cert to tmp file");
+    X509_free(cert); cert = NULL;
+    
+    // read cert
+    rewind(f);
+    while (true) {
+      char buff[1024];
+      size_t i = fread(buff, sizeof(char), sizeof(buff), f);
+      _cert_pem.append(buff, i);
+      if (i == 0) {
+	if (feof(f))
+	  break;
+	else
+	  throw String("error while reading certificate from temp file");
+      }
+    }
+    fclose(f); f = NULL;
+  } catch ( ... ) {  
+    if (cert)
+      X509_free(cert);
+    if (f)
+      fclose(f);
+    _cert_pem.clear();
+    throw;
+  }
+  
+  return true;
+}
+
+String 
+SSLClient::peer_cert_fingerprint(String& digest)
+{
+  if (!peer_has_cert())
+    throw String("peer did not present cert");
+  
+  String f_name("/tmp/luci_tmp_XXXXXX");
+  int fd = -1;
+  char* buff = new char[f_name.size() + 1];
+  try {
+    // pick a filename
+    strcpy(buff, f_name.c_str());
+    if ((fd = mkstemp(buff)) == -1)
+      throw String("unable to generate random file");
+    f_name = buff;
+    delete[] buff; buff = 0;
+    while (close(fd) && errno == EINTR) ; fd = -1;
+    
+    File f = File::open(f_name, true);
+    f.replace(_cert_pem);
+    
+    String out, err;
+    int status;
+    vector<String> args;
+    args.push_back("x509");
+    args.push_back("-sha1");
+    args.push_back("-in");
+    args.push_back(f_name);
+    args.push_back("-noout");
+    args.push_back("-fingerprint");
+    if (utils::execute("/usr/bin/openssl", 
+		       args,
+		       out,
+		       err,
+		       status,
+		       false))
+      throw command_not_found_error_msg("/usr/bin/openssl");
+    if (status)
+      throw String("openssl command failed");
+    unlink(f_name.c_str());
+    
+    vector<String> words(utils::split(utils::strip(out)));
+    if (words.size() != 2)
+      throw String("error parsing fingerprint");
+    
+    String finger(words[1]);
+    String::size_type idx = finger.find('=');
+    if (idx == finger.npos ||
+	idx+1 == finger.size())
+      throw String("error parsing fingerprint");
+    
+    digest = words[0];
+    return finger.substr(idx+1);
+  } catch ( ... ) {
+    delete[] buff;
+    if (fd != -1)
+      while (close(fd) && errno == EINTR)
+	;
+    unlink(f_name.c_str());
+    throw;
+  }
+}
+
+bool 
+SSLClient::peer_cert_trusted()
+{
+  // signed by trusted CAs?
+  X509* cert = SSL_get_peer_certificate(_ssl);
+  if (!cert) 
+    return false;
+  X509_free(cert);
+  if (SSL_get_verify_result(_ssl) == X509_V_OK)
+    return true;
+  
+  // cert present among saved certs?
+  peer_has_cert();  // make sure cert is saved in _cert_pem
+  MutexLocker l(global_lock);
+  for (list<file_cert>::const_iterator iter = trusted_certs.begin();
+       iter != trusted_certs.end();
+       iter++)
+    if (iter->cert == _cert_pem)
+      return true;
+  return false;
+}
+
+bool 
+SSLClient::trust_peer_cert()
+{
+  MutexLocker l(global_lock);
+  
+  if (peer_cert_trusted())
+    return true;
+  
+  if (!peer_has_cert())
+    throw String("peer did not present cert");
+  
+  String f_name(_certs_store_dir);
+  f_name += "/peer_cert_XXXXXX";
+  int fd = -1;
+  char* buff = new char[f_name.size() + 1];
+  try {
+    // pick a filename
+    strcpy(buff, f_name.c_str());
+    if ((fd = mkstemp(buff)) == -1)
+      throw String("unable to generate random file");
+    f_name = buff;
+    delete[] buff; buff = 0;
+    
+    String data(_cert_pem);
+    while (data.size()) {
+      ssize_t i = write(fd, data.c_str(), data.size());
+      if (i == -1) {
+	if (errno != EINTR)
+	  throw String("error writing certificate");
+      } else
+	data = data.substr(i);
+    }
+    while (close(fd) && errno == EINTR)
+      ;
+  } catch ( ... ) {
+    delete[] buff;
+    if (fd != -1)
+      while (close(fd) && errno == EINTR)
+	;
+    unlink(f_name.c_str());
+    return false;
+  }
+  
+  load_peer_certs();
+  
+  return true;
+}
+
+bool 
+SSLClient::untrust_peer_cert()
+{
+  MutexLocker l(global_lock);
+  
+  if (!peer_has_cert())
+    throw String("peer did not present cert");
+  
+  for (list<file_cert>::const_iterator iter = trusted_certs.begin();
+       iter != trusted_certs.end();
+       iter++)
+    if (iter->cert == _cert_pem)
+      unlink(iter->file.c_str());
+  
+  load_peer_certs();
+  return true;
+}
+
+ClientSocket&
+SSLClient::socket()
+{
+  return _sock;
+}
+
+void
+SSLClient::check_error(int value, bool& want_read, bool& want_write)
+{
+  want_read = want_write = false;
+  
+  String e;
+  switch (SSL_get_error(_ssl, value)) {
+  case SSL_ERROR_NONE:
+    e = "SSL_ERROR_NONE";
+    break;
+  case SSL_ERROR_ZERO_RETURN:
+    e = "SSL_ERROR_ZERO_RETURN";
+    break;
+  case SSL_ERROR_WANT_READ:
+    want_read = true;
+    return;
+  case SSL_ERROR_WANT_WRITE:
+    want_write = true;
+    return;
+  case SSL_ERROR_WANT_CONNECT:
+    e = "SSL_ERROR_WANT_CONNECT";
+    break;
+  case SSL_ERROR_WANT_ACCEPT:
+    e = "SSL_ERROR_WANT_ACCEPT";
+    break;
+  case SSL_ERROR_WANT_X509_LOOKUP:
+    e = "SSL_ERROR_WANT_X509_LOOKUP";
+    break;
+  case SSL_ERROR_SYSCALL:
+    e = "SSL_ERROR_SYSCALL";
+    break;
+  case SSL_ERROR_SSL:
+    e = "SSL_ERROR_SSL";
+    break;
+  }
+  
+  //FILE* f = fopen("/tmp/ssl_error_que", "a");
+  //ERR_print_errors_fp(f);
+  //fclose(f);
+  
+  throw String("SSL error: ") + e;
+}
/cvs/cluster/conga/luci/conga_ssl/SSLClient.h,v  -->  standard output
revision 1.1.2.1
--- conga/luci/conga_ssl/SSLClient.h
+++ -	2006-12-08 18:27:34.372060000 +0000
@@ -0,0 +1,80 @@
+/*
+  Copyright Red Hat, Inc. 2005
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+/*
+ * Author: Stanko Kupcevic <kupcevic at redhat.com>
+ */
+
+
+#ifndef SSLClient_h
+#define SSLClient_h
+
+#include "Socket.h"
+
+#include "String.h"
+#include <openssl/ssl.h>
+
+
+#define _privkey          "/var/lib/luci/var/certs/privkey.pem"
+#define _pubkey           "/var/lib/luci/var/certs/cacert.pem"
+#define _trust_CAs        "/var/lib/luci/var/certs/trust_CAs"
+#define _certs_store_dir  "/var/lib/luci/var/certs/peers"
+
+
+// NOT THREAD SAFE
+
+
+class SSLClient
+{
+ public:
+  SSLClient(ClientSocket sock);
+  virtual ~SSLClient();
+  
+  bool connect(unsigned int timeout);
+  
+  String send(const String& msg, unsigned int timeout);
+  String recv(unsigned int timeout);
+  
+  
+  bool peer_has_cert();
+  bool peer_cert_trusted();  // return true if peer's cert is trusted (either thru CA chain, or saved in cert_store)
+  
+  String peer_cert_fingerprint(String& digest);
+  
+  bool trust_peer_cert();
+  bool untrust_peer_cert();  // remove peer's cert from cert_store
+  
+  ClientSocket& socket();
+  
+ private:
+  SSLClient(const SSLClient&);
+  SSLClient operator=(const SSLClient&);
+  
+  ClientSocket _sock;
+  SSL*         _ssl;
+  String  _cert_pem;
+  
+  bool _connected;
+  
+  void check_error(int value, bool& want_read, bool& want_write);
+  
+  
+};  // class SSLClient
+
+
+#endif  // SSLClient_h
/cvs/cluster/conga/luci/conga_ssl/conga_ssl_lib.cpp,v  -->  standard output
revision 1.1.2.1
--- conga/luci/conga_ssl/conga_ssl_lib.cpp
+++ -	2006-12-08 18:27:34.717960000 +0000
@@ -0,0 +1,374 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+/*
+ * Author: Stanko Kupcevic <kupcevic at redhat.com>
+ */
+
+
+#include <Python.h>
+
+#include <Socket.h>
+#include <String.h>
+#include <Time.h>
+#include <XML.h>
+#include <utils.h>
+
+#include "SSLClient.h"
+
+#include <map>
+
+using namespace std;
+
+
+class PythonThreadsAllower
+{
+public:
+  PythonThreadsAllower()
+  { _save = PyEval_SaveThread(); }
+  
+  ~PythonThreadsAllower()
+  { PyEval_RestoreThread(_save); }
+  
+private:
+  PyThreadState *_save;
+};
+
+
+
+static Mutex mutex;
+static map<int, counting_auto_ptr<SSLClient> > ssls;
+
+
+
+static PyObject *
+conga_ssl_lib_connect(PyObject *self, PyObject *args);
+static PyObject *
+conga_ssl_lib_disconnect(PyObject *self, PyObject *args);
+
+static PyObject *
+conga_ssl_lib_send(PyObject *self, PyObject *args);
+static PyObject *
+conga_ssl_lib_recv(PyObject *self, PyObject *args);
+
+static PyObject *
+conga_ssl_lib_trust(PyObject *self, PyObject *args);
+static PyObject *
+conga_ssl_lib_trusted(PyObject *self, PyObject *args);
+static PyObject *
+conga_ssl_lib_untrust(PyObject *self, PyObject *args);
+
+static PyObject *
+conga_ssl_lib_peer_fingerprint(PyObject *self, PyObject *args);
+
+
+
+static PyMethodDef SSLMethods[] = {
+  {"connect", conga_ssl_lib_connect, METH_VARARGS,
+   "doc"},
+  {"disconnect", conga_ssl_lib_disconnect, METH_VARARGS,
+   "doc"},
+  {"send", conga_ssl_lib_send, METH_VARARGS,
+   "doc"},
+  {"recv", conga_ssl_lib_recv, METH_VARARGS,
+   "doc"},
+  {"trust", conga_ssl_lib_trust, METH_VARARGS,
+   "doc"},
+  {"trusted", conga_ssl_lib_trusted, METH_VARARGS,
+   "doc"},
+  {"untrust", conga_ssl_lib_untrust, METH_VARARGS,
+   "doc"},
+  {"peer_fingerprint", conga_ssl_lib_peer_fingerprint, METH_VARARGS,
+   "doc"},
+  {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+
+
+PyMODINIT_FUNC
+initconga_ssl_lib(void)
+{
+  (void) Py_InitModule("conga_ssl_lib", SSLMethods);
+}
+
+
+
+PyObject *
+conga_ssl_lib_connect(PyObject *self, PyObject *args)
+{
+  const char* hostname;
+  int port;
+  int timeout;
+  if (!PyArg_ParseTuple(args, 
+			"sii", 
+			&hostname,
+			&port,
+			&timeout))
+    return NULL;
+  if (port < 1 || port > 65535) {
+    PyErr_SetString(PyExc_ValueError, "invalid port number");
+    return NULL;
+  }
+  if (timeout < 0) {
+    PyErr_SetString(PyExc_ValueError, "negative timeout");
+    return NULL;
+  }
+  
+  try {
+    counting_auto_ptr<SSLClient> ss;
+    {
+      PythonThreadsAllower all;
+      ClientSocket sock(hostname, port);
+      ss = counting_auto_ptr<SSLClient>(new SSLClient(sock));
+      ss->connect(timeout * 1000);
+    }
+    int id = (int) ss->socket().get_sock();
+    ssls[id] = ss;
+    return Py_BuildValue("i", id);
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
+
+PyObject *
+conga_ssl_lib_disconnect(PyObject *self, PyObject *args)
+{
+  int id;
+  if (!PyArg_ParseTuple(args, "i", &id))
+    return NULL;
+  
+  try {
+    map<int, counting_auto_ptr<SSLClient> >::iterator iter = 
+      ssls.find(id);
+    if (iter != ssls.end())
+      ssls.erase(iter);
+    Py_INCREF(Py_None);
+    return Py_None;
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
+
+PyObject *
+conga_ssl_lib_send(PyObject *self, PyObject *args)
+{
+  int id;
+  const char* msg;
+  int timeout;
+  if (!PyArg_ParseTuple(args, "isi", &id, &msg, &timeout))
+    return NULL;
+  if (timeout < 0) {
+    PyErr_SetString(PyExc_ValueError, "negative timeout");
+    return NULL;
+  }
+  
+  try {
+    map<int, counting_auto_ptr<SSLClient> >::const_iterator iter = 
+      ssls.find(id);
+    if (iter == ssls.end())
+      throw String("SSL connection closed");
+    
+    {
+      PythonThreadsAllower all;
+      int beg = int(time_sec());
+      String out(msg);
+      while (true) {
+	if (int(time_sec()) > beg + timeout)
+	  throw String("timeout");
+	else
+	  if ((out = iter->second->send(out, 400)).empty())
+	    break;
+      }
+    }
+    
+    Py_INCREF(Py_None);
+    return Py_None;
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
+
+PyObject *
+conga_ssl_lib_recv(PyObject *self, PyObject *args)
+{
+  int id, timeout;
+  if (!PyArg_ParseTuple(args, "ii", &id, &timeout))
+    return NULL;
+  if (timeout < 0) {
+    PyErr_SetString(PyExc_ValueError, "negative timeout");
+    return NULL;
+  }
+  
+  try {
+    map<int, counting_auto_ptr<SSLClient> >::const_iterator iter = 
+      ssls.find(id);
+    if (iter == ssls.end())
+      throw String("SSL connection closed");
+    
+    String resp;
+    {
+      PythonThreadsAllower all;
+      int beg = int(time_sec());
+      String xml_in;
+      while (true) {
+	if (int(time_sec()) > beg + timeout)
+	  throw String("timeout");
+	else
+	  xml_in += iter->second->recv(400);
+	try {
+	  parseXML(xml_in);
+	  resp = xml_in;
+	  break;
+	} catch ( ... ) {}
+      }
+    }
+    
+    PyObject* resp_p = Py_BuildValue("s", resp.c_str());
+    return resp_p;
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
+
+PyObject *
+conga_ssl_lib_trust(PyObject *self, PyObject *args)
+{
+  int id;
+  if (!PyArg_ParseTuple(args, "i", &id))
+    return NULL;
+  
+  try {
+    map<int, counting_auto_ptr<SSLClient> >::const_iterator iter = 
+      ssls.find(id);
+    if (iter == ssls.end())
+      throw String("SSL connection closed");
+    
+    bool resp;
+    {
+      PythonThreadsAllower all;
+      resp = iter->second->trust_peer_cert();
+    }
+    
+    PyObject* resp_p = Py_BuildValue("i", (resp)?1:0);
+    return resp_p;
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
+
+PyObject *
+conga_ssl_lib_trusted(PyObject *self, PyObject *args)
+{
+  int id;
+  if (!PyArg_ParseTuple(args, "i", &id))
+    return NULL;
+  
+  try {
+    map<int, counting_auto_ptr<SSLClient> >::const_iterator iter = 
+      ssls.find(id);
+    if (iter == ssls.end())
+      throw String("SSL connection closed");
+    
+    bool resp;
+    {
+      PythonThreadsAllower all;
+      resp = iter->second->peer_cert_trusted();
+    }
+    
+    PyObject* resp_p = Py_BuildValue("i", (resp)?1:0);
+    return resp_p;
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
+
+PyObject *
+conga_ssl_lib_untrust(PyObject *self, PyObject *args)
+{
+  int id;
+  if (!PyArg_ParseTuple(args, "i", &id))
+    return NULL;
+  
+  try {
+    map<int, counting_auto_ptr<SSLClient> >::const_iterator iter = 
+      ssls.find(id);
+    if (iter == ssls.end())
+      throw String("SSL connection closed");
+    
+    bool resp;
+    {
+      PythonThreadsAllower all;
+      resp = iter->second->untrust_peer_cert();
+    }
+    
+    PyObject* resp_p = Py_BuildValue("i", (resp)?1:0);
+    return resp_p;
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
+
+PyObject *
+conga_ssl_lib_peer_fingerprint(PyObject *self, PyObject *args)
+{
+  int id;
+  if (!PyArg_ParseTuple(args, "i", &id))
+    return NULL;
+  
+  try {
+    map<int, counting_auto_ptr<SSLClient> >::const_iterator iter = 
+      ssls.find(id);
+    if (iter == ssls.end())
+      throw String("SSL connection closed");
+    
+    String finger, digest;
+    {
+      PythonThreadsAllower all;
+      finger = iter->second->peer_cert_fingerprint(digest);
+    }
+    
+    PyObject* resp_p = Py_BuildValue("(ss)", digest.c_str(), finger.c_str());
+    return resp_p;
+  } catch (String e) {
+    PyErr_SetString(PyExc_Exception, e.c_str());
+  } catch ( ... ) {
+    PyErr_SetString(PyExc_Exception, "unknown");
+  }
+  return NULL;
+}
/cvs/cluster/conga/luci/conga_ssl/setup.py,v  -->  standard output
revision 1.1.2.1
--- conga/luci/conga_ssl/setup.py
+++ -	2006-12-08 18:27:35.171396000 +0000
@@ -0,0 +1,37 @@
+
+from distutils.core import setup, Extension
+
+
+module1 = Extension('conga_ssl_lib',
+                    define_macros = [('MAJOR_VERSION', '0'),
+                                     ('MINOR_VERSION', '8')],
+                    include_dirs = ['../../ricci/include',
+                                    '/usr/include/libxml2'],
+                    libraries = ['ssl', 'xml2'],
+                    #library_dirs = ['/usr/local/lib'],
+                    sources = ['conga_ssl_lib.cpp', 
+                               'SSLClient.cpp', 
+                               '../../ricci/common/ClientSocket.cpp', 
+                               '../../ricci/common/Socket.cpp', 
+                               '../../ricci/common/Logger.cpp', 
+                               '../../ricci/common/Time.cpp', 
+                               '../../ricci/common/File.cpp', 
+                               '../../ricci/common/XML.cpp', 
+                               '../../ricci/common/utils.cpp', 
+                               '../../ricci/common/executils.cpp'])
+
+
+
+setup (name = 'conga_ssl_lib',
+       version = '0.8',
+       description = 'SSL Python bindings for Conga', 
+       author = 'Stanko Kupcevic', 
+       author_email = 'kupcevic at redhat.com',
+       copyright = 'Red Hat, Inc.',
+       license = 'GPL', 
+       url = 'http://www.sourceware.org/cluster/conga',
+       long_description = '''
+       conga_ssl_lib
+       ''',
+       ext_modules = [module1])
+
--- conga/luci/site/Makefile	2006/08/24 14:38:28	1.11
+++ conga/luci/site/Makefile	2006/12/08 18:27:32	1.11.2.1
@@ -82,6 +82,7 @@
 	install -d ${DESTDIR}/var/lib/luci/var/pts
 #	install -m 644 `find luci/var/pts -maxdepth 1 -type f | grep .mo | grep -v \~ | grep -v \#` ${DESTDIR}/var/lib/luci/var/pts
 	install -d ${DESTDIR}/var/lib/luci/var/certs
+	install -d ${DESTDIR}/var/lib/luci/var/certs/peers
 	install -m 644 luci/var/certs/cacert.config ${DESTDIR}/var/lib/luci/var/certs
 	install -d ${DESTDIR}/var/lib/luci/var/stunnel
 
/cvs/cluster/conga/luci/site/luci/Extensions/conga_ssl.py,v  -->  standard output
revision 1.1.2.1
--- conga/luci/site/luci/Extensions/conga_ssl.py
+++ -	2006-12-08 18:27:35.466686000 +0000
@@ -0,0 +1,48 @@
+
+
+import sys
+sys.path.append('/usr/lib/luci/ssl')
+sys.path.append('/usr/lib64/luci/ssl')
+import conga_ssl_lib
+sys.path.remove('/usr/lib/luci/ssl')
+sys.path.remove('/usr/lib64/luci/ssl')
+
+
+
+# timeouts are in seconds (int)
+
+
+class SSLSocket:
+    
+    def __init__(self,
+                 hostname,
+                 port,
+                 timeout):
+        self.__id = -1
+        self.__id = conga_ssl_lib.connect(hostname, port, timeout)
+        pass
+    def __del__(self):
+        self.disconnect()
+        pass
+    def disconnect(self):
+        if self.__id != -1:
+            conga_ssl_lib.disconnect(self.__id)
+            self.__id = -1
+    
+    def peer_fingerprint(self):
+        return conga_ssl_lib.peer_fingerprint(self.__id)
+    
+    def trusted(self):
+        return conga_ssl_lib.trusted(self.__id) == 1
+    def trust(self):
+        if self.trusted():
+            return True
+        return conga_ssl_lib.trust(self.__id) == 1
+    def untrust(self):
+        return conga_ssl_lib.untrust(self.__id) == 1
+    
+    
+    def send(self, msg, timeout):
+        conga_ssl_lib.send(self.__id, msg, timeout)
+    def recv(self, timeout):
+        return conga_ssl_lib.recv(self.__id, timeout)
--- conga/luci/site/luci/Extensions/HelperFunctions.py	2006/11/29 22:33:50	1.4.2.1
+++ conga/luci/site/luci/Extensions/HelperFunctions.py	2006/12/08 18:27:32	1.4.2.2
@@ -1,6 +1,8 @@
 
 import AccessControl
 
+import threading
+from ricci_communicator import RicciCommunicator
 
 
 def add_commas(self, str1, str2):
@@ -29,17 +31,75 @@
 
 
 
+
+class Worker(threading.Thread):
+    def __init__(self,
+                 mutex,
+                 hosts,
+                 riccis):
+        threading.Thread.__init__(self)
+        self.mutex = mutex
+        self.hosts = hosts
+        self.riccis = riccis
+        return
+    def run(self):
+        while True:
+            self.mutex.acquire()
+            if len(self.hosts) == 0:
+                self.mutex.release()
+                return
+            host = self.hosts.pop()
+            self.mutex.release()
+            r = None
+            try:
+                r = RicciCommunicator(host)
+                #print host, 'done'
+            except Exception, e:
+                #print host, 'failed', str(e)
+                pass
+            except:
+                #print host, 'failed'
+                pass
+            self.mutex.acquire()
+            self.riccis[host] = r
+            self.mutex.release()
+        
+        
+                 
 # removes systems that user is not authorized access to
-def get_systems_statuses(self, systems):
-    ss = {}
+def get_systems_statuses(self, systems, from_cache=False):
+    CACHED_INDEX = '_get_systems_statuses()_cached_result_'
+    session = self.REQUEST.SESSION
+    if session.has_key(CACHED_INDEX):
+        res = session[CACHED_INDEX]
+        if res != None:
+            session.set(CACHED_INDEX, None)
+            if from_cache:
+                return res
+        pass
+    
     ass = self.allowed_systems(self, None, systems)
+    
+    mutex = threading.RLock()
+    hive  = [] # workers
+    ss    = {} # storage systems (will store riccis, and then use them to retrieve real info)
+    hosts = [] # hostnames
     for system in ass:
-        hostname = system[0]
+        hosts.append(system[0])
+        if len(hosts) < 10:
+            hive.append(Worker(mutex, hosts, ss))
+    
+    for bee in hive:
+        bee.start()
+    for bee in hive:
+        bee.join()
+    
+    for hostname in ss.keys():
         OS = ''
         cluname = ''
         cluali = ''
         authed = False
-        ricci = self.get_ricci_communicator(hostname, ass)
+        ricci = ss[hostname]
         if ricci != None:
             OS = ricci.os()
             cluname = ricci.cluster_info()[0]
@@ -53,6 +113,7 @@
              'clualias' : cluali, 
              'available': ricci != None,
              'authed'   : authed}
+        # replace ricci with system's info
         ss[hostname] = s
         pass
     ss_list = []
@@ -60,6 +121,9 @@
     sorted_keys.sort()
     for name in sorted_keys:
         ss_list.append(ss[name])
+    
+    session.set(CACHED_INDEX, ss_list)
+    
     return ss_list
 
 
@@ -88,7 +152,6 @@
     response.setCookie(cookie_prefix + var_name,
                        value, 
                        expires='Tue, 30 Jun 2060 12:00:00 GMT')
-    
     return value
 
 
--- conga/luci/site/luci/Extensions/StorageReport.py	2006/11/29 18:26:53	1.20.2.1
+++ conga/luci/site/luci/Extensions/StorageReport.py	2006/12/08 18:27:32	1.20.2.2
@@ -1878,17 +1878,8 @@
 
 
 
-def group_systems_by_cluster(self, allowed_systems, cache_it=False):
-    CACHED_INDEX = '_group_systems_by_cluster_cached_result_'
-    session = self.REQUEST.SESSION
-    if session.has_key(CACHED_INDEX):
-        res = session[CACHED_INDEX]
-        if res != None:
-            session.set(CACHED_INDEX, None)
-            return res
-        pass
-    
-    ss = get_systems_statuses(self, allowed_systems)
+def group_systems_by_cluster(self, allowed_systems, from_cache=False):
+    ss = get_systems_statuses(self, allowed_systems, from_cache)
     clusters = {}
     bad_list = []
     for s in ss:
@@ -1912,10 +1903,6 @@
     
     ret = [nonclu_list, clu_list, bad_list]
     
-    if cache_it:
-        session.set(CACHED_INDEX, ret)
-        pass
-    
     return ret
 
 
--- conga/luci/site/luci/Extensions/ricci_communicator.py	2006/11/20 23:32:43	1.9.2.6
+++ conga/luci/site/luci/Extensions/ricci_communicator.py	2006/12/08 18:27:32	1.9.2.7
@@ -1,8 +1,8 @@
-from socket import socket, ssl, AF_INET, SOCK_STREAM
 import xml
 import xml.dom
 from xml.dom import minidom
 from LuciSyslog import LuciSyslog
+from conga_ssl import SSLSocket
 
 CERTS_DIR_PATH = '/var/lib/luci/var/certs/'
 
@@ -15,32 +15,25 @@
     pass
 
 class RicciCommunicator:
-    def __init__(self, hostname, port=11111):
+    def __init__(self, hostname, enforce_trust=False, port=11111):
         self.__hostname = hostname
         self.__port = port
         
+        self.__timeout_init  = 4
+        self.__timeout_auth  = 4
+        self.__timeout_short = 6
+        self.__timeout_long  = 600
+        
         self.__privkey_file = CERTS_DIR_PATH + 'privkey.pem'
         self.__cert_file = CERTS_DIR_PATH + 'cacert.pem'
         
-        # socket
         try:
-            sock = socket(AF_INET, SOCK_STREAM)
-            sock.settimeout(2.0)
-            sock.connect((self.__hostname, self.__port))
-        except Exception, e:
-            raise RicciError, 'Error connecting to %s:%d: %s' \
-                    % (self.__hostname, self.__port, str(e))
-        except:
-            raise RicciError, 'Error connecting to %s:%d: unknown error' \
-                    % (self.__hostname, self.__port)
-
-        luci_log.debug_verbose('RC:init0: Connected to %s:%d' \
-            % (self.__hostname, self.__port))
-        try:
-            self.ss = ssl(sock, self.__privkey_file, self.__cert_file)
-            # TODO: data transfer timeout should be much less, 
-            # leave until all calls are async ricci calls
-            sock.settimeout(600.0) # 10 minutes
+            self.ss = SSLSocket(self.__hostname,
+                                self.__port,
+                                self.__timeout_init)
+            if enforce_trust:
+                if not self.ss.trusted():
+                    raise RicciError, 'ricci\'s certificate is not trusted'
         except Exception, e:
             raise RicciError, 'Error setting up SSL for connection to %s: %s' \
                 % (self.__hostname, str(e))
@@ -49,20 +42,20 @@
                 % self.__hostname
         
         # receive ricci header
-        hello = self.__receive()
+        hello = self.__receive(self.__timeout_init)
         try:
-            luci_log.debug_verbose('RC:init1: Received header from %s: \"%s\"' \
+            luci_log.debug_verbose('RC:init0: Received header from %s: \"%s\"' \
                 % (self.__hostname, hello.toxml()))
         except:
             pass
-
+        
         self.__authed = hello.firstChild.getAttribute('authenticated') == 'true'
         self.__cluname = hello.firstChild.getAttribute('clustername')
         self.__clualias = hello.firstChild.getAttribute('clusteralias')
         self.__reported_hostname = hello.firstChild.getAttribute('hostname')
         self.__os = hello.firstChild.getAttribute('os')
         self.__dom0 = hello.firstChild.getAttribute('xen_host') == 'true'
-
+        
         pass
     
     
@@ -104,10 +97,10 @@
         ricci.setAttribute("function", "authenticate")
         ricci.setAttribute("password", password)
         doc.appendChild(ricci)
-        self.__send(doc)
+        self.__send(doc, self.__timeout_auth)
         
         # receive response
-        resp = self.__receive()
+        resp = self.__receive(self.__timeout_auth)
         self.__authed = resp.firstChild.getAttribute('authenticated') == 'true'
 
         luci_log.debug_verbose('RC:auth1: auth call returning %d' \
@@ -121,8 +114,8 @@
         ricci.setAttribute('version', '1.0')
         ricci.setAttribute('function', 'unauthenticate')
         doc.appendChild(ricci)
-        self.__send(doc)
-        resp = self.__receive()
+        self.__send(doc, self.__timeout_auth)
+        resp = self.__receive(self.__timeout_auth)
 
         luci_log.debug_verbose('RC:unauth0: trying to unauthenticate to %s' \
             % self.__hostname)
@@ -167,7 +160,7 @@
         
         # send request
         try:
-            self.__send(doc)
+            self.__send(doc, self.__timeout_short)
         except Exception, e:
             luci_log.debug_verbose('RC:PB1: Error sending XML \"%s\" to host %s' \
                 % (doc.toxml(), self.__hostname))
@@ -177,7 +170,7 @@
             raise RicciError, 'Error sending XML to host %s' % self.__hostname
         
         # receive response
-        doc = self.__receive()
+        doc = self.__receive(self.__timeout_long)
         try:
             luci_log.debug_verbose('RC:PB2: received from %s XML \"%s\"' \
                 % (self.__hostname, doc.toxml()))
@@ -243,11 +236,11 @@
         doc.appendChild(ricci)
         
         # send request
-        self.__send(doc)
+        self.__send(doc, self.__timeout_short)
  
        
         # receive response
-        doc = self.__receive()
+        doc = self.__receive(self.__timeout_short)
         if doc.firstChild.getAttribute('success') == '12':
             return None
         if doc.firstChild.getAttribute('success') != '0':
@@ -265,20 +258,18 @@
     
     
     
-    def __send(self, xml_doc):
+    def __send(self, xml_doc, timeout):
         buff = xml_doc.toxml() + '\n'
-        while len(buff) != 0:
-            try:
-                pos = self.ss.write(buff)
-            except Exception, e:
-                luci_log.debug_verbose('RC:send0: Error sending XML \"%s\" to %s: %s' \
-                    % (buff, self.__hostname, str(e)))
-                raise RicciError, 'write error while sending XML to host %s' \
-                        % self.__hostname
-            except:
-                raise RicciError, 'write error while sending XML to host %s' \
-                        % self.__hostname
-            buff = buff[pos:]
+        try:
+            self.ss.send(buff, timeout)
+        except Exception, e:
+            luci_log.debug_verbose('RC:send0: Error sending XML \"%s\" to %s: %s' \
+                                   % (buff, self.__hostname, str(e)))
+            raise RicciError, 'write error while sending XML to host %s' \
+                  % self.__hostname
+        except:
+            raise RicciError, 'write error while sending XML to host %s' \
+                  % self.__hostname
         try:
             luci_log.debug_verbose('RC:send1: Sent XML \"%s\" to host %s' \
                 % (xml_doc.toxml(), self.__hostname))
@@ -286,21 +277,11 @@
             pass
         return
     
-    def __receive(self):
+    def __receive(self, timeout):
         doc = None
         xml_in = ''
         try:
-            while True:
-                buff = self.ss.read(10485760)
-                if buff == '':
-                    break
-                xml_in += buff
-                try:
-                    doc = minidom.parseString(xml_in)
-                    break
-                except:
-                    # we haven't received all of the XML data yet.
-                    continue
+            xml_in = self.ss.recv(timeout)
         except Exception, e:
             luci_log.debug_verbose('RC:recv0: Error reading data from %s: %s' \
                 % (self.__hostname, str(e)))
--- conga/luci/site/luci/Extensions/storage_adapters.py	2006/10/19 14:57:17	1.7.2.1
+++ conga/luci/site/luci/Extensions/storage_adapters.py	2006/12/08 18:27:32	1.7.2.2
@@ -61,7 +61,7 @@
     #display_clusters = True
     display_clusters = False
     if display_clusters:
-      sorted_data = self.group_systems_by_cluster(systems, cache_it=True)
+      sorted_data = self.group_systems_by_cluster(systems, from_cache=False)
       for sdl in sorted_data[:2]:
         for data in sdl:
           createStorageChooser_inner(url,
@@ -70,7 +70,7 @@
                                      data,
                                      syslist)
     else:
-      sorted_data = get_systems_statuses(self, systems)
+      sorted_data = get_systems_statuses(self, systems, from_cache=False)
       for data in sorted_data:
         createStorageChooser_inner(url,
                                    pagetype,
--- conga/luci/storage/form-macros	2006/10/31 17:48:33	1.17.2.3
+++ conga/luci/storage/form-macros	2006/12/08 18:27:32	1.17.2.4
@@ -293,7 +293,7 @@
     </form>
    </fieldset> 
    
-   <dl tal:define="tmp_triple   python:here.group_systems_by_cluster(allowed_systems);
+   <dl tal:define="tmp_triple   python:here.group_systems_by_cluster(allowed_systems, from_cache=True);
                    nonclu_list  python:tmp_triple[0];
                    clu_list     python:tmp_triple[1];
                    bad_list     python:tmp_triple[2]">
--- conga/ricci/ricci/SSLInstance.cpp	2006/10/23 21:13:22	1.5.2.1
+++ conga/ricci/ricci/SSLInstance.cpp	2006/12/08 18:27:32	1.5.2.2
@@ -137,6 +137,11 @@
   else
     ssl_locks[n]->unlock();
 }
+static pthread_t
+ssl_id_callback(void)
+{
+  return pthread_self();
+}
 
 
 
@@ -157,12 +162,12 @@
       // TODO: random number generator,
       // not on systems with /dev/urandom (eg. Linux)
       
-      // set up lockings
+      // thread support
       ssl_locks.clear();
-      for (int i=0; i<CRYPTO_num_locks(); i++)
+      for (int i=0; i<CRYPTO_num_locks()+1; i++)
 	ssl_locks.push_back(counting_auto_ptr<Mutex>(new Mutex()));
       CRYPTO_set_locking_callback(ssl_mutex_callback);
-      //CRYPTO_set_id_callback(ssl_id_function); not needed on Linux
+      CRYPTO_set_id_callback(ssl_id_callback);
       
       // create context
       if (!ctx)
@@ -354,6 +359,7 @@
   
   // cert present among saved certs?
   client_has_cert();  // make sure cert is saved in _cert_pem
+  MutexLocker l(global_lock);
   for (list<file_cert>::const_iterator iter = authorized_certs.begin();
        iter != authorized_certs.end();
        iter++)




More information about the Cluster-devel mailing list