From f8b3ccaa4edd4836885dc3e22062b69e80883f36 Mon Sep 17 00:00:00 2001 From: Loïc Collignon <loic.collignon@iot.bzh> Date: Thu, 26 Oct 2017 16:27:49 +0200 Subject: add nfc pam module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Icc42361f64948e2c2ab082fa973793f19737df2d Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh> --- pam_agl/CMakeLists.txt | 27 +++--- pam_agl/pam_agl.c | 223 ------------------------------------------------- pam_agl/pam_agl_nfc.c | 152 +++++++++++++++++++++++++++++++++ pam_agl/pam_agl_usb.c | 186 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 355 insertions(+), 233 deletions(-) delete mode 100644 pam_agl/pam_agl.c create mode 100644 pam_agl/pam_agl_nfc.c create mode 100644 pam_agl/pam_agl_usb.c diff --git a/pam_agl/CMakeLists.txt b/pam_agl/CMakeLists.txt index 17c85be..7cd39cc 100644 --- a/pam_agl/CMakeLists.txt +++ b/pam_agl/CMakeLists.txt @@ -25,22 +25,29 @@ include(FindPkgConfig) set(PAM_INCLUDE_DIR "/usr/include/") set(PAM_LIBRARY "/lib64/libpam.so.0") include_directories(${PAM_INCLUDE_DIR}) +if (NOT DEFINED CMAKE_INSTALL_LIBDIR) + get_filename_component(CMAKE_INSTALL_LIBDIR ${PAM_LIBRARY} DIRECTORY) +endif() # Find json-c pkg_check_modules(${JSON_C} REQUIRED json-c) include_directories(${${JSON_C}_INCLUDE_DIRS}) add_compile_options(${${JSON_C}_CFLAGS}) -# Add the target -add_library(pam_agl SHARED pam_agl.c) -target_link_libraries(pam_agl ${PAM_LIBRARY} ${${JSON_C}_LIBRARIES}) -#list (APPEND link_libraries ${${JSON_C}_LDFLAGS}) -set_property(TARGET pam_agl PROPERTY POSITION_INDEPENDENT_CODE ON) -set_property(TARGET pam_agl PROPERTY PREFIX "") +# Add the pam_agl_usb target +add_library(pam_agl_usb SHARED pam_agl_usb.c) +target_link_libraries(pam_agl_usb ${PAM_LIBRARY} ${${JSON_C}_LIBRARIES}) +set_property(TARGET pam_agl_usb PROPERTY POSITION_INDEPENDENT_CODE ON) +set_property(TARGET pam_agl_usb PROPERTY PREFIX "") -if (NOT DEFINED CMAKE_INSTALL_LIBDIR) - get_filename_component(CMAKE_INSTALL_LIBDIR ${PAM_LIBRARY} DIRECTORY) -endif() +install(TARGETS pam_agl_usb + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/security/") + +# Add the pam_agl_nfc target +add_library(pam_agl_nfc SHARED pam_agl_nfc.c) +target_link_libraries(pam_agl_nfc ${PAM_LIBRARY} ${${JSON_C}_LIBRARIES}) +set_property(TARGET pam_agl_nfc PROPERTY POSITION_INDEPENDENT_CODE ON) +set_property(TARGET pam_agl_nfc PROPERTY PREFIX "") -install(TARGETS pam_agl +install(TARGETS pam_agl_nfc LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/security/") diff --git a/pam_agl/pam_agl.c b/pam_agl/pam_agl.c deleted file mode 100644 index c85979d..0000000 --- a/pam_agl/pam_agl.c +++ /dev/null @@ -1,223 +0,0 @@ -#include <fcntl.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <uuid/uuid.h> -#include <json-c/json.h> - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT -#define PAM_SM_SESSION -#define PAM_SM_PASSWORD -#include <security/pam_modules.h> -#include <security/pam_appl.h> - -#define DATABASE_FILE "/etc/agl/keys.json" - -#define BLOCK_SIZE 4096 -typedef struct header_ -{ - char mn[4]; - size_t size; -} header; - -int is_valid_mn(const char* v) -{ - return v && v[0] == 'I' && v[1] == 'D' && v[2] == 'K' && v[3] == 'Y'; -} - -char* get_file_content(const char* path) -{ - char* buffer; - long length; - FILE* f; - - buffer = NULL; - length = 0; - - f = fopen(path, "rb"); - if (f) - { - fseek(f, 0, SEEK_END); - length = ftell(f); - fseek(f, 0, SEEK_SET); - buffer = malloc(length + 1); - if (buffer) - { - if (fread (buffer, 1, length, f) != length) - { - free(buffer); - buffer = NULL; - } - else buffer[length] = 0; - } - fclose (f); - } - - return buffer; -} - -int read_device(const char* device, char** idkey) -{ - int fd; - ssize_t sz; - header h; - - printf("[PAM DEBUG] check_device %s...\n", device); - fd = open(device, O_RDONLY); - if (fd == -1) - { - printf("[PAM DEBUG] Failed to open the device %s!\n", device); - return PAM_SERVICE_ERR; - } - - sz = read(fd, &h, sizeof(header)); - if (sz != sizeof(header) || !is_valid_mn(h.mn) || h.size < 1) { close(fd); printf("[PAM DEBUG]: bad header!\n"); return PAM_SERVICE_ERR; } - printf("[PAM DEBUG]: data size=%lu\n", h.size); - - *idkey = (char*)malloc(h.size + 1); - if (!*idkey) { close(fd); printf("[PAM DEBUG] Bad alloc!\n"); return PAM_SERVICE_ERR; } - - memset(*idkey, 0, h.size + 1); - sz = read(fd, *idkey, h.size); - close(fd); - if (sz != h.size) { free(idkey); printf("[PAM DEBUG] Bad data read!\n"); return PAM_SERVICE_ERR; } - return PAM_SUCCESS; -} - -int authenticate(pam_handle_t* pamh, const char* uuid) -{ - char* file_content; - struct json_object* database; - struct json_object* key; - - file_content = get_file_content(DATABASE_FILE); - if (!file_content) - { - printf("[PAM DEBUG] Failed to read database file (%s)\n", DATABASE_FILE); - return PAM_SERVICE_ERR; - } - - database = json_tokener_parse(file_content); - if (!database) - { - printf("[PAM DEBUG] Failed to parse the database\n"); - return PAM_SERVICE_ERR; - } - - if (json_object_object_get_ex(database, uuid, &key)) - { - printf("[PAM] Key found!\n"); - printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uuid); - pam_set_item(pamh, PAM_USER, uuid); - - const char* pam_authtok; - if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok) - pam_set_item(pamh, PAM_AUTHTOK, uuid); - - json_object_put(database); - free(file_content); - return PAM_SUCCESS; - } - - printf("[PAM] Key not found!\n"); - free(file_content); - if (database) json_object_put(database); - return PAM_AUTH_ERR; -} - -int check_device(pam_handle_t* pamh, const char* device) -{ - char* idkey; - int ret; - - ret = read_device(device, &idkey); - if (ret != PAM_SUCCESS) return ret; - - printf("[PAM DEBUG] Data read:\n%s\n", idkey); - - json_object* idkey_json = json_tokener_parse(idkey); - if (!idkey_json) - { - free(idkey); - printf("[PAM DEBUG] Failed to parse json data!\n"); - return PAM_SERVICE_ERR; - } - - json_object* uuid_json; - if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json)) - { - free(idkey); - printf("[PAM DEBUG] The json does not contains a valid uuid\n"); - return PAM_SERVICE_ERR; - } - - const char* uuid = json_object_get_string(uuid_json); - printf("[PAM DEBUG] uuid: %s\n", uuid); - - ret = authenticate(pamh, uuid); - free(idkey); - json_object_put(idkey_json); - return ret; -} - -void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device) -{ - printf("[PAM DEBUG] ---------- %s ----------\n", fname); - printf("[PAM DEBUG] flags: %d\n", flags); - for(int i = 0; i < argc; ++i) - { - printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]); - } - printf("[PAM DEBUG] device: %s\n", device); - printf("[PAM DEBUG] ----------------------------------------\n"); -} - -/*! - @brief The pam_sm_authenticate function is the service module's implementation - of the pam_authenticate(3) interface. - This function performs the task of authenticating the user. - - @param[in] pamh Unknown. - @param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK. - @return PAM_SUCCESS if ok. -*/ -PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv) -{ - const char* device = pam_getenv(pamh, "DEVICE"); - log_pam("pam_sm_authenticate", flags, argc, argv, device); - return check_device(pamh, device); -} - -PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv) -{ - log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE")); - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv) -{ - log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE")); - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv) -{ - log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE")); - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv) -{ - log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE")); - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv) -{ - log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE")); - return PAM_SUCCESS; -} diff --git a/pam_agl/pam_agl_nfc.c b/pam_agl/pam_agl_nfc.c new file mode 100644 index 0000000..b25ba5c --- /dev/null +++ b/pam_agl/pam_agl_nfc.c @@ -0,0 +1,152 @@ +#include <fcntl.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <uuid/uuid.h> +#include <json-c/json.h> + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD +#include <security/pam_modules.h> +#include <security/pam_appl.h> + +#include <security/pam_client.h> +#include <security/pam_ext.h> +#include <security/pam_filter.h> +#include <security/pam_misc.h> +#include <security/pam_modutil.h> + +#define DATABASE_FILE "/etc/agl/keys.json" + +int authenticate(pam_handle_t* pamh, const char* uid) +{ + struct json_object* database; + struct json_object* nfc; + struct json_object* key; + + database = json_object_from_file(DATABASE_FILE); + if (!database) + { + printf("[PAM DEBUG] Failed to parse the database\n"); + return PAM_SERVICE_ERR; + } + + if (json_object_object_get_ex(database, "nfc", &nfc)) + { + if (json_object_object_get_ex(nfc, uid, &key)) + { + printf("[PAM] Key found!\n"); + printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uid); + pam_set_item(pamh, PAM_USER, uid); + + const char* pam_authtok; + if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok) + pam_set_item(pamh, PAM_AUTHTOK, uid); + + json_object_put(database); + return PAM_SUCCESS; + } + } + + printf("[PAM] Key not found!\n"); + if (database) json_object_put(database); + return PAM_AUTH_ERR; +} + +int check_device(pam_handle_t* pamh, const char* device) +{ + char* idkey; + int ret; + + ret = read_device(device, &idkey); + if (ret != PAM_SUCCESS) return ret; + + printf("[PAM DEBUG] Data read:\n%s\n", idkey); + + json_object* idkey_json = json_tokener_parse(idkey); + if (!idkey_json) + { + free(idkey); + printf("[PAM DEBUG] Failed to parse json data!\n"); + return PAM_SERVICE_ERR; + } + + json_object* uuid_json; + if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json)) + { + free(idkey); + printf("[PAM DEBUG] The json does not contains a valid uuid\n"); + return PAM_SERVICE_ERR; + } + + const char* uuid = json_object_get_string(uuid_json); + printf("[PAM DEBUG] uuid: %s\n", uuid); + + ret = authenticate(pamh, uuid); + free(idkey); + json_object_put(idkey_json); + return ret; +} + +void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device) +{ + printf("[PAM DEBUG] ---------- %s ----------\n", fname); + printf("[PAM DEBUG] flags: %d\n", flags); + for(int i = 0; i < argc; ++i) + { + printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]); + } + printf("[PAM DEBUG] device: %s\n", device); + printf("[PAM DEBUG] ----------------------------------------\n"); +} + +/*! + @brief The pam_sm_authenticate function is the service module's implementation + of the pam_authenticate(3) interface. + This function performs the task of authenticating the user. + + @param[in] pamh Unknown. + @param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK. + @return PAM_SUCCESS if ok. +*/ +PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + const char* uid = pam_getenv(pamh, "UID"); + log_pam("pam_sm_authenticate", flags, argc, argv, uid); + return authenticate(pamh, uid); +} + +PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} diff --git a/pam_agl/pam_agl_usb.c b/pam_agl/pam_agl_usb.c new file mode 100644 index 0000000..7afe73d --- /dev/null +++ b/pam_agl/pam_agl_usb.c @@ -0,0 +1,186 @@ +#include <fcntl.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <uuid/uuid.h> +#include <json-c/json.h> + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD +#include <security/pam_modules.h> +#include <security/pam_appl.h> + +#define DATABASE_FILE "/etc/agl/keys.json" + +#define BLOCK_SIZE 4096 +typedef struct header_ +{ + char mn[4]; + size_t size; +} header; + +int is_valid_mn(const char* v) +{ + return v && v[0] == 'I' && v[1] == 'D' && v[2] == 'K' && v[3] == 'Y'; +} + +int read_device(const char* device, char** idkey) +{ + int fd; + ssize_t sz; + header h; + + printf("[PAM DEBUG] check_device %s...\n", device); + fd = open(device, O_RDONLY); + if (fd == -1) + { + printf("[PAM DEBUG] Failed to open the device %s!\n", device); + return PAM_SERVICE_ERR; + } + + sz = read(fd, &h, sizeof(header)); + if (sz != sizeof(header) || !is_valid_mn(h.mn) || h.size < 1) { close(fd); printf("[PAM DEBUG]: bad header!\n"); return PAM_SERVICE_ERR; } + printf("[PAM DEBUG]: data size=%lu\n", h.size); + + *idkey = (char*)malloc(h.size + 1); + if (!*idkey) { close(fd); printf("[PAM DEBUG] Bad alloc!\n"); return PAM_SERVICE_ERR; } + + memset(*idkey, 0, h.size + 1); + sz = read(fd, *idkey, h.size); + close(fd); + if (sz != h.size) { free(idkey); printf("[PAM DEBUG] Bad data read!\n"); return PAM_SERVICE_ERR; } + return PAM_SUCCESS; +} + +int authenticate(pam_handle_t* pamh, const char* uuid) +{ + struct json_object* database; + struct json_object* usb; + struct json_object* key; + + database = json_object_from_file(DATABASE_FILE); + if (!database) + { + printf("[PAM DEBUG] Failed to parse the database\n"); + return PAM_SERVICE_ERR; + } + + if (json_object_object_get_ex(database, "usb", &usb)) + { + if (json_object_object_get_ex(usb, uuid, &key)) + { + printf("[PAM] Key found!\n"); + printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uuid); + pam_set_item(pamh, PAM_USER, uuid); + + const char* pam_authtok; + if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok) + pam_set_item(pamh, PAM_AUTHTOK, uuid); + + json_object_put(database); + return PAM_SUCCESS; + } + } + + printf("[PAM] Key not found!\n"); + if (database) json_object_put(database); + return PAM_AUTH_ERR; +} + +int check_device(pam_handle_t* pamh, const char* device) +{ + char* idkey; + int ret; + + ret = read_device(device, &idkey); + if (ret != PAM_SUCCESS) return ret; + + printf("[PAM DEBUG] Data read:\n%s\n", idkey); + + json_object* idkey_json = json_tokener_parse(idkey); + if (!idkey_json) + { + free(idkey); + printf("[PAM DEBUG] Failed to parse json data!\n"); + return PAM_SERVICE_ERR; + } + + json_object* uuid_json; + if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json)) + { + free(idkey); + printf("[PAM DEBUG] The json does not contains a valid uuid\n"); + return PAM_SERVICE_ERR; + } + + const char* uuid = json_object_get_string(uuid_json); + printf("[PAM DEBUG] uuid: %s\n", uuid); + + ret = authenticate(pamh, uuid); + free(idkey); + json_object_put(idkey_json); + return ret; +} + +void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device) +{ + printf("[PAM DEBUG] ---------- %s ----------\n", fname); + printf("[PAM DEBUG] flags: %d\n", flags); + for(int i = 0; i < argc; ++i) + { + printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]); + } + printf("[PAM DEBUG] device: %s\n", device); + printf("[PAM DEBUG] ----------------------------------------\n"); +} + +/*! + @brief The pam_sm_authenticate function is the service module's implementation + of the pam_authenticate(3) interface. + This function performs the task of authenticating the user. + + @param[in] pamh Unknown. + @param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK. + @return PAM_SUCCESS if ok. +*/ +PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + const char* device = pam_getenv(pamh, "DEVICE"); + log_pam("pam_sm_authenticate", flags, argc, argv, device); + return check_device(pamh, device); +} + +PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv) +{ + log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE")); + return PAM_SUCCESS; +} -- cgit