VERSION: Bump version up to Samba 4.17.8...
[Samba.git] / lib / util / msghdr.c
blob3a1d6f5a017e5a85cf292fc2e4858c0a1e7dd1c4
1 /*
2 * Unix SMB/CIFS implementation.
3 * Copyright (C) Volker Lendecke 2014
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "replace.h"
20 #include "lib/util/msghdr.h"
21 #include "lib/util/iov_buf.h"
22 #include <sys/socket.h>
24 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
26 ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
27 const int *fds, size_t num_fds)
29 size_t fds_size = sizeof(int) * MIN(num_fds, INT8_MAX);
30 size_t cmsg_len = CMSG_LEN(fds_size);
31 size_t cmsg_space = CMSG_SPACE(fds_size);
32 struct cmsghdr *cmsg;
33 void *fdptr;
35 if (num_fds == 0) {
36 if (msg != NULL) {
37 msg->msg_control = NULL;
38 msg->msg_controllen = 0;
41 * C99 doesn't allow 0-length arrays
43 return 1;
45 if (num_fds > INT8_MAX) {
46 return -1;
48 if ((msg == NULL) || (cmsg_space > bufsize)) {
50 * C99 doesn't allow 0-length arrays
52 return MAX(cmsg_space, 1);
55 msg->msg_control = buf;
56 msg->msg_controllen = cmsg_space;
58 cmsg = CMSG_FIRSTHDR(msg);
59 cmsg->cmsg_level = SOL_SOCKET;
60 cmsg->cmsg_type = SCM_RIGHTS;
61 cmsg->cmsg_len = cmsg_len;
62 fdptr = CMSG_DATA(cmsg);
63 memcpy(fdptr, fds, fds_size);
64 msg->msg_controllen = cmsg->cmsg_len;
66 return cmsg_space;
69 size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
70 size_t num_fds)
72 size_t ret = CMSG_SPACE(sizeof(int) * num_fds);
74 if (bufsize < ret) {
75 return ret;
77 if (msg != NULL) {
78 if (num_fds != 0) {
79 msg->msg_control = buf;
80 msg->msg_controllen = ret;
81 } else {
82 msg->msg_control = NULL;
83 msg->msg_controllen = 0;
86 return ret;
89 size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
91 struct cmsghdr *cmsg;
92 size_t num_fds;
94 for(cmsg = CMSG_FIRSTHDR(msg);
95 cmsg != NULL;
96 cmsg = CMSG_NXTHDR(msg, cmsg))
98 if ((cmsg->cmsg_type == SCM_RIGHTS) &&
99 (cmsg->cmsg_level == SOL_SOCKET)) {
100 break;
104 if (cmsg == NULL) {
105 return 0;
108 num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
110 if ((num_fds != 0) && (fds != NULL) && (fds_size >= num_fds)) {
111 memcpy(fds, CMSG_DATA(cmsg), num_fds * sizeof(int));
114 return num_fds;
117 #elif defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
119 ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
120 const int *fds, size_t num_fds)
122 size_t needed;
124 if (num_fds > INT8_MAX) {
125 return -1;
128 needed = sizeof(int) * num_fds;
130 if ((msg == NULL) || (needed > bufsize)) {
131 return needed;
134 memcpy(buf, fds, needed);
136 msg->msg_accrights = (caddr_t) buf;
137 msg->msg_accrightslen = needed;
139 return needed;
142 size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
143 size_t num_fds)
145 size_t ret = num_fds * sizeof(int);
147 if (bufsize < ret) {
148 return ret;
151 if (msg != NULL) {
152 if (num_fds != 0) {
153 msg->msg_accrights = (caddr_t) buf;
154 msg->msg_accrightslen = ret;
155 } else {
156 msg->msg_accrights = NULL;
157 msg->msg_accrightslen = 0;
160 return ret;
163 size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
165 size_t num_fds = msg->msg_accrightslen / sizeof(int);
167 if ((fds != 0) && (num_fds <= fds_size)) {
168 memcpy(fds, msg->msg_accrights, msg->msg_accrightslen);
171 return num_fds;
174 #else
176 ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
177 const int *fds, size_t num_fds)
179 return -1;
182 size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
183 size_t num_fds)
185 return 0;
188 size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
190 return 0;
193 #endif
195 struct msghdr_buf {
196 struct msghdr msg;
197 struct sockaddr_storage addr;
198 struct iovec iov;
199 uint8_t buf[];
202 ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
203 const void *addr, socklen_t addrlen,
204 const struct iovec *iov, int iovcnt,
205 const int *fds, size_t num_fds)
207 ssize_t fd_len;
208 size_t iov_len, needed, bufsize;
210 bufsize = (msgsize > offsetof(struct msghdr_buf, buf)) ?
211 msgsize - offsetof(struct msghdr_buf, buf) : 0;
213 if (msg != NULL) {
214 msg->msg = (struct msghdr) { 0 };
216 fd_len = msghdr_prep_fds(&msg->msg, msg->buf, bufsize,
217 fds, num_fds);
218 } else {
219 fd_len = msghdr_prep_fds(NULL, NULL, bufsize, fds, num_fds);
222 if (fd_len == -1) {
223 return -1;
226 if (bufsize >= (size_t)fd_len) {
227 bufsize -= fd_len;
228 } else {
229 bufsize = 0;
232 if (msg != NULL) {
234 if (addr != NULL) {
235 if (addrlen > sizeof(struct sockaddr_storage)) {
236 errno = EMSGSIZE;
237 return -1;
239 memcpy(&msg->addr, addr, addrlen);
240 msg->msg.msg_name = &msg->addr;
241 msg->msg.msg_namelen = addrlen;
242 } else {
243 msg->msg.msg_name = NULL;
244 msg->msg.msg_namelen = 0;
247 msg->iov.iov_base = msg->buf + fd_len;
248 msg->iov.iov_len = iov_buf(
249 iov, iovcnt, msg->iov.iov_base, bufsize);
250 iov_len = msg->iov.iov_len;
252 msg->msg.msg_iov = &msg->iov;
253 msg->msg.msg_iovlen = 1;
254 } else {
255 iov_len = iov_buflen(iov, iovcnt);
258 needed = offsetof(struct msghdr_buf, buf) + fd_len;
259 if (needed < (size_t)fd_len) {
260 return -1;
262 needed += iov_len;
263 if (needed < iov_len) {
264 return -1;
267 return needed;
270 struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg)
272 return &msg->msg;