Blame pam/pam_fprintd.c

Packit f7449a
/*
Packit f7449a
 * pam_fprint: PAM module for fingerprint authentication through fprintd
Packit f7449a
 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
Packit f7449a
 * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
Packit f7449a
 *
Packit f7449a
 * This program is free software; you can redistribute it and/or modify
Packit f7449a
 * it under the terms of the GNU General Public License as published by
Packit f7449a
 * the Free Software Foundation; either version 2 of the License, or
Packit f7449a
 * (at your option) any later version.
Packit f7449a
 *
Packit f7449a
 * This program is distributed in the hope that it will be useful,
Packit f7449a
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit f7449a
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit f7449a
 * GNU General Public License for more details.
Packit f7449a
 *
Packit f7449a
 * You should have received a copy of the GNU General Public License along
Packit f7449a
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit f7449a
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit f7449a
 */
Packit f7449a
Packit f7449a
#include <config.h>
Packit f7449a
Packit f7449a
#include <stdio.h>
Packit f7449a
#include <stdlib.h>
Packit f7449a
#include <unistd.h>
Packit f7449a
#include <sys/types.h>
Packit f7449a
#include <string.h>
Packit f7449a
#include <syslog.h>
Packit f7449a
Packit f7449a
#include <glib/gi18n-lib.h>
Packit f7449a
#include <dbus/dbus-glib-bindings.h>
Packit f7449a
#include <dbus/dbus-glib-lowlevel.h>
Packit f7449a
Packit f7449a
#define PAM_SM_AUTH
Packit f7449a
#include <security/pam_modules.h>
Packit f7449a
Packit f7449a
#include "marshal.h"
Packit f7449a
Packit f7449a
#define TR(s) dgettext(GETTEXT_PACKAGE, s)
Packit f7449a
Packit f7449a
#include "fingerprint-strings.h"
Packit f7449a
Packit f7449a
#define DEFAULT_MAX_TRIES 3
Packit f7449a
#define DEFAULT_TIMEOUT 30
Packit f7449a
Packit f7449a
#define MAX_TRIES_MATCH "max-tries="
Packit f7449a
#define TIMEOUT_MATCH "timeout="
Packit f7449a
Packit f7449a
#define D(pamh, ...) {					\
Packit f7449a
	if (debug) {					\
Packit f7449a
		char *s;				\
Packit f7449a
		s = g_strdup_printf (__VA_ARGS__);	\
Packit f7449a
		send_debug_msg (pamh, s);		\
Packit f7449a
		g_free (s);				\
Packit f7449a
	}						\
