pwrap: Add pam_get_items.so and pam_set_items.so
authorJakub Hrozek <jakub.hrozek@posteo.se>
Tue, 20 Oct 2015 13:47:48 +0000 (15:47 +0200)
committerAndreas Schneider <asn@samba.org>
Thu, 10 Dec 2015 12:31:19 +0000 (13:31 +0100)
src/CMakeLists.txt
src/modules/pam_get_items.c [new file with mode: 0644]
src/modules/pam_set_items.c [new file with mode: 0644]
tests/CMakeLists.txt
tests/services/pwrap_get_set.in [new file with mode: 0644]
tests/test_pam_wrapper.c

index b09a78fd03fadc516902a3495e9df5b4e084fc71..1455bb36baf8e346ae32348e02709996a5136122 100644 (file)
@@ -45,25 +45,27 @@ install(
   ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
 )
 
-add_library(pam_matrix MODULE modules/pam_matrix.c)
-set_property(TARGET pam_matrix PROPERTY PREFIX "")
-
+set(PAM_MODULES pam_matrix pam_get_items pam_set_items)
 set(PAM_LIBRARIES
     pam
     pam_misc)
 
-target_link_libraries(pam_matrix
-                       ${PAM_LIBRARIES})
-
 set(PWRAP_PRIVATE_LIBRARIES
        ${LIB_INSTALL_DIR}/pam_wrapper)
 
-install(
-  TARGETS
-    pam_matrix
-  LIBRARY DESTINATION ${PWRAP_PRIVATE_LIBRARIES}
-  ARCHIVE DESTINATION ${PWRAP_PRIVATE_LIBRARIES}
-)
+foreach(_PAM_MODULE ${PAM_MODULES})
+       add_library(${_PAM_MODULE} MODULE modules/${_PAM_MODULE}.c)
+       set_property(TARGET ${_PAM_MODULE} PROPERTY PREFIX "")
+
+       target_link_libraries(${_PAM_MODULE}
+                               ${PAM_LIBRARIES})
+
+       install(
+               TARGETS
+                       ${_PAM_MODULE}
+               LIBRARY DESTINATION ${PWRAP_PRIVATE_LIBRARIES}
+               ARCHIVE DESTINATION ${PWRAP_PRIVATE_LIBRARIES})
+endforeach()
 
 # This needs to be at the end
 if (POLICY CMP0026)
