]>
Commit | Line | Data |
---|---|---|
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 | 43 | lxc_log_define(af_unix, lxc); |
b0a33c1e | 44 | |
c62fb5e0 | 45 | static 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 | ||
73 | int 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 | 116 | void lxc_abstract_unix_close(int fd) |
b0a33c1e | 117 | { |
b0a33c1e | 118 | close(fd); |
b0a33c1e | 119 | } |
120 | ||
aae93dd3 | 121 | int 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 |
151 | int 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 |
193 | int 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 | 232 | out: |
ae467c54 | 233 | free(cmsgbuf); |
604f0955 | 234 | return ret; |
b0a33c1e | 235 | } |
236 | ||
aae93dd3 | 237 | int 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 | 268 | int 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 | 306 | out: |
604f0955 | 307 | return ret; |
b0a33c1e | 308 | } |