Packit f7449a
}
Packit f7449a
Packit f7449a
Packit f7449a
static gboolean debug = FALSE;
Packit f7449a
static guint max_tries = DEFAULT_MAX_TRIES;
Packit f7449a
static guint timeout = DEFAULT_TIMEOUT;
Packit f7449a
Packit f7449a
static gboolean send_info_msg(pam_handle_t *pamh, const char *msg)
Packit f7449a
{
Packit f7449a
	const struct pam_message mymsg = {
Packit f7449a
		.msg_style = PAM_TEXT_INFO,
Packit f7449a
		.msg = msg,
Packit f7449a
	};
Packit f7449a
	const struct pam_message *msgp = &mymsg;
Packit f7449a
	const struct pam_conv *pc;
Packit f7449a
	struct pam_response *resp;
Packit f7449a
	int r;
Packit f7449a
Packit f7449a
	r = pam_get_item(pamh, PAM_CONV, (const void **) &pc);
Packit f7449a
	if (r != PAM_SUCCESS)
Packit f7449a
		return FALSE;
Packit f7449a
Packit f7449a
	if (!pc || !pc->conv)
Packit f7449a
		return FALSE;
Packit f7449a
Packit f7449a
	return (pc->conv(1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS);
Packit f7449a
}
Packit f7449a
Packit f7449a
static gboolean send_err_msg(pam_handle_t *pamh, const char *msg)
Packit f7449a
{
Packit f7449a
	const struct pam_message mymsg = {
Packit f7449a
		.msg_style = PAM_ERROR_MSG,
Packit f7449a
		.msg = msg,
Packit f7449a
	};
Packit f7449a
	const struct pam_message *msgp = &mymsg;
Packit f7449a
	const struct pam_conv *pc;
Packit f7449a
	struct pam_response *resp;
Packit f7449a
	int r;
Packit f7449a
Packit f7449a
	r = pam_get_item(pamh, PAM_CONV, (const void **) &pc);
Packit f7449a
	if (r != PAM_SUCCESS)
Packit f7449a
		return FALSE;
Packit f7449a
Packit f7449a
	if (!pc || !pc->conv)
Packit f7449a
		return FALSE;
Packit f7449a
Packit f7449a
	return (pc->conv(1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS);
Packit f7449a
}
Packit f7449a
Packit f7449a
static void send_debug_msg(pam_handle_t *pamh, const char *msg)
Packit f7449a
{
Packit f7449a
	gconstpointer item;
Packit f7449a
	const char *service;
Packit f7449a
Packit f7449a
	if (pam_get_item(pamh, PAM_SERVICE, &item) != PAM_SUCCESS || !item)
Packit f7449a
		service = "<unknown>";
Packit f7449a
	else
Packit f7449a
		service = item;
Packit f7449a
Packit f7449a
	openlog (service, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
Packit f7449a
Packit f7449a
	syslog (LOG_AUTHPRIV|LOG_WARNING, "%s(%s): %s", "pam_fprintd", service, msg);
Packit f7449a
Packit f7449a
	closelog ();
Packit f7449a
Packit f7449a
}
Packit f7449a
Packit f7449a
static DBusGProxy *create_manager (pam_handle_t *pamh, DBusGConnection **ret_conn, GMainLoop **ret_loop)
Packit f7449a
{
Packit f7449a
	DBusGConnection *connection;
Packit f7449a
	DBusConnection *conn;
Packit f7449a
	DBusGProxy *manager;
Packit f7449a
	DBusError error;
Packit f7449a
	GMainLoop *loop;
Packit f7449a
	GMainContext *ctx;
Packit f7449a
Packit f7449a
	/* Otherwise dbus-glib doesn't setup it value types */
Packit f7449a
	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
Packit f7449a
Packit f7449a
	if (connection != NULL)
Packit f7449a
		dbus_g_connection_unref (connection);
Packit f7449a
Packit f7449a
	/* And set us up a private D-Bus connection */
Packit f7449a
	dbus_error_init (&error);
Packit f7449a
	conn = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error);
Packit f7449a
	if (conn == NULL) {
Packit f7449a
		D(pamh, "Error with getting the bus: %s", error.message);
Packit f7449a
		dbus_error_free (&error);
Packit f7449a
		return NULL;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	/* Set up our own main loop context */
Packit f7449a
	ctx = g_main_context_new ();
Packit f7449a
	loop = g_main_loop_new (ctx, FALSE);
Packit f7449a
	dbus_connection_setup_with_g_main (conn, ctx);
Packit f7449a
Packit f7449a
	connection = dbus_connection_get_g_connection (conn);
Packit f7449a
Packit f7449a
	manager = dbus_g_proxy_new_for_name(connection,
Packit f7449a
					    "net.reactivated.Fprint",
Packit f7449a
					    "/net/reactivated/Fprint/Manager",
Packit f7449a
					    "net.reactivated.Fprint.Manager");
Packit f7449a
	*ret_conn = connection;
Packit f7449a
	*ret_loop = loop;
Packit f7449a
Packit f7449a
	return manager;
Packit f7449a
}
Packit f7449a
Packit f7449a
static void close_and_unref (DBusGConnection *connection)
Packit f7449a
{
Packit f7449a
	DBusConnection *conn;
Packit f7449a
Packit f7449a
	conn = dbus_g_connection_get_connection (connection);
Packit f7449a
	dbus_connection_close (conn);
Packit f7449a
	dbus_g_connection_unref (connection);
Packit f7449a
}
Packit f7449a
Packit f7449a
static void unref_loop (GMainLoop *loop)
Packit f7449a
{
Packit f7449a
	GMainContext *ctx;
Packit f7449a
Packit f7449a
	/* The main context was created separately, so
Packit f7449a
	 * we'll need to unref it ourselves */
Packit f7449a
	ctx = g_main_loop_get_context (loop);
Packit f7449a
	g_main_loop_unref (loop);
Packit f7449a
	g_main_context_unref (ctx);
Packit f7449a
}
Packit f7449a
Packit f7449a
#define DBUS_TYPE_G_OBJECT_PATH_ARRAY (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH))
Packit f7449a
Packit f7449a
static DBusGProxy *open_device(pam_handle_t *pamh, DBusGConnection *connection, DBusGProxy *manager, gboolean *has_multiple_devices)
Packit f7449a
{
Packit f7449a
	GError *error = NULL;
Packit f7449a
	const char *path;
Packit f7449a
	DBusGProxy *dev;
Packit f7449a
	GPtrArray *paths_array;
Packit f7449a
	const char **paths;
Packit f7449a
Packit f7449a
	if (!dbus_g_proxy_call (manager, "GetDevices", &error,
Packit f7449a
				G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH_ARRAY,
Packit f7449a
				&paths_array, G_TYPE_INVALID)) {
Packit f7449a
		D(pamh, "get_devices failed: %s", error->message);
Packit f7449a
		g_error_free (error);
Packit f7449a
		return NULL;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	if (paths_array == NULL || paths_array->len == 0) {
Packit f7449a
		if (paths_array != NULL)
Packit f7449a
			g_ptr_array_free (paths_array, TRUE);
Packit f7449a
		D(pamh, "No devices found\n");
Packit f7449a
		return NULL;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	*has_multiple_devices = (paths_array->len > 1);
Packit f7449a
	paths = (const char **)paths_array->pdata;
Packit f7449a
	path = paths[0];
Packit f7449a
Packit f7449a
	D(pamh, "Using device %s\n", path);
Packit f7449a
Packit f7449a
	dev = dbus_g_proxy_new_for_name(connection,
Packit f7449a
					"net.reactivated.Fprint",
Packit f7449a
					path,
Packit f7449a
					"net.reactivated.Fprint.Device");
Packit f7449a
Packit f7449a
	g_ptr_array_free (paths_array, TRUE);
Packit f7449a
Packit f7449a
	return dev;
Packit f7449a
}
Packit f7449a
Packit f7449a
typedef struct {
Packit f7449a
	guint max_tries;
Packit f7449a
	char *result;
Packit f7449a
	gboolean timed_out;
Packit f7449a
	gboolean is_swipe;
Packit f7449a
	pam_handle_t *pamh;
Packit f7449a
	GMainLoop *loop;
Packit f7449a
Packit f7449a
	char *driver;
Packit f7449a
} verify_data;
Packit f7449a
Packit f7449a
static void verify_result(GObject *object, const char *result, gboolean done, gpointer user_data)
Packit f7449a
{
Packit f7449a
	verify_data *data = user_data;
Packit f7449a
	const char *msg;
Packit f7449a
Packit f7449a
	D(data->pamh, "Verify result: %s\n", result);
Packit f7449a
	if (done != FALSE) {
Packit f7449a
		data->result = g_strdup (result);
Packit f7449a
		g_main_loop_quit (data->loop);
Packit f7449a
		return;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	msg = TR(verify_result_str_to_msg (result, data->is_swipe));
Packit f7449a
	send_err_msg (data->pamh, msg);
Packit f7449a
}
Packit f7449a
Packit f7449a
static void verify_finger_selected(GObject *object, const char *finger_name, gpointer user_data)
Packit f7449a
{
Packit f7449a
	verify_data *data = user_data;
Packit f7449a
	char *msg;
Packit f7449a
Packit f7449a
	msg = finger_str_to_msg(finger_name, data->driver, data->is_swipe);
Packit f7449a
Packit f7449a
	D(data->pamh, "verify_finger_selected %s", msg);
Packit f7449a
	send_info_msg (data->pamh, msg);
Packit f7449a
	g_free (msg);
Packit f7449a
}
Packit f7449a
Packit f7449a
static gboolean verify_timeout_cb (gpointer user_data)
Packit f7449a
{
Packit f7449a
	verify_data *data = user_data;
Packit f7449a
Packit f7449a
	data->timed_out = TRUE;
Packit f7449a
	send_info_msg (data->pamh, "Verification timed out");
Packit f7449a
	g_main_loop_quit (data->loop);
Packit f7449a
Packit f7449a
	return FALSE;
Packit f7449a
}
Packit f7449a
Packit f7449a
static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev, gboolean has_multiple_devices)
Packit f7449a
{
Packit f7449a
	GError *error = NULL;
Packit f7449a
	GHashTable *props;
Packit f7449a
	DBusGProxy *p;
Packit f7449a
	verify_data *data;
Packit f7449a
	int ret;
Packit f7449a
Packit f7449a
	data = g_new0 (verify_data, 1);
Packit f7449a
	data->max_tries = max_tries;
Packit f7449a
	data->pamh = pamh;
Packit f7449a
	data->loop = loop;
Packit f7449a
Packit f7449a
	/* Get some properties for the device */
Packit f7449a
	p = dbus_g_proxy_new_from_proxy (dev, "org.freedesktop.DBus.Properties", NULL);
Packit f7449a
Packit f7449a
	if (dbus_g_proxy_call (p, "GetAll", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID,
Packit f7449a
			       dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) {
Packit f7449a
		const char *scan_type;
Packit f7449a
		if (has_multiple_devices)
Packit f7449a
			data->driver = g_value_dup_string (g_hash_table_lookup (props, "name"));
Packit f7449a
		scan_type = g_value_dup_string (g_hash_table_lookup (props, "scan-type"));
Packit f7449a
		if (g_str_equal (scan_type, "swipe"))
Packit f7449a
			data->is_swipe = TRUE;
Packit f7449a
		g_hash_table_destroy (props);
Packit f7449a
	}
Packit f7449a
Packit f7449a
	g_object_unref (p);
Packit f7449a
Packit f7449a
	dbus_g_proxy_add_signal(dev, "VerifyStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL);
Packit f7449a
	dbus_g_proxy_add_signal(dev, "VerifyFingerSelected", G_TYPE_STRING, NULL);
Packit f7449a
	dbus_g_proxy_connect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result),
Packit f7449a
				    data, NULL);
Packit f7449a
	dbus_g_proxy_connect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected),
Packit f7449a
				    data, NULL);
Packit f7449a
Packit f7449a
	ret = PAM_AUTH_ERR;
Packit f7449a
Packit f7449a
	while (ret == PAM_AUTH_ERR && data->max_tries > 0) {
Packit f7449a
		GSource *source;
Packit f7449a
Packit f7449a
		/* Set up the timeout on our non-default context */
Packit f7449a
		source = g_timeout_source_new_seconds (timeout);
Packit f7449a
		g_source_attach (source, g_main_loop_get_context (loop));
Packit f7449a
		g_source_set_callback (source, verify_timeout_cb, data, NULL);
Packit f7449a
Packit f7449a
		data->timed_out = FALSE;
Packit f7449a
Packit f7449a
		if (!dbus_g_proxy_call (dev, "VerifyStart", &error, G_TYPE_STRING, "any", G_TYPE_INVALID, G_TYPE_INVALID)) {
Packit f7449a
			if (dbus_g_error_has_name(error, "net.reactivated.Fprint.Error.NoEnrolledPrints"))
Packit f7449a
				ret = PAM_USER_UNKNOWN;
Packit f7449a
Packit f7449a
			D(pamh, "VerifyStart failed: %s", error->message);
Packit f7449a
			g_error_free (error);
Packit f7449a
Packit f7449a
			g_source_destroy (source);
Packit f7449a
			g_source_unref (source);
Packit f7449a
			break;
Packit f7449a
		}
Packit f7449a
Packit f7449a
		g_main_loop_run (loop);
Packit f7449a
Packit f7449a
		g_source_destroy (source);
Packit f7449a
		g_source_unref (source);
Packit f7449a
Packit f7449a
		/* Ignore errors from VerifyStop */
Packit f7449a
		dbus_g_proxy_call (dev, "VerifyStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
Packit f7449a
Packit f7449a
		if (data->timed_out) {
Packit f7449a
			ret = PAM_AUTHINFO_UNAVAIL;
Packit f7449a
			break;
Packit f7449a
		} else {
Packit f7449a
			if (g_str_equal (data->result, "verify-no-match")) {
Packit f7449a
				send_err_msg (data->pamh, "Failed to match fingerprint");
Packit f7449a
				ret = PAM_AUTH_ERR;
Packit f7449a
			} else if (g_str_equal (data->result, "verify-match"))
Packit f7449a
				ret = PAM_SUCCESS;
Packit f7449a
			else if (g_str_equal (data->result, "verify-unknown-error"))
Packit f7449a
				ret = PAM_AUTHINFO_UNAVAIL;
Packit f7449a
			else if (g_str_equal (data->result, "verify-disconnected")) {
Packit f7449a
				ret = PAM_AUTHINFO_UNAVAIL;
Packit f7449a
				g_free (data->result);
Packit f7449a
				break;
Packit f7449a
			} else {
Packit f7449a
				send_info_msg (data->pamh, "An unknown error occurred");
Packit f7449a
				ret = PAM_AUTH_ERR;
Packit f7449a
				g_free (data->result);
Packit f7449a
				break;
Packit f7449a
			}
Packit f7449a
			g_free (data->result);
Packit f7449a
			data->result = NULL;
Packit f7449a
		}
Packit f7449a
		data->max_tries--;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	dbus_g_proxy_disconnect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result), data);
Packit f7449a
	dbus_g_proxy_disconnect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected), data);
Packit f7449a
Packit f7449a
	g_free (data->driver);
Packit f7449a
	g_free (data);
Packit f7449a
Packit f7449a
	return ret;
Packit f7449a
}
Packit f7449a
Packit f7449a
static gboolean user_has_prints(DBusGProxy *dev, const char *username)
Packit f7449a
{
Packit f7449a
	char **fingers;
Packit f7449a
	gboolean have_prints;
Packit f7449a
Packit f7449a
	if (!dbus_g_proxy_call (dev, "ListEnrolledFingers", NULL,
Packit f7449a
				G_TYPE_STRING, username, G_TYPE_INVALID,
Packit f7449a
				G_TYPE_STRV, &fingers, G_TYPE_INVALID)) {
Packit f7449a
		/* If ListEnrolledFingers fails then verification should
Packit f7449a
		 * also fail (both use the same underlying call), so we
Packit f7449a
		 * report FALSE here and bail out early.  */
Packit f7449a
		return FALSE;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	have_prints = fingers != NULL && g_strv_length (fingers) > 0;
Packit f7449a
	g_strfreev (fingers);
Packit f7449a
Packit f7449a
	return have_prints;
Packit f7449a
}
Packit f7449a
Packit f7449a
static void release_device(pam_handle_t *pamh, DBusGProxy *dev)
Packit f7449a
{
Packit f7449a
	GError *error = NULL;
Packit f7449a
	if (!dbus_g_proxy_call (dev, "Release", &error, G_TYPE_INVALID, G_TYPE_INVALID)) {
Packit f7449a
		D(pamh, "ReleaseDevice failed: %s\n", error->message);
Packit f7449a
		g_error_free (error);
Packit f7449a
	}
Packit f7449a
}
Packit f7449a
Packit f7449a
static gboolean claim_device(pam_handle_t *pamh, DBusGProxy *dev, const char *username)
Packit f7449a
{
Packit f7449a
	GError *error = NULL;
Packit f7449a
Packit f7449a
	if (!dbus_g_proxy_call (dev, "Claim", &error, G_TYPE_STRING, username, G_TYPE_INVALID, G_TYPE_INVALID)) {
Packit f7449a
		D(pamh, "failed to claim device %s\n", error->message);
Packit f7449a
		g_error_free (error);
Packit f7449a
		return FALSE;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	return TRUE;
Packit f7449a
}
Packit f7449a
Packit f7449a
static int do_auth(pam_handle_t *pamh, const char *username)
Packit f7449a
{
Packit f7449a
	DBusGProxy *manager;
Packit f7449a
	DBusGConnection *connection;
Packit f7449a
	DBusGProxy *dev;
Packit f7449a
	GMainLoop *loop;
Packit f7449a
	gboolean have_prints;
Packit f7449a
	gboolean has_multiple_devices;
Packit f7449a
	int ret = PAM_AUTHINFO_UNAVAIL;
Packit f7449a
Packit f7449a
	manager = create_manager (pamh, &connection, &loop);
Packit f7449a
	if (manager == NULL)
Packit f7449a
		return PAM_AUTHINFO_UNAVAIL;
Packit f7449a
Packit f7449a
	dev = open_device(pamh, connection, manager, &has_multiple_devices);
Packit f7449a
	g_object_unref (manager);
Packit f7449a
	if (!dev) {
Packit f7449a
		unref_loop (loop);
Packit f7449a
		close_and_unref (connection);
Packit f7449a
		return PAM_AUTHINFO_UNAVAIL;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	have_prints = user_has_prints(dev, username);
Packit f7449a
	D(pamh, "prints registered: %s\n", have_prints ? "yes" : "no");
Packit f7449a
Packit f7449a
	if (have_prints) {
Packit f7449a
		if (claim_device (pamh, dev, username)) {
Packit f7449a
			ret = do_verify (loop, pamh, dev, has_multiple_devices);
Packit f7449a
			release_device (pamh, dev);
Packit f7449a
		}
Packit f7449a
	}
Packit f7449a
Packit f7449a
	unref_loop (loop);
Packit f7449a
	g_object_unref (dev);
Packit f7449a
	close_and_unref (connection);
Packit f7449a
Packit f7449a
	return ret;
Packit f7449a
}
Packit f7449a
Packit f7449a
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
Packit f7449a
				   const char **argv)
Packit f7449a
{
Packit f7449a
	const char *rhost = NULL;
Packit f7449a
	const char *username;
Packit f7449a
	guint i;
Packit f7449a
	int r;
Packit f7449a
Packit f7449a
	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
Packit f7449a
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Packit f7449a
Packit f7449a
#if !GLIB_CHECK_VERSION (2, 36, 0)
Packit f7449a
	g_type_init();
Packit f7449a
#endif
Packit f7449a
Packit f7449a
	dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN,
Packit f7449a
					   G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID);
Packit f7449a
Packit f7449a
	pam_get_item(pamh, PAM_RHOST, (const void **)(const void*) &rhost);
Packit f7449a
Packit f7449a
	/* NULL or empty rhost if the host information is not available or set.
Packit f7449a
	 * "localhost" if the host is local.
Packit f7449a
	 * We want to not run for known remote hosts */
Packit f7449a
	if (rhost != NULL &&
Packit f7449a
	    *rhost != '\0' &&
Packit f7449a
	    strcmp (rhost, "localhost") != 0) {
Packit f7449a
		return PAM_AUTHINFO_UNAVAIL;
Packit f7449a
	}
Packit f7449a
Packit f7449a
	r = pam_get_user(pamh, &username, NULL);
Packit f7449a
	if (r != PAM_SUCCESS)
Packit f7449a
		return PAM_AUTHINFO_UNAVAIL;
Packit f7449a
Packit f7449a
	for (i = 0; i < argc; i++) {
Packit f7449a
		if (argv[i] != NULL) {
Packit f7449a
			if(g_str_equal (argv[i], "debug")) {
Packit f7449a
				g_message ("debug on");
Packit f7449a
				debug = TRUE;
Packit f7449a
			}
Packit f7449a
			else if (strncmp(argv[i], MAX_TRIES_MATCH, strlen (MAX_TRIES_MATCH)) == 0 && strlen(argv[i]) == strlen (MAX_TRIES_MATCH) + 1) {
Packit f7449a
				max_tries = atoi (argv[i] + strlen (MAX_TRIES_MATCH));
Packit f7449a
				if (max_tries < 1)
Packit f7449a
					max_tries = DEFAULT_MAX_TRIES;
Packit f7449a
				D(pamh, "max_tries specified as: %d", max_tries);
Packit f7449a
			}
Packit f7449a
			else if (strncmp(argv[i], TIMEOUT_MATCH, strlen (TIMEOUT_MATCH)) == 0 && strlen(argv[i]) <= strlen (TIMEOUT_MATCH) + 2) {
Packit f7449a
				timeout = atoi (argv[i] + strlen (TIMEOUT_MATCH));
Packit f7449a
				if (timeout < 10)
Packit f7449a
					timeout = DEFAULT_TIMEOUT;
Packit f7449a
				D(pamh, "timeout specified as: %d", timeout);
Packit f7449a
			}
Packit f7449a
		}
Packit f7449a
	}
Packit f7449a
Packit f7449a
	r = do_auth(pamh, username);
Packit f7449a
Packit f7449a
	return r;
Packit f7449a
}
Packit f7449a
Packit f7449a
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
Packit f7449a
			      const char **argv)
Packit f7449a
{
Packit f7449a
	return PAM_SUCCESS;
Packit f7449a
}
Packit f7449a
Packit f7449a
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
Packit f7449a
				const char **argv)
Packit f7449a
{
Packit f7449a
	return PAM_SUCCESS;
Packit f7449a
}
Packit f7449a