1
/* ThinkFinger Pluggable Authentication Module
3
* PAM module for libthinkfinger which is a driver for the UPEK/SGS Thomson
4
* Microelectronics fingerprint reader.
6
* Copyright (C) 2007 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the
20
* Free Software Foundation, Inc.,
21
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
#include <libthinkfinger.h>
27
#include <pam_thinkfinger-uinput.h>
35
#include <security/pam_modules.h>
37
#include "pam_thinkfinger-compat.h"
39
#include <security/pam_ext.h>
46
volatile static int pam_tf_debug = 0;
51
pthread_t t_pam_prompt;
52
pthread_t t_thinkfinger;
60
static void pam_thinkfinger_log (const pam_thinkfinger_s *pam_thinkfinger, int type, const char *format, ...)
62
char message[LINE_MAX];
66
va_start (ap, format);
67
vsnprintf (message, sizeof(message), format, ap);
69
pam_syslog (pam_thinkfinger->pamh, type, message);
73
static void pam_thinkfinger_options (const pam_thinkfinger_s *pam_thinkfinger, int argc, const char **argv)
77
for (i = 0; i < argc; i++) {
78
if (!strcmp(argv[i], "debug"))
80
else if (!strcmp(argv[i], " ") || !strcmp(argv[i], "\t"))
83
pam_thinkfinger_log (pam_thinkfinger, LOG_INFO,
84
"Option '%s' is not recognised or not yet supported.", *(argv+i));
88
static int pam_thinkfinger_user_sanity_check (const pam_thinkfinger_s *pam_thinkfinger)
90
const char *user = pam_thinkfinger->user;
91
size_t len = strlen(user);
93
return strstr(user, "../") || user[0] == '-' || user[len - 1] == '/';
96
static int pam_thinkfinger_user_bir_check (const pam_thinkfinger_s *pam_thinkfinger)
100
char bir_file[MAX_PATH];
102
snprintf (bir_file, MAX_PATH-1, "%s/%s.bir", PAM_BIRDIR, pam_thinkfinger->user);
103
fd = open (bir_file, O_RDONLY | O_NOFOLLOW);
105
pam_thinkfinger_log (pam_thinkfinger, LOG_ERR,
106
"Could not open '%s/%s.bir': (%s).", PAM_BIRDIR, pam_thinkfinger->user, strerror (errno));
117
static libthinkfinger_state pam_thinkfinger_verify (const pam_thinkfinger_s *pam_thinkfinger)
119
libthinkfinger_state tf_state = TF_STATE_VERIFY_FAILED;
120
char bir_file[MAX_PATH];
123
snprintf (bir_file, MAX_PATH, "%s/%s.bir", PAM_BIRDIR, pam_thinkfinger->user);
125
if (pam_thinkfinger->tf == NULL)
128
libthinkfinger_set_file (pam_thinkfinger->tf, bir_file);
129
/* if the USB device is being removed while verification (e.g. suspend) retry */
130
while ((tf_state = libthinkfinger_verify (pam_thinkfinger->tf)) == TF_RESULT_USB_ERROR && --retry > 0)
133
if (retry == 0 && tf_state == TF_STATE_USB_ERROR)
134
pam_thinkfinger_log (pam_thinkfinger, LOG_WARNING, "USB device did not reappear in time");
139
static void thinkfinger_thread (void *data)
142
pam_thinkfinger_s *pam_thinkfinger = data;
143
libthinkfinger_state tf_state;
145
pam_thinkfinger_log (pam_thinkfinger, LOG_NOTICE, "%s called.", __FUNCTION__);
147
tf_state = pam_thinkfinger_verify (pam_thinkfinger);
148
if (tf_state == TF_RESULT_VERIFY_SUCCESS) {
149
pam_thinkfinger->swipe_retval = PAM_SUCCESS;
150
pam_thinkfinger_log (pam_thinkfinger, LOG_NOTICE,
151
"User '%s' authenticated (biometric identification record matched).", pam_thinkfinger->user);
152
} else if (tf_state == TF_RESULT_VERIFY_FAILED) {
153
pam_thinkfinger->swipe_retval = PAM_AUTH_ERR;
154
pam_thinkfinger_log (pam_thinkfinger, LOG_NOTICE,
155
"User '%s' verification failed (biometric identification record not matched).",
156
pam_thinkfinger->user);
158
pam_thinkfinger->swipe_retval = PAM_AUTH_ERR;
159
pam_thinkfinger_log (pam_thinkfinger, LOG_NOTICE,
160
"User '%s' verification failed (0x%x).", pam_thinkfinger->user, tf_state);
164
ret = uinput_cr (&pam_thinkfinger->uinput_fd);
166
pam_thinkfinger_log (pam_thinkfinger, LOG_ERR,
167
"Could not send carriage return via uinput: %s.", strerror (ret));
169
pam_thinkfinger_log (pam_thinkfinger, LOG_NOTICE,
170
"%s returning '%d': %s.", __FUNCTION__, pam_thinkfinger->swipe_retval,
171
pam_thinkfinger->swipe_retval ? pam_strerror (pam_thinkfinger->pamh, pam_thinkfinger->swipe_retval) : "success");
175
static void pam_prompt_thread (void *data)
177
pam_thinkfinger_s *pam_thinkfinger = data;
180
/* always returning from pam_prompt due to the CR sent by the keyboard or by uinput */
181
pam_prompt (pam_thinkfinger->pamh, PAM_PROMPT_ECHO_OFF, &resp, "Password or swipe finger: ");
182
pam_set_item (pam_thinkfinger->pamh, PAM_AUTHTOK, resp);
184
/* ThinkFinger thread will return once we call libthinkfinger_free */
185
if (pam_thinkfinger->tf != NULL)
186
libthinkfinger_free (pam_thinkfinger->tf);
191
static const char *handle_error (libthinkfinger_init_status init_status)
195
switch (init_status) {
196
case TF_INIT_NO_MEMORY:
197
msg = "Not enough memory.";
199
case TF_INIT_USB_DEVICE_NOT_FOUND:
200
msg = "USB device not found.";
202
case TF_INIT_USB_OPEN_FAILED:
203
msg = "Could not open USB device.";
205
case TF_INIT_USB_CLAIM_FAILED:
206
msg = "Could not claim USB device.";
208
case TF_INIT_USB_HELLO_FAILED:
209
msg = "Sending HELLO failed.";
211
case TF_INIT_UNDEFINED:
212
msg = "Undefined error.";
215
msg = "Unknown error.";
222
int pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, const char **argv)
225
int retval = PAM_AUTH_ERR;
226
pam_thinkfinger_s pam_thinkfinger;
227
struct termios term_attr;
228
libthinkfinger_init_status init_status;
230
pam_thinkfinger.swipe_retval = PAM_SERVICE_ERR;
231
pam_thinkfinger.pamh = pamh;
233
pam_thinkfinger_options (&pam_thinkfinger, argc, argv);
234
pam_thinkfinger_log (&pam_thinkfinger, LOG_INFO, "%s called.", __FUNCTION__);
236
pam_thinkfinger.isatty = isatty (STDIN_FILENO);
237
if (pam_thinkfinger.isatty == 1)
238
tcgetattr (STDIN_FILENO, &term_attr);
240
pam_get_user (pamh, &pam_thinkfinger.user, NULL);
241
if (pam_thinkfinger_user_sanity_check (&pam_thinkfinger) || pam_thinkfinger_user_bir_check (&pam_thinkfinger) < 0) {
242
pam_thinkfinger_log (&pam_thinkfinger, LOG_ERR, "User '%s' is unknown.", pam_thinkfinger.user);
243
retval = PAM_USER_UNKNOWN;
247
ret = uinput_open (&pam_thinkfinger.uinput_fd);
249
pam_thinkfinger_log (&pam_thinkfinger, LOG_ERR, "Initializing uinput failed: %s.", strerror (ret));
250
retval = PAM_AUTHINFO_UNAVAIL;
254
pam_thinkfinger.tf = libthinkfinger_new (&init_status);
255
if (init_status != TF_INIT_SUCCESS) {
256
pam_thinkfinger_log (&pam_thinkfinger, LOG_ERR, "Error: %s", handle_error (init_status));
257
retval = PAM_AUTHINFO_UNAVAIL;
261
ret = pthread_create (&pam_thinkfinger.t_pam_prompt, NULL, (void *) &pam_prompt_thread, &pam_thinkfinger);
263
pam_thinkfinger_log (&pam_thinkfinger, LOG_ERR, "Error calling pthread_create (%s).", strerror (ret));
266
ret = pthread_create (&pam_thinkfinger.t_thinkfinger, NULL, (void *) &thinkfinger_thread, &pam_thinkfinger);
268
pam_thinkfinger_log (&pam_thinkfinger, LOG_ERR, "Error calling pthread_create (%s).", strerror (ret));
271
ret = pthread_join (pam_thinkfinger.t_thinkfinger, NULL);
273
pam_thinkfinger_log (&pam_thinkfinger, LOG_ERR, "Error calling pthread_join (%s).", strerror (ret));
276
ret = pthread_join (pam_thinkfinger.t_pam_prompt, NULL);
278
pam_thinkfinger_log (&pam_thinkfinger, LOG_ERR, "Error calling pthread_join (%s).", strerror (ret));
282
if (pam_thinkfinger.uinput_fd > 0)
283
uinput_close (&pam_thinkfinger.uinput_fd);
284
if (pam_thinkfinger.isatty == 1) {
285
tcsetattr (STDIN_FILENO, TCSADRAIN, &term_attr);
288
if (pam_thinkfinger.swipe_retval == PAM_SUCCESS)
289
retval = PAM_SUCCESS;
291
retval = PAM_AUTHINFO_UNAVAIL;
293
pam_thinkfinger_log (&pam_thinkfinger, LOG_INFO,
294
"%s returning '%d': %s.", __FUNCTION__, retval, retval ? pam_strerror (pamh, retval) : "success");
299
int pam_sm_setcred (pam_handle_t *pamh, int flags, int argc, const char **argv)
305
int pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv)
311
struct pam_module _pam_thinkfinger_modstruct = {