[LON-CAPA-cvs] cvs: loncom(Refactoring) / lond

foxr lon-capa-cvs@mail.lon-capa.org
Tue, 23 Mar 2004 11:50:12 -0000


This is a MIME encoded message

--foxr1080042612
Content-Type: text/plain

foxr		Tue Mar 23 06:50:12 2004 EDT

  Modified files:              (Branch: Refactoring)
    /loncom	lond 
  Log:
  Clean compile after refactoring the hell out of the authentication based 
  functions.
  
  
--foxr1080042612
Content-Type: text/plain
Content-Disposition: attachment; filename="foxr-20040323065012.txt"

Index: loncom/lond
diff -u loncom/lond:1.178.2.12 loncom/lond:1.178.2.13
--- loncom/lond:1.178.2.12	Mon Mar 22 05:02:24 2004
+++ loncom/lond	Tue Mar 23 06:50:12 2004
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.178.2.12 2004/03/22 10:02:24 foxr Exp $
+# $Id: lond,v 1.178.2.13 2004/03/23 11:50:12 foxr Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -53,7 +53,7 @@
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.178.2.12 $'; #' stupid emacs
+my $VERSION='$Revision: 1.178.2.13 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid;
 my $currentdomainid;
@@ -237,7 +237,7 @@
     $namespace=~s/\//\_/g;	# / -> _
     $namespace=~s/\W//g;		# whitespace eliminated.
     my $proname     = propath($domain, $user);
-    
+   
     # If this is a namespace for which a history is kept,
     # make the history log entry:
     
@@ -739,106 +739,16 @@
     chomp($upass);
     $upass=unescape($upass);
 
-    # Fetch the user authentication information:
-   
-    my $realpasswd = GetAuthType($udom, $uname);
-    if($realpasswd ne "nouser") { # nouser means no passwd file.
-	my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
-	my $pwdcorrect=0;
-	#
-	#   Authenticate against password stored in the internal file.
-	#
-	Debug("Authenticating via $howpwd");
-	if ($howpwd eq 'internal') {
-	    &Debug("Internal auth");
-	    $pwdcorrect= (crypt($upass,$contentpwd) eq $contentpwd);
-	    #
-	    #   Authenticate against the unix password file.
-	    #
-	} elsif ($howpwd eq 'unix') {
-	    &Debug("Unix auth");
-	    if((getpwnam($uname))[1] eq "") { #no such user!
-		$pwdcorrect = 0;
-	    } else {
-		$contentpwd=(getpwnam($uname))[1];
-		my $pwauth_path="/usr/local/sbin/pwauth";
-		unless ($contentpwd eq 'x') { # Not in shadow file.
-		    $pwdcorrect= (crypt($upass,$contentpwd) eq $contentpwd);
-		} elsif (-e $pwauth_path) { # In shadow file so
-		    open PWAUTH, "|$pwauth_path" or # use external program
-			die "Cannot invoke authentication";
-		    print PWAUTH "$uname\n$upass\n";
-		    close PWAUTH;
-		    $pwdcorrect=!$?;
-		}
-	    }
-	    #
-	    #   Authenticate against a Kerberos 4 server:
-	    #
-	} elsif ($howpwd eq 'krb4') {
-	    my $null=pack("C",0);
-	    unless ($upass=~/$null/) {
-		my $krb4_error = &Authen::Krb4::get_pw_in_tkt($uname,
-							      "",
-							      $contentpwd,
-							      'krbtgt',
-							      $contentpwd,
-							      1,
-							      $upass);
-		if (!$krb4_error) {
-		    $pwdcorrect = 1;
-		} else { 
-		    $pwdcorrect=0; 
-		    # log error if it is not a bad password
-		    if ($krb4_error != 62) {
-			&logthis('krb4:'.$uname.','.$contentpwd.','.
-				 &Authen::Krb4::get_err_txt($Authen::Krb4::error));
-		    }
-		}
-	    }
-	    #
-	    #   Authenticate against a Kerberos 5 server:
-	    #
-	} elsif ($howpwd eq 'krb5') {
-	    my $null=pack("C",0);
-	    unless ($upass=~/$null/) {
-		my $krbclient=&Authen::Krb5::parse_name($uname.'@'.$contentpwd);
-		my $krbservice="krbtgt/".$contentpwd."\@".$contentpwd;
-		my $krbserver=&Authen::Krb5::parse_name($krbservice);
-		my $credentials=&Authen::Krb5::cc_default();
-		$credentials->initialize($krbclient);
-		my $krbreturn = &Authen::Krb5::get_in_tkt_with_password($krbclient,
-									$krbserver,
-									$upass,
-									$credentials);
-		$pwdcorrect = ($krbreturn == 1);
-	    } else { 
-		$pwdcorrect=0; 
-	    }
-	    #
-	    #  Finally, the user may have written in an authentication module.
-	    #  in that case, if requested, authenticate against it.
-	    #
-	} elsif ($howpwd eq 'localauth') {
-	    $pwdcorrect=&localauth::localauth($uname,$upass,$contentpwd);
-	}
+    my $pwdcorrect = ValidateUser($udom, $uname, $upass);
+    if($pwdcorrect) {
+	Reply( $client, "authorized\n", $userinput);
 	#
-	#   Successfully authorized.
+	#  Bad credentials: Failed to authorize
 	#
-	if ($pwdcorrect) {
-	    Reply( $client, "authorized\n", $userinput);
-	    #
-	    #  Bad credentials: Failed to authorize
-	    #
-	} else {
-	    Failure( $client, "non_authorized\n", $userinput);
-	}
-	#  Used to be unknown_user but that allows crackers to 
-	#  distinguish between bad username and bad password so...
-	#  
     } else {
 	Failure( $client, "non_authorized\n", $userinput);
     }
+
     return 1;
 }
 RegisterHandler("auth", \&AuthenticateHandler, 1, 1, 0);
