From 7f6f56a7d5b406bd86ea3ca36fcb6ec8e4b915db Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 2 Jun 2015 14:57:13 +0200 Subject: Rename to pam_network_manager --- pam_network_manager_helper.c | 252 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 pam_network_manager_helper.c (limited to 'pam_network_manager_helper.c') diff --git a/pam_network_manager_helper.c b/pam_network_manager_helper.c new file mode 100644 index 0000000..7043ade --- /dev/null +++ b/pam_network_manager_helper.c @@ -0,0 +1,252 @@ +/* + 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: + + https://developer.gnome.org/libnm-glib/0.9/ + https://developer.gnome.org/libnm-util/0.9/ +*/ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#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); +} -- cgit v1.2.3