As I mentioned in the dim and distant past, I've been working on adding
native GSSAPI support to Authen::SASL::Perl, so that the
Authen::SASL::Cyrus module isn't required to use Kerberos.

Attached is the first cut of this support. It supports GSSAPI
authentication, but does not implement security layers. This means that
whilst a connection to the server using this module is authenticated, it
is _not_ encrypted or integrity checked, and can be subverted by a man
in the middle attacker.

Security layers are a work in progress, I suspect that they may require
some changes to the Authen::SASL::Perl framework, so I'll send them in
an additional patch.

Feedback welcome!

Cheers,

Simon.
Index: lib/Authen/SASL/Perl/GSSAPI.pm
===================================================================
--- lib/Authen/SASL/Perl/GSSAPI.pm      (revision 0)
+++ lib/Authen/SASL/Perl/GSSAPI.pm      (revision 0)
@@ -0,0 +1,87 @@
+# Copyright (c) 2006 Simon Wilkinson
+# All rights reserved. This program is free software; you can redistribute
+# it and/or modify it under the same terms as Perl itself.
+
+package Authen::SASL::Perl::GSSAPI;
+
+use strict;
+
+use vars qw($VERSION @ISA);
+use GSSAPI;
+
+$VERSION= "0.01";
[EMAIL PROTECTED] = qw(Authen::SASL::Perl);
+
+my %secflags = (
+  noplaintext => 1,
+  noanonymous => 1,
+);
+
+sub _order { 4 }
+sub _secflags {
+  shift;
+  scalar grep { $secflags{$_} } @_;
+}
+
+sub mechanism { 'GSSAPI' }
+
+sub client_start {
+  my $self = shift;
+  my $status;
+  my $principal = $self->service."@".$self->host;
+
+  $self->{gss_name} = new GSSAPI::Name;
+  $status = $self->{gss_name}->import($self->{gss_name}, $principal, 
+                                     gss_nt_service_name)
+    or return $self->set_error("GSSAPI Error : ".$status);
+  $self->{gss_ctx} = new GSSAPI::Context;
+  $self->{gss_state} = 0;
+  return $self->client_step("");
+}
+
+sub client_step
+{
+  my ($self, $challenge) = @_;
+
+  my $status;
+
+  if ($self->{gss_state}==0) {
+    my $outtok;
+    my $flags;
+    $status = $self->{gss_ctx}->init(undef, $self->{gss_name}, 
+                                    gss_mech_krb5, 
+                                    GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG, 
+                                    undef, undef, $challenge, undef, 
+                                    $outtok, $flags, undef);
+
+    if (GSSAPI::Status::GSS_ERROR($status->major)) {
+      return $self->set_error("GSSAPI Error : ".$status);
+    }
+    if ($status->major == GSS_S_COMPLETE) {
+      $self->{gss_state}=1;
+    }
+    return $outtok;
+  } elsif ($self->{gss_state}==1) {
+    # If the server has an empty output token when it COMPLETEs, Cyrus SASL
+    # kindly sends us that empty token. We need to ignore it, which introduces
+    # another round into the process. 
+    return "" if $challenge eq "";
+ 
+    my $unwrapped;
+    $status = $self->{gss_ctx}->unwrap($challenge, $unwrapped, undef, undef)
+      or return $self->set_error("GSSAPI Error : ".$status);
+
+    # XXX - Security layer support will require us to decode this packet
+
+    # Need to set message to be 0x01, 0x00, 0x00, 0x00 for no security layers
+    my $message = pack('CCCC', 0x01, 0x00, 0x00, 0x00);
+    $message.= $self->_call('user');
+    my $outtok;
+    $status = $self->{gss_ctx}->wrap(0, undef, $message, undef, $outtok)
+      or return $self->set_error("GSSAPI Error : ".$status);
+    
+    $self->{gss_state}=0;
+    return $outtok;
+  }
+}
+

Reply via email to