diff --git a/src/modules/pam_get_items.c b/src/modules/pam_get_items.c
new file mode 100644 (file)
index 0000000..ec9f70f
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
+ * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <security/pam_modules.h>
+#include <security/pam_appl.h>
+
+static const char *str_opt(const int opt)
+{
+       switch (opt) {
+       case PAM_SERVICE:
+               return "PAM_SERVICE";
+       case PAM_USER:
+               return "PAM_USER";
+       case PAM_USER_PROMPT:
+               return "PAM_USER_PROMPT";
+       case PAM_TTY:
+               return "PAM_TTY";
+       case PAM_RUSER:
+               return "PAM_RUSER";
+       case PAM_RHOST:
+               return "PAM_RHOST";
+       case PAM_AUTHTOK:
+               return "PAM_AUTHTOK";
+       case PAM_OLDAUTHTOK:
+               return "PAM_OLDAUTHTOK";
+       case PAM_XDISPLAY:
+               return "PAM_XDISPLAY";
+       case PAM_AUTHTOK_TYPE:
+               return "PAM_AUTHTOK_TYPE";
+       }
+
+       return NULL;    /* Unsupported */
+}
+
+static int putenv_item(pam_handle_t *pamh,
+                      int item_type)
+{
+       const char *opt_name;
+       const char *value = NULL;
+       char *env_name;
+       size_t env_len;
+       int rv;
+
+       rv = pam_get_item(pamh, item_type, (const void **) &value);
+       if (rv != PAM_SUCCESS) {
+               return rv;
+       }
+
+       if (value == NULL) {
+               return PAM_SUCCESS;
+       }
+
+       opt_name = str_opt(item_type);
+       if (opt_name == NULL) {
+               /* Probably some non-printable value */
+               return PAM_BAD_ITEM;
+       }
+
+       env_len = strlen(value) + strlen(opt_name) + 2;
+       env_name = malloc(env_len);
+       if (env_name == NULL) {
+               return PAM_BUF_ERR;
+       }
+
+       rv = snprintf(env_name, env_len, "%s=%s", opt_name, value);
+       if (rv < 0) {
+               free(env_name);
+               return PAM_BUF_ERR;
+       }
+
+       rv = pam_putenv(pamh, env_name);
+       free(env_name);
+
+       return rv;
+}
+
+/* Get all pam_items and put them into environment */
+static int pam_putitem(pam_handle_t *pamh)
+{
+
+       putenv_item(pamh, PAM_SERVICE);
+       putenv_item(pamh, PAM_USER);
+       putenv_item(pamh, PAM_USER_PROMPT);
+       putenv_item(pamh, PAM_TTY);
+       putenv_item(pamh, PAM_RUSER);
+       putenv_item(pamh, PAM_RHOST);
+       putenv_item(pamh, PAM_AUTHTOK);
+       putenv_item(pamh, PAM_OLDAUTHTOK);
+       putenv_item(pamh, PAM_XDISPLAY);
+       putenv_item(pamh, PAM_AUTHTOK_TYPE);
+
+       return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
+                   int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       return pam_putitem(pamh);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags,
+              int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       return pam_putitem(pamh);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+                int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       return pam_putitem(pamh);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+                   int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       return pam_putitem(pamh);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags,
+                    int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       return pam_putitem(pamh);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+                int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       return pam_putitem(pamh);
+}
diff --git a/src/modules/pam_set_items.c b/src/modules/pam_set_items.c
new file mode 100644 (file)
index 0000000..0fccf4c
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
+ * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <security/pam_modules.h>
+#include <security/pam_appl.h>
+
+#define ITEM_FILE_KEY  "item_file="
+
+static const char *envs[] = {
+       "PAM_SERVICE",
+       "PAM_USER",
+       "PAM_USER_PROMPT",
+       "PAM_TTY",
+       "PAM_RUSER",
+       "PAM_RHOST",
+       "PAM_AUTHTOK",
+       "PAM_OLDAUTHTOK",
+       "PAM_XDISPLAY",
+       "PAM_AUTHTOK_TYPE",
+       NULL
+};
+
+static const int items[] = {
+       PAM_SERVICE,
+       PAM_USER,
+       PAM_USER_PROMPT,
+       PAM_TTY,
+       PAM_RUSER,
+       PAM_RHOST,
+       PAM_AUTHTOK,
+       PAM_OLDAUTHTOK,
+       PAM_XDISPLAY,
+       PAM_AUTHTOK_TYPE,
+};
+
+static void pam_setitem_env(pam_handle_t *pamh)
+{
+       int i;
+       int rv;
+       const char *v;
+
+       for (i = 0; envs[i] != NULL; i++) {
+               v = getenv(envs[i]);
+               if (v == NULL) {
+                       continue;
+               }
+
+               rv = pam_set_item(pamh, items[i], v);
+               if (rv != PAM_SUCCESS) {
+                       continue;
+               }
+       }
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
+                   int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       pam_setitem_env(pamh);
+       return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags,
+              int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       pam_setitem_env(pamh);
+       return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+                int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       pam_setitem_env(pamh);
+       return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+                   int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       pam_setitem_env(pamh);
+       return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags,
+                    int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       pam_setitem_env(pamh);
+       return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+                int argc, const char *argv[])
+{
+       (void) flags;   /* unused */
+       (void) argc;    /* unused */
+       (void) argv;    /* unused */
+
+       pam_setitem_env(pamh);
+       return PAM_SUCCESS;
+}
+
index c53090c0b753d3f609013f9472302af68915bd74..59db52ba634f1edf7837911e56d0f7f8cc274544 100644 (file)
@@ -15,6 +15,8 @@ set(PASSDB_PATH
 configure_file(passdb_ro ${PASSDB_PATH} @ONLY)
 configure_file(services/pwrap_pam_opt.in ${CMAKE_CURRENT_BINARY_DIR}/services/pwrap_pam_opt @ONLY)
 
+configure_file(services/pwrap_get_set.in ${CMAKE_CURRENT_BINARY_DIR}/services/pwrap_get_set @ONLY)
+
 if (OSX)
        set(TEST_ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${PAM_WRAPPER_LOCATION};PAM_WRAPPER=1;PAM_WRAPPER_CONFDIR=${CMAKE_CURRENT_BINARY_DIR}/services})
        add_definitions(-DOSX)
