[LON-CAPA-cvs] cvs: loncom / lond

foxr lon-capa-cvs@mail.lon-capa.org
Tue, 17 Aug 2004 10:44:00 -0000


This is a MIME encoded message

--foxr1092739440
Content-Type: text/plain

foxr		Tue Aug 17 06:44:00 2004 EDT

  Modified files:              
    /loncom	lond 
  Log:
  Handlerized and style fixed the following requests:
  - rolesdel
  - get
  - eget
  - del
  - keys
  - currentdump
  - dump
  - store
  - restore
  
  
  
--foxr1092739440
Content-Type: text/plain
Content-Disposition: attachment; filename="foxr-20040817064400.txt"

Index: loncom/lond
diff -u loncom/lond:1.230 loncom/lond:1.231
--- loncom/lond:1.230	Mon Aug 16 07:44:10 2004
+++ loncom/lond	Tue Aug 17 06:44:00 2004
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.230 2004/08/16 11:44:10 foxr Exp $
+# $Id: lond,v 1.231 2004/08/17 10:44:00 foxr Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -57,7 +57,7 @@
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.230 $'; #' stupid emacs
+my $VERSION='$Revision: 1.231 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -2147,6 +2147,535 @@
 &register_handler("rolesput", \&roles_put_handler, 1,1,0);  # Encoded client only.
 
 #
