Skip to content

Commit

Permalink
#31: Support multiple devices per user (#177)
Browse files Browse the repository at this point in the history
- adds support for multiple devices per user
- agent now starts a device watching thread per configured device
  • Loading branch information
mcdope authored Jul 20, 2024
1 parent d8402f9 commit 898cfcf
Show file tree
Hide file tree
Showing 16 changed files with 283 additions and 117 deletions.
8 changes: 8 additions & 0 deletions doc/pam_usb.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ See https://github.com/mcdope/pam_usb/wiki/Configuration
<volume_uuid>6F6B-42FC</volume_uuid>
<option name="probe_timeout">10</option>
</device>
<device id="MySecondDevice">
<vendor>Commodore</vendor>
<model>REU</model>
<serial>CMDKXXXXXXXXXXXXXXXX</serial>
<volume_uuid>6F6B-00FF</volume_uuid>
<option name="probe_timeout">10</option>
</device>
-->
</devices>

Expand All @@ -38,6 +45,7 @@ See https://github.com/mcdope/pam_usb/wiki/Configuration
removal:
<user id="scox">
<device>MyDevice</device>
<device>MySecondDevice</device>
<option name="quiet">true</option>
<agent event="lock">
<cmd>gnome-screensaver-command -\-lock</cmd>
Expand Down
63 changes: 51 additions & 12 deletions src/conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,40 +88,43 @@ static int pusb_conf_device_get_property(
xmlDoc *doc,
const char *property,
char *store,
size_t size
size_t size,
char *deviceId
)
{
char *xpath = NULL;
size_t xpath_len;
int retval;

xpath_len = strlen(CONF_DEVICE_XPATH) + strlen(opts->device.name) + strlen(property) + 1;
xpath_len = strlen(CONF_DEVICE_XPATH) + strlen(deviceId) + strlen(property) + 1;
xpath = xmalloc(xpath_len);
if (xpath == NULL) {
log_error("Memory allocation failed\n");
return 0;
}
memset(xpath, 0x00, xpath_len);
snprintf(xpath, xpath_len, CONF_DEVICE_XPATH, opts->device.name, property);
snprintf(xpath, xpath_len, CONF_DEVICE_XPATH, deviceId, property);
retval = pusb_xpath_get_string(doc, xpath, store, size);
xfree(xpath);
return retval;
}

static int pusb_conf_parse_device(
t_pusb_options *opts,
xmlDoc *doc
xmlDoc *doc,
int deviceIndex,
char *deviceId
)
{
pusb_conf_device_get_property(opts, doc, "vendor", opts->device.vendor, sizeof(opts->device.vendor));
pusb_conf_device_get_property(opts, doc, "model", opts->device.model, sizeof(opts->device.model));
pusb_conf_device_get_property(opts, doc, "vendor", opts->device_list[deviceIndex].vendor, sizeof(opts->device_list[deviceIndex].vendor), deviceId);
pusb_conf_device_get_property(opts, doc, "model", opts->device_list[deviceIndex].model, sizeof(opts->device_list[deviceIndex].model), deviceId);

if (!pusb_conf_device_get_property(opts, doc, "serial", opts->device.serial, sizeof(opts->device.serial)))
if (!pusb_conf_device_get_property(opts, doc, "serial", opts->device_list[deviceIndex].serial, sizeof(opts->device_list[deviceIndex].serial), deviceId))
{
return 0;
}

pusb_conf_device_get_property(opts, doc, "volume_uuid", opts->device.volume_uuid, sizeof(opts->device.volume_uuid));
pusb_conf_device_get_property(opts, doc, "volume_uuid", opts->device_list[deviceIndex].volume_uuid, sizeof(opts->device_list[deviceIndex].volume_uuid), deviceId);
return 1;
}

Expand Down Expand Up @@ -177,26 +180,62 @@ int pusb_conf_parse(
return 0;
}
snprintf(device_xpath, sizeof(device_xpath), CONF_USER_XPATH, user, "device");
retval = pusb_xpath_get_string(

char *device_list[10] = {
xmalloc(128), xmalloc(128), xmalloc(128), xmalloc(128), xmalloc(128),
xmalloc(128), xmalloc(128), xmalloc(128), xmalloc(128), xmalloc(128)
};
for (int currentDevice = 0; currentDevice < 10; currentDevice++)
{
memset(device_list[currentDevice], 0x0, 128);
}
retval = pusb_xpath_get_string_list(
doc,
device_xpath,
opts->device.name,
device_list,
sizeof(opts->device.name)
);
if (!retval || !pusb_conf_parse_device(opts, doc))
if (!retval)
{
log_error("No authentication device configured for user \"%s\".\n", user);
log_error("No authentication device(s) configured for user \"%s\".\n", user);
xmlFreeDoc(doc);
xmlCleanupParser();

for (int currentDevice = 0; currentDevice < 10; currentDevice++)
{
xfree(device_list[currentDevice]);
}
return 0;
}

for (int currentDevice = 0; currentDevice < 10; currentDevice++)
{
if (device_list[currentDevice] == NULL || strlen(device_list[currentDevice]) == 0)
{
continue;
}

strcpy(opts->device_list[currentDevice].name, device_list[currentDevice]);
pusb_conf_parse_device(opts, doc, currentDevice, device_list[currentDevice]);
}

if (!pusb_conf_parse_options(opts, doc, user, service))
{
xmlFreeDoc(doc);
xmlCleanupParser();

for (int currentDevice = 0; currentDevice < 10; currentDevice++)
{
xfree(device_list[currentDevice]);
}
return (0);
}
xmlFreeDoc(doc);
xmlCleanupParser();

for (int currentDevice = 0; currentDevice < 10; currentDevice++)
{
xfree(device_list[currentDevice]);
}
return (1);
}
1 change: 1 addition & 0 deletions src/conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ typedef struct pusb_options
char system_pad_directory[PATH_MAX];
char device_pad_directory[PATH_MAX];
t_pusb_device device;
t_pusb_device device_list[10];
} t_pusb_options;

