diff --git a/.gitignore b/.gitignore index b25c15b..8d73a56 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *~ +pam_wlan.so +pam_wlan_test diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 74cddb8..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -cmake_minimum_required(VERSION 2.8.3) -project(PAM_NETWORK_MANAGER C) - -set(CMAKE_MODULE_PATH ${PAM_NETWORK_MANAGER_SOURCE_DIR}) - -find_package(PAM REQUIRED) -find_package(libnm_glib REQUIRED) - -set(PAM_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/lib/security" CACHE STRING "PAM module directory") -set(PAM_NETWORK_MANAGER_HELPER_DIR "${CMAKE_INSTALL_PREFIX}/lib/security/pam_network_manager" CACHE STRING "pam_network_manager_helper install directory") - -set(CONNECTION_TIMEOUT "10" CACHE STRING "Connection timeout") -set(CONNECTION_ID "" CACHE STRING "Connection ID") -set(CONNECTION_UUID "" CACHE STRING "Connection UUID") -set(CONNECTION_SSID "" CACHE STRING "Connection SSID") -set(CONNECTION_AUTH_ALG "open" CACHE STRING "Connection authentication algorithm") -set(CONNECTION_KEY_MGMT "wpa-eap" CACHE STRING "Connection key management method") -set(CONNECTION_EAP "ttls" CACHE STRING "Connection EAP method") -set(CONNECTION_PHASE2_AUTHEAP "mschapv2" CACHE STRING "Connection EAP phase2 authentication method") - -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${PAM_INCLUDE_DIR} ${LIBNM_GLIB_INCLUDE_DIRS}) -link_directories(${LIBNM_GLIB_LIBRARY_DIRS}) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) - -add_executable(pam_network_manager_helper pam_network_manager_helper.c) -set_property(TARGET pam_network_manager_helper PROPERTY COMPILE_DEFINITIONS "_DEFAULT_SOURCE;_BSD_SOURCE") -set_property(TARGET pam_network_manager_helper PROPERTY COMPILE_FLAGS "-std=c99 -Wall ${LIBNM_GLIB_CFLAGS_OTHER}") -set_property(TARGET pam_network_manager_helper PROPERTY LINK_FLAGS "${LIBNM_GLIB_LDFLAGS_OTHER}") -target_link_libraries(pam_network_manager_helper ${LIBNM_GLIB_LIBRARIES}) - -add_executable(pam_network_manager_test pam_network_manager.c) -set_property(TARGET pam_network_manager_test PROPERTY COMPILE_DEFINITIONS "_DEFAULT_SOURCE;_BSD_SOURCE;TEST") -set_property(TARGET pam_network_manager_test PROPERTY COMPILE_FLAGS "-std=c99 -Wall") - -add_library(pam_network_manager MODULE pam_network_manager.c) -set_property(TARGET pam_network_manager PROPERTY COMPILE_DEFINITIONS "_DEFAULT_SOURCE;_BSD_SOURCE") -set_property(TARGET pam_network_manager PROPERTY COMPILE_FLAGS "-std=c99 -Wall") -set_property(TARGET pam_network_manager PROPERTY PREFIX "") - -install(TARGETS pam_network_manager pam_network_manager_helper - RUNTIME DESTINATION "${PAM_NETWORK_MANAGER_HELPER_DIR}" - LIBRARY DESTINATION "${PAM_MODULE_DIR}" -) diff --git a/FindPAM.cmake b/FindPAM.cmake deleted file mode 100644 index bccdf9b..0000000 --- a/FindPAM.cmake +++ /dev/null @@ -1,15 +0,0 @@ -FIND_PATH(PAM_INCLUDE_DIR security/pam_modules.h) - -IF (PAM_INCLUDE_DIR) - SET(PAM_FOUND TRUE) -ENDIF (PAM_INCLUDE_DIR) - -IF (PAM_FOUND) - IF (NOT PAM_FIND_QUIETLY) - MESSAGE(STATUS "Found PAM (include path: ${PAM_INCLUDE_DIR})") - ENDIF (NOT PAM_FIND_QUIETLY) -ELSE (PAM_FOUND) - IF (PAM_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find PAM") - ENDIF (PAM_FIND_REQUIRED) -ENDIF (PAM_FOUND) diff --git a/Findlibnm_glib.cmake b/Findlibnm_glib.cmake deleted file mode 100644 index 3256940..0000000 --- a/Findlibnm_glib.cmake +++ /dev/null @@ -1,20 +0,0 @@ -# Defines the following variables: -# LIBNM_GLIB_FOUND -# LIBNM_GLIB_INCLUDE_DIRS -# LIBNM_GLIB_CFLAGS_OTHER -# LIBNM_GLIB_LIBRARIES -# LIBNM_GLIB_LIBRARY_DIRS -# LIBNM_GLIB_LDFLAGS_OTHER - - -find_package(PkgConfig REQUIRED QUIET) -pkg_check_modules(_LIBNM_GLIB libnm-glib) - -set(LIBNM_GLIB_INCLUDE_DIRS "${_LIBNM_GLIB_INCLUDE_DIRS}" CACHE STRING "Include directories for libnm-glib") -set(LIBNM_GLIB_CFLAGS_OTHER "${_LIBNM_GLIB_CFLAGS_OTHER}" CACHE STRING "Additional compiler flags for libnm-glib") -set(LIBNM_GLIB_LIBRARY_DIRS "${_LIBNM_GLIB_LIBRARY_DIRS}" CACHE STRING "Library directories for libnm-glib") -set(LIBNM_GLIB_LIBRARIES "${_LIBNM_GLIB_LIBRARIES}" CACHE STRING "Libraries for libnm-glib") -set(LIBNM_GLIB_LDFLAGS_OTHER "${_LIBNM_GLIB_LDFLAGS_OTHER}" CACHE STRING "Additional linker flags for libnm-glib") - -find_package_handle_standard_args(LIBNM_GLIB REQUIRED_VARS LIBNM_GLIB_LIBRARIES LIBNM_GLIB_INCLUDE_DIRS) -mark_as_advanced(LIBNM_GLIB_INCLUDE_DIRS LIBNM_GLIB_CFLAGS_OTHER LIBNM_GLIB_LIBRARIES LIBNM_GLIB_LIBRARY_DIRS LIBNM_GLIB_LDFLAGS_OTHER) diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 28f845a..0000000 --- a/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2015, Kristof Stahl -Copyright (c) 2015, Matthias Schiffer -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. - -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 HOLDER 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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0f62ec7 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all : pam_wlan.so pam_wlan_test + +pam_wlan.so : pam_wlan.c + $(CC) -fPIC -shared -o pam_wlan.so pam_wlan.c $(shell pkg-config --cflags --libs libnm-glib) -Wall + +pam_wlan_test : pam_wlan.c + $(CC) -g -DTEST -o pam_wlan_test pam_wlan.c $(shell pkg-config --cflags --libs libnm-glib) -Wall diff --git a/config.h.in b/config.h.in deleted file mode 100644 index a0ab8bc..0000000 --- a/config.h.in +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright (c) 2015, Kristof Stahl - Copyright (c) 2015, Matthias Schiffer - 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. - - 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 HOLDER 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. -*/ - - -#pragma once - - -#define PAM_NETWORK_MANAGER_HELPER "@PAM_NETWORK_MANAGER_HELPER_DIR@/pam_network_manager_helper" - - -#define CONNECTION_TIMEOUT @CONNECTION_TIMEOUT@ -#define CONNECTION_ID "@CONNECTION_ID@" -#define CONNECTION_UUID "@CONNECTION_UUID@" -#define CONNECTION_SSID "@CONNECTION_SSID@" -#define CONNECTION_AUTH_ALG "@CONNECTION_AUTH_ALG@" -#define CONNECTION_KEY_MGMT "@CONNECTION_KEY_MGMT@" -#define CONNECTION_EAP "@CONNECTION_EAP@" -#define CONNECTION_PHASE2_AUTHEAP "@CONNECTION_PHASE2_AUTHEAP@" diff --git a/pam_network_manager.c b/pam_network_manager.c deleted file mode 100644 index 15a2f3c..0000000 --- a/pam_network_manager.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright (c) 2015, Kristof Stahl - Copyright (c) 2015, Matthias Schiffer - 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. - - 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 HOLDER 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. -*/ - - -/* - See: - - http://www.linux-pam.org/Linux-PAM-html/mwg-expected-of-module-auth.html - http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html - http://www.linux-pam.org/Linux-PAM-html/mwg-see-programming-libs.html - some (bad) example.. https://github.com/beatgammit/simple-pam/blob/master/src/mypam.c -*/ - -#define PAM_SM_AUTH - -#include -#include - -#include -#include - -#include - -#include - - -#define UNUSED __attribute__((unused)) - - -static int authenticate(const char *user, const char *pass) { - FILE *stream = popen(PAM_NETWORK_MANAGER_HELPER, "we"); - - fputs(user, stream); - fputc(0, stream); - fputs(pass, stream); - - int status = pclose(stream); - - if (WIFEXITED(status)) - return WEXITSTATUS(status); - else - return PAM_SYSTEM_ERR; -} - -#ifdef TEST - -int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: pam_network_manager_test \n"); - return 1; - } - - char *pass = getpass("Password: "); - - fprintf(stderr, "Return: %i\n", authenticate(argv[1], pass)); - - return 0; -} - -#else - -PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, UNUSED int flags, UNUSED int argc, UNUSED const char **argv) { - const void *pass; - const void *user; - int result; - - result = pam_get_item(pamh, PAM_USER, &user); - if (result != PAM_SUCCESS) - return PAM_INCOMPLETE; - - result = pam_get_item(pamh, PAM_AUTHTOK, &pass); - if (result != PAM_SUCCESS) - return PAM_INCOMPLETE; - - return authenticate(user, pass); -} - -#endif diff --git a/pam_network_manager_helper.c b/pam_wlan.c similarity index 65% rename from pam_network_manager_helper.c rename to pam_wlan.c index e4153f4..181bb6a 100644 --- a/pam_network_manager_helper.c +++ b/pam_wlan.c @@ -26,14 +26,31 @@ /* - See: + Helpful pages: + + http://www.linux-pam.org/Linux-PAM-html/mwg-expected-of-module-auth.html + http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html + http://www.linux-pam.org/Linux-PAM-html/mwg-see-programming-libs.html + some (bad) example.. https://github.com/beatgammit/simple-pam/blob/master/src/mypam.c https://developer.gnome.org/libnm-glib/0.9/ https://developer.gnome.org/libnm-util/0.9/ */ +#define PAM_SM_AUTH + +#ifdef TEST + #include + +#endif + +#include #include +#include + +#include +#include #include @@ -46,10 +63,16 @@ #include #include -#include +#define TIMEOUT 10 +#define CONNECTION_ID "UzL-Wlan" +#define CONNECTION_UUID "af7b7f0b-3e09-442e-8841-f7d7482fa7b0" -#define UNUSED __attribute__((unused)) +#define CONNECTION_SSID "UzL-Wlan" +#define CONNECTION_AUTH_ALG "open" +#define CONNECTION_KEY_MGMT "wpa-eap" +#define CONNECTION_EAP "ttls" +#define CONNECTION_PHASE2_AUTHEAP "mschapv2" static GByteArray * string_to_byte_array(const char *str) { @@ -112,7 +135,7 @@ static int setup_connection(NMConnection *con, const char *user, const char *pas /* NMSettingIP6Config */ setting = nm_setting_ip6_config_new(); g_object_set(G_OBJECT(setting), - NM_SETTING_IP6_CONFIG_METHOD, "link-local", + NM_SETTING_IP6_CONFIG_METHOD, "auto", NULL); nm_connection_add_setting(con, setting); @@ -123,7 +146,6 @@ typedef struct { int ret; GMainLoop *loop; NMClient *client; - NMRemoteConnection *con; } cb_arg; @@ -141,14 +163,7 @@ static NMDevice * find_device(NMClient *client) { return NULL; } -static gboolean timeout_cb(gpointer user_data) { - cb_arg *arg = user_data; - g_main_loop_quit(arg->loop); - - return FALSE; -} - -static void state_cb(NMDevice *device, UNUSED GParamSpec *pspec, gpointer user_data) { +static void state_cb(NMDevice *device, GParamSpec *pspec, gpointer user_data) { cb_arg *arg = user_data; NMActiveConnection *active_connection = nm_device_get_active_connection(device); @@ -165,19 +180,20 @@ static void state_cb(NMDevice *device, UNUSED GParamSpec *pspec, gpointer user_d } } -static void activate_cb(UNUSED NMClient *client, UNUSED NMActiveConnection *active_connection, GError *error, gpointer user_data) { +static void activate_cb(NMClient *client, NMActiveConnection *active_connection, GError *error, gpointer user_data) { cb_arg *arg = user_data; if (error) goto error; + return; error: g_main_loop_quit(arg->loop); } -static void add_cb(UNUSED NMRemoteSettings *settings, NMRemoteConnection *con, GError *error, gpointer user_data) { +static void add_cb(NMRemoteSettings *settings, NMRemoteConnection *con, GError *error, gpointer user_data) { cb_arg *arg = user_data; if (error) @@ -187,86 +203,21 @@ static void add_cb(UNUSED NMRemoteSettings *settings, NMRemoteConnection *con, G if (!device) goto error; - arg->con = con; - g_signal_connect(device, "notify::state", G_CALLBACK(state_cb), arg); nm_client_activate_connection(arg->client, NM_CONNECTION(con), device, NULL, activate_cb, arg); - - g_timeout_add_seconds(CONNECTION_TIMEOUT, timeout_cb, arg); return; error: g_main_loop_quit(arg->loop); } -static void delete_cb(UNUSED NMRemoteConnection *connection, UNUSED GError *error, gpointer user_data) { - cb_arg *arg = user_data; - g_main_loop_quit(arg->loop); -} - -static void read_cb(UNUSED NMRemoteSettings *settings, gpointer user_data) { - cb_arg *arg = user_data; - g_main_loop_quit(arg->loop); -} - -static gboolean match_connection_user(NMConnection *connection, const char *user) { - NMSetting8021x *setting = nm_connection_get_setting_802_1x(connection); - if (!setting) - return FALSE; - - const char *identity = nm_setting_802_1x_get_identity(setting); - if (!identity) - return FALSE; - - return (strcmp(identity, user) == 0); -} - -static gboolean is_connection_active(NMConnection *connection, cb_arg *arg) { - NMDevice *device = find_device(arg->client); - if (!device) - return FALSE; - - NMActiveConnection *active_connection = nm_device_get_active_connection(device); - if (!active_connection) - return FALSE; - - if (strcmp(nm_connection_get_path(connection), nm_active_connection_get_connection(active_connection)) != 0) - return FALSE; - - NMActiveConnectionState state = nm_active_connection_get_state(active_connection); - - return (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED); -} - -static gboolean handle_old_connection(NMRemoteSettings *settings, const char *user, cb_arg *arg) { - NMRemoteConnection *con = NULL; - - g_signal_connect(settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ, - G_CALLBACK(read_cb), arg); - - g_main_loop_run(arg->loop); - - con = nm_remote_settings_get_connection_by_uuid(settings, CONNECTION_UUID); - if (!con) - goto end; - - if (match_connection_user(NM_CONNECTION(con), user) && is_connection_active(NM_CONNECTION(con), arg)) - return TRUE; - - nm_remote_connection_delete(con, delete_cb, arg); - g_main_loop_run(arg->loop); - - end: - return FALSE; -} - -static int authenticate(const char *user, const char *pass) { +static int do_authenticate(const char *user, const char *pass) { DBusGConnection *dbus = NULL; NMRemoteSettings *settings = NULL; NMConnection *con = NULL; cb_arg arg = {}; - arg.ret = PAM_SERVICE_ERR; + arg.ret = PAM_SYSTEM_ERR; arg.loop = g_main_loop_new(NULL, FALSE); arg.client = nm_client_new(); @@ -281,13 +232,7 @@ static int authenticate(const char *user, const char *pass) { if (!settings) goto end; - if (handle_old_connection(settings, user, &arg)) { - arg.ret = PAM_IGNORE; - goto end; - } - con = nm_connection_new(); - setup_connection(con, user, pass); if (!nm_remote_settings_add_connection_unsaved(settings, con, add_cb, &arg)) @@ -297,47 +242,81 @@ static int authenticate(const char *user, const char *pass) { g_main_loop_run(arg.loop); - if (arg.ret == PAM_SUCCESS) - goto end; - - /* Error */ - if (arg.con) { - nm_remote_connection_delete(arg.con, delete_cb, &arg); - g_main_loop_run(arg.loop); - } - end: - if (con) - g_object_unref(con); - if (settings) - g_object_unref(settings); - if (dbus) - dbus_g_connection_unref(dbus); - if (arg.client) - g_object_unref(arg.client); + g_object_unref(con); + + g_object_unref(settings); + dbus_g_connection_unref(dbus); + g_object_unref(arg.client); g_main_loop_unref(arg.loop); return arg.ret; } -int main() { - char buf[1024]; - size_t len = 0; +static int authenticate(const char *user, const char *pass) { + int status; + int fds[2]; + if (pipe(fds)) + return PAM_SYSTEM_ERR; - while (len < sizeof(buf)-1) { - size_t r = fread(buf+len, 1, sizeof(buf)-len-1, stdin); - if (!r) - break; + pid_t pid = fork(); + if (pid < 0) + return PAM_SYSTEM_ERR; - len += r; + if (pid == 0) { + close(fds[0]); + status = do_authenticate(user, pass); + write(fds[1], &status, sizeof(status)); + close(fds[1]); + _exit(0); } - buf[len] = 0; + close(fds[1]); - const char *user = buf; - const char *pass = user + strlen(user) + 1; - if (pass > buf+len) - return PAM_SYSTEM_ERR; + if (waitpid(pid, NULL, 0) < 0) + goto error; + + if (read(fds[0], &status, sizeof(status)) != sizeof(status)) + goto error; + + close(fds[0]); + return status; + + error: + close(fds[0]); + return PAM_SYSTEM_ERR; +} + +#ifdef TEST + +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: pam_wlan_test \n"); + return 1; + } + + char *pass = getpass("Password: "); + + fprintf(stderr, "Return: %i\n", authenticate(argv[1], pass)); + + return 0; +} + +#else + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, __attribute__((unused)) int flags, __attribute__((unused)) int argc, __attribute__((unused)) const char **argv) { + const void *pass; + const void *user; + int result; + + result = pam_get_item(pamh, PAM_USER, &user); + if (result != PAM_SUCCESS) + return PAM_INCOMPLETE; + + result = pam_get_item(pamh, PAM_AUTHTOK, &pass); + if (result != PAM_SUCCESS) + return PAM_INCOMPLETE; return authenticate(user, pass); } +#endif