+#   Deletes (removes) a role for a user.   This is equivalent to removing
+#  a permissions package associated with the role from the user's profile.
+#
+# Parameters:
+#     $cmd                 - The command (rolesdel)
+#     $tail                - The remainder of the request line. This consists
+#                             of:
+#                             The domain and user requesting the change (logged)
+#                             The domain and user being changed.
+#                             The roles being revoked.  These are shipped to us
+#                             as a bunch of & separated role name keywords.
+#     $client              - The file handle open on the client.
+# Returns:
+#     1                    - Continue processing
+#     0                    - Exit.
+#
+sub roles_delete_handler {
+    my ($cmd, $tail, $client)  = @_;
+
+    my $userinput    = "$cmd:$tail";
+   
+    my ($exedom,$exeuser,$udom,$uname,$what)=split(/:/,$tail);
+    &Debug("cmd = ".$cmd." exedom= ".$exedom."user = ".$exeuser." udom=".$udom.
+	   "what = ".$what);
+    my $namespace='roles';
+    chomp($what);
+    my $hashref = &tie_user_hash($udom, $uname, $namespace,
+				 &GDBM_WRCREAT(), "D",
+				 "$exedom:$exeuser:$what");
+    
+    if ($hashref) {
+	my @rolekeys=split(/\&/,$what);
+	
+	foreach my $key (@rolekeys) {
+	    delete $hashref->{$key};
+	}
+	if (untie(%$hashref)) {
+	    &Reply($client, "ok\n", $userinput);
+	} else {
+	    &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ".
+		     "while attempting rolesdel\n", $userinput);
+	}
+    } else {
+        &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ".
+		 "while attempting rolesdel\n", $userinput);
+    }
+    
+    return 1;
+}
+&register_handler("rolesdel", \&roles_delete_handler, 1,1, 0); # Encoded client only
+
+# Unencrypted get from a user's profile database.  See 
+# GetProfileEntryEncrypted for a version that does end-to-end encryption.
+# This function retrieves a keyed item from a specific named database in the
+# user's directory.
+#
+# Parameters:
+#   $cmd             - Command request keyword (get).
+#   $tail            - Tail of the command.  This is a colon separated list
+#                      consisting of the domain and username that uniquely
+#                      identifies the profile,
+#                      The 'namespace' which selects the gdbm file to 
+#                      do the lookup in, 
+#                      & separated list of keys to lookup.  Note that
+#                      the values are returned as an & separated list too.
+#   $client          - File descriptor open on the client.
+# Returns:
+#   1       - Continue processing.
+#   0       - Exit.
+#
+sub get_profile_entry {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput= "$cmd:$tail";
+   
+    my ($udom,$uname,$namespace,$what) = split(/:/,$tail);
+    chomp($what);
+    my $hashref = &tie_user_hash($udom, $uname, $namespace,
+				 &GDBM_READER());
+    if ($hashref) {
+        my @queries=split(/\&/,$what);
+        my $qresult='';
+	
+	for (my $i=0;$i<=$#queries;$i++) {
+	    $qresult.="$hashref->{$queries[$i]}&";    # Presumably failure gives empty string.
+	}
+	$qresult=~s/\&$//;              # Remove trailing & from last lookup.
+	if (untie(%$hashref)) {
+	    &Reply($client, "$qresult\n", $userinput);
+	} else {
+	    &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+		    "while attempting get\n", $userinput);
+	}
+    } else {
+	if ($!+0 == 2) {               # +0 coerces errno -> number 2 is ENOENT
+	    &Failure($client, "error:No such file or ".
+		    "GDBM reported bad block error\n", $userinput);
+	} else {                        # Some other undifferentiated err.
+	    &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+		    "while attempting get\n", $userinput);
+	}
+    }
+    return 1;
+}
+&register_handler("get", \&get_profile_entry, 0,1,0);
+
+#
+#  Process the encrypted get request.  Note that the request is sent
+#  in clear, but the reply is encrypted.  This is a small covert channel:
+#  information about the sensitive keys is given to the snooper.  Just not
+#  information about the values of the sensitive key.  Hmm if I wanted to
+#  know these I'd snoop for the egets. Get the profile item names from them
+#  and then issue a get for them since there's no enforcement of the
+#  requirement of an encrypted get for particular profile items.  If I
+#  were re-doing this, I'd force the request to be encrypted as well as the
+#  reply.  I'd also just enforce encrypted transactions for all gets since
+#  that would prevent any covert channel snooping.
+#
+#  Parameters:
+#     $cmd               - Command keyword of request (eget).
+#     $tail              - Tail of the command.  See GetProfileEntry#                          for more information about this.
+#     $client            - File open on the client.
+#  Returns:
+#     1      - Continue processing
+#     0      - server should exit.
+sub get_profile_entry_encrypted {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput = "$cmd:$tail";
+   
+    my ($cmd,$udom,$uname,$namespace,$what) = split(/:/,$userinput);
+    chomp($what);
+    my $hashref = &tie_user_hash($udom, $uname, $namespace,
+				 &GDBM_READER());
+    if ($hashref) {
+        my @queries=split(/\&/,$what);
+        my $qresult='';
+	for (my $i=0;$i<=$#queries;$i++) {
+	    $qresult.="$hashref->{$queries[$i]}&";
+	}
+	if (untie(%$hashref)) {
+	    $qresult=~s/\&$//;
+	    if ($cipher) {
+		my $cmdlength=length($qresult);
+		$qresult.="         ";
+		my $encqresult='';
+		for(my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
+		    $encqresult.= unpack("H16", 
+					 $cipher->encrypt(substr($qresult,
+								 $encidx,
+								 8)));
+		}
+		&Reply( $client, "enc:$cmdlength:$encqresult\n", $userinput);
+	    } else {
+		&Failure( $client, "error:no_key\n", $userinput);
+	    }
+	} else {
+	    &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+		    "while attempting eget\n", $userinput);
+	}
+    } else {
+	&Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+		"while attempting eget\n", $userinput);
+    }
+    
+    return 1;
+}
+&register_handler("eget", \&GetProfileEntryEncrypted, 0, 1, 0);
+#
+#   Deletes a key in a user profile database.
+#   
+#   Parameters:
+#       $cmd                  - Command keyword (del).
+#       $tail                 - Command tail.  IN this case a colon
+#                               separated list containing:
+#                               The domain and user that identifies uniquely
+#                               the identity of the user.
+#                               The profile namespace (name of the profile
+#                               database file).
+#                               & separated list of keywords to delete.
+#       $client              - File open on client socket.
+# Returns:
+#     1   - Continue processing
+#     0   - Exit server.
+#
+#
+
+sub delete_profile_entry {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput = "cmd:$tail";
+
+    my ($udom,$uname,$namespace,$what) = split(/:/,$tail);
+    chomp($what);
+    my $hashref = &tie_user_hash($udom, $uname, $namespace,
+				 &GDBM_WRCREAT(),
+				 "D",$what);
+    if ($hashref) {
+        my @keys=split(/\&/,$what);
+	foreach my $key (@keys) {
+	    delete($hashref->{$key});
+	}
+	if (untie(%$hashref)) {
+	    &Reply($client, "ok\n", $userinput);
+	} else {
+	    &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+		    "while attempting del\n", $userinput);
+	}
+    } else {
+	&Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ".
+		 "while attempting del\n", $userinput);
+    }
+    return 1;
+}
+&register_handler("del", \&delete_profile_entry, 0, 1, 0);
+#
+#  List the set of keys that are defined in a profile database file.
+#  A successful reply from this will contain an & separated list of
+#  the keys. 
+# Parameters:
+#     $cmd              - Command request (keys).
+#     $tail             - Remainder of the request, a colon separated
+#                         list containing domain/user that identifies the
+#                         user being queried, and the database namespace
+#                         (database filename essentially).
+#     $client           - File open on the client.
+#  Returns:
+#    1    - Continue processing.
+#    0    - Exit the server.
+#
+sub get_profile_keys {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput = "$cmd:$tail";
+
+    my ($udom,$uname,$namespace)=split(/:/,$tail);
+    my $qresult='';
+    my $hashref = &tie_user_hash($udom, $uname, $namespace,
+				  &GDBM_READER());
+    if ($hashref) {
+	foreach my $key (keys %$hashref) {
+	    $qresult.="$key&";
+	}
+	if (untie(%$hashref)) {
+	    $qresult=~s/\&$//;
+	    &Reply($client, "$qresult\n", $userinput);
+	} else {
+	    &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+		    "while attempting keys\n", $userinput);
+	}
+    } else {
+	&Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ".
+		 "while attempting keys\n", $userinput);
+    }
+   
+    return 1;
+}
+&register_handler("keys", \&get_profile_keys, 0, 1, 0);
+
+#
+#   Dump the contents of a user profile database.
+#   Note that this constitutes a very large covert channel too since
+#   the dump will return sensitive information that is not encrypted.
+#   The naive security assumption is that the session negotiation ensures
+#   our client is trusted and I don't believe that's assured at present.
+#   Sure want badly to go to ssl or tls.  Of course if my peer isn't really
+#   a LonCAPA node they could have negotiated an encryption key too so >sigh<.
+# 
+#  Parameters:
+#     $cmd           - The command request keyword (currentdump).
+#     $tail          - Remainder of the request, consisting of a colon
+#                      separated list that has the domain/username and
+#                      the namespace to dump (database file).
+#     $client        - file open on the remote client.
+# Returns:
+#     1    - Continue processing.
+#     0    - Exit the server.
+#
+sub dump_profile_database {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput = "$cmd:$tail";
+   
+    my ($udom,$uname,$namespace) = split(/:/,$tail);
+    my $hashref = &tie_user_hash($udom, $uname, $namespace,
+				 &GDBM_READER());
+    if ($hashref) {
+	# Structure of %data:
+	# $data{$symb}->{$parameter}=$value;
+	# $data{$symb}->{'v.'.$parameter}=$version;
+	# since $parameter will be unescaped, we do not
+ 	# have to worry about silly parameter names...
+	
+        my $qresult='';
+	my %data = ();                     # A hash of anonymous hashes..
+	while (my ($key,$value) = each(%$hashref)) {
+	    my ($v,$symb,$param) = split(/:/,$key);
+	    next if ($v eq 'version' || $symb eq 'keys');
+	    next if (exists($data{$symb}) && 
+		     exists($data{$symb}->{$param}) &&
+		     $data{$symb}->{'v.'.$param} > $v);
+	    $data{$symb}->{$param}=$value;
+	    $data{$symb}->{'v.'.$param}=$v;
+	}
+	if (untie(%$hashref)) {
+	    while (my ($symb,$param_hash) = each(%data)) {
+		while(my ($param,$value) = each (%$param_hash)){
+		    next if ($param =~ /^v\./);       # Ignore versions...
+		    #
+		    #   Just dump the symb=value pairs separated by &
+		    #
+		    $qresult.=$symb.':'.$param.'='.$value.'&';
+		}
+	    }
+	    chop($qresult);
+	    &Reply($client , "$qresult\n", $userinput);
+	} else {
+	    &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ".
+		     "while attempting currentdump\n", $userinput);
+	}
+    } else {
+	&Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+		"while attempting currentdump\n", $userinput);
+    }
+
+    return 1;
+}
+&register_handler("currentdump", \&dump_profile_database, 0, 1, 0);
+
+#
+#   Dump a profile database with an optional regular expression
+#   to match against the keys.  In this dump, no effort is made
+#   to separate symb from version information. Presumably the
+#   databases that are dumped by this command are of a different
+#   structure.  Need to look at this and improve the documentation of
+#   both this and the currentdump handler.
+# Parameters:
+#    $cmd                     - The command keyword.
+#    $tail                    - All of the characters after the $cmd:
+#                               These are expected to be a colon
+#                               separated list containing:
+#                               domain/user - identifying the user.
+#                               namespace   - identifying the database.
+#                               regexp      - optional regular expression
+#                                             that is matched against
+#                                             database keywords to do
+#                                             selective dumps.
+#   $client                   - Channel open on the client.
+# Returns:
+#    1    - Continue processing.
+# Side effects:
+#    response is written to $client.
+#
+sub dump_with_regexp {
+    my ($cmd, $tail, $client) = @_;
+
+
+    my $userinput = "$cmd:$tail";
+
+    my ($udom,$uname,$namespace,$regexp)=split(/:/,$tail);
+    if (defined($regexp)) {
+	$regexp=&unescape($regexp);
+    } else {
+	$regexp='.';
+    }
+    my $hashref = &tie_user_hash($udom, $uname, $namespace,
+				 &GDBM_READER());
+    if ($hashref) {
+        my $qresult='';
+	while (my ($key,$value) = each(%$hashref)) {
+	    if ($regexp eq '.') {
+		$qresult.=$key.'='.$value.'&';
+	    } else {
+		my $unescapeKey = &unescape($key);
+		if (eval('$unescapeKey=~/$regexp/')) {
+		    $qresult.="$key=$value&";
+		}
+	    }
+	}
+	if (untie(%$hashref)) {
+	    chop($qresult);
+	    &Reply($client, "$qresult\n", $userinput);
+	} else {
+	    &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ".
+		     "while attempting dump\n", $userinput);
+	}
+    } else {
+	&Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+		"while attempting dump\n", $userinput);
+    }
+
+    return 1;
+}
+
+&register_handler("dump", \&dump_with_regexp, 0, 1, 0);
+
+#  Store a set of key=value pairs associated with a versioned name.
+#
+#  Parameters:
+#    $cmd                - Request command keyword.
+#    $tail               - Tail of the request.  This is a colon
+#                          separated list containing:
+#                          domain/user - User and authentication domain.
+#                          namespace   - Name of the database being modified
+#                          rid         - Resource keyword to modify.
+#                          what        - new value associated with rid.
+#
+#    $client             - Socket open on the client.
+#
+#
+#  Returns:
+#      1 (keep on processing).
+#  Side-Effects:
+#    Writes to the client
+sub store_handler {
+    my ($cmd, $tail, $client) = @_;
+ 
+    my $userinput = "$cmd:$tail";
+
+    my ($udom,$uname,$namespace,$rid,$what) =split(/:/,$tail);
+    if ($namespace ne 'roles') {
+
+	chomp($what);
+	my @pairs=split(/\&/,$what);
+	my $hashref  = &tie_user_hash($udom, $uname, $namespace,
+				       &GDBM_WRCREAT(), "P",
+				       "$rid:$what");
+	if ($hashref) {
+	    my $now = time;
+	    my @previouskeys=split(/&/,$hashref->{"keys:$rid"});
+	    my $key;
+	    $hashref->{"version:$rid"}++;
+	    my $version=$hashref->{"version:$rid"};
+	    my $allkeys=''; 
+	    foreach my $pair (@pairs) {
+		my ($key,$value)=split(/=/,$pair);
+		$allkeys.=$key.':';
+		$hashref->{"$version:$rid:$key"}=$value;
+	    }
+	    $hashref->{"$version:$rid:timestamp"}=$now;
+	    $allkeys.='timestamp';
+	    $hashref->{"$version:keys:$rid"}=$allkeys;
+	    if (untie($hashref)) {
+		&Reply($client, "ok\n", $userinput);
+	    } else {
+		&Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+			"while attempting store\n", $userinput);
+	    }
+	} else {
+	    &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ".
+		     "while attempting store\n", $userinput);
+	}
+    } else {
+	&Failure($client, "refused\n", $userinput);
+    }
+
+    return 1;
+}
+&register_handler("store", \&store_handler, 0, 1, 0);
+#
+#  Dump out all versions of a resource that has key=value pairs associated
+# with it for each version.  These resources are built up via the store
+# command.
+#
+#  Parameters:
+#     $cmd               - Command keyword.
+#     $tail              - Remainder of the request which consists of:
+#                          domain/user   - User and auth. domain.
+#                          namespace     - name of resource database.
+#                          rid           - Resource id.
+#    $client             - socket open on the client.
+#
+# Returns:
+#      1  indicating the caller should not yet exit.
+# Side-effects:
+#   Writes a reply to the client.
+#   The reply is a string of the following shape:
+#   version=current&version:keys=k1:k2...&1:k1=v1&1:k2=v2...
+#    Where the 1 above represents version 1.
+#    this continues for all pairs of keys in all versions.
+#
+#
+#    
+#
+sub restore_handler {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput = "$cmd:$tail";	# Only used for logging purposes.
+
+    my ($cmd,$udom,$uname,$namespace,$rid) = split(/:/,$userinput);
+    $namespace=~s/\//\_/g;
+    $namespace=~s/\W//g;
+    chomp($rid);
+    my $proname=&propath($udom,$uname);
+    my $qresult='';
+    my %hash;
+    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",
+	    &GDBM_READER(),0640)) {
+	my $version=$hash{"version:$rid"};
+	$qresult.="version=$version&";
+	my $scope;
+	for ($scope=1;$scope<=$version;$scope++) {
+	    my $vkeys=$hash{"$scope:keys:$rid"};
+	    my @keys=split(/:/,$vkeys);
+	    my $key;
+	    $qresult.="$scope:keys=$vkeys&";
+	    foreach $key (@keys) {
+		$qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&";
+	    }                                  
+	}
+	if (untie(%hash)) {
+	    $qresult=~s/\&$//;
+	    &Reply( $client, "$qresult\n", $userinput);
+	} else {
+	    &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+		    "while attempting restore\n", $userinput);
+	}
+    } else {
+	&Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+		"while attempting restore\n", $userinput);
+    }
+  
+    return 1;
+
+
+}
+&register_handler("restore", \&restore_handler, 0,1,0);
+#
+#
 #---------------------------------------------------------------
 #
 #   Getting, decoding and dispatching requests:
