[fprint] [fprintd][PATCH] Support for password prompt while finger scanning

Jaroslav Barton djaara at djaara.net
Mon Mar 9 13:00:59 GMT 2009


Next try:

Multiple pam stackes will be better, but for some applications
  it is unusable or like sci-fi at this moment (some console
  applications like su, sudo, etc.). Password prompt should be
  enabled by "askpass" pam module parameter in service configuration
  file. Password is stored in PAM_AUTHTOK for next pam module.
  Multiple pam stack aware should use service configuration file
  without askpass option.
---
 pam/Makefile.am           |    5 +-
 pam/README                |    4 +
 pam/fingerprint-strings.h |   21 ++--
 pam/pam_fprintd-uinput.c  |  117 ++++++++++++++++++
 pam/pam_fprintd-uinput.h  |   38 ++++++
 pam/pam_fprintd.c         |  299 ++++++++++++++++++++++++++++++++++++---------
 6 files changed, 413 insertions(+), 71 deletions(-)
 create mode 100644 pam/pam_fprintd-uinput.c
 create mode 100644 pam/pam_fprintd-uinput.h

diff --git a/pam/Makefile.am b/pam/Makefile.am
index 59927d9..7dab1b0 100644
--- a/pam/Makefile.am
+++ b/pam/Makefile.am
@@ -3,12 +3,13 @@ if HAVE_PAM
 pammod_PROGRAMS = pam_fprintd.so
 pammoddir=$(libdir)/security
 
-pam_fprintd_so_SOURCES = pam_fprintd.c $(MARSHALFILES)
+pam_fprintd_so_SOURCES = pam_fprintd.c $(MARSHALFILES) $(UINPUTFILES)
 pam_fprintd_so_CFLAGS = -fPIC $(WARN_CFLAGS) $(GLIB_CFLAGS)
-pam_fprintd_so_LDFLAGS = -shared
+pam_fprintd_so_LDFLAGS = -shared -lpthread
 pam_fprintd_so_LDADD = $(PAM_LIBS) $(GLIB_LIBS)
 
 MARSHALFILES = marshal.c marshal.h
+UINPUTFILES = pam_fprintd-uinput.c pam_fprintd-uinput.h
 GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
 BUILT_SOURCES = $(MARSHALFILES)
 
diff --git a/pam/README b/pam/README
index 9174deb..cf0157b 100644
--- a/pam/README
+++ b/pam/README
@@ -14,6 +14,10 @@ Options:
 * You can add the "debug" option on the pam configuration file line above,
   this will log more information from PAM to the file specified in your
   syslog configuration (/var/log/secure by default on Fedora)
+* You also can add "askpass" option on the pam configuration file line above,
+  this will allow use "try_first_pas" option of pam_unix module. This option
+  allow entering either the password or a fingerprint (but please see Known
+  issues).
 
 Known issues:
 * pam_fprintd does not support identifying the user itself as
