Update copyright dates
[src/app-framework-binder.git] / src / afb-cred.c
index 8a77700..09a4803 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 "IoT.bzh"
+ * Copyright (C) 2015-2020 "IoT.bzh"
  * Author: José Bollo <jose.bollo@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,8 @@
 #define _GNU_SOURCE
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/socket.h>
 
 #include "afb-cred.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;
-
-       cred = malloc(1 + size + sizeof *cred);
+       char *dest, user[64];
+       size_t i;
+       uid_t u;
+
+       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 +76,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 +114,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 +128,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 +168,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 +184,36 @@ 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;
+}