@@ -2261,390 +2790,9 @@
 #------------------- Commands not yet in spearate handlers. --------------
 
 
-# -------------------------------------------------------------------- rolesdel
-    if ($userinput =~ /^rolesdel/) {
-	if(isClient) {
-	    &Debug("rolesdel");
-	    if ($wasenc==1) {
-		my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
-		    =split(/:/,$userinput);
-		&Debug("cmd = ".$cmd." exedom= ".$exedom.
-		       "user = ".$exeuser." udom=".$udom.
-		       "what = ".$what);
-		my $namespace='roles';
-		chomp($what);
-		my $proname=propath($udom,$uname);
-		my $now=time;
-		my @rolekeys=split(/\&/,$what);
-		my %hash;
-		if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
-		    {
-			my $hfh;
-			if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { 
-			    print $hfh "D:$now:$exedom:$exeuser:$what\n";
-			}
-		    }
-		    foreach my $key (@rolekeys) {
-			delete $hash{$key};
-		    }
-		    if (untie(%hash)) {
-			print $client "ok\n";
-		    } else {
-			print $client "error: ".($!+0)
-			    ." untie(GDBM) Failed ".
-			    "while attempting rolesdel\n";
-		    }
-		} else {
-		    print $client "error: ".($!+0)
-			." tie(GDBM) Failed ".
-			"while attempting rolesdel\n";
-		}
-	    } else {
-		print $client "refused\n";
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
-# ------------------------------------------------------------------------- get
-    } elsif ($userinput =~ /^get/) {
-	if(isClient) {
-	    my ($cmd,$udom,$uname,$namespace,$what)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    chomp($what);
-	    my @queries=split(/\&/,$what);
-	    my $proname=propath($udom,$uname);
-	    my $qresult='';
-	    my %hash;
-	    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
-		for (my $i=0;$i<=$#queries;$i++) {
-		    $qresult.="$hash{$queries[$i]}&";
-		}
-		if (untie(%hash)) {
-		    $qresult=~s/\&$//;
-		    print $client "$qresult\n";
-		} else {
-		    print $client "error: ".($!+0)
-			." untie(GDBM) Failed ".
-			"while attempting get\n";
-		}
-	    } else {
-		if ($!+0 == 2) {
-		    print $client "error:No such file or ".
-			"GDBM reported bad block error\n";
-		} else {
-		    print $client "error: ".($!+0)
-			." tie(GDBM) Failed ".
-			"while attempting get\n";
-		}
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
-# ------------------------------------------------------------------------ eget
-    } elsif ($userinput =~ /^eget/) {
-	if (isClient) {
-	    my ($cmd,$udom,$uname,$namespace,$what)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    chomp($what);
-	    my @queries=split(/\&/,$what);
-	    my $proname=propath($udom,$uname);
-	    my $qresult='';
-	    my %hash;
-	    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
-		for (my $i=0;$i<=$#queries;$i++) {
-		    $qresult.="$hash{$queries[$i]}&";
-		}
-		if (untie(%hash)) {
-		    $qresult=~s/\&$//;
-		    if ($cipher) {
-			my $cmdlength=length($qresult);
-			$qresult.="         ";
-			my $encqresult='';
-			for 
-			    (my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
-				$encqresult.=
-				    unpack("H16",
-					   $cipher->encrypt(substr($qresult,$encidx,8)));
-			    }
-			print $client "enc:$cmdlength:$encqresult\n";
-		    } else {
-			print $client "error:no_key\n";
-		    }
-		} else {
-		    print $client "error: ".($!+0)
-			." untie(GDBM) Failed ".
-			"while attempting eget\n";
-		}
-	    } else {
-		print $client "error: ".($!+0)
-		    ." tie(GDBM) Failed ".
-		    "while attempting eget\n";
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
-# ------------------------------------------------------------------------- del
-    } elsif ($userinput =~ /^del/) {
-	if(isClient) {
-	    my ($cmd,$udom,$uname,$namespace,$what)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    chomp($what);
-	    my $proname=propath($udom,$uname);
-	    my $now=time;
-	    my @keys=split(/\&/,$what);
-	    my %hash;
-	    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
-		unless ($namespace=~/^nohist\_/) {
-		    my $hfh;
-		    if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { print $hfh "D:$now:$what\n"; }
-		}
-		foreach my $key (@keys) {
-		    delete($hash{$key});
-		}
-		if (untie(%hash)) {
-		    print $client "ok\n";
-		} else {
-		    print $client "error: ".($!+0)
-			." untie(GDBM) Failed ".
-			"while attempting del\n";
-		}
-	    } else {
-		print $client "error: ".($!+0)
-		    ." tie(GDBM) Failed ".
-		    "while attempting del\n";
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
-# ------------------------------------------------------------------------ keys
-    } elsif ($userinput =~ /^keys/) {
-	if(isClient) {
-	    my ($cmd,$udom,$uname,$namespace)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    my $proname=propath($udom,$uname);
-	    my $qresult='';
-	    my %hash;
-	    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
-		foreach my $key (keys %hash) {
-		    $qresult.="$key&";
-		}
-		if (untie(%hash)) {
-		    $qresult=~s/\&$//;
-		    print $client "$qresult\n";
-		} else {
-		    print $client "error: ".($!+0)
-			." untie(GDBM) Failed ".
-			"while attempting keys\n";
-		}
-	    } else {
-		print $client "error: ".($!+0)
-		    ." tie(GDBM) Failed ".
-		    "while attempting keys\n";
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
-# ----------------------------------------------------------------- dumpcurrent
-    } elsif ($userinput =~ /^currentdump/) {
-	if (isClient) {
-	    my ($cmd,$udom,$uname,$namespace)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    my $qresult='';
-	    my $proname=propath($udom,$uname);
-	    my %hash;
-	    if (tie(%hash,'GDBM_File',
-		    "$proname/$namespace.db",
-		    &GDBM_READER(),0640)) {
-			    # Structure of %data:
-		# $data{$symb}->{$parameter}=$value;
-		# $data{$symb}->{'v.'.$parameter}=$version;
-		# since $parameter will be unescaped, we do not
-		# have to worry about silly parameter names...
-		my %data = ();
-		while (my ($key,$value) = each(%hash)) {
-		    my ($v,$symb,$param) = split(/:/,$key);
-		    next if ($v eq 'version' || $symb eq 'keys');
-		    next if (exists($data{$symb}) && 
-			     exists($data{$symb}->{$param}) &&
-			     $data{$symb}->{'v.'.$param} > $v);
-		    $data{$symb}->{$param}=$value;
-		    $data{$symb}->{'v.'.$param}=$v;
-		}
-		if (untie(%hash)) {
-		    while (my ($symb,$param_hash) = each(%data)) {
-			while(my ($param,$value) = each (%$param_hash)){
-			    next if ($param =~ /^v\./);
-			    $qresult.=$symb.':'.$param.'='.$value.'&';
-			}
-		    }
-		    chop($qresult);
-		    print $client "$qresult\n";
-		} else {
-		    print $client "error: ".($!+0)
-			." untie(GDBM) Failed ".
-			"while attempting currentdump\n";
-		}
-	    } else {
-		print $client "error: ".($!+0)
-		    ." tie(GDBM) Failed ".
-		    "while attempting currentdump\n";
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	}
-# ------------------------------------------------------------------------ dump
-    } elsif ($userinput =~ /^dump/) {
-	if(isClient) {
-	    my ($cmd,$udom,$uname,$namespace,$regexp)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    if (defined($regexp)) {
-		$regexp=&unescape($regexp);
-	    } else {
-		$regexp='.';
-	    }
-	    my $qresult='';
-	    my $proname=propath($udom,$uname);
-	    my %hash;
-	    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
-		while (my ($key,$value) = each(%hash)) {
-		    if ($regexp eq '.') {
-			$qresult.=$key.'='.$value.'&';
-		    } else {
-			my $unescapeKey = &unescape($key);
-			if (eval('$unescapeKey=~/$regexp/')) {
-			    $qresult.="$key=$value&";
-			}
-		    }
-		}
-		if (untie(%hash)) {
-		    chop($qresult);
-		    print $client "$qresult\n";
-		} else {
-		    print $client "error: ".($!+0)
-			." untie(GDBM) Failed ".
-			"while attempting dump\n";
-		}
-	    } else {
-		print $client "error: ".($!+0)
-		    ." tie(GDBM) Failed ".
-		    "while attempting dump\n";
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
-# ----------------------------------------------------------------------- store
-    } elsif ($userinput =~ /^store/) {
-	if(isClient) {
-	    my ($cmd,$udom,$uname,$namespace,$rid,$what)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    if ($namespace ne 'roles') {
-		chomp($what);
-		my $proname=propath($udom,$uname);
-		my $now=time;
-		my @pairs=split(/\&/,$what);
-		my %hash;
-		if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
-		    unless ($namespace=~/^nohist\_/) {
-			my $hfh;
-			if ($hfh=IO::File->new(">>$proname/$namespace.hist")) {
-			    print $hfh "P:$now:$rid:$what\n";
-			}
-		    }
-		    my @previouskeys=split(/&/,$hash{"keys:$rid"});
-		    my $key;
-		    $hash{"version:$rid"}++;
-		    my $version=$hash{"version:$rid"};
-		    my $allkeys=''; 
-		    foreach my $pair (@pairs) {
-			my ($key,$value)=split(/=/,$pair);
-			$allkeys.=$key.':';
-			$hash{"$version:$rid:$key"}=$value;
-		    }
-		    $hash{"$version:$rid:timestamp"}=$now;
-		    $allkeys.='timestamp';
-		    $hash{"$version:keys:$rid"}=$allkeys;
-		    if (untie(%hash)) {
-			print $client "ok\n";
-		    } else {
-			print $client "error: ".($!+0)
-			    ." untie(GDBM) Failed ".
-			    "while attempting store\n";
-				}
-		} else {
-		    print $client "error: ".($!+0)
-			." tie(GDBM) Failed ".
-			"while attempting store\n";
-		}
-	    } else {
-		print $client "refused\n";
-	    }
-	} else {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
-# --------------------------------------------------------------------- restore
-    } elsif ($userinput =~ /^restore/) {
-	if(isClient) {
-	    my ($cmd,$udom,$uname,$namespace,$rid)
-		=split(/:/,$userinput);
-	    $namespace=~s/\//\_/g;
-	    $namespace=~s/\W//g;
-	    chomp($rid);
-	    my $proname=propath($udom,$uname);
-	    my $qresult='';
-	    my %hash;
-	    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
-		my $version=$hash{"version:$rid"};
-		$qresult.="version=$version&";
-		my $scope;
-		for ($scope=1;$scope<=$version;$scope++) {
-		    my $vkeys=$hash{"$scope:keys:$rid"};
-		    my @keys=split(/:/,$vkeys);
-		    my $key;
-		    $qresult.="$scope:keys=$vkeys&";
-		    foreach $key (@keys) {
-			$qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&";
-		    }                                  
-		}
-		if (untie(%hash)) {
-		    $qresult=~s/\&$//;
-		    print $client "$qresult\n";
-		} else {
-		    print $client "error: ".($!+0)
-			." untie(GDBM) Failed ".
-			"while attempting restore\n";
-		}
-	    } else {
-		print $client "error: ".($!+0)
-		    ." tie(GDBM) Failed ".
-		    "while attempting restore\n";
-	    }
-	} else  {
-	    Reply($client, "refused\n", $userinput);
-	    
-	}
+
 # -------------------------------------------------------------------- chatsend
-    } elsif ($userinput =~ /^chatsend/) {
+   if ($userinput =~ /^chatsend/) {
 	if(isClient) {
 	    my ($cmd,$cdom,$cnum,$newpost)=split(/\:/,$userinput);
 	    &chatadd($cdom,$cnum,$newpost);
@@ -3010,21 +3158,21 @@
 	return 0;
 	
 # ---------------------------------- set current host/domain
-    } elsif ($userinput =~ /^sethost:/) {
+    } elsif ($userinput =~ /^sethost/) {
 	if (isClient) {
 	    print $client &sethost($userinput)."\n";
 	} else {
 	    print $client "refused\n";
 	}
 #---------------------------------- request file (?) version.
-    } elsif ($userinput =~/^version:/) {
+    } elsif ($userinput =~/^version/) {
 	if (isClient) {
 	    print $client &version($userinput)."\n";
 	} else {
 	    print $client "refused\n";
 	}
 #------------------------------- is auto-enrollment enabled?
-    } elsif ($userinput =~/^autorun:/) {
+    } elsif ($userinput =~/^autorun/) {
 	if (isClient) {
 	    my ($cmd,$cdom) = split(/:/,$userinput);
 	    my $outcome = &localenroll::run($cdom);
@@ -3033,7 +3181,7 @@
 	    print $client "0\n";
 	}
 #------------------------------- get official sections (for auto-enrollment).
-    } elsif ($userinput =~/^autogetsections:/) {
+    } elsif ($userinput =~/^autogetsections/) {
 	if (isClient) {
 	    my ($cmd,$coursecode,$cdom)=split(/:/,$userinput);
 	    my @secs = &localenroll::get_sections($coursecode,$cdom);
@@ -3043,7 +3191,7 @@
 	    print $client "refused\n";
 	}
 #----------------------- validate owner of new course section (for auto-enrollment).
-    } elsif ($userinput =~/^autonewcourse:/) {
+    } elsif ($userinput =~/^autonewcourse/) {
 	if (isClient) {
 	    my ($cmd,$inst_course_id,$owner,$cdom)=split(/:/,$userinput);
 	    my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom);
@@ -3052,7 +3200,7 @@
 	    print $client "refused\n";
 	}
 #-------------- validate course section in schedule of classes (for auto-enrollment).
-    } elsif ($userinput =~/^autovalidatecourse:/) {
+    } elsif ($userinput =~/^autovalidatecourse/) {
 	if (isClient) {
 	    my ($cmd,$inst_course_id,$cdom)=split(/:/,$userinput);
 	    my $outcome=&localenroll::validate_courseID($inst_course_id,$cdom);
@@ -3061,7 +3209,7 @@
 	    print $client "refused\n";
 	}
 #--------------------------- create password for new user (for auto-enrollment).
-    } elsif ($userinput =~/^autocreatepassword:/) {
+    } elsif ($userinput =~/^autocreatepassword/) {
 	if (isClient) {
 	    my ($cmd,$authparam,$cdom)=split(/:/,$userinput);
 	    my ($create_passwd,$authchk);
@@ -3071,7 +3219,7 @@
 	    print $client "refused\n";
 	}
 #---------------------------  read and remove temporary files (for auto-enrollment).
-    } elsif ($userinput =~/^autoretrieve:/) {
+    } elsif ($userinput =~/^autoretrieve/) {
 	if (isClient) {
 	    my ($cmd,$filename) = split(/:/,$userinput);
 	    my $source = $perlvar{'lonDaemons'}.'/tmp/'.$filename;
@@ -3097,7 +3245,7 @@
 	    print $client "refused\n";
 	}
 #---------------------  read and retrieve institutional code format (for support form).
-    } elsif ($userinput =~/^autoinstcodeformat:/) {
+    } elsif ($userinput =~/^autoinstcodeformat/) {
 	if (isClient) {
 	    my $reply;
 	    my($cmd,$cdom,$course) = split(/:/,$userinput);

--foxr1092739440--