diff options
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/afb-api-dbus.c | 32 | ||||
-rw-r--r-- | src/afb-api-ws.c | 7 | ||||
-rw-r--r-- | src/afb-cred.c | 136 | ||||
-rw-r--r-- | src/afb-cred.h | 38 | ||||
-rw-r--r-- | src/afb-ws-json1.c | 4 |
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); } } |