GeniCH.pm.in 32.5 KB
Newer Older
1
#!/usr/bin/perl -wT
2
#
3
# GENIPUBLIC-COPYRIGHT
4
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
5
6
# All rights reserved.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
7
package GeniCH;
8

Leigh B. Stoller's avatar
Leigh B. Stoller committed
9
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
10
# The server side of the Geni ClearingHouse API. 
Leigh B. Stoller's avatar
Leigh B. Stoller committed
11
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
12
13
14
use strict;
use Exporter;
use vars qw(@ISA @EXPORT);
15

Leigh B. Stoller's avatar
Leigh B. Stoller committed
16
17
@ISA    = "Exporter";
@EXPORT = qw ( );
18

19
#use Devel::TraceUse;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
20
use GeniDB;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
21
use Genixmlrpc;
22
use GeniSlice;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
23
use GeniResponse;
24
use GeniUser;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
25
use GeniComponent;
26
use GeniHRN;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
27
use GeniAuthority;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
28
use emutil;
29
use libtestbed qw(SENDMAIL);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
30
31
use English;
use Data::Dumper;
32
33
use Date::Parse;
use Time::Local;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
34
35
36
37
38
39
40
41

# Configure variables
my $TB		   = "@prefix@";
my $TBOPS          = "@TBOPSEMAIL@";
my $TBAPPROVAL     = "@TBAPPROVALEMAIL@";
my $TBAUDIT   	   = "@TBAUDITEMAIL@";
my $BOSSNODE       = "@BOSSNODE@";
my $OURDOMAIN      = "@OURDOMAIN@";
42
my $SLICESHUTDOWN  = "$TB/sbin/protogeni/shutdownslice";
43

44
45
my $API_VERSION = 1;

Leigh B Stoller's avatar
Leigh B Stoller committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#
# This is for Flack. 
#
sub WhoAmI($)
{
    my $caller_urn = $ENV{'GENIURN'};
    my $caller_gid = $ENV{'SSL_CLIENT_CERT'};
    my $sa_urn;
    my $sa_url;

    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
				"Malformed URN ")
	if (!GeniHRN::IsValid($caller_urn));
    
    # Convert the caller URN to an SA urn.
    my ($auth, $type, $id) = GeniHRN::Parse($caller_urn);
    $sa_urn = GeniHRN::Generate($auth, "authority", "sa");

    my $authority = GeniAuthority->Lookup($sa_urn);
    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				"No such slice authority $sa_urn")
	if (!defined($authority));
    $sa_url = $authority->url();

    my $blob = {
	"urn"    => $caller_urn,
	"sa_urn" => $sa_urn,
	"sa_url" => $sa_url,
    };
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);    
}

78
79
80
81
82
83
84
#
# Tell the client what API revision we support.  The correspondence
# between revision numbers and API features is to be specified elsewhere.
# No credentials are required.
#
sub GetVersion()
{
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    my $me = GeniAuthority->Lookup($ENV{'MYURN'});
    if (!defined($me)) {
	print STDERR "Could not find local authority object\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
    my $commithash = VersionInfo("commithash") || "";
    my @authorities = ();
    my %peers = ();

    if (GeniAuthority->ListAll(\@authorities) != 0) {
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
    foreach my $authority (@authorities) {
	next
	    if ($authority->type() ne "cm");
	$peers{$authority->urn()} = $authority->url();
    }
    my $blob = {
	"peers"      => \%peers,
	"api"        => $API_VERSION,
	"urn"        => $me->urn(),
	"hrn"        => $me->hrn(),
	"url"        => $me->url(),
	"interface"  => "registry",
	"code_tag"   => $commithash,
	# XXX
	"hostname"   => "www." . $OURDOMAIN,
    };
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
114
115
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
116
#
117
118
119
120
# Get a credential to use the ClearingHouse. For the moment, the initial
# credential will be provided to callers with the proper certificate, which
# means just SAs/CMs that we know about via the ssl certificate used to
# connect to us.
121
#
122
sub GetCredential($)
123
{
Leigh B. Stoller's avatar
Leigh B. Stoller committed
124
    my ($argref) = @_;
125
126
    my $cred = $argref->{'credential'};
    my $type = $argref->{'type'};
127
    my $gid  = $argref->{'gid'} || $argref->{'cert'};
128

129
130
131
132
    #
    # The caller has to be known to us, but how are they known to us?
    # Probably need a web interface? 
    #
133
    my $caller_authority = GeniAuthority->Lookup($ENV{'GENIURN'});
Leigh B. Stoller's avatar
Leigh B. Stoller committed
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
    if (!defined($caller_authority)) {
        if (!defined($gid)) {
	    return GeniResponse->Create(GENIRESPONSE_REFUSED,
					undef, "Who are You?");
	}
	#
	# Must be a new site. We could not have gotten this far without
	# their CA certificate being know to us, so lets just register them
	# and tell tbops about it.
	#
	if (! ($gid =~ /^[\012\015\040-\176]*$/)) {
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					"cert: Invalid characters");
	}
	my $certificate = GeniCertificate->LoadFromString($gid);
	return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				    "Could not parse certificate")
	    if (!defined($certificate));

	if (! ($certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
					"Improper format for uuid");
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
157
	if (! ($certificate->hrn() =~ /^[-\w\.]+$/)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
158
159
160
161
162
163
164
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
					"Improper format for hrn");
	}
	my $url = $certificate->URL();
	return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				    "Could not find URL in the certificate")
	    if (!defined($url));
165
	
166
167
168
	if ($certificate->hrn() =~ /^unknown/i) {
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
					"Please define PROTOGENI_DOMAIN");
169
170
171
172
173
174
175
176
177
178
	}	

	my $urn = $certificate->urn();
	return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				    "Could not find URN in the certificate")
	    if (!defined($urn));
	return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
				    "Malformed URN in the certificate")
	    if (!GeniHRN::IsValid($urn));
	my ($auth, $type, $id) = GeniHRN::Parse($urn);
