--- 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 #include +#include #include #include #include +#include #include @@ -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; }