]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/af_unix.c
netns_ifaddrs: fix missing include
[mirror_lxc.git] / src / lxc / af_unix.c
CommitLineData
b0a33c1e 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
b0a33c1e 8 *
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.
13 *
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.
18 *
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
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
b0a33c1e 22 */
d06245b8
NC
23#include "config.h"
24
94ac256f
CB
25#include <errno.h>
26#include <fcntl.h>
27#include <stddef.h>
ae467c54
CB
28#include <stdio.h>
29#include <stdlib.h>
b0a33c1e 30#include <string.h>
31#include <unistd.h>
b0a33c1e 32#include <sys/socket.h>
94ac256f 33#include <sys/syscall.h>
b0a33c1e 34#include <sys/un.h>
35
2dcb28a9 36#include "log.h"
0059379f 37#include "utils.h"
2dcb28a9 38
9de31d5a
CB
39#ifndef HAVE_STRLCPY
40#include "include/strlcpy.h"
41#endif
42
ac2cecc4 43lxc_log_define(af_unix, lxc);
b0a33c1e 44
c62fb5e0 45static ssize_t lxc_abstract_unix_set_sockaddr(struct sockaddr_un *addr,
46 const char *path)
b0a33c1e 47{
ddb17f1f 48 size_t len;
b0a33c1e 49
c62fb5e0 50 if (!addr || !path) {
51 errno = EINVAL;
b0a33c1e 52 return -1;
c62fb5e0 53 }
b0a33c1e 54
aae93dd3 55 /* Clear address structure */
c62fb5e0 56 memset(addr, 0, sizeof(*addr));
b0a33c1e 57
c62fb5e0 58 addr->sun_family = AF_UNIX;
aae93dd3 59
caf3beb0 60 len = strlen(&path[1]);
c62fb5e0 61
caf3beb0 62 /* do not enforce \0-termination */
c62fb5e0 63 if (len >= INT_MAX || len >= sizeof(addr->sun_path)) {
aae93dd3
ÇO
64 errno = ENAMETOOLONG;
65 return -1;
ddb17f1f 66 }
9de31d5a
CB
67
68 /* do not enforce \0-termination */
c62fb5e0 69 memcpy(&addr->sun_path[1], &path[1], len);
70 return len;
71}
72
73int lxc_abstract_unix_open(const char *path, int type, int flags)
74{
75 int fd, ret;
76 ssize_t len;
77 struct sockaddr_un addr;
78
79 fd = socket(PF_UNIX, type, 0);
80 if (fd < 0)
81 return -1;
82
83 if (!path)
84 return fd;
85
86 len = lxc_abstract_unix_set_sockaddr(&addr, path);
87 if (len < 0) {
88 int saved_errno = errno;
89 close(fd);
90 errno = saved_errno;
91 return -1;
92 }
b0a33c1e 93
77b0073a
CB
94 ret = bind(fd, (struct sockaddr *)&addr,
95 offsetof(struct sockaddr_un, sun_path) + len + 1);
96 if (ret < 0) {
c62fb5e0 97 int saved_errno = errno;
b0a33c1e 98 close(fd);
c62fb5e0 99 errno = saved_errno;
b0a33c1e 100 return -1;
101 }
ddb17f1f 102
77b0073a
CB
103 if (type == SOCK_STREAM) {
104 ret = listen(fd, 100);
105 if (ret < 0) {
c62fb5e0 106 int saved_errno = errno;
77b0073a 107 close(fd);
c62fb5e0 108 errno = saved_errno;
77b0073a
CB
109 return -1;
110 }
b0a33c1e 111 }
112
113 return fd;
114}
115
9044b79e 116void lxc_abstract_unix_close(int fd)
b0a33c1e 117{
b0a33c1e 118 close(fd);
b0a33c1e 119}
120
aae93dd3 121int lxc_abstract_unix_connect(const char *path)
b0a33c1e 122{
77b0073a 123 int fd, ret;
c62fb5e0 124 ssize_t len;
b0a33c1e 125 struct sockaddr_un addr;
126
127 fd = socket(PF_UNIX, SOCK_STREAM, 0);
128 if (fd < 0)
129 return -1;
130
c62fb5e0 131 len = lxc_abstract_unix_set_sockaddr(&addr, path);
132 if (len < 0) {
133 int saved_errno = errno;
aae93dd3 134 close(fd);
c62fb5e0 135 errno = saved_errno;
aae93dd3
ÇO
136 return -1;
137 }
9de31d5a 138
77b0073a
CB
139 ret = connect(fd, (struct sockaddr *)&addr,
140 offsetof(struct sockaddr_un, sun_path) + len + 1);
141 if (ret < 0) {
9044b79e 142 int saved_errno = errno;
b0a33c1e 143 close(fd);
9044b79e 144 errno = saved_errno;
b0a33c1e 145 return -1;
146 }
147
148 return fd;
149}
150
ae467c54
CB
151int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds,
152 void *data, size_t size)
b0a33c1e 153{
ae467c54
CB
154 int ret;
155 struct msghdr msg;
604f0955 156 struct iovec iov;
ae467c54 157 struct cmsghdr *cmsg = NULL;
caf3beb0 158 char buf[1] = {0};
ae467c54
CB
159 char *cmsgbuf;
160 size_t cmsgbufsize = CMSG_SPACE(num_sendfds * sizeof(int));
161
162 memset(&msg, 0, sizeof(msg));
163 memset(&iov, 0, sizeof(iov));
164
165 cmsgbuf = malloc(cmsgbufsize);
9044b79e 166 if (!cmsgbuf) {
167 errno = ENOMEM;
ae467c54 168 return -1;
9044b79e 169 }
b0a33c1e 170
604f0955 171 msg.msg_control = cmsgbuf;
ae467c54 172 msg.msg_controllen = cmsgbufsize;
b0a33c1e 173
604f0955 174 cmsg = CMSG_FIRSTHDR(&msg);
604f0955
ÇO
175 cmsg->cmsg_level = SOL_SOCKET;
176 cmsg->cmsg_type = SCM_RIGHTS;
ae467c54 177 cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int));
b0a33c1e 178
ae467c54
CB
179 msg.msg_controllen = cmsg->cmsg_len;
180
181 memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int));
b0a33c1e 182
604f0955
ÇO
183 iov.iov_base = data ? data : buf;
184 iov.iov_len = data ? size : sizeof(buf);
185 msg.msg_iov = &iov;
186 msg.msg_iovlen = 1;
b0a33c1e 187
ae467c54
CB
188 ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
189 free(cmsgbuf);
190 return ret;
b0a33c1e 191}
192
ae467c54
CB
193int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
194 void *data, size_t size)
b0a33c1e 195{
ae467c54
CB
196 int ret;
197 struct msghdr msg;
604f0955 198 struct iovec iov;
ae467c54 199 struct cmsghdr *cmsg = NULL;
caf3beb0 200 char buf[1] = {0};
ae467c54
CB
201 char *cmsgbuf;
202 size_t cmsgbufsize = CMSG_SPACE(num_recvfds * sizeof(int));
203
204 memset(&msg, 0, sizeof(msg));
205 memset(&iov, 0, sizeof(iov));
206
207 cmsgbuf = malloc(cmsgbufsize);
9044b79e 208 if (!cmsgbuf) {
209 errno = ENOMEM;
ae467c54 210 return -1;
9044b79e 211 }
b0a33c1e 212
604f0955 213 msg.msg_control = cmsgbuf;
ae467c54 214 msg.msg_controllen = cmsgbufsize;
b0a33c1e 215
604f0955
ÇO
216 iov.iov_base = data ? data : buf;
217 iov.iov_len = data ? size : sizeof(buf);
218 msg.msg_iov = &iov;
219 msg.msg_iovlen = 1;
b0a33c1e 220
221 ret = recvmsg(fd, &msg, 0);
222 if (ret <= 0)
223 goto out;
224
604f0955 225 cmsg = CMSG_FIRSTHDR(&msg);
b0a33c1e 226
ae467c54
CB
227 memset(recvfds, -1, num_recvfds * sizeof(int));
228 if (cmsg && cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
9044b79e 229 cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
ae467c54 230 memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
ae467c54 231
b0a33c1e 232out:
ae467c54 233 free(cmsgbuf);
604f0955 234 return ret;
b0a33c1e 235}
236
aae93dd3 237int lxc_abstract_unix_send_credential(int fd, void *data, size_t size)
b0a33c1e 238{
77b0073a 239 struct msghdr msg = {0};
604f0955
ÇO
240 struct iovec iov;
241 struct cmsghdr *cmsg;
b0a33c1e 242 struct ucred cred = {
0059379f 243 .pid = lxc_raw_getpid(), .uid = getuid(), .gid = getgid(),
b0a33c1e 244 };
caf3beb0
CB
245 char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
246 char buf[1] = {0};
b0a33c1e 247
604f0955
ÇO
248 msg.msg_control = cmsgbuf;
249 msg.msg_controllen = sizeof(cmsgbuf);
b0a33c1e 250
604f0955
ÇO
251 cmsg = CMSG_FIRSTHDR(&msg);
252 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
253 cmsg->cmsg_level = SOL_SOCKET;
254 cmsg->cmsg_type = SCM_CREDENTIALS;
0e391e57 255 memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
b0a33c1e 256
604f0955
ÇO
257 msg.msg_name = NULL;
258 msg.msg_namelen = 0;
b0a33c1e 259
604f0955
ÇO
260 iov.iov_base = data ? data : buf;
261 iov.iov_len = data ? size : sizeof(buf);
262 msg.msg_iov = &iov;
263 msg.msg_iovlen = 1;
b0a33c1e 264
6168ff15 265 return sendmsg(fd, &msg, MSG_NOSIGNAL);
b0a33c1e 266}
267
aae93dd3 268int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size)
b0a33c1e 269{
77b0073a 270 struct msghdr msg = {0};
604f0955
ÇO
271 struct iovec iov;
272 struct cmsghdr *cmsg;
b0a33c1e 273 struct ucred cred;
b0a33c1e 274 int ret;
caf3beb0
CB
275 char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
276 char buf[1] = {0};
b0a33c1e 277
604f0955
ÇO
278 msg.msg_name = NULL;
279 msg.msg_namelen = 0;
280 msg.msg_control = cmsgbuf;
281 msg.msg_controllen = sizeof(cmsgbuf);
b0a33c1e 282
604f0955
ÇO
283 iov.iov_base = data ? data : buf;
284 iov.iov_len = data ? size : sizeof(buf);
285 msg.msg_iov = &iov;
286 msg.msg_iovlen = 1;
b0a33c1e 287
288 ret = recvmsg(fd, &msg, 0);
289 if (ret <= 0)
290 goto out;
291
604f0955 292 cmsg = CMSG_FIRSTHDR(&msg);
b0a33c1e 293
604f0955 294 if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
77b0073a
CB
295 cmsg->cmsg_level == SOL_SOCKET &&
296 cmsg->cmsg_type == SCM_CREDENTIALS) {
0e391e57 297 memcpy(&cred, CMSG_DATA(cmsg), sizeof(cred));
77b0073a
CB
298 if (cred.uid &&
299 (cred.uid != getuid() || cred.gid != getgid())) {
9044b79e 300 INFO("Message denied for '%d/%d'", cred.uid, cred.gid);
301 errno = EACCES;
302 return -1;
2dcb28a9 303 }
604f0955 304 }
9044b79e 305
b0a33c1e 306out:
604f0955 307 return ret;
b0a33c1e 308}