179
180
181
182
183
184
185
186
	
	return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
				    "Not an authority certificate")
	    if ($type ne "authority");
	return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
				    "Not an am/cm/sa/ses certificate")
	    if (! ($id =~ /^(am|cm|ses|sa)$/i));
	
Leigh B. Stoller's avatar
Leigh B. Stoller committed
187
188
189
	#
	# Check for an existing authority. 
	#
190
	if (GeniAuthority->CheckExisting($certificate) != 0) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
191
192
	    print STDERR "Attempt to register existing slice authority\n";
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
193
					"Authority already exists");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
194
195
196
197
198
	}

	SENDMAIL($TBOPS, "New ProtoGeni Authority",
		 $certificate->asText());

199
	$caller_authority = GeniAuthority->Create($certificate, $url, $id);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
200
	if (!defined($caller_authority)) {
201
	    print STDERR "Could not create new authority\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
202
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
203
					"Could not create new authority");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
204
205
	}
    }
206
207
208
209
210
211
212
213
214
    
    #
    # No credential, then return a generic credential giving caller permission
    # to do other things.
    #
    if (!defined($cred)) {
	#
	# This credential is for access to this authority.
	#
215
	my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
216
217
	if (!defined($authority)) {
	    print STDERR "Could not find local authority object\n";
218
219
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					"Who are you?");
220
	}
221
222
223
224
225
226
227
228
229
230
231
232
233
234
	my $credential = GeniCredential->Create($authority, $caller_authority);
	if (!defined($credential)) {
	    print STDERR "Could not create credential for $caller_authority\n";
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
	#
	# We want this credential to be valid for a long time;
	#
	$credential->SetExpiration(time() + 24 * 60 * 60 * 120);
	
	if ($credential->Sign($GeniCredential::LOCALMA_FLAG) != 0) {
	    $credential->Delete();
	    print STDERR "Could not sign credential for $caller_authority\n";
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
235
				    "Could not create signed credential")
236
	}
237
238
	return GeniResponse->Create(GENIRESPONSE_SUCCESS,
				    $credential->asString());
239
240
    }

241
242
243
244
245
    #
    # User provided a credential, and wants a new credential to access
    # the object referenced by the uuid.
    #
    return GeniResponse->Create(GENIRESPONSE_UNSUPPORTED);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
246
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
247

