aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/afb-api-dbus.c32
-rw-r--r--src/afb-api-ws.c7
-rw-r--r--src/afb-cred.c136
-rw-r--r--src/afb-cred.h38
-rw-r--r--src/afb-ws-json1.c4
6 files changed, 218 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0566206e..6956d0d2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -65,6 +65,7 @@ ADD_LIBRARY(afb-lib STATIC
afb-common.c
afb-config.c
afb-context.c
+ afb-cred.c
afb-ditf.c
afb-evt.c
afb-hook.c
diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c
index a9f50109..593232b9 100644
--- a/src/afb-api-dbus.c
+++ b/src/afb-api-dbus.c
@@ -35,6 +35,7 @@
#include "afb-apis.h"
#include "afb-api-so.h"
#include "afb-context.h"
+#include "afb-cred.h"
#include "afb-evt.h"
#include "afb-xreq.h"
#include "verbose.h"
@@ -663,10 +664,39 @@ struct origin
/* count of references */
int refcount;
+ /* credentials of the origin */
+ struct afb_cred *cred;
+
/* the origin */
char name[1];
};
+/* get the credentials for the message */
+static void init_origin_creds(struct origin *origin)
+{
+ int rc;
+ sd_bus_creds *c;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ const char *context;
+
+ rc = sd_bus_get_name_creds(origin->api->sdbus, origin->name,
+ SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT,
+ &c);
+ if (rc < 0)
+ origin->cred = NULL;
+ else {
+ afb_cred_unref(origin->cred);
+ sd_bus_creds_get_uid(c, &uid);
+ sd_bus_creds_get_gid(c, &gid);
+ sd_bus_creds_get_pid(c, &pid);
+ sd_bus_creds_get_selinux_context(c, &context);
+ origin->cred = afb_cred_create(uid, gid, pid, context);
+ sd_bus_creds_unref(c);
+ }
+}
+
static struct origin *afb_api_dbus_server_origin_get(struct api_dbus *api, const char *sender)
{
struct origin *origin;
@@ -689,6 +719,7 @@ static struct origin *afb_api_dbus_server_origin_get(struct api_dbus *api, const
origin->api = api;
origin->refcount = 1;
strcpy(origin->name, sender);
+ init_origin_creds(origin);
origin->next = api->server.origins;
api->server.origins = origin;
}
@@ -704,6 +735,7 @@ static void afb_api_dbus_server_origin_unref(struct origin *origin)
while(*prv != origin)
prv = &(*prv)->next;
*prv = origin->next;
+ afb_cred_unref(origin->cred);
free(origin);
}
}
diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c
index 4b870d45..8be74c03 100644
--- a/src/afb-api-ws.c
+++ b/src/afb-api-ws.c
@@ -38,6 +38,7 @@
#include "afb-common.h"
#include "afb-session.h"
+#include "afb-cred.h"
#include "afb-ws.h"
#include "afb-msg-json.h"
#include "afb-apis.h"
@@ -125,6 +126,9 @@ struct api_ws_client
/* websocket */
struct afb_ws *ws;
+
+ /* credentials */
+ struct afb_cred *cred;
};
/******************* websocket interface for client part **********************************/
@@ -903,6 +907,7 @@ static void api_ws_server_client_unref(struct api_ws_client *client)
if (!--client->refcount) {
afb_evt_listener_unref(client->listener);
afb_ws_destroy(client->ws);
+ afb_cred_unref(client->cred);
free(client);
}
}
@@ -994,6 +999,7 @@ static void api_ws_server_accept(struct api_ws *api)
lenaddr = (socklen_t)sizeof addr;
client->fd = accept(api->fd, &addr, &lenaddr);
if (client->fd >= 0) {
+ client->cred = afb_cred_create_for_socket(client->fd);
fcntl(client->fd, F_SETFD, FD_CLOEXEC);
fcntl(client->fd, F_SETFL, O_NONBLOCK);
client->ws = afb_ws_create(afb_common_get_event_loop(), client->fd, &api_ws_server_ws_itf, client);
@@ -1002,6 +1008,7 @@ static void api_ws_server_accept(struct api_ws *api)
client->refcount = 1;
return;
}
+ afb_cred_unref(client->cred);
close(client->fd);
}
afb_evt_listener_unref(client->listener);
diff --git a/src/afb-cred.c b/src/afb-cred.c
new file mode 100644
index 00000000..8a777009
--- /dev/null
+++ b/src/afb-cred.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 "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 <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "afb-cred.h"
+
+#define MAX_LABEL_LENGTH 1024
+
+static struct afb_cred *current;
+
+static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *label, size_t size)
+{
+ struct afb_cred *cred;
+ char *dest;
+
+ cred = malloc(1 + size + sizeof *cred);
+ if (!cred)
+ errno = ENOMEM;
+ else {
+ cred->refcount = 1;
+ cred->uid = uid;
+ cred->gid = gid;
+ cred->pid = pid;
+ dest = (char*)(&cred[1]);
+ memcpy(dest, label, size);
+ dest[size] = 0;
+ cred->label = dest;
+ cred->id = dest;
+ dest = strrchr(dest, ':');
+ if (dest && dest[1])
+ cred->id = &dest[1];
+ }
+ return cred;
+}
+
+static struct afb_cred *mkcurrent()
+{
+ char label[MAX_LABEL_LENGTH];
+ int fd;
+ ssize_t rc;
+
+ fd = open("/proc/self/attr/current", O_RDONLY);
+ if (fd < 0)
+ rc = 0;
+ else {
+ rc = read(fd, label, sizeof label);
+ if (rc < 0)
+ rc = 0;
+ close(fd);
+ }
+
+ return mkcred(getuid(), getgid(), getpid(), label, (size_t)rc);
+}
+
+struct afb_cred *afb_cred_create(uid_t uid, gid_t gid, pid_t pid, const char *label)
+{
+ label = label ? : "";
+ return mkcred(uid, gid, pid, label, strlen(label));
+}
+
+struct afb_cred *afb_cred_create_for_socket(int fd)
+{
+ int rc;
+ socklen_t length;
+ struct ucred ucred;
+ char label[MAX_LABEL_LENGTH];
+
+ /* get the credentials */
+ length = (socklen_t)(sizeof ucred);
+ rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length);
+ if (rc < 0 || length != (socklen_t)(sizeof ucred)) {
+ if (!rc)
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* get the security label */
+ length = (socklen_t)(sizeof label);
+ rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, label, &length);
+ if (rc < 0 || length > (socklen_t)(sizeof label)) {
+ if (!rc)
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* makes the result */
+ return mkcred(ucred.uid, ucred.gid, ucred.pid, label, (size_t)length);
+}
+
+struct afb_cred *afb_cred_addref(struct afb_cred *cred)
+{
+ if (cred)
+ __atomic_add_fetch(&cred->refcount, 1, __ATOMIC_RELAXED);
+ return cred;
+}
+
+void afb_cred_unref(struct afb_cred *cred)
+{
+ if (cred && !__atomic_sub_fetch(&cred->refcount, 1, __ATOMIC_RELAXED)) {
+ if (cred != current)
+ free(cred);
+ else
+ cred->refcount = 1;
+ }
+}
+
+struct afb_cred *afb_cred_current()
+{
+ if (!current)
+ current = mkcurrent();
+ return afb_cred_addref(current);
+}
+
diff --git a/src/afb-cred.h b/src/afb-cred.h
new file mode 100644
index 00000000..5bd54233
--- /dev/null
+++ b/src/afb-cred.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 "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
+
+#include <sys/types.h>
+
+struct afb_cred
+{
+ int refcount;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ const char *label;
+ const char *id;
+};
+
+extern struct afb_cred *afb_cred_current();
+extern struct afb_cred *afb_cred_create(uid_t uid, gid_t gid, pid_t pid, const char *label);
+extern struct afb_cred *afb_cred_create_for_socket(int fd);
+extern struct afb_cred *afb_cred_addref(struct afb_cred *cred);
+extern void afb_cred_unref(struct afb_cred *cred);
+
+
diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c
index 9d560c5a..fec41173 100644
--- a/src/afb-ws-json1.c
+++ b/src/afb-ws-json1.c
@@ -32,6 +32,7 @@
#include "afb-common.h"
#include "afb-msg-json.h"
#include "afb-session.h"
+#include "afb-cred.h"
#include "afb-apis.h"
#include "afb-xreq.h"
#include "afb-context.h"
@@ -62,6 +63,7 @@ struct afb_ws_json1
struct afb_session *session;
struct afb_evt_listener *listener;
struct afb_wsj1 *wsj1;
+ struct afb_cred *cred;
int new_session;
};
@@ -128,6 +130,7 @@ struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_context *context, vo
if (result->listener == NULL)
goto error4;
+ result->cred = afb_cred_create_for_socket(fd);
return result;
error4:
@@ -155,6 +158,7 @@ static void aws_unref(struct afb_ws_json1 *ws)
if (ws->cleanup != NULL)
ws->cleanup(ws->cleanup_closure);
afb_session_unref(ws->session);
+ afb_cred_unref(ws->cred);
free(ws);
}
}