Index: fedd/fedd_access.py
===================================================================
--- fedd/fedd_access.py	(revision fd729b99d1f3dd242eae6b1fbb97e59b7726f59b)
+++ fedd/fedd_access.py	(revision f8582c9a024862e2f99c61a303029f0c7929d8b3)
@@ -16,4 +16,6 @@
 import pickle
 
+from threading import *
+
 from fedd_access_project import access_project
 from fedd_services import *
@@ -49,4 +51,130 @@
 	    "dynamic_projects_cert_pwd", "dynamic_projects_trusted_certs")
     id_list_attrs = ("restricted",)
+
+    def __init__(self, config=None):
+	"""
+	Initializer.  Pulls parameters out of the ConfigParser's access section.
+	"""
+
+	# Make sure that the configuration is in place
+	if config: 
+	    if not config.has_section("access"):
+		config.add_section("access")
+	    if not config.has_section("globals"):
+		config.add_section("globals")
+	else:
+	    raise RunTimeError("No config to fedd_access")
+
+
+	# Create instance attributes from the static lists
+	for a in fedd_access.bool_attrs:
+	    if config.has_option("access", a):
+		setattr(self, a, config.get("access", a))
+	    else:
+		setattr(self, a, False)
+
+	for a in fedd_access.emulab_attrs + fedd_access.id_attrs:
+	    if config.has_option("access", a):
+		setattr(self, a, config.get("access",a))
+	    else:
+		setattr(self, a, None)
+
+	self.attrs = { }
+	self.access = { }
+	self.restricted = [ ]
+	self.fedid_category = { }
+	self.projects = { }
+	self.keys = { }
+	self.allocation = { }
+	self.state = { 
+	    'projects': self.projects,
+	    'allocation' : self.allocation,
+	    'keys' : self.keys
+	}
+	self.state_lock = Lock()
+	self.fedid_default = "testbed"
+	if config.has_option("access", "accessdb"):
+	    self.read_access(config.get("access", "accessdb"))
+	if config.has_option("access", "trustdb"):
+	    self.read_trust(config.get("access", "trustdb"))
+
+	self.state_filename = config.get("access", "access_state", "")
+	self.log = logging.getLogger("fedd.access")
+	set_log_level(config, "access", self.log)
+	self.read_state()
+
+
+	# Certs are promoted from the generic to the specific, so without a
+	# specific proxy certificate, the main certificates are used for
+	# proxy interactions. If no dynamic project certificates, then
+	# proxy certs are used, and if none of those the main certs.
+
+	if config.has_option("globals", "proxy_cert_file"):
+	    if not self.dynamic_projects_cert_file:
+		self.dynamic_projects_cert_file = \
+			config.get("globals", "proxy_cert_file")
+		if config.has_option("globals", "porxy_cert_pwd"):
+		    self.dynamic_projects_cert_pwd = \
+			    config.get("globals", "proxy_cert_pwd")
+
+	if config.has_option("globals", "proxy_trusted_certs"):
+	    if not self.dynamic_projects_trusted_certs:
+		self.dynamic_projects_trusted_certs =\
+			config.get("globals", proxy_trusted_certs)
+
+	if config.has_option("globals", "cert_file"):
+	    has_pwd = config.has_option("globals", "cert_pwd")
+	    if not self.dynamic_projects_cert_file:
+		self.dynamic_projects_cert_file = \
+			config.get("globals", "cert_file")
+		if has_pwd: 
+		    self.dynamic_projects_cert_pwd = \
+			    config.get("globals", "cert_pwd")
+	    if not self.proxy_cert_file:
+		self.proxy_cert_file = config.get("globals", "cert_file")
+		if has_pwd:
+		    self.proxy_cert_pwd = config.get("globals", "cert_pwd")
+
+	if config.get("globals", "trusted_certs"):
+	    if not self.proxy_trusted_certs:
+		self.proxy_trusted_certs = \
+			config.get("globals", "trusted_certs")
+	    if not self.dynamic_projects_trusted_certs:
+		self.dynamic_projects_trusted_certs = \
+			config.get("globals", "trusted_certs")
+
+	proj_certs = (self.dynamic_projects_cert_file, 
+		self.dynamic_projects_trusted_certs,
+		self.dynamic_projects_cert_pwd)
+
+	self.soap_services = {\
+	    'RequestAccess': make_soap_handler(\
+		RequestAccessRequestMessage.typecode,\
+		self.RequestAccess, RequestAccessResponseMessage,\
+		"RequestAccessResponseBody"), \
+	    'ReleaseAccess': make_soap_handler(\
+		ReleaseAccessRequestMessage.typecode,\
+		self.ReleaseAccess, ReleaseAccessResponseMessage,\
+		"ReleaseAccessResponseBody")\
+	    }
+	self.xmlrpc_services =  {\
+	    'RequestAccess': make_xmlrpc_handler(\
+		self.RequestAccess, "RequestAccessResponseBody"),\
+	    'ReleaseAccess': make_xmlrpc_handler(\
+		self.ReleaseAccess, "ReleaseAccessResponseBody")\
+	    }
+
+
+	if not config.has_option("access", "dynamic_projects_url"):
+	    self.allocate_project = \
+		fedd_allocate_project_local(config)
+	else:
+	    self.allocate_project = \
+		fedd_allocate_project_remote(config)
+
+	# If the project allocator exports services, put them in this object's
+	# maps so that classes that instantiate this can call the services.
+	self.soap_services.update(self.allocate_project.soap_services)
+	self.xmlrpc_services.update(self.allocate_project.xmlrpc_services)
 
     def read_trust(self, trust):