248
249
250
251
252
##
# Lookup a UUID and return a blob of stuff. We allow lookups of both
# users and slices, which is what we allow clients to register.
#
sub Resolve($)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
253
254
{
    my ($argref) = @_;
255
    my $cred = $argref->{'credential'};
Leigh B. Stoller's avatar
Leigh B. Stoller committed
256
    my $uuid = $argref->{'uuid'};
257
    my $hrn  = $argref->{'hrn'};
258
    my $urn  = $argref->{'urn'};
259
    my $type = $argref->{'type'};
Leigh B. Stoller's avatar
Leigh B. Stoller committed
260

261
    if (! (defined($uuid) || defined($hrn) || defined($urn))) {
262
263
	return GeniResponse->MalformedArgsResponse();
    }
264
265
    # URN always takes precedence and all items at the clearinghouse
    # now have URNs in their certificates. 
266
    if (defined($urn)) {
267
268
269
270
271
272
273
274
275
276
277
	return GeniResponse->MalformedArgsResponse()
	    if (!GeniHRN::IsValid($urn));
	$hrn = $uuid = undef;
    }
    elsif (defined($uuid) && GeniHRN::IsValid($uuid)) {
	$urn  = $uuid;
	$uuid = $hrn = undef;
    }
    elsif (defined($hrn) && GeniHRN::IsValid($hrn)) {
	$urn = $hrn;
	$hrn = $uuid = undef;
278
    }
279
    elsif (defined($uuid) && !($uuid =~ /^[-\w]*$/)) {
280
281
	return GeniResponse->MalformedArgsResponse();
    }
282
    elsif (defined($hrn) && !($hrn =~ /^[-\w\.]*$/)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
283
284
	return GeniResponse->MalformedArgsResponse();
    }
285
286
    if (! (defined($type) &&
	   ($type =~ /^(SA|AM|CM|MA|Component|Slice|User)$/i))){
287
	return GeniResponse->MalformedArgsResponse();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
288
    }
289
    $type = lc($type);
290
    my $lookup_token = ($urn || $uuid || $hrn);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
291

292
    my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
293
294
295
296
    if (!defined($authority)) {
	print STDERR "Could not find local authority object\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
297
298
299
300
301
302
303
304
305
306
307
308
309

    #
    # We allow any valid user without a credential, to resolve
    # authorities. Helpful for Flack. 
    #
    if (! defined($cred) &&
	! ($type eq "cm" || $type eq "am" || $type eq "sa")) {
	return GeniResponse->MalformedArgsResponse();
    }
    else {
	my $credential = CheckCredential($cred, $authority);
	return $credential
	    if (GeniResponse::IsResponse($credential));
310
   
311
312
313
314
315
	$credential->HasPrivilege( "authority" ) or
	    $credential->HasPrivilege( "resolve" ) or
	    return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
					 "Insufficient privilege" );
    }
316

317
318
    if ($type eq "user") {
	my $user = GeniUser->Lookup($lookup_token);
319
320
	if (!defined($user)) {
	    return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
321
					"No such user $lookup_token");
322
323
324
325
326
	}

	# Return a blob.
	my $blob = { "uid"      => $user->uid(),
		     "hrn"      => $user->hrn(),
327
		     "urn"      => $user->urn() || '',
328
329
		     "uuid"     => $user->uuid(),
		     "email"    => $user->email(),
Leigh B. Stoller's avatar
Leigh B. Stoller committed
330
		     "gid"      => $user->cert(),
331
332
333
334
		     "name"     => $user->name(),
		 };
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
    }
335
336
    if ($type eq "component") {
	my $component = GeniComponent->Lookup($lookup_token);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
337
338
339
	
	if (!defined($component)) {
	    return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
340
					"No such component $lookup_token");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
341
	}
Leigh B Stoller's avatar
Leigh B Stoller committed
342
	my $manager = $component->GetManager();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
343
344

	# Return a blob.
Leigh B Stoller's avatar
Leigh B Stoller committed
345
346
	my $blob = { "gid"         => $component->cert(),
		     "url"         => $component->url(),
347
		     "urn"         => $component->urn(),
Leigh B Stoller's avatar
Leigh B Stoller committed
348
		     "manager_gid" => $manager->cert(),
Leigh B. Stoller's avatar
Leigh B. Stoller committed
349
350
351
352
		 };
    
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
    }
353
    if ($type eq "cm" || $type eq "am" || $type eq "sa") {
354
	my $manager = GeniAuthority->Lookup($lookup_token);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
355
	if (!defined($manager)) {
356
	    return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
357
					"No such manager $lookup_token");
358
359
	}
	# Return a blob.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
360
361
	my $blob = { "gid"         => $manager->cert(),
		     "url"         => $manager->url(),
362
		     "urn"         => $manager->urn(),
363
		     "type"        => $manager->type(),
364
365
366
		 };
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
    }
367
    if ($type eq "ma") {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
368
369
370
371
372
373
	#
	# I think the MA is the ClearingHouse?
	#
	# Return a blob.
	my $blob = { "gid"         => $authority->cert(),
		     "url"         => $authority->url(),
374
		     "urn"         => $authority->urn(),
375
		     "type"        => $authority->type(),
Leigh B. Stoller's avatar
Leigh B. Stoller committed
376
377
378
		 };
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
    }
