diff --git a/tests/aux/ldap.pl b/tests/aux/ldap.pl new file mode 100755 index 0000000..6d854e6 --- /dev/null +++ b/tests/aux/ldap.pl @@ -0,0 +1,104 @@ +#!/usr/bin/perl + +# Copyright (c) 2015 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use strict; +use warnings; + +package PamServer; +use Net::LDAP::Server; +use Net::LDAP::Constant qw/LDAP_SUCCESS/; + +use base 'Net::LDAP::Server'; + +use constant RESULT_OK => { + 'matchedDN' => '', + 'errorMessage' => '', + 'resultCode' => LDAP_SUCCESS +}; + +my %objects = ( + 'uid=foo,ou=users,dc=example,dc=com' => 'vvincredible', +); + +sub bind { + my $self = shift; + my $reqData = shift; + return RESULT_OK; +} + +sub search { + my $self = shift; + my $reqData = shift; + my $base = $reqData->{'baseObject'}; + my $id = $objects{$base}; + my @entries; + if($id) { + my $entry = Net::LDAP::Entry->new; + $entry->dn($base); + $entry->add(objectClass => [ "person" ]); + $entry->add(yubiKeyId => [ $id ]); + push @entries, $entry; + } + return RESULT_OK, @entries; +} + +package main; + +use IO::Socket::INET; +use IO::Select; + +my $port = shift; +die "no port specified" unless $port; + +my $sock = IO::Socket::INET->new( + Proto => 'tcp', + LocalAddr => "localhost:$port", + Reuse => 1 +) or die "$!"; +$sock->listen(); + +my $sel = IO::Select->new($sock); +my %handlers; + +while (my @ready = $sel->can_read) { + foreach my $fh (@ready) { + if ($fh == $sock) { + my $psock = $sock->accept; + $sel->add($psock); + $handlers{*$psock} = PamServer->new($psock); + } else { + my $result = $handlers{*$fh}->handle; + if ($result) { + $sel->remove($fh); + $fh->close; + delete $handlers{*$fh}; + } + } + } +} diff --git a/tests/pam_test.c b/tests/pam_test.c index a888eee..45729c7 100644 --- a/tests/pam_test.c +++ b/tests/pam_test.c @@ -49,6 +49,18 @@ static struct data { {"foo", "vvincredibletrerdegkkrkkneieultcjdghrejjbckl"}, }; + +static const char *ldap_cfg[] = { + "id=1", + "urllist=http://localhost:8889/wsapi/2/verify;http://localhost:8888/wsapi/2/verify", + "authfile=aux/authfile", + "ldap_uri=ldap://localhost:8890", + "ldapdn=ou=users,dc=example,dc=com", + "user_attr=uid", + "yubi_attr=yubiKeyId", + "debug" +}; + static const char *err = "error"; static const struct data *test_get_data(void *id) { @@ -165,18 +177,34 @@ static int test_fail_authenticate3(void) { return pam_sm_authenticate(3, 0, sizeof(cfg) / sizeof(char*), cfg); } -static pid_t run_mock(const char *port) { +static int test_authenticate_ldap1(void) { + return pam_sm_authenticate(0, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg); +} + +static int test_authenticate_ldap_fail1(void) { + return pam_sm_authenticate(1, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg); +} + +static int test_authenticate_ldap_fail2(void) { + return pam_sm_authenticate(2, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg); +} + +static pid_t run_mock(const char *port, const char *type) { pid_t pid = fork(); if(pid == 0) { - execlp("aux/ykval.pl", "aux/ykval.pl", port, NULL); + execlp(type, type, port, NULL); } return pid; } +#define YKVAL "aux/ykval.pl" +#define LDAP "aux/ldap.pl" + int main () { int ret = 0; - pid_t child = run_mock("8888"); - pid_t child2 = run_mock("8889"); + pid_t child = run_mock("8888", YKVAL); + pid_t child2 = run_mock("8889", YKVAL); + pid_t child3 = run_mock("8890", LDAP); /* Give the "server" time to settle */ sleep(1); @@ -201,11 +229,26 @@ int main () { ret = 5; goto out; } +#ifdef HAVE_LIBLDAP + if(test_authenticate_ldap1() != PAM_SUCCESS) { + ret = 6; + goto out; + } + if(test_authenticate_ldap_fail1() != PAM_USER_UNKNOWN) { + ret = 7; + goto out; + } + if(test_authenticate_ldap_fail2() != PAM_AUTH_ERR) { + ret = 8; + goto out; + } +#endif out: kill(child, 9); kill(child2, 9); - printf("killed %d and %d\n", child, child2); + kill(child3, 9); + printf("killed %d, %d and %d\n", child, child2, child3); if(ret != 0) { fprintf(stderr, "test %d failed!\n", ret); }