252 lines
6.7 KiB
C
252 lines
6.7 KiB
C
/*
|
|
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>
|
|
|
|
#include <config.h>
|
|
|
|
|
|
#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);
|
|
}
|