Package: libauthen-sasl-perl
Version: 2.09-0pm2
Severity: normal
Tags: patch

Hi,

although DIGEST-MD5 support in Authen::SASL 2.09 is improved compared to 
Authen::SASL 2.08 in Debian there is still room for improvement.

The attached patch from Authen::SASL's SVN repository fixes a bug that
slipped into Authen::SASL 2.09, adds better checks and adds a few
callback option to DIGEST-MD5.

Please update libauthen-sasl-perl !

Peter

-- System Information:
Debian Release: testing/unstable
  APT prefers testing
  APT policy: (990, 'testing'), (500, 'unstable'), (500, 'stable')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.12-1-k7
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8)

Versions of packages libauthen-sasl-perl depends on:
ii  perl                          5.8.7-3    Larry Wall's Practical Extraction 

libauthen-sasl-perl recommends no packages.

-- no debconf information
--- lib/Authen/SASL/Perl/DIGEST_MD5.pm  2005-04-26 15:34:23.000000000 +0200
+++ lib/Authen/SASL/Perl/DIGEST_MD5.pm  2005-08-11 14:14:02.000000000 +0200
@@ -1,4 +1,4 @@
-# Copyright (c) 2003 Graham Barr, Djamel Boudjerda, Paul Connolly, Julian 
Onions and Nexor.
+# Copyright (c) 2003-2005 Graham Barr, Djamel Boudjerda, Paul Connolly, Julian 
Onions and Nexor.
 # All rights reserved. This program is free software; you can redistribute 
 # it and/or modify it under the same terms as Perl itself.
 
@@ -10,7 +10,7 @@
 use vars qw($VERSION @ISA $CNONCE);
 use Digest::MD5 qw(md5_hex md5);
 
-$VERSION = "1.04";
+$VERSION = "1.05";
 @ISA = qw(Authen::SASL::Perl);
 
 my %secflags = (
@@ -21,6 +21,9 @@
 # some have to be quoted - some don't - sigh!
 my %qdval; @qdval{qw(username authzid realm nonce cnonce digest-uri)} = ();
 
+my %multi; @multi{qw(realm auth-param)} = ();
+my @required = qw(algorithm nonce);
+
 sub _order { 3 }
 sub _secflags {
   shift;
@@ -43,29 +46,54 @@
   while($challenge =~ s/^(?:\s*,)?\s*(\w+)=("([^\\"]+|\\.)*"|[^,]+)\s*//) {
     my ($k, $v) = ($1,$2);
     if ($v =~ /^"(.*)"$/s) {
-      ($v = $1) =~ s/\\//g;
+      ($v = $1) =~ s/\\(.)/$1/g;
+    }
+    if (exists $multi{$k}) {
+      my $aref = $sparams{$k} ||= [];
+      push @$aref, $v;
+    }
+    elsif (defined $sparams{$k}) {
+      return $self->set_error("Bad challenge: '$challenge'");
+    }
+    else {
+      $sparams{$k} = $v;
     }
-    $sparams{$k} = $v;
   }
 
   return $self->set_error("Bad challenge: '$challenge'")
     if length $challenge;
 
+  # qop in server challenge is optional: if not there "auth" is assumed
   return $self->set_error("Server does not support auth (qop = 
$sparams{'qop'})")
-    unless grep { /^auth$/ } split(/,/, $sparams{'qop'});
+    if ($sparams{qop} && ! grep { /^auth$/ } split(/,/, $sparams{'qop'}));
+
+  # check required fields in server challenge
+  if (my @missing = grep { !exists $sparams{$_} } @required) {
+    return $self->set_error("Server did not provide required field(s): 
@missing")
+  }
 
   my %response = (
     nonce        => $sparams{'nonce'},
-    username     => $self->_call('user'),
-    realm        => $sparams{'realm'},
-    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 $s_realm = $sparams{realm} || [];
+  my $realm = $self->_call('realm', @$s_realm);
+  unless (defined $realm) {
+    # If the user does not pick a realm, use the first from the server
+    $realm = $s_realm->[0];
+  }
+  if (defined $realm) {
+    $response{realm} = $realm;
+  }
+
   my $authzid = $self->_call('authname');
   if (defined $authzid) {
     $response{authzid} = $authzid;
@@ -73,15 +101,23 @@
 
   my $serv_name = $self->_call('serv');
   if (defined $serv_name) {
-    $response{'digest_uri'} .= '/' . $serv_name;
+    $response{'digest-uri'} .= '/' . $serv_name;
   }
 
+  my $user = $self->_call('user');
+  return $self->set_error("Username is required")
+    unless defined $user;
+  $response{username} = $user;
+
   my $password = $self->_call('pass');
+  return $self->set_error("Password is required")
+    unless defined $password;
 
   # Generate the response value
 
+  $realm = "" unless defined $realm;
   my $A1 = join (":", 
-    md5(join (":", @response{qw(username realm)}, $password)),
+    md5(join (":", $user, $realm, $password)),
     @response{defined($authzid) ? qw(nonce cnonce authzid) : qw(nonce cnonce)}
   );
 
@@ -162,6 +198,11 @@
 
 The service name when authenticating to a replicated service
 
+=item realm
+
+The authentication realm when overriding the server-provided default.
+If not given the server-provided value is used.
+
 =back
 
 =head1 SEE ALSO
@@ -178,8 +219,8 @@
 
 =head1 COPYRIGHT 
 
-Copyright (c) 2003 Graham Barr, Djamel Boudjerda, Paul Connolly, Julian Onions
-and Nexor.
+Copyright (c) 2003-2005 Graham Barr, Djamel Boudjerda, Paul Connolly,
+Julian Onions, Nexor and Peter Marschall.
 All rights reserved. This program is free software; you can redistribute 
 it and/or modify it under the same terms as Perl itself.
 
--- lib/Authen/SASL/Perl.pm     2005-04-26 15:34:23.000000000 +0200
+++ lib/Authen/SASL/Perl.pm     2005-08-11 14:14:02.000000000 +0200
@@ -90,20 +90,36 @@
 }
 
 sub _call {
-  my ($self, $name) = @_;
+  my ($self, $name) = splice(@_,0,2);
 
   my $cb = $self->{callback}{$name};
 
+  return undef unless defined $cb;
+
+  my $value;
+
   if (ref($cb) eq 'ARRAY') {
     my @args = @$cb;
     $cb = shift @args;
-    return $cb->($self, @args);
+    $value = $cb->($self, @args);
   }
   elsif (ref($cb) eq 'CODE') {
-    return $cb->($self);
+    $value = $cb->($self, @_);
+  }
+  else {
+    $value = $cb;
   }
 
-  return $cb;
+  $self->{answer}{$name} = $value
+    unless $name eq 'pass'; # Do not store password
+
+  return $value;
+}
+
+# TODO: Need a better name than this
+sub answer {
+  my ($self, $name) = @_;
+  $self->{answer}{$name};
 }
 
 sub _secflags { 0 }

Reply via email to