@@ -192,128 +320,4 @@
 	f.close()
 
-
-    def __init__(self, config=None):
-	"""
-	Initializer.  Pulls parameters out of the ConfigParser's access section.
-	"""
-
-	# Make sure that the configuration is in place
-	if config: 
-	    if not config.has_section("access"):
-		config.add_section("access")
-	    if not config.has_section("globals"):
-		config.add_section("globals")
-	else:
-	    raise RunTimeError("No config to fedd_access")
-
-
-	# Create instance attributes from the static lists
-	for a in fedd_access.bool_attrs:
-	    if config.has_option("access", a):
-		setattr(self, a, config.get("access", a))
-	    else:
-		setattr(self, a, False)
-
-	for a in fedd_access.emulab_attrs + fedd_access.id_attrs:
-	    if config.has_option("access", a):
-		setattr(self, a, config.get("access",a))
-	    else:
-		setattr(self, a, None)
-
-	self.attrs = { }
-	self.access = { }
-	self.restricted = [ ]
-	self.fedid_category = { }
-	self.projects = { }
-	self.keys = { }
-	self.allocation = { }
-	self.state = { 
-	    'projects': self.projects,
-	    'allocation' : self.allocation,
-	    'keys' : self.keys
-	}
-	self.fedid_default = "testbed"
-	if config.has_option("access", "accessdb"):
-	    self.read_access(config.get("access", "accessdb"))
-	if config.has_option("access", "trustdb"):
-	    self.read_trust(config.get("access", "trustdb"))
-
-	self.state_filename = config.get("access", "access_state", "")
-	self.log = logging.getLogger("fedd.access")
-	self.read_state()
-
-
-	# Certs are promoted from the generic to the specific, so without a
-	# specific proxy certificate, the main certificates are used for
-	# proxy interactions. If no dynamic project certificates, then
-	# proxy certs are used, and if none of those the main certs.
-
-	if config.has_option("globals", "proxy_cert_file"):
-	    if not self.dynamic_projects_cert_file:
-		self.dynamic_projects_cert_file = \
-			config.get("globals", "proxy_cert_file")
-		if config.has_option("globals", "porxy_cert_pwd"):
-		    self.dynamic_projects_cert_pwd = \
-			    config.get("globals", "proxy_cert_pwd")
-
-	if config.has_option("globals", "proxy_trusted_certs"):
-	    if not self.dynamic_projects_trusted_certs:
-		self.dynamic_projects_trusted_certs =\
-			config.get("globals", proxy_trusted_certs)
-
-	if config.has_option("globals", "cert_file"):
-	    has_pwd = config.has_option("globals", "cert_pwd")
-	    if not self.dynamic_projects_cert_file:
-		self.dynamic_projects_cert_file = \
-			config.get("globals", "cert_file")
-		if has_pwd: 
-		    self.dynamic_projects_cert_pwd = \
-			    config.get("globals", "cert_pwd")
-	    if not self.proxy_cert_file:
-		self.proxy_cert_file = config.get("globals", "cert_file")
-		if has_pwd:
-		    self.proxy_cert_pwd = config.get("globals", "cert_pwd")
-
-	if config.get("globals", "trusted_certs"):
-	    if not self.proxy_trusted_certs:
-		self.proxy_trusted_certs = \
-			config.get("globals", "trusted_certs")
-	    if not self.dynamic_projects_trusted_certs:
-		self.dynamic_projects_trusted_certs = \
-			config.get("globals", "trusted_certs")
-
-	proj_certs = (self.dynamic_projects_cert_file, 
-		self.dynamic_projects_trusted_certs,
-		self.dynamic_projects_cert_pwd)
-
-	self.soap_services = {\
-	    'RequestAccess': make_soap_handler(\
-		RequestAccessRequestMessage.typecode,\
-		self.RequestAccess, RequestAccessResponseMessage,\
-		"RequestAccessResponseBody"), \
-	    'ReleaseAccess': make_soap_handler(\
-		ReleaseAccessRequestMessage.typecode,\
-		self.ReleaseAccess, ReleaseAccessResponseMessage,\
-		"ReleaseAccessResponseBody")\
-	    }
-	self.xmlrpc_services =  {\
-	    'RequestAccess': make_xmlrpc_handler(\
-		self.RequestAccess, "RequestAccessResponseBody"),\
-	    'ReleaseAccess': make_xmlrpc_handler(\
-		self.ReleaseAccess, "ReleaseAccessResponseBody")\
-	    }
-
-
-	if not config.has_option("access", "dynamic_projects_url"):
-	    self.allocate_project = \
-		fedd_allocate_project_local(config)
-	else:
-	    self.allocate_project = \
-		fedd_allocate_project_remote(config)
-
-	# If the project allocator exports services, put them in this object's
-	# maps so that classes that instantiate this can call the services.
-	self.soap_services.update(self.allocate_project.soap_services)
-	self.xmlrpc_services.update(self.allocate_project.xmlrpc_services)
 
     def dump_state(self):
