source: vendor/current/source3/lib/msghdr.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 5.5 KB
Line 
1/*
2 * Unix SMB/CIFS implementation.
3 * Copyright (C) Volker Lendecke 2014
4 *
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.
9 *
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.
14 *
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/>.
17 */
18
19#include "replace.h"
20#include "lib/msghdr.h"
21#include "lib/util/iov_buf.h"
22#include <sys/socket.h>
23
24#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
25
26ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
27 const int *fds, size_t num_fds)
28{
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;
34
35 if (num_fds == 0) {
36 if (msg != NULL) {
37 msg->msg_control = NULL;
38 msg->msg_controllen = 0;
39 }
40 return 0;
41 }
42 if (num_fds > INT8_MAX) {
43 return -1;
44 }
45 if ((msg == NULL) || (cmsg_space > bufsize)) {
46 return cmsg_space;
47 }
48
49 msg->msg_control = buf;
50 msg->msg_controllen = cmsg_space;
51
52 cmsg = CMSG_FIRSTHDR(msg);
53 cmsg->cmsg_level = SOL_SOCKET;
54 cmsg->cmsg_type = SCM_RIGHTS;
55 cmsg->cmsg_len = cmsg_len;
56 fdptr = CMSG_DATA(cmsg);
57 memcpy(fdptr, fds, fds_size);
58 msg->msg_controllen = cmsg->cmsg_len;
59
60 return cmsg_space;
61}
62
63size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
64 size_t num_fds)
65{
66 size_t ret = CMSG_SPACE(sizeof(int) * num_fds);
67
68 if (bufsize < ret) {
69 return ret;
70 }
71 if (msg != NULL) {
72 if (num_fds != 0) {
73 msg->msg_control = buf;
74 msg->msg_controllen = ret;
75 } else {
76 msg->msg_control = NULL;
77 msg->msg_controllen = 0;
78 }
79 }
80 return ret;
81}
82
83size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
84{
85 struct cmsghdr *cmsg;
86 size_t num_fds;
87
88 for(cmsg = CMSG_FIRSTHDR(msg);
89 cmsg != NULL;
90 cmsg = CMSG_NXTHDR(msg, cmsg))
91 {
92 if ((cmsg->cmsg_type == SCM_RIGHTS) &&
93 (cmsg->cmsg_level == SOL_SOCKET)) {
94 break;
95 }
96 }
97
98 if (cmsg == NULL) {
99 return 0;
100 }
101
102 num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
103
104 if ((num_fds != 0) && (fds != NULL) && (fds_size >= num_fds)) {
105 memcpy(fds, CMSG_DATA(cmsg), num_fds * sizeof(int));
106 }
107
108 return num_fds;
109}
110
111#elif defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
112
113ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
114 const int *fds, size_t num_fds)
115{
116 size_t needed;
117
118 if (num_fds > INT8_MAX) {
119 return -1;
120 }
121
122 needed = sizeof(int) * num_fds;
123
124 if ((msg == NULL) || (needed > bufsize)) {
125 return needed;
126 }
127
128 memcpy(buf, fds, needed);
129
130 msg->msg_accrights = (caddr_t) buf;
131 msg->msg_accrightslen = needed;
132
133 return needed;
134}
135
136size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
137 size_t num_fds)
138{
139 size_t ret = num_fds * sizeof(int);
140
141 if (bufsize < ret) {
142 return ret;
143 }
144
145 if (msg != NULL) {
146 if (num_fds != 0) {
147 msg->msg_accrights = (caddr_t) buf;
148 msg->msg_accrightslen = ret;
149 } else {
150 msg->msg_accrights = NULL;
151 msg->msg_accrightslen = 0;
152 }
153 }
154 return ret;
155}
156
157size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
158{
159 size_t num_fds = msg->msg_accrightslen / sizeof(int);
160
161 if ((fds != 0) && (num_fds <= fds_size)) {
162 memcpy(fds, msg->msg_accrights, msg->msg_accrightslen);
163 }
164
165 return num_fds;
166}
167
168#else
169
170ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
171 const int *fds, size_t num_fds)
172{
173 return -1;
174}
175
176size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
177 size_t num_fds)
178{
179 return 0;
180}
181
182size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
183{
184 return 0;
185}
186
187#endif
188
189struct msghdr_buf {
190 struct msghdr msg;
191 struct sockaddr_storage addr;
192 struct iovec iov;
193 uint8_t buf[];
194};
195
196ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
197 const void *addr, socklen_t addrlen,
198 const struct iovec *iov, int iovcnt,
199 const int *fds, size_t num_fds)
200{
201 ssize_t fd_len;
202 size_t iov_len, needed, bufsize;
203
204 bufsize = (msgsize > offsetof(struct msghdr_buf, buf)) ?
205 msgsize - offsetof(struct msghdr_buf, buf) : 0;
206
207 if (msg != NULL) {
208 msg->msg = (struct msghdr) { 0 };
209
210 fd_len = msghdr_prep_fds(&msg->msg, msg->buf, bufsize,
211 fds, num_fds);
212 } else {
213 fd_len = msghdr_prep_fds(NULL, NULL, bufsize, fds, num_fds);
214 }
215
216 if (fd_len == -1) {
217 return -1;
218 }
219
220 if (bufsize >= fd_len) {
221 bufsize -= fd_len;
222 } else {
223 bufsize = 0;
224 }
225
226 if (msg != NULL) {
227
228 if (addr != NULL) {
229 if (addrlen > sizeof(struct sockaddr_storage)) {
230 errno = EMSGSIZE;
231 return -1;
232 }
233 memcpy(&msg->addr, addr, addrlen);
234 msg->msg.msg_name = &msg->addr;
235 msg->msg.msg_namelen = addrlen;
236 } else {
237 msg->msg.msg_name = NULL;
238 msg->msg.msg_namelen = 0;
239 }
240
241 msg->iov.iov_base = msg->buf + fd_len;
242 msg->iov.iov_len = iov_buf(
243 iov, iovcnt, msg->iov.iov_base, bufsize);
244 iov_len = msg->iov.iov_len;
245
246 msg->msg.msg_iov = &msg->iov;
247 msg->msg.msg_iovlen = 1;
248 } else {
249 iov_len = iov_buflen(iov, iovcnt);
250 }
251
252 needed = offsetof(struct msghdr_buf, buf) + fd_len;
253 if (needed < fd_len) {
254 return -1;
255 }
256 needed += iov_len;
257 if (needed < iov_len) {
258 return -1;
259 }
260
261 return needed;
262}
263
264struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg)
265{
266 return &msg->msg;
267}
Note: See TracBrowser for help on using the repository browser.