@@ -882,62 +792,44 @@
     $upass=&unescape($upass);
     $npass=&unescape($npass);
     &Debug("Trying to change password for $uname");
-    my $realpasswd  = GetAuthType($udom, $uname);
-    if ($realpasswd ne "nouser") {
+
+    # First require that the user can be authenticated with their
+    # old password:
+
+    my $validated = ValidUser($udom, $uname, $upass);
+    if($validated) {
+	my $realpasswd  = GetAuthType($udom, $uname); # Defined since authd.
+	
 	my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
 	if ($howpwd eq 'internal') {
 	    &Debug("internal auth");
-	    if (crypt($upass,$contentpwd) eq $contentpwd) {
-		my $salt=time;
-		$salt=substr($salt,6,2);
-		my $ncpass=crypt($npass,$salt);
-		if(RewritePwFile($udom, $uname, "internal:$ncpass")) {
-		    &logthis("Result of password change for "
-			     ."$uname: pwchange_success");
-		    Reply($client, "ok\n", $userinput);
-		} else {
-		    &logthis("Unable to open $uname passwd "               
-			     ."to change password");
-		    Failure( $client, "non_authorized\n",$userinput);
-		}
+	    my $salt=time;
+	    $salt=substr($salt,6,2);
+	    my $ncpass=crypt($npass,$salt);
+	    if(RewritePwFile($udom, $uname, "internal:$ncpass")) {
+		&logthis("Result of password change for "
+			 ."$uname: pwchange_success");
+		Reply($client, "ok\n", $userinput);
 	    } else {
-		Failure($client, "non_authorized\n", $userinput);
+		&logthis("Unable to open $uname passwd "               
+			 ."to change password");
+		Failure( $client, "non_authorized\n",$userinput);
 	    }
 	} elsif ($howpwd eq 'unix') {
 	    # Unix means we have to access /etc/password
-	    # one way or another.
-	    # First: Make sure the current password is
-	    #        correct
 	    &Debug("auth is unix");
-	    $contentpwd=(getpwnam($uname))[1];
-	    my $pwdcorrect = "0";
-	    my $pwauth_path="/usr/local/sbin/pwauth";
-	    unless ($contentpwd eq 'x') {
-		$pwdcorrect= (crypt($upass,$contentpwd) eq $contentpwd);
-	    } elsif (-e $pwauth_path) {
-		open PWAUTH, "|$pwauth_path" or
-		    die "Cannot invoke authentication";
-		print PWAUTH "$uname\n$upass\n";
-		close PWAUTH;
-		&Debug("exited pwauth with $? ($uname,$upass) ");
-		$pwdcorrect=($? == 0);
-	    }
-	    if ($pwdcorrect) {
-		my $execdir=$perlvar{'lonDaemons'};
-		&Debug("Opening lcpasswd pipeline");
-		my $pf = IO::File->new("|$execdir/lcpasswd > "
-				       ."$perlvar{'lonDaemons'}"
-				       ."/logs/lcpasswd.log");
-		print $pf "$uname\n$npass\n$npass\n";
-		close $pf;
-		my $err = $?;
-		my $result = ($err>0 ? 'pwchange_failure' : 'ok');
-		&logthis("Result of password change for $uname: ".
-			 &lcpasswdstrerror($?));
-		Reply($client, "$result\n", $userinput);
-	    } else {
-		Reply($client, "non_authorized\n", $userinput);
-	    }
+	    my $execdir=$perlvar{'lonDaemons'};
+	    &Debug("Opening lcpasswd pipeline");
+	    my $pf = IO::File->new("|$execdir/lcpasswd > "
+				   ."$perlvar{'lonDaemons'}"
+				   ."/logs/lcpasswd.log");
+	    print $pf "$uname\n$npass\n$npass\n";
+	    close $pf;
+	    my $err = $?;
+	    my $result = ($err>0 ? 'pwchange_failure' : 'ok');
+	    &logthis("Result of password change for $uname: ".
+		     &lcpasswdstrerror($?));
+	    Reply($client, "$result\n", $userinput);
 	} else {
 	    # this just means that the current password mode is not
 	    # one we know how to change (e.g the kerberos auth modes or
@@ -945,12 +837,12 @@
 	    #
 	    Reply( $client, "auth_mode_error\n", $userinput);
 	}  
-    } else {
-	#  used to be unknonw user but that gives out too much info..
-	#  so make it the same as if the initial passwd was bad.
-	#
+	
+    }
+    else {
 	Reply( $client, "non_authorized\n", $userinput);
     }
+
     return 1;
 }
 RegisterHandler("passwd", \&ChangePasswordHandler, 1, 1, 0);
@@ -1308,7 +1200,7 @@
 }
 RegisterHandler("unusb", \&UnsubscribeHandler, 0, 1, 0);
 