379
    if ($type eq "slice") {
380
	my $slice = GeniSlice->Lookup($lookup_token);
381
382
	if (!defined($slice)) {
	    return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
383
					"No such slice $lookup_token");
384
385
386
387
	}

	# Return a blob.
	my $blob = { "hrn"          => $slice->hrn(),
388
		     "urn"          => $slice->urn() || '',
389
390
		     "uuid"         => $slice->uuid(),
		     "creator_uuid" => $slice->creator_uuid(),
391
		     "creator_urn"  => $slice->creator_urn() || '',
Leigh B. Stoller's avatar
Leigh B. Stoller committed
392
		     "gid"          => $slice->cert(),
393
394
395
396
		 };
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
    }
    return GeniResponse->Create(GENIRESPONSE_UNSUPPORTED);
397
398
}

399
400
##
# Register a new object.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
401
#
402
sub Register($)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
403
{
Leigh B. Stoller's avatar
Leigh B. Stoller committed
404
    my ($argref) = @_;
405
    my $cred  = $argref->{'credential'};
406
    my $cert  = $argref->{'gid'} || $argref->{'cert'};
407
408
    my $info  = $argref->{'info'};
    my $type  = $argref->{'type'};
Leigh B. Stoller's avatar
Leigh B. Stoller committed
409

410
    if (! (defined($type) &&
411
	   ($type =~ /^(SA|MA|AM|CM|SES|Component|Slice|User)$/i))){
412
	return GeniResponse->MalformedArgsResponse();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
413
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
414
    $type = lc($type);
415
416
    if (! defined($cred)) {
	return GeniResponse->MalformedArgsResponse();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
417
    }
418
419
    if (! defined($cert)) {
	return GeniResponse->MalformedArgsResponse();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
420
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
421
    if (! ($cert =~ /^[\012\015\040-\176]*$/)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
422
	return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
Leigh B. Stoller's avatar
Leigh B. Stoller committed
423
				    "cert: Invalid characters");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
424
    }
425
426
427
428
    if (! defined($info)) {
	return GeniResponse->MalformedArgsResponse();
    }

429
    my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
430
431
432
    if (!defined($authority)) {
	print STDERR "Could not find local authority object\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
433
    }
434
435
436
437
    my $credential = CheckCredential($cred, $authority);
    return $credential
	if (GeniResponse::IsResponse($credential));
   
438
439
440
441
442
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "refresh" ) or
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );

Leigh B. Stoller's avatar
Leigh B. Stoller committed
443
    #
444
    # Grab the uuid and hrn out of the certificate.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
445
    #
446
447
448
449
    my $certificate = GeniCertificate->LoadFromString($cert);
    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				"Could not parse certificate")
	if (!defined($certificate));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
450

451
    if (! ($certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
452
453
	return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
				    "Improper format for uuid");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
454
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
455
    if (! ($certificate->hrn() =~ /^[-\w\.]+$/)) {
456
457
458
	return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
				    "Improper format for hrn");
    }
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
    if (! (defined($certificate->urn()) &&
	   GeniHRN::IsValid($certificate->urn()))) {
	my $email = ($type eq "user" ?
		     $info->{'email'} : $certificate->email());

	#
	# This will go away when all users updated.
	#
	if (defined($email) &&
	    TBcheck_dbslot($email, "users", "usr_email",
			   TBDB_CHECKDBSLOT_ERROR)) {
	    print STDERR "Sending mail to $email about missing URN\n";
		
	    SENDMAIL($email, "ProtoGENI Registration Error",
		     "Your user certificate is out of date! \n".
		     "Please login to your home Emulab and generate\n".
		     "a new encrypted SSL certificate.\n",
		     $TBOPS, "BCC: protogeni-errors\@flux.utah.edu");
	}
	return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
	    "Improper or missing URN in certificate; Please regenerate");
    }
481
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
482
    if ($type eq "user") {
483
484
	my $name    = $info->{'name'};
	my $email   = $info->{'email'};
485
486
487
488
489
490
491
492
493
494
495
496

	if (! TBcheck_dbslot($name, "users", "usr_name",
			     TBDB_CHECKDBSLOT_ERROR)) {
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					"name: ". TBFieldErrorString());
	}
	if (! TBcheck_dbslot($email, "users", "usr_email",
			     TBDB_CHECKDBSLOT_ERROR)){
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					"email: ". TBFieldErrorString());
	}
	#
497
	# Need to verify the caller is authorized.
498
	#
499
	my $slice_authority = GeniAuthority->Lookup($ENV{'GENIURN'});
Leigh B. Stoller's avatar
Leigh B. Stoller committed
500
501
502
503
	if (!defined($slice_authority)) {
	    print STDERR "Could not find authority object for caller.\n";
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
504
	if (! $slice_authority->CheckValidIssuer($certificate)) {
505
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
506
					"Certificate issuer is not valid ");
507
508
	}

