--- loncom/lond	2006/06/07 01:49:43	1.333
+++ loncom/lond	2007/03/28 00:05:38	1.363
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.333 2006/06/07 01:49:43 raeburn Exp $
+# $Id: lond,v 1.363 2007/03/28 00:05:38 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -40,10 +40,10 @@ use IO::File;
 use POSIX;
 use Crypt::IDEA;
 use LWP::UserAgent();
+use Digest::MD5 qw(md5_hex);
 use GDBM_File;
 use Authen::Krb4;
 use Authen::Krb5;
-use lib '/home/httpd/lib/perl/';
 use localauth;
 use localenroll;
 use localstudentphoto;
@@ -59,7 +59,7 @@ my $DEBUG = 0;		       # Non zero to ena
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.333 $'; #' stupid emacs
+my $VERSION='$Revision: 1.363 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -503,30 +503,30 @@ sub AdjustHostContents {
     my $adjusted;
     my $me        = $perlvar{'lonHostID'};
 
- foreach my $line (split(/\n/,$contents)) {
+    foreach my $line (split(/\n/,$contents)) {
 	if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) {
 	    chomp($line);
 	    my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);
 	    if ($id eq $me) {
-          my $ip = gethostbyname($name);
-          my $ipnew = inet_ntoa($ip);
-         $ip = $ipnew;
+		my $ip = gethostbyname($name);
+		my $ipnew = inet_ntoa($ip);
+		$ip = $ipnew;
 		#  Reconstruct the host line and append to adjusted:
 		
-		   my $newline = "$id:$domain:$role:$name:$ip";
-		   if($maxcon ne "") { # Not all hosts have loncnew tuning params
-		     $newline .= ":$maxcon:$idleto:$mincon";
-		   }
-		   $adjusted .= $newline."\n";
+		my $newline = "$id:$domain:$role:$name:$ip";
+		if($maxcon ne "") { # Not all hosts have loncnew tuning params
+		    $newline .= ":$maxcon:$idleto:$mincon";
+		}
+		$adjusted .= $newline."\n";
 		
-      } else {		# Not me, pass unmodified.
-		   $adjusted .= $line."\n";
-      }
+	    } else {		# Not me, pass unmodified.
+		$adjusted .= $line."\n";
+	    }
 	} else {                  # Blank or comment never re-written.
 	    $adjusted .= $line."\n";	# Pass blanks and comments as is.
 	}
- }
- return $adjusted;
+    }
+    return $adjusted;
 }
 #
 #   InstallFile: Called to install an administrative file:
@@ -835,16 +835,14 @@ sub AdjustOurHost {
     #   Use the config line to get my hostname.
     #   Use gethostbyname to translate that into an IP address.
     #
-    my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon) = split(/:/,$ConfigLine);
-    my $BinaryIp = gethostbyname($name);
-    my $ip       = inet_ntoa($ip);
+    my ($id,$domain,$role,$name,$maxcon,$idleto,$mincon) = split(/:/,$ConfigLine);
     #
     #  Reassemble the config line from the elements in the list.
     #  Note that if the loncnew items were not present before, they will
     #  be now even if they would be empty
     #
     my $newConfigLine = $id;
