commit fa94a16116d8382a987ddf9e8cdd88027dd1f647 Author: Ingo Franzki Date: Tue Feb 16 17:13:34 2021 +0100 Event support: Add event client Signed-off-by: Ingo Franzki 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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