aboutsummaryrefslogtreecommitdiffstats
path: root/ll-auth-binding/src
diff options
context:
space:
mode:
authorLoïc Collignon <loic.collignon@iot.bzh>2017-07-11 06:36:33 +0200
committerLoïc Collignon <loic.collignon@iot.bzh>2017-07-11 06:36:33 +0200
commit0455a7401f9f0f9bfad82c5ddf04f7dd70b0b852 (patch)
tree819bc150cb62c8eb344656086bbb52892f5288b8 /ll-auth-binding/src
parent66b90d26cfd555b2aa5fef67d31e539a70256719 (diff)
first somewhat working version.
Change-Id: I3101dc6b8add87eccac3bbf177b1320137f72463 Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh>
Diffstat (limited to 'll-auth-binding/src')
-rw-r--r--ll-auth-binding/src/CMakeLists.txt21
-rw-r--r--ll-auth-binding/src/export.map1
-rw-r--r--ll-auth-binding/src/ll-auth-binding.c208
3 files changed, 230 insertions, 0 deletions
diff --git a/ll-auth-binding/src/CMakeLists.txt b/ll-auth-binding/src/CMakeLists.txt
new file mode 100644
index 0000000..2b682bd
--- /dev/null
+++ b/ll-auth-binding/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+PROJECT_TARGET_ADD(ll-auth-binding)
+
+# Require PAM but there is no find_package
+set(PAM_INCLUDE_DIR "/usr/include/")
+set(PAM_LIBRARY "/lib64/libpam.so.0")
+set(PAM_MISC_LIBRARY "/lib64/libpam_misc.so.0")
+include_directories(${PAM_INCLUDE_DIR})
+
+add_library(ll-auth-binding MODULE ll-auth-binding.c)
+
+set_target_properties(ll-auth-binding PROPERTIES
+ PREFIX "afb-"
+ LABELS "BINDING"
+ LINK_FLAGS ${BINDINGS_LINK_FLAG}
+ OUTPUT_NAME ${TARGET_NAME})
+
+target_link_libraries(ll-auth-binding ${link_libraries} ${PAM_LIBRARY} ${PAM_MISC_LIBRARY})
+
+install(
+ TARGETS ll-auth-binding
+ LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR})
diff --git a/ll-auth-binding/src/export.map b/ll-auth-binding/src/export.map
new file mode 100644
index 0000000..ee2f413
--- /dev/null
+++ b/ll-auth-binding/src/export.map
@@ -0,0 +1 @@
+{ global: afbBindingV*; local: *; };
diff --git a/ll-auth-binding/src/ll-auth-binding.c b/ll-auth-binding/src/ll-auth-binding.c
new file mode 100644
index 0000000..e85d63a
--- /dev/null
+++ b/ll-auth-binding/src/ll-auth-binding.c
@@ -0,0 +1,208 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <json-c/json.h>
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+static struct pam_conv conv = { misc_conv, NULL };
+
+static char* current_device = NULL;
+static char* current_user = NULL;
+
+afb_event evt_login, evt_logout;
+
+/// @brief API's verb 'login'. Try to login a user using a device
+/// @param[in] req The request object. Should contains a json with a "device" key.
+static void verb_login(struct afb_req req)
+{
+ struct json_object* args = NULL;
+ struct json_object* device_object = NULL;
+ pam_handle_t* pamh;
+ int r;
+
+ if (current_user)
+ {
+ AFB_ERROR("[login] the current user must be logged out first!");
+ afb_req_fail(req, "current user must be logged out first!", NULL);
+ return;
+ }
+
+ args = afb_req_json(req);
+ if (args == NULL || !json_object_object_get_ex(args, "device", &device_object))
+ {
+ AFB_ERROR("[login] device must be provided!");
+ afb_req_fail(req, "device must be provided!", NULL);
+ return;
+ }
+
+ const char* device = json_object_get_string(device_object);
+
+ if ((r = pam_start("agl", NULL, &conv, &pamh)) != PAM_SUCCESS)
+ {
+ AFB_ERROR("PAM start failed!");
+ afb_req_fail(req, "PAM start failed!", NULL);
+ return;
+ }
+
+ char pam_variable[4096] = "DEVICE=";
+ strcat(pam_variable, device);
+
+ if ((r = pam_putenv(pamh, pam_variable)) != PAM_SUCCESS)
+ {
+ AFB_ERROR("PAM putenv failed!");
+ afb_req_fail(req, "PAM putenv failed!", NULL);
+ pam_end(pamh, r);
+ return;
+ }
+
+ if ((r = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
+ {
+ AFB_ERROR("PAM authenticate failed!");
+ afb_req_fail(req, "PAM authenticate failed!", NULL);
+ pam_end(pamh, r);
+ return;
+ }
+
+ if ((r = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS)
+ {
+ AFB_ERROR("PAM acct_mgmt failed!");
+ afb_req_fail(req, "PAM acct_mgmt failed!", NULL);
+ pam_end(pamh, r);
+ return;
+ }
+
+ const char* pam_user;
+ pam_get_item(pamh, PAM_USER, (const void**)&pam_user);
+ if (!pam_user)
+ {
+ AFB_ERROR("[login] No user provided by the PAM module!");
+ afb_req_fail(req, "No user provided by the PAM module!", NULL);
+ return;
+ }
+
+ current_device = strdup(device);
+ current_user = strdup(pam_user);
+
+ if ((r = pam_end(pamh, r)) != PAM_SUCCESS)
+ {
+ AFB_ERROR("PAM end failed!");
+ afb_req_fail(req, "PAM end failed!", NULL);
+ return;
+ }
+
+ AFB_INFO("[login] device: %s, user: %s", current_device, current_user);
+ json_object* result = json_object_new_object();
+ json_object_object_add(result, "device", json_object_new_string(current_device));
+ json_object_object_add(result, "user", json_object_new_string(current_user));
+ afb_req_success(req, NULL, current_device);
+ afb_event_broadcast(evt_login, result);
+}
+
+/// @brief API's verb 'lgout'. Try to logout a user using a device
+/// @param[in] req The request object. Should contains a json with a "device" key.
+static void verb_logout(struct afb_req req)
+{
+ struct json_object* args = NULL;
+ struct json_object* device_object = NULL;
+
+ args = afb_req_json(req);
+ if (args == NULL || !json_object_object_get_ex(args, "device", &device_object))
+ {
+ AFB_INFO("[logout] device must be provided!");
+ afb_req_fail(req, "device must be provided!", NULL);
+ return;
+ }
+
+ const char* device = json_object_get_string(device_object);
+ if (current_device && !strcmp(device, current_device))
+ {
+ free(current_device);
+ current_device = NULL;
+ if (current_user)
+ {
+ free(current_user);
+ current_user = NULL;
+ AFB_INFO("[logout] device: %s", device);
+ afb_req_success(req, NULL, device);
+ afb_event_broadcast(evt_logout, NULL);
+ return;
+ }
+ else
+ {
+ AFB_INFO("No user was linked to this device!");
+ afb_req_fail(req, "No user was linked to this device!", NULL);
+ return;
+ }
+ }
+
+ AFB_INFO("The unplugged device wasn't the user key!");
+ afb_req_fail(req, "The unplugged device wasn't the user key!", NULL);
+}
+
+static void verb_getuser(struct afb_req req)
+{
+ if (!current_device || !current_user)
+ {
+ afb_req_fail(req, "there is no logged user!", NULL);
+ return;
+ }
+
+ json_object* result = json_object_new_object();
+ json_object_object_add(result, "user", json_object_new_string(current_user));
+ json_object_object_add(result, "device", json_object_new_string(current_device));
+
+ afb_req_success(req, result, NULL);
+}
+
+int ll_auth_init()
+{
+ current_user = NULL;
+ current_device = NULL;
+ evt_login = afb_daemon_make_event("login");
+ evt_logout = afb_daemon_make_event("logout");
+
+ if (afb_event_is_valid(evt_login) && afb_event_is_valid(evt_logout))
+ return 0;
+
+ AFB_ERROR("Can't create events");
+ return -1;
+}
+
+static const afb_verb_v2 _ll_auth_binding_verbs[]= {
+ {
+ .verb = "login",
+ .callback = verb_login,
+ .auth = NULL,
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "logout",
+ .callback = verb_logout,
+ .auth = NULL,
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "getuser",
+ .callback = verb_getuser,
+ .auth = NULL,
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ { .verb=NULL}
+};
+
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "ll-auth",
+ .specification = NULL,
+ .verbs = _ll_auth_binding_verbs,
+ .preinit = ll_auth_init,
+ .init = NULL,
+ .onevent = NULL,
+ .noconcurrency = 0
+};