-#   Subscribe to a resource.
+#   Subscribe to a resource
 #
 # Parameters:
 #    $cmd      - The command that got us here.
@@ -4247,6 +4139,135 @@
     }
 }
 
+#
+#  Validate a user given their domain, name and password.  This utility
+#  function is used by both  AuthenticateHandler and ChangePasswordHandler
+#  to validate the login credentials of a user.
+# Parameters:
+#    $domain    - The domain being logged into (this is required due to
+#                 the capability for multihomed systems.
+#    $user      - The name of the user being validated.
+#    $password  - The user's propoposed password.
+#
+# Returns:
+#     1        - The domain,user,pasword triplet corresponds to a valid
+#                user.
+#     0        - The domain,user,password triplet is not a valid user.
+#
+sub ValidateUser {
+    my $domain  = shift;
+    my $user    = shift;
+    my $password= shift;
+
+    # Why negative ~pi you may well ask?  Well this function is about
+    # authentication, and therefore very important to get right.
+    # I've initialized the flag that determines whether or not I've 
+    # validated correctly to a value it's not supposed to get.
+    # At the end of this function. I'll ensure that it's not still that
+    # value so we don't just wind up returning some accidental value
+    # as a result of executing an unforseen code path that
+    # did not set $validated.
+
+    my $validated = -3.14159;
+
+    #  How we authenticate is determined by the type of authentication
+    #  the user has been assigned.  If the authentication type is
+    #  "nouser", the user does not exist so we will return 0.
+
+    my $contents = GetAuthType($domain, $user);
+    my ($howpwd, $contentpwd) = split(/:/, $contents);
+
+    my $null = pack("C",0);	# Used by kerberos auth types.
+
+    if ($howpwd ne 'nouser') {
+
+	if($howpwd eq "internal") { # Encrypted is in local password file.
+	    $validated = (crypt($password, $contentpwd) eq $contentpwd);
+	}
+	elsif ($howpwd eq "unix") { # User is a normal unix user.
+	    $contentpwd = (getpwname($user))[1];
+	    if($contentpwd) {
+		if($contentpwd eq 'x') { # Shadow password file...
+		    my $pwauth_path = "/usr/local/sbin/pwauth";
+		    open PWAUTH,  "|$pwauth_path" or
+			die "Cannot invoke authentication";
+		    print PWAUTH "$user\n$password\n";
+		    close PWAUTH;
+		    $validated = ! $?;
+
+		} else { 	         # Passwords in /etc/passwd. 
+		    $validated = (crypt($password,
+					$contentpwd) eq $contentpwd);
+		}
+	    } else {
+		$validated = 0;
+	    }
+	}
+	elsif ($howpwd eq "krb4") { # user is in kerberos 4 auth. domain.
+	    if(! ($password =~ /$null/) ) {
+		my $k4error = &Authen::Krb4::get_pw_in_tkt($user,
+							   "",
+							   $contentpwd,,
+							   'krbtgt',
+							   $contentpwd,
+							   1,
+							   $password);
+		if(!$k4error) {
+		    $validated = 1;
+		}
+		else {
+		    $validated = 0;
+		    &logthis('krb4: '.$user.', '.$contentpwd.', '.
+			     &Authen::Krb4::get_err_txt($Authen::Krb4::error));
+		}
+	    }
+	    else {
+		$validated = 0; # Password has a match with null.
+	    }
+	}
+	elsif ($howpwd eq "krb5") { # User is in kerberos 5 auth. domain.
+	    if(!($password =~ /$null/)) { # Null password not allowed.
+		my $krbclient = &Authen::Krb5::parse_name($user.'@'
+							  .$contentpwd);
+		my $krbservice = "krbtgt/".$contentpwd."\@".$contentpwd;
+		my $krbserver  = &Authen::Krb5::parse_name($krbservice);
+		my $credentials= &Authen::Krb5::cc_default();
+		$credentials->initialize($krbclient);
+		my $krbreturn  = &Authen::KRb5::get_in_tkt_with_password($krbclient,
+									 $krbserver,
+									 $password,
+									 $credentials);
+		$validated = ($krbreturn == 1);
+	    }
+	    else {
+		$validated = 0;
+	    }
+	}
+	elsif ($howpwd eq "localauth") { 
+	    #  Authenticate via installation specific authentcation method:
+	    $validated = &localauth::localauth($user, 
+					       $password, 
+					       $contentpwd);
+	}
+	else {			# Unrecognized auth is also bad.
+	    $validated = 0;
+	}
+    } else {
+	$validated = 0;
+    }
+    #
+    #  $validated has the correct stat of the authentication:
+    #
+
+    unless ($validated != -3.14159) {
+	die "ValidateUser - failed to set the value of validated";
+    }
+    return $validated;
+}
+
+#
+#    Add a line to the subscription list?
+#
 sub addline {
     my ($fname,$hostid,$ip,$newline)=@_;
     my $contents;
@@ -4266,7 +4287,9 @@
     $sh->close();
     return $found;
 }
-
+#
+#    Get chat messages.
+#
 sub getchat {
     my ($cdom,$cname,$udom,$uname)=@_;
     my %hash;
@@ -4291,7 +4314,9 @@
     }
     return (@participants,@entries);
 }
-
+#
+#   Add a chat message
+#
 sub chatadd {
     my ($cdom,$cname,$newchat)=@_;
     my %hash;

--foxr1080042612--