struct s_opt_list
Expand Down
56 changes: 35 additions & 21 deletions src/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,47 @@ static int pusb_device_connected(t_pusb_options *opts, UDisksClient *udisks)
GDBusObjectManager *manager = udisks_client_get_object_manager(udisks);
GList *objects = g_dbus_object_manager_get_objects(manager);
int retval = 0;
int i;
int i;
UDisksObject *object = NULL;
UDisksDrive *drive = NULL;

log_debug("Searching for \"%s\" in the hardware database...\n", opts->device.name);

for (i = 0; i < g_list_length(objects); ++i)
for (int currentDevice = 0; currentDevice < 10; currentDevice++)
{
object = UDISKS_OBJECT(g_list_nth(objects, i)->data);
if (udisks_object_peek_drive(object))
if (strcmp(opts->device_list[currentDevice].name, "") == 0)
{
drive = udisks_object_get_drive(object);
retval = strcmp(udisks_drive_get_serial(drive), opts->device.serial) == 0;
continue;
}

if (strcmp(opts->device.vendor, "Generic") != 0)
{
retval = retval && strcmp(udisks_drive_get_vendor(drive), opts->device.vendor) == 0;
}
log_error("Searching for \"%s\" in the hardware database...\n", opts->device_list[currentDevice].name);

if (strcmp(opts->device.model, "Generic") != 0)
for (i = 0; i < g_list_length(objects); ++i)
{
object = UDISKS_OBJECT(g_list_nth(objects, i)->data);
if (udisks_object_peek_drive(object))
{
retval = retval && strcmp(udisks_drive_get_model(drive), opts->device.model) == 0;
}

g_object_unref(drive);
if (retval) {
break;
drive = udisks_object_get_drive(object);
retval = strcmp(udisks_drive_get_serial(drive), opts->device_list[currentDevice].serial) == 0;

if (strcmp(opts->device_list[currentDevice].vendor, "Generic") != 0)
{
retval = retval && strcmp(udisks_drive_get_vendor(drive), opts->device_list[currentDevice].vendor) == 0;
}

if (strcmp(opts->device_list[currentDevice].model, "Generic") != 0)
{
retval = retval && strcmp(udisks_drive_get_model(drive), opts->device_list[currentDevice].model) == 0;
}

g_object_unref(drive);
if (retval) {
strncpy(opts->device.name, opts->device_list[currentDevice].name, sizeof(opts->device.name) - 1);
strncpy(opts->device.vendor, opts->device_list[currentDevice].vendor, sizeof(opts->device.vendor) - 1);
strncpy(opts->device.model, opts->device_list[currentDevice].model, sizeof(opts->device.model) - 1);
strncpy(opts->device.serial, opts->device_list[currentDevice].serial, sizeof(opts->device.serial) - 1);
strncpy(opts->device.volume_uuid, opts->device_list[currentDevice].volume_uuid, sizeof(opts->device.volume_uuid) - 1);
currentDevice = 10;
break;
}
}
}
}
Expand All @@ -68,7 +82,7 @@ static int pusb_device_connected(t_pusb_options *opts, UDisksClient *udisks)
}
else
{
log_error("Authentication device \"%s\" is not connected.\n", opts->device.name);
log_error("None of the configured authentication devices is connected.\n");
}

for (i = 0; i < g_list_length(objects); ++i)
Expand All @@ -90,7 +104,7 @@ int pusb_device_check(t_pusb_options *opts, const char *user)
if (udisks_client_error != NULL)
{
log_error("Unable to check for device, could not get UDisksClient! Error was: %s\n", udisks_client_error->message);
g_error_free (udisks_client_error);
g_error_free(udisks_client_error);
return (0);
}

Expand Down
Loading

0 comments on commit 898cfcf

Please sign in to comment.