Bugzilla – Attachment 263921 Details for
Bug 441144
kdm freezes if fingerprintreader is enabled
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Forgot Password
[patch]
Updated pam_fp.c to make kdm etc work with pam_fp
pam_fp.c (text/plain), 15.54 KB, created by
Mischa Salle
on 2009-01-08 16:52:43 UTC
(
hide
)
Description:
Updated pam_fp.c to make kdm etc work with pam_fp
Filename:
MIME Type:
Creator:
Mischa Salle
Created:
2009-01-08 16:52:43 UTC
Size:
15.54 KB
patch
obsolete
>/* pam_fp Pluggable Authentication Module > * > * PAM module for libfprint which is a driver for various fingerprint > * readers. > * > * Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net> > * > * Based on pam_thinkfinger of the ThinkFinger project. > * Copyright (C) 2007 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net> > * > * Based on pam_fprint of the libfprint project. > * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> > * > * 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 <stdio.h> >#include <stdlib.h> >#include <stdarg.h> >#include <unistd.h> >#include <string.h> >#include <fcntl.h> >#include <pwd.h> >#include <termios.h> >#include <pthread.h> >#include <signal.h> >#include <syslog.h> >#include <sys/types.h> >#include <sys/wait.h> > >#include <security/pam_modules.h> >#include <security/pam_ext.h> >#ifdef HAVE_OLD_PAM >#include "pam_fp-compat.h" >#else >#include <security/pam_ext.h> >#endif > >#include <fprint.h> > >#include <pam_fp-uinput.h> > >#define PAM_SM_AUTH > >#define MAX_PATH 256 >#define FP_RETRY_MAX 3 >#define FP_RECLAIM_MAX 15 > >volatile static int pam_tf_debug = 0; > >typedef struct { > struct fp_dscv_dev **ddevs; > struct fp_dscv_print **prints; > struct fp_dscv_dev *ddev; > struct fp_dscv_print *print; > struct fp_dev *dev; > enum fp_finger finger; > struct fp_print_data *data; >} pam_fp_libfprint_s; > >typedef struct { > const char *user; > pthread_t t_pam_prompt; > pthread_t t_fingerprint; > int swipe_result; > int swipe_succeeded; > int prompt_retval; > int isatty; > int uinput_fd; > pam_handle_t *pamh; > int child; > int parent; > int fds[2]; > struct sigaction sigchld_action; > struct sigaction sigchld_action_old; > struct sigaction sigpipe_action; > struct sigaction sigpipe_action_old; > pam_fp_libfprint_s fprint; >} pam_fp_s; > >static void pam_fp_log (const pam_fp_s *pam_fp, int type, const char *format, ...) >{ > char message[4096]; > va_list ap; > > if (pam_tf_debug) { > va_start (ap, format); > vsnprintf (message, sizeof(message), format, ap); > va_end (ap); > pam_syslog (pam_fp->pamh, type, "%s", message); > } >} > >static int pam_fp_save_sigchld_handler (pam_fp_s *pam_fp) >{ > int retval; > > pam_fp->sigchld_action.sa_handler = SIG_IGN; > sigemptyset (&pam_fp->sigchld_action.sa_mask); > retval = sigaction (SIGCHLD, &pam_fp->sigchld_action, &pam_fp->sigchld_action_old); > > return retval; >} > >static int pam_fp_restore_sigchld_handler (const pam_fp_s *pam_fp) >{ > int retval; > > retval = sigaction (SIGCHLD, &pam_fp->sigchld_action_old, NULL); > > return retval; >} > >static int pam_fp_save_sigpipe_handler (pam_fp_s *pam_fp) >{ > int retval; > > pam_fp->sigpipe_action.sa_handler = SIG_IGN; > sigemptyset (&pam_fp->sigchld_action.sa_mask); > retval = sigaction (SIGPIPE, &pam_fp->sigpipe_action, &pam_fp->sigpipe_action_old); > > return retval; >} > >static int pam_fp_restore_sigpipe_handler (const pam_fp_s *pam_fp) >{ > int retval; > > retval = sigaction (SIGPIPE, &pam_fp->sigpipe_action_old, NULL); > > return retval; >} > >static void pam_fp_options (const pam_fp_s *pam_fp, int argc, const char **argv) >{ > int i; > > for (i = 0; i < argc; i++) { > if (!strcmp (argv[i], "debug")) > pam_tf_debug = 1; > else if (!strcmp (argv[i], " ") || !strcmp (argv[i], "\t")) > continue; > else > pam_fp_log (pam_fp, LOG_INFO, > "Option '%s' is not recognised or not yet supported.", *(argv+i)); > } >} > >static int pam_fp_read_pipe (const pam_fp_s *pam_fp, int *result) >{ > int retval = -1; > > close (pam_fp->fds[1]); > retval = read (pam_fp->fds[0], result, sizeof(int)); > close (pam_fp->fds[0]); > > return retval; >} > >static void pam_fp_write_pipe (const pam_fp_s *pam_fp, int status) >{ > close (pam_fp->fds[0]); > if (write (pam_fp->fds[1], &status, sizeof(int)) < 0) > pam_fp_log (pam_fp, LOG_ERR, "Error writing to pipe."); > close (pam_fp->fds[1]); >} > >static const char *pam_fp_fts (enum fp_finger finger) >{ > const char *names[] = { > [LEFT_THUMB] = "left thumb", > [LEFT_INDEX] = "left index", > [LEFT_MIDDLE] = "left middle", > [LEFT_RING] = "left ring", > [LEFT_LITTLE] = "left little", > [RIGHT_THUMB] = "right thumb", > [RIGHT_INDEX] = "right index", > [RIGHT_MIDDLE] = "right middle", > [RIGHT_RING] = "right ring", > [RIGHT_LITTLE] = "right little", > }; > > if (finger < LEFT_THUMB || finger > RIGHT_LITTLE) > return "UNKNOWN"; > return names[finger]; >} > >static int pam_fp_find_match (struct fp_dscv_dev **ddevs, struct fp_dscv_print **prints, struct fp_dscv_dev **_ddev, > struct fp_dscv_print **_print) >{ > int ret = -1; > int i = 0; > struct fp_dscv_print *print; > struct fp_dscv_dev *ddev; > > while ((print = prints[i++]) != NULL) { > ddev = fp_dscv_dev_for_dscv_print (ddevs, print); > if (ddev) { > *_ddev = ddev; > *_print = print; > ret = 0; > goto out; > } > } >out: > return ret; >} > >static int pam_fp_libfprint_user_swipe (pam_fp_s *pam_fp, struct fp_print_data *data) >{ > int ret = -1; > pam_fp_libfprint_s *fprint = &pam_fp->fprint; > const char *driver_name = fp_driver_get_full_name (fp_dev_get_driver (fprint->dev)); > const char *fstr = pam_fp_fts (fprint->finger); > > pam_fp_log (pam_fp, LOG_NOTICE, "Awaiting swipe (%s, %s).", driver_name, fstr); > > ret = fp_verify_finger (fprint->dev, data); > if (ret < 0) { > pam_fp_log (pam_fp, LOG_NOTICE, "Aborting swipe (%s , %s).", driver_name, fstr); > goto out; > } > pam_fp_log (pam_fp, LOG_NOTICE, "Received swipe (%s, %s).", driver_name, fstr); > switch (ret) { > case FP_VERIFY_NO_MATCH: { > pam_fp_log (pam_fp, LOG_NOTICE, "%s: no match.", __FUNCTION__); > pam_fp->swipe_result = PAM_AUTH_ERR; > ret = 0; > break; > } > case FP_VERIFY_MATCH: { > pam_fp_log (pam_fp, LOG_NOTICE, "%s: match.", __FUNCTION__); > pam_fp->swipe_result = PAM_SUCCESS; > ret = 0; > break; > } > case FP_VERIFY_RETRY: > break; > case FP_VERIFY_RETRY_TOO_SHORT: > break; > case FP_VERIFY_RETRY_CENTER_FINGER: > break; > case FP_VERIFY_RETRY_REMOVE_FINGER: > break; > } > >out: > return ret; >} > >static int pam_fp_libfprint_init (pam_fp_s *pam_fp) >{ > int retval = -1; > int ret; > pam_fp_libfprint_s *fprint = &pam_fp->fprint; > int std_err, std_err_new; > char *home_dir_old = NULL; > char *home_dir = NULL; > struct passwd *passwd; > > /* don't let libfprint clutter console prompts in case of errors */ > std_err = dup (STDERR_FILENO); > std_err_new = open ("/dev/null", O_WRONLY); > dup2 (std_err_new, STDERR_FILENO); > > passwd = getpwnam (pam_fp->user); > if (passwd == NULL) { > pam_fp_log (pam_fp, LOG_ERR, "getpwnam(3) failed."); > goto out; > } > > home_dir_old = getenv ("HOME"); > if (home_dir_old != NULL) { > home_dir_old = strdup (home_dir_old); > if (home_dir_old == NULL) { > pam_fp_log (pam_fp, LOG_ERR, "strdup(3) failed."); > goto out; > } > } > > pam_fp_log (pam_fp, LOG_NOTICE, "Stored $HOME=\"%s\".", home_dir_old); > > home_dir = strdup (passwd->pw_dir); > if (home_dir == NULL) { > pam_fp_log (pam_fp, LOG_ERR, "strdup(3) failed."); > free (home_dir_old); > goto out; > } > > ret = setenv ("HOME", home_dir, 1); > if (ret < 0) { > pam_fp_log (pam_fp, LOG_ERR, "setenv(3) failed."); > goto out; > } > > pam_fp_log (pam_fp, LOG_NOTICE, "Set $HOME=\"%s\".", home_dir); > > ret = fp_init(); > if (ret < 0) { > pam_fp_log (pam_fp, LOG_ERR, "fp_init failed."); > goto out; > } > > fprint->ddevs = fp_discover_devs (); > if (fprint->ddevs == NULL) { > pam_fp_log (pam_fp, LOG_ERR, "fp_discover_devs failed."); > goto out; > } > > fprint->prints = fp_discover_prints (); > if (fprint->prints == NULL) { > pam_fp_log (pam_fp, LOG_ERR, "fp_discover_prints failed."); > fp_dscv_devs_free(fprint->ddevs); > goto out; > } > > ret = pam_fp_find_match (fprint->ddevs, fprint->prints, &fprint->ddev, &fprint->print); > if (ret != 0) { > pam_fp_log (pam_fp, LOG_ERR, "No device <-> stored fingerprint match."); > fp_dscv_prints_free(fprint->prints); > fp_dscv_devs_free(fprint->ddevs); > goto out; > } > > fprint->dev = fp_dev_open (fprint->ddev); > if (fprint->dev == NULL) { > pam_fp_log (pam_fp, LOG_ERR, "fp_dev_open() failed."); > fp_dscv_devs_free (fprint->ddevs); > fp_dscv_prints_free (fprint->prints); > goto out; > } > > fprint->finger = fp_dscv_print_get_finger (fprint->print); > > ret = fp_print_data_from_dscv_print (fprint->print, &fprint->data); > fp_dscv_prints_free (fprint->prints); > if (ret != 0) { > pam_fp_log (pam_fp, LOG_ERR, "%s (fp_print_data_from_dscv_print failed).", __FUNCTION__); > fp_dev_close (fprint->dev); > fp_print_data_free (fprint->data); > goto out; > } > > retval = 0; > >out: > if (home_dir_old) { > pam_fp_log (pam_fp, LOG_NOTICE, "Restoring $HOME=\"%s\".", home_dir_old); > ret = setenv ("HOME", home_dir_old, 1); > if (ret < 0) > pam_fp_log (pam_fp, LOG_ERR, "setenv(3) failed."); > free (home_dir_old); > } > if (home_dir) > free (home_dir); > dup2 (std_err, STDERR_FILENO); > if (std_err_new > 0) > close (std_err_new); > if (std_err > 0) > close (std_err); > return retval; >} > >static void pam_fp_libfprint_deinit (pam_fp_s *pam_fp) >{ > pam_fp_libfprint_s *fprint = &pam_fp->fprint; > /* MISCHA added NULL checking, so that we can call deinit even if > * already done. Also necessary to call deinit just before the reclaim loop, > * otherwise device is taken. Hence have move deinit towards beginning. */ > if (fprint->data!=NULL) > fp_print_data_free (fprint->data); > if (fprint->dev!=NULL) > fp_dev_close (fprint->dev); >} > >static int pam_fp_libfprint_verify (pam_fp_s *pam_fp) >{ > int ret = -1; > int retry = 0; > int reclaim = 0; > pam_fp_libfprint_s *fprint = &pam_fp->fprint; > int init_ret; > > while (retry++ <= FP_RETRY_MAX) { > ret = pam_fp_libfprint_user_swipe (pam_fp, fprint->data); > if (ret == 0) { > pam_fp->swipe_succeeded = 1; > ret = 0; > break; > } > > while (reclaim++ <= FP_RECLAIM_MAX) { > /* MISCHA added pam_fp_libfprint_deinit here, otherwise > * device cannot be reclaimed */ > pam_fp_libfprint_deinit (pam_fp); > /* surprise removal, e.g. suspend */ > pam_fp_log (pam_fp, LOG_NOTICE, > "%s reclaim loop (#%i, retry %i).", __FUNCTION__, reclaim, retry); > usleep (250000); > /* MISCHA added logging of return val of init (in else) */ > if ((init_ret=pam_fp_libfprint_init (pam_fp)) == 0) { > reclaim = 0; > pam_fp_log (pam_fp, LOG_NOTICE, "%s reclaim success.", __FUNCTION__); > break; > } else > pam_fp_log (pam_fp, LOG_NOTICE, "%s returned %d", __FUNCTION__,init_ret); > > if (reclaim == FP_RECLAIM_MAX || retry == FP_RETRY_MAX) { > pam_fp_log (pam_fp, LOG_ERR, "Fingerprint reader did not return in time."); > ret = -1; > goto out; > } > } > } > >out: > fp_print_data_free (fprint->data); > return ret; >} > >static void pam_fp_swipe (pam_fp_s *pam_fp) >{ > int ret = -1; > > ret = pam_fp_libfprint_verify (pam_fp); > if (ret != 0) { > pam_fp_log (pam_fp, LOG_ERR, "pam_fp_verify failed (%i)", ret); > goto out; > } > > pam_fp_log (pam_fp, LOG_NOTICE, "Writing result to pipe: %i", pam_fp->swipe_result); > pam_fp_write_pipe (pam_fp, pam_fp->swipe_result); > > ret = uinput_cr (&pam_fp->uinput_fd); > if (ret != 0) > pam_fp_log (pam_fp, LOG_ERR, > "Could not send carriage return via uinput: %s.", strerror (ret)); > >out: > pam_fp_log (pam_fp, LOG_INFO, "%s (child) exit.", __FUNCTION__); > _exit (0); >} > >static void pam_fp_prompt (pam_fp_s *pam_fp) >{ > int ret = -1; > int stat_loc,wait_ret; /* for waitpid(), used to be wait() */ > char *resp = NULL; > > /* always returning from pam_prompt due to the CR sent by the keyboard or by uinput (child) */ > pam_prompt (pam_fp->pamh, PAM_PROMPT_ECHO_OFF, &resp, "Password or swipe finger: "); > pam_set_item (pam_fp->pamh, PAM_AUTHTOK, resp); > > if (strlen (resp) > 0) { > /* password was given, authenticate based on the passwordD, if any */ > pam_fp_log (pam_fp, LOG_NOTICE, "Password received, stopping child process (pid %i).", pam_fp->child); > kill (pam_fp->child, SIGKILL); > /* MISCHA changed: wait(NULL) would hang because child had > * already disappeared (?); this caused kdm to crash; using > * WNOHANG seems to have solved it. For WNOHANG need waitpid() > * instead of wait() Also added LOG_NOTICE */ > wait_ret=waitpid((pid_t)-1,&stat_loc,WNOHANG); > pam_fp_log (pam_fp, LOG_NOTICE, "Waitpid() returned with: stat_loc=%d, return val=%d",stat_loc,wait_ret); > > goto out; > } > > ret = pam_fp_read_pipe (pam_fp, &pam_fp->swipe_result); > if (ret > 0) { > /* there was a swipe, store its result */ > pam_fp_log (pam_fp, LOG_NOTICE, "Read result from pipe: %i", pam_fp->swipe_result); > pam_fp->swipe_succeeded = 1; > } > >out: > pam_fp_log (pam_fp, LOG_INFO, "%s (parent) exit.", __FUNCTION__); > return; >} > >PAM_EXTERN >int pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, const char **argv) >{ > int ret; > int retval = PAM_AUTHINFO_UNAVAIL; > const char *rhost = NULL; > pam_fp_s pam_fp; > struct termios term_attr; > int pid; > > pam_fp.pamh = pamh; > pam_fp.user = NULL; > pam_fp.swipe_result = PAM_AUTHINFO_UNAVAIL; > pam_fp.swipe_succeeded = 0; > pam_fp_options (&pam_fp, argc, argv); > memset (&pam_fp.sigchld_action, 0, sizeof(pam_fp.sigchld_action)); > memset (&pam_fp.sigpipe_action, 0, sizeof(pam_fp.sigpipe_action)); > pam_fp_save_sigchld_handler (&pam_fp); > pam_fp_save_sigpipe_handler (&pam_fp); > > pam_fp.isatty = isatty (STDIN_FILENO); > if (pam_fp.isatty == 1) > tcgetattr (STDIN_FILENO, &term_attr); > > pam_get_item (pamh, PAM_RHOST, (const void **)(const void*) &rhost); > if (rhost != NULL && strlen (rhost) > 0) { > pam_fp_log (&pam_fp, LOG_ERR, "Error: Remote login from host \"%s\" detected.", rhost); > goto out; > } > > ret = pam_get_user (pamh, &pam_fp.user, NULL); > if (ret != PAM_SUCCESS) { > pam_fp_log (&pam_fp, LOG_ERR, "No user name was provided."); > retval = PAM_USER_UNKNOWN; > goto out; > } > > ret = uinput_open (&pam_fp.uinput_fd); > if (ret != 0) { > pam_fp_log (&pam_fp, LOG_ERR, "Initializing uinput failed: %s.", strerror (ret)); > goto out; > } > > ret = pipe (pam_fp.fds); > if (ret < 0) { > pam_fp_log (&pam_fp, LOG_ERR, "pipe(2) failed."); > goto out; > } > > ret = pam_fp_libfprint_init (&pam_fp); > if (ret != 0) { > pam_fp_log (&pam_fp, LOG_ERR, "Initializing libfprint failed."); > goto out; > } > > pam_fp.parent = getpid (); > pid = fork (); > if (pid < 0) { > pam_fp_log (&pam_fp, LOG_ERR, "fork(2) failed."); > goto out; > } > > if (pid == 0) { > /* child */ > pam_fp.child = getpid (); > pam_fp_log (&pam_fp, LOG_INFO, "Starting pam_fp_swipe (pid %i).", pam_fp.child); > pam_fp_swipe (&pam_fp); > } else { > /* parent */ > pam_fp.child = pid; > pam_fp_log (&pam_fp, LOG_INFO, "Starting pam_fp_prompt (pid %i).", pam_fp.parent); > pam_fp_prompt (&pam_fp); > } > > pam_fp_libfprint_deinit (&pam_fp); >out: > if (pam_fp.uinput_fd > 0) > uinput_close (&pam_fp.uinput_fd); > if (pam_fp.isatty == 1) > tcsetattr (STDIN_FILENO, TCSADRAIN, &term_attr); > if (pam_fp.swipe_succeeded) > retval = pam_fp.swipe_result; > else > retval = PAM_AUTHINFO_UNAVAIL; > pam_fp_restore_sigpipe_handler (&pam_fp); > pam_fp_restore_sigchld_handler (&pam_fp); > > pam_fp_log (&pam_fp, LOG_INFO, > "%s returning '%d': %s.", __FUNCTION__, retval, retval ? pam_strerror (pamh, retval) : "success"); > > return retval; >} > > >PAM_EXTERN >int pam_sm_setcred (pam_handle_t *pamh, int flags, int argc, const char **argv) >{ > return PAM_SUCCESS; >} > >PAM_EXTERN >int pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv) >{ > return PAM_SUCCESS; >} > >#ifdef PAM_STATIC >struct pam_module _pam_fp_modstruct = { > "pam_fp", > pam_sm_authenticate, > pam_sm_setcred, > NULL, > NULL, > NULL, > pam_sm_chauthtok >}; >#endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 441144
:
255566
|
263084
|
263085
| 263921 |
266122
|
267710