--- /usr/local/lib/perl5/site_perl/5.8.7/Apache/AuthDBI.pm-dist	Fri Aug 19 18:34:57 2005
+++ /usr/local/lib/perl5/site_perl/5.8.7/Apache/AuthDBI.pm	Tue Mar 28 21:17:39 2006
@@ -61,6 +61,7 @@
     'Auth_DBI_uidcasesensitive' => 'on',
     'Auth_DBI_pwdcasesensitive' => 'on',
     'Auth_DBI_placeholder'      => 'off',
+    'Auth_DBI_expeditive'       => 'off',
 );
 
 # stores the configuration of current URL.
@@ -203,7 +204,7 @@
         print STDERR "==========\n$prefix request type = >$type< \n";
     }
 
-    return MP2 ? Apache2::Const::OK() : Apache::Constants::OK() unless $r->is_initial_req; # only the first internal request
+    return (MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) unless $r->is_initial_req; # only the first internal request
 
     print STDERR "REQUEST:\n", $r->as_string if $Apache::AuthDBI::DEBUG > 1;
 
@@ -241,11 +242,11 @@
     # if not configured decline
     unless ($Attr->{pwd_table} && $Attr->{uid_field} && $Attr->{pwd_field}) {
         print STDERR "$prefix not configured, return DECLINED\n" if $Apache::AuthDBI::DEBUG > 1;
-        return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+        return (MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED());
     }
 
     # do we want Windows-like case-insensitivity?
-    $user_sent   = lc($user_sent)   if $Attr->{uidcasesensitive} eq "off";
+    $user_sent   = lc($user_sent)   if $Attr->{uidcasesensitive} eq "off" or $Attr->{uidcasesensitive} eq "offkludge";
     $passwd_sent = lc($passwd_sent) if $Attr->{pwdcasesensitive} eq "off";
 
     # check whether the user is cached but consider that the password possibly has changed
@@ -290,49 +291,59 @@
         }
         unless ($dbh) {
             $r->log_reason("$prefix db connect error with data_source >$Attr->{data_source}<: $DBI::errstr", $r->uri);
-            return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+            return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
         }
 
         # generate statement
-        my $user_sent_quoted = $dbh->quote($user_sent);
-        my $select    = "SELECT $Attr->{pwd_field}";
+        my $user_sent_quoted = $dbh->quote($user_sent) unless $Attr->{placeholder} eq "on";
+        my $select    = "SELECT $Attr->{pwd_field}, $Attr->{uid_field}";
         my $from      = "FROM $Attr->{pwd_table}";
-        my $where     = ($Attr->{uidcasesensitive} eq "off") ? "WHERE lower($Attr->{uid_field}) =" : "WHERE $Attr->{uid_field} =";
-        my $compare   = ($Attr->{placeholder}      eq "on")  ? "?" : "$user_sent_quoted";
+        my $where     = ($Attr->{uidcasesensitive} eq "offkludge" ? "WHERE LOWER($Attr->{uid_field}) =" : "WHERE $Attr->{uid_field} =");
+        my $compare   = ($Attr->{placeholder} eq "on" ? "?" : $user_sent_quoted);
         my $statement = "$select $from $where $compare";
-        $statement   .= " AND $Attr->{pwd_whereclause}" if $Attr->{pwd_whereclause};
+        $statement   .= " AND ($Attr->{pwd_whereclause})" if $Attr->{pwd_whereclause};
         print STDERR "$prefix statement: $statement\n" if $Apache::AuthDBI::DEBUG > 1;
+        print STDERR "$prefix placeholder:  $user_sent_quoted\n" if $Apache::AuthDBI::DEBUG > 1 and $Attr->{placeholder} eq "on";
 
         # prepare statement
         my $sth;
         unless ($sth = $dbh->prepare($statement)) {
             $r->log_reason("$prefix can not prepare statement: $DBI::errstr", $r->uri);
             $dbh->disconnect;
-            return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+            return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
         }
 
         # execute statement
         my $rv;
