# HG changeset patch # User Mahlon E. Smith # Date 1570988656 25200 # Node ID 3b6cb1117ffba057997bd3e6791dc5a88f4e6834 # Parent af3c3c0a1f3b178bcb7f3c796b37678a7f21b6f7 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. diff -r af3c3c0a1f3b -r 3b6cb1117ffb CONTRIBUTORS --- 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. Rong-En Fan Salvatore Bonaccorso +Uwe Kleine-König Yann Cezard diff -r af3c3c0a1f3b -r 3b6cb1117ffb shelldap --- 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 + +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'} = ); 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;