-    foreach my $item ($domain, $role, $name, $ip, $maxcon, $idleto, $mincon) {
+    foreach my $item ($domain, $role, $name, $maxcon, $idleto, $mincon) {
 	$newConfigLine .= ":".$item;
     }
     #  Replace the line:
@@ -890,11 +888,11 @@ sub EditFile {
 
     #  Split the command into it's pieces:  edit:filetype:script
 
-    my ($request, $filetype, $script) = split(/:/, $request,3);	# : in script
+    my ($cmd, $filetype, $script) = split(/:/, $request,3);	# : in script
 
     #  Check the pre-coditions for success:
 
-    if($request != "edit") {	# Something is amiss afoot alack.
+    if($cmd != "edit") {	# Something is amiss afoot alack.
 	return "error:edit request detected, but request != 'edit'\n";
     }
     if( ($filetype ne "hosts")  &&
@@ -1252,7 +1250,7 @@ sub push_file_handler {
 #
 sub du_handler {
     my ($cmd, $ududir, $client) = @_;
-    my ($ududir) = split(/:/,$ududir); # Make 'telnet' testing easier.
+    ($ududir) = split(/:/,$ududir); # Make 'telnet' testing easier.
     my $userinput = "$cmd:$ududir";
 
     if ($ududir=~/\.\./ || $ududir!~m|^/home/httpd/|) {
@@ -1270,6 +1268,7 @@ sub du_handler {
 	my $code=sub { 
 	    if ($_=~/\.\d+\./) { return;} 
 	    if ($_=~/\.meta$/) { return;}
+	    if (-d $_)         { return;}
 	    $total_size+=(stat($_))[7];
 	};
 	chdir($ududir);
@@ -1576,17 +1575,24 @@ sub change_password_handler {
     #  uname - Username.
     #  upass - Current password.
     #  npass - New password.
+    #  context - Context in which this was called 
+    #            (preferences or reset_by_email).
    
-    my ($udom,$uname,$upass,$npass)=split(/:/,$tail);
+    my ($udom,$uname,$upass,$npass,$context)=split(/:/,$tail);
 
     $upass=&unescape($upass);
     $npass=&unescape($npass);
     &Debug("Trying to change password for $uname");
 
     # First require that the user can be authenticated with their
-    # old password:
-
-    my $validated = &validate_user($udom, $uname, $upass);
+    # old password unless context was 'reset_by_email':
+    
+    my $validated;
+    if ($context eq 'reset_by_email') {
+        $validated = 1;
+    } else {
+        $validated = &validate_user($udom, $uname, $upass);
+    }
     if($validated) {
 	my $realpasswd  = &get_auth_type($udom, $uname); # Defined since authd.
 	
@@ -1605,7 +1611,7 @@ sub change_password_handler {
 			 ."to change password");
 		&Failure( $client, "non_authorized\n",$userinput);
 	    }
-	} elsif ($howpwd eq 'unix') {
+	} elsif ($howpwd eq 'unix' && $context ne 'reset_by_email') {
 	    my $result = &change_unix_password($uname, $npass);
 	    &logthis("Result of password change for $uname: ".
 		     $result);
@@ -1847,6 +1853,7 @@ sub update_resource_handler {
 		my $reply=&reply("unsub:$fname","$clientname");
 		&devalidate_meta_cache($fname);
 		unlink("$fname");
+		unlink("$fname.meta");
 	    } else {
 		my $transname="$fname.in.transfer";
 		my $remoteurl=&reply("sub:$fname","$clientname");
@@ -2124,14 +2131,21 @@ sub token_auth_user_file_handler {
     
     chomp($session);
     my $reply="non_auth\n";
-    if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'.
-	     $session.'.id')) {
+    my $file = $perlvar{'lonIDsDir'}.'/'.$session.'.id';
+    if (open(ENVIN,"$file")) {
 	flock(ENVIN,LOCK_SH);
-	while (my $line=<ENVIN>) {
-	    my ($envname)=split(/=/,$line,2);
-	    $envname=&unescape($envname);
-	    if ($envname=~ m|^userfile\.\Q$fname\E|) { $reply="ok\n"; }
+	tie(my %disk_env,'GDBM_File',"$file",&GDBM_READER(),0640);
+	if (exists($disk_env{"userfile.$fname"})) {
+	    $reply="ok\n";
+	} else {
+	    foreach my $envname (keys(%disk_env)) {
+		if ($envname=~ m|^userfile\.\Q$fname\E|) {
+		    $reply="ok\n";
+		    last;
+		}
+	    }
 	}
+	untie(%disk_env);
 	close(ENVIN);
 	&Reply($client, $reply, "$cmd:$tail");
     } else {
@@ -2594,7 +2608,7 @@ sub get_profile_entry_encrypted {
 
     my $userinput = "$cmd:$tail";
    
-    my ($cmd,$udom,$uname,$namespace,$what) = split(/:/,$userinput);
+    my ($udom,$uname,$namespace,$what) = split(/:/,$tail);
     chomp($what);
     my $qresult = read_profile($udom, $uname, $namespace, $what);
     my ($first) = split(/:/, $qresult);
@@ -3039,10 +3053,10 @@ sub restore_handler {
     my ($cmd, $tail, $client) = @_;
 
     my $userinput = "$cmd:$tail";	# Only used for logging purposes.
-
-    my ($cmd,$udom,$uname,$namespace,$rid) = split(/:/,$userinput);
+    my ($udom,$uname,$namespace,$rid) = split(/:/,$tail);
     $namespace=~s/\//\_/g;
-    $namespace=~s/\W//g;
+    $namespace = &LONCAPA::clean_username($namespace);
+
     chomp($rid);
     my $qresult='';
     my $hashref = &tie_user_hash($udom, $uname, $namespace, &GDBM_READER());
@@ -3215,7 +3229,7 @@ sub reply_query_handler {
 
     my $userinput = "$cmd:$tail";
 
-    my ($cmd,$id,$reply)=split(/:/,$userinput); 
+    my ($id,$reply)=split(/:/,$tail); 
     my $store;
     my $execdir=$perlvar{'lonDaemons'};
     if ($store=IO::File->new(">$execdir/tmp/$id")) {
@@ -3279,13 +3293,14 @@ sub put_course_id_handler {
 	foreach my $pair (@pairs) {
             my ($key,$courseinfo) = split(/=/,$pair,2);
             $courseinfo =~ s/=/:/g;
-
-            my @current_items = split(/:/,$hashref->{$key});
+            my @current_items = split(/:/,$hashref->{$key},-1);
             shift(@current_items); # remove description
             pop(@current_items);   # remove last access
             my $numcurrent = scalar(@current_items);
-
-            my @new_items = split(/:/,$courseinfo);
+            if ($numcurrent > 3) {
+                $numcurrent = 3;
+            }
+            my @new_items = split(/:/,$courseinfo,-1);
             my $numnew = scalar(@new_items);
             if ($numcurrent > 0) {
                 if ($numnew <= $numcurrent) { # flushcourselogs() from pre 2.2 
@@ -3335,12 +3350,11 @@ sub put_course_id_handler {
 #                 institutional code - optional supplied code to filter 
 #                            the dump. Only courses with an institutional code 
 #                            that match the supplied code will be returned.
-#                 owner    - optional supplied username of owner to filter
-#                            the dump.  Only courses for which the course 
-#                            owner matches the supplied username will be
-#                            returned. Implicit assumption that owner
-#                            is a user in the domain in which the
-#                            course database is defined.
+#                 owner    - optional supplied username and domain of owner to
+#                            filter the dump.  Only courses for which the course
+#                            owner matches the supplied username and/or domain
+#                            will be returned. Pre-2.2.0 legacy entries from 
+#                            nohist_courseiddump will only contain usernames.
 #     $client  - The socket open on the client.
 # Returns:
 #    1     - Continue processing.
@@ -3352,7 +3366,7 @@ sub dump_course_id_handler {
     my $userinput = "$cmd:$tail";
 
     my ($udom,$since,$description,$instcodefilter,$ownerfilter,$coursefilter,
-        $typefilter) =split(/:/,$tail);
+        $typefilter,$regexp_ok) =split(/:/,$tail);
     if (defined($description)) {
 	$description=&unescape($description);
     } else {
@@ -3363,11 +3377,22 @@ sub dump_course_id_handler {
     } else {
         $instcodefilter='.';
     }
+    my ($ownerunamefilter,$ownerdomfilter);
     if (defined($ownerfilter)) {
         $ownerfilter=&unescape($ownerfilter);
+        if ($ownerfilter ne '.' && defined($ownerfilter)) {
+            if ($ownerfilter =~ /^([^:]*):([^:]*)$/) {
+                 $ownerunamefilter = $1;
+                 $ownerdomfilter = $2;
+            } else {
+                $ownerunamefilter = $ownerfilter;
+                $ownerdomfilter = '';
+            }
+        }
     } else {
         $ownerfilter='.';
     }
+
     if (defined($coursefilter)) {
         $coursefilter=&unescape($coursefilter);
     } else {
@@ -3378,6 +3403,9 @@ sub dump_course_id_handler {
     } else {
         $typefilter='.';
     }
+    if (defined($regexp_ok)) {
+        $regexp_ok=&unescape($regexp_ok);
+    }
 
     unless (defined($since)) { $since=0; }
     my $qresult='';
@@ -3398,14 +3426,49 @@ sub dump_course_id_handler {
             }
             unless ($instcodefilter eq '.' || !defined($instcodefilter)) {
                 my $unescapeInstcode = &unescape($inst_code);
-                unless (eval('$unescapeInstcode=~/\Q$instcodefilter\E/i')) {
-                    $match = 0;
+                if ($regexp_ok) {
+                    unless (eval('$unescapeInstcode=~/$instcodefilter/')) {
+                        $match = 0;
+                    }
+                } else {
+                    unless (eval('$unescapeInstcode=~/\Q$instcodefilter\E/i')) {
+                        $match = 0;
+                    }
                 }
 	    }
             unless ($ownerfilter eq '.' || !defined($ownerfilter)) {
                 my $unescapeOwner = &unescape($owner);
-                unless (eval('$unescapeOwner=~/\Q$ownerfilter\E/i')) {
-                    $match = 0;
+                if (($ownerunamefilter ne '') && ($ownerdomfilter ne '')) {
+                    if ($unescapeOwner =~ /:/) {
+                        if (eval('$unescapeOwner !~ 
+                             /\Q$ownerunamefilter\E:\Q$ownerdomfilter\E$/i')) {
+                            $match = 0;
+                        } 
+                    } else {
+                        if (eval('$unescapeOwner!~/\Q$ownerunamefilter\E/i')) {
+                            $match = 0;
+                        }
+                    }
+                } elsif ($ownerunamefilter ne '') {
+                    if ($unescapeOwner =~ /:/) {
+                        if (eval('$unescapeOwner!~/\Q$ownerunamefilter\E:[^:]+$/i')) {
+                             $match = 0;
+                        }
+                    } else {
+                        if (eval('$unescapeOwner!~/\Q$ownerunamefilter\E/i')) {
+                            $match = 0;
+                        }
+                    }
+                } elsif ($ownerdomfilter ne '') {
+                    if ($unescapeOwner =~ /:/) {
+                        if (eval('$unescapeOwner!~/^[^:]+:\Q$ownerdomfilter\E/')) {
+                             $match = 0;
+                        }
+                    } else {
+                        if ($ownerdomfilter ne $udom) {
+                            $match = 0;
+                        }
+                    }
                 }
             }
             unless ($coursefilter eq '.' || !defined($coursefilter)) {
@@ -3416,7 +3479,7 @@ sub dump_course_id_handler {
             }
             unless ($typefilter eq '.' || !defined($typefilter)) {
                 my $unescapeType = &unescape($type);
-                if (!defined($type)) {
+                if ($type eq '') {
                     if ($typefilter ne 'Course') {
                         $match = 0;
                     }
@@ -3448,6 +3511,99 @@ sub dump_course_id_handler {
 &register_handler("courseiddump", \&dump_course_id_handler, 0, 1, 0);
 
 #
+# Puts an unencrypted entry in a namespace db file at the domain level 
+#
+# Parameters:
+#    $cmd      - The command that got us here.
+#    $tail     - Tail of the command (remaining parameters).
+#    $client   - File descriptor connected to client.
+# Returns
+#     0        - Requested to exit, caller should shut down.
+#     1        - Continue processing.
+#  Side effects:
+#     reply is written to $client.
+#
+sub put_domain_handler {
+    my ($cmd,$tail,$client) = @_;
+
+    my $userinput = "$cmd:$tail";
+
+    my ($udom,$namespace,$what) =split(/:/,$tail,3);
+    chomp($what);
+    my @pairs=split(/\&/,$what);
+    my $hashref = &tie_domain_hash($udom, "$namespace", &GDBM_WRCREAT(),
+                                   "P", $what);
+    if ($hashref) {
+        foreach my $pair (@pairs) {
+            my ($key,$value)=split(/=/,$pair);
+            $hashref->{$key}=$value;
+        }
+        if (&untie_domain_hash($hashref)) {
+            &Reply($client, "ok\n", $userinput);
+        } else {
+            &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+                     "while attempting putdom\n", $userinput);
+        }
+    } else {
+        &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ".
+                  "while attempting putdom\n", $userinput);
+    }
+
+    return 1;
+}
+&register_handler("putdom", \&put_domain_handler, 0, 1, 0);
+
+# Unencrypted get from the namespace database file at the domain level.
+# This function retrieves a keyed item from a specific named database in the
+# domain directory.
+#
+# Parameters:
+#   $cmd             - Command request keyword (get).
+#   $tail            - Tail of the command.  This is a colon separated list
+#                      consisting of the domain and 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.
+#  Side effects:
+#     reply is written to $client.
+#
+
+sub get_domain_handler {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput = "$client:$tail";
+
+    my ($udom,$namespace,$what)=split(/:/,$tail,3);
+    chomp($what);
+    my @queries=split(/\&/,$what);
+    my $qresult='';
+    my $hashref = &tie_domain_hash($udom, "$namespace", &GDBM_READER());
+    if ($hashref) {
+        for (my $i=0;$i<=$#queries;$i++) {
+            $qresult.="$hashref->{$queries[$i]}&";
+        }
+        if (&untie_domain_hash($hashref)) {
+            $qresult=~s/\&$//;
+            &Reply($client, "$qresult\n", $userinput);
+        } else {
+            &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ".
+                      "while attempting getdom\n",$userinput);
+        }
+    } else {
+        &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+                 "while attempting getdom\n",$userinput);
+    }
+
+    return 1;
+}
+&register_handler("getdom", \&get_domain_handler, 0, 1, 0);
+
+
+#
 #  Puts an id to a domains id database. 
 #
 #  Parameters:
@@ -3818,15 +3974,23 @@ sub tmp_put_handler {
 
     my $userinput = "$cmd:$what";	# Reconstruct for logging.
 
-
-    my $store;
+    my ($record,$context) = split(/:/,$what);
+    if ($context ne '') {
+        chomp($context);
+        $context = &unescape($context);
+    }
+    my ($id,$store);
     $tmpsnum++;
-    my $id=$$.'_'.$clientip.'_'.$tmpsnum;
+    if ($context eq 'resetpw') {
+        $id = &md5_hex(&md5_hex(time.{}.rand().$$));
+    } else {
+        $id = $$.'_'.$clientip.'_'.$tmpsnum;
+    }
     $id=~s/\W/\_/g;
-    $what=~s/\n//g;
+    $record=~s/\n//g;
     my $execdir=$perlvar{'lonDaemons'};
     if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) {
-	print $store $what;
+	print $store $record;
 	close $store;
 	&Reply($client, "$id\n", $userinput);
     } else {
@@ -4043,7 +4207,8 @@ sub enrollment_enabled_handler {
     my $userinput = $cmd.":".$tail; # For logging purposes.
 
     
-    my $cdom = split(/:/, $tail);   # Domain we're asking about.
+    my ($cdom) = split(/:/, $tail, 2);   # Domain we're asking about.
+
     my $outcome  = &localenroll::run($cdom);
     &Reply($client, "$outcome\n", $userinput);
 
@@ -4099,6 +4264,7 @@ sub validate_course_owner_handler {
     my $userinput = "$cmd:$tail";
     my ($inst_course_id, $owner, $cdom) = split(/:/, $tail);
 
+    $owner = &unescape($owner);
     my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom);
     &Reply($client, "$outcome\n", $userinput);
 
@@ -4139,16 +4305,47 @@ sub validate_course_section_handler {
 &register_handler("autovalidatecourse", \&validate_course_section_handler, 0, 1, 0);
 
 #
-#   Create a password for a new auto-enrollment user.
-#   I think/guess, this password allows access to the institutions 
-#   AIS class list server/services.  Stuart can correct this comment
-#   when he finds out how wrong I am.
+#   Validate course owner's access to enrollment data for specific class section. 
+#   
+#
+# Formal Parameters:
+#    $cmd     - The command request that got us dispatched.
+#    $tail    - The tail of the command.   In this case this is a colon separated
+#               set of words that will be split into:
+#               $inst_class  - Institutional code for the specific class section   
+#               $courseowner - The escaped username:domain of the course owner 
+#               $cdom        - The domain of the course from the institution's
+#                              point of view.
+#    $client  - The socket open on the client.
+# Returns:
+#    1 - continue processing.
+#
+
+sub validate_class_access_handler {
+    my ($cmd, $tail, $client) = @_;
+    my $userinput = "$cmd:$tail";
+    my ($inst_class,$courseowner,$cdom) = split(/:/, $tail);
+    $courseowner = &unescape($courseowner);
+    my $outcome;
+    eval {
+	local($SIG{__DIE__})='DEFAULT';
+	$outcome=&localenroll::check_section($inst_class,$courseowner,$cdom);
+    };
+    &Reply($client,"$outcome\n", $userinput);
+
+    return 1;
+}
+&register_handler("autovalidateclass_sec", \&validate_class_access_handler, 0, 1, 0);
+
+#
+#   Create a password for a new LON-CAPA user added by auto-enrollment.
+#   Only used for case where authentication method for new user is localauth
 #
 # Formal Parameters:
 #    $cmd     - The command request that got us dispatched.
 #    $tail    - The tail of the command.   In this case this is a colon separated
 #               set of words that will be split into:
-#               $authparam - An authentication parameter (username??).
+#               $authparam - An authentication parameter (localauth parameter).
 #               $cdom      - The domain of the course from the institution's
 #                            point of view.
 #    $client  - The socket open on the client.
@@ -4275,6 +4472,38 @@ sub get_institutional_code_format_handle
 &register_handler("autoinstcodeformat",
 		  \&get_institutional_code_format_handler,0,1,0);
 
+sub get_institutional_defaults_handler {
+    my ($cmd, $tail, $client)   = @_;
+    my $userinput               = "$cmd:$tail";
+
+    my $dom = $tail;
+    my %defaults_hash;
+    my @code_order;
+    my $outcome;
+    eval {
+        local($SIG{__DIE__})='DEFAULT';
+        $outcome = &localenroll::instcode_defaults($dom,\%defaults_hash,
+                                                   \@code_order);
+    };
+    if (!$@) {
+        if ($outcome eq 'ok') {
+            my $result='';
+            while (my ($key,$value) = each(%defaults_hash)) {
+                $result.=&escape($key).'='.&escape($value).'&';
+            }
+            $result .= 'code_order='.&escape(join('&',@code_order));
+            &Reply($client,$result."\n",$userinput);
+        } else {
+            &Reply($client,"error\n", $userinput);
+        }
+    } else {
+        &Failure($client,"unknown_cmd\n",$userinput);
+    }
+}
+&register_handler("autoinstcodedefaults",
+                  \&get_institutional_defaults_handler,0,1,0);
+
+
 # Get domain specific conditions for import of student photographs to a course
 #
 # Retrieves information from photo_permission subroutine in localenroll.
@@ -4402,6 +4631,31 @@ sub student_photo_handler {
 }
 &register_handler("studentphoto", \&student_photo_handler, 0, 1, 0);
 
+sub inst_usertypes_handler {
+    my ($cmd, $domain, $client) = @_;
+    my $res;
+    my $userinput = $cmd.":".$domain; # For logging purposes.
+    my (%typeshash,@order);  
+    if (&localenroll::inst_usertypes($domain,\%typeshash,\@order) eq 'ok') {
+        if (keys(%typeshash) > 0) {
+            foreach my $key (keys(%typeshash)) {
+                $res.=&escape($key).'='.&escape($typeshash{$key}).'&';
+            }
+        }
+        $res=~s/\&$//;
+        $res .= ':';
+        if (@order > 0) {
+            foreach my $item (@order) {
+                $res .= &escape($item).'&';
+            }
+        }
+        $res=~s/\&$//;
+    }
+    &Reply($client, "$res\n", $userinput);
+    return 1;
+}
+&register_handler("inst_usertypes", \&inst_usertypes_handler, 0, 1, 0);
+
 # mkpath makes all directories for a file, expects an absolute path with a
 # file or a trailing / if just a dir is passed
 # returns 1 on success 0 on failure
@@ -5055,15 +5309,36 @@ sub reconlonc {
     }
 }
 
-# -------------------------------------------------- Non-critical communication
+sub create_connection {
+    my ($server) = @_;
+    my $client=IO::Socket::UNIX->new(Peer    => $perlvar{'lonSockCreate'},
+				     Type    => SOCK_STREAM,
+				     Timeout => 10);
+    return 0 if (!$client);
+    print $client ("$server\n");
+    my $result = <$client>;
+    chomp($result);
+    return 1 if ($result eq 'done');
+    return 0;
+}
 
+# -------------------------------------------------- Non-critical communication
+my $max_connection_retries = 10;
 sub subreply {
     my ($cmd,$server)=@_;
     my $peerfile="$perlvar{'lonSockDir'}/".$hostname{$server};
-    my $sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
-                                      Type    => SOCK_STREAM,
-                                      Timeout => 10)
-       or return "con_lost";
+    my $sclient;
+    for (my $retries = 0; $retries < $max_connection_retries; $retries++) {
+	$sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
+				       Type    => SOCK_STREAM,
+				       Timeout => 10);
+	if($sclient) {
+	    last;		# Connected!
+	} else {
+	    &create_connection($hostname{$server});
+	}
+        sleep(1);		# Try again later if failed connection.
+    }
     print $sclient "sethost:$server:$cmd\n";
     my $answer=<$sclient>;
     chomp($answer);
@@ -5238,7 +5513,8 @@ sub make_new_child {
 #        my $tmpsnum=0;            # Now global
 #---------------------------------------------------- kerberos 5 initialization
         &Authen::Krb5::init_context();
-	unless (($dist eq 'fedora4') || ($dist eq 'suse9.3')) {
+	unless (($dist eq 'fedora5') || ($dist eq 'fedora4') ||  
+		($dist eq 'fedora6') || ($dist eq 'suse9.3')) {
 	    &Authen::Krb5::init_ets();
 	}
 
@@ -5279,7 +5555,7 @@ sub make_new_child {
 	    my $remotereq=<$client>;
 	    chomp($remotereq);
 	    Debug("Got init: $remotereq");
-	    my $inikeyword = split(/:/, $remotereq);
+
 	    if ($remotereq =~ /^init/) {
 		&sethost("sethost:$perlvar{'lonHostID'}");
 		#
@@ -5651,7 +5927,8 @@ sub validate_user {
 		my $krbservice = "krbtgt/".$contentpwd."\@".$contentpwd;
 		my $krbserver  = &Authen::Krb5::parse_name($krbservice);
 		my $credentials= &Authen::Krb5::cc_default();
-		$credentials->initialize($krbclient);
+		$credentials->initialize(&Authen::Krb5::parse_name($user.'@'
+                                                                 .$contentpwd));
 		my $krbreturn  = &Authen::Krb5::get_in_tkt_with_password($krbclient,
 									 $krbserver,
 									 $password,
@@ -5664,7 +5941,12 @@ sub validate_user {
 	    #  Authenticate via installation specific authentcation method:
 	    $validated = &localauth::localauth($user, 
 					       $password, 
-					       $contentpwd);
+					       $contentpwd,
+					       $domain);
+	    if ($validated < 0) {
+		&logthis("localauth for $contentpwd $user:$domain returned a $validated");
+		$validated = 0;
+	    }
 	} else {			# Unrecognized auth is also bad.
 	    $validated = 0;
 	}
@@ -5690,8 +5972,7 @@ sub addline {
     my ($fname,$hostid,$ip,$newline)=@_;
     my $contents;
     my $found=0;
-    my $expr='^'.$hostid.':'.$ip.':';
-    $expr =~ s/\./\\\./g;
+    my $expr='^'.quotemeta($hostid).':'.quotemeta($ip).':';
     my $sh;
     if ($sh=IO::File->new("$fname.subscription")) {
 	while (my $subline=<$sh>) {
@@ -5712,7 +5993,7 @@ sub get_chat {
     my @entries=();
     my $namespace = 'nohist_chatroom';
     my $namespace_inroom = 'nohist_inchatroom';
-    if (defined($group)) {
+    if ($group ne '') {
         $namespace .= '_'.$group;
         $namespace_inroom .= '_'.$group;
     }
@@ -5744,7 +6025,7 @@ sub chat_add {
     my $time=time;
     my $namespace = 'nohist_chatroom';
     my $logfile = 'chatroom.log';
-    if (defined($group)) {
+    if ($group ne '') {
         $namespace .= '_'.$group;
         $logfile = 'chatroom_'.$group.'.log';
     }