Fedora 30 packaging fix issu
[src/app-framework-binder.git] / src / afb-cred.c
index eda0c9d..a2cb577 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 "IoT.bzh"
+ * Copyright (C) 2017, 2018 "IoT.bzh"
  * Author: José Bollo <jose.bollo@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,7 @@
 #define _GNU_SOURCE
 
 #include <stdlib.h>
+#include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
@@ -26,6 +27,8 @@
 #include <sys/socket.h>
 
 #include "afb-cred.h"
+#include "verbose.h"
+
 
 #define MAX_LABEL_LENGTH  1024
 
 #  define DEFAULT_PEERCRED_PID 0  /* no process */
 #endif
 
+static char on_behalf_credential_permission[] = "urn:AGL:permission:*:partner:on-behalf-credentials";
+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)
@@ -70,6 +77,7 @@ 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]);
                cred->user = dest;
                while(i)
@@ -161,10 +169,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);
+               }
        }
 }
 
@@ -175,3 +185,105 @@ 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;
+}
+
+struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported)
+
+{
+       struct afb_cred *imported;
+       if (exported) {
+               if (afb_cred_has_permission(cred, on_behalf_credential_permission, context)) {
+                       imported = afb_cred_import(exported);
+                       if (imported)
+                               return imported;
+                       ERROR("Can't import on behalf credentials: %m");
+               } else {
+                       ERROR("On behalf credentials refused");
+               }
+       }
+       return afb_cred_addref(cred);
+}
+
+/*********************************************************************************/
+#ifdef BACKEND_PERMISSION_IS_CYNARA
+
+#include <pthread.h>
+#include <cynara-client.h>
+
+static cynara *handle;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *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, 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, const char *context)
+{
+       WARNING("Granting permission %s by default of backend", permission ?: "(null)");
+       return !!permission;
+}
+#endif
+