summaryrefslogtreecommitdiffstats
path: root/ll-auth-binding/src/ll-auth-binding.c
diff options
context:
space:
mode:
Diffstat (limited to 'll-auth-binding/src/ll-auth-binding.c')
-rw-r--r--ll-auth-binding/src/ll-auth-binding.c208
1 files changed, 208 insertions, 0 deletions
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
+};