summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt34
-rw-r--r--FindPAM.cmake15
-rw-r--r--Findlibnm_glib.cmake20
-rw-r--r--Makefile7
-rw-r--r--config.h.in31
-rw-r--r--pam_wlan.c249
-rw-r--r--pam_wlan_helper.c261
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"
diff --git a/pam_wlan.c b/pam_wlan.c
index 181bb6a..81abe8a 100644
--- a/pam_wlan.c
+++ b/pam_wlan.c
@@ -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);
+}