-        unless ($rv = ($Attr->{placeholder} eq "on") ? $sth->execute($user_sent) : $sth->execute) {
+        unless ($rv = ($Attr->{placeholder} eq "on" ? $sth->execute($user_sent) : $sth->execute)) {
             $r->log_reason("$prefix can not execute statement: $DBI::errstr", $r->uri);
             $dbh->disconnect;
-            return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+            return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
         }
 
         # fetch result
-        while ($_ = $sth->fetchrow_array) {
+        while (my ($pwd, $uid) = $sth->fetchrow_array) {
+            # The select may not be case-sensitive.
+            next if $Attr->{uidcasesensitive} eq "on" and $uid ne $user_sent;
+
+            next unless defined $pwd;
+
             # strip trailing blanks for fixed-length data-type
-            $_ =~ s/ +$// if $_;
+            $pwd =~ s/ +$//;
+
+            # do we want Windows-like case-insensitivity?
+            $pwd = lc $pwd if $Attr->{pwdcasesensitive} eq 'off';
+
             # consider the case with many users sharing the same userid
-	    $passwd .= "$_$;";
+            $passwd .= "$pwd$;";
         }
 
+        undef $passwd if $passwd eq ''; # so we can distinguish later on between no password and empty password
         chop  $passwd if $passwd;
-        undef $passwd if 0 == $sth->rows; # so we can distinguish later on between no password and empty password
 
         if ($sth->err) {
             $dbh->disconnect;
-            return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+            return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
         }
         $sth->finish;
 
@@ -349,23 +360,23 @@
         if ($Attr->{authoritative} eq 'on') {
             $r->log_reason("$prefix password for user $user_sent not found", $r->uri);
             $r->note_basic_auth_failure;
-            return MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED();
+            return (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED());
         } else {
             # else pass control to the next authentication module
-            return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+            return (MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED());
         }
     }
 
     # allow any password if nopasswd = on and the retrieved password is empty
     if ($Attr->{nopasswd} eq 'on' && !$passwd) {
-        return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+        return (MP2 ? Apache2::Const::OK() : Apache::Constants::OK());
     }
 
     # if nopasswd is off, reject user
     unless ($passwd_sent && $passwd) {
         $r->log_reason("$prefix user $user_sent: empty password(s) rejected", $r->uri);
         $r->note_basic_auth_failure;
-        return MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED();
+        return (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED());
     }
 
     # compare passwords
@@ -414,7 +425,7 @@
     unless ($found) {
         $r->log_reason("$prefix user $user_sent: password mismatch", $r->uri);
         $r->note_basic_auth_failure;
-        return MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED();
+        return (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED());
     }
 
     # logging option
@@ -429,7 +440,7 @@
             }
             unless ($connect) {
                 $r->log_reason("$prefix db connect error with $Attr->{data_source}", $r->uri);
-                return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+                return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
             }
         }
         my $user_sent_quoted = $dbh->quote($user_sent);
@@ -438,7 +449,7 @@
         unless ($dbh->do($statement)) {
             $r->log_reason("$prefix can not do statement: $DBI::errstr", $r->uri);
             $dbh->disconnect;
-            return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+            return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
         }
         $dbh->disconnect;
     }
@@ -456,7 +467,7 @@
     }
 
     print STDERR "$prefix return OK\n" if $Apache::AuthDBI::DEBUG > 1;
-    return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+    return (MP2 ? Apache2::Const::OK() : Apache::Constants::OK());
 }
 
 #Encrypts a password in all supported/requested methods and passes back array for comparison
@@ -478,7 +489,7 @@
     }
     #CRYPT
     if ($Attr->{encryption_method} =~ /(^|\/)crypt($|\/)/i) {
-      $salt = $Attr->{encryption_salt} eq 'userid' ? $params{'user_sent'} : $params{'password'};
+      $salt = ($Attr->{encryption_salt} eq 'userid' ? $params{'user_sent'} : $params{'password'});
       #Bug Fix in v0.94 (marked as 0.93 in file.  salt was NOT being sent to crypt) - KAM - 06-16-2005
       push (@passwds_to_check, crypt($params{'passwd_sent'}, $salt));
     }
@@ -516,11 +527,11 @@
     }
 
     unless ($r->is_initial_req) {
-      return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+      return (MP2 ? Apache2::Const::OK() : Apache::Constants::OK());
     }; # only the first internal request
 
-    my ($user_result)  = MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
-    my ($group_result) = MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+    my ($user_result)  = (MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED());
+    my ($group_result) = (MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED());
 
     # get username
     my ($user_sent) = $r->user;
@@ -537,18 +548,18 @@
     # if not configured decline
     unless ($Attr->{pwd_table} && $Attr->{uid_field} && $Attr->{grp_field}) {
         print STDERR "$prefix not configured, return DECLINED\n" if $Apache::AuthDBI::DEBUG > 1;
-        return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+        return (MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED());
     }
 
     # do we want Windows-like case-insensitivity?
-    $user_sent = lc($user_sent) if $Attr->{uidcasesensitive} eq "off";
+    $user_sent = lc($user_sent) if $Attr->{uidcasesensitive} eq "off" or $Attr->{uidcasesensitive} eq "offkludge";
 
     # select code to return if authorization is denied:
     my ($authz_denied);
     if (MP2) {
-      $authz_denied = $Attr->{expeditive} eq 'on' ? Apache2::Const::FORBIDDEN() : Apache2::Const::AUTH_REQUIRED();
+      $authz_denied = ($Attr->{expeditive} eq 'on' ? Apache2::Const::FORBIDDEN() : Apache2::Const::AUTH_REQUIRED());
     } else {
-      $authz_denied = $Attr->{expeditive} eq 'on' ? Apache::Constants::FORBIDDEN() : Apache::Constants::AUTH_REQUIRED();
+      $authz_denied = ($Attr->{expeditive} eq 'on' ? Apache::Constants::FORBIDDEN() : Apache::Constants::AUTH_REQUIRED());
     }
 
     # check if requirements exists