509
	my $existing = GeniUser->Lookup($certificate->urn());
510
	if (defined($existing)) {
511
	    if ($existing->hrn() ne $certificate->hrn()) {
512
513
514
515
		return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					    "Not allowed to change hrn");
	    }
	    #
516
	    # Update operation, but only name, email
517
	    #
518
	    if ($existing->Modify($name, $email) != 0) {
519
520
521
522
523
		return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					    "Could not update user");
	    }
	    return GeniResponse->Create(GENIRESPONSE_SUCCESS);
	}
524
	#
525
526
	# Temporary: Look for existing user with same uuid but no urn.
	# We want to store the new certificate since it has a urn.
527
	#
528
529
530
531
532
533
534
535
536
	$existing = GeniUser->Lookup($certificate->uuid());
	if ($existing) {
	    if ($certificate->Store()) {
		return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					    "could not update certificate");
	    }
	    return GeniResponse->Create(GENIRESPONSE_SUCCESS);
	}
	
537
	#
538
539
540
	# A conflict is another user with the same hrn or email.
	#
	if (GeniUser->CheckConflict($certificate)) {
541
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
542
					"user already registered");
543
	}
544
	my $newuser = GeniUser->Create($certificate, $slice_authority, $info);
545
546
	if (!defined($newuser)) {
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
547
					"Could not be registered");
548
549
	}
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, undef,
550
				    "User has been registered");
551
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
552
    if ($type eq "slice") {
553
	my $creator_token  = $info->{'creator_uuid'} || $info->{'creator_urn'};
554
555
	my $slice_expires  = $info->{'valid_until'}  || $info->{'expiration'};

556
	if (!defined($creator_token)) {
557
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
558
					"Who is the creator of this slice?");
559
560
561
562
	}
	#
	# Make sure the geni user exists. 	
	#
563
	my $user = GeniUser->Lookup($creator_token);
564
565
	if (!defined($user)) {
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
566
					"No such user: $creator_token");
567
	}
568

569
	#
570
	# Need to verify the caller is allowed to register the run.
571
	#
572
	my $slice_authority = GeniAuthority->Lookup($ENV{'GENIURN'});
Leigh B. Stoller's avatar
Leigh B. Stoller committed
573
574
575
576
	if (!defined($slice_authority)) {
	    print STDERR "Could not find authority object for caller.\n";
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
577
	if (! $slice_authority->CheckValidIssuer($certificate)) {
578
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
579
					"Certificate issuer is not valid ");
580
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
581

582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
	#
	# Set the expiration; we age these out in the ch_daemon.
	#
	if (defined($slice_expires)) {
	    # Convert slice expiration to a time.
	    my $slice_when = str2time($slice_expires);
	    if (!defined($slice_when)) {
		return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
				    "Could not parse slice expiration");
	    }
	    if ($slice_when < time()) {
		return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
					    "Expiration is in the past");
	    }
	    $slice_expires = $slice_when;
	}
	else {
	    #
	    # Default to 30 days until all CMs updated. We will get a new
	    # expiration if the slice is renewed.
	    #
	    $slice_expires = time() + (30 * 24 * 3600);
	}

606
607
608
	#
	# Reregistration of existing slice is okay.
	#
609
	my $existing = GeniSlice->Lookup($certificate->urn());
610
	if (defined($existing)) {
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
	    #
	    # Same slice URN but a different certificate. Delete and
	    # continue with the registration.
	    #
	    if ($certificate->uuid() ne $existing->uuid()) {
		if ($existing->Delete()) {
		    print STDERR "Could not delete $existing!\n";
		    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				"$existing could not be unregistered");
		}
	    }
	    else {
		if (defined($slice_expires) &&
		    $existing->SetExpiration($slice_expires) != 0) {
		    print STDERR
			"Could not update expiration for $existing ".
			"to $slice_expires\n";
		}
		return GeniResponse->Create(GENIRESPONSE_SUCCESS);
	    }
631
632
633
634
635
636
637
638
	}
	#
	# Temporary: Look for existing slice with same uuid but no urn.
	# We want to store the new certificate since it has a urn.
	#
	$existing = GeniSlice->Lookup($certificate->uuid());
	if ($existing) {
	    if ($certificate->Store()) {
639
		return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
640
					    "could not update certificate");
641
642
643
	    }
	    return GeniResponse->Create(GENIRESPONSE_SUCCESS);
	}
644
	#
645
	# Temporary: How long are HRNs going to be around?
646
	#
647
648
	if (defined($certificate->hrn())) {
	    $existing = GeniSlice->Lookup($certificate->hrn());
649

650
651
652
653
654
	    if (defined($existing)) {
		return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				"Slice already registered with HRN");
	    }
	}
