summaryrefslogtreecommitdiffstats
path: root/src/aia-get.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/aia-get.c')
-rw-r--r--src/aia-get.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/src/aia-get.c b/src/aia-get.c
new file mode 100644
index 0000000..56c82b0
--- /dev/null
+++ b/src/aia-get.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+
+#include <json-c/json.h>
+#include <curl/curl.h>
+
+#include "curl-wrap.h"
+#include "oidc-agent.h"
+
+/*
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <json-c/json.h>
+
+#include <afb/afb-binding.h>
+#include <afb/afb-req-itf.h>
+#include <afb/afb-event-itf.h>
+#include <afb/afb-service-itf.h>
+
+
+#include "u2f-bluez.h"
+*/
+
+
+struct keyrequest {
+ struct keyrequest *next;
+ int dead;
+ time_t expiration;
+ const char *url;
+ const char *appli;
+ const char *idp;
+ void (*callback)(void *closure, int status, const void *buffer, size_t size);
+ void *closure;
+ json_object *token;
+ pthread_t tid;
+};
+
+static struct keyrequest *keyrequests = 0;
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int curl_initialized = 0;
+
+static void perform_query_callback(void *closure, int status, CURL *curl, const char *result, size_t size)
+{
+ struct keyrequest *kr = closure;
+ kr->callback(kr->closure, status, result, size);
+}
+
+static void perform_query(struct keyrequest *kr)
+{
+ CURL *curl;
+
+ curl = curl_wrap_prepare_get_url(kr->url);
+ if (!curl)
+ kr->callback(kr->closure, 0, "out of memory", 0);
+ else {
+ oidc_add_bearer(curl, kr->token);
+ curl_wrap_do(curl, perform_query_callback, kr);
+ }
+}
+
+static void token_success(void *closure, struct json_object *token)
+{
+ struct keyrequest *kr = closure;
+ kr->token = token;
+ perform_query(kr);
+}
+
+static void token_error(void *closure, const char *message, const char *indice)
+{
+ struct keyrequest *kr = closure;
+ kr->callback(kr->closure, 0, message, 0);
+}
+
+static void *kr_get_thread(void *closure)
+{
+ struct oidc_grant_cb cb;
+ struct keyrequest *kr = closure;
+
+ if (!kr->appli)
+ perform_query(kr);
+ else {
+ cb.closure = kr;
+ cb.success = token_success;
+ cb.error = token_error;
+ oidc_grant_owner_password(kr->appli, kr->idp, NULL, &cb);
+ }
+ kr->dead = 1;
+ return NULL;
+}
+
+static void kr_free(struct keyrequest *kr)
+{
+ json_object_put(kr->token);
+ free(kr);
+}
+
+static struct keyrequest *kr_alloc(
+ const char *url,
+ time_t expiration,
+ const char *appli,
+ const char *idp,
+ void (*callback)(void *closure, int status, const void *buffer, size_t size),
+ void *closure
+)
+{
+ struct keyrequest *result;
+ char *buf;
+ size_t surl, sappli, sidp;
+
+ surl = 1 + strlen(url);
+ sappli = appli ? 1 + strlen(appli) : 0;
+ sidp = idp ? 1 + strlen(idp) : 0;
+
+ result = calloc(1, surl + sappli + sidp + sizeof *result);
+ if (result) {
+ result->next = NULL;
+ result->dead = 0;
+ result->expiration = expiration;
+ result->callback = callback;
+ result->closure = closure;
+ result->token = NULL;
+ result->tid = 0;
+
+ buf = (char*)(&result[1]);
+ result->url = buf;
+ buf = mempcpy(buf, url, surl);
+ if (!appli)
+ result->appli = NULL;
+ else {
+ result->appli = buf;
+ buf = mempcpy(buf, appli, sappli);
+ }
+ if (!idp)
+ result->idp = NULL;
+ else {
+ result->idp = buf;
+ buf = mempcpy(buf, idp, sidp);
+ }
+ }
+ return result;
+}
+
+void aia_get(
+ const char *url,
+ int delay,
+ const char *appli,
+ const char *idp,
+ void (*callback)(void *closure, int status, const void *buffer, size_t size),
+ void *closure
+)
+{
+ int rc;
+ time_t now;
+ struct keyrequest **pkr, *kr, *found_kr;
+
+ /* initialize CURL component */
+ pthread_mutex_lock(&mutex);
+ if (!curl_initialized) {
+ curl_initialized = 1;
+ curl_global_init(CURL_GLOBAL_DEFAULT);
+ }
+
+ /* search for the same request and also cleanup deads */
+ now = time(NULL);
+ found_kr = 0;
+ pkr = &keyrequests;
+ kr = *pkr;
+ while (kr) {
+ if (now > kr->expiration) {
+ if (kr->dead) {
+ *pkr = kr->next;
+ kr_free(kr);
+ } else {
+ pkr = &kr->next;
+ }
+ } else {
+ if (!strcmp(url, kr->url))
+ found_kr = kr;
+ pkr = &kr->next;
+ }
+ kr = *pkr;
+ }
+
+ /* check if found and pending */
+ if (found_kr) {
+ /* found -> cancel */
+ pthread_mutex_unlock(&mutex);
+ callback(closure, 0, NULL, 0);
+ return;
+ }
+
+ /* allocates the keyrequest */
+ kr = kr_alloc(url, now + delay, appli, idp, callback, closure);
+ if (!kr) {
+ pthread_mutex_unlock(&mutex);
+ callback(closure, 0, "Out of memory", 0);
+ return;
+ }
+
+ /* link the request */
+ kr->next = keyrequests;
+ keyrequests = kr;
+
+ /* makes the request in a new thread */
+ rc = pthread_create(&kr->tid, 0, kr_get_thread, kr);
+ if (rc != 0) {
+ /* error, unlink */
+ keyrequests = kr->next;
+ pthread_mutex_unlock(&mutex);
+ kr_free(kr);
+ callback(closure, 0, "Can't create a new thread", 0);
+ return;
+ }
+ pthread_mutex_unlock(&mutex);
+}
+
+/* vim: set colorcolumn=80: */
+