diff --git a/pam/fingerprint-strings.h b/pam/fingerprint-strings.h
index d1b919e..5499538 100644
--- a/pam/fingerprint-strings.h
+++ b/pam/fingerprint-strings.h
@@ -1,6 +1,7 @@
 /*
  * Helper functions to translate statuses and actions to strings
  * Copyright (C) 2008 Bastien Nocera <hadess at hadess.net>
+ * Copyright (C) 2009 Jaroslav Barton <djaara at djaara.net>
  * 
  * Experimental code. This will be moved out of fprintd into it's own
  * package once the system has matured.
@@ -25,16 +26,16 @@ struct {
 	const char *place_str;
 	const char *swipe_str;
 } fingers[11] = {
-	{ "left-thumb", N_("Place your left thumb on %s"), N_("Swipe your left thumb on %s") },
-	{ "left-index-finger", N_("Place your left index finger on %s"), N_("Swipe your left index finger on %s") },
-	{ "left-middle-finger", N_("Place your left middle finger on %s"), N_("Swipe your left middle finger on %s") },
-	{ "left-ring-finger", N_("Place your left ring finger on %s"), N_("Swipe your left ring finger on %s") },
-	{ "left-little-finger", N_("Place your left little finger on %s"), N_("Swipe your left little finger on %s") },
-	{ "right-thumb", N_("Place your right thumb on %s"), N_("Swipe your right thumb on %s") },
-	{ "right-index-finger", N_("Place your right index finger on %s"), N_("Swipe your right index finger on %s") },
-	{ "right-middle-finger", N_("Place your right middle finger on %s"), N_("Swipe your right middle finger on %s") },
-	{ "right-ring-finger", N_("Place your right ring finger on %s"), N_("Swipe your right ring finger on %s") },
-	{ "right-little-finger", N_("Place your right little finger on %s"), N_("Swipe your right little finger on %s") },
+	{ "left-thumb", N_("Place your left thumb on %s: "), N_("Swipe your left thumb on %s: ") },
+	{ "left-index-finger", N_("Place your left index finger on %s: "), N_("Swipe your left index finger on %s: ") },
+	{ "left-middle-finger", N_("Place your left middle finger on %s: "), N_("Swipe your left middle finger on %s: ") },
+	{ "left-ring-finger", N_("Place your left ring finger on %s: "), N_("Swipe your left ring finger on %s: ") },
+	{ "left-little-finger", N_("Place your left little finger on %s: "), N_("Swipe your left little finger on %s: ") },
+	{ "right-thumb", N_("Place your right thumb on %s: "), N_("Swipe your right thumb on %s: ") },
+	{ "right-index-finger", N_("Place your right index finger on %s: "), N_("Swipe your right index finger on %s: ") },
+	{ "right-middle-finger", N_("Place your right middle finger on %s: "), N_("Swipe your right middle finger on %s: ") },
+	{ "right-ring-finger", N_("Place your right ring finger on %s: "), N_("Swipe your right ring finger on %s: ") },
+	{ "right-little-finger", N_("Place your right little finger on %s: "), N_("Swipe your right little finger on %s: ") },
 	{ NULL, NULL, NULL }
 };
 
diff --git a/pam/pam_fprintd-uinput.c b/pam/pam_fprintd-uinput.c
new file mode 100644
index 0000000..05b2e47
--- /dev/null
+++ b/pam/pam_fprintd-uinput.c
@@ -0,0 +1,117 @@
+/*
+ *   pam_fprintd authentication module
+ *   Copyright (C) 2009 Jaroslav Barton <djaara at djaara.net>
+ *
+ *   Based on:
+ *
+ *
+ *   ThinkFinger Pluggable Authentication Module
+ *
+ *   PAM module for libthinkfinger which is a driver for the UPEK/SGS Thomson
+ *   Microelectronics fingerprint reader.
+ *
+ *   Copyright (C) 2007 Timo Hoenig <thoenig at suse.de>, <thoenig at nouse.net>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the
+ *   Free Software Foundation, Inc.,
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <config.h>
+#include <pam_fprintd-uinput.h>
+
+#include <linux/input.h>
+#include <linux/uinput.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int uinput_cr (int *fd)
+{
+	int retval = 0, ev_size = 0;
+	struct input_event ev = {
+		.type = EV_KEY,
+		.code = KEY_ENTER,
+		.time = {0, }
+	};
+
+	ev_size = sizeof (ev);
+
+	/* key press */
+	ev.value = 1;
+	if (write (*fd, &ev, ev_size) != ev_size) {
+		retval = errno;
+		goto out;
+	}
+	/* key release */
+	ev.value = 0;
+	if (write (*fd, &ev, ev_size) != ev_size) {
+		retval = errno;
+		goto out;
+	}
+
+out:
+	return retval;
+}
+
+int uinput_close (int *fd)
+{
+	int retval = 0;
+
+	/* destroy virtual input device */
+	if (ioctl (*fd, UI_DEV_DESTROY, 0) < 0)
+		retval = errno;
+
+	if (close (*fd) < 0)
+		retval = errno;
+
+	return retval;
+}
+
+int uinput_open (int *fd)
+{
+	int retval = 0, i, device_size = 0;
+	struct uinput_user_dev device = {
+		.name = "Virtual ThinkFinger Keyboard"
+	};
+
+        *fd = open ("/dev/input/uinput", O_WRONLY | O_NDELAY);
+        if (*fd < 0)
+                *fd = open ("/dev/misc/uinput", O_WRONLY | O_NDELAY);
+        if (*fd < 0)
+                *fd = open ("/dev/uinput", O_WRONLY | O_NDELAY);
+        if (*fd < 0) {
+		retval = errno;
+		goto out;
+	}
+
+	device_size = sizeof (device);
+
+	/* our single key keyboard */
+	i  = ioctl (*fd, UI_SET_EVBIT, EV_KEY) < 0;
+	i |= ioctl (*fd, UI_SET_KEYBIT, KEY_ENTER) < 0;
+
+	if (write (*fd, &device, device_size) != device_size) {
+		retval = errno;
+		goto out;
+	}
+
+	/* create virtual input device */
+	if (ioctl (*fd, UI_DEV_CREATE, 0) < 0)
+		retval = errno;
+
+out:
+	return retval;
+}
+
diff --git a/pam/pam_fprintd-uinput.h b/pam/pam_fprintd-uinput.h
new file mode 100644
index 0000000..2e647b0
--- /dev/null
+++ b/pam/pam_fprintd-uinput.h
@@ -0,0 +1,38 @@
+/*
+ *   pam_fprintd authentication module
+ *   Copyright (C) 2009 Jaroslav Barton <djaara at djaara.net>
+ *
+ *   Based on:
+ *
+ *
+ *   ThinkFinger Pluggable Authentication Module
+ *
+ *   PAM module for libthinkfinger which is a driver for the UPEK/SGS Thomson
+ *   Microelectronics fingerprint reader.
+ *
+ *   Copyright (C) 2007 Timo Hoenig <thoenig at suse.de>, <thoenig at nouse.net>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the
+ *   Free Software Foundation, Inc.,
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef PAM_THINKFINGER_UINPUT_H
+#define PAM_THINKFINGER_UINPUT_H
+
+int uinput_cr    (int *fd);
+int uinput_close (int *fd);
+int uinput_open  (int *fd);
+
+#endif /* PAM_THINKFINGER_UINPUT_H */
diff --git a/pam/pam_fprintd.c b/pam/pam_fprintd.c
index 5e8757c..8d4b7f8 100644
--- a/pam/pam_fprintd.c
+++ b/pam/pam_fprintd.c
@@ -2,6 +2,7 @@
  * pam_fprint: PAM module for fingerprint authentication through fprintd
  * Copyright (C) 2007 Daniel Drake <dsd at gentoo.org>
  * Copyright (C) 2008 Bastien Nocera <hadess at hadess.net>
