summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/afb-context.c15
-rw-r--r--src/afb-context.h4
-rw-r--r--src/afb-export.c3
-rw-r--r--src/afb-session.c51
-rw-r--r--src/afb-stub-ws.c3
-rw-r--r--src/afb-token.c182
-rw-r--r--src/afb-token.h28
-rw-r--r--src/afb-ws-json1.c5
-rw-r--r--src/main-afb-daemon.c3
10 files changed, 275 insertions, 20 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index abc81c8b..0d5e7122 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -104,6 +104,7 @@ SET(AFB_LIB_SOURCES
afb-socket.c
afb-stub-ws.c
afb-supervision.c
+ afb-token.c
afb-trace.c
afb-websock.c
afb-ws-client.c
diff --git a/src/afb-context.c b/src/afb-context.c
index fd394939..6057e69d 100644
--- a/src/afb-context.c
+++ b/src/afb-context.c
@@ -50,12 +50,19 @@ void afb_context_init(struct afb_context *context, struct afb_session *session,
init_context(context, afb_session_addref(session), token);
}
+void afb_context_init_validated(struct afb_context *context, struct afb_session *session)
+{
+ afb_context_init(context, session, NULL);
+ context->validated = 1;
+}
+
void afb_context_subinit(struct afb_context *context, struct afb_context *super)
{
context->session = super->session;
context->flags = 0;
context->super = super;
context->api_key = NULL;
+ context->token = NULL;
context->validated = super->validated;
}
@@ -75,6 +82,14 @@ int afb_context_connect(struct afb_context *context, const char *uuid, const cha
return 0;
}
+int afb_context_connect_validated(struct afb_context *context, const char *uuid)
+{
+ int rc = afb_context_connect(context, uuid, NULL);
+ if (!rc)
+ context->validated = 1;
+ return rc;
+}
+
void afb_context_disconnect(struct afb_context *context)
{
if (context->session && !context->super) {
diff --git a/src/afb-context.h b/src/afb-context.h
index bec1d35c..21af4b23 100644
--- a/src/afb-context.h
+++ b/src/afb-context.h
@@ -18,10 +18,12 @@
#pragma once
struct afb_session;
+struct afb_token;
struct afb_context
{
struct afb_session *session;
+ struct afb_token *token;
const void *api_key;
struct afb_context *super;
union {
@@ -39,8 +41,10 @@ struct afb_context
};
extern void afb_context_init(struct afb_context *context, struct afb_session *session, const char *token);
+extern void afb_context_init_validated(struct afb_context *context, struct afb_session *session);
extern void afb_context_subinit(struct afb_context *context, struct afb_context *super);
extern int afb_context_connect(struct afb_context *context, const char *uuid, const char *token);
+extern int afb_context_connect_validated(struct afb_context *context, const char *uuid);
extern void afb_context_disconnect(struct afb_context *context);
extern const char *afb_context_sent_token(struct afb_context *context);
extern const char *afb_context_sent_uuid(struct afb_context *context);
diff --git a/src/afb-export.c b/src/afb-export.c
index 38ef4021..3cf1fc94 100644
--- a/src/afb-export.c
+++ b/src/afb-export.c
@@ -1952,7 +1952,6 @@ void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq)
void afb_export_context_init(struct afb_export *export, struct afb_context *context)
{
- afb_context_init(context, export->session, NULL);
- context->validated = 1;
+ afb_context_init_validated(context, export->session);
}
diff --git a/src/afb-session.c b/src/afb-session.c
index 61aa3f61..fe5aa4af 100644
--- a/src/afb-session.c
+++ b/src/afb-session.c
@@ -28,6 +28,7 @@
#include "afb-session.h"
#include "afb-hook.h"
+#include "afb-token.h"
#include "verbose.h"
#include "pearson.h"
#include "uuid.h"
@@ -68,7 +69,7 @@ struct afb_session
uint8_t autoclose: 1; /**< close the session when unreferenced */
uint8_t notinset: 1; /**< session removed from the set of sessions */
uuid_stringz_t uuid; /**< long term authentication of remote client */
- uuid_stringz_t token; /**< short term authentication of remote client */
+ struct afb_token *token;/**< short term authentication of remote client */
};
/**
@@ -79,14 +80,14 @@ static struct {
int max; /**< maximum count of sessions */
int timeout; /**< common initial timeout */
struct afb_session *heads[HEADCOUNT]; /**< sessions */
- uuid_stringz_t initok; /**< common initial token */
+ struct afb_token *initok;/**< common initial token */
pthread_mutex_t mutex; /**< declare a mutex to protect hash table */
} sessions = {
.count = 0,
.max = 10,
.timeout = 3600,
.heads = { 0 },
- .initok = { 0 },
+ .initok = 0,
.mutex = PTHREAD_MUTEX_INITIALIZER
};
@@ -203,6 +204,7 @@ static void session_destroy (struct afb_session *session)
afb_hook_session_destroy(session);
#endif
pthread_mutex_destroy(&session->mutex);
+ afb_token_unref(session->token);
free(session->lang);
free(session);
}
@@ -249,12 +251,13 @@ static struct afb_session *session_add(const char *uuid, int timeout, time_t now
pthread_mutex_init(&session->mutex, NULL);
session->refcount = 1;
strcpy(session->uuid, uuid);
- strcpy(session->token, sessions.initok);
+ session->token = afb_token_addref(sessions.initok);
session->timeout = timeout;
session_update_expiration(session, now);
/* add */
if (sessionset_add(session, hashidx)) {
+ afb_token_unref(session->token);
free(session);
return NULL;
}
@@ -309,6 +312,9 @@ static time_t sessionset_cleanup (int force)
*/
int afb_session_init (int max_session_count, int timeout, const char *initok)
{
+ int rc;
+ uuid_stringz_t uuid;
+
/* check parameters */
if (initok && strlen(initok) >= sizeof sessions.initok) {
ERROR("initial token '%s' too long (max length %d)",
@@ -322,10 +328,16 @@ int afb_session_init (int max_session_count, int timeout, const char *initok)
sessionset_cleanup(1);
sessions.max = max_session_count;
sessions.timeout = timeout;
- if (initok == NULL)
- uuid_new_stringz(sessions.initok);
- else
- strcpy(sessions.initok, initok);
+ if (initok == NULL) {
+ uuid_new_stringz(uuid);
+ initok = uuid;
+ }
+ sessions.initok = 0;
+ if (*initok) {
+ rc = afb_token_get(&sessions.initok, initok);
+ if (rc < 0)
+ return rc;
+ }
sessionset_unlock();
return 0;
}
@@ -367,7 +379,7 @@ void afb_session_purge()
*/
const char *afb_session_initial_token()
{
- return sessions.initok;
+ return sessions.initok ? afb_token_string(sessions.initok) : "";
}
/* Searchs the session of 'uuid' */
@@ -528,7 +540,7 @@ int afb_session_check_token (struct afb_session *session, const char *token)
session_lock(session);
r = !session->closed
&& session->expiration >= NOW
- && !(session->token[0] && strcmp (token, session->token));
+ && !(session->token && strcmp(token, afb_session_token(session)));
session_unlock(session);
return r;
}
@@ -536,12 +548,23 @@ int afb_session_check_token (struct afb_session *session, const char *token)
/* generate a new token and update client context */
void afb_session_new_token (struct afb_session *session)
{
+ int rc;
+ uuid_stringz_t uuid;
+ struct afb_token *previous, *next;
session_lock(session);
- uuid_new_stringz(session->token);
- session_update_expiration(session, NOW);
+ uuid_new_stringz(uuid);
+ rc = afb_token_get(&next, uuid);
+ if (rc < 0)
+ ERROR("can't renew token");
+ else {
+ previous = session->token;
+ session->token = next;
+ session_update_expiration(session, NOW);
#if WITH_AFB_HOOK
- afb_hook_session_renew(session);
+ afb_hook_session_renew(session);
#endif
+ afb_token_unref(previous);
+ }
session_unlock(session);
}
@@ -554,7 +577,7 @@ const char *afb_session_uuid (struct afb_session *session)
/* Returns the token of 'session' */
const char *afb_session_token (struct afb_session *session)
{
- return session->token;
+ return afb_token_string(session->token);
}
/**
diff --git a/src/afb-stub-ws.c b/src/afb-stub-ws.c
index 6a52f6fc..3e9ede2f 100644
--- a/src/afb-stub-ws.c
+++ b/src/afb-stub-ws.c
@@ -523,9 +523,8 @@ static void server_on_call_cb(void *closure, struct afb_proto_ws_call *call, con
wreq->call = call;
/* init the context */
- if (afb_context_connect(&wreq->xreq.context, sessionid, NULL) < 0)
+ if (afb_context_connect_validated(&wreq->xreq.context, sessionid) < 0)
goto unconnected;
- wreq->xreq.context.validated = 1;
server_record_session(stubws, wreq->xreq.context.session);
if (wreq->xreq.context.created)
afb_session_set_autoclose(wreq->xreq.context.session, 1);
diff --git a/src/afb-token.c b/src/afb-token.c
new file mode 100644
index 00000000..b81a87df
--- /dev/null
+++ b/src/afb-token.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2015-2019 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "afb-token.h"
+
+/**
+ * structure for recording a token
+ */
+struct afb_token
+{
+ /** link to the next token of the list */
+ struct afb_token *next;
+
+ /** reference of the token */
+ uint16_t refcount;
+
+ /** local numeric id of the token */
+ uint16_t id;
+
+ /** string value of the token */
+ char text[];
+};
+
+struct tokenset
+{
+ struct afb_token *first;
+ pthread_mutex_t mutex;
+ uint16_t idgen;
+};
+
+static struct tokenset tokenset = {
+ .first = 0,
+ .mutex = PTHREAD_MUTEX_INITIALIZER,
+ .idgen = 0
+};
+
+static struct afb_token *searchid(uint16_t id)
+{
+ struct afb_token *r = tokenset.first;
+ while (r && r->id != id)
+ r = r->next;
+ return r;
+}
+
+/**
+ * Get a token for the given value
+ *
+ * @param token address to return the pointer to the gotten token
+ * @param tokenstring string value of the token to get
+ * @return 0 in case of success or a -errno like negative code
+ */
+int afb_token_get(struct afb_token **token, const char *tokenstring)
+{
+ int rc;
+ struct afb_token *tok;
+ size_t length;
+
+ /* get length of the token string */
+ length = + strlen(tokenstring);
+
+ /* concurrency */
+ pthread_mutex_lock(&tokenset.mutex);
+
+ /* search the token */
+ tok = tokenset.first;
+ while (tok && memcmp(tokenstring, tok->text, length))
+ tok = tok->next;
+
+ /* search done */
+ if (tok) {
+ /* found */
+ tok = afb_token_addref(tok);
+ rc = 0;
+ } else {
+ /* not found, create */
+ tok = malloc(length + sizeof *tok);
+ if (!tok)
+ /* creation failed */
+ rc = -ENOMEM;
+ else {
+ while(!++tokenset.idgen || searchid(tokenset.idgen));
+ tok->next = tokenset.first;
+ tokenset.first = tok;
+ tok->id = tokenset.idgen;
+ tok->refcount = 1;
+ memcpy(tok->text, tokenstring, length);
+ rc = 0;
+ }
+ }
+ pthread_mutex_unlock(&tokenset.mutex);
+ *token = tok;
+ return rc;
+}
+
+/**
+ * Add a reference count to the given token
+ *
+ * @param token the token to reference
+ * @return the token with the reference added
+ */
+struct afb_token *afb_token_addref(struct afb_token *token)
+{
+ if (token)
+ __atomic_add_fetch(&token->refcount, 1, __ATOMIC_RELAXED);
+ return token;
+}
+
+/**
+ * Remove a reference to the given token and clean the memory if needed
+ *
+ * @param token the token that is unreferenced
+ */
+void afb_token_unref(struct afb_token *token)
+{
+ struct afb_token **pt;
+ if (token && !__atomic_sub_fetch(&token->refcount, 1, __ATOMIC_RELAXED)) {
+ pthread_mutex_lock(&tokenset.mutex);
+ pt = &tokenset.first;
+ while (*pt && *pt != token)
+ if (*pt)
+ *pt = token->next;
+ pthread_mutex_unlock(&tokenset.mutex);
+ free(token);
+ }
+}
+
+/**
+ * Check whether the token is valid or not
+ *
+ * @param token the token to check
+ * @return a boolean value: 0 if not valid, 1 if valid
+ */
+int afb_token_check(struct afb_token *token)
+{
+ /* TODO */
+ return 1;
+}
+
+/**
+ * Get the string value of the token
+ *
+ * @param token the token whose string value is queried
+ * @return the string value of the token
+ */
+const char *afb_token_string(const struct afb_token *token)
+{
+ return token->text;
+}
+
+/**
+ * Get the "local" numeric id of the token
+ *
+ * @param token the token whose id is queried
+ * @return the numeric id of the token
+ */
+uint16_t afb_token_id(const struct afb_token *token)
+{
+ return token->id;
+}
diff --git a/src/afb-token.h b/src/afb-token.h
new file mode 100644
index 00000000..69b0fa05
--- /dev/null
+++ b/src/afb-token.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016-2019 "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.
+ */
+
+#pragma once
+
+struct afb_token;
+
+extern int afb_token_get(struct afb_token **token, const char *tokenstring);
+extern struct afb_token *afb_token_addref(struct afb_token *token);
+extern void afb_token_unref(struct afb_token *token);
+
+extern int afb_token_check(struct afb_token *token);
+extern const char *afb_token_string(const struct afb_token *token);
+extern uint16_t afb_token_id(const struct afb_token *token);
diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c
index c7991934..d0cca2bd 100644
--- a/src/afb-ws-json1.c
+++ b/src/afb-ws-json1.c
@@ -34,6 +34,7 @@
#include "afb-xreq.h"
#include "afb-context.h"
#include "afb-evt.h"
+#include "afb-token.h"
#include "systemd.h"
#include "verbose.h"
@@ -62,6 +63,7 @@ struct afb_ws_json1
void (*cleanup)(void*);
void *cleanup_closure;
struct afb_session *session;
+ struct afb_token *token;
struct afb_evt_listener *listener;
struct afb_wsj1 *wsj1;
struct afb_cred *cred;
@@ -121,6 +123,7 @@ struct afb_ws_json1 *afb_ws_json1_create(struct fdev *fdev, struct afb_apiset *a
result->cleanup = cleanup;
result->cleanup_closure = cleanup_closure;
result->session = afb_session_addref(context->session);
+ result->token = afb_token_addref(context->token);
result->new_session = context->created != 0;
if (result->session == NULL)
goto error2;
@@ -141,6 +144,7 @@ error4:
afb_wsj1_unref(result->wsj1);
error3:
afb_session_unref(result->session);
+ afb_token_unref(result->token);
error2:
free(result);
error:
@@ -161,6 +165,7 @@ void afb_ws_json1_unref(struct afb_ws_json1 *ws)
afb_wsj1_unref(ws->wsj1);
if (ws->cleanup != NULL)
ws->cleanup(ws->cleanup_closure);
+ afb_token_unref(ws->token);
afb_session_unref(ws->session);
afb_cred_unref(ws->cred);
afb_apiset_unref(ws->apiset);
diff --git a/src/main-afb-daemon.c b/src/main-afb-daemon.c
index 3421be81..165d1400 100644
--- a/src/main-afb-daemon.c
+++ b/src/main-afb-daemon.c
@@ -659,8 +659,7 @@ static void startup_call_current(struct startup_req *sreq)
json = strchr(verb, ':');
if (json) {
afb_xreq_init(&sreq->xreq, &startup_xreq_itf);
- afb_context_init(&sreq->xreq.context, sreq->session, NULL);
- sreq->xreq.context.validated = 1;
+ afb_context_init_validated(&sreq->xreq.context, sreq->session);
sreq->api = strndup(api, verb - api);
sreq->verb = strndup(verb + 1, json - verb - 1);
sreq->xreq.request.called_api = sreq->api;