655
656
	my $newslice = GeniSlice->Create($certificate,
					 $user, $slice_authority);
657
658
	if (!defined($newslice)) {
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
659
					"Could not be registered");
660
	}
661
662
663
664
665
666
	if (defined($slice_expires) &&
	    $newslice->SetExpiration($slice_expires) != 0) {
	    print STDERR
		"Could not set expiration for $newslice to $slice_expires\n";
	}
	
667
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, undef,
668
				    "Slice has been registered");
669
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
670
    if ($type eq "component") {
671
	my $manager = GeniAuthority->Lookup($ENV{'GENIURN'});
Leigh B. Stoller's avatar
Leigh B. Stoller committed
672
673
	if (!defined($manager)) {
	    print STDERR "Could not find manager object for caller.\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
674
675
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
676
677
678
	my $component = GeniComponent->CreateFromCertificate($certificate,
							     $manager);
	if (!defined($component)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
679
680
681
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
					"Could not register new resource");
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
682
	return GeniResponse->Create(GENIRESPONSE_SUCCESS);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
683
    }
684
    if ($type eq "cm" || $type eq "sa" || $type eq "ses" || $type eq "am") {
685
686
	my ($auth, $which, $type) = GeniHRN::Parse($certificate->urn());
	
Leigh B. Stoller's avatar
Leigh B. Stoller committed
687
688
689
690
691
	my $url = $certificate->URL();
	return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				    "Could not find URL in the certificate")
	    if (!defined($url));

692
693
694
695
	if ($certificate->hrn() =~ /^unknown/i) {
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
					"Please define PROTOGENI_DOMAIN");
	}
696
697
698
699
700
701
702
703
704

	#
	# Check for an existing authority. 
	#
	if (GeniAuthority->CheckExisting($certificate) != 0) {
	    print STDERR "Attempt to register existing authority\n";
	    return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
					"Authority already exists");
	}
705
	
Leigh B. Stoller's avatar
Leigh B. Stoller committed
706
707
708
	SENDMAIL($TBOPS, "ProtoGeni Authority Registration",
		 $certificate->asText());
	
Leigh B. Stoller's avatar
Leigh B. Stoller committed
709
710
711
712
713
714
715
	my $authority = GeniAuthority->Create($certificate, $url, $type);
	if (!defined($authority)) {
	    print STDERR "Could not register new authority\n";
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
	return GeniResponse->Create(GENIRESPONSE_SUCCESS);
    }
716
    return GeniResponse->Create(GENIRESPONSE_UNSUPPORTED);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
717
718
}

719
720
##
# Delete an object.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
721
#
722
sub Remove($)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
723
724
{
    my ($argref) = @_;
725
    my $cred  = $argref->{'credential'};
Leigh B. Stoller's avatar
Leigh B. Stoller committed
726
    my $uuid  = $argref->{'uuid'};
727
    my $urn   = $argref->{'urn'};
728
    my $type  = $argref->{'type'};
729
    my $token = $uuid || $urn;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
730

731
    if (! (defined($type) && ($type =~ /^(Slice|User)$/))) {
732
	return GeniResponse->MalformedArgsResponse();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
733
    }
734
    if (! ((defined($uuid) || defined($urn)) && defined($cred))) {
735
	return GeniResponse->MalformedArgsResponse();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
736
    }
737
738
739
740
    return GeniResponse->MalformedArgsResponse()
	if (defined($uuid) && $uuid !~ /^[-\w]*$/);
    return GeniResponse->MalformedArgsResponse()
	if (defined($urn) && !GeniHRN::IsValid($urn));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
741

742
    my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
743
    if (!defined($authority)) {
744
745
746
	print STDERR "Could not find local authority object\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
747
748
749
750
    my $credential = CheckCredential($cred, $authority);
    return $credential
	if (GeniResponse::IsResponse($credential));
   
751
752
753
754
755
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "refresh" ) or
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );

756
    if ($type eq "User") {
757
	my $user = GeniUser->Lookup($token);
758
759
	if (!defined($user)) {
	    return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
760
					"No such user $token");
761
762
763
764
	}
	if (!$user->Delete()) {
	    print STDERR "Could not delete $user from ClearingHouse!\n";
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
765
					"$token could not be unregistered");
766
767
	}
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, undef,
768
				    "$token has been unregistered");
