Fix sasl for DIGEST-MD5, PLAIN, and LOGIN mechanisms, which I don't think ever actually worked properly.
Add a sasluser argument if a specific identity is required for the
backend, which if unsupplied, tries to guess if a binddn is present.
(Uwe's previous commit fixed EXTERNAL and GSSAPI, which did work, but
randomly failed due to hash ordering.)
Minor style cleanups, remove duplicate/unecessary logic for anonymous
binds.
--- a/CONTRIBUTORS Sun Oct 13 10:19:40 2019 -0700
+++ b/CONTRIBUTORS Sun Oct 13 10:44:16 2019 -0700
@@ -17,5 +17,6 @@
Rick H. <rickh_shelldap@printstring.com>
Rong-En Fan <rafan@FreeBSD.org>
Salvatore Bonaccorso <carnil@debian.org>
+Uwe Kleine-König <uwe@kleine-koenig.org>
Yann Cezard <yann.cezard@univ-pau.fr>
--- a/shelldap Sun Oct 13 10:19:40 2019 -0700
+++ b/shelldap Sun Oct 13 10:44:16 2019 -0700
@@ -166,7 +166,20 @@
A space separated list of SASL mechanisms. Requires the Authen::SASL
module.
- --sasl 'PLAIN CRAM-MD5 GSSAPI'
+ --sasl 'PLAIN DIGEST-MD5 EXTERNAL GSSAPI'
+ -Y 'PLAIN DIGEST-MD5 EXTERNAL GSSAPI'
+
+=back
+
+=over 4
+
+=item B<sasluser>
+
+SASL authorization identity, if one is explicitly required by your
+backend mechanism.
+
+ --sasluser mahlon
+ -X mahlon
=back
@@ -709,8 +722,8 @@
You may try connecting insecurely, or install the module and try again.\n} if $@;
}
- if ($conf->{'binddn'}) {
- if($conf->{'promptpass'}) {
+ if ( $conf->{'binddn'} ) {
+ if ( $conf->{'promptpass'} ) {
# Prompt for a password after disabling local echo.
#
print "Bind password: ";
@@ -718,9 +731,11 @@
chomp( $conf->{'bindpass'} = <STDIN> );
Term::ReadKey::ReadMode 0;
print "\n";
- } elsif($conf->{'pass'}) {
+ }
+ elsif ( $conf->{'pass'} ) {
$conf->{'bindpass'} = $conf->{'pass'}
- } elsif($conf->{'passfile'}) {
+ }
+ elsif ( $conf->{'passfile'} ) {
chomp( $conf->{'bindpass'} = slurp($conf->{'passfile'}));
}
}
@@ -762,16 +777,20 @@
if ( $use_sasl ) {
my $serv = $conf->{'server'};
$serv =~ s!^ldap[si]?://!!;
- $sasl = Authen::SASL->new( mechanism => $conf->{'sasl'} );
+ my $user = $1 if $conf->{'binddn'} && $conf->{'binddn'} =~ /uid=([^,]*),/i;
+ my $callback = {
+ pass => $conf->{'bindpass'},
+ user => $conf->{'sasluser'} || $user
+ };
+
+ $sasl = Authen::SASL->new( mechanism => $conf->{'sasl'}, callback => $callback );
$sasl_conn = $sasl->client_new( 'ldap', $serv );
}
# bind with sasl
#
if ( $sasl_conn ) {
- $rv = $ldap->bind( $conf->{'binddn'},
- sasl => $sasl_conn
- );
+ $rv = $ldap->bind( $conf->{'binddn'}, sasl => $sasl_conn );
}
# simple bind as an authenticated dn
@@ -785,7 +804,7 @@
# bind anonymously
#
else {
- $rv = $sasl_conn ? $ldap->bind( sasl => $sasl_conn ) : $ldap->bind();
+ $rv = $ldap->bind();
}
my $err = $rv->error();
@@ -2715,9 +2734,10 @@
'passfile|y=s',
'timeout=i',
'sasl|Y=s',
+ 'sasluser|X=s',
'simple|x!' => sub {
my($opt,$arg) = @_;
- $conf->{sasl} = $arg ? undef : 'PLAIN CRAM-MD5 GSSAPI'
+ $conf->{sasl} = $arg ? undef : 'PLAIN DIGEST-MD5 GSSAPI'
},
'tls_cacert=s',
'tls_cert=s',
@@ -2755,8 +2775,8 @@
# Allow command line option --attributes to override settings from
# config file.
-if($conf->{'cmdline_attributes'}) {
- $conf->{'attributes'} = $conf->{'cmdline_attributes'}
+if ( $conf->{'cmdline_attributes'} ) {
+ $conf->{'attributes'} = $conf->{'cmdline_attributes'};
}
# create and enter shell loop while also handling Ctrl+C correctly.
@@ -2774,9 +2794,9 @@
}
my $sigaction = POSIX::SigAction->new( \&ctrl_c_handler, $sigset, 0);
my $old_action = POSIX::SigAction->new;
-POSIX::sigaction(&POSIX::SIGINT, $sigaction, $old_action); # save default one
+POSIX::sigaction( &POSIX::SIGINT, $sigaction, $old_action ); # save default one
$shell->cmdloop();
-POSIX::sigaction(&POSIX::SIGINT, $old_action); # restore default one
+POSIX::sigaction( &POSIX::SIGINT, $old_action ); # restore default one
### List of default config files
###
@@ -2813,13 +2833,13 @@
my $conf2 = eval { YAML::Syck::Load( $data ) };
die "Invalid YAML in $confpath\n" if $@;
- if( $conf2->{'configfile'} and ($confpath eq $conf2->{'configfile'})) {
- delete $conf2->{'configfile'}
+ if ( $conf2->{'configfile'} and ($confpath eq $conf2->{'configfile'}) ) {
+ delete $conf2->{'configfile'};
}
$conf2->{alias} ||= {};
- return($confpath, $conf2);
+ return( $confpath, $conf2 );
}
### dump YAML config into conf file while making sure that
@@ -2833,8 +2853,8 @@
my %conf2 = %$conf;
# This check is currently unnecessary because the comparison will always
# be true, but is left here for effect of least surprise in the future.
- if( $conf->{configfile} and ($confpath eq $conf->{configfile})) {
- delete $conf2{'configfile'}
+ if ( $conf->{configfile} and ($confpath eq $conf->{configfile}) ) {
+ delete $conf2{'configfile'};
}
YAML::Syck::DumpFile( $confpath, \%conf2 );
chmod 0600, $confpath;