@@ -735,11 +739,8 @@
 			"SSH access parameters required")
 	    # keep track of what's been added
-	    if req['allocID'].has_key('fedid'):
-		aid = unicode(req['allocId']['fedid'])
-	    elif req['allocID'].has_key('localname'):
-		aid = req['allocID']['localname']
-	    else:
-		raise service_error(service_error.req, "Bad allocation ID")
-
+	    allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
+	    aid = unicode(allocID)
+
+	    self.state_lock.acquire()
 	    self.allocation[aid] = { }
 	    if dyn[1]:
@@ -747,4 +748,5 @@
 		    pname = ap['project']['name']['localname']
 		except KeyError:
+		    self.state_lock.release()
 		    raise service_error(service_error.internal,
 			    "Misformed allocation response?")
@@ -765,9 +767,11 @@
 			self.allocation[aid]['keys'].append((uname, k))
 	    except KeyError:
+		self.state_lock.release()
 		raise service_error(service_error.internal,
 			"Misformed allocation response?")
 
 	    self.write_state()
-	    resp = self.build_response(req['allocID'], ap)
+	    self.state_lock.release()
+	    resp = self.build_response({ 'fedid': allocID } , ap)
 	    return resp
 	else:
@@ -806,5 +810,4 @@
 	    raise service_error(service_error.req, "No request!?")
 
-	print req
 	try:
 	    if req['allocID'].has_key('localname'):
@@ -827,4 +830,5 @@
 	del_project = None
 	if self.allocation.has_key(aid):
+	    self.state_lock.acquire()
 	    for k in self.allocation[aid]['keys']:
 		kk = "%s:%s" % k
@@ -844,9 +848,11 @@
 
 	    del self.allocation[aid]
+	    self.write_state()
+	    self.state_lock.release()
 	    # If we actually have resources to deallocate, prepare the call.
 	    if del_project or del_users:
 		msg = { 'project': { }}
 		if del_project:
-		    msg['project']['name']['localname'] =  del_project
+		    msg['project']['name']= {'localname': del_project}
 		users = [ ]
 		for u in del_users.keys():
@@ -860,5 +866,4 @@
 		    msg = { 'ReleaseProjectRequestBody' : msg}
 		    self.allocate_project.release_project(msg)
-	    self.write_state()
 	    return { 'allocID': req['allocID'] } 
 	else:
Index: fedd/fedd_allocate_project.py
===================================================================
--- fedd/fedd_allocate_project.py	(revision fd729b99d1f3dd242eae6b1fbb97e59b7726f59b)
+++ fedd/fedd_allocate_project.py	(revision f8582c9a024862e2f99c61a303029f0c7929d8b3)
@@ -20,6 +20,5 @@
 from fedd_internal_services import *
 from fedd_util import *