769
770
    }
    if ($type eq "Slice") {
771
	my $slice = GeniSlice->Lookup($token);
772
	if (!defined($slice)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
773
	    return GeniResponse->Create(GENIRESPONSE_SUCCESS, undef,
774
					"No such slice $token");
775
776
777
778
	}
	if ($slice->Delete()) {
	    print STDERR "Could not delete $slice from ClearingHouse!\n";
	    return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
779
					"$token could not be unregistered");
780
781
	}
	return GeniResponse->Create(GENIRESPONSE_SUCCESS, undef,
782
				    "$token has been unregistered");
783
784
    }
    return GeniResponse->Create(GENIRESPONSE_UNSUPPORTED);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
785
786
}

787
788
789
790
791
792
793
794
#
# Emergency Shutdown of a slice. 
#
sub Shutdown($)
{
    my ($argref) = @_;
    my $cred   = $argref->{'credential'};
    my $uuid   = $argref->{'uuid'};
795
    my $urn    = $argref->{'slice_urn'} || $argref->{'urn'};
796
797
    my $clear  = $argref->{'clear'};

798
    if (! ((defined($uuid) || defined($urn)) && defined($cred))) {
799
800
	return GeniResponse->MalformedArgsResponse();
    }
801
802
803
804
    return GeniResponse->MalformedArgsResponse()
	if (defined($uuid) && $uuid !~ /^[-\w]*$/);
    return GeniResponse->MalformedArgsResponse()
	if (defined($urn) && !GeniHRN::IsValid($urn));
805

806
    $clear = (defined($clear) ? $clear : 0);
807

808
    my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
809
810
811
812
    if (!defined($authority)) {
	print STDERR "Could not find local authority object\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
813
814
815
816
817
    #
    # XXX This should be a slice credential, not a clearinghouse
    # credential. But need to wait until new SA is running everywhere.
    #
    my $credential = CheckCredential($cred);
818
819
    return $credential
	if (GeniResponse::IsResponse($credential));
820
821
822
823
824
825

    if ($credential->target_urn() ne $authority->urn() &&
	$credential->target_urn() ne $urn) {
	return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
				    "Insufficient privilege");
    }
826
827
828
829
830
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "operator" ) or
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );

831
    my $slice = GeniSlice->Lookup($uuid || $urn);
832
    if (!defined($slice)) {
833
834
835
836
837
838
839
840
	if (!defined($urn)) {
	    return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
					"No such slice registered here");
	}
    }
    else {
	$urn = $slice->urn()
	    if (!defined($urn));
841
842
843
844
845
846
    }

    #
    # Pass the whole thing off to a script that will contact the
    # CMs.
    #
847
    my $opt = ($clear ? "-u": "");
848
    # -c option indicates acting as CH. 
849
    system("$SLICESHUTDOWN -c $opt $urn");
850
    if ($?) {
851
	print STDERR "Could not shutdown $urn!\n";
852
853
854
855
856
857
	return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				    "Error shutting down slice");
    }
    return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
858
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
859
860
# This is just a placeholder; return a list of all components. Eventually
# takes an rspec and we do a resource mapping. 
Leigh B. Stoller's avatar
Leigh B. Stoller committed
861
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
862
sub ListComponents($)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
863
864
{
    my ($argref) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
865
866
867
868
869
    my $cred  = $argref->{'credential'};

    if (! defined($cred)) {
	return GeniResponse->MalformedArgsResponse();
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
870

871
872
873
    my $credential = CheckCredential($cred);
    return $credential
	if (GeniResponse::IsResponse($credential));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
874

875
876
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "resolve" ) or
877
	$credential->HasPrivilege( "info" ) or
878
879
880
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );

Leigh B. Stoller's avatar
Leigh B. Stoller committed
881
    #
Leigh B. Stoller's avatar
Leigh B. Stoller committed
882
    # Return simple list of components managers (aggregate managers?)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
883
884
    #
    my @results = ();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
