summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_socket_msg.h
diff options
context:
space:
mode:
authorTiago Natel de Moura <t.nateldemoura@f5.com>2021-11-09 15:48:44 +0300
committerTiago Natel de Moura <t.nateldemoura@f5.com>2021-11-09 15:48:44 +0300
commitff6a7053f500414dc74568a4e49adbac7f0cf634 (patch)
treecda31505e9746138fb864a6b2902b89107e04bc7 /src/nxt_socket_msg.h
parente878f6d54376ea676b96b56f41708f01cfc4d8b4 (diff)
downloadunit-ff6a7053f500414dc74568a4e49adbac7f0cf634.tar.gz
unit-ff6a7053f500414dc74568a4e49adbac7f0cf634.tar.bz2
Introduced SCM_CREDENTIALS / SCM_CREDS in the socket control msgs.
Diffstat (limited to 'src/nxt_socket_msg.h')
-rw-r--r--src/nxt_socket_msg.h220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/nxt_socket_msg.h b/src/nxt_socket_msg.h
new file mode 100644
index 00000000..04de1761
--- /dev/null
+++ b/src/nxt_socket_msg.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NXT_SOCKET_MSG_H_INCLUDED_
+#define _NXT_SOCKET_MSG_H_INCLUDED_
+
+#if (NXT_HAVE_UCRED)
+#include <sys/un.h>
+#endif
+
+
+#if (NXT_HAVE_UCRED)
+#define NXT_CRED_USECMSG 1
+#define NXT_CRED_CMSGTYPE SCM_CREDENTIALS
+#define NXT_CRED_GETPID(u) (u->pid)
+
+typedef struct ucred nxt_socket_cred_t;
+
+#elif (NXT_HAVE_MSGHDR_CMSGCRED)
+#define NXT_CRED_USECMSG 1
+#define NXT_CRED_CMSGTYPE SCM_CREDS
+#define NXT_CRED_GETPID(u) (u->cmcred_pid)
+
+typedef struct cmsgcred nxt_socket_cred_t;
+#endif
+
+#if (NXT_CRED_USECMSG)
+#define NXT_OOB_RECV_SIZE \
+ (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t)))
+#else
+#define NXT_OOB_RECV_SIZE \
+ CMSG_SPACE(2 * sizeof(int))
+#endif
+
+#if (NXT_HAVE_MSGHDR_CMSGCRED)
+#define NXT_OOB_SEND_SIZE \
+ (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t)))
+#else
+#define NXT_OOB_SEND_SIZE \
+ CMSG_SPACE(2 * sizeof(int))
+#endif
+
+
+typedef struct {
+ size_t size;
+ u_char buf[NXT_OOB_RECV_SIZE];
+} nxt_recv_oob_t;
+
+
+typedef struct {
+ size_t size;
+ u_char buf[NXT_OOB_SEND_SIZE];
+} nxt_send_oob_t;
+
+
+/**
+ * The nxt_sendmsg is a wrapper for sendmsg.
+ * The oob struct must be initialized using nxt_socket_msg_oob_init().
+ */
+NXT_EXPORT ssize_t nxt_sendmsg(nxt_socket_t s, nxt_iobuf_t *iob,
+ nxt_uint_t niob, const nxt_send_oob_t *oob);
+
+/**
+ * The nxt_recvmsg is a wrapper for recvmsg.
+ * The oob buffer must be consumed by using nxt_socket_msg_oob_get().
+ */
+NXT_EXPORT ssize_t nxt_recvmsg(nxt_socket_t s,
+ nxt_iobuf_t *iob, nxt_uint_t niob, nxt_recv_oob_t *oob);
+
+
+nxt_inline void
+nxt_socket_msg_oob_init(nxt_send_oob_t *oob, int *fds)
+{
+ int nfds;
+ struct cmsghdr *cmsg;
+
+#if (NXT_HAVE_MSGHDR_CMSGCRED)
+ cmsg = (struct cmsghdr *) (oob->buf);
+ /*
+ * Fill all padding fields with 0.
+ * Code in Go 1.11 validate cmsghdr using padding field as part of len.
+ * See Cmsghdr definition and socketControlMessageHeaderAndData function.
+ */
+ nxt_memzero(cmsg, sizeof(struct cmsghdr));
+
+ cmsg->cmsg_len = CMSG_LEN(sizeof(nxt_socket_cred_t));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = NXT_CRED_CMSGTYPE;
+
+ oob->size = CMSG_SPACE(sizeof(nxt_socket_cred_t));
+
+#else
+ oob->size = 0;
+#endif
+
+ nfds = (fds[0] != -1 ? 1 : 0) + (fds[1] != -1 ? 1 : 0);
+
+ if (nfds == 0) {
+ return;
+ }
+
+ cmsg = (struct cmsghdr *) (oob->buf + oob->size);
+
+ nxt_memzero(cmsg, sizeof(struct cmsghdr));
+
+ cmsg->cmsg_len = CMSG_LEN(nfds * sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+
+ /*
+ * nxt_memcpy() is used instead of simple
+ * *(int *) CMSG_DATA(&cmsg.cm) = fd;
+ * because GCC 4.4 with -O2/3/s optimization may issue a warning:
+ * dereferencing type-punned pointer will break strict-aliasing rules
+ *
+ * Fortunately, GCC with -O1 compiles this nxt_memcpy()
+ * in the same simple assignment as in the code above.
+ */
+ nxt_memcpy(CMSG_DATA(cmsg), fds, nfds * sizeof(int));
+
+ oob->size += CMSG_SPACE(nfds * sizeof(int));
+}
+
+
+nxt_inline nxt_int_t
+nxt_socket_msg_oob_get_fds(nxt_recv_oob_t *oob, nxt_fd_t *fd)
+{
+ size_t size;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+
+ msg.msg_control = oob->buf;
+ msg.msg_controllen = oob->size;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ size = cmsg->cmsg_len - CMSG_LEN(0);
+
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) {
+ return NXT_ERROR;
+ }
+
+ nxt_memcpy(fd, CMSG_DATA(cmsg), size);
+
+ return NXT_OK;
+ }
+ }
+
+ return NXT_OK;
+}
+
+
+nxt_inline nxt_int_t
+nxt_socket_msg_oob_get(nxt_recv_oob_t *oob, nxt_fd_t *fd, nxt_pid_t *pid)
+{
+ size_t size;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+
+ if (oob->size == 0) {
+ return NXT_OK;
+ }
+
+#if (NXT_CRED_USECMSG)
+ *pid = -1;
+#endif
+
+ msg.msg_control = oob->buf;
+ msg.msg_controllen = oob->size;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ size = cmsg->cmsg_len - CMSG_LEN(0);
+
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) {
+ return NXT_ERROR;
+ }
+
+ nxt_memcpy(fd, CMSG_DATA(cmsg), size);
+
+#if (!NXT_CRED_USECMSG)
+ break;
+#endif
+ }
+
+#if (NXT_CRED_USECMSG)
+ else if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == NXT_CRED_CMSGTYPE)
+ {
+ nxt_socket_cred_t *creds;
+
+ if (nxt_slow_path(size != sizeof(nxt_socket_cred_t))) {
+ return NXT_ERROR;
+ }
+
+ creds = (nxt_socket_cred_t *) CMSG_DATA(cmsg);
+ *pid = NXT_CRED_GETPID(creds);
+ }
+#endif
+ }
+
+#if (NXT_CRED_USECMSG)
+ /* For platforms supporting credential passing, it's enforced */
+ if (nxt_slow_path(*pid == -1)) {
+ return NXT_ERROR;
+ }
+#endif
+
+ return NXT_OK;
+}
+
+
+#endif /* _NXT_SOCKET_MSG_H_INCLUDED_ */