+ * Copyright (C) 2009 Jaroslav Barton <djaara at djaara.net>
  * 
  * Experimental code. This will be moved out of fprintd into it's own
  * package once the system has matured.
@@ -26,17 +27,20 @@
 #include <sys/types.h>
 #include <string.h>
 #include <syslog.h>
+#include <pthread.h>
 
 #include <dbus/dbus-glib-bindings.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
 #define PAM_SM_AUTH
 #include <security/pam_modules.h>
+#include <security/pam_ext.h>
 
 #include "marshal.h"
 
 #define N_(x) x
 #include "fingerprint-strings.h"
+#include "pam_fprintd-uinput.h"
 
 #define MAX_TRIES 3
 #define TIMEOUT 30
@@ -50,13 +54,47 @@
 	}						\
 }
 
+#define E(pamh, ...) {					\
+	char *s;					\
+	s = g_strdup_printf (__VA_ARGS__);		\
+	send_err_msg (pamh, s);				\
+	g_free (s);					\
+}
+
+typedef struct {
+	guint max_tries;
+	char *result;
+	gboolean timed_out;
+	gboolean is_swipe;
+	pam_handle_t *pamh;
+	GMainLoop *loop;
+
+	char *driver;
+} verify_data;
+
+typedef struct {
+	const char* user;
+	pthread_t t_pam_prompt;
+	pthread_t t_finger;
+	int finger_retval;
+	int prompt_retval;
+	pam_handle_t *pamh;
+	char done;
+	int uinput_fd;
+	verify_data* data;
+} pam_fprintd_s;
+
 
 static gboolean debug = FALSE;
