4 #include <json-c/json.h>
5 #include <security/pam_appl.h>
6 #include <security/pam_misc.h>
8 #define AFB_BINDING_VERSION 2
9 #include <afb/afb-binding.h>
11 static struct pam_conv conv = { misc_conv, NULL };
13 static char* current_device = NULL;
14 static char* current_user = NULL;
16 afb_event evt_login, evt_logout, evt_failed;
18 /// @brief API's verb 'login'. Try to login a user using a device
19 /// @param[in] req The request object. Should contains a json with a "device" key.
20 static void verb_login(struct afb_req req)
22 struct json_object* args = NULL;
23 struct json_object* device_object = NULL;
29 AFB_ERROR("[login] the current user must be logged out first!");
30 afb_req_fail(req, "current user must be logged out first!", NULL);
31 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"A user is already logged in!\"}"));
35 args = afb_req_json(req);
36 if (args == NULL || !json_object_object_get_ex(args, "device", &device_object))
38 AFB_ERROR("[login] device must be provided!");
39 afb_req_fail(req, "device must be provided!", NULL);
40 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"device must be provided!\"}"));
44 const char* device = json_object_get_string(device_object);
46 if ((r = pam_start("agl", NULL, &conv, &pamh)) != PAM_SUCCESS)
48 AFB_ERROR("PAM start failed!");
49 afb_req_fail(req, "PAM start failed!", NULL);
50 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"PAM start failed!\"}"));
54 char pam_variable[4096] = "DEVICE=";
55 strcat(pam_variable, device);
57 if ((r = pam_putenv(pamh, pam_variable)) != PAM_SUCCESS)
59 AFB_ERROR("PAM putenv failed!");
60 afb_req_fail(req, "PAM putenv failed!", NULL);
62 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"PAM putenv failed!\"}"));
66 if ((r = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
68 AFB_ERROR("PAM authenticate failed!");
69 afb_req_fail(req, "PAM authenticate failed!", NULL);
71 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"PAM authenticate failed!\"}"));
75 if ((r = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS)
77 AFB_ERROR("PAM acct_mgmt failed!");
78 afb_req_fail(req, "PAM acct_mgmt failed!", NULL);
80 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"PAM acct_mgmt failed!\"}"));
85 pam_get_item(pamh, PAM_USER, (const void**)&pam_user);
88 AFB_ERROR("[login] No user provided by the PAM module!");
89 afb_req_fail(req, "No user provided by the PAM module!", NULL);
90 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"No user provided by the PAM module!\"}"));
94 current_device = strdup(device);
95 current_user = strdup(pam_user);
97 if ((r = pam_end(pamh, r)) != PAM_SUCCESS)
99 AFB_ERROR("PAM end failed!");
100 afb_req_fail(req, "PAM end failed!", NULL);
101 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"PAM end failed!\"}"));
105 AFB_INFO("[login] device: %s, user: %s", current_device, current_user);
106 json_object* result = json_object_new_object();
107 json_object_object_add(result, "device", json_object_new_string(current_device));
108 json_object_object_add(result, "user", json_object_new_string(current_user));
109 afb_req_success(req, NULL, current_device);
110 afb_event_broadcast(evt_login, result);
113 /// @brief API's verb 'lgout'. Try to logout a user using a device
114 /// @param[in] req The request object. Should contains a json with a "device" key.
115 static void verb_logout(struct afb_req req)
117 struct json_object* args = NULL;
118 struct json_object* device_object = NULL;
120 args = afb_req_json(req);
121 if (args == NULL || !json_object_object_get_ex(args, "device", &device_object))
123 AFB_INFO("[logout] device must be provided!");
124 afb_req_fail(req, "device must be provided!", NULL);
125 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"Device must be provided!\"}"));
129 const char* device = json_object_get_string(device_object);
130 if (current_device && !strcmp(device, current_device))
132 free(current_device);
133 current_device = NULL;
138 AFB_INFO("[logout] device: %s", device);
139 afb_req_success(req, NULL, device);
140 afb_event_broadcast(evt_logout, NULL);
145 AFB_INFO("No user was linked to this device!");
146 afb_req_fail(req, "No user was linked to this device!", NULL);
147 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"No user was linked to this device!\"}"));
152 AFB_INFO("The unplugged device wasn't the user key!");
153 afb_req_fail(req, "The unplugged device wasn't the user key!", NULL);
154 afb_event_broadcast(evt_failed, json_tokener_parse("{\"message\":\"The unplugged device wasn't the user key!\"}"));
157 static void verb_getuser(struct afb_req req)
159 if (!current_device || !current_user)
161 afb_req_fail(req, "there is no logged user!", NULL);
165 json_object* result = json_object_new_object();
166 json_object_object_add(result, "user", json_object_new_string(current_user));
167 json_object_object_add(result, "device", json_object_new_string(current_device));
169 afb_req_success(req, result, NULL);
175 current_device = NULL;
176 evt_login = afb_daemon_make_event("login");
177 evt_logout = afb_daemon_make_event("logout");
178 evt_failed = afb_daemon_make_event("failed");
180 if (afb_event_is_valid(evt_login) && afb_event_is_valid(evt_logout))
183 AFB_ERROR("Can't create events");
187 static const afb_verb_v2 _ll_auth_binding_verbs[]= {
190 .callback = verb_login,
193 .session = AFB_SESSION_NONE_V2
197 .callback = verb_logout,
200 .session = AFB_SESSION_NONE_V2
204 .callback = verb_getuser,
207 .session = AFB_SESSION_NONE_V2
212 const struct afb_binding_v2 afbBindingV2 = {
214 .specification = NULL,
215 .verbs = _ll_auth_binding_verbs,
216 .preinit = ll_auth_init,