Blob Blame History Raw
commit fa94a16116d8382a987ddf9e8cdd88027dd1f647
Author: Ingo Franzki <ifranzki@linux.ibm.com>
Date:   Tue Feb 16 17:13:34 2021 +0100

    Event support: Add event client
    
    Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>

diff --git a/usr/lib/common/common.mk b/usr/lib/common/common.mk
index 2178ad45..882c84f4 100644
--- a/usr/lib/common/common.mk
+++ b/usr/lib/common/common.mk
@@ -4,7 +4,7 @@ noinst_HEADERS +=							\
 	usr/lib/common/shared_memory.h usr/lib/common/tok_spec_struct.h	\
 	usr/lib/common/trace.h usr/lib/common/h_extern.h		\
 	usr/lib/common/sw_crypt.h usr/lib/common/defs.h			\
-	usr/lib/common/p11util.h					\
+	usr/lib/common/p11util.h usr/lib/common/event_client.h		\
 	usr/lib/common/list.h usr/lib/common/tok_specific.h
 
 usr/lib/common/lexer.c: usr/lib/common/parser.h
diff --git a/usr/lib/common/event_client.c b/usr/lib/common/event_client.c
new file mode 100644
index 00000000..86117b84
--- /dev/null
+++ b/usr/lib/common/event_client.c
@@ -0,0 +1,215 @@
+/*
+ * COPYRIGHT (c) International Business Machines Corp. 2021
+ *
+ * This program is provided under the terms of the Common Public License,
+ * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
+ * software constitutes recipient's acceptance of CPL-1.0 terms which can be
+ * found in the file LICENSE file or at
+ * https://opensource.org/licenses/cpl1.0.php
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <grp.h>
+
+#include "slotmgr.h"
+#include "event_client.h"
+
+static int connect_socket(const char *file_path)
+{
+    int socketfd;
+    struct sockaddr_un daemon_address;
+    struct stat file_info;
+    struct group *grp;
+    int rc;
+
+    if (stat(file_path, &file_info))
+        return -errno;
+
+    grp = getgrnam("pkcs11");
+    if (!grp)
+        return -errno;
+
+    if (file_info.st_uid != 0 || file_info.st_gid != grp->gr_gid)
+        return -EPERM;
+
+    if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+        return -errno;
+
+    memset(&daemon_address, 0, sizeof(struct sockaddr_un));
+    daemon_address.sun_family = AF_UNIX;
+    strcpy(daemon_address.sun_path, file_path);
+
+    if (connect(socketfd, (struct sockaddr *) &daemon_address,
+                sizeof(struct sockaddr_un)) != 0) {
+        rc = -errno;
+        goto error;
+    }
+
+    return socketfd;
+
+error:
+    close(socketfd);
+    return rc;
+}
+
+static ssize_t read_all(int socketfd, char *buffer, size_t size)
+{
+    size_t bytes_received = 0;
+    ssize_t n;
+
+    while (bytes_received < size) {
+        n = read(socketfd, buffer + bytes_received, size - bytes_received);
+        if (n < 0) {
+            // read error
+            if (errno == EINTR)
+                continue;
+            return -errno;
+        }
+        if (n == 0)
+            break;
+
+        bytes_received += n;
+    }
+
+    return bytes_received;
+}
+
+static ssize_t send_all(int socketfd, char *buffer, size_t size)
+{
+    size_t bytes_sent = 0;
+    ssize_t n;
+
+    while (bytes_sent < size) {
+        n = send(socketfd, buffer + bytes_sent, size - bytes_sent, 0);
+        if (n < 0) {
+            // send error
+            if (errno == EINTR)
+                continue;
+            return -errno;
+        }
+        if (n == 0)
+            break;
+
+        bytes_sent += n;
+    }
+
+    return bytes_sent;
+}
+
+/*
+ * Initialize an admin connection to the pkcsslotd.
+ * Returns a file descriptor representing the connection, or a negative errno
+ * in case of an error.
+ */
+int init_event_client()
+{
+    int fd;
+
+    fd = connect_socket(ADMIN_SOCKET_FILE_PATH);
+
+    return fd;
+}
+
+/*
+ * Send an event though the admin connection to the pkcsslotd, and thus to
+ * all active token instances.
+ * If parameter fd is < 0, then a connection to pkcsslotd is established
+ * inside the function and closed before return. This is for a one shot event.
+ * Otherwise, pass a file descriptor received from init_event_client(). This
+ * is to send multiple events.
+ * Event type is mandatory, flags can be zero.
+ * The event payload is optional, if payload_len is non-zero, then payload must
+ * point to a buffer containing the payload to send with the event.
+ * The event destination can be used to selectively send the event to certain
+ * token instances only. If destination is NULL, it is sent to all token
+ * instances.
+ * If flag EVENT_FLAGS_REPLY_REQ is on in the flags parameter, then it is waited
+ * until all active token instances have replied. The combined result of the
+ * replies from the token instances is returned in the reply structure.
+ * Parameter reply must be non-NULL if flag EVENT_FLAGS_REPLY_REQ is set.
+ * Returns zero for success, or a negative errno in case of an error. In most
+ * error cases the connection to the pkcsslotd is out of sequence and can no
+ * longer be used to send further events.
+ */
+int send_event(int fd, unsigned int type, unsigned int flags,
+               unsigned int payload_len, const char *payload,
+               const struct event_destination *destination,
+               struct event_reply *reply)
+{
+    event_msg_t event_msg;
+    event_reply_t event_reply;
+    int rc, term = 0;
+
+    if (payload_len > 0 && payload == NULL)
+        return -EINVAL;
+    if ((flags & EVENT_FLAGS_REPLY_REQ) && reply == NULL)
+        return -EINVAL;
+    if (payload_len > EVENT_MAX_PAYLOAD_LENGTH)
+        return -EMSGSIZE;
+
+    if (fd < 0) {
+        fd = init_event_client();
+        if (fd < 0)
+            return fd;
+        term = 1;
+    }
+
+    memset(&event_msg, 0, sizeof(event_msg));
+    event_msg.version = EVENT_VERSION_1;
+    event_msg.type = type;
+    event_msg.flags = flags;
+    if (destination != NULL) {
+        event_msg.token_type = destination->token_type;
+        memcpy(event_msg.token_label, destination->token_label,
+               sizeof(event_msg.token_label));
+        event_msg.process_id = destination->process_id;
+    } else {
+        memset(event_msg.token_label, ' ', sizeof(event_msg.token_label));
+    }
+    event_msg.payload_len = payload_len;
+
+    rc = send_all(fd, (char *)&event_msg, sizeof(event_msg));
+    if (rc < 0)
+        goto out;
+
+    if (payload_len > 0) {
+        rc = send_all(fd, (char *)payload, payload_len);
+        if (rc < 0)
+            goto out;
+    }
+
+    if (flags & EVENT_FLAGS_REPLY_REQ) {
+        rc = read_all(fd, (char *)&event_reply, sizeof(event_reply));
+        if (rc < 0)
+            goto out;
+
+        reply->positive_replies = event_reply.positive_replies;
+        reply->negative_replies = event_reply.negative_replies;
+        reply->nothandled_replies = event_reply.nothandled_replies;
+    }
+
+    rc = 0;
+
+out:
+    if (term)
+        term_event_client(fd);
+
+    return rc;
+}
+
+/*
+ * Terminate the admin connection to the pkcsslotd.
+ */
+void term_event_client(int fd)
+{
+    if (fd >= 0)
+        close(fd);
+}
+
diff --git a/usr/lib/common/event_client.h b/usr/lib/common/event_client.h
new file mode 100644
index 00000000..2e4917b0
--- /dev/null
+++ b/usr/lib/common/event_client.h
@@ -0,0 +1,39 @@
+/*
+ * COPYRIGHT (c) International Business Machines Corp. 2021
+ *
+ * This program is provided under the terms of the Common Public License,
+ * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
+ * software constitutes recipient's acceptance of CPL-1.0 terms which can be
+ * found in the file LICENSE file or at
+ * https://opensource.org/licenses/cpl1.0.php
+ */
+
+
+#ifndef _EVENT_CLIENT_H_
+#define _EVENT_CLIENT_H_
+
+#include "events.h"
+
+struct event_destination {
+    unsigned int token_type;    /* Destination token type: EVENT_TOK_TYPE_xxx */
+    char token_label[member_size(event_msg_t, token_label)];
+                                /* Label of destination token (or blanks) */
+    pid_t process_id;           /* Process ID of destination process (or 0) */
+};
+
+struct event_reply {
+    unsigned long positive_replies;
+    unsigned long negative_replies;
+    unsigned long nothandled_replies;
+};
+
+int init_event_client();
+
+int send_event(int fd, unsigned int type, unsigned int flags,
+               unsigned int payload_len, const char *payload,
+               const struct event_destination *destination,
+               struct event_reply *reply);
+
+void term_event_client(int fd);
+
+#endif