--- pam-fprint/src/pam_fprint.c	2009-01-08 22:31:21.000000000 +0100
+++ pam-fprint-ds/src/pam_fprint.c	2012-01-30 16:36:49.000000000 +0100
@@ -19,9 +19,11 @@
 
 #include <stdio.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <pwd.h>
 #include <string.h>
+#include <utmpx.h>
 
 #include <fprint.h>
 
@@ -150,16 +152,34 @@
 }
 
 static int do_identify(pam_handle_t *pamh, struct fp_dev *dev,
-	struct fp_print_data **gallery, enum fp_finger *fingers)
+	struct fp_print_data **gallery, enum fp_finger *fingers, int default_finger)
 {
+	int finger_pos = 0;
 	int max_tries = 5;
 	size_t offset;
 	const char *driver_name = fp_driver_get_full_name(fp_dev_get_driver(dev));
-	const char *fstr = fingerstr(fingers[0]);
+	const char *fstr;
+	char msg[128];
+	
+	
+	if (default_finger > 0) {
+	    for (;gallery[finger_pos];finger_pos++) {
+		if (fingers[finger_pos] == default_finger)
+		    break;
+	    }
+	    
+	    if (!gallery[finger_pos]) {
+		snprintf(msg, sizeof(msg), "Finger %d (%s) is not enrolled", default_finger, fingerstr(default_finger));
+			msg[sizeof(msg) - 1] = 0;
+			send_err_msg(pamh, msg);
+			return PAM_AUTHINFO_UNAVAIL;
+	    }
+	}
+	
+	fstr = fingerstr(fingers[finger_pos]);
 	
 	do {
 		int r;
-		char msg[128];
 
 		
 		if (fp_dev_supports_identification(dev)) {
@@ -173,7 +193,7 @@
 		    snprintf(msg, sizeof(msg), "Scan %s finger on %s", fstr, driver_name);
 		    msg[sizeof(msg) - 1] = 0;
 		    send_info_msg(pamh, msg);
-		    r = fp_verify_finger(dev, gallery[0]);
+		    r = fp_verify_finger(dev, gallery[finger_pos]);
 		}
 		if (r < 0) {
 			snprintf(msg, sizeof(msg), "Fingerprint verification error %d", r);
@@ -207,7 +227,7 @@
 	return PAM_AUTHINFO_UNAVAIL;
 }
 
-static int do_auth(pam_handle_t *pamh)
+static int do_auth(pam_handle_t *pamh, int finger)
 {
 	int r;
 	struct fp_dscv_dev **ddevs;
@@ -255,7 +275,7 @@
 		return PAM_AUTHINFO_UNAVAIL;
 	}
 
-	r = do_identify(pamh, dev, gallery, fingers);
+	r = do_identify(pamh, dev, gallery, fingers, finger);
 	
 	gallery_iter = gallery;
 	while (*gallery_iter)
@@ -269,9 +289,15 @@
 	return r;
 }
 
+
 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
 	const char **argv)
 {
+	int i;
+	int finger = -1;
+	char msg[128];
+	const char *tty;
+	const char *env;
 	const char *rhost = NULL;
 	FILE *fd;
 	char buf[5];
@@ -294,6 +320,90 @@
 	if (!passwd)
 		return PAM_AUTHINFO_UNAVAIL;
 
+	for (i = 0; i < argc; i++) {
+	    if (!strncmp(argv[i], "finger=", 7)) {
+		char *endptr;
+		finger = strtol(argv[i] + 7, &endptr, 10);
+		if (*endptr != '\0') {
+		    snprintf(msg, sizeof(msg), "pam_fprint: invalid finger \"%s\" is specified", argv[i] + 7);
+		    msg[sizeof(msg) - 1] = 0;
+		    send_err_msg(pamh, msg);
+		    return PAM_AUTHINFO_UNAVAIL;
+		}
+	    } else if (!strncmp(argv[i], "check=", 6)) {
+		int ret;
+		pid_t pid;
+		
+		pid = fork();
+		if (pid == -1) {
+		    send_err_msg(pamh, "Fork failed");
+		    return PAM_AUTHINFO_UNAVAIL;
+		}
+		
+		if (!pid) {
+		    const char *appname = strrchr(argv[i] + 6, '/');
+		    if (appname) appname++;
+		    else appname = argv[i] + 6;
+	
+		    execlp(argv[i] + 6, appname, username, (char*)NULL);
+		    snprintf(msg, sizeof(msg), "pam_fprint: execution of \"%s\" is failed", argv[i] + 6);
+		    msg[sizeof(msg) - 1] = 0;
+		    send_err_msg(pamh, msg);
+		    return PAM_AUTHINFO_UNAVAIL;
+		}
+		
+		    // we may like to have timeout here to avoid broken scripts breaking authentication
+		waitpid(pid, &ret, 0);
+		if (ret) return PAM_AUTHINFO_UNAVAIL;
+	    } else {
+		snprintf(msg, sizeof(msg), "pam_fprint: unhandled parameter \"%s\"", argv[i]);
+		msg[sizeof(msg) - 1] = 0;
+		send_err_msg(pamh, msg);
+		return PAM_AUTHINFO_UNAVAIL;
+	    }
+	}
+	
+
+
+	tty = ttyname(STDIN_FILENO);
+	if (tty) {
+	    struct utmpx *u;
+	    
+	    if (!strncmp(tty, "/dev/", 5)) tty += 5;
+
+	    setutxent();
+	    while (u = getutxent()) {
+		if (!strncmp(tty, u->ut_line, sizeof(u->ut_line))) {
+			// local terminals
+		    if ((u->ut_host == 0)||(*u->ut_host == 0)) break;
+			// xorg terminals
+		    if (*u->ut_host = ':') break;
+
+		    endutxent();
+		    
+			// remote terminals
+		    return PAM_AUTHINFO_UNAVAIL;
+		}
+	    }
+	    endutxent();
+	}
+	
+	env = getenv("SSH_CLIENT");
+	if ((env)&&(*env)) 
+	        return PAM_AUTHINFO_UNAVAIL;
+
+	env = getenv("SSH_TTY");
+	if ((env)&&(*env)) 
+	        return PAM_AUTHINFO_UNAVAIL;
+
+	env = getenv("SSH_CONNECTION");
+	if ((env)&&(*env)) 
+	        return PAM_AUTHINFO_UNAVAIL;
+	
+	env = getenv("NXSESSIONID");
+	if ((env)&&(*env)) 
+	        return PAM_AUTHINFO_UNAVAIL;
+
 	homedir = strdup(passwd->pw_dir);
 
 	/* a bit of a hack to make libfprint use the right home dir */
@@ -303,7 +413,7 @@
 		return PAM_AUTHINFO_UNAVAIL;
 	}
 
-	r = do_auth(pamh);
+	r = do_auth(pamh, finger);
 	free(homedir);
 	return r;
 }
