]>
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 | ||
2dcb28a9 | 43 | lxc_log_define(lxc_af_unix, lxc); |
b0a33c1e | 44 | |
aae93dd3 | 45 | int lxc_abstract_unix_open(const char *path, int type, int flags) |
b0a33c1e | 46 | { |
77b0073a | 47 | int fd, ret; |
ddb17f1f | 48 | size_t len; |
b0a33c1e | 49 | struct sockaddr_un addr; |
50 | ||
b0a33c1e | 51 | fd = socket(PF_UNIX, type, 0); |
52 | if (fd < 0) | |
53 | return -1; | |
54 | ||
aae93dd3 | 55 | /* Clear address structure */ |
b0a33c1e | 56 | memset(&addr, 0, sizeof(addr)); |
57 | ||
58 | if (!path) | |
59 | return fd; | |
60 | ||
61 | addr.sun_family = AF_UNIX; | |
aae93dd3 | 62 | |
caf3beb0 CB |
63 | len = strlen(&path[1]); |
64 | /* do not enforce \0-termination */ | |
65 | if (len >= sizeof(addr.sun_path)) { | |
aae93dd3 | 66 | close(fd); |
aae93dd3 ÇO |
67 | errno = ENAMETOOLONG; |
68 | return -1; | |
ddb17f1f | 69 | } |
9de31d5a CB |
70 | |
71 | /* do not enforce \0-termination */ | |
72 | memcpy(&addr.sun_path[1], &path[1], len); | |
b0a33c1e | 73 | |
77b0073a CB |
74 | ret = bind(fd, (struct sockaddr *)&addr, |
75 | offsetof(struct sockaddr_un, sun_path) + len + 1); | |
76 | if (ret < 0) { | |
dba104c8 | 77 | int tmp = errno; |
b0a33c1e | 78 | close(fd); |
dba104c8 | 79 | errno = tmp; |
b0a33c1e | 80 | return -1; |
81 | } | |
ddb17f1f | 82 | |
77b0073a CB |
83 | if (type == SOCK_STREAM) { |
84 | ret = listen(fd, 100); | |
85 | if (ret < 0) { | |
86 | int tmp = errno; | |
87 | close(fd); | |
88 | errno = tmp; | |
89 | return -1; | |
90 | } | |
91 | ||
b0a33c1e | 92 | } |
93 | ||
94 | return fd; | |
95 | } | |
96 | ||
aae93dd3 | 97 | int lxc_abstract_unix_close(int fd) |
b0a33c1e | 98 | { |
b0a33c1e | 99 | close(fd); |
b0a33c1e | 100 | return 0; |
101 | } | |
102 | ||
aae93dd3 | 103 | int lxc_abstract_unix_connect(const char *path) |
b0a33c1e | 104 | { |
77b0073a | 105 | int fd, ret; |
aae93dd3 | 106 | size_t len; |
b0a33c1e | 107 | struct sockaddr_un addr; |
108 | ||
109 | fd = socket(PF_UNIX, SOCK_STREAM, 0); | |
110 | if (fd < 0) | |
111 | return -1; | |
112 | ||
113 | memset(&addr, 0, sizeof(addr)); | |
114 | ||
115 | addr.sun_family = AF_UNIX; | |
b0a33c1e | 116 | |
caf3beb0 CB |
117 | len = strlen(&path[1]); |
118 | /* do not enforce \0-termination */ | |
119 | if (len >= sizeof(addr.sun_path)) { | |
aae93dd3 | 120 | close(fd); |
aae93dd3 ÇO |
121 | errno = ENAMETOOLONG; |
122 | return -1; | |
123 | } | |
9de31d5a CB |
124 | |
125 | /* do not enforce \0-termination */ | |
126 | memcpy(&addr.sun_path[1], &path[1], len); | |
aae93dd3 | 127 | |
77b0073a CB |
128 | ret = connect(fd, (struct sockaddr *)&addr, |
129 | offsetof(struct sockaddr_un, sun_path) + len + 1); | |
130 | if (ret < 0) { | |
b0a33c1e | 131 | close(fd); |
132 | return -1; | |
133 | } | |
134 | ||
135 | return fd; | |
136 | } | |
137 | ||
ae467c54 CB |
138 | int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds, |
139 | void *data, size_t size) | |
b0a33c1e | 140 | { |
ae467c54 CB |
141 | int ret; |
142 | struct msghdr msg; | |
604f0955 | 143 | struct iovec iov; |
ae467c54 | 144 | struct cmsghdr *cmsg = NULL; |
caf3beb0 | 145 | char buf[1] = {0}; |
ae467c54 CB |
146 | char *cmsgbuf; |
147 | size_t cmsgbufsize = CMSG_SPACE(num_sendfds * sizeof(int)); | |
148 | ||
149 | memset(&msg, 0, sizeof(msg)); | |
150 | memset(&iov, 0, sizeof(iov)); | |
151 | ||
152 | cmsgbuf = malloc(cmsgbufsize); | |
153 | if (!cmsgbuf) | |
154 | return -1; | |
b0a33c1e | 155 | |
604f0955 | 156 | msg.msg_control = cmsgbuf; |
ae467c54 | 157 | msg.msg_controllen = cmsgbufsize; |
b0a33c1e | 158 | |
604f0955 | 159 | cmsg = CMSG_FIRSTHDR(&msg); |
604f0955 ÇO |
160 | cmsg->cmsg_level = SOL_SOCKET; |
161 | cmsg->cmsg_type = SCM_RIGHTS; | |
ae467c54 | 162 | cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int)); |
b0a33c1e | 163 | |
ae467c54 CB |
164 | msg.msg_controllen = cmsg->cmsg_len; |
165 | ||
166 | memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int)); | |
b0a33c1e | 167 | |
604f0955 ÇO |
168 | iov.iov_base = data ? data : buf; |
169 | iov.iov_len = data ? size : sizeof(buf); | |
170 | msg.msg_iov = &iov; | |
171 | msg.msg_iovlen = 1; | |
b0a33c1e | 172 | |
ae467c54 CB |
173 | ret = sendmsg(fd, &msg, MSG_NOSIGNAL); |
174 | free(cmsgbuf); | |
175 | return ret; | |
b0a33c1e | 176 | } |
177 | ||
ae467c54 CB |
178 | int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds, |
179 | void *data, size_t size) | |
b0a33c1e | 180 | { |
ae467c54 CB |
181 | int ret; |
182 | struct msghdr msg; | |
604f0955 | 183 | struct iovec iov; |
ae467c54 | 184 | struct cmsghdr *cmsg = NULL; |
caf3beb0 | 185 | char buf[1] = {0}; |
ae467c54 CB |
186 | char *cmsgbuf; |
187 | size_t cmsgbufsize = CMSG_SPACE(num_recvfds * sizeof(int)); | |
188 | ||
189 | memset(&msg, 0, sizeof(msg)); | |
190 | memset(&iov, 0, sizeof(iov)); | |
191 | ||
192 | cmsgbuf = malloc(cmsgbufsize); | |
193 | if (!cmsgbuf) | |
194 | return -1; | |
b0a33c1e | 195 | |
604f0955 | 196 | msg.msg_control = cmsgbuf; |
ae467c54 | 197 | msg.msg_controllen = cmsgbufsize; |
b0a33c1e | 198 | |
604f0955 ÇO |
199 | iov.iov_base = data ? data : buf; |
200 | iov.iov_len = data ? size : sizeof(buf); | |
201 | msg.msg_iov = &iov; | |
202 | msg.msg_iovlen = 1; | |
b0a33c1e | 203 | |
204 | ret = recvmsg(fd, &msg, 0); | |
205 | if (ret <= 0) | |
206 | goto out; | |
207 | ||
604f0955 | 208 | cmsg = CMSG_FIRSTHDR(&msg); |
b0a33c1e | 209 | |
ae467c54 CB |
210 | memset(recvfds, -1, num_recvfds * sizeof(int)); |
211 | if (cmsg && cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) && | |
212 | cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { | |
213 | memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int)); | |
604f0955 | 214 | } |
ae467c54 | 215 | |
b0a33c1e | 216 | out: |
ae467c54 | 217 | free(cmsgbuf); |
604f0955 | 218 | return ret; |
b0a33c1e | 219 | } |
220 | ||
aae93dd3 | 221 | int lxc_abstract_unix_send_credential(int fd, void *data, size_t size) |
b0a33c1e | 222 | { |
77b0073a | 223 | struct msghdr msg = {0}; |
604f0955 ÇO |
224 | struct iovec iov; |
225 | struct cmsghdr *cmsg; | |
b0a33c1e | 226 | struct ucred cred = { |
0059379f | 227 | .pid = lxc_raw_getpid(), .uid = getuid(), .gid = getgid(), |
b0a33c1e | 228 | }; |
caf3beb0 CB |
229 | char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0}; |
230 | char buf[1] = {0}; | |
b0a33c1e | 231 | |
604f0955 ÇO |
232 | msg.msg_control = cmsgbuf; |
233 | msg.msg_controllen = sizeof(cmsgbuf); | |
b0a33c1e | 234 | |
604f0955 ÇO |
235 | cmsg = CMSG_FIRSTHDR(&msg); |
236 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); | |
237 | cmsg->cmsg_level = SOL_SOCKET; | |
238 | cmsg->cmsg_type = SCM_CREDENTIALS; | |
0e391e57 | 239 | memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred)); |
b0a33c1e | 240 | |
604f0955 ÇO |
241 | msg.msg_name = NULL; |
242 | msg.msg_namelen = 0; | |
b0a33c1e | 243 | |
604f0955 ÇO |
244 | iov.iov_base = data ? data : buf; |
245 | iov.iov_len = data ? size : sizeof(buf); | |
246 | msg.msg_iov = &iov; | |
247 | msg.msg_iovlen = 1; | |
b0a33c1e | 248 | |
6168ff15 | 249 | return sendmsg(fd, &msg, MSG_NOSIGNAL); |
b0a33c1e | 250 | } |
251 | ||
aae93dd3 | 252 | int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size) |
b0a33c1e | 253 | { |
77b0073a | 254 | struct msghdr msg = {0}; |
604f0955 ÇO |
255 | struct iovec iov; |
256 | struct cmsghdr *cmsg; | |
b0a33c1e | 257 | struct ucred cred; |
b0a33c1e | 258 | int ret; |
caf3beb0 CB |
259 | char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0}; |
260 | char buf[1] = {0}; | |
b0a33c1e | 261 | |
604f0955 ÇO |
262 | msg.msg_name = NULL; |
263 | msg.msg_namelen = 0; | |
264 | msg.msg_control = cmsgbuf; | |
265 | msg.msg_controllen = sizeof(cmsgbuf); | |
b0a33c1e | 266 | |
604f0955 ÇO |
267 | iov.iov_base = data ? data : buf; |
268 | iov.iov_len = data ? size : sizeof(buf); | |
269 | msg.msg_iov = &iov; | |
270 | msg.msg_iovlen = 1; | |
b0a33c1e | 271 | |
272 | ret = recvmsg(fd, &msg, 0); | |
273 | if (ret <= 0) | |
274 | goto out; | |
275 | ||
604f0955 | 276 | cmsg = CMSG_FIRSTHDR(&msg); |
b0a33c1e | 277 | |
604f0955 | 278 | if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) && |
77b0073a CB |
279 | cmsg->cmsg_level == SOL_SOCKET && |
280 | cmsg->cmsg_type == SCM_CREDENTIALS) { | |
0e391e57 | 281 | memcpy(&cred, CMSG_DATA(cmsg), sizeof(cred)); |
77b0073a CB |
282 | if (cred.uid && |
283 | (cred.uid != getuid() || cred.gid != getgid())) { | |
2dcb28a9 | 284 | INFO("message denied for '%d/%d'", cred.uid, cred.gid); |
d8cc9804 | 285 | return -EACCES; |
2dcb28a9 | 286 | } |
604f0955 | 287 | } |
b0a33c1e | 288 | out: |
604f0955 | 289 | return ret; |
b0a33c1e | 290 | } |