83445d8565e62a4fa940d945a6f33f4c0fd49917
[sfa.git] / archive / server / server.py
1 #wrapper for the registry
2
3 # Socket address
4 LISTEN_HOST = '127.0.0.1' 
5 LISTEN_PORT = 8002
6 SR_FILE = 'interface_tree_sr'
7 CR_FILE = 'interface_tree_cr'
8
9 AUTH_HOST = '127.0.0.1' 
10 AUTH_PORT = 8002
11
12 import SocketServer
13
14 import socket, os, sys
15 from M2Crypto import SSL
16 from M2Crypto.SSL import SSLError
17 from M2Crypto import X509
18 from pg import DB
19 sys.path.append('../')
20 sys.path.append('../util')
21 sys.path.append('../util/sec')
22 sys.path.append("../PLCAPI/trunk")
23 from util import *
24 from tree import *
25 from excep import *
26 from sec import *
27 from db import *
28 from pl_to_geni import *
29 import time, datetime, calendar
30
31 # Import the API Shell
32 from PLC.Shell import Shell
33 shell = Shell(globals = globals())             # Add all the API methods to the global namespace
34 ##                 ,config = options.config,     # Configuartion file (Optional. Defaluts to /etc/planetlab/plc_config)
35 ##                 url = options.url,           # XML-RPC server uirl (Optional)
36 ##                 xmlrpc = options.xmlrpc,     # Use XML-RPC ? (Optional)
37 ##                 cacert = options.cacert,     # Certificate to use (Optional)
38 ##                 method = options.method,     # API authentication method (Optional)
39 ##                 role = options.role,         # Role to assume (Optional)
40 ##                 user = options.user,         # (Optional)
41 ##                 password = options.password, # (Required if user is specified)
42 ##                 session = options.session)   # Session authentication 
43
44 class GENIServer(SSL.SSLServer):
45
46     #record is the record to be registered
47     #dbinfo is the information showing the relevant tables to act (db and table name), in the subtree this interface manages
48     def register(self, record, dbinfo):
49         cnx = dbinfo[0]
50         table = dbinfo[1] 
51         type = record['g_params']["type"]
52         
53         try:
54             #check if record already exists
55             existing_res = check_exists_geni(record, dbinfo)
56             if existing_res:
57                     raise ExistingRecord("Record "+record['g_params']['hrn']+" already exists.\n" )
58             if type == "SA" or type == 'MA':
59                 #geni parameters
60                 record['g_params']["wrapperurl"] = 'local'
61                 reg_type = ''
62                 if type == "SA":
63                     reg_type = 'slc'
64                 else:
65                     reg_type = 'comp'
66                 rights = '(2-0)(4-0)(6-0)(7-0)(8-0)(9-0)(0-1)(1-1)(2-1)(3-1)(4-1)(5-1)(6-1)(7-1)(8-1)(9-1)'
67                 rights = rights + '#0:reg:'+reg_type+":"+obtain_authority(record['g_params']["hrn"])+'#1:reg:'+reg_type+":"+record['g_params']["hrn"]
68                 record['g_params']['rights'] = rights
69                 long_hrn = record['g_params']["hrn"]
70                 hrn_suffix = get_leaf(record['g_params']["hrn"])
71                 pointer = -1
72                 login_base = ''
73                 #PL specific parameters
74                 site_fields = record['p_params']
75                 
76                 #check if the authority's site exists already
77                 other_tree = None
78                 if reg_type == 'slc':
79                     other_tree = self.cr_tree
80                 else:
81                     other_tree = self.sr_tree
82                 info = other_tree.tree_lookup(long_hrn)
83                 if info:
84                     login_base = info.login_base
85                     pointer = cnx.query("SELECT site_id FROM sites WHERE login_base = '"+login_base+"';").dictresult()[0]['site_id']
86                 else:
87                     #check if login_base is specified
88                     if site_fields.has_key('login_base'):
89                         login_base = site_fields['login_base']
90                         querystr = "SELECT * FROM sites WHERE login_base = '"+login_base+"'"
91                         res = cnx.query(querystr).dictresult()
92                         if res:
93                             return "Site login_base '"+login_base+", already exists in the system. Try another name.\n"
94                     else:
95                         #determine new login_base
96                         login_base = hrn_to_loginbase(long_hrn)
97                         for i in range(1,10):
98                             querystr = "SELECT * FROM sites WHERE login_base = '"+login_base+"'"
99                             res = cnx.query(querystr).dictresult()
100                             if not res:
101                                 break
102                             else:
103                                 login_base = hrn_to_loginbase(long_hrn, i)
104                         site_fields['login_base'] = login_base                        
105                     #add into PL table
106                     pointer = shell.AddSite(pl_auth, site_fields)
107                     
108                 #create the folder for the site and keys
109                 curdir = os.getcwd()
110                 if reg_type == 'slc':
111                     dir_type = 'slice'
112                 else:
113                     dir_type = 'component'
114                 dirname = dir_type+'/'+(long_hrn).replace('.','/')
115                 if os.path.exists(dirname):
116                     os.system('rm -rf '+dirname)
117                 os.makedirs(dirname)
118                 os.chdir(dirname)
119                 create_self_cert(hrn_suffix)
120                 os.chdir(curdir)
121                 
122                 #insert into GENI parent table  
123                 record['g_params']["hrn"] = get_leaf(record['g_params']["hrn"])
124                 record['g_params']['pubkey'] = X509.load_cert(dirname+'/'+hrn_suffix+'.cert').get_pubkey().as_pem(cipher=None)
125                 record['g_params']['pointer'] = pointer
126                 querystr = generate_querystr('INSERT', table, record['g_params'])
127                 cnx.query(querystr)
128                 
129                 #create the new table for the site
130                 new_table_name = hrn_to_tablename(long_hrn, reg_type)
131                 cnx.query('DROP TABLE IF EXISTS '+new_table_name) #drop the table if it exists
132                 querystr = "CREATE TABLE "+new_table_name+" ( \
133                 hrn text, \
134                 type text, \
135                 uuid text, \
136                 userlist text, \
137                 rights text, \
138                 description text, \
139                 pubkey text, \
140                 wrapperURL text, \
141                 disabled text, \
142                 pointer integer);"
143                 cnx.query(querystr)
144                 
145                 #update the interface tree
146                 tree = None
147                 if type == 'SA':
148                     tree = self.sr_tree
149                 else:
150                     tree = self.cr_tree
151                 parent_data = tree.tree_lookup(obtain_authority(long_hrn)).node_data
152                 parent_db_info = parent_data['db_info']
153                 parent_key_info = parent_data['key_info']
154                 info = TreeNodeInfo()
155                 info.name = long_hrn
156                 info.login_base = login_base
157                 db_info = DbInfo()
158                 key_info = KeyInfo()
159                 info.node_data = {'db_info':db_info, 'key_info':key_info}
160                 
161                 db_info.table_name = new_table_name
162                 db_info.db_name = parent_db_info.db_name
163                 db_info.address = parent_db_info.address
164                 db_info.port = parent_db_info.port
165                 db_info.user = parent_db_info.user
166                 db_info.password = parent_db_info.password
167                 
168                 key_info.acc_file = ''
169                 key_info.cred_file = ''
170                 key_info.folder = parent_key_info.folder+'/'+hrn_suffix
171                 key_info.id_file = hrn_suffix+'.cert'
172                 key_info.id_key_file = hrn_suffix+'.pkey'
173
174                 tree.tree_add(info)
175                 if type == 'SA':
176                     self.save_state('sr')
177                 else:
178                     self.save_state('cr')
179                 return type+' '+long_hrn + ' is successfully added.\n'
180             
181             elif type == "slice":
182                 login_base = get_leaf(obtain_authority(record['g_params']["hrn"]))
183                 #geni parameters
184                 #hrn is inside dictionary, passed by the client
185                 long_hrn = record['g_params']["hrn"]
186                 hrn_suffix = get_leaf(record['g_params']["hrn"])
187                 #PL specific parameters
188                 slice_fields = record['p_params']
189                 slice_fields['name'] = login_base + "_" + hrn_suffix
190                 
191                 #insert the PL tables first
192                 pointer = shell.AddSlice(pl_auth, slice_fields)
193                 #insert into the GENI tables
194                 record['g_params']["pointer"] = pointer
195                 querystr = "UPDATE "+table+" SET hrn = '"+hrn_suffix+"'"
196                 if record['g_params'].has_key('userlist'):
197                     querystr = querystr+" userlist = '"+record['g_params']['userlist']+"'"
198                 if record['g_params'].has_key('rights'):
199                     querystr = querystr+" rights = '"+record['g_params']['rights']+"'"
200                 querystr = querystr+" WHERE pointer = "+str(record['g_params']["pointer"])
201                 cnx.query(querystr)
202                 return "Slice "+long_hrn+" is successfully added.\n"
203             elif type == "user":        
204                 #geni parameters
205                 #hrn and pubkey are inside dictinary, passed by the client
206                 long_hrn = record['g_params']["hrn"]
207                 record['g_params']["hrn"] = get_leaf(record['g_params']["hrn"])
208                 rights = '(2-0)(4-0)(6-0)(7-0)(8-0)(9-0)'
209                 rights = rights + '#0:reg:slc:'+obtain_authority(record['g_params']["hrn"])
210                 record['g_params']["rights"] = rights
211                 #PL specific parameters
212                 user_fields = record['p_params']
213                 
214                 #insert the PL tables first
215                 pointer = shell.AddPerson(pl_auth, user_fields)
216                 #insert into the GENI tables
217                 record['g_params']["pointer"] = pointer
218                 querystr = generate_querystr('INSERT', table, record['g_params'])
219                 cnx.query(querystr)
220                 return "User "+long_hrn+" is successfully added.\n"
221                 
222             elif type == "node":        
223                 #geni parameters
224                 #hrn and pubkey are inside dictinary, passed by the client
225                 long_hrn = record['g_params']["hrn"]
226                 login_base = self.cr_tree.tree_lookup(obtain_authority(long_hrn)).login_base
227                 record['g_params']["hrn"] = get_leaf(record['g_params']["hrn"])
228                 rights = ''
229                 record['g_params']["rights"] = rights
230                 #PL specific parameters
231                 node_fields = record['p_params']
232                 
233                 #insert the PL tables first
234                 pointer = shell.AddNode(pl_auth, login_base, node_fields)
235         
236                 #insert into the GENI tables
237                 record['g_params']["pointer"] = pointer
238                 querystr = "UPDATE "+table+" SET hrn = '"+record['g_params']["hrn"]+"'"
239                 if record['g_params'].has_key('rights') and record['g_params']['rights'] != '':
240                     querystr = querystr+" rights = '"+record['g_params']['rights']+"'"
241                 querystr = querystr+" WHERE pointer = "+str(record['g_params']["pointer"])
242                 cnx.query(querystr)
243                 return "Node "+long_hrn+" is successfully added.\n"
244                 
245         except Exception, e:
246             print "Error in 'register():"+str(e)
247             return "Error in register:."+str(e)
248             
249     #record is the record to be updated
250     #record contains the new values of the fields to be changed in a dictionary. 
251     #precondition: the authorization mechanism should already checked the fields intended to be updated
252     #dbinfo is the information showing the relevant tables to act (db and table name), in the subtree this interface manages
253     def update(self, record, dbinfo):
254         cnx = dbinfo[0]
255         table = dbinfo[1] 
256         try:
257             #determine the type and PL pointer of the record
258             existing_res = check_exists_geni(record, dbinfo)
259             if not existing_res:
260                 raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
261             type = existing_res['type']
262             pointer = existing_res['pointer']
263             long_hrn = record['g_params']["hrn"]
264             
265             #PL update
266             if type == "SA" and pointer != -1:
267                 #check if record exists in PL
268                 pl_res = shell.GetSites(pl_auth, [pointer])
269                 if not pl_res:
270                     self.remove(record,dbinfo)
271                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
272                 #PL specific parameters
273                 site_fields = record['p_params']
274                 #update the PL tables
275                 shell.UpdateSite(pl_auth, pointer, site_fields)
276             elif type == "MA" and pointer != -1:
277                 #check if record exists in PL
278                 pl_res = shell.GetSites(pl_auth, [pointer])
279                 if not pl_res:
280                     self.remove(record,dbinfo)
281                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
282                 #PL specific parameters
283                 site_fields = record['p_params']
284                 #update the PL tables
285                 shell.UpdateSite(pl_auth, pointer, site_fields)
286             elif type == "slice":
287                 #check if record exists in PL
288                 pl_res = shell.GetSlices(pl_auth, [pointer])
289                 if not pl_res:
290                     self.remove(record,dbinfo)
291                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
292                 #PL specific parameters
293                 slice_fields = record['p_params']
294                 #update the PL tables
295                 shell.UpdateSlice(pl_auth, pointer, slice_fields)
296                 #process the new users added to the slice
297                 for user in record['g_params']['userlist']:
298                     usr_dbinfo = determine_dbinfo(get_authority(user), self.tree)
299                     if usr_dbinfo:
300                         rec = {'g_params':{'hrn':user}, 'p_params':{}}
301                         user_pointer = self.lookup(rec, usr_dbinfo)['geni']['pointer']
302                         querystr = "INSERT INTO slice_person VALUES("+pointer+", "+user_pointer+");"
303                         cnx.query(querystr)
304             elif type == "user":
305                 #check if record exists in PL
306                 pl_res = shell.GetPersons(pl_auth, [pointer])
307                 if not pl_res:
308                     self.remove(record,dbinfo)
309                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
310                 #PL specific parameters
311                 user_fields = record['p_params']
312                 #update the PL tables
313                 shell.UpdatePerson(pl_auth, pointer, user_fields)
314             elif type == "node":
315                 #check if record exists in PL
316                 pl_res = shell.GetNodes(pl_auth, [pointer])
317                 if not pl_res:
318                     self.remove(record,dbinfo)
319                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
320                 #PL specific parameters
321                 node_fields = record['p_params']
322                 #update the PL tables
323                 shell.UpdateNode(pl_auth, pointer, node_fields)
324                 
325             #geni update
326             #all fields to be updated resides in the dictionary passed by the client, we just change the hrn field
327             record['g_params']["hrn"] = get_leaf(record['g_params']["hrn"])
328             #update the GENI table
329             querystr = generate_querystr('UPDATE', table, record['g_params'])
330             cnx.query(querystr)
331             return "The record '"+long_hrn+"' is successfully updated.\n"
332         except Exception, e:
333             print "Error in 'update():'"+str(e)
334             return "Error in update:"+str(e)
335
336     #record shows the hrn to be deleted
337     #dbinfo is the information showing the relevant tables to act (db and table name), in the subtree this interface manages
338     #we enforce that the deletions of SA/MA are only at leaf
339     def remove(self, record, dbinfo):
340         cnx = dbinfo[0]
341         table = dbinfo[1] 
342         try:
343             #determine the type and PL pointer of the record
344             long_hrn = record['g_params']["hrn"]
345             hrn_suffix = get_leaf(record['g_params']["hrn"])
346             existing_res = check_exists_geni(record, dbinfo)
347             if not existing_res:
348                 raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
349             type = existing_res['type']
350             pointer = existing_res['pointer']
351             
352             #delete from the PL tables
353             if type == "SA" or type == "MA":
354                 #do not allow removal if site is not leaf
355                 tree = None
356                 if type == 'SA':
357                     tree = self.sr_tree
358                 else:
359                     tree = self.cr_tree
360                 leaf = tree.is_leaf(long_hrn)
361                 if leaf == None:
362                     return "Error in remove.\n"
363                 elif leaf == False:
364                     return "Site removal should be at the leaves.\n"
365             
366                 #update the interface tree
367                 tree.tree_remove(long_hrn)
368                 
369                 if type == 'SA':
370                     self.save_state('sr')
371                 else:
372                     self.save_state('cr')
373                 
374                 #if the site still exists in the tree, do not remove from pl, else remove
375                 if not site_to_auth(pointer):
376                     try:
377                         shell.DeleteSite(pl_auth, pointer)
378                     except:
379                         1==1  #the site may not be deleted because ttl of it expired, so should continue
380             elif type == 'user':
381                 shell.DeletePerson(pl_auth, pointer)
382             elif type == "slice":
383                 shell.DeleteSlice(pl_auth, pointer)
384             elif type == "node":
385                 shell.DeleteNode(pl_auth, pointer)
386
387             #delete from the GENI table
388             querystr = generate_querystr('DELETE', table, record['g_params'])
389             cnx.query(querystr)
390             return "The record '"+long_hrn+"' is successfully removed.\n"
391         except Exception, e:
392             print "Error in 'delete()'"+str(e)
393             return "Error in delete:"+str(e)
394
395     #record shows the hrn to be searched
396     #dbinfo is the information showing the relevant tables to act (db and table name), in the subtree this interface manages
397     def lookup(self, record, dbinfo):
398         cnx = dbinfo[0]
399         table = dbinfo[1]
400         try:
401             #lookup in GENI tables
402             existing_res = check_exists_geni(record, dbinfo)
403             if not existing_res:
404                 print "Record "+record['g_params']["hrn"]+" does not exist.\n" 
405                 raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
406             type = existing_res['type']
407             pointer = existing_res['pointer']
408             #lookup in the PL tables
409             pl_res = None
410             if type == "SA" and pointer != -1:
411                 pl_res = shell.GetSites(pl_auth, [pointer])
412                 if not pl_res:
413                     self.remove(record,dbinfo)
414                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
415                 pl_res = pl_res[0]
416             elif type == "MA" and pointer != -1:
417                 pl_res = shell.GetSites(pl_auth, [pointer])
418                 if not pl_res:
419                     self.remove(record,dbinfo)
420                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
421                 pl_res = pl_res[0]
422             elif type == "slice":
423                 pl_res = shell.GetSlices(pl_auth, [pointer])
424                 if not pl_res:
425                     self.remove(record,dbinfo)
426                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
427                 pl_res = pl_res[0]
428             elif type == "user":
429                 pl_res = shell.GetPersons(pl_auth, [pointer])
430                 if not pl_res:
431                     self.remove(record,dbinfo)
432                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
433                 pl_res = pl_res[0]
434             elif type == "node":
435                 pl_res = shell.GetNodes(pl_auth, [pointer])
436                 if not pl_res:
437                     self.remove(record,dbinfo)
438                     raise NonexistingRecord("Record "+record['g_params']["hrn"]+" does not exist.\n" )
439                 pl_res = pl_res[0]
440             return str({'pl':pl_res, 'geni':existing_res})
441         except Exception, e:
442             print "Lookup returned exception", e
443             return None
444             
445
446     def list(self, record, dbinfo):
447         x=1
448         
449     #grants the credentials existing in database to the caller
450     #peer parameter shows the caller information
451     #record keeps the parameter: credential name
452     #dbinfo is the information showing the relevant tables to act (db and table name), in the subtree this interface manages
453     #keyinfo is the id, id_key, and accounting data for the authority
454     #peerinfo is [peer_hrn, peer_certficate]
455     def getCredential(self, record, dbinfo, keyinfo, peerinfo):
456         cnx = dbinfo[0]
457         table = dbinfo[1] 
458         try:
459             cred_pem = None
460             if record['g_params']['cred_name'].split(':')[0] == 'registry':
461                 #lookup in GENI tables
462                 geni_res = cnx.query("SELECT * FROM "+table+" WHERE hrn = '"+get_leaf(peerinfo[0])+"' ").dictresult()
463                 if geni_res:
464                     geni_res = geni_res[0]
465                 else:
466                     raise NonexistingRecord("Record "+peerinfo[0]+" does not exist.\n" )
467                 type = geni_res['type']
468                 pointer = geni_res['pointer']
469                 rights = geni_res['rights']
470                 #lookup in the PL tables
471                 pl_res = None
472                 if type == "SA" and pointer != -1:
473                     pl_res = shell.GetSites(pl_auth, [pointer])
474                     if not pl_res:
475                         self.remove(record,dbinfo)
476                         raise NonexistingRecord("Record "+peerinfo[0]+" does not exist.\n" )
477                 elif type == "MA" and pointer != -1:
478                     pl_res = shell.GetSites(pl_auth, [pointer])
479                     if not pl_res:
480                         self.remove(record,dbinfo)
481                         raise NonexistingRecord("Record "+peerinfo[0]+" does not exist.\n" )
482                 elif type == "user":
483                     pl_res = shell.GetPersons(pl_auth, [pointer])
484                     if not pl_res:
485                         self.remove(record,dbinfo)
486                         raise NonexistingRecord("Record "+peerinfo[0]+" does not exist.\n" )
487                     pl_res = shell.GetPersons(pl_auth, [pointer])[0]
488                     if rights == '' or rights == None:
489                         if 'admin' in pl_res['roles']:
490                             rights = '(0-0)(1-0)(2-0)(3-0)(4-0)(5-0)(6-0)(7-0)(8-0)(9-0)'+ \
491                                         '(0-1)(1-1)(2-1)(3-1)(4-1)(5-1)(6-1)(7-1)(8-1)(9-1)'
492                             rights = rights + '#0:reg:slc:'+ROOT_AUTH + '#1:reg:comp:'+ROOT_AUTH
493                         elif 'pi' in pl_res['roles']:
494                             rights = '(0-0)(1-0)(2-0)(3-0)(4-0)(5-0)(6-0)(7-0)(8-0)(9-0)'+\
495                                         '(0-1)(1-1)(2-1)(3-1)(4-1)(5-1)(6-1)(7-1)(8-1)(9-1)'
496                             rights = rights + '#0:reg:slc:'+obtain_authority(peerinfo[0]) + '#1:reg:comp:'+obtain_authority(peerinfo[0])
497                         elif 'user' in pl_res['roles']:
498                             rights = '(2-0)(4-0)(6-0)(7-0)(8-0)(9-0)'
499                             rights = rights + '#0:reg:slc:'+obtain_authority(peerinfo[0])
500                 elif type == "node":
501                     pl_res = shell.GetNodes(pl_auth, [pointer])
502                     if not pl_res:
503                         self.remove(record,dbinfo)
504                         raise NonexistingRecord("Record "+peerinfo[0]+" does not exist.\n" )
505                 #authcert, authkey, pubkey, cname, rights, time
506                 cname = 'Registry credentials'
507                 openssl_cert = peerinfo[1]
508                 cred_pem = create_cred(keyinfo[0], keyinfo[1], openssl_cert.get_pubkey(), cname, rights)
509             else:
510                 cred_name = record['g_params']['cred_name'].split(':')
511                 if cred_name[0] == 'slice':
512                     slc_rec = {'g_params':{'hrn':cred_name[1]}, 'p_params':{}}
513                     slc_result = self.lookup(slc_rec, dbinfo)
514                     slc_result = eval(slc_result)
515                     has_slc = False
516                     if slc_result:
517                         usr_dbinfo = determine_dbinfo(obtain_authority(peerinfo[0]), self.sr_tree)
518                         if usr_dbinfo:
519                             rec = {'g_params':{'hrn':peerinfo[0]}, 'p_params':{}}
520                             user_pointer = eval(self.lookup(rec, usr_dbinfo))['geni']['pointer']
521                             # XXX SMBAKER: person_slice doesn't exist -- fix this to use shell/plc_api
522                             #              need to see if slice belongs to person
523                             has_slc = True
524                             #querystr = "SELECT * FROM person_slice WHERE person_id = "+user_pointer+" AND slice_id = "+slc_result['geni']['pointer']
525                             #usr_slc_res = cnx.query(querystr).dictresult()
526                             #if usr_slc_res:
527                             #    has_slc = True
528                         if has_slc:
529                             rights = ''
530                             if slc_result['geni']['rights'] != '' and slc_result['geni']['rights'] != None:
531                                 rights = slc_result['geni']['rights']
532                             else:
533                                 rights = '(10-0)(11-0)(12-0)(13-0)(14-0)(15-0)(16-0)(17-0)(18-0)(20-0)(21-0)(22-0)(23-0)'
534                                 rights = rights + '#0:comp:planetlab.*'
535                             #authcert, authkey, pubkey, cname, rights, time
536                             # XXX SMBAKER: need to compute expiration time here and apply
537                             #              it to the credential
538                             cname = slc_result['geni']['hrn']
539                             openssl_cert = peerinfo[1]
540                             cred_pem = create_cred(keyinfo[0], keyinfo[1], openssl_cert.get_pubkey(), cname, rights)
541                 else:
542                     raise NonexistingCredType("Credential "+cred_name[0]+" does not exist.\n" )
543             if cred_pem == None:
544                 return cred_pem
545             else:
546                 return crypto.dump_certificate(crypto.FILETYPE_PEM, cred_pem)+keyinfo[3]
547         except Exception, e:
548             print "getCredential return exception:", e
549             return None
550
551
552     #returns the existing acconting information in database to the caller
553     #peer parameter shows the caller certificate, containing the public key
554     #record keeps the parameter: account_name to ask for
555     #dbinfo is the information showing the relevant tables to act (db and table name), in the subtree this interface manages
556     #keyinfo is the id, id_key, and accounting data for the authority
557     #peer_cert is the ssl certificate of the peer
558     def getAccounting(self, record, dbinfo, keyinfo, peer_cert):
559         cnx = dbinfo[0]
560         table = dbinfo[1]
561         try:
562             acc = None
563             #check if the record exists
564             rec = {'g_params':{'hrn':record['g_params']['account_name']}, 'p_params':{}}
565             res = eval(self.lookup(rec, dbinfo))
566             if not res:
567                 print "Record "+record['g_params']["account_name"]+" does not exist."
568                 raise NonexistingRecord("Record "+record['g_params']["account_name"]+" does not exist.\n" )
569             if not res['geni']['pubkey']:
570                 print "Record "+record['g_params']["account_name"]+" missing public key."
571                 # XXX SMBAKER: raise exception here
572             if res['geni']['pubkey'] == peer_cert.get_pubkey().as_pem(cipher=None):
573                 openssl_cert = crypto.load_certificate(crypto.FILETYPE_PEM, peer_cert.as_pem())
574                 uuid = 0
575                 if not res['pl']:
576                     uuid = res['geni']['uuid']
577                 else:
578                     uuid = res['pl']['uuid']
579                 acc = create_acc(keyinfo[0], keyinfo[1], openssl_cert.get_pubkey(), record['g_params']['account_name'], uuid)
580             if acc == None:
581                 return acc
582             else:
583                 return crypto.dump_certificate(crypto.FILETYPE_PEM, acc)+keyinfo[2]
584         except Exception, e:
585             print "getAccounting returned exception: ", e
586             return None
587
588     def __init__(self, socket, handler):
589         #initialize trees
590         self.sr_tree_file = SR_FILE
591         self.cr_tree_file = CR_FILE
592         self.sr_tree = None
593         self.cr_tree = None
594         self.construct_hierarchy()
595         set_tree_globals(self.sr_tree, self.cr_tree)
596         #initialize security module
597         self.sec = None
598         self.sec_init()
599         #set function list
600         self.functionList = {"register":self.register, "remove":self.remove, "update":self.update, "lookup":self.lookup, "list":self.list, "getCredential":self.getCredential, "getAccounting":self.getAccounting}
601         SSL.SSLServer.__init__(self, socket, handler, self.sec.ctx)
602     
603     def construct_hierarchy(self):
604         self.sr_tree = InterfaceTree('slice', self.sr_tree_file, (AUTH_HOST, AUTH_PORT)) #slice registry interface tree
605         self.cr_tree = InterfaceTree('component', self.cr_tree_file, (AUTH_HOST, AUTH_PORT)) #component registry interface tree
606     
607     def sec_init(self):
608         key_info = self.sr_tree.my_tree.info.node_data['key_info']
609         id_file = key_info.folder+'/'+key_info.id_file
610         id_key_file = key_info.folder+'/'+key_info.id_key_file
611         acc_file = key_info.folder+'/'+key_info.acc_file
612         cred_file = key_info.folder+'/'+key_info.cred_file
613             
614         self.sec = Sec('server', id_file, id_key_file, acc_file, cred_file) 
615         renew_cert('accounting', key_info.folder, 'slice', self.sr_tree.my_tree.info.name, None, None, (AUTH_HOST, AUTH_PORT), self.sec)
616         renew_cert('credential', key_info.folder, 'slice', self.sr_tree.my_tree.info.name, None, None, (AUTH_HOST, AUTH_PORT), self.sec)
617         
618     #save the state of the interface trees
619     def save_state(self, type='both'):
620         if type == 'sr' or type == 'both' :
621             self.sr_tree.save_tree()
622         if type == 'cr' or type == 'both' :
623             self.cr_tree.save_tree()
624
625 class handle_connection(SocketServer.BaseRequestHandler):
626     def handle(self):
627 ##        pid = os.fork()
628 ##        if pid:
629 ##            # parent process closes connnection and returns
630 ##            self.request.socket.close()
631 ##            return
632 ##        else:
633         try:
634             peer = server.sec.auth_protocol(self.request)
635             if not peer:
636                 return
637             
638             operation_request = msg_to_params(self.request.read())
639             #determine the database information associated with the hrn of the call
640             hrn_of_call = operation_request["g_params"]["hrn"]
641             opname = operation_request["opname"]
642             target_hrn = ''
643             if opname == "register" or opname == "remove" or opname == "update" or opname == "lookup":
644                 target_hrn = obtain_authority(hrn_of_call)
645             elif opname == 'list' or opname == 'getCredential' or opname == 'getAccounting':
646                 target_hrn = hrn_of_call 
647             reg_type = ''
648             if opname == "register" or opname == "remove" or opname == "update" or opname == "lookup" or opname == 'list':
649                 type = operation_request["g_params"]["type"]
650                 if type == 'slice' or type == 'user' or type == 'SA':
651                     reg_type = 'slice'
652                 else:
653                     reg_type = 'component'
654             elif opname == 'getCredential':
655                 # XXX SMBAKER- support for getCredential slice:hrn.of.slice
656                 if operation_request["g_params"]["cred_name"].split(':')[0] == 'slice':
657                     reg_type = 'slice'
658                 elif operation_request["g_params"]["cred_name"].split(':')[1] == 'slc':
659                     reg_type = 'slice'
660                 else:
661                     reg_type = 'component'
662             elif opname == 'getAccounting':
663                 reg_type = operation_request["g_params"]["registry"]
664             tree = None
665             if reg_type == 'slice':
666                 tree = server.sr_tree
667             else:
668                 tree = server.cr_tree    
669             dbinfo = determine_dbinfo(target_hrn, tree)
670             keyinfo = None
671             if opname == 'getAccounting':
672                 keyinfo = tree.determine_keyinfo(target_hrn, server, 'accounting')
673             elif opname == 'getCredential':
674                 keyinfo = tree.determine_keyinfo(target_hrn, server, 'credential')
675             if (dbinfo == None):
676                 self.request.write("WRONG INTERFACE")
677                 return
678             # check to see if a matching function has been registered
679             if not server.functionList.has_key(operation_request['opname']): 
680                 self.request.write("NO FUNC")
681                 return
682             #check the authorization of the peer
683             if not server.sec.check_authorization(peer.acc, peer.cred, operation_request):
684                 self.request.write("AUTHORIZATION FAIL")
685                 return
686         
687             #perform the function call
688             op = server.functionList[operation_request["opname"]]
689             params = {'g_params':operation_request["g_params"], 'p_params':operation_request["p_params"]} 
690             result = None
691             if op == server.getAccounting:
692                 result = op(params,dbinfo, keyinfo, peer.cert)
693             elif op == server.getCredential:
694                 peerinfo = [peer.acc.get_hrn(), crypto.load_certificate(crypto.FILETYPE_PEM, peer.cert.as_pem())]
695                 result = op(params,dbinfo, keyinfo, peerinfo)
696             elif op == server.register or op == server.update or op == server.remove:
697                 result = str({'message':op(params,dbinfo)})
698             else:
699                 result = op(params,dbinfo)
700                 if not result: 
701                     self.request.write(str({'message':'Requested record does not exist.\n'}))
702             self.request.write(result)
703             return
704         except Exception, e:
705             print "There is an error handling the request. "+str(e)
706             return
707
708 #child process never executes this function, because it exits in "handle_connection".
709 ##    def finish(self):
710 ##        server.save_state()
711     
712 server = GENIServer((LISTEN_HOST, LISTEN_PORT), handle_connection)
713 def main():
714     server.save_state()
715     server.serve_forever()   
716
717
718 if __name__=="__main__":
719     main()
720