]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/af_unix.c
2ff98dc1b6e6de6cdc3f2ac430219d3dcf4c27a3
2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <daniel.lezcano at free.fr>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
34 #include <sys/socket.h>
35 #include <sys/syscall.h>
40 #include "memory_utils.h"
41 #include "raw_syscalls.h"
45 #include "include/strlcpy.h"
48 lxc_log_define(af_unix
, lxc
);
50 static ssize_t
lxc_abstract_unix_set_sockaddr(struct sockaddr_un
*addr
,
60 /* Clear address structure */
61 memset(addr
, 0, sizeof(*addr
));
63 addr
->sun_family
= AF_UNIX
;
65 len
= strlen(&path
[1]);
67 /* do not enforce \0-termination */
68 if (len
>= INT_MAX
|| len
>= sizeof(addr
->sun_path
)) {
73 /* do not enforce \0-termination */
74 memcpy(&addr
->sun_path
[1], &path
[1], len
);
78 int lxc_abstract_unix_open(const char *path
, int type
, int flags
)
82 struct sockaddr_un addr
;
84 fd
= socket(PF_UNIX
, type
| SOCK_CLOEXEC
, 0);
91 len
= lxc_abstract_unix_set_sockaddr(&addr
, path
);
93 int saved_errno
= errno
;
99 ret
= bind(fd
, (struct sockaddr
*)&addr
,
100 offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
102 int saved_errno
= errno
;
108 if (type
== SOCK_STREAM
) {
109 ret
= listen(fd
, 100);
111 int saved_errno
= errno
;
121 void lxc_abstract_unix_close(int fd
)
126 int lxc_abstract_unix_connect(const char *path
)
130 struct sockaddr_un addr
;
132 fd
= socket(PF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
, 0);
136 len
= lxc_abstract_unix_set_sockaddr(&addr
, path
);
138 int saved_errno
= errno
;
144 ret
= connect(fd
, (struct sockaddr
*)&addr
,
145 offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
147 int saved_errno
= errno
;
156 int lxc_abstract_unix_send_fds_iov(int fd
, int *sendfds
, int num_sendfds
,
157 struct iovec
*iov
, size_t iovlen
)
159 __do_free
char *cmsgbuf
= NULL
;
162 struct cmsghdr
*cmsg
= NULL
;
163 size_t cmsgbufsize
= CMSG_SPACE(num_sendfds
* sizeof(int));
165 memset(&msg
, 0, sizeof(msg
));
167 cmsgbuf
= malloc(cmsgbufsize
);
173 msg
.msg_control
= cmsgbuf
;
174 msg
.msg_controllen
= cmsgbufsize
;
176 cmsg
= CMSG_FIRSTHDR(&msg
);
177 cmsg
->cmsg_level
= SOL_SOCKET
;
178 cmsg
->cmsg_type
= SCM_RIGHTS
;
179 cmsg
->cmsg_len
= CMSG_LEN(num_sendfds
* sizeof(int));
181 msg
.msg_controllen
= cmsg
->cmsg_len
;
183 memcpy(CMSG_DATA(cmsg
), sendfds
, num_sendfds
* sizeof(int));
186 msg
.msg_iovlen
= iovlen
;
189 ret
= sendmsg(fd
, &msg
, MSG_NOSIGNAL
);
197 int lxc_abstract_unix_send_fds(int fd
, int *sendfds
, int num_sendfds
,
198 void *data
, size_t size
)
202 .iov_base
= data
? data
: buf
,
203 .iov_len
= data
? size
: sizeof(buf
),
205 return lxc_abstract_unix_send_fds_iov(fd
, sendfds
, num_sendfds
, &iov
,
209 int lxc_unix_send_fds(int fd
, int *sendfds
, int num_sendfds
, void *data
,
212 return lxc_abstract_unix_send_fds(fd
, sendfds
, num_sendfds
, data
, size
);
215 static int lxc_abstract_unix_recv_fds_iov(int fd
, int *recvfds
, int num_recvfds
,
216 struct iovec
*iov
, size_t iovlen
)
218 __do_free
char *cmsgbuf
= NULL
;
221 struct cmsghdr
*cmsg
= NULL
;
223 size_t cmsgbufsize
= CMSG_SPACE(sizeof(struct ucred
)) +
224 CMSG_SPACE(num_recvfds
* sizeof(int));
226 memset(&msg
, 0, sizeof(msg
));
228 cmsgbuf
= malloc(cmsgbufsize
);
234 msg
.msg_control
= cmsgbuf
;
235 msg
.msg_controllen
= cmsgbufsize
;
238 msg
.msg_iovlen
= iovlen
;
241 ret
= recvmsg(fd
, &msg
, 0);
252 * If SO_PASSCRED is set we will always get a ucred message.
254 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
255 if (cmsg
->cmsg_type
!= SCM_RIGHTS
)
258 memset(recvfds
, -1, num_recvfds
* sizeof(int));
260 cmsg
->cmsg_len
== CMSG_LEN(num_recvfds
* sizeof(int)) &&
261 cmsg
->cmsg_level
== SOL_SOCKET
)
262 memcpy(recvfds
, CMSG_DATA(cmsg
), num_recvfds
* sizeof(int));
270 int lxc_abstract_unix_recv_fds(int fd
, int *recvfds
, int num_recvfds
,
271 void *data
, size_t size
)
275 .iov_base
= data
? data
: buf
,
276 .iov_len
= data
? size
: sizeof(buf
),
278 return lxc_abstract_unix_recv_fds_iov(fd
, recvfds
, num_recvfds
, &iov
, 1);
281 int lxc_abstract_unix_send_credential(int fd
, void *data
, size_t size
)
283 struct msghdr msg
= {0};
285 struct cmsghdr
*cmsg
;
286 struct ucred cred
= {
287 .pid
= lxc_raw_getpid(), .uid
= getuid(), .gid
= getgid(),
289 char cmsgbuf
[CMSG_SPACE(sizeof(cred
))] = {0};
292 msg
.msg_control
= cmsgbuf
;
293 msg
.msg_controllen
= sizeof(cmsgbuf
);
295 cmsg
= CMSG_FIRSTHDR(&msg
);
296 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
297 cmsg
->cmsg_level
= SOL_SOCKET
;
298 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
299 memcpy(CMSG_DATA(cmsg
), &cred
, sizeof(cred
));
304 iov
.iov_base
= data
? data
: buf
;
305 iov
.iov_len
= data
? size
: sizeof(buf
);
309 return sendmsg(fd
, &msg
, MSG_NOSIGNAL
);
312 int lxc_abstract_unix_rcv_credential(int fd
, void *data
, size_t size
)
314 struct msghdr msg
= {0};
316 struct cmsghdr
*cmsg
;
319 char cmsgbuf
[CMSG_SPACE(sizeof(cred
))] = {0};
324 msg
.msg_control
= cmsgbuf
;
325 msg
.msg_controllen
= sizeof(cmsgbuf
);
327 iov
.iov_base
= data
? data
: buf
;
328 iov
.iov_len
= data
? size
: sizeof(buf
);
332 ret
= recvmsg(fd
, &msg
, 0);
336 cmsg
= CMSG_FIRSTHDR(&msg
);
338 if (cmsg
&& cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)) &&
339 cmsg
->cmsg_level
== SOL_SOCKET
&&
340 cmsg
->cmsg_type
== SCM_CREDENTIALS
) {
341 memcpy(&cred
, CMSG_DATA(cmsg
), sizeof(cred
));
343 (cred
.uid
!= getuid() || cred
.gid
!= getgid())) {
344 INFO("Message denied for '%d/%d'", cred
.uid
, cred
.gid
);
354 int lxc_unix_sockaddr(struct sockaddr_un
*ret
, const char *path
)
360 return minus_one_set_errno(EINVAL
);
361 if (path
[0] != '/' && path
[0] != '@')
362 return minus_one_set_errno(EINVAL
);
364 return minus_one_set_errno(EINVAL
);
366 if (len
+ 1 > sizeof(ret
->sun_path
))
367 return minus_one_set_errno(EINVAL
);
369 *ret
= (struct sockaddr_un
){
370 .sun_family
= AF_UNIX
,
373 if (path
[0] == '@') {
374 memcpy(ret
->sun_path
+ 1, path
+ 1, len
);
375 return (int)(offsetof(struct sockaddr_un
, sun_path
) + len
);
378 memcpy(ret
->sun_path
, path
, len
+ 1);
379 return (int)(offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
382 int lxc_unix_connect_type(struct sockaddr_un
*addr
, int type
)
384 __do_close_prot_errno
int fd
= -EBADF
;
388 fd
= socket(AF_UNIX
, type
| SOCK_CLOEXEC
, 0);
390 SYSERROR("Failed to open new AF_UNIX socket");
394 if (addr
->sun_path
[0] == '\0')
395 len
= strlen(&addr
->sun_path
[1]);
397 len
= strlen(&addr
->sun_path
[0]);
399 ret
= connect(fd
, (struct sockaddr
*)addr
,
400 offsetof(struct sockaddr_un
, sun_path
) + len
);
402 SYSERROR("Failed to bind new AF_UNIX socket");
409 int lxc_unix_connect(struct sockaddr_un
*addr
, int type
)
411 return lxc_unix_connect_type(addr
, SOCK_STREAM
);
414 int lxc_socket_set_timeout(int fd
, int rcv_timeout
, int snd_timeout
)
416 struct timeval out
= {0};
419 out
.tv_sec
= snd_timeout
;
420 ret
= setsockopt(fd
, SOL_SOCKET
, SO_SNDTIMEO
, (const void *)&out
,
425 out
.tv_sec
= rcv_timeout
;
426 ret
= setsockopt(fd
, SOL_SOCKET
, SO_RCVTIMEO
, (const void *)&out
,