X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-cred.c;h=b6e6febae597d6a28f88cc1abb9291ede0634b01;hb=b70caad7da2eaea85db06dec8377b1cbebcec997;hp=8a77700912b6be8278334c663c91698cf248011e;hpb=a05138e6bf1257b0e7b1ad90c974fb9e12f1d040;p=src%2Fapp-framework-binder.git diff --git a/src/afb-cred.c b/src/afb-cred.c index 8a777009..b6e6feba 100644 --- a/src/afb-cred.c +++ b/src/afb-cred.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 "IoT.bzh" + * Copyright (C) 2017-2019 "IoT.bzh" * Author: José Bollo * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,8 @@ #define _GNU_SOURCE #include +#include +#include #include #include #include @@ -26,17 +28,49 @@ #include #include "afb-cred.h" +#include "afb-context.h" +#include "afb-token.h" +#include "verbose.h" #define MAX_LABEL_LENGTH 1024 +#if !defined(NO_DEFAULT_PEERCRED) && !defined(ADD_DEFAULT_PEERCRED) +# define NO_DEFAULT_PEERCRED +#endif + +#if !defined(DEFAULT_PEERSEC_LABEL) +# define DEFAULT_PEERSEC_LABEL "NoLabel" +#endif +#if !defined(DEFAULT_PEERCRED_UID) +# define DEFAULT_PEERCRED_UID 99 /* nobody */ +#endif +#if !defined(DEFAULT_PEERCRED_GID) +# define DEFAULT_PEERCRED_GID 99 /* nobody */ +#endif +#if !defined(DEFAULT_PEERCRED_PID) +# define DEFAULT_PEERCRED_PID 0 /* no process */ +#endif + +static char export_format[] = "%x:%x:%x-%s"; +static char import_format[] = "%x:%x:%x-%n"; + 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; + char *dest, user[64]; + size_t i; + uid_t u; - cred = malloc(1 + size + sizeof *cred); + i = 0; + u = uid; + do { + user[i++] = (char)('0' + u % 10); + u = u / 10; + } while(u && i < sizeof user); + + cred = malloc(2 + i + size + sizeof *cred); if (!cred) errno = ENOMEM; else { @@ -44,13 +78,18 @@ static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *labe cred->uid = uid; cred->gid = gid; cred->pid = pid; + cred->exported = NULL; dest = (char*)(&cred[1]); - memcpy(dest, label, size); - dest[size] = 0; + cred->user = dest; + while(i) + *dest++ = user[--i]; + *dest++ = 0; cred->label = dest; cred->id = dest; + memcpy(dest, label, size); + dest[size] = 0; dest = strrchr(dest, ':'); - if (dest && dest[1]) + if (dest) cred->id = &dest[1]; } return cred; @@ -77,7 +116,7 @@ static struct afb_cred *mkcurrent() struct afb_cred *afb_cred_create(uid_t uid, gid_t gid, pid_t pid, const char *label) { - label = label ? : ""; + label = label ? : DEFAULT_PEERSEC_LABEL; return mkcred(uid, gid, pid, label, strlen(label)); } @@ -91,19 +130,30 @@ struct afb_cred *afb_cred_create_for_socket(int fd) /* 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 < 0 || length != (socklen_t)(sizeof ucred) || !~ucred.uid) { +#if !defined(NO_DEFAULT_PEERCRED) + ucred.uid = DEFAULT_PEERCRED_UID; + ucred.gid = DEFAULT_PEERCRED_GID; + ucred.pid = DEFAULT_PEERCRED_PID; +#else if (!rc) errno = EINVAL; return NULL; +#endif } /* 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 !defined(NO_DEFAULT_PEERSEC) + length = (socklen_t)strlen(DEFAULT_PEERSEC_LABEL); + strcpy (label, DEFAULT_PEERSEC_LABEL); +#else if (!rc) errno = EINVAL; return NULL; +#endif } /* makes the result */ @@ -120,10 +170,12 @@ struct afb_cred *afb_cred_addref(struct afb_cred *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 + if (cred == current) cred->refcount = 1; + else { + free((void*)cred->exported); + free(cred); + } } } @@ -134,3 +186,94 @@ struct afb_cred *afb_cred_current() return afb_cred_addref(current); } +const char *afb_cred_export(struct afb_cred *cred) +{ + int rc; + + if (!cred->exported) { + rc = asprintf((char**)&cred->exported, + export_format, + (int)cred->uid, + (int)cred->gid, + (int)cred->pid, + cred->label); + if (rc < 0) { + errno = ENOMEM; + cred->exported = NULL; + } + } + return cred->exported; +} + +struct afb_cred *afb_cred_import(const char *string) +{ + struct afb_cred *cred; + int rc, uid, gid, pid, pos; + + rc = sscanf(string, import_format, &uid, &gid, &pid, &pos); + if (rc == 3) + cred = afb_cred_create((uid_t)uid, (gid_t)gid, (pid_t)pid, &string[pos]); + else { + errno = EINVAL; + cred = NULL; + } + return cred; +} + +/*********************************************************************************/ +static const char *token_of_context(struct afb_context *context) +{ + return context && context->token ? afb_token_string(context->token) : "X"; +} + +/*********************************************************************************/ +#ifdef BACKEND_PERMISSION_IS_CYNARA + +#include +#include + +static cynara *handle; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +int afb_cred_has_permission(struct afb_cred *cred, const char *permission, struct afb_context *context) +{ + int rc; + + if (!cred) { + /* case of permission for self */ + return 1; + } + if (!permission) { + ERROR("Got a null permission!"); + return 0; + } + + /* cynara isn't reentrant */ + pthread_mutex_lock(&mutex); + + /* lazy initialisation */ + if (!handle) { + rc = cynara_initialize(&handle, NULL); + if (rc != CYNARA_API_SUCCESS) { + handle = NULL; + ERROR("cynara initialisation failed with code %d", rc); + return 0; + } + } + + /* query cynara permission */ + rc = cynara_check(handle, cred->label, token_of_context(context), cred->user, permission); + + pthread_mutex_unlock(&mutex); + return rc == CYNARA_API_ACCESS_ALLOWED; +} + +/*********************************************************************************/ +#else +int afb_cred_has_permission(struct afb_cred *cred, const char *permission, struct afb_context *context) +{ + WARNING("Granting permission %s by default of backend", permission ?: "(null)"); + return !!permission; +} +#endif +