885
    my $query_result = DBQueryWarn("select uuid from geni_authorities ".
886
				   "where type='cm' or type='am'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
887
888
889
    return GeniResponse->Create(GENIRESPONSE_DBERROR)
	if (!defined($query_result));

Leigh B. Stoller's avatar
Leigh B. Stoller committed
890
891
    while (my ($manager_uuid) = $query_result->fetchrow_array()) {
	my $manager = GeniAuthority->Lookup($manager_uuid);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
892
	return GeniResponse->Create(GENIRESPONSE_DBERROR)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
893
	    if (!defined($manager));
894
895
	next
	    if ($manager->disabled());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
896
	    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
897
898
	push(@results, { "gid" => $manager->cert(),
			 "hrn" => $manager->hrn(),
Leigh B. Stoller's avatar
Leigh B. Stoller committed
899
			 "urn" => $manager->urn() || "",
Leigh B. Stoller's avatar
Leigh B. Stoller committed
900
		         "url" => $manager->url() });
Leigh B. Stoller's avatar
Leigh B. Stoller committed
901
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
902
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, \@results);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
903
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
904

Leigh B. Stoller's avatar
Leigh B. Stoller committed
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
#
# Post a new CRL
#
sub PostCRL($)
{
    my ($argref) = @_;
    my $cred  = $argref->{'credential'};
    my $cert  = $argref->{'cert'};

    if (! defined($cred)) {
	return GeniResponse->MalformedArgsResponse();
    }
    if (! defined($cert)) {
	return GeniResponse->MalformedArgsResponse();
    }
    if (! ($cert =~ /^[\012\015\040-\176]*$/)) {
	return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
				    "cert: Invalid characters");
    }

925
    my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
Leigh B. Stoller's avatar
Leigh B. Stoller committed
926
927
928
929
    if (!defined($authority)) {
	print STDERR "Could not find local authority object\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
930
931
932
933
    my $credential = CheckCredential($cred, $authority);
    return $credential
	if (GeniResponse::IsResponse($credential));
   
934
935
936
937
938
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "refresh" ) or
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );

939
    my $caller_authority = GeniAuthority->Lookup($ENV{'GENIURN'});
Leigh B. Stoller's avatar
Leigh B. Stoller committed
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
    if (!defined($caller_authority)) {
	print STDERR "Could not find authority object for caller.\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
    if (GeniCertificate->StoreCRL($caller_authority, $cert) != 0) {
	print STDERR "Could not store CRL for $caller_authority\n";

	SENDMAIL($TBOPS, "Failed to Store CRL",
		 "Fail to store CRL for $caller_authority\n".
		 "$cert");
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
    SENDMAIL($TBOPS, "Stored a new CRL",
	     "Storeed a new CRL for $caller_authority\n".
	     "$cert");
    return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
957
958
959
960
961
962
963
964
965
966
967
968

##
# Lookup a UUID and return a blob of stuff. We allow lookups of both
# users and slices, which is what we allow clients to register.
#
sub List($)
{
    my ($argref) = @_;
    my $cred = $argref->{'credential'};
    my $type = $argref->{'type'};
    my @results = ();

969
970
    if (! (defined($type) &&
	   ($type =~ /^(Authorities|Components|Slices|Users)$/i))){
971
972
973
974
975
976
977
	return GeniResponse->MalformedArgsResponse();
    }
    $type = lc($type);
    if (! defined($cred)) {
	return GeniResponse->MalformedArgsResponse();
    }

978
    my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
979
980
981
982
    if (!defined($authority)) {
	print STDERR "Could not find local authority object\n";
	return GeniResponse->Create(GENIRESPONSE_ERROR);
    }
983
984
985
986
    my $credential = CheckCredential($cred, $authority);
    return $credential
	if (GeniResponse::IsResponse($credential));
   
987
988
989
990
991
992
993
994
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "resolve" ) or
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );

    if ($type eq "slices") {
	my @slices;

995
	if (GeniSlice->ListAll(\@slices) != 0) {
996
997
998
999
1000
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
	foreach my $slice (@slices) {
	    my $blob = {"gid"  => $slice->cert(),
			"hrn"  => $slice->hrn(),
1001
			"urn"  => $slice->urn() || '',
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
			"uuid" => $slice->uuid() };
	    
	    push(@results, $blob);
	}
    }
    elsif ($type eq "authorities") {
	my @authorities;

	if (GeniAuthority->ListAll(\@authorities) != 0) {
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
	foreach my $authority (@authorities) {
	    my $blob = {"gid"  => $authority->cert(),
			"hrn"  => $authority->hrn(),
1016
			"urn"  => $authority->urn() || '',
1017
1018
1019
1020
1021
			"uuid" => $authority->uuid() };
	    
	    push(@results, $blob);
	}
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1022
1023
1024
1025
1026
1027
1028
1029
1030
    elsif ($type eq "users") {
	my @users;

	if (GeniUser->ListAll(\@users) != 0) {
	    return GeniResponse->Create(GENIRESPONSE_ERROR);
	}
	foreach my $user (@users) {
	    my $blob = {"gid"  => $user->cert(),
			"hrn"  => $user->hrn(),
1031
			"urn"  => $user->urn() || '',
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1032
1033
1034
1035
1036
			"uuid" => $user->uuid() };
	    
	    push(@results, $blob);
	}
    }
1037
1038
1039
1040
1041
1042
    else {
	return GeniResponse->Create(GENIRESPONSE_UNSUPPORTED);
    }
    
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, \@results);
}
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077