The branch, master has been updated via ead5fb5 doc: Add generated pam_chatty.8 man page via 00c1573 doc: Add pam_chatty man page source via b3151fa modules: Remove duplicated discard_const* macros via f23566b tests: Add test for verbose PAM modules via 9398419 tests: Add service file for chatty module via 6a12a71 modules: Add pam_chatty module via c24b23c python: Fix crash when the PAM module outputs too much data via 47250d2 python: Add failure test via c348d45 python: Fix typos from e6574f6 pwrap: Add support for pam_start_confdir()
https://git.samba.org/?p=pam_wrapper.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit ead5fb506cd229ac592bbb3fc3339a3bba20b739 Author: Bastien Nocera <had...@hadess.net> Date: Wed Mar 4 12:50:44 2020 +0100 doc: Add generated pam_chatty.8 man page And install it. Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 00c1573119ca5eb909b800f4d85f939518e1e3a0 Author: Bastien Nocera <had...@hadess.net> Date: Wed Mar 4 12:50:29 2020 +0100 doc: Add pam_chatty man page source Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit b3151fa71d9ff5432eb0a3645e4406277f992ecc Author: Bastien Nocera <had...@hadess.net> Date: Wed Mar 4 12:37:43 2020 +0100 modules: Remove duplicated discard_const* macros They were already defined a couple of lines above. Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit f23566bf85eceb41579cfe0fac07bf94ce16f21d Author: Bastien Nocera <had...@hadess.net> Date: Wed Jan 22 12:22:30 2020 +0100 tests: Add test for verbose PAM modules Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 9398419a3b653c49dcab7da15d2f99a058ed8669 Author: Bastien Nocera <had...@hadess.net> Date: Wed Jan 22 12:21:05 2020 +0100 tests: Add service file for chatty module So we can test it. Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 6a12a712bf7b7b8be33d0410c5ddd48713580012 Author: Bastien Nocera <had...@hadess.net> Date: Wed Jan 22 12:17:03 2020 +0100 modules: Add pam_chatty module Add a simple PAM module that will output "num_lines" lines of PAM info and/or error output. Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit c24b23c628079c7d64386270968209339d29b78c Author: Bastien Nocera <had...@hadess.net> Date: Wed Jan 22 11:50:37 2020 +0100 python: Fix crash when the PAM module outputs too much data This code expected each input (whether echo on or echo off input), to generate at most one info or error output, which is obviously not correct. A PAM module with external inputs can throw dozens of messages and warnings even if the only expected input is a password. Allocate those placeholder arrays to be as big as possible to accomodate chatty PAM modules. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14245 Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 47250d2a974131c7c1db76c13303707dda28aaa4 Author: Bastien Nocera <had...@hadess.net> Date: Wed Jan 22 11:49:31 2020 +0100 python: Add failure test We only had successful pam tests, add a failing one, and check that it fails. Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit c348d45fb518775f6a9b60a6c9b889bb3667d344 Author: Bastien Nocera <had...@hadess.net> Date: Mon Jan 20 18:35:40 2020 +0100 python: Fix typos Signed-off-by: Bastien Nocera <had...@hadess.net> Reviewed-by: Andreas Schneider <a...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> ----------------------------------------------------------------------- Summary of changes: doc/CMakeLists.txt | 5 ++ doc/pam_chatty.8 | 93 ++++++++++++++++++++++++++ doc/pam_chatty.8.txt | 46 +++++++++++++ src/modules/CMakeLists.txt | 2 +- src/modules/pam_chatty.c | 163 +++++++++++++++++++++++++++++++++++++++++++++ src/modules/pam_matrix.c | 8 --- src/python/pypamtest.c | 8 +-- tests/CMakeLists.txt | 3 + tests/pypamtest_test.py | 12 +++- tests/services/chatty.in | 1 + 10 files changed, 327 insertions(+), 14 deletions(-) create mode 100644 doc/pam_chatty.8 create mode 100644 doc/pam_chatty.8.txt create mode 100644 src/modules/pam_chatty.c create mode 100644 tests/services/chatty.in Changeset truncated at 500 lines: diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 21850a5..8a8e60a 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -8,6 +8,11 @@ install(FILES DESTINATION ${MAN_INSTALL_DIR}/man8) +install(FILES + pam_chatty.8 + DESTINATION + ${MAN_INSTALL_DIR}/man8) + install(FILES pam_get_items.8 DESTINATION diff --git a/doc/pam_chatty.8 b/doc/pam_chatty.8 new file mode 100644 index 0000000..89618cb --- /dev/null +++ b/doc/pam_chatty.8 @@ -0,0 +1,93 @@ +'\" t +.\" Title: pam_chatty +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/> +.\" Date: 2020-03-05 +.\" Manual: \ \& +.\" Source: \ \& +.\" Language: English +.\" +.TH "PAM_CHATTY" "8" "2020\-03\-05" "\ \&" "\ \&" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +pam_chatty \- A PAM test module that generates PAM info and error messages\&. +.SH "SYNOPSIS" +.sp +pam_chatty\&.so [\&...] +.SH "DESCRIPTION" +.sp +The \fBpam_chatty\fR module makes it easy to replicate the behaviour of PAM modules that generate a lot of output, in order to ensure that PAM clients react as expected\&. +.SH "IMPORTANT" +.sp +pam_chatty is a \fBtest tool\fR\&. It should be considered completely insecure and never used outside test environments! As you\(cqll see when reading description of the options, many of them don\(cqt make any sense in the real world and were added just to make tests possible\&. +.sp +The pam_chatty module generates a lot of PAM info and error output, when its authentication method is called, and then returns success\&. +.SH "OPTIONS" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fBnum_lines=NUMBER\fR +\- the number of lines of messages to output, for each one of the enabled types of messages selected\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fBerror\fR +\- whether to output error level messages\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fBinfo\fR +\- whether to output info level messages\&. +.RE +.SH "MODULE TYPES PROVIDED" +.sp +Only the \fBauth\fR module type is supported\&. +.SH "EXAMPLE" +.sp +.if n \{\ +.RS 4 +.\} +.nf +auth required pam_chatty\&.so num_lines=16 info error +.fi +.if n \{\ +.RE +.\} diff --git a/doc/pam_chatty.8.txt b/doc/pam_chatty.8.txt new file mode 100644 index 0000000..a30f2cd --- /dev/null +++ b/doc/pam_chatty.8.txt @@ -0,0 +1,46 @@ +pam_chatty(8) +=============== +:revdate: 2020-03-05 + +NAME +---- + +pam_chatty - A PAM test module that generates PAM info and error messages. + +SYNOPSIS +-------- +pam_chatty.so [...] + +DESCRIPTION +----------- +The *pam_chatty* module makes it easy to replicate the behaviour of PAM +modules that generate a lot of output, in order to ensure that PAM clients +react as expected. + +IMPORTANT +--------- +pam_chatty is a *test tool*. It should be considered completely insecure +and never used outside test environments! As you'll see when reading +description of the options, many of them don't make any sense +in the real world and were added just to make tests possible. + +The pam_chatty module generates a lot of PAM info and error output, when +its authentication method is called, and then returns success. + +OPTIONS +------- +* *num_lines=NUMBER* - the number of lines of messages to output, for each +one of the enabled types of messages selected. + +* *error* - whether to output error level messages. + +* *info* - whether to output info level messages. + +MODULE TYPES PROVIDED +--------------------- +Only the *auth* module type is supported. + +EXAMPLE +------- +[source,bash] +auth required pam_chatty.so num_lines=16 info error diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index e7b2604..93bb7d2 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -1,6 +1,6 @@ project(pam_wrapper-modules C) -set(PAM_MODULES pam_matrix pam_get_items pam_set_items) +set(PAM_MODULES pam_matrix pam_get_items pam_set_items pam_chatty) set(PAM_LIBRARIES pam) if (HAVE_PAM_MISC) diff --git a/src/modules/pam_chatty.c b/src/modules/pam_chatty.c new file mode 100644 index 0000000..ba9f65c --- /dev/null +++ b/src/modules/pam_chatty.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2015 Andreas Schneider <a...@samba.org> + * Copyright (c) 2015 Jakub Hrozek <jakub.hro...@posteo.se> + * Copyright (c) 2020 Bastien Nocera <had...@hadess.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <pwd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <time.h> +#include <stdint.h> + +#ifndef discard_const +#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) +#endif + +#ifndef discard_const_p +#define discard_const_p(type, ptr) ((type *)discard_const(ptr)) +#endif + +#ifdef HAVE_SECURITY_PAM_APPL_H +#include <security/pam_appl.h> +#endif +#ifdef HAVE_SECURITY_PAM_MODULES_H +#include <security/pam_modules.h> +#endif +#ifdef HAVE_SECURITY_PAM_EXT_H +#include <security/pam_ext.h> +#endif + +#include "pwrap_compat.h" + +#define ERROR_KEY "error" +#define INFO_KEY "info" +#define NUM_LINES_KEY "num_lines=" + +#define DEFAULT_NUM_LINES 3 + +/* We only return up to 16 messages from the PAM conversation. + * Value from src/python/pypamtest.c */ +#define PAM_CONV_MSG_MAX 16 + +#define PAM_CHATTY_FLG_ERROR (1 << 0) +#define PAM_CHATTY_FLG_INFO (1 << 1) + +static int pam_chatty_conv(pam_handle_t *pamh, + const int msg_style, + const char *msg) +{ + int ret; + const struct pam_conv *conv = NULL; + const struct pam_message *mesg[1]; + struct pam_response *r = NULL; + struct pam_message *pam_msg = NULL; + + ret = pam_get_item(pamh, PAM_CONV, (const void **) &conv); + if (ret != PAM_SUCCESS) { + return ret; + } + + pam_msg = calloc(sizeof(struct pam_message), 1); + if (pam_msg == NULL) { + return PAM_BUF_ERR; + } + + pam_msg->msg_style = msg_style; + pam_msg->msg = discard_const_p(char, msg); + + mesg[0] = (const struct pam_message *) pam_msg; + ret = conv->conv(1, mesg, &r, conv->appdata_ptr); + free(pam_msg); + + return ret; +} + +/* Evaluate command line arguments and store info about them in the + * pam_matrix context + */ +static uint32_t parse_args(int argc, + const char *argv[], + unsigned int *num_lines) +{ + uint32_t flags = 0; + + *num_lines = DEFAULT_NUM_LINES; + + for (; argc-- > 0; ++argv) { + if (strncmp(*argv, NUM_LINES_KEY, strlen(NUM_LINES_KEY)) == 0) { + if (*(*argv+strlen(NUM_LINES_KEY)) != '\0') { + *num_lines = atoi(*argv+strlen(NUM_LINES_KEY)); + if (*num_lines <= DEFAULT_NUM_LINES) + *num_lines = DEFAULT_NUM_LINES; + if (*num_lines > PAM_CONV_MSG_MAX) + *num_lines = PAM_CONV_MSG_MAX; + } + } else if (strncmp(*argv, ERROR_KEY, + strlen(ERROR_KEY)) == 0) { + flags |= PAM_CHATTY_FLG_ERROR; + } else if (strncmp(*argv, INFO_KEY, + strlen(INFO_KEY)) == 0) { + flags |= PAM_CHATTY_FLG_INFO; + } + } + + return flags; +} + +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + uint32_t optflags; + unsigned int num_lines; + + (void) flags; /* unused */ + + optflags = parse_args (argc, argv, &num_lines); + if (optflags & PAM_CHATTY_FLG_INFO) { + unsigned int i; + + for (i = 0; i < num_lines; i++) { + pam_chatty_conv(pamh, + PAM_TEXT_INFO, + "Authentication succeeded"); + } + } + + if (optflags & PAM_CHATTY_FLG_ERROR) { + unsigned int i; + + for (i = 0; i < num_lines; i++) { + pam_chatty_conv(pamh, + PAM_ERROR_MSG, + "Authentication generated an error"); + } + } + + return PAM_SUCCESS; +} diff --git a/src/modules/pam_matrix.c b/src/modules/pam_matrix.c index c48a916..6fb6a2f 100644 --- a/src/modules/pam_matrix.c +++ b/src/modules/pam_matrix.c @@ -93,14 +93,6 @@ } \ } while(0); -#ifndef discard_const -#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) -#endif - -#ifndef discard_const_p -#define discard_const_p(type, ptr) ((type *)discard_const(ptr)) -#endif - struct pam_lib_items { const char *username; const char *service; diff --git a/src/python/pypamtest.c b/src/python/pypamtest.c index 905c652..8de05e9 100644 --- a/src/python/pypamtest.c +++ b/src/python/pypamtest.c @@ -303,7 +303,7 @@ set_pypamtest_exception(PyObject *exc, if (test_repr[0] != '\0' && failed != NULL) { PyErr_Format(exc, - "Error [%d]: Test case %s retured [%d]", + "Error [%d]: Test case %s returned [%d]", perr, test_repr, failed->op_rv); } else { obj = Py_BuildValue(discard_const_p(char, "(i,s)"), @@ -852,8 +852,8 @@ static int fill_conv_data(PyObject *py_echo_off, return ENOMEM; } - conv_data->out_info = new_conv_list(conv_count); - conv_data->out_err = new_conv_list(conv_count); + conv_data->out_info = new_conv_list(PAM_CONV_MSG_MAX); + conv_data->out_err = new_conv_list(PAM_CONV_MSG_MAX); if (conv_data->out_info == NULL || conv_data->out_err == NULL) { free_conv_data(conv_data); return ENOMEM; @@ -906,7 +906,7 @@ static int py_tc_list_to_cstruct_list(PyObject *py_test_list, PyDoc_STRVAR(RunPamTest__doc__, "Run PAM tests\n\n" "This function runs PAM test cases and reports result\n" -"Paramaters:\n" +"Parameters:\n" "service: The PAM service to use in the conversation (string)\n" "username: The user to run PAM conversation as\n" "test_list: Sequence of pypamtest.TestCase objects\n" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d22c272..de8da05 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,9 @@ configure_file(services/matrix_py.in ${CMAKE_CURRENT_BINARY_DIR}/services/matrix configure_file(services/pwrap_get_set.in ${CMAKE_CURRENT_BINARY_DIR}/services/pwrap_get_set @ONLY) +set(PAM_CHATTY_PATH "${CMAKE_BINARY_DIR}/src/modules/pam_chatty.so") +configure_file(services/chatty.in ${CMAKE_CURRENT_BINARY_DIR}/services/chatty @ONLY) + function(ADD_CMOCKA_TEST_ENVIRONMENT _TEST_NAME) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) diff --git a/tests/pypamtest_test.py b/tests/pypamtest_test.py index 32ef65d..c4534bb 100755 --- a/tests/pypamtest_test.py +++ b/tests/pypamtest_test.py @@ -115,6 +115,16 @@ class PyPamTestRunTest(unittest.TestCase): self.assertSequenceEqual(res.info, (u'Authentication succeeded',)) self.assertSequenceEqual(res.errors, ()) + def test_run_failed_auth(self): + neo_password = "not-the-secret" + tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=7) # PAM_AUTH_ERR + res = pypamtest.run_pamtest("neo", "matrix_py", [tc], [ neo_password ]) + + def test_run_chatty_auth(self): + neo_password = "secret" + tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE) + res = pypamtest.run_pamtest("neo", "chatty", [tc], [ neo_password ]) + def test_repr(self): tc = pypamtest.TestCase(pypamtest.PAMTEST_CHAUTHTOK, 1, 2) r = repr(tc) @@ -127,7 +137,7 @@ class PyPamTestRunTest(unittest.TestCase): self.assertRaisesRegexp(pypamtest.PamTestError, "Error \[2\]: Test case { pam_operation \[0\] " "expected_rv \[0\] flags \[0\] } " - "retured \[\d\]", + "returned \[\d\]", pypamtest.run_pamtest, "neo", "matrix_py", [tc], [ neo_password ]) diff --git a/tests/services/chatty.in b/tests/services/chatty.in new file mode 100644 index 0000000..1a81cfc --- /dev/null +++ b/tests/services/chatty.in @@ -0,0 +1 @@ +auth required @PAM_CHATTY_PATH@ num_lines=16 info error -- pam wrapper repository