9ef04ee0df1943ce41b4ca886ee2913d27d21619
[lttng-tools.git] / src / common / sessiond-comm / unix.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <assert.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <errno.h>
29
30 #include <common/defaults.h>
31 #include <common/error.h>
32
33 #include "unix.h"
34
35 /*
36 * Connect to unix socket using the path name.
37 */
38 __attribute__((visibility("hidden")))
39 int lttcomm_connect_unix_sock(const char *pathname)
40 {
41 struct sockaddr_un sun;
42 int fd, ret, closeret;
43
44 fd = socket(PF_UNIX, SOCK_STREAM, 0);
45 if (fd < 0) {
46 PERROR("socket");
47 ret = fd;
48 goto error;
49 }
50
51 memset(&sun, 0, sizeof(sun));
52 sun.sun_family = AF_UNIX;
53 strncpy(sun.sun_path, pathname, sizeof(sun.sun_path));
54 sun.sun_path[sizeof(sun.sun_path) - 1] = '\0';
55
56 ret = connect(fd, (struct sockaddr *) &sun, sizeof(sun));
57 if (ret < 0) {
58 /*
59 * Don't print message on connect error, because connect is used in
60 * normal execution to detect if sessiond is alive.
61 */
62 goto error_connect;
63 }
64
65 return fd;
66
67 error_connect:
68 closeret = close(fd);
69 if (closeret) {
70 PERROR("close");
71 }
72 error:
73 return ret;
74 }
75
76 /*
77 * Do an accept(2) on the sock and return the new file descriptor. The socket
78 * MUST be bind(2) before.
79 */
80 __attribute__((visibility("hidden")))
81 int lttcomm_accept_unix_sock(int sock)
82 {
83 int new_fd;
84 struct sockaddr_un sun;
85 socklen_t len = 0;
86
87 /* Blocking call */
88 new_fd = accept(sock, (struct sockaddr *) &sun, &len);
89 if (new_fd < 0) {
90 PERROR("accept");
91 }
92
93 return new_fd;
94 }
95
96 /*
97 * Creates a AF_UNIX local socket using pathname bind the socket upon creation
98 * and return the fd.
99 */
100 __attribute__((visibility("hidden")))
101 int lttcomm_create_unix_sock(const char *pathname)
102 {
103 struct sockaddr_un sun;
104 int fd;
105 int ret = -1;
106
107 /* Create server socket */
108 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
109 PERROR("socket");
110 goto error;
111 }
112
113 memset(&sun, 0, sizeof(sun));
114 sun.sun_family = AF_UNIX;
115 strncpy(sun.sun_path, pathname, sizeof(sun.sun_path));
116 sun.sun_path[sizeof(sun.sun_path) - 1] = '\0';
117
118 /* Unlink the old file if present */
119 (void) unlink(pathname);
120 ret = bind(fd, (struct sockaddr *) &sun, sizeof(sun));
121 if (ret < 0) {
122 PERROR("bind");
123 goto error;
124 }
125
126 return fd;
127
128 error:
129 return ret;
130 }
131
132 /*
133 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
134 */
135 __attribute__((visibility("hidden")))
136 int lttcomm_listen_unix_sock(int sock)
137 {
138 int ret;
139
140 ret = listen(sock, LTTNG_SESSIOND_COMM_MAX_LISTEN);
141 if (ret < 0) {
142 PERROR("listen");
143 }
144
145 return ret;
146 }
147
148 /*
149 * Receive data of size len in put that data into the buf param. Using recvmsg
150 * API.
151 *
152 * Return the size of received data.
153 */
154 __attribute__((visibility("hidden")))
155 ssize_t lttcomm_recv_unix_sock(int sock, void *buf, size_t len)
156 {
157 struct msghdr msg;
158 struct iovec iov[1];
159 ssize_t ret = -1;
160
161 memset(&msg, 0, sizeof(msg));
162
163 iov[0].iov_base = buf;
164 iov[0].iov_len = len;
165 msg.msg_iov = iov;
166 msg.msg_iovlen = 1;
167
168 do {
169 ret = recvmsg(sock, &msg, MSG_WAITALL);
170 } while (ret < 0 && errno == EINTR);
171 if (ret < 0) {
172 PERROR("recvmsg");
173 }
174
175 return ret;
176 }
177
178 /*
179 * Send buf data of size len. Using sendmsg API.
180 *
181 * Return the size of sent data.
182 */
183 __attribute__((visibility("hidden")))
184 ssize_t lttcomm_send_unix_sock(int sock, void *buf, size_t len)
185 {
186 struct msghdr msg;
187 struct iovec iov[1];
188 ssize_t ret = -1;
189
190 memset(&msg, 0, sizeof(msg));
191
192 iov[0].iov_base = buf;
193 iov[0].iov_len = len;
194 msg.msg_iov = iov;
195 msg.msg_iovlen = 1;
196
197 ret = sendmsg(sock, &msg, 0);
198 if (ret < 0) {
199 /*
200 * Only warn about EPIPE when quiet mode is deactivated.
201 * We consider EPIPE as expected.
202 */
203 if (errno != EPIPE || !lttng_opt_quiet) {
204 PERROR("sendmsg");
205 }
206 }
207
208 return ret;
209 }
210
211 /*
212 * Shutdown cleanly a unix socket.
213 */
214 __attribute__((visibility("hidden")))
215 int lttcomm_close_unix_sock(int sock)
216 {
217 int ret, closeret;
218
219 /* Shutdown receptions and transmissions */
220 ret = shutdown(sock, SHUT_RDWR);
221 if (ret < 0) {
222 PERROR("shutdown");
223 }
224
225 closeret = close(sock);
226 if (closeret) {
227 PERROR("close");
228 }
229
230 return ret;
231 }
232
233 /*
234 * Send a message accompanied by fd(s) over a unix socket.
235 *
236 * Returns the size of data sent, or negative error value.
237 */
238 __attribute__((visibility("hidden")))
239 ssize_t lttcomm_send_fds_unix_sock(int sock, int *fds, size_t nb_fd)
240 {
241 struct msghdr msg;
242 struct cmsghdr *cmptr;
243 struct iovec iov[1];
244 ssize_t ret = -1;
245 unsigned int sizeof_fds = nb_fd * sizeof(int);
246 char tmp[CMSG_SPACE(sizeof_fds)];
247 char dummy = 0;
248
249 memset(&msg, 0, sizeof(msg));
250
251 if (nb_fd > LTTCOMM_MAX_SEND_FDS)
252 return -EINVAL;
253
254 msg.msg_control = (caddr_t)tmp;
255 msg.msg_controllen = CMSG_LEN(sizeof_fds);
256
257 cmptr = CMSG_FIRSTHDR(&msg);
258 cmptr->cmsg_level = SOL_SOCKET;
259 cmptr->cmsg_type = SCM_RIGHTS;
260 cmptr->cmsg_len = CMSG_LEN(sizeof_fds);
261 memcpy(CMSG_DATA(cmptr), fds, sizeof_fds);
262 /* Sum of the length of all control messages in the buffer: */
263 msg.msg_controllen = cmptr->cmsg_len;
264
265 iov[0].iov_base = &dummy;
266 iov[0].iov_len = 1;
267 msg.msg_iov = iov;
268 msg.msg_iovlen = 1;
269
270 do {
271 ret = sendmsg(sock, &msg, 0);
272 } while (ret < 0 && errno == EINTR);
273 if (ret < 0) {
274 /*
275 * Only warn about EPIPE when quiet mode is deactivated.
276 * We consider EPIPE as expected.
277 */
278 if (errno != EPIPE || !lttng_opt_quiet) {
279 PERROR("sendmsg");
280 }
281 }
282 return ret;
283 }
284
285 /*
286 * Recv a message accompanied by fd(s) from a unix socket.
287 *
288 * Returns the size of received data, or negative error value.
289 *
290 * Expect at most "nb_fd" file descriptors. Returns the number of fd
291 * actually received in nb_fd.
292 */
293 __attribute__((visibility("hidden")))
294 ssize_t lttcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd)
295 {
296 struct iovec iov[1];
297 ssize_t ret = 0;
298 struct cmsghdr *cmsg;
299 size_t sizeof_fds = nb_fd * sizeof(int);
300 char recv_fd[CMSG_SPACE(sizeof_fds)];
301 struct msghdr msg;
302 char dummy;
303
304 memset(&msg, 0, sizeof(msg));
305
306 /* Prepare to receive the structures */
307 iov[0].iov_base = &dummy;
308 iov[0].iov_len = 1;
309 msg.msg_iov = iov;
310 msg.msg_iovlen = 1;
311 msg.msg_control = recv_fd;
312 msg.msg_controllen = sizeof(recv_fd);
313
314 do {
315 ret = recvmsg(sock, &msg, 0);
316 } while (ret < 0 && errno == EINTR);
317 if (ret < 0) {
318 PERROR("recvmsg fds");
319 goto end;
320 }
321 if (ret != 1) {
322 fprintf(stderr, "Error: Received %zd bytes, expected %d\n",
323 ret, 1);
324 goto end;
325 }
326 if (msg.msg_flags & MSG_CTRUNC) {
327 fprintf(stderr, "Error: Control message truncated.\n");
328 ret = -1;
329 goto end;
330 }
331 cmsg = CMSG_FIRSTHDR(&msg);
332 if (!cmsg) {
333 fprintf(stderr, "Error: Invalid control message header\n");
334 ret = -1;
335 goto end;
336 }
337 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
338 fprintf(stderr, "Didn't received any fd\n");
339 ret = -1;
340 goto end;
341 }
342 if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
343 fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
344 (size_t) cmsg->cmsg_len, (size_t) CMSG_LEN(sizeof_fds));
345 ret = -1;
346 goto end;
347 }
348 memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
349 ret = sizeof_fds;
350 end:
351 return ret;
352 }
353
354 /*
355 * Send a message with credentials over a unix socket.
356 *
357 * Returns the size of data sent, or negative error value.
358 */
359 __attribute__((visibility("hidden")))
360 ssize_t lttcomm_send_creds_unix_sock(int sock, void *buf, size_t len)
361 {
362 struct msghdr msg;
363 struct iovec iov[1];
364 ssize_t ret = -1;
365 #ifdef __linux__
366 struct cmsghdr *cmptr;
367 size_t sizeof_cred = sizeof(lttng_sock_cred);
368 char anc_buf[CMSG_SPACE(sizeof_cred)];
369 lttng_sock_cred *creds;
370 #endif /* __linux__ */
371
372 memset(&msg, 0, sizeof(msg));
373
374 iov[0].iov_base = buf;
375 iov[0].iov_len = len;
376 msg.msg_iov = iov;
377 msg.msg_iovlen = 1;
378
379 #ifdef __linux__
380 msg.msg_control = (caddr_t) anc_buf;
381 msg.msg_controllen = CMSG_LEN(sizeof_cred);
382
383 cmptr = CMSG_FIRSTHDR(&msg);
384 cmptr->cmsg_level = SOL_SOCKET;
385 cmptr->cmsg_type = LTTNG_SOCK_CREDS;
386 cmptr->cmsg_len = CMSG_LEN(sizeof_cred);
387
388 creds = (lttng_sock_cred*) CMSG_DATA(cmptr);
389
390 LTTNG_SOCK_SET_UID_CRED(creds, geteuid());
391 LTTNG_SOCK_SET_GID_CRED(creds, getegid());
392 LTTNG_SOCK_SET_PID_CRED(creds, getpid());
393 #endif /* __linux__ */
394
395 do {
396 ret = sendmsg(sock, &msg, 0);
397 } while (ret < 0 && errno == EINTR);
398 if (ret < 0) {
399 /*
400 * Only warn about EPIPE when quiet mode is deactivated.
401 * We consider EPIPE as expected.
402 */
403 if (errno != EPIPE || !lttng_opt_quiet) {
404 PERROR("sendmsg");
405 }
406 }
407 return ret;
408 }
409
410 /*
411 * Recv a message accompanied with credentials from a unix socket.
412 *
413 * Returns the size of received data, or negative error value.
414 */
415 __attribute__((visibility("hidden")))
416 ssize_t lttcomm_recv_creds_unix_sock(int sock, void *buf, size_t len,
417 lttng_sock_cred *creds)
418 {
419 struct msghdr msg;
420 struct iovec iov[1];
421 ssize_t ret;
422 #ifdef __linux__
423 struct cmsghdr *cmptr;
424 size_t sizeof_cred = sizeof(lttng_sock_cred);
425 char anc_buf[CMSG_SPACE(sizeof_cred)];
426 #endif /* __linux__ */
427
428 memset(&msg, 0, sizeof(msg));
429
430 /* Not allowed */
431 if (creds == NULL) {
432 ret = -1;
433 goto end;
434 }
435
436 /* Prepare to receive the structures */
437 iov[0].iov_base = buf;
438 iov[0].iov_len = len;
439 msg.msg_iov = iov;
440 msg.msg_iovlen = 1;
441
442 #ifdef __linux__
443 msg.msg_control = anc_buf;
444 msg.msg_controllen = sizeof(anc_buf);
445 #endif /* __linux__ */
446
447 do {
448 ret = recvmsg(sock, &msg, 0);
449 } while (ret < 0 && errno == EINTR);
450 if (ret < 0) {
451 PERROR("recvmsg fds");
452 goto end;
453 }
454
455 #ifdef __linux__
456 if (msg.msg_flags & MSG_CTRUNC) {
457 fprintf(stderr, "Error: Control message truncated.\n");
458 ret = -1;
459 goto end;
460 }
461
462 cmptr = CMSG_FIRSTHDR(&msg);
463 if (cmptr == NULL) {
464 fprintf(stderr, "Error: Invalid control message header\n");
465 ret = -1;
466 goto end;
467 }
468
469 if (cmptr->cmsg_level != SOL_SOCKET ||
470 cmptr->cmsg_type != LTTNG_SOCK_CREDS) {
471 fprintf(stderr, "Didn't received any credentials\n");
472 ret = -1;
473 goto end;
474 }
475
476 if (cmptr->cmsg_len != CMSG_LEN(sizeof_cred)) {
477 fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
478 (size_t) cmptr->cmsg_len, (size_t) CMSG_LEN(sizeof_cred));
479 ret = -1;
480 goto end;
481 }
482
483 memcpy(creds, CMSG_DATA(cmptr), sizeof_cred);
484 #elif (defined(__FreeBSD__) || defined(__CYGWIN__))
485 {
486 int peer_ret;
487
488 peer_ret = getpeereid(sock, &creds->uid, &creds->gid);
489 if (peer_ret != 0) {
490 return peer_ret;
491 }
492 }
493 #else
494 #error "Please implement credential support for your OS."
495 #endif /* __linux__ */
496
497 end:
498 return ret;
499 }
500
501 /*
502 * Set socket option to use credentials passing.
503 */
504 #ifdef __linux__
505 __attribute__((visibility("hidden")))
506 int lttcomm_setsockopt_creds_unix_sock(int sock)
507 {
508 int ret, on = 1;
509
510 /* Set socket for credentials retrieval */
511 ret = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
512 if (ret < 0) {
513 PERROR("setsockopt creds unix sock");
514 }
515 return ret;
516 }
517 #elif (defined(__FreeBSD__) || defined(__CYGWIN__))
518 __attribute__((visibility("hidden")))
519 int lttcomm_setsockopt_creds_unix_sock(int sock)
520 {
521 return 0;
522 }
523 #else
524 #error "Please implement credential support for your OS."
525 #endif /* __linux__ */
This page took 0.038121 seconds and 3 git commands to generate.