pam: Stop authentication with PAM_AUTHINFO_UNAVAIL on name owner change

If fprintd disappears or is replaced, then we might be getting signals
from another daemon/verifcation session.

As such we must give up at that point.

Related: #47
This commit is contained in:
Benjamin Berg
2020-12-05 00:55:06 +01:00
parent a170a3a09f
commit c5877bbc12

View File

@ -160,6 +160,9 @@ out:
} }
typedef struct { typedef struct {
char *dev;
bool has_multiple_devices;
unsigned max_tries; unsigned max_tries;
char *result; char *result;
bool timed_out; bool timed_out;
@ -325,56 +328,49 @@ static int verify_started_cb (sd_bus_message *m,
} }
static int static int
do_verify (pam_handle_t *pamh, do_verify (sd_bus *bus,
sd_bus *bus, verify_data *data)
const char *dev,
bool has_multiple_devices)
{ {
verify_data *data;
sd_bus_slot *verify_status_slot, *verify_finger_selected_slot; sd_bus_slot *verify_status_slot, *verify_finger_selected_slot;
char *scan_type = NULL; char *scan_type = NULL;
int ret; int ret;
int r; int r;
data = calloc (1, sizeof(verify_data));
data->max_tries = max_tries;
data->pamh = pamh;
/* Get some properties for the device */ /* Get some properties for the device */
r = get_property_string (bus, r = get_property_string (bus,
"net.reactivated.Fprint", "net.reactivated.Fprint",
dev, data->dev,
"net.reactivated.Fprint.Device", "net.reactivated.Fprint.Device",
"scan-type", "scan-type",
NULL, NULL,
&scan_type); &scan_type);
if (r < 0) if (r < 0)
pam_syslog (data->pamh, LOG_ERR, "Failed to get scan-type for %s: %d", dev, r); pam_syslog (data->pamh, LOG_ERR, "Failed to get scan-type for %s: %d", data->dev, r);
if (debug) if (debug)
pam_syslog (data->pamh, LOG_DEBUG, "scan-type for %s: %s", dev, scan_type); pam_syslog (data->pamh, LOG_DEBUG, "scan-type for %s: %s", data->dev, scan_type);
if (str_equal (scan_type, "swipe")) if (str_equal (scan_type, "swipe"))
data->is_swipe = true; data->is_swipe = true;
free (scan_type); free (scan_type);
if (has_multiple_devices) { if (data->has_multiple_devices) {
get_property_string (bus, get_property_string (bus,
"net.reactivated.Fprint", "net.reactivated.Fprint",
dev, data->dev,
"net.reactivated.Fprint.Device", "net.reactivated.Fprint.Device",
"name", "name",
NULL, NULL,
&data->driver); &data->driver);
if (r < 0) if (r < 0)
pam_syslog (data->pamh, LOG_ERR, "Failed to get driver name for %s: %d", dev, r); pam_syslog (data->pamh, LOG_ERR, "Failed to get driver name for %s: %d", data->dev, r);
if (debug && r == 0) if (debug && r == 0)
pam_syslog (data->pamh, LOG_DEBUG, "driver name for %s: %s", dev, data->driver); pam_syslog (data->pamh, LOG_DEBUG, "driver name for %s: %s", data->dev, data->driver);
} }
verify_status_slot = NULL; verify_status_slot = NULL;
sd_bus_match_signal (bus, sd_bus_match_signal (bus,
&verify_status_slot, &verify_status_slot,
"net.reactivated.Fprint", "net.reactivated.Fprint",
dev, data->dev,
"net.reactivated.Fprint.Device", "net.reactivated.Fprint.Device",
"VerifyStatus", "VerifyStatus",
verify_result, verify_result,
@ -384,7 +380,7 @@ do_verify (pam_handle_t *pamh,
sd_bus_match_signal (bus, sd_bus_match_signal (bus,
&verify_finger_selected_slot, &verify_finger_selected_slot,
"net.reactivated.Fprint", "net.reactivated.Fprint",
dev, data->dev,
"net.reactivated.Fprint.Device", "net.reactivated.Fprint.Device",
"VerifyFingerSelected", "VerifyFingerSelected",
verify_finger_selected, verify_finger_selected,
@ -405,7 +401,7 @@ do_verify (pam_handle_t *pamh,
r = sd_bus_call_method_async (bus, r = sd_bus_call_method_async (bus,
NULL, NULL,
"net.reactivated.Fprint", "net.reactivated.Fprint",
dev, data->dev,
"net.reactivated.Fprint.Device", "net.reactivated.Fprint.Device",
"VerifyStart", "VerifyStart",
verify_started_cb, verify_started_cb,
@ -415,7 +411,7 @@ do_verify (pam_handle_t *pamh,
if (r < 0) { if (r < 0) {
if (debug) if (debug)
pam_syslog (pamh, LOG_DEBUG, "VerifyStart call failed: %d", r); pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart call failed: %d", r);
break; break;
} }
@ -437,7 +433,8 @@ do_verify (pam_handle_t *pamh,
break; break;
if (r == 0) { if (r == 0) {
if (debug) { if (debug) {
pam_syslog(pamh, LOG_DEBUG, "Waiting for %"PRId64" seconds (%"PRId64" usecs)", pam_syslog(data->pamh, LOG_DEBUG,
"Waiting for %"PRId64" seconds (%"PRId64" usecs)",
wait_time / USEC_PER_SEC, wait_time / USEC_PER_SEC,
wait_time); wait_time);
} }
@ -461,7 +458,7 @@ do_verify (pam_handle_t *pamh,
data->verify_started = false; data->verify_started = false;
sd_bus_call_method (bus, sd_bus_call_method (bus,
"net.reactivated.Fprint", "net.reactivated.Fprint",
dev, data->dev,
"net.reactivated.Fprint.Device", "net.reactivated.Fprint.Device",
"VerifyStop", "VerifyStop",
NULL, NULL,
@ -501,11 +498,6 @@ do_verify (pam_handle_t *pamh,
sd_bus_slot_unref (verify_status_slot); sd_bus_slot_unref (verify_status_slot);
sd_bus_slot_unref (verify_finger_selected_slot); sd_bus_slot_unref (verify_finger_selected_slot);
if (data->result)
free (data->result);
free (data->driver);
free (data);
return ret; return ret;
} }
@ -609,39 +601,88 @@ claim_device (pam_handle_t *pamh,
return true; return true;
} }
static int
name_owner_changed (sd_bus_message *m,
void *userdata,
sd_bus_error *ret_error)
{
verify_data *data = userdata;
const char *name = NULL;
const char *old_owner = NULL;
const char *new_owner = NULL;
if (sd_bus_message_read (m, "sss", &name, &old_owner, &new_owner) < 0) {
pam_syslog (data->pamh, LOG_ERR, "Failed to parse NameOwnerChanged signal: %d", errno);
return 0;
}
if (strcmp (name, "net.reactivated.Fprint") != 0)
return 0;
/* Name owner for fprintd changed, give up as we might start listening
* to events from a new name owner otherwise. */
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
if (debug)
pam_syslog (data->pamh, LOG_ERR, "fprintd name owner changed during operation!\n");
return 0;
}
static int do_auth(pam_handle_t *pamh, const char *username) static int do_auth(pam_handle_t *pamh, const char *username)
{ {
char *dev;
bool have_prints; bool have_prints;
bool has_multiple_devices;
int ret = PAM_AUTHINFO_UNAVAIL; int ret = PAM_AUTHINFO_UNAVAIL;
verify_data *data;
sd_bus_slot *name_owner_changed_slot;
sd_bus *bus = NULL; sd_bus *bus = NULL;
data = calloc (1, sizeof(verify_data));
data->max_tries = max_tries;
data->pamh = pamh;
if (sd_bus_open_system (&bus) < 0) { if (sd_bus_open_system (&bus) < 0) {
pam_syslog (pamh, LOG_ERR, "Error with getting the bus: %d", errno); pam_syslog (pamh, LOG_ERR, "Error with getting the bus: %d", errno);
return PAM_AUTHINFO_UNAVAIL; return PAM_AUTHINFO_UNAVAIL;
} }
dev = open_device (pamh, bus, &has_multiple_devices); name_owner_changed_slot = NULL;
if (dev == NULL) { sd_bus_match_signal (bus,
&name_owner_changed_slot,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"NameOwnerChanged",
name_owner_changed,
data);
data->dev = open_device (pamh, bus, &data->has_multiple_devices);
if (data->dev == NULL) {
sd_bus_unref (bus); sd_bus_unref (bus);
return PAM_AUTHINFO_UNAVAIL; return PAM_AUTHINFO_UNAVAIL;
} }
have_prints = user_has_prints (pamh, bus, dev, username); have_prints = user_has_prints (pamh, bus, data->dev, username);
if (debug) if (debug)
pam_syslog (pamh, LOG_DEBUG, "prints registered: %s\n", have_prints ? "yes" : "no"); pam_syslog (pamh, LOG_DEBUG, "prints registered: %s\n", have_prints ? "yes" : "no");
if (!have_prints) if (!have_prints)
goto out; goto out;
if (claim_device (pamh, bus, dev, username)) { if (claim_device (pamh, bus, data->dev, username)) {
ret = do_verify (pamh, bus, dev, has_multiple_devices); ret = do_verify (bus, data);
release_device (pamh, bus, dev); release_device (pamh, bus, data->dev);
} }
out: out:
free (dev); sd_bus_slot_unref (name_owner_changed_slot);
if (data->result)
free (data->result);
free (data->driver);
free (data->dev);
free (data);
sd_bus_unref (bus); sd_bus_unref (bus);
return ret; return ret;