diff --git a/tests/services/pwrap_get_set.in b/tests/services/pwrap_get_set.in
new file mode 100644 (file)
index 0000000..48809b9
--- /dev/null
@@ -0,0 +1,2 @@
+session                required        @CMAKE_CURRENT_BINARY_DIR@/../src/pam_set_items.so
+session                required        @CMAKE_CURRENT_BINARY_DIR@/../src/pam_get_items.so
index d34b0974c7f15f2cd238d0bdb1e9ab2afd89c17e..69d95b62d137ba73656df647b14c98e82c1f02ae 100644 (file)
@@ -619,6 +619,58 @@ static void test_pam_vsyslog(void **state)
        pam_syslog(test_ctx->ph, LOG_INFO, "This is pam_wrapper test\n");
 }
 
+#define test_setenv(env) setenv(env, "test_"env, 1)
+
+#define test_getenv(envlist, key) do {                             \
+       const char *__v;                                            \
+       __v = string_in_list(envlist, key);                         \
+       assert_non_null(__v);                                       \
+       assert_string_equal(__v, "test_"key);                       \
+} while(0);
+
+static void test_get_set(void **state)
+{
+       const char *svc;
+       enum pamtest_err perr;
+       struct pamtest_case tests[] = {
+               { PAMTEST_OPEN_SESSION, PAM_SUCCESS, 0, 0 },
+               { PAMTEST_GETENVLIST, PAM_SUCCESS, 0, 0 },
+               { PAMTEST_SENTINEL, 0, 0, 0 },
+       };
+
+       (void) state;   /* unused */
+
+       test_setenv("PAM_SERVICE");
+       test_setenv("PAM_USER");
+       test_setenv("PAM_USER_PROMPT");
+       test_setenv("PAM_TTY");
+       test_setenv("PAM_RUSER");
+       test_setenv("PAM_RHOST");
+       test_setenv("PAM_AUTHTOK");
+       test_setenv("PAM_OLDAUTHTOK");
+       test_setenv("PAM_XDISPLAY");
+       test_setenv("PAM_AUTHTOK_TYPE");
+
+       perr = pamtest("pwrap_get_set", "testuser", NULL, tests);
+       assert_int_equal(perr, PAMTEST_ERR_OK);
+
+       /* PAM_SERVICE is a special case, libpam lowercases it */
+       svc = string_in_list(tests[1].case_out.envlist, "PAM_SERVICE");
+       assert_non_null(svc);
+       assert_string_equal(svc, "test_pam_service");
+
+       //test_getenv(tests[1].case_out.envlist, "PAM_SERVICE");
+       test_getenv(tests[1].case_out.envlist, "PAM_USER");
+       test_getenv(tests[1].case_out.envlist, "PAM_USER_PROMPT");
+       test_getenv(tests[1].case_out.envlist, "PAM_TTY");
+       test_getenv(tests[1].case_out.envlist, "PAM_RUSER");
+       test_getenv(tests[1].case_out.envlist, "PAM_RHOST");
+       test_getenv(tests[1].case_out.envlist, "PAM_AUTHTOK");
+       test_getenv(tests[1].case_out.envlist, "PAM_OLDAUTHTOK");
+       test_getenv(tests[1].case_out.envlist, "PAM_XDISPLAY");
+       test_getenv(tests[1].case_out.envlist, "PAM_AUTHTOK_TYPE");
+}
+
 int main(void) {
        int rc;
 
@@ -669,6 +721,7 @@ int main(void) {
                cmocka_unit_test_setup_teardown(test_pam_vsyslog,
                                                setup_noconv,
                                                teardown),
+               cmocka_unit_test(test_get_set),
        };
 
        rc = cmocka_run_group_tests(init_tests, NULL, NULL);