--- loncom/lond	2006/10/13 04:23:02	1.344
+++ loncom/lond	2006/11/27 22:51:14	1.351
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.344 2006/10/13 04:23:02 raeburn Exp $
+# $Id: lond,v 1.351 2006/11/27 22:51:14 banghart Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -40,6 +40,7 @@ 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;
@@ -59,7 +60,7 @@ my $DEBUG = 0;		       # Non zero to ena
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.344 $'; #' stupid emacs
+my $VERSION='$Revision: 1.351 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -1574,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.
 	
@@ -1603,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);
@@ -3045,10 +3053,10 @@ sub restore_handler {
     my ($cmd, $tail, $client) = @_;
 
     my $userinput = "$cmd:$tail";	# Only used for logging purposes.
-
     my ($udom,$uname,$namespace,$rid) = split(/:/,$tail);
+    $namespace = &LONCAPA::clean_username($namespace);
     $namespace=~s/\//\_/g;
-    $namespace=~s/\W//g;
+
     chomp($rid);
     my $qresult='';
     my $hashref = &tie_user_hash($udom, $uname, $namespace, &GDBM_READER());
@@ -3502,6 +3510,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_id_handler, 0, 1, 0);
+
+
+#
 #  Puts an id to a domains id database. 
 #
 #  Parameters:
@@ -3872,15 +3973,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 {
@@ -4362,6 +4471,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.
@@ -5325,7 +5466,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 'suse9.3')) {
 	    &Authen::Krb5::init_ets();
 	}