commit 9bfc0cc2449c17d230b1d3c3e8f856dfd4548ff9 Author: Andrea Luzzardi Date: Sun Oct 8 01:11:08 2006 +0000 Simple engine using HAL, XML parser, test application. diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..156971e --- /dev/null +++ b/src/Makefile @@ -0,0 +1,17 @@ +SRC = test.c \ + conf.c \ + log.c \ + xpath.c \ + hal.c +OBJ = $(SRC:.c=.o) +NAME = test +CC = gcc +CFLAGS = -Wall `pkg-config --cflags hal` `pkg-config --cflags libxml-2.0` +LDFLAGS = `pkg-config --libs hal` `pkg-config --libs libxml-2.0` + +all : $(NAME) +$(NAME) : $(OBJ) + $(CC) -o $(NAME) $(LDFLAGS) $(OBJ) + +clean : + rm -f $(OBJ) \ No newline at end of file diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 0000000..c8e28fa --- /dev/null +++ b/src/conf.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 +#include +#include +#include "conf.h" +#include "xpath.h" +#include "log.h" + +static void pusb_conf_options_get_from(t_pusb_options *opts, + const char *from, + xmlDoc *doc) +{ + pusb_xpath_get_string_from(doc, from, "option[@name='hostname']", + opts->hostname, sizeof(opts->hostname)); + pusb_xpath_get_bool_from(doc, from, "option[@name='debug']", + &(opts->debug)); + pusb_xpath_get_bool_from(doc, from, "option[@name='enable']", + &(opts->enable)); + pusb_xpath_get_bool_from(doc, from, "option[@name='try_otp']", + &(opts->try_otp)); + pusb_xpath_get_bool_from(doc, from, "option[@name='enforce_otp']", + &(opts->enforce_otp)); +} + +static int pusb_conf_parse_options(t_pusb_options *opts, + xmlDoc *doc, + const char *user, + const char *service) +{ + char *xpath = NULL; + size_t xpath_size; + int i; + struct s_opt_list opt_list[] = { + { CONF_DEVICE_XPATH, opts->device.name }, + { CONF_USER_XPATH, (char *)user }, + { CONF_SERVICE_XPATH, (char *)service }, + { NULL, NULL } + }; + + pusb_conf_options_get_from(opts, "//configuration/defaults/", doc); + for (i = 0; opt_list[i].name != NULL; ++i) + { + xpath_size = strlen(opt_list[i].name) + strlen(opt_list[i].value) + 1; + if (!(xpath = malloc(xpath_size))) + { + log_error("malloc error\n"); + return (0); + } + memset(xpath, 0x00, xpath_size); + snprintf(xpath, xpath_size, opt_list[i].name, opt_list[i].value, ""); + pusb_conf_options_get_from(opts, xpath, doc); + free(xpath); + } + return (1); +} + +static int pusb_conf_device_get_property(t_pusb_options *opts, + xmlDoc *doc, + const char *property, + char *store, + size_t size) +{ + char *xpath = NULL; + size_t xpath_len; + int retval; + + xpath_len = strlen(CONF_DEVICE_XPATH) + strlen(opts->device.name) + \ + strlen(property) + 1; + if (!(xpath = malloc(xpath_len))) + { + log_error("malloc error!\n"); + return (0); + } + memset(xpath, 0x00, xpath_len); + snprintf(xpath, xpath_len, CONF_DEVICE_XPATH, opts->device.name, + property); + retval = pusb_xpath_get_string(doc, xpath, store, size); + free(xpath); + return (retval); +} + +static int pusb_conf_parse_device(t_pusb_options *opts, xmlDoc *doc) +{ + log_debug("Parsing settings...\n"); + if (!pusb_conf_device_get_property(opts, doc, "vendor", opts->device.vendor, + sizeof(opts->device.vendor))) + return (0); + if (!pusb_conf_device_get_property(opts, doc, "model", opts->device.model, + sizeof(opts->device.model))) + return (0); + if (!pusb_conf_device_get_property(opts, doc, "serial", opts->device.serial, + sizeof(opts->device.serial))) + return (0); + return (1); +} + +int pusb_conf_init(t_pusb_options *opts) +{ + memset(opts, 0x00, sizeof(*opts)); + if (gethostname(opts->hostname, sizeof(opts->hostname)) == -1) + { + log_error("gethostname: %s\n", strerror(errno)); + return (0); + } + opts->enable = 1; + opts->try_otp = 1; + opts->enforce_otp = 0; + opts->debug = 0; + return (1); +} + +int pusb_conf_parse(const char *file, t_pusb_options *opts, + const char *user, const char *service) +{ + xmlDoc *doc = NULL; + int retval; + char device_xpath[sizeof(CONF_USER_XPATH) + CONF_USER_MAXLEN + \ + sizeof("device")]; + + if (strlen(user) > CONF_USER_MAXLEN) + { + log_error("Username \"%s\" is too long (max: %d)\n", user, + CONF_USER_MAXLEN); + return (0); + } + if (!(doc = xmlReadFile(file, NULL, 0))) + { + log_error("Unable to parse \"%s\"\n", file); + return (0); + } + snprintf(device_xpath, sizeof(device_xpath), CONF_USER_XPATH, user, + "device"); + retval = pusb_xpath_get_string(doc, + device_xpath, + opts->device.name, + sizeof(opts->device.name)); + if (!retval || !pusb_conf_parse_device(opts, doc)) + { + log_error("No device found for user \"%s\"\n", user); + xmlFreeDoc(doc); + xmlCleanupParser(); + return (0); + } + if (!pusb_conf_parse_options(opts, doc, user, service)) + { + xmlFreeDoc(doc); + xmlCleanupParser(); + return (0); + } + xmlFreeDoc(doc); + xmlCleanupParser(); + return (1); +} diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 0000000..3bfc254 --- /dev/null +++ b/src/conf.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 + */ + +#ifndef PUSB_CONF_H_ +# define PUSB_CONF_H_ +# define CONF_DEVICE_XPATH "//configuration/devices/device[@id='%s']/%s" +# define CONF_USER_XPATH "//configuration/users/user[@id='%s']/%s" +# define CONF_SERVICE_XPATH "//configuration/services/service[@id='%s']/%s" +# define CONF_USER_MAXLEN 32 + +typedef struct pusb_device +{ + char name[32]; + char vendor[32]; + char model[32]; + char serial[64]; +} t_pusb_device; + +typedef struct pusb_options +{ + int enable; + int try_otp; + int enforce_otp; + int debug; + char hostname[32]; + t_pusb_device device; +} t_pusb_options; + +struct s_opt_list +{ + char *name; + char *value; +}; + +int pusb_conf_init(t_pusb_options *opts); +int pusb_conf_parse(const char *file, t_pusb_options *opts, + const char *user, const char *service); + +#endif /* !PUSB_CONF_H_ */ diff --git a/src/conf.xml b/src/conf.xml new file mode 100644 index 0000000..4fc9e92 --- /dev/null +++ b/src/conf.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + SanDisk Corp. + Cruzer Titanium + SNDKB882652FC4A03701 + + + + + + foobar + + + + foobar + + + + + + + + + + + + + + + + diff --git a/src/hal.c b/src/hal.c new file mode 100644 index 0000000..f8d8606 --- /dev/null +++ b/src/hal.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 +#include +#include +#include "conf.h" +#include "log.h" + +static DBusConnection *pusb_hal_dbus_connect(void) +{ + DBusConnection *dbus = NULL; + DBusError error; + + dbus_error_init(&error); + if (!(dbus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) + { + log_error("Cannot connect to system bus: %s\n", + error.message); + dbus_error_free(&error); + return (NULL); + } + return (dbus); +} + +static void pusb_hal_dbus_disconnect(DBusConnection *dbus) +{ + dbus_connection_close(dbus); + dbus_connection_unref(dbus); + dbus_shutdown(); +} + +static LibHalContext *pusb_hal_init(DBusConnection *dbus) +{ + DBusError error; + LibHalContext *ctx = NULL; + + dbus_error_init(&error); + if (!(ctx = libhal_ctx_new())) + { + log_error("Failed to create a HAL context\n"); + return (NULL); + } + if (!libhal_ctx_set_dbus_connection(ctx, dbus)) + { + log_error("Failed to attach dbus connection to hal\n"); + libhal_ctx_free(ctx); + return (NULL); + } + if (!libhal_ctx_init(ctx, &error)) + { + log_error("libhal_ctx_init: %s\n", error.name, error.message); + libhal_ctx_free(ctx); + return (NULL); + } + return (ctx); +} + +static int pusb_hal_verify_model(LibHalContext *ctx, + t_pusb_options *opts, + const char *udi) +{ + DBusError error; + char *data; + int i; + struct s_opt_list check_list[] = { + { "usb_device.vendor", opts->device.vendor }, + { "info.product", opts->device.model }, + { NULL, NULL } + }; + + log_debug("Verifying model...\n"); + dbus_error_init(&error); + for (i = 0; check_list[i].name; ++i) + { + data = libhal_device_get_property_string(ctx, udi, + check_list[i].name, + &error); + if (!data) + { + log_error("Cannot retrieve device %s: %s\n", + check_list[i].name, + error.message); + dbus_error_free(&error); + return (0); + } + if (strcmp(data, check_list[i].value) != 0) + { + log_error("[KO]\t%s -> %s\n", check_list[i].name, data); + libhal_free_string(data); + return (0); + } + log_debug("[OK]\t%s -> %s \n", check_list[i].name, data); + libhal_free_string(data); + } + return (1); +} + +static int pusb_hal_find_device(LibHalContext *ctx, + t_pusb_options *opts) +{ + DBusError error; + char **devices; + int n_devices; + int retval = 0; + + dbus_error_init(&error); + if (!(devices = libhal_manager_find_device_string_match(ctx, + "usb_device.serial", + opts->device.serial, + &n_devices, + &error))) + { + log_error("Unable to find device \"%s\": %s\n", opts->device.name, + error.message); + dbus_error_free(&error); + return (0); + } + if (n_devices > 0) + { + log_debug("Device \"%s\" connected (S/N: %s)\n", opts->device.name, + opts->device.serial); + retval = pusb_hal_verify_model(ctx, opts, devices[0]); + } + else + log_error("Device \"%s\" not connected\n", opts->device.name); + libhal_free_string_array(devices); + return (retval); +} + +int pusb_hal_device_check(t_pusb_options *opts) +{ + DBusConnection *dbus; + LibHalContext *ctx; + int retval; + + if (!(dbus = pusb_hal_dbus_connect())) + return (0); + if (!(ctx = pusb_hal_init(dbus))) + return (0); + retval = pusb_hal_find_device(ctx, opts); + pusb_hal_dbus_disconnect(dbus); + libhal_ctx_free(ctx); + return (retval); +} diff --git a/src/hal.h b/src/hal.h new file mode 100644 index 0000000..3b14aec --- /dev/null +++ b/src/hal.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 + */ + +#ifndef HAL_H_ +# define HAL_H_ + +int pusb_hal_device_check(t_pusb_options *opts); + +#endif /* !HAL_H_ */ diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..a95a969 --- /dev/null +++ b/src/log.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 +#include +#include "log.h" + +void log_debug(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void log_error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void log_verbose(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..272f6ce --- /dev/null +++ b/src/log.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 + */ + +#ifndef LOG_H_ +# define LOG_H_ + +void log_debug(const char *fmt, ...); +void log_error(const char *fmt, ...); +void log_verbose(const char *fmt, ...); + +#endif /* !LOG_H_ */ diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..281cc5a --- /dev/null +++ b/src/test.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 +#include "conf.h" +#include "hal.h" +#include "log.h" + +static void pusb_dump_conf(t_pusb_options *opts) +{ + printf("\nConfiguration dump:\n"); + printf("enable:\t\t%d\n", opts->enable); + printf("try_otp:\t%d\n", opts->try_otp); + printf("enforce_otp:\t%d\n", opts->enforce_otp); + printf("debug:\t\t%d\n", opts->debug); + printf("hostname:\t%s\n", opts->hostname); +} + +int main(int argc, char **argv) +{ + t_pusb_options opts; + + if (argc < 3) + { + printf("Usage: %s \n", argv[0]); + return (1); + } + pusb_conf_init(&opts); + if (!pusb_conf_parse("conf.xml", &opts, argv[1], argv[2])) + return (0); + pusb_dump_conf(&opts); + if (!opts.enable) + { + printf("not enabled, exiting\n"); + return (0); + } + printf("\n"); + printf ("Access %s.\n", pusb_hal_device_check(&opts) ? "granted" : "denied"); + return (0); +} diff --git a/src/xpath.c b/src/xpath.c new file mode 100644 index 0000000..d5d5746 --- /dev/null +++ b/src/xpath.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 +#include +#include "xpath.h" +#include "log.h" + +static xmlXPathObject *pusb_xpath_match(xmlDocPtr doc, const char *path) +{ + xmlXPathContext *context = NULL; + xmlXPathObject *result = NULL; + + context = xmlXPathNewContext(doc); + if (context == NULL) + { + log_error("Unable to create XML context\n"); + return (NULL); + } + result = xmlXPathEvalExpression((xmlChar *)path, context); + xmlXPathFreeContext(context); + if (result == NULL) + { + log_error("Error in xmlXPathEvalExpression\n"); + return (NULL); + } + if (xmlXPathNodeSetIsEmpty(result->nodesetval)) + { + xmlXPathFreeObject(result); + return (NULL); + } + return (result); +} + +int pusb_xpath_get_string(xmlDocPtr doc, const char *path, + char *value, size_t size) +{ + xmlXPathObject *result = NULL; + xmlNode *node = NULL; + xmlChar *result_string = NULL; + + if (!(result = pusb_xpath_match(doc, path))) + return (0); + + if (result->nodesetval->nodeNr > 1) + { + xmlXPathFreeObject(result); + log_debug("Syntax error: %s: more than one record found\n", path); + return (0); + } + + node = result->nodesetval->nodeTab[0]->xmlChildrenNode; + result_string = xmlNodeListGetString(doc, node, 1); + if (strlen((const char *)result_string) + 1 > size) + { + xmlFree(result_string); + xmlXPathFreeObject(result); + log_debug("Result for %s (%s) is too long (max: %d)\n", + path, (const char *)result_string, size); + return (0); + } + memset(value, '\0', size); + strncpy(value, (const char *)result_string, size); + xmlFree(result_string); + xmlXPathFreeObject(result); + return (1); +} + +int pusb_xpath_get_string_from(xmlDocPtr doc, + const char *base, + const char *path, + char *value, size_t size) +{ + char *xpath = NULL; + size_t xpath_size; + int retval; + + xpath_size = strlen(base) + strlen(path) + 1; + if (!(xpath = malloc(xpath_size))) + { + log_error("malloc error !\n"); + return (0); + } + memset(xpath, 0x00, xpath_size); + snprintf(xpath, xpath_size, "%s%s", base, path); + retval = pusb_xpath_get_string(doc, xpath, value, size); + if (retval) + log_debug("%s%s -> %s\n", base, path, value); + free(xpath); + return (retval); +} + +int pusb_xpath_get_bool(xmlDocPtr doc, const char *path, int *value) +{ + char ret[6]; /* strlen("false") + 1 */ + + if (!pusb_xpath_get_string(doc, path, ret, sizeof(ret))) + return (0); + + if (!strcmp(ret, "true")) + { + *value = 1; + return (1); + } + + if (!strcmp(ret, "false")) + { + *value = 0; + return (1); + } + + log_debug("Expecting a boolean, got %s\n", ret); + return (0); +} + +int pusb_xpath_get_bool_from(xmlDocPtr doc, + const char *base, + const char *path, + int *value) +{ + char *xpath = NULL; + size_t xpath_size; + int retval; + + xpath_size = strlen(base) + strlen(path) + 1; + if (!(xpath = malloc(xpath_size))) + { + log_error("malloc error!\n"); + return (0); + } + memset(xpath, 0x00, xpath_size); + snprintf(xpath, xpath_size, "%s%s", base, path); + retval = pusb_xpath_get_bool(doc, xpath, value); + free(xpath); + if (retval) + log_debug("%s%s -> %s\n", base, path, *value ? "true" : "false"); + return (retval); +} diff --git a/src/xpath.h b/src/xpath.h new file mode 100644 index 0000000..3c316f2 --- /dev/null +++ b/src/xpath.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2003-2006 Andrea Luzzardi + * + * This file is part of the pam_usb project. pam_usb is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * pam_usb 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 + */ + +#ifndef PUSB_XPATH_H_ +# define PUSB_XPATH_H_ +# include + +int pusb_xpath_get_string(xmlDocPtr doc, const char *path, char *value, + size_t size); +int pusb_xpath_get_bool(xmlDocPtr doc, const char *path, int *value); +int pusb_xpath_get_string_from(xmlDocPtr doc, const char *base, + const char *path, char *value, size_t size); +int pusb_xpath_get_bool_from(xmlDocPtr doc, const char *base, const char *path, + int *value); +#endif /* !PUSB_XPATH_H_ */