+static gboolean askpass = FALSE;
+static char *msg = NULL;
+static pthread_mutex_t msg_m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t msg_c = PTHREAD_COND_INITIALIZER;
 
-static gboolean send_info_msg(pam_handle_t *pamh, const char *msg)
+static gboolean send_msg(pam_handle_t *pamh, const char *msg, int msgtype)
 {
 	const struct pam_message mymsg = {
-		.msg_style = PAM_TEXT_INFO,
+		.msg_style = msgtype,
 		.msg = msg,
 	};
 	const struct pam_message *msgp = &mymsg;
@@ -74,25 +112,15 @@ static gboolean send_info_msg(pam_handle_t *pamh, const char *msg)
 	return (pc->conv(1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS);
 }
 
-static gboolean send_err_msg(pam_handle_t *pamh, const char *msg)
-{
-	const struct pam_message mymsg = {
-		.msg_style = PAM_ERROR_MSG,
-		.msg = msg,
-	};
-	const struct pam_message *msgp = &mymsg;
-	const struct pam_conv *pc;
-	struct pam_response *resp;
-	int r;
-
-	r = pam_get_item(pamh, PAM_CONV, (const void **) &pc);
-	if (r != PAM_SUCCESS)
-		return FALSE;
 
-	if (!pc || !pc->conv)
-		return FALSE;
+static gboolean send_info_msg(pam_handle_t *pamh, const char *msg)
+{
+	return send_msg(pamh, msg, PAM_TEXT_INFO);
+}
 
-	return (pc->conv(1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS);
+static gboolean send_err_msg(pam_handle_t *pamh, const char *msg)
+{
+	return send_msg(pamh, msg, PAM_ERROR_MSG);
 }
 
 static void send_debug_msg(pam_handle_t *pamh, const char *msg)
@@ -200,17 +228,6 @@ static DBusGProxy *open_device(pam_handle_t *pamh, DBusGConnection *connection,
 	return dev;
 }
 
-typedef struct {
-	guint max_tries;
-	char *result;
-	gboolean timed_out;
-	gboolean is_swipe;
-	pam_handle_t *pamh;
-	GMainLoop *loop;
-
-	char *driver;
-} verify_data;
-
 static void verify_result(GObject *object, const char *result, gboolean done, gpointer user_data)
 {
 	verify_data *data = user_data;
@@ -229,20 +246,33 @@ static void verify_result(GObject *object, const char *result, gboolean done, gp
 
 static void verify_finger_selected(GObject *object, const char *finger_name, gpointer user_data)
 {
+	if (askpass) {
+		pthread_mutex_lock(&msg_m);
+	}
+
 	verify_data *data = user_data;
-	char *msg;
 
 	if (g_str_equal (finger_name, "any")) {
 		if (data->is_swipe == FALSE)
-			msg = g_strdup_printf ("Place your finger on %s", data->driver);
+			msg = g_strdup_printf (N_("Place your finger on %s"), data->driver);
 		else
-			msg = g_strdup_printf ("Swipe your finger on %s", data->driver);
+			msg = g_strdup_printf (N_("Swipe your finger on %s"), data->driver);
 	} else {
 		msg = g_strdup_printf (finger_str_to_msg(finger_name, data->is_swipe), data->driver);
 	}
+
 	D(data->pamh, "verify_finger_selected %s", msg);
-	send_info_msg (data->pamh, msg);
-	g_free (msg);
+
+	if (askpass) {
+		char* msg2 = g_strdup_printf(N_("Password or %s"), msg);
+		g_free(msg);
+		msg = msg2;
+		pthread_cond_broadcast(&msg_c);
+		pthread_mutex_unlock(&msg_m);
+	} else {
+		send_info_msg(data->pamh, msg);
+		g_free(msg);
+	}
 }
 
 static gboolean verify_timeout_cb (gpointer user_data)
@@ -251,23 +281,43 @@ static gboolean verify_timeout_cb (gpointer user_data)
 
 	data->timed_out = TRUE;
 	send_info_msg (data->pamh, "Verification timed out");
-	g_main_loop_quit (data->loop);
+
+	if (data && g_main_loop_is_running(data->loop)) {
+		g_main_loop_quit (data->loop);
+	}
 
 	return FALSE;
 }
 
-static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev)
+static gboolean pass_typed(gpointer user_data) {
+	pam_fprintd_s *fprintd = user_data;
+	pthread_mutex_lock(&msg_m);
+		if (fprintd->done) {
+			if (fprintd->data && g_main_loop_is_running(fprintd->data->loop)) {
+				g_main_loop_quit(fprintd->data->loop);
+			}
+			return FALSE;
+		}
+	pthread_mutex_unlock(&msg_m);
+	return TRUE;
+}
+
+static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev, pam_fprintd_s *fpdata)
 {
 	GError *error = NULL;
 	GHashTable *props;
 	DBusGProxy *p;
 	verify_data *data;
 	int ret;
+	int r;
+
+	pam_fprintd_s* fprintd = fpdata;
 
 	data = g_new0 (verify_data, 1);
 	data->max_tries = MAX_TRIES;
 	data->pamh = pamh;
 	data->loop = loop;
+	fpdata->data = data;
 
 	/* Get some properties for the device */
 	p = dbus_g_proxy_new_from_proxy (dev, "org.freedesktop.DBus.Properties", NULL);
@@ -296,7 +346,7 @@ static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev)
 
 	ret = PAM_AUTH_ERR;
 
-	while (ret == PAM_AUTH_ERR && data->max_tries > 0) {
+	while (ret == PAM_AUTH_ERR && data->max_tries > 0 && !fprintd->done) {
 		GSource *source;
 		guint timeout_id;
 
@@ -305,6 +355,13 @@ static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev)
 		timeout_id = g_source_attach (source, g_main_loop_get_context (loop));
 		g_source_set_callback (source, verify_timeout_cb, data, NULL);
 
+		/* quit finger thread after pass is typed on keyboard */
+		GSource *passtyped;
+		guint passtyped_id;
+		passtyped = g_timeout_source_new_seconds (1);
+		passtyped_id = g_source_attach (passtyped, g_main_loop_get_context(loop));
+		g_source_set_callback (passtyped, pass_typed, fprintd, NULL);
+
 		data->timed_out = FALSE;
 
 		if (!dbus_g_proxy_call (dev, "VerifyStart", &error, G_TYPE_STRING, "any", G_TYPE_INVALID, G_TYPE_INVALID)) {
@@ -313,6 +370,9 @@ static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev)
 
 			g_source_remove (timeout_id);
 			g_source_unref (source);
+
+			g_source_remove (passtyped_id);
+			g_source_unref (passtyped);
 			break;
 		}
 
@@ -321,19 +381,27 @@ static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev)
 		g_source_remove (timeout_id);
 		g_source_unref (source);
 
+		g_source_remove (passtyped_id);
+		g_source_unref (passtyped);
+
 		/* Ignore errors from VerifyStop */
 		dbus_g_proxy_call (dev, "VerifyStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
-
-		if (data->timed_out) {
+		if (data->timed_out || fprintd->done) {
 			ret = PAM_AUTHINFO_UNAVAIL;
 			break;
 		} else {
 			if (g_str_equal (data->result, "verify-no-match")) {
 				send_err_msg (data->pamh, "Failed to match fingerprint");
 				ret = PAM_AUTH_ERR;
-			} else if (g_str_equal (data->result, "verify-match"))
+			} else if (g_str_equal (data->result, "verify-match")) {
+				if (askpass) {
+					r =uinput_cr (&fprintd->uinput_fd);
+					if (r != 0) {
+						E(pamh, "Could not send carriage return via uinput: %s.", strerror (r));
+					}
+				}
 				ret = PAM_SUCCESS;
-			else if (g_str_equal (data->result, "verify-unknown-error"))
+			} else if (g_str_equal (data->result, "verify-unknown-error"))
 				ret = PAM_AUTHINFO_UNAVAIL;
 			else if (g_str_equal (data->result, "verify-disconnected")) {
 				ret = PAM_AUTHINFO_UNAVAIL;
@@ -369,33 +437,101 @@ static void release_device(pam_handle_t *pamh, DBusGProxy *dev)
 	}
 }
 
-static int do_auth(pam_handle_t *pamh, const char *username)
+static void do_auth(void* data)
 {
+	pam_fprintd_s *fprintd = data;
+
 	DBusGProxy *manager;
 	DBusGConnection *connection;
 	DBusGProxy *dev;
 	GMainLoop *loop;
 	int ret;
 
-	manager = create_manager (pamh, &connection, &loop);
-	if (manager == NULL)
-		return PAM_AUTHINFO_UNAVAIL;
+	manager = create_manager (fprintd->pamh, &connection, &loop);
+	fprintd->done = 0;
+	if (manager == NULL) {
+		fprintd->finger_retval = PAM_AUTHINFO_UNAVAIL;
+		return;
+	}
 
-	dev = open_device(pamh, connection, manager, username);
+	dev = open_device (fprintd->pamh, connection, manager, fprintd->user);
 	g_object_unref (manager);
 	if (!dev) {
 		g_main_loop_unref (loop);
 		close_and_unref (connection);
-		return PAM_AUTHINFO_UNAVAIL;
+		fprintd->finger_retval = PAM_AUTHINFO_UNAVAIL;
+		return;
 	}
-	ret = do_verify(loop, pamh, dev);
+	ret = do_verify(loop, fprintd->pamh, dev, fprintd);
 
 	g_main_loop_unref (loop);
-	release_device(pamh, dev);
+	release_device(fprintd->pamh, dev);
 	g_object_unref (dev);
 	close_and_unref (connection);
 
-	return ret;
+	fprintd->finger_retval = ret;
+	if (askpass) {
+		pthread_exit (NULL);
+	}
+}
+
+/**
+ * Parse module parameters
+ */
+static void pam_fprintd_options(int argc, const char** argv)
+{
+	guint i;
+
+	for (i = 0; i < argc; i++) {
+		if (argv[i] != NULL) {
+			if (g_str_equal (argv[i], "debug")) {
+				g_message ("debug on");
+				debug = TRUE;
+			} else if (g_str_equal (argv[i], "askpass")) {
+				/* g_message ("asking for password"); */
+				askpass = TRUE;
+			}
+		}
+	}
+}
+
+/**
+ * Modified from pam_thinkginger
+ */
+static int pam_user_sanity_check (const char* user)
+{
+	size_t len = strlen(user);
+	return strstr(user, "../") || user[0] == '-' || user[len - 1] == '/';
+}
+
+/**
+ * Modified from pam_thinkfinger
+ */
+static void pam_prompt_thread(void* data)
+{
+	pthread_mutex_lock (&msg_m);
+		while (msg == NULL) {
+			pthread_cond_wait (&msg_c, &msg_m);
+		}
+	pthread_mutex_unlock(&msg_m);
+
+	pam_fprintd_s* fprintd = data;
+	char* resp;
+
+	/* always returning from pam_prompt due to the CR sent by the keyboard or by uinput */
+	pam_prompt (fprintd->pamh, PAM_PROMPT_ECHO_OFF, &resp, msg);
+	g_free(msg);
+
+	/* set authentication token (password) for pam_unix or others */
+	pam_set_item (fprintd->pamh, PAM_AUTHTOK, resp);
+	D(fprintd->pamh, "PAM_AUTHTOK is set");
+
+	/* pam prompt is done, finger thread shoud quit too */
+	pthread_mutex_lock(&msg_m);
+		fprintd->done = 1;
+	pthread_mutex_unlock(&msg_m);
+
+	pthread_exit (NULL);
 }
 
 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
@@ -403,36 +539,81 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
 {
 	const char *rhost = NULL;
 	const char *username;
-	guint i;
 	int r;
+	int retval = PAM_AUTH_ERR;
+	pam_fprintd_s fprintd;
 
 	g_type_init ();
 
+	pam_fprintd_options (argc, argv);
+
 	dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN,
 					   G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID);
 
 	pam_get_item(pamh, PAM_RHOST, (const void **)(const void*) &rhost);
 	if (rhost != NULL && strlen(rhost) > 0) {
 		/* remote login (e.g. over SSH) */
+		D(pamh, "Remote loggin (%s), bypassing...", rhost);
 		return PAM_AUTHINFO_UNAVAIL;
 	}
 
 	r = pam_get_user(pamh, &username, NULL);
-	if (r != PAM_SUCCESS)
+	if (r != PAM_SUCCESS || pam_user_sanity_check(username))
 		return PAM_AUTHINFO_UNAVAIL;
 
-	for (i = 0; i < argc; i++) {
-		if (argv[i] != NULL && g_str_equal (argv[i], "debug")) {
-			g_message ("debug on");
-			debug = TRUE;
+	fprintd.pamh = pamh;
+	fprintd.user = username;
+
+	if (askpass) {
+		r = uinput_open (&fprintd.uinput_fd);
+		if (r != 0) {
+			E(pamh, "Initializing uinput failed: %s.", strerror (r));
+			retval = PAM_AUTHINFO_UNAVAIL;
+			goto out;
 		}
+
+		r = pthread_create(&fprintd.t_pam_prompt, NULL, (void*)pam_prompt_thread, &fprintd);
+		if (r != 0) {
+			E(pamh, "Error calling pthread_create (%s).", strerror (r));
+			goto out;
+		}
+
+		r = pthread_create(&fprintd.t_finger, NULL, (void*)do_auth, &fprintd);
+		if (r != 0) {
+			E(pamh, "Error calling pthread_create (%s).", strerror (r));
+			goto out;
+		}
+
+		r = pthread_join (fprintd.t_finger, NULL);
+		if (r != 0) {
+			E(pamh, "Error calling pthread_join (%s).", strerror (r));
+			goto out;
+		}
+
+		r = pthread_join (fprintd.t_pam_prompt, NULL);
+		if (r != 0) {
+			E(pamh, "Error calling pthread_join (%s).", strerror (r));
+			goto out;
+		}
+	} else {
+		do_auth((void*)&fprintd);
 	}
 
-	r = do_auth(pamh, username);
+	if (fprintd.finger_retval == PAM_SUCCESS)
+		retval = PAM_SUCCESS;
+	else
+		retval = PAM_AUTHINFO_UNAVAIL;
 
-	return r;
+	if (askpass && fprintd.uinput_fd > 0) {
+		uinput_close(&fprintd.uinput_fd);
+	}
+
+out:
+	return retval;
 }
 
+
+
 PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
 			      const char **argv)
 {
-- 
1.6.0.6



More information about the fprint mailing list