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