@@ -556,13 +567,13 @@
     unless ($ary_ref) {
         if ($Attr->{authoritative} eq 'on') {
             $r->log_reason("user $user_sent denied, no access rules specified (DBI-Authoritative)", $r->uri);
-            if ($authz_denied == MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED()) {
+            if ($authz_denied == (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED())) {
               $r->note_basic_auth_failure;
             }
             return $authz_denied;
         }
         print STDERR "$prefix no requirements and not authoritative, return DECLINED\n" if $Apache::AuthDBI::DEBUG > 1;
-        return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+        return (MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED());
     }
 
     # iterate over all requirement directives and store them according to their type (valid-user, user, group)
@@ -581,32 +592,32 @@
             $group_requirements .= " $val";
         }
     }
-    $user_requirements  =~ s/^ //go;
-    $group_requirements =~ s/^ //go;
+    $user_requirements  =~ s/^ //go if defined $user_requirements;
+    $group_requirements =~ s/^ //go if defined $group_requirements;
     print STDERR "$prefix requirements: valid-user=>$valid_user< user=>$user_requirements< group=>$group_requirements< \n"  if $Apache::AuthDBI::DEBUG > 1;
 
     # check for valid-user
     if ($valid_user) {
-        $user_result = MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+        $user_result = (MP2 ? Apache2::Const::OK() : Apache::Constants::OK());
         print STDERR "$prefix user_result = OK: valid-user\n" if $Apache::AuthDBI::DEBUG > 1;
     }
 
     # check for users
-    if (($user_result != MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) && $user_requirements) {
-        $user_result = MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED();
+    if ($user_result != (MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) && $user_requirements) {
+        $user_result = (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED());
         my $user_required;
         foreach $user_required (split /\s+/, $user_requirements) {
             if ($user_required eq $user_sent) {
                 print STDERR "$prefix user_result = OK for $user_required \n" if $Apache::AuthDBI::DEBUG > 1;
-                $user_result = MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+                $user_result = (MP2 ? Apache2::Const::OK() : Apache::Constants::OK());
                 last;
            }
         }
     }
 
     # check for groups
-    if (($user_result != MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) && $group_requirements) {
-        $group_result = MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED();
+    if ($user_result != (MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) && $group_requirements) {
+        $group_result = (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED());
         my ($group, $group_required);
 
         # check whether the user is cached but consider that the group possibly has changed
@@ -646,38 +657,42 @@
             }
             unless ($connect) {
                 $r->log_reason("$prefix db connect error with $Attr->{data_source}", $r->uri);
-                return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+                return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
             }
 
             # generate statement
-            my $user_sent_quoted = $dbh->quote($user_sent);
-            my $select    = "SELECT $Attr->{grp_field}";
-            my $from      = ($Attr->{grp_table}) ? "FROM $Attr->{grp_table}" : "FROM $Attr->{pwd_table}";
-            my $where     = ($Attr->{uidcasesensitive} eq "off") ? "WHERE lower($Attr->{uid_field}) =" : "WHERE $Attr->{uid_field} =";
-            my $compare   = ($Attr->{placeholder}      eq "on")  ? "?" : "$user_sent_quoted";
+            my $user_sent_quoted = $dbh->quote($user_sent) unless $Attr->{placeholder} eq "on";
+            my $select    = "SELECT $Attr->{grp_field}, $Attr->{uid_field}";
+            my $from      = "FROM " . ($Attr->{grp_table} or $Attr->{pwd_table});
+            my $where     = ($Attr->{uidcasesensitive} eq "offkludge" ? "WHERE LOWER($Attr->{uid_field}) =" : "WHERE $Attr->{uid_field} =");
+            my $compare   = ($Attr->{placeholder} eq "on" ? "?" : $user_sent_quoted);
             my $statement = "$select $from $where $compare";
-            $statement   .= " AND $Attr->{grp_whereclause}" if ($Attr->{grp_whereclause});
+            $statement   .= " AND ($Attr->{grp_whereclause})" if $Attr->{grp_whereclause};
             print STDERR "$prefix statement: $statement\n" if $Apache::AuthDBI::DEBUG > 1;
+            print STDERR "$prefix placeholder:  $user_sent_quoted\n" if $Apache::AuthDBI::DEBUG > 1 and $Attr->{placeholder} eq "on";
 
             # prepare statement
             my $sth;
             unless ($sth = $dbh->prepare($statement)) {
                 $r->log_reason("can not prepare statement: $DBI::errstr", $r->uri);
                 $dbh->disconnect;
-                return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+                return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
             }
 
             # execute statement
             my $rv;
-            unless ($rv = ($Attr->{placeholder} eq "on") ? $sth->execute($user_sent) : $sth->execute) {
+            unless ($rv = ($Attr->{placeholder} eq "on" ? $sth->execute($user_sent) : $sth->execute)) {
                 $r->log_reason("can not execute statement: $DBI::errstr", $r->uri);
                 $dbh->disconnect;
-                return MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR();
+                return (MP2 ? Apache2::Const::SERVER_ERROR() : Apache::Constants::SERVER_ERROR());
             }
 
             # fetch result and build a group-list
             my $group;
-            while ( $group = $sth->fetchrow_array ) {
+            while (my ($group, $uid) = $sth->fetchrow_array) {
+                # The select may not be case-sensitive.
+                next if $Attr->{uidcasesensitive} eq "on" and $uid ne $user_sent;
+
                 # strip trailing blanks for fixed-length data-type
                 $group =~ s/ +$//;
                 $groups .= "$group,";
@@ -696,7 +711,7 @@
             foreach $group (split(/,/, $groups)) {
                 # check group
                 if ($group_required eq $group) {
-                    $group_result = MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+                    $group_result = (MP2 ? Apache2::Const::OK() : Apache::Constants::OK());
                     $r->subprocess_env(REMOTE_GROUP => $group);
                     print STDERR "$prefix user $user_sent: group_result = OK for >$group< \n" if $Apache::AuthDBI::DEBUG > 1;
                     # update timestamp and cache userid/groups if CacheTime is configured
@@ -722,31 +737,31 @@
     }
 
     # check the results of the requirement checks
-    if ($Attr->{authoritative} eq 'on' && ($user_result != MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) && ($group_result != MP2 ? Apache2::Const::OK() : Apache::Constants::OK())) {
+    if ($Attr->{authoritative} eq 'on' && $user_result != (MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) && $group_result != (MP2 ? Apache2::Const::OK() : Apache::Constants::OK())) {
         my $reason;
-        if ($user_result == MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED()) {
+        if ($user_result == (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED())) {
           $reason .= " USER";
         }
-        if ($group_result == MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED()) {
+        if ($group_result == (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED())) {
           $reason .= " GROUP";
         }
         $r->log_reason("DBI-Authoritative: Access denied on $reason rule(s)", $r->uri);
         
-        if ($authz_denied == MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED()) {
+        if ($authz_denied == (MP2 ? Apache2::Const::AUTH_REQUIRED() : Apache::Constants::AUTH_REQUIRED())) {
           $r->note_basic_auth_failure;
         }
         return $authz_denied;
     }
 
     # return OK if authorization was successful
-    if (($user_result == MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) || ($group_result == MP2 ? Apache2::Const::OK() : Apache::Constants::OK())) {
+    if ($user_result == (MP2 ? Apache2::Const::OK() : Apache::Constants::OK()) || $group_result == (MP2 ? Apache2::Const::OK() : Apache::Constants::OK())) {
         print STDERR "$prefix return OK\n" if $Apache::AuthDBI::DEBUG > 1;
-        return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+        return (MP2 ? Apache2::Const::OK() : Apache::Constants::OK());
     }
 
     # otherwise fall through
     print STDERR "$prefix fall through, return DECLINED\n" if $Apache::AuthDBI::DEBUG > 1;
-    return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+    return (MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED());
 }
 
 
@@ -1200,16 +1215,24 @@
 the userid as salt. 
 
 =item *
-Auth_DBI_uidcasesensitive  < on / off > (Authentication and Authorization)
+Auth_DBI_uidcasesensitive  < on / off / offkludge > (Authentication and Authorization)
 
-Default is 'on'. When set 'off', the entered userid is converted to lower case.
-Also the userid in the password select-statement is converted to lower case. 
+Default is 'on'.  If on, the username is always checked for case sensitivity.
+'off' will change the user input to lowercase, requiring the database to either
+have them stored in lowercase or do a case insensitive comparison.  'offkluge'
+is the same as off, but it will apply LOWER() to the username column.  Note that
+this is a bad idea because the database cannot use indexing on the username
+column, causing terrible performance on large user databases.  If possible, it is
+better to actually store the names in lowercase or convince your database to use
+case-insensitive comparisons.
 
 =item *
 Auth_DBI_pwdcasesensitive  < on / off > (Authentication only)
 
 Default is 'on'. When set 'off', the entered password is converted to lower 
-case. 
+case.  This means passwords must be stored in lower-case or else the user won't
+be able to log in.  This is because once a password is encrypted, an insensitive
+comparison is infeasible.
 
 =item *
 Auth_DBI_placeholder < on / off > (Authentication and Authorization)
