diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2015-05-12 16:35:54 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2015-05-12 16:35:54 +0200 |
commit | 11f2c30f5b58de7c543ffc3e93fd508e3c8bcab3 (patch) | |
tree | 02f0d965ef6bf65f5841fff69b49750f8c136b2f | |
parent | 6ae9a6a1642fcaf808c934931139484776a56a9a (diff) | |
download | pam_network_manager-11f2c30f5b58de7c543ffc3e93fd508e3c8bcab3.tar pam_network_manager-11f2c30f5b58de7c543ffc3e93fd508e3c8bcab3.zip |
Split module into a helper executable and a minimal module
-rw-r--r-- | CMakeLists.txt | 34 | ||||
-rw-r--r-- | FindPAM.cmake | 15 | ||||
-rw-r--r-- | Findlibnm_glib.cmake | 20 | ||||
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | config.h.in | 31 | ||||
-rw-r--r-- | pam_wlan.c | 249 | ||||
-rw-r--r-- | pam_wlan_helper.c | 261 |
7 files changed, 375 insertions, 242 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1bb7f49 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8.3) +project(PAM_WLAN C) + +set(CMAKE_MODULE_PATH ${PAM_WLAN_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_WLAN_HELPER_DIR "${CMAKE_INSTALL_PREFIX}/lib/security/pam_wlan" CACHE STRING "pam_wlan_helper install directory") + +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_wlan_helper pam_wlan_helper.c) +set_property(TARGET pam_wlan_helper PROPERTY COMPILE_DEFINITIONS "_DEFAULT_SOURCE;_BSD_SOURCE") +set_property(TARGET pam_wlan_helper PROPERTY COMPILE_FLAGS "-std=c99 -Wall ${LIBNM_GLIB_CFLAGS_OTHER}") +set_property(TARGET pam_wlan_helper PROPERTY LINK_FLAGS "${LIBNM_GLIB_LDFLAGS_OTHER}") +target_link_libraries(pam_wlan_helper ${LIBNM_GLIB_LIBRARIES}) + +add_executable(pam_wlan_test pam_wlan.c) +set_property(TARGET pam_wlan_test PROPERTY COMPILE_DEFINITIONS "_DEFAULT_SOURCE;_BSD_SOURCE;TEST") +set_property(TARGET pam_wlan_test PROPERTY COMPILE_FLAGS "-std=c99 -Wall") + +add_library(pam_wlan MODULE pam_wlan.c) +set_property(TARGET pam_wlan PROPERTY COMPILE_DEFINITIONS "_DEFAULT_SOURCE;_BSD_SOURCE") +set_property(TARGET pam_wlan PROPERTY COMPILE_FLAGS "-std=c99 -Wall") + +install(TARGETS pam_wlan pam_wlan_helper + RUNTIME DESTINATION "${PAM_WLAN_HELPER_DIR}" + LIBRARY DESTINATION "${PAM_MODULE_DIR}" +) diff --git a/FindPAM.cmake b/FindPAM.cmake new file mode 100644 index 0000000..bccdf9b --- /dev/null +++ b/FindPAM.cmake @@ -0,0 +1,15 @@ +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 new file mode 100644 index 0000000..3256940 --- /dev/null +++ b/Findlibnm_glib.cmake @@ -0,0 +1,20 @@ +# 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/Makefile b/Makefile deleted file mode 100644 index 0f62ec7..0000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -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 new file mode 100644 index 0000000..e5d6a26 --- /dev/null +++ b/config.h.in @@ -0,0 +1,31 @@ +/* + Copyright (c) 2015, Kristof Stahl <stahl@itsc.uni-luebeck.de> + Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net> + 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_WLAN_HELPER "@PAM_WLAN_HELPER_DIR@/pam_wlan_helper" @@ -26,27 +26,17 @@ /* - Helpful pages: + 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 - - https://developer.gnome.org/libnm-glib/0.9/ - https://developer.gnome.org/libnm-util/0.9/ */ #define PAM_SM_AUTH -#ifdef TEST - #include <stdio.h> - -#endif - -#include <stdlib.h> -#include <string.h> #include <unistd.h> #include <sys/types.h> @@ -54,237 +44,25 @@ #include <security/pam_modules.h> -#include <nm-client.h> -#include <nm-remote-settings.h> -#include <nm-setting-connection.h> -#include <nm-setting-wireless.h> -#include <nm-setting-wireless-security.h> -#include <nm-setting-8021x.h> -#include <nm-setting-ip4-config.h> -#include <nm-setting-ip6-config.h> - - -#define TIMEOUT 10 -#define CONNECTION_ID "UzL-Wlan" -#define CONNECTION_UUID "af7b7f0b-3e09-442e-8841-f7d7482fa7b0" - -#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) { - size_t len = strlen(str); - GByteArray *ba = g_byte_array_sized_new(len); - - g_byte_array_append(ba, (const unsigned char *)str, len); - - return ba; -} - -static int setup_connection(NMConnection *con, const char *user, const char *pass) { - NMSetting *setting; - - /* NMSettingConnection */ - setting = nm_setting_connection_new(); - g_object_set(G_OBJECT(setting), - NM_SETTING_CONNECTION_UUID, CONNECTION_UUID, - NM_SETTING_CONNECTION_ID, CONNECTION_ID, - NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, - NULL); - nm_connection_add_setting(con, setting); - - /* NMSettingWireless */ - setting = nm_setting_wireless_new(); - GByteArray *ssid = string_to_byte_array(CONNECTION_SSID); - g_object_set(G_OBJECT(setting), - NM_SETTING_WIRELESS_SSID, ssid, - NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, - NULL); - g_byte_array_unref(ssid); - nm_connection_add_setting(con, setting); - - /* NMSettingWirelessSecurity */ - setting = nm_setting_wireless_security_new(); - g_object_set(G_OBJECT(setting), - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, CONNECTION_AUTH_ALG, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, CONNECTION_KEY_MGMT, - NULL); - nm_connection_add_setting(con, setting); +#include <config.h> - /* NMSetting8021x */ - setting = nm_setting_802_1x_new(); - /* TODO: Add certificate and subject check */ - nm_setting_802_1x_add_eap_method(NM_SETTING_802_1X(setting), CONNECTION_EAP); - g_object_set(setting, - NM_SETTING_802_1X_IDENTITY, user, - NM_SETTING_802_1X_PASSWORD, pass, - NM_SETTING_802_1X_PHASE2_AUTHEAP, CONNECTION_PHASE2_AUTHEAP, - NULL); - nm_connection_add_setting(con, setting); - /* NMSettingIP4Config */ - setting = nm_setting_ip4_config_new(); - g_object_set(G_OBJECT(setting), - NM_SETTING_IP4_CONFIG_METHOD, "auto", - NULL); - nm_connection_add_setting(con, setting); +#define UNUSED __attribute__((unused)) - /* NMSettingIP6Config */ - setting = nm_setting_ip6_config_new(); - g_object_set(G_OBJECT(setting), - NM_SETTING_IP6_CONFIG_METHOD, "auto", - NULL); - nm_connection_add_setting(con, setting); - - return PAM_SUCCESS; -} - -typedef struct { - int ret; - GMainLoop *loop; - NMClient *client; -} cb_arg; - - -static NMDevice * find_device(NMClient *client) { - size_t i; - const GPtrArray *devices = nm_client_get_devices(client); - - for (i = 0; i < devices->len; i++) { - NMDevice *device = g_ptr_array_index(devices, i); - - if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_WIFI) - return device; - } - - return NULL; -} - -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); - if (!active_connection) - return; - - NMActiveConnectionState state = nm_active_connection_get_state(active_connection); - - if (state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING && state != NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { - if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) - arg->ret = PAM_SUCCESS; - - g_main_loop_quit(arg->loop); - } -} - -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(NMRemoteSettings *settings, NMRemoteConnection *con, GError *error, gpointer user_data) { - cb_arg *arg = user_data; - - if (error) - goto error; - - NMDevice *device = find_device(arg->client); - if (!device) - goto error; - - 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); - return; - - error: - g_main_loop_quit(arg->loop); -} - -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_SYSTEM_ERR; - arg.loop = g_main_loop_new(NULL, FALSE); - - arg.client = nm_client_new(); - if (!arg.client) - goto end; - - dbus = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); - if (!dbus) - goto end; - - settings = nm_remote_settings_new(dbus); - if (!settings) - goto end; - - con = nm_connection_new(); - setup_connection(con, user, pass); - - if (!nm_remote_settings_add_connection_unsaved(settings, con, add_cb, &arg)) - goto end; - - arg.ret = PAM_AUTH_ERR; - - g_main_loop_run(arg.loop); - - end: - 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; -} static int authenticate(const char *user, const char *pass) { - int status; - int fds[2]; - if (pipe(fds)) - return PAM_SYSTEM_ERR; + FILE *stream = popen(PAM_WLAN_HELPER, "we"); - pid_t pid = fork(); - if (pid < 0) - return PAM_SYSTEM_ERR; - - if (pid == 0) { - close(fds[0]); - status = do_authenticate(user, pass); - write(fds[1], &status, sizeof(status)); - close(fds[1]); - _exit(0); - } - - close(fds[1]); + fputs(user, stream); + fputc(0, stream); + fputs(pass, stream); - if (waitpid(pid, NULL, 0) < 0) - goto error; + int status = fclose(stream); - if (read(fds[0], &status, sizeof(status)) != sizeof(status)) - goto error; - - close(fds[0]); - return status; - - error: - close(fds[0]); - return PAM_SYSTEM_ERR; + if (WIFEXITED(status)) + return WEXITSTATUS(status); + else + return PAM_SYSTEM_ERR; } #ifdef TEST @@ -304,7 +82,7 @@ int main(int argc, char *argv[]) { #else -PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, __attribute__((unused)) int flags, __attribute__((unused)) int argc, __attribute__((unused)) const char **argv) { +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; @@ -319,4 +97,5 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, __attribute__((unused)) i return authenticate(user, pass); } + #endif diff --git a/pam_wlan_helper.c b/pam_wlan_helper.c new file mode 100644 index 0000000..76db00a --- /dev/null +++ b/pam_wlan_helper.c @@ -0,0 +1,261 @@ +/* + Copyright (c) 2015, Kristof Stahl <stahl@itsc.uni-luebeck.de> + Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net> + 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: + + https://developer.gnome.org/libnm-glib/0.9/ + https://developer.gnome.org/libnm-util/0.9/ +*/ + +#include <stdio.h> +#include <string.h> + +#include <security/pam_modules.h> + +#include <nm-client.h> +#include <nm-remote-settings.h> +#include <nm-setting-connection.h> +#include <nm-setting-wireless.h> +#include <nm-setting-wireless-security.h> +#include <nm-setting-8021x.h> +#include <nm-setting-ip4-config.h> +#include <nm-setting-ip6-config.h> + + +#define TIMEOUT 10 +#define CONNECTION_ID "UzL-Wlan" +#define CONNECTION_UUID "af7b7f0b-3e09-442e-8841-f7d7482fa7b0" + +#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" + + +#define UNUSED __attribute__((unused)) + + +static GByteArray * string_to_byte_array(const char *str) { + size_t len = strlen(str); + GByteArray *ba = g_byte_array_sized_new(len); + + g_byte_array_append(ba, (const unsigned char *)str, len); + + return ba; +} + +static int setup_connection(NMConnection *con, const char *user, const char *pass) { + NMSetting *setting; + + /* NMSettingConnection */ + setting = nm_setting_connection_new(); + g_object_set(G_OBJECT(setting), + NM_SETTING_CONNECTION_UUID, CONNECTION_UUID, + NM_SETTING_CONNECTION_ID, CONNECTION_ID, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + nm_connection_add_setting(con, setting); + + /* NMSettingWireless */ + setting = nm_setting_wireless_new(); + GByteArray *ssid = string_to_byte_array(CONNECTION_SSID); + g_object_set(G_OBJECT(setting), + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, + NULL); + g_byte_array_unref(ssid); + nm_connection_add_setting(con, setting); + + /* NMSettingWirelessSecurity */ + setting = nm_setting_wireless_security_new(); + g_object_set(G_OBJECT(setting), + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, CONNECTION_AUTH_ALG, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, CONNECTION_KEY_MGMT, + NULL); + nm_connection_add_setting(con, setting); + + /* NMSetting8021x */ + setting = nm_setting_802_1x_new(); + /* TODO: Add certificate and subject check */ + nm_setting_802_1x_add_eap_method(NM_SETTING_802_1X(setting), CONNECTION_EAP); + g_object_set(setting, + NM_SETTING_802_1X_IDENTITY, user, + NM_SETTING_802_1X_PASSWORD, pass, + NM_SETTING_802_1X_PHASE2_AUTHEAP, CONNECTION_PHASE2_AUTHEAP, + NULL); + nm_connection_add_setting(con, setting); + + /* NMSettingIP4Config */ + setting = nm_setting_ip4_config_new(); + g_object_set(G_OBJECT(setting), + NM_SETTING_IP4_CONFIG_METHOD, "auto", + NULL); + nm_connection_add_setting(con, setting); + + /* NMSettingIP6Config */ + setting = nm_setting_ip6_config_new(); + g_object_set(G_OBJECT(setting), + NM_SETTING_IP6_CONFIG_METHOD, "auto", + NULL); + nm_connection_add_setting(con, setting); + + return PAM_SUCCESS; +} + +typedef struct { + int ret; + GMainLoop *loop; + NMClient *client; +} cb_arg; + + +static NMDevice * find_device(NMClient *client) { + size_t i; + const GPtrArray *devices = nm_client_get_devices(client); + + for (i = 0; i < devices->len; i++) { + NMDevice *device = g_ptr_array_index(devices, i); + + if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_WIFI) + return device; + } + + return NULL; +} + +static void state_cb(NMDevice *device, UNUSED GParamSpec *pspec, gpointer user_data) { + cb_arg *arg = user_data; + + NMActiveConnection *active_connection = nm_device_get_active_connection(device); + if (!active_connection) + return; + + NMActiveConnectionState state = nm_active_connection_get_state(active_connection); + + if (state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING && state != NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { + if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) + arg->ret = PAM_SUCCESS; + + g_main_loop_quit(arg->loop); + } +} + +static void activate_cb(UNUSED NMClient *client, UNUSED 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) { + cb_arg *arg = user_data; + + if (error) + goto error; + + NMDevice *device = find_device(arg->client); + if (!device) + goto error; + + 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); + return; + + error: + g_main_loop_quit(arg->loop); +} + +static int 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.loop = g_main_loop_new(NULL, FALSE); + + arg.client = nm_client_new(); + if (!arg.client) + goto end; + + dbus = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL); + if (!dbus) + goto end; + + settings = nm_remote_settings_new(dbus); + if (!settings) + goto end; + + con = nm_connection_new(); + setup_connection(con, user, pass); + + if (!nm_remote_settings_add_connection_unsaved(settings, con, add_cb, &arg)) + goto end; + + arg.ret = PAM_AUTH_ERR; + + g_main_loop_run(arg.loop); + + end: + 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; + + while (len < sizeof(buf)-1) { + size_t r = fread(buf+len, 1, sizeof(buf)-len-1, stdin); + if (!r) + break; + + len += r; + } + + buf[len] = 0; + + const char *user = buf; + const char *pass = user + strlen(user) + 1; + if (pass > buf+len) + return PAM_SYSTEM_ERR; + + return authenticate(user, pass); +} |