Hi Steve,

On Tuesday 09 August 2005 20:08, SteveC wrote:
> I think that I might have spotted what's causing my problem:
>
> This Microsoft technet article
>
> http://www.microsoft.com/technet/prodtechnol/windowsserver2003/library/Tech
>Ref/717b450c-f4a0-4cc9-86f4-cc0633aae5f9.mspx
>
> explains how Microsoft pre-computes and saves certain MD5 hashes based
> on combinations of account names (UPN and SamAccountName, DNS names,
> fixed strings, and paswords -- in various combinations) [See Digest
> Hashes section in the body].  These pre-computed hashes mean that AD
> doesn't need to hold passwords in a reversible encryption format.[This
> is a new feature in W2k3 -- W2k needs the reversible encryption
> apparently if digest authentication is going to be used.]
>
> In my environment, I have (don't ask my to justify why all the following
> non-standard settings!):
> - My UPN is [EMAIL PROTECTED]  (where BASE is some string, i.e. not a real 
> fqdn)
> - my SamAccountName is name_2
> - the forest root domain is ROOT.BASE
> - the AD domain I belong to is XXXX.ROOT.BASE
> - the flat domain name is XXXX
>
> So, given all the above, when the 'A1' hash is calculated the 'realm'
> used by DIGEST_MD5 is the one supplied by the domain controller which is
> XXXX.ROOT.BASE.  If this is the case, then the only entry from the table
> in the above technet article that can ever work is if I provide the
> SamAccountname -- then row 2 of the table (SamAccountName +
> DNSDomainaname + password) will match a pre-computed hash.
>
> Does that make sense?

I don't know if it makes sense, but it seems to match the results of my 
tests ;-)
As long als the server provided realm is used the samAccountname is to be used 
as the value of the user callback.


> If that is the case, then if the SASL & DIGEST_MD5 modules provided a
> callback to enable the realm to be overridden, a user could provide one
> of the Microsoft 'standard' values (in the case of a perverse
> configuration like mine!) and things would work with the 'preferred'
> UPN. [It still doesn't solve my auth-int/auth-conf follow-on
> requirements however!]

I have extended the patch to Authen::SASL 2.09. It now
- corrects the un-escaping behaviour when reading the challenge
- checks for required fields (according to the RFC)
- allows for qop not to be sent froj the server (according to the RFC)
- corrects the digest-uri bug
- adds a callback for the realm

Graham, 
please add this patch to the Authen-SASL SVN
(alternatively you may give my pmarschall account write access to the
Authen-SASL SVN in addition to the perl-ldap SVN so that I can do it
myself)

Peter

-- 
Peter Marschall
eMail: [EMAIL PROTECTED]
--- lib/Authen/SASL/Perl/DIGEST_MD5.pm
+++ lib/Authen/SASL/Perl/DIGEST_MD5.pm	2005-08-07 18:41:14.000000000 +0200
@@ -43,16 +43,24 @@
   while($challenge =~ s/^(?:\s*,)?\s*(\w+)=("([^\\"]+|\\.)*"|[^,]+)\s*//) {
     my ($k, $v) = ($1,$2);
     if ($v =~ /^"(.*)"$/s) {
-      ($v = $1) =~ s/\\//g;
+      ($v = $1) =~ s/\\(.)/$1/g;
     }
     $sparams{$k} = $v;
   }
+  # TODO: detect multiple occurrence of fields: fail when forbidden
 
   return $self->set_error("Bad challenge: '$challenge'")
     if length $challenge;
 
-  return $self->set_error("Server does not support auth (qop = $sparams{'qop'})")
-    unless grep { /^auth$/ } split(/,/, $sparams{'qop'});
+  # qop in server challenge is optional: if not there "auth" is assumed
+  return $self->set_error("Server does not support auth (qop = $sparams{qop})")
+    if ($sparams{qop} && ! grep { /^auth$/ } split(/,/, $sparams{qop}));
+
+  # check required fields in server challenge: nonce, algorithm
+  foreach (qw/nonce algorithm/) {
+    return $self->set_error("Server did not provide required field $_ in challenge")
+      if (!defined $sparams{$_});
+  }  
 
   my %response = (
     nonce        => $sparams{'nonce'},
@@ -61,11 +69,13 @@
     nonce        => $sparams{'nonce'},
     cnonce       => md5_hex($CNONCE || join (":", $$, time, rand)),
     'digest-uri' => $self->service . '/' . $self->host,
-    qop          => 'auth',
+    qop          => 'auth',		# we currently support 'auth' only
+    # calc how often the server nonce has been seen; server expects "00000001"
     nc           => sprintf("%08d",     ++$self->{nonce}{$sparams{'nonce'}}),
     charset      => $sparams{'charset'},
   );
 
+  # let caller-provided fields override defaults: authorization ID, service name, realm
   my $authzid = $self->_call('authname');
   if (defined $authzid) {
     $response{authzid} = $authzid;
@@ -73,8 +83,14 @@
 
   my $serv_name = $self->_call('serv');
   if (defined $serv_name) {
-    $response{'digest_uri'} .= '/' . $serv_name;
+    $response{'digest-uri'} .= '/' . $serv_name;
+  }
+
+  my $realm = $self->_call('realm');
+  if (defined $realm) {
+    $response{realm} = $realm;
   }
+  # else TODO: use one of the realms provided by the server
 
   my $password = $self->_call('pass');
 

Reply via email to