char dummy = 0;
memset(&msg, 0, sizeof(msg));
- memset(tmp, 0, CMSG_SPACE(sizeof_fds) * sizeof(char));
+ memset(tmp, 0, sizeof(tmp));
if (nb_fd > LTTCOMM_MAX_SEND_FDS)
return -EINVAL;
if (!cmptr) {
return -1;
}
+
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
cmptr->cmsg_len = CMSG_LEN(sizeof_fds);
ssize_t ret = 0;
struct cmsghdr *cmsg;
size_t sizeof_fds = nb_fd * sizeof(int);
- char recv_fd[CMSG_SPACE(sizeof_fds)];
+
+#ifdef __linux__
+/* Account for the struct ucred cmsg in the buffer size */
+#define LTTNG_SOCK_RECV_FDS_BUF_SIZE CMSG_SPACE(sizeof_fds) + CMSG_SPACE(sizeof(struct ucred))
+#else
+#define LTTNG_SOCK_RECV_FDS_BUF_SIZE CMSG_SPACE(sizeof_fds)
+#endif /* __linux__ */
+
+ char recv_buf[LTTNG_SOCK_RECV_FDS_BUF_SIZE];
struct msghdr msg;
char dummy;
iov[0].iov_len = 1;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
- msg.msg_control = recv_fd;
- msg.msg_controllen = sizeof(recv_fd);
+
+ cmsg = (struct cmsghdr *) recv_buf;
+ cmsg->cmsg_len = CMSG_LEN(sizeof_fds);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+
+ msg.msg_control = cmsg;
+ msg.msg_controllen = CMSG_LEN(sizeof(recv_buf));
+ msg.msg_flags = 0;
do {
ret = recvmsg(sock, &msg, 0);
PERROR("recvmsg fds");
goto end;
}
+
if (ret != 1) {
fprintf(stderr, "Error: Received %zd bytes, expected %d\n",
ret, 1);
goto end;
}
+
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr, "Error: Control message truncated.\n");
ret = -1;
goto end;
}
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg) {
- fprintf(stderr, "Error: Invalid control message header\n");
- ret = -1;
- goto end;
- }
- if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
- fprintf(stderr, "Didn't received any fd\n");
- ret = -1;
- goto end;
- }
- if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
- fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
- (size_t) cmsg->cmsg_len, (size_t) CMSG_LEN(sizeof_fds));
- ret = -1;
- goto end;
+
+ /*
+ * If the socket was configured with SO_PASSCRED, the kernel will add a
+ * control message (cmsg) to the ancillary data of the unix socket. We
+ * need to expect a cmsg of the SCM_CREDENTIALS as the first control
+ * message.
+ */
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET) {
+ fprintf(stderr, "Error: The socket needs to be of type SOL_SOCKET\n");
+ ret = -1;
+ goto end;
+ }
+ if (cmsg->cmsg_type == SCM_RIGHTS) {
+ /*
+ * We found the controle message for file descriptors,
+ * now copy the fds to the fds ptr and return success.
+ */
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
+ fprintf(stderr, "Error: Received %zu bytes of"
+ "ancillary data for FDs, expected %zu\n",
+ (size_t) cmsg->cmsg_len,
+ (size_t) CMSG_LEN(sizeof_fds));
+ ret = -1;
+ goto end;
+ }
+ memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
+ ret = sizeof_fds;
+ goto end;
+ }
+#ifdef __linux__
+ if (cmsg->cmsg_type == SCM_CREDENTIALS) {
+ /*
+ * Expect credentials to be sent when expecting fds even
+ * if no credential were include in the send(). The
+ * kernel adds them...
+ */
+ ret = -1;
+ }
+#endif /* __linux__ */
}
- memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
- ret = sizeof_fds;
end:
return ret;
}