-import fixed_key
-import parse_detail
+from fixed_resource import read_key_db, read_project_db
 from service_error import *
 import logging
@@ -60,25 +59,17 @@
 	fixed_key_db = config.get("access", "fixed_keys", None)
 	fixed_project_db = config.get("access", "fixed_projects", None)
-	if fixed_key_db:
-	    try:
-		self.fixed_keys = fixed_key.read_db(fixed_key_db)
-	    except:
-		log.debug("Can't read fixed_key_db from %s" % fixed_key_db)
-	else:
-	    self.fixed_keys = set()
-
-	if fixed_project_db:
-	    try:
-		f = open(fixed_project_db, "r")
-		for line in f:
-		    self.fixed_projects.add(line.rstrip())
-		f.close()
-	    except:
-		log.debug("Can't read fixed_project_db from %s" % \
-			fixed_project_db)
-	else:
-	    self.fixed_projects = set()
-
-
+	self.fixed_keys = set()
+	self.fixed_projects = set()
+
+	# initialize the fixed resource sets
+	for db, rset, fcn in (\
+		(fixed_key_db, self.fixed_keys, read_key_db), \
+		(fixed_project_db, self.fixed_projects, read_project_db)):
+	    if db:
+		try:
+		    rset.update(fcn(db))
+		except:
+		    self.log.debug("Can't read resources from %s" % db)
+	
 	# Internal services are SOAP only
 	self.soap_services = {\
@@ -91,8 +82,8 @@
 		self.static_project, StaticProjectResponseMessage,\
 		"StaticProjectResponseBody"),\
-		#"ReleaseProject": make_soap_handler(\
-		#ReleaseProjectRequestMessage.typecode,\
-		#self.release_project, ReleaseProjectResponseMessage,\
-		#"ReleaseProjectResponseBody")\
+		"ReleaseProject": make_soap_handler(\
+		ReleaseProjectRequestMessage.typecode,\
+		self.release_project, ReleaseProjectResponseMessage,\
+		"ReleaseProjectResponseBody")\
 		}
 	self.xmlrpc_services = { }
@@ -290,6 +281,4 @@
 		    rc = subprocess.call(cmd)
 		except OSError, e:
-		    print "Static project subprocess creation error "+ \
-				    "[%s] (%s)" %  (cmd[0], e.strerror)
 		    raise service_error(service_error.internal,
 			    "Static project subprocess creation error "+ \
@@ -315,5 +304,4 @@
 	users = []
 
-	print "release %s" % req
 	try:
 	    if req['ReleaseProjectRequestBody']['project'].has_key('name'):
@@ -332,8 +320,8 @@
 	    for sk in [ k['sshPubkey'] for k in u.get('access', []) \
 		    if k.has_key('sshPubkey')]:
-		if (name, sk) not in self.fixed_keys:
+		if (name.rstrip(), sk.rstrip()) not in self.fixed_keys:
 		    cmds.append((self.wap, self.addpubkey, '-R', '-w', \
 			    '-u', name, '-k', sk))
-	if pname and pname not in fixed_projects:
+	if pname and pname not in self.fixed_projects:
 	    cmds.append((self.wap, self.rmproj, pname))
 
@@ -346,6 +334,4 @@
 		    rc = subprocess.call(cmd)
 		except OSError, e:
-		    print "Release project subprocess creation error "+ \
-				    "[%s] (%s)" %  (cmd[0], e.strerror)
 		    raise service_error(service_error.internal,
 			    "Release project subprocess creation error "+ \
@@ -425,4 +411,7 @@
 	    "StaticProjectRequestBody", StaticProjectRequestMessage,
 	    "StaticProjectResponseBody")
+    release_project = make_proxy("ReleaseProject",
+	    "ReleaseProjectRequestBody", ReleaseProjectRequestMessage,
+	    "ReleaseProjectResponseBody")
 
     def __init__(self, config):
@@ -468,3 +457,2 @@
 	self.log = logging.getLogger("fedd.allocate.remote")
 	set_log_level(config, "access", self.log)
-	self.release_project = None
Index: fedd/fedd_experiment_control.py
===================================================================
--- fedd/fedd_experiment_control.py	(revision fd729b99d1f3dd242eae6b1fbb97e59b7726f59b)
+++ fedd/fedd_experiment_control.py	(revision f8582c9a024862e2f99c61a303029f0c7929d8b3)
@@ -852,5 +852,5 @@
 	# case, making all the subclasses of basestring into unicode strings
 	# unifies the response format and solves the problem.
-	r = make_unicode(unpack_soap(resp))
+	r = make_unicode(fedids_to_obj(unpack_soap(resp)))
 
 	if r.has_key('RequestAccessResponseBody'):
@@ -896,8 +896,7 @@
 	# The basic request
 	req = { 'allocID' : aid }
-	
+
 	# No retry loop here.  Proxy servers must correctly authenticate
 	# themselves without help
-
 	try:
 	    ctx = fedd_ssl_context(self.cert_file, 
@@ -926,6 +925,4 @@
 
 	# better error coding
-
-
 
     def remote_splitter(self, uri, desc, master):
@@ -1644,5 +1641,7 @@
 	os.rmdir(tmpdir)
 
-	resp = { 'federant' : [ tbparams[tb]['federant'] \
+	# The deepcopy prevents the allocation ID and other binaries from being
+	# translated into other formats
+	resp = { 'federant' : [ copy.deepcopy(tbparams[tb]['federant']) \
 		for tb in tbparams.keys() \
 		    if tbparams[tb].has_key('federant') ],\
@@ -1691,5 +1690,5 @@
 	if exp:
 	    if exp.has_key('fedid'):
-		key = fedid(bits=exp['fedid'])
+		key = exp['fedid']
 		keytype = "fedid"
 	    elif exp.has_key('localname'):
@@ -1724,5 +1723,5 @@
 	if exp:
 	    if exp.has_key('fedid'):
-		key = fedid(bits=exp['fedid'])
+		key = exp['fedid']
 		keytype = "fedid"
 	    elif exp.has_key('localname'):
@@ -1757,5 +1756,5 @@
 	if exp:
 	    if exp.has_key('fedid'):
-		key = fedid(bits=exp['fedid'])
+		key = exp['fedid']
 		keytype = "fedid"
 	    elif exp.has_key('localname'):
@@ -1792,5 +1791,5 @@
 	if exp:
 	    if exp.has_key('fedid'):
-		key = fedid(bits=exp['fedid'])
+		key = exp['fedid']
 		keytype = "fedid"
 	    elif exp.has_key('localname'):
Index: fedd/fedd_internal_bindings.wsdl
===================================================================
--- fedd/fedd_internal_bindings.wsdl	(revision fd729b99d1f3dd242eae6b1fbb97e59b7726f59b)
+++ fedd/fedd_internal_bindings.wsdl	(revision f8582c9a024862e2f99c61a303029f0c7929d8b3)
@@ -58,4 +58,25 @@
 	</fault>
       </operation>
+      <operation name="ReleaseProject">
+	<documentation>
+	  The bindings of this operation are straightforward SOAP RPC 1.1.
+	</documentation>
+	<soap:operation soapAction="ReleaseProject"/> 
+	<input>
+	  <soap:body use="encoded" parts="tns:ReleaseProjectRequestBody"
+	    namespace="http://www.isi.edu/faber/fedd_internal.wsdl"
+	    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+	</input>
+	<output>
+	  <soap:body use="encoded" parts="tns:ReleaseProjectResponseBody"
+	    namespace="http://www.isi.edu/faber/fedd_internal.wsdl"
+	    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+	</output>
+	<fault>
+	  <soap:fault use="encoded"  name="tns:ReleaseProjectFault"
+	    namespace="http://www.isi.edu/faber/fedd_internal.wsdl"
+	    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+	</fault>
+      </operation>
       <operation name="Ns2Split">
 	<documentation>
Index: fedd/fedd_internal_messages.wsdl
===================================================================
--- fedd/fedd_internal_messages.wsdl	(revision fd729b99d1f3dd242eae6b1fbb97e59b7726f59b)
+++ fedd/fedd_internal_messages.wsdl	(revision f8582c9a024862e2f99c61a303029f0c7929d8b3)
@@ -35,4 +35,13 @@
   </message>
 
+  <message name="ReleaseProjectRequestMessage">
+    <part name="ReleaseProjectRequestBody" type="xsd1:projectAllocType"/>
+  </message>
+
+  <message name="ReleaseProjectResponseMessage">
+    <part name="ReleaseProjectResponseBody" 
+      type="xsd1:projectAllocResponseType"/>
+  </message>
+
   <message name="Ns2SplitRequestMessage">
     <part name="Ns2SplitRequestBody" type="xsd1:ns2SplitRequestType"/>
@@ -65,4 +74,14 @@
       <fault name="InternalFault" message="tns:FaultMessage"/>
     </operation>
+    <operation name="ReleaseProject">
+      <documentation>
+	This internal interface allows the part of a fedd running on a machine
+	other than the boss node of the emulab in question to release resources
+	allocated to either a static or dynamic project.
+      </documentation>
+      <input message="tns:ReleaseProjectRequestMessage"/>
+      <output message="tns:ReleaseProjectResponseMessage"/>
+      <fault name="InternalFault" message="tns:FaultMessage"/>
+    </operation>
     <operation name="Ns2Split">
       <documentation>
Index: fedd/fedd_util.py
===================================================================
--- fedd/fedd_util.py	(revision fd729b99d1f3dd242eae6b1fbb97e59b7726f59b)
+++ fedd/fedd_util.py	(revision f8582c9a024862e2f99c61a303029f0c7929d8b3)
@@ -192,5 +192,4 @@
 	if attr: obj = attr()
 	else:
-	    print dir(container)
 	    raise TypeError("%s does not have a new_%s attribute" % \
 		    (container, name))
@@ -233,57 +232,58 @@
     else: 
 	return element
+def apply_to_tags(e, map):
+    """
+    Map is an iterable of ordered pairs (tuples) that map a key to a function.
+    This function walks the given message and replaces any object with a key in
+    the map with the result of applying that function to the object.
+    """
+    dict_type = type(dict())
+    list_type = type(list())
+    str_type = type(str())
+
+    if isinstance(e, dict_type):
+	for k in e.keys():
+	    for tag, fcn in map:
+		if k == tag:
+		    if isinstance(e[k], list_type):
+			e[k] = [ fcn(b) for b in e[k]]
+		    else:
+			e[k] = fcn(e[k])
+		elif isinstance(e[k], dict_type):
+		    apply_to_tags(e[k], map)
+		elif isinstance(e[k], list_type):
+		    for ee in e[k]:
+			apply_to_tags(ee, map)
+    # Other types end the recursion - they should be leaves
+    return e
+
+# These are all just specializations of apply_to_tags
+def fedids_to_obj(e, tags=('fedid',)):
+    """
+    Turn the fedids in a message that are encoded as bitstrings into fedid
+    objects.
+    """
+    map = [ (t, lambda x: fedid(bits=x)) for t in tags]
+    return apply_to_tags(e, map)
 
 def encapsulate_binaries(e, tags):
     """Walk through a message and encapsulate any dictionary entries in 
     tags into a binary object."""
-    dict_type = type(dict())
-    list_type = type(list())
-    str_type = type(str())
-
-    if isinstance(e, dict_type):
-	for k in e.keys():
-	    if k in tags:
-		if isinstance(e[k], list_type):
-		    bin_list = []
-		    for ee in e[k]:
-			if getattr(ee, 'pack_xmlrpc', None):
-			    bin_list.append(Binary(ee.pack_xmlrpc()))
-			else:
-			    bin_list.append(Binary(ee))
-		    e[k] = bin_list
-		elif getattr(e[k],'pack_xmlrpc', None):
-		    e[k] = Binary(e[k].pack_xmlrpc())
-		else:
-		    e[k] = Binary(e[k])
-	    elif isinstance(e[k], dict_type):
-		encapsulate_binaries(e[k], tags)
-	    elif isinstance(e[k], list_type):
-		for ee in e[k]:
-		    encapsulate_binaries(ee, tags)
-    # Other types end the recursion - they should be leaves
-    return e
+
+    def to_binary(o):
+	pack = getattr(o, 'pack_xmlrpc', None)
+	if callable(pack): return Binary(pack())
+	else: return Binary(o)
+
+    map = [ (t, to_binary) for t in tags]
+    return apply_to_tags(e, map)
 
 def decapsulate_binaries(e, tags):
     """Walk through a message and encapsulate any dictionary entries in 
     tags into a binary object."""
-    dict_type = type(dict())
-    list_type = type(list())
-    str_type = type(str())
-
-    if isinstance(e, dict_type):
-	for k in e.keys():
-	    if k in tags:
-		if isinstance(e[k], list_type):
-		    e[k] = [ b.data for b in e[k]]
-		else:
-		    e[k] = e[k].data
-	    elif isinstance(e[k], dict_type):
-		decapsulate_binaries(e[k], tags)
-	    elif isinstance(e[k], list_type):
-		for ee in e[k]:
-		    decapsulate_binaries(ee, tags)
-    # Other types end the recursion - they should be leaves
-    return e
-
+
+    map = [ (t, lambda x: x.data) for t in tags]
+    return apply_to_tags(e, map)
+#end of tag specializations
 
 def strip_unicode(obj):
@@ -318,5 +318,5 @@
     Create a new certificate and derive a fedid from it.
 
-    The fedid and the certificte are returned as a tuple.
+    The fedid and the certificate are returned as a tuple.
     """
 
@@ -340,5 +340,4 @@
 	    if trace: call_out = trace
 	    else: 
-		log.debug("set to dev/null")
 		call_out = open("/dev/null", "w")
 
@@ -382,5 +381,5 @@
 	req = ps.Parse(typecode)
 
-	msg = method(unpack_soap(req), fedid)
+	msg = method(fedids_to_obj(unpack_soap(req)), fid)
 
 	resp = constructor()
@@ -397,6 +396,5 @@
     return handler
 
-def make_xmlrpc_handler(method, body_name, input_binaries=('fedid',), 
-	output_binaries=('fedid',)):
+def make_xmlrpc_handler(method, body_name):
     """
     Generate the handler code to unpack and pack SOAP requests and responses
@@ -405,17 +403,20 @@
     The code to marshall and unmarshall XMLRPC parameters to and from a fedd
     service is largely the same.  This helper creates such a handler.  The
-    parameters are the method name, the name of the body struct that contains
-    the response asn the list of fields that are encoded as Binary objects in
-    the input and in the output.  A handler is created that takes the params
-    response from an xm,lrpclib.loads on the incoming rpc and a fedid and
-    responds with a hash representing the struct ro be returned to the other
-    side.  On error None is returned.
+    parameters are the method name, and the name of the body struct that
+    contains the response.  A handler is created that takes the params response
+    from an xmlrpclib.loads on the incoming rpc and a fedid and responds with
+    a hash representing the struct ro be returned to the other side.  On error
+    None is returned.  Fedid fields are decapsulated from binary and converted
+    to fedid objects on input and encapsulated as Binaries on output.
     """
     def handler(params, fid):
-	p = decapsulate_binaries(params[0], input_binaries)
-	msg = method(p, fedid)
+	decap_fedids = (('fedid', lambda x: fedid(bits=x.data)),)
+
+	#p = decapsulate_binaries(params[0], input_binaries)
+	p = apply_to_tags(params[0], decap_fedids)
+	msg = method(p, fid)
 
 	if msg != None:
-	    return encapsulate_binaries({ body_name: msg }, output_binaries)
+	    return encapsulate_binaries({ body_name: msg }, ('fedid',))
 	else:
 	    return None
Index: fedd/fixed_resource.py
===================================================================
--- fedd/fixed_resource.py	(revision fd729b99d1f3dd242eae6b1fbb97e59b7726f59b)
+++ fedd/fixed_resource.py	(revision f8582c9a024862e2f99c61a303029f0c7929d8b3)
@@ -68,4 +68,7 @@
 
     class key_opts(OptionParser):
+	"""
+	Options to the command line, pretty self describing
+	"""
 	def __init__(self):
 	    OptionParser.__init__(self, usage="%prog " + \
@@ -90,5 +93,4 @@
     parser = key_opts()
     action = sys.argv[1]
-    keys = set()
 
     # Check the action
@@ -96,5 +98,5 @@
     else: sys.exit("Bad action, must be one of %s" % ", ".join(actions))
 
-    # Parse the options
+    # Parse and check the the options for consistency
     (opts, args) = parser.parse_args()
     if not opts.file:
@@ -149,4 +151,5 @@
 		print >>sys.stderr, "Cannot delete (%s, %s): not in db" % \
 			(user, key)
+	# init action falls through to write an empty DB
 	write_key_db(opts.file, keys)
     else:
@@ -176,4 +179,6 @@
 	    else:
 		print >>sys.stderr, "Cannot delete %s: not in db" % project
+
+	# init action falls through to write an empty DB
 	write_project_db(opts.file, projects)
 
