Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision 593e901c6f5948d13170376f94bcd56a297b7a62)
+++ fedd/federation/emulab_access.py	(revision 9b3627e2bc4bf66eafb212abd8218420b86c0d95)
@@ -56,4 +56,15 @@
         Initializer.  Pulls parameters out of the ConfigParser's access section.
         """
+
+	def software_list(v):
+	    l = [ ]
+	    if v:
+		ps = v.split(" ")
+		while len(ps):
+		    loc, file = ps[0:2]
+		    del ps[0:2]
+		    l.append((loc, file))
+	    return l
+
 
         # Make sure that the configuration is in place
@@ -73,4 +84,6 @@
 	self.userconfcmd = config.get("access","userconfcmd")
 	self.userconfurl = config.get("access","userconfurl")
+	self.federation_software = config.get("access", "federation_software")
+	self.portal_software = config.get("access", "portal_software")
 	self.ssh_privkey_file = config.get("access","ssh_privkey_file")
 	self.ssh_pubkey_file = config.get("access","ssh_pubkey_file")
@@ -79,4 +92,7 @@
 	self.cleanup = not config.getboolean("access", "leave_tmpfiles")
 	self.access_type = config.get("access", "type")
+   
+	self.federation_software = software_list(self.federation_software)
+	self.portal_software = software_list(self.portal_software)
 
 	self.access_type = self.access_type.lower()
@@ -968,4 +984,20 @@
 		'userconfig': client_null,
 	    }
+
+	def server_port(f, s):
+	    p = urlparse(s.get('server', 'http://localhost'))
+	    print >>f, 'port: remote:%s:%s:%s' % (p.port, p.hostname, p.port) 
+
+	def server_null(f,s): pass
+
+	def server_seer(f, s):
+	    print >>f, 'seer: true'
+
+	server_service_out = {
+		'SMB': server_port,
+		'tmcd': server_port,
+		'userconfig': server_null,
+		'seer': server_seer,
+	    }
 	# XXX: end un hardcode this
 
@@ -1006,7 +1038,5 @@
 			for s in [s for s in services \
 				if s.get('name', "") in self.imports]:
-			    p = urlparse(s.get('server', 'http://localhost'))
-			    print >>f, 'port: remote:%s:%s:%s' % \
-				    (p.port, p.hostname, p.port)
+			    server_service_out[s['name']](f, s)
 
 		if tunnelconfig:
@@ -1026,17 +1056,17 @@
 	    
 	    # XXX: This little seer config file needs to go away.
-	    if not seer_out:
-		try:
-		    seerfn = "%s/seer.conf" % tmpdir
-		    f = open(seerfn, "w")
-		    if not master:
-			print >>f, "ControlNode: control.%s.%s%s" % \
-			    (meid.lower(), mproj.lower(), mdomain)
-		    print >>f, "ExperimentID: %s" % mexp
-		    f.close()
-		except IOError, e:
-		    raise service_error(service_error.internal, 
-			    "Can't write seer.conf: %s" %e)
-		seer_out = True
+	    #if not seer_out:
+		#try:
+		    #seerfn = "%s/seer.conf" % tmpdir
+		    #f = open(seerfn, "w")
+		    #if not master:
+			#print >>f, "ControlNode: control.%s.%s%s" % \
+			    #(meid.lower(), mproj.lower(), mdomain)
+		    #print >>f, "ExperimentID: %s" % mexp
+		    #f.close()
+		#except IOError, e:
+		    #raise service_error(service_error.internal, 
+			    #"Can't write seer.conf: %s" %e)
+		#seer_out = True
 
 	    if not client_out and type in ('control', 'both'):
@@ -1050,5 +1080,5 @@
 				s.get('visibility','') == 'import':
 			    client_service_out[s['name']](f, s)
-		    # Does seer need this? (evidently so)
+		    # Seer uses this?
 		    print >>f, "ExperimentID: %s/%s" % (mproj, meid)
 		    f.close()
@@ -1105,4 +1135,18 @@
 		return e.name[0] not in self.nodes
 
+	def add_kit(e, kit):
+	    """
+	    Add a Software object created from the list of (install, location)
+	    tuples passed as kit  to the software attribute of an object e.  We
+	    do this enough to break out the code, but it's kind of a hack to
+	    avoid changing the old tuple rep.
+	    """
+
+	    s = [ topdl.Software(install=i, location=l) for i, l in kit]
+
+	    if isinstance(e.software, list): e.software.extend(s)
+	    else: e.software = s 
+
+
 	t = topo.clone()
 
@@ -1149,9 +1193,9 @@
 	    if isinstance(e, topdl.Segment):
 		t.elements.remove(e)
-	    # Fix software paths
-	    for s in getattr(e, 'software', []):
-		s.location = re.sub("^.*/", softdir, s.location)
 	    if isinstance(e, topdl.Computer):
+		add_kit(e, self.federation_software)
 		if e.get_attribute('portal') and gate_cmd:
+		    # Add local portal support software
+		    add_kit(e, self.portal_software)
 		    # Portals never have a user-specified start command
 		    e.set_attribute('startup', gate_cmd)
@@ -1167,4 +1211,7 @@
 		e.interface = [i for i in e.interface \
 			if not i.get_attribute('portal') or i.name in dinf ]
+	    # Fix software paths
+	    for s in getattr(e, 'software', []):
+		s.location = re.sub("^.*/", softdir, s.location)
 
 	t.substrates = [ s.clone() for s in t.substrates ]
@@ -1368,4 +1415,9 @@
 		get_url(s, certfile, softdir)
 
+	    # Copy local portal node software to the tempdir
+	    for l, f in self.portal_software:
+		base = os.path.basename(f)
+		copy_file(f, "%s/%s" % (softdir, base))
+
 	    for a in attrs:
 		if a['attribute'] in configs:
