merge r863,r874,r891: partial unit tests for openpam_dispatch()

merge r864-867,r871,r880,r883: various improvements to tests and test suite


git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/branches/nooath@894 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
Dag-Erling Smørgrav 2017-01-17 14:29:41 +00:00
parent abee687e7a
commit debbcc1b75
11 changed files with 424 additions and 12 deletions

View File

@ -41,6 +41,8 @@
#include <sys/param.h>
#include <stdint.h>
#include <security/pam_appl.h>
#include "openpam_impl.h"

View File

@ -2,18 +2,22 @@
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/lib/libpam
noinst_HEADERS = t.h
AM_TESTS_ENVIRONMENT = \
PAM_RETURN_SO=$(abs_top_builddir)/modules/pam_return/.libs/pam_return.so
noinst_HEADERS = t.h t_pam_conv.h
# tests
TESTS =
TESTS += t_openpam_ctype
TESTS += t_openpam_dispatch
TESTS += t_openpam_readword
TESTS += t_openpam_readlinev
check_PROGRAMS = $(TESTS)
# libt - common support code
check_LIBRARIES = libt.a
libt_a_SOURCES = t_main.c t_file.c
libt_a_SOURCES = t_main.c t_file.c t_pam_conv.c
# link with libpam and libt
LDADD = libt.a

10
t/t.h
View File

@ -32,6 +32,10 @@
#ifndef T_H_INCLUDED
#define T_H_INCLUDED
#if _BullseyeCoverage
_Pragma("BullseyeCoverage save off")
#endif
#include <security/openpam_attr.h>
struct t_test {
@ -42,13 +46,13 @@ struct t_test {
#define T_FUNC(n, d) \
static int t_ ## n ## _func(void *); \
static const struct t_test t_ ## n = \
static struct t_test t_ ## n = \
{ t_ ## n ## _func, d, NULL }; \
static int t_ ## n ## _func(OPENPAM_UNUSED(void *arg))
#define T_FUNC_ARG(n, d, a) \
static int t_ ## n ## _func(void *); \
static const struct t_test t_ ## n = \
static struct t_test t_ ## n = \
{ t_ ## n ## _func, d, a }; \
static int t_ ## n ## _func(void *arg)
@ -57,7 +61,7 @@ struct t_test {
extern const char *t_progname;
const struct t_test **t_prepare(int, char **);
struct t_test **t_prepare(int, char **);
void t_cleanup(void);
void t_verbose(const char *, ...)

View File

@ -92,6 +92,8 @@ t_fprintf(struct t_file *tf, const char *fmt, ...)
va_end(ap);
if (ferror(tf->file))
err(1, "%s(): vfprintf()", __func__);
if (fflush(tf->file) != 0)
err(1, "%s(): fflush()", __func__);
return (len);
}

View File

@ -70,7 +70,7 @@ usage(void)
int
main(int argc, char *argv[])
{
const struct t_test **t_plan;
struct t_test **t_plan;
const char *desc;
int n, pass, fail;
int opt;

View File

@ -94,7 +94,7 @@ T_OC(pfcs)
* Boilerplate
*/
static const struct t_test *t_plan[] = {
static struct t_test *t_plan[] = {
T(t_oc_digit),
T(t_oc_xdigit),
T(t_oc_upper),
@ -107,7 +107,7 @@ static const struct t_test *t_plan[] = {
NULL
};
const struct t_test **
struct t_test **
t_prepare(int argc, char *argv[])
{

223
t/t_openpam_dispatch.c Normal file
View File

@ -0,0 +1,223 @@
/*-
* Copyright (c) 2015 Dag-Erling Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/openpam.h>
#include "openpam_impl.h"
#include "t.h"
#include "t_pam_conv.h"
const char *pam_return_so;
T_FUNC(null, "null handle")
{
int pam_err;
#if __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
#elif __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
#endif
pam_err = pam_authenticate(NULL, 0);
#if __clang__
#pragma clang diagnostic pop
#elif __GNUC__
#pragma GCC diagnostic pop
#endif
return (pam_err == PAM_SYSTEM_ERR);
}
T_FUNC(empty_policy, "empty policy")
{
struct t_pam_conv_script script;
struct pam_conv pamc;
struct t_file *tf;
pam_handle_t *pamh;
int pam_err, ret;
memset(&script, 0, sizeof script);
pamc.conv = &t_pam_conv;
pamc.appdata_ptr = &script;
tf = t_fopen(NULL);
t_fprintf(tf, "# empty policy\n");
pam_err = pam_start(tf->name, "test", &pamc, &pamh);
t_verbose("pam_start() returned %d\n", pam_err);
/*
* Note: openpam_dispatch() currently returns PAM_SYSTEM_ERR when
* the chain is empty, it should possibly return PAM_SERVICE_ERR
* instead.
*/
pam_err = pam_authenticate(pamh, 0);
t_verbose("pam_authenticate() returned %d\n", pam_err);
ret = (pam_err != PAM_SUCCESS);
pam_err = pam_setcred(pamh, 0);
t_verbose("pam_setcred() returned %d\n", pam_err);
ret |= (pam_err != PAM_SUCCESS);
pam_err = pam_acct_mgmt(pamh, 0);
t_verbose("pam_acct_mgmt() returned %d\n", pam_err);
ret |= (pam_err != PAM_SUCCESS);
pam_err = pam_chauthtok(pamh, 0);
t_verbose("pam_chauthtok() returned %d\n", pam_err);
ret |= (pam_err != PAM_SUCCESS);
pam_err = pam_open_session(pamh, 0);
t_verbose("pam_open_session() returned %d\n", pam_err);
ret |= (pam_err != PAM_SUCCESS);
pam_err = pam_close_session(pamh, 0);
t_verbose("pam_close_session() returned %d\n", pam_err);
ret |= (pam_err != PAM_SUCCESS);
pam_err = pam_end(pamh, pam_err);
ret |= (pam_err == PAM_SUCCESS);
t_fclose(tf);
return (ret);
}
static struct t_pam_return_case {
int facility;
int primitive;
int flags;
struct {
int ctlflag;
int modret;
} mod[2];
int result;
} t_pam_return_cases[] = {
{
PAM_AUTH, PAM_SM_AUTHENTICATE, 0,
{
{ PAM_REQUIRED, PAM_SUCCESS },
{ PAM_REQUIRED, PAM_SUCCESS },
},
PAM_SUCCESS,
},
};
T_FUNC(mod_return, "module return value")
{
struct t_pam_return_case *tc;
struct t_pam_conv_script script;
struct pam_conv pamc;
struct t_file *tf;
pam_handle_t *pamh;
unsigned int i, j, n;
int pam_err;
memset(&script, 0, sizeof script);
pamc.conv = &t_pam_conv;
pamc.appdata_ptr = &script;
n = sizeof t_pam_return_cases / sizeof t_pam_return_cases[0];
for (i = 0; i < n; ++i) {
tc = &t_pam_return_cases[i];
tf = t_fopen(NULL);
for (j = 0; j < 2; ++j) {
t_fprintf(tf, "%s %s %s error=%s\n",
pam_facility_name[tc->facility],
pam_control_flag_name[tc->mod[j].ctlflag],
pam_return_so,
pam_err_name[tc->mod[j].modret]);
}
pam_err = pam_start(tf->name, "test", &pamc, &pamh);
t_verbose("pam_start() returned %d\n", pam_err);
if (pam_err != PAM_SUCCESS)
continue;
switch (tc->primitive) {
case PAM_SM_AUTHENTICATE:
pam_err = pam_authenticate(pamh, tc->flags);
break;
case PAM_SM_SETCRED:
pam_err = pam_setcred(pamh, tc->flags);
break;
case PAM_SM_ACCT_MGMT:
pam_err = pam_acct_mgmt(pamh, tc->flags);
break;
case PAM_SM_OPEN_SESSION:
pam_err = pam_open_session(pamh, tc->flags);
break;
case PAM_SM_CLOSE_SESSION:
pam_err = pam_close_session(pamh, tc->flags);
break;
case PAM_SM_CHAUTHTOK:
pam_err = pam_chauthtok(pamh, tc->flags);
break;
}
t_verbose("%s returned %d\n",
pam_func_name[tc->primitive], pam_err);
t_fclose(tf);
}
return (1);
}
/***************************************************************************
* Boilerplate
*/
static struct t_test *t_plan[] = {
T(null),
T(empty_policy),
T(mod_return),
NULL
};
struct t_test **
t_prepare(int argc, char *argv[])
{
if ((pam_return_so = getenv("PAM_RETURN_SO")) == NULL)
return (NULL);
openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
openpam_set_feature(OPENPAM_FALLBACK_TO_OTHER, 0);
(void)argc;
(void)argv;
return (t_plan);
}
void
t_cleanup(void)
{
}

View File

@ -302,7 +302,7 @@ T_FUNC(unterminated_line, "unterminated line")
* Boilerplate
*/
static const struct t_test *t_plan[] = {
static struct t_test *t_plan[] = {
T(empty_input),
T(empty_line),
T(unterminated_empty_line),
@ -319,7 +319,7 @@ static const struct t_test *t_plan[] = {
NULL
};
const struct t_test **
struct t_test **
t_prepare(int argc, char *argv[])
{

View File

@ -949,7 +949,7 @@ T_FUNC(line_continuation_within_word, "line continuation within word")
* Boilerplate
*/
static const struct t_test *t_plan[] = {
static struct t_test *t_plan[] = {
T(empty_input),
T(empty_line),
T(unterminated_line),
@ -1019,7 +1019,7 @@ static const struct t_test *t_plan[] = {
NULL
};
const struct t_test **
struct t_test **
t_prepare(int argc, char *argv[])
{

132
t/t_pam_conv.c Normal file
View File

@ -0,0 +1,132 @@
/*-
* Copyright (c) 2015 Dag-Erling Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/openpam.h>
#include "openpam_impl.h"
#include "openpam_asprintf.h"
#include "t.h"
#include "t_pam_conv.h"
/*
* Conversation function
*
* The appdata argument points to a struct t_pam_conv_script which
* contains both the expected messages and the desired responses. If
* script.responses is NULL, t_pam_conv() will return PAM_CONV_ERR. If an
* error occurs (incorrect number of messages, messages don't match script
* etc.), script.comment will be set to point to a malloc()ed string
* describing the error. Otherwise, t_pam_conv() will return to its
* caller a malloc()ed copy of script.responses.
*/
int
t_pam_conv(int nm, const struct pam_message **msgs,
struct pam_response **respsp, void *ad)
{
struct t_pam_conv_script *s = ad;
struct pam_response *resps;
int i;
/* check message count */
if (nm != s->nmsg) {
asprintf(&s->comment, "expected %d messages, got %d",
s->nmsg, nm);
return (PAM_CONV_ERR);
}
if (nm <= 0 || nm > PAM_MAX_NUM_MSG) {
/* since the previous test passed, this is intentional! */
s->comment = NULL;
return (PAM_CONV_ERR);
}
/* check each message and provide the sed answer */
if ((resps = calloc(nm, sizeof *resps)) == NULL)
goto enomem;
for (i = 0; i < nm; ++i) {
if (msgs[i]->msg_style != s->msgs[i].msg_style) {
asprintf(&s->comment,
"message %d expected style %d got %d", i,
s->msgs[i].msg_style, msgs[i]->msg_style);
goto fail;
}
if (strcmp(msgs[i]->msg, s->msgs[i].msg) != 0) {
asprintf(&s->comment,
"message %d expected \"%s\" got \"%s\"", i,
s->msgs[i].msg, msgs[i]->msg);
goto fail;
}
switch (msgs[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
t_verbose("[PAM_PROMPT_ECHO_OFF] %s\n", msgs[i]->msg);
break;
case PAM_PROMPT_ECHO_ON:
t_verbose("[PAM_PROMPT_ECHO_ON] %s\n", msgs[i]->msg);
break;
case PAM_ERROR_MSG:
t_verbose("[PAM_ERROR_MSG] %s\n", msgs[i]->msg);
break;
case PAM_TEXT_INFO:
t_verbose("[PAM_TEXT_INFO] %s\n", msgs[i]->msg);
break;
default:
asprintf(&s->comment, "invalid message style %d",
msgs[i]->msg_style);
goto fail;
}
/* copy the response, if there is one */
if (s->resps[i].resp != NULL &&
(resps[i].resp = strdup(s->resps[i].resp)) == NULL)
goto enomem;
resps[i].resp_retcode = s->resps[i].resp_retcode;
}
s->comment = NULL;
*respsp = resps;
return (PAM_SUCCESS);
enomem:
asprintf(&s->comment, "%s", strerror(ENOMEM));
fail:
for (i = 0; i < nm; ++i)
free(resps[i].resp);
free(resps);
return (PAM_CONV_ERR);
}

45
t/t_pam_conv.h Normal file
View File

@ -0,0 +1,45 @@
/*-
* Copyright (c) 2015 Dag-Erling Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $Id$
*/
#ifndef T_PAM_CONV_H_INCLUDED
#define T_PAM_CONV_H_INCLUDED
struct t_pam_conv_script {
int nmsg;
struct pam_message *msgs;
struct pam_response *resps;
char *comment;
};
int t_pam_conv(int, const struct pam_message **, struct pam_response **,
void *);
#endif