From d6257e2b1ab60485b6f71068b05147c1cbb35845 Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Fri, 3 Dec 2021 14:33:20 +0100 Subject: pam_env: add a test of return values * modules/pam_env/tst-pam_env-retval.c: New file. * modules/pam_env/Makefile.am (TESTS): Add $(check_PROGRAMS). (check_PROGRAMS, tst_pam_env_retval_LDADD): New variables. Co-authored-by: Dmitry V. Levin --- modules/pam_env/tst-pam_env-retval.c | 199 +++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 modules/pam_env/tst-pam_env-retval.c (limited to 'modules/pam_env/tst-pam_env-retval.c') diff --git a/modules/pam_env/tst-pam_env-retval.c b/modules/pam_env/tst-pam_env-retval.c new file mode 100644 index 00000000..6b9b3065 --- /dev/null +++ b/modules/pam_env/tst-pam_env-retval.c @@ -0,0 +1,199 @@ +/* + * Check pam_env return values. + * + * Copyright (c) 2020-2022 Dmitry V. Levin + * Copyright (c) 2022 Stefan Schubert + */ + +#include "test_assert.h" + +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "pam_env" +#define TEST_NAME "tst-" MODULE_NAME "-retval" + +static const char service_file[] = TEST_NAME ".service"; +static const char missing_file[] = TEST_NAME ".missing"; +static const char my_conf[] = TEST_NAME ".conf"; +static const char my_env[] = TEST_NAME ".env"; + +static struct pam_conv conv; + +static void +setup(void) +{ + FILE *fp; + + ASSERT_NE(NULL, fp = fopen(my_conf, "w")); + ASSERT_LT(0, fprintf(fp, + "EDITOR\tDEFAULT=vim\n" + "PAGER\tDEFAULT=more\n")); + ASSERT_EQ(0, fclose(fp)); + + ASSERT_NE(NULL, fp = fopen(my_env, "w")); + ASSERT_LT(0, fprintf(fp, + "test_value=foo\n" + "test2_value=bar\n")); + ASSERT_EQ(0, fclose(fp)); +} + +static void +cleanup(void) +{ + ASSERT_EQ(0, unlink(my_conf)); + ASSERT_EQ(0, unlink(my_env)); +} + +static void +check_array(const char **array1, char **array2) +{ + for (const char **a1 = array1; *a1 != NULL; ++a1) { + char **a2; + for (a2 = array2; *a2 != NULL; ++a2) { + if (strcmp(*a1, *a2) == 0) + break; + } + ASSERT_NE(NULL, *a2); + } +} + +static void +check_env(const char **list) +{ + pam_handle_t *pamh = NULL; + + ASSERT_EQ(PAM_SUCCESS, + pam_start_confdir(service_file, "", &conv, ".", &pamh)); + ASSERT_NE(NULL, pamh); + + ASSERT_EQ(PAM_SUCCESS, pam_open_session(pamh, 0)); + + char **env_list = pam_getenvlist(pamh); + ASSERT_NE(NULL, env_list); + + check_array(list, env_list); + + for (char **e = env_list; *e != NULL; ++e) + free(*e); + free(env_list); + + ASSERT_EQ(PAM_SUCCESS, pam_close_session(pamh, 0)); + ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0)); +} + +int +main(void) +{ + pam_handle_t *pamh = NULL; + FILE *fp; + char cwd[PATH_MAX]; + + ASSERT_NE(NULL, getcwd(cwd, sizeof(cwd))); + + setup(); + + /* + * When conffile= specifies a missing file, all methods except + * pam_sm_acct_mgmt and pam_sm_chauthtok return PAM_IGNORE. + * The return code of the stack where every module returns PAM_IGNORE + * is PAM_PERM_DENIED. + */ + ASSERT_NE(NULL, fp = fopen(service_file, "w")); + ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n" + "auth required %s/.libs/%s.so conffile=%s/%s\n" + "account required %s/.libs/%s.so conffile=%s/%s\n" + "password required %s/.libs/%s.so conffile=%s/%s\n" + "session required %s/.libs/%s.so conffile=%s/%s\n", + cwd, MODULE_NAME, cwd, missing_file, + cwd, MODULE_NAME, cwd, missing_file, + cwd, MODULE_NAME, cwd, missing_file, + cwd, MODULE_NAME, cwd, missing_file)); + ASSERT_EQ(0, fclose(fp)); + + ASSERT_EQ(PAM_SUCCESS, + pam_start_confdir(service_file, "", &conv, ".", &pamh)); + ASSERT_NE(NULL, pamh); + ASSERT_EQ(PAM_PERM_DENIED, pam_authenticate(pamh, 0)); + ASSERT_EQ(PAM_PERM_DENIED, pam_setcred(pamh, 0)); + ASSERT_EQ(PAM_SERVICE_ERR, pam_acct_mgmt(pamh, 0)); + ASSERT_EQ(PAM_SERVICE_ERR, pam_chauthtok(pamh, 0)); + ASSERT_EQ(PAM_PERM_DENIED, pam_open_session(pamh, 0)); + ASSERT_EQ(PAM_PERM_DENIED, pam_close_session(pamh, 0)); + ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0)); + pamh = NULL; + + /* + * When conffile= specifies a missing file, all methods except + * pam_sm_acct_mgmt and pam_sm_chauthtok return PAM_IGNORE. + * pam_permit is added after pam_env to convert PAM_IGNORE to PAM_SUCCESS. + */ + ASSERT_NE(NULL, fp = fopen(service_file, "w")); + ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n" + "auth required %s/.libs/%s.so conffile=%s/%s\n" + "auth required %s/../pam_permit/.libs/pam_permit.so\n" + "account required %s/.libs/%s.so conffile=%s/%s\n" + "account required %s/../pam_permit/.libs/pam_permit.so\n" + "password required %s/.libs/%s.so conffile=%s/%s\n" + "password required %s/../pam_permit/.libs/pam_permit.so\n" + "session required %s/.libs/%s.so conffile=%s/%s\n" + "session required %s/../pam_permit/.libs/pam_permit.so\n", + cwd, MODULE_NAME, cwd, missing_file, cwd, + cwd, MODULE_NAME, cwd, missing_file, cwd, + cwd, MODULE_NAME, cwd, missing_file, cwd, + cwd, MODULE_NAME, cwd, missing_file, cwd)); + ASSERT_EQ(0, fclose(fp)); + + ASSERT_EQ(PAM_SUCCESS, + pam_start_confdir(service_file, "", &conv, ".", &pamh)); + ASSERT_NE(NULL, pamh); + ASSERT_EQ(PAM_SUCCESS, pam_authenticate(pamh, 0)); + ASSERT_EQ(PAM_SUCCESS, pam_setcred(pamh, 0)); + ASSERT_EQ(PAM_SERVICE_ERR, pam_acct_mgmt(pamh, 0)); + ASSERT_EQ(PAM_SERVICE_ERR, pam_chauthtok(pamh, 0)); + ASSERT_EQ(PAM_SUCCESS, pam_open_session(pamh, 0)); + ASSERT_EQ(PAM_SUCCESS, pam_close_session(pamh, 0)); + ASSERT_EQ(PAM_SUCCESS, pam_end(pamh, 0)); + pamh = NULL; + + /* + * conffile= specifies an existing file, + * envfile= specifies an empty file. + */ + ASSERT_NE(NULL, fp = fopen(service_file, "w")); + ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n" + "session required %s/.libs/%s.so" + " conffile=%s/%s envfile=%s\n", + cwd, MODULE_NAME, + cwd, my_conf, "/dev/null")); + ASSERT_EQ(0, fclose(fp)); + + const char *env1[] = { "EDITOR=vim", "PAGER=more", NULL }; + check_env(env1); + + /* + * conffile= specifies an empty file, + * envfile= specifies an existing file. + */ + ASSERT_NE(NULL, fp = fopen(service_file, "w")); + ASSERT_LT(0, fprintf(fp, "#%%PAM-1.0\n" + "session required %s/.libs/%s.so" + " conffile=%s envfile=%s/%s\n", + cwd, MODULE_NAME, + "/dev/null", cwd, my_env)); + ASSERT_EQ(0, fclose(fp)); + + const char *env2[] = { "test_value=foo", "test2_value=bar", NULL }; + check_env(env2); + + /* cleanup */ + cleanup(); + ASSERT_EQ(0, unlink(service_file)); + + return 0; +} -- cgit v1.2.3