2 * Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 /* Helper process that runs setuid root or with appropriate privileges to
22 * listen on ports < 1024, do multicast operations and get MAC addresses of
23 * interfaces. Privileges are dropped after these operations are done.
25 * It listens on the PTP multicast group on port 319 and 320 and forwards
26 * everything received there to stdout, while forwarding everything received
27 * on stdout to those sockets.
28 * Additionally it provides the MAC address of a network interface via stdout
37 #include <sys/types.h>
39 #include <sys/ioctl.h>
41 #include <netinet/in.h>
44 #ifdef HAVE_GETIFADDRS_AF_LINK
46 #include <net/if_dl.h>
49 #ifdef HAVE_PTP_HELPER_SETUID
54 #ifdef HAVE_PTP_HELPER_CAPABILITIES
55 #include <sys/capability.h>
62 #include <gst/net/gstptp_private.h>
64 #define PTP_MULTICAST_GROUP "224.0.1.129"
65 #define PTP_EVENT_PORT 319
66 #define PTP_GENERAL_PORT 320
68 static gchar **ifaces = NULL;
69 static gboolean verbose = FALSE;
70 static guint64 clock_id = (guint64) - 1;
71 static guint8 clock_id_array[8];
73 static GOptionEntry opt_entries[] = {
74 {"interface", 'i', 0, G_OPTION_ARG_STRING_ARRAY, &ifaces,
75 "Interface to listen on", NULL},
76 {"clock-id", 'c', 0, G_OPTION_ARG_INT64, &clock_id,
77 "PTP clock id", NULL},
78 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
83 static GSocketAddress *event_saddr, *general_saddr;
84 static GSocket *socket_event, *socket_general;
85 static GIOChannel *stdin_channel, *stdout_channel;
88 have_socket_data_cb (GSocket * socket, GIOCondition condition,
96 StdIOHeader header = { 0, };
98 read = g_socket_receive (socket, buffer, sizeof (buffer), NULL, &err);
100 g_error ("Failed to read from socket: %s", err->message);
101 g_clear_error (&err);
104 g_message ("Received %" G_GSSIZE_FORMAT " bytes from %s socket", read,
105 (socket == socket_event ? "event" : "general"));
108 header.type = (socket == socket_event) ? TYPE_EVENT : TYPE_GENERAL;
111 g_io_channel_write_chars (stdout_channel, (gchar *) & header,
112 sizeof (header), &written, &err);
113 if (status == G_IO_STATUS_ERROR) {
114 g_error ("Failed to write to stdout: %s", err->message);
115 g_clear_error (&err);
116 } else if (status == G_IO_STATUS_EOF) {
117 g_message ("EOF on stdout");
119 } else if (status != G_IO_STATUS_NORMAL) {
120 g_error ("Unexpected stdout write status: %d", status);
121 } else if (written != sizeof (header)) {
122 g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
126 g_io_channel_write_chars (stdout_channel, buffer, read, &written, &err);
127 if (status == G_IO_STATUS_ERROR) {
128 g_error ("Failed to write to stdout: %s", err->message);
129 g_clear_error (&err);
130 } else if (status == G_IO_STATUS_EOF) {
131 g_message ("EOF on stdout");
133 } else if (status != G_IO_STATUS_NORMAL) {
134 g_error ("Unexpected stdout write status: %d", status);
135 } else if (written != read) {
136 g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
139 return G_SOURCE_CONTINUE;
143 have_stdin_data_cb (GIOChannel * channel, GIOCondition condition,
147 StdIOHeader header = { 0, };
153 if ((condition & G_IO_STATUS_EOF)) {
154 g_message ("EOF on stdin");
159 g_io_channel_read_chars (channel, (gchar *) & header, sizeof (header),
161 if (status == G_IO_STATUS_ERROR) {
162 g_error ("Failed to read from stdin: %s", err->message);
163 g_clear_error (&err);
164 } else if (status == G_IO_STATUS_EOF) {
165 g_message ("EOF on stdin");
167 } else if (status != G_IO_STATUS_NORMAL) {
168 g_error ("Unexpected stdin read status: %d", status);
169 } else if (read != sizeof (header)) {
170 g_error ("Unexpected read size: %" G_GSIZE_FORMAT, read);
171 } else if (header.size > 8192) {
172 g_error ("Unexpected size: %u", header.size);
175 status = g_io_channel_read_chars (channel, buffer, header.size, &read, &err);
176 if (status == G_IO_STATUS_ERROR) {
177 g_error ("Failed to read from stdin: %s", err->message);
178 g_clear_error (&err);
179 } else if (status == G_IO_STATUS_EOF) {
180 g_message ("EOF on stdin");
182 } else if (status != G_IO_STATUS_NORMAL) {
183 g_error ("Unexpected stdin read status: %d", status);
184 } else if (read != header.size) {
185 g_error ("Unexpected read size: %" G_GSIZE_FORMAT, read);
188 switch (header.type) {
192 g_socket_send_to (header.type ==
193 TYPE_EVENT ? socket_event : socket_general,
194 (header.type == TYPE_EVENT ? event_saddr : general_saddr), buffer,
195 header.size, NULL, &err);
197 g_error ("Failed to write to socket: %s", err->message);
198 else if (written != header.size)
199 g_error ("Unexpected write size: %" G_GSSIZE_FORMAT, written);
200 g_clear_error (&err);
202 g_message ("Sent %" G_GSSIZE_FORMAT " bytes to %s socket", read,
203 (header.type == TYPE_EVENT ? "event" : "general"));
209 return G_SOURCE_CONTINUE;
215 GInetAddress *bind_addr, *mcast_addr;
216 GSocketAddress *bind_saddr;
217 GSource *socket_event_source, *socket_general_source;
218 gchar **probed_ifaces = NULL;
223 g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
224 G_SOCKET_PROTOCOL_UDP, &err);
226 g_error ("Couldn't create event socket: %s", err->message);
227 g_clear_error (&err);
230 g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
231 G_SOCKET_PROTOCOL_UDP, &err);
233 g_error ("Couldn't create general socket: %s", err->message);
234 g_clear_error (&err);
237 bind_addr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
238 bind_saddr = g_inet_socket_address_new (bind_addr, PTP_EVENT_PORT);
239 if (!g_socket_bind (socket_event, bind_saddr, TRUE, &err))
240 g_error ("Couldn't bind event socket: %s", err->message);
241 g_object_unref (bind_saddr);
242 bind_saddr = g_inet_socket_address_new (bind_addr, PTP_GENERAL_PORT);
243 if (!g_socket_bind (socket_general, bind_saddr, TRUE, &err))
244 g_error ("Couldn't bind general socket: %s", err->message);
245 g_object_unref (bind_saddr);
246 g_object_unref (bind_addr);
248 /* Probe all non-loopback interfaces */
250 #if defined(HAVE_SIOCGIFCONF_SIOCGIFFLAGS_SIOCGIFHWADDR)
255 ifc.ifc_len = sizeof (buf);
257 if (ioctl (g_socket_get_fd (socket_event), SIOCGIFCONF, &ifc) != -1) {
260 probed_ifaces = g_new0 (gchar *, ifc.ifc_len + 1);
262 for (i = 0; i < ifc.ifc_len / sizeof (struct ifreq); i++) {
263 strncpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name, IFNAMSIZ);
264 if (ioctl (g_socket_get_fd (socket_event), SIOCGIFFLAGS, &ifr) == 0) {
265 if ((ifr.ifr_flags & IFF_LOOPBACK))
267 probed_ifaces[idx] = g_strndup (ifc.ifc_req[i].ifr_name, IFNAMSIZ);
270 g_warning ("can't get flags of interface '%s'",
271 ifc.ifc_req[i].ifr_name);
272 probed_ifaces[idx] = g_strndup (ifc.ifc_req[i].ifr_name, IFNAMSIZ);
276 ifaces = probed_ifaces;
279 #elif defined(HAVE_GETIFADDRS_AF_LINK)
280 struct ifaddrs *ifaddr, *ifa;
282 if (getifaddrs (&ifaddr) != -1) {
285 arr = g_ptr_array_new ();
287 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
288 if ((ifa->ifa_flags & IFF_LOOPBACK))
291 if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_LINK)
294 g_ptr_array_add (arr, g_strdup (ifa->ifa_name));
296 freeifaddrs (ifaddr);
298 g_ptr_array_add (arr, NULL);
299 ifaces = probed_ifaces = (gchar **) g_ptr_array_free (arr, FALSE);
302 #warning "Implement something to list all network interfaces"
306 /* Get a clock id from the MAC address if none was given */
307 if (clock_id == (guint64) - 1) {
308 gboolean success = FALSE;
310 #if defined(HAVE_SIOCGIFCONF_SIOCGIFFLAGS_SIOCGIFHWADDR)
314 gchar **ptr = ifaces;
317 strncpy (ifr.ifr_name, *ptr, IFNAMSIZ);
318 if (ioctl (g_socket_get_fd (socket_event), SIOCGIFHWADDR, &ifr) == 0) {
319 clock_id_array[0] = ifr.ifr_hwaddr.sa_data[0];
320 clock_id_array[1] = ifr.ifr_hwaddr.sa_data[1];
321 clock_id_array[2] = ifr.ifr_hwaddr.sa_data[2];
322 clock_id_array[3] = 0xff;
323 clock_id_array[4] = 0xfe;
324 clock_id_array[5] = ifr.ifr_hwaddr.sa_data[3];
325 clock_id_array[6] = ifr.ifr_hwaddr.sa_data[4];
326 clock_id_array[7] = ifr.ifr_hwaddr.sa_data[5];
337 ifc.ifc_len = sizeof (buf);
339 if (ioctl (g_socket_get_fd (socket_event), SIOCGIFCONF, &ifc) != -1) {
342 for (i = 0; i < ifc.ifc_len / sizeof (struct ifreq); i++) {
343 strncpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name, IFNAMSIZ);
344 if (ioctl (g_socket_get_fd (socket_event), SIOCGIFFLAGS, &ifr) == 0) {
345 if ((ifr.ifr_flags & IFF_LOOPBACK))
348 if (ioctl (g_socket_get_fd (socket_event), SIOCGIFHWADDR,
350 clock_id_array[0] = ifr.ifr_hwaddr.sa_data[0];
351 clock_id_array[1] = ifr.ifr_hwaddr.sa_data[1];
352 clock_id_array[2] = ifr.ifr_hwaddr.sa_data[2];
353 clock_id_array[3] = 0xff;
354 clock_id_array[4] = 0xfe;
355 clock_id_array[5] = ifr.ifr_hwaddr.sa_data[3];
356 clock_id_array[6] = ifr.ifr_hwaddr.sa_data[4];
357 clock_id_array[7] = ifr.ifr_hwaddr.sa_data[5];
362 g_warning ("can't get flags of interface '%s'",
363 ifc.ifc_req[i].ifr_name);
368 #elif defined(HAVE_GETIFADDRS_AF_LINK)
369 struct ifaddrs *ifaddr, *ifa;
371 if (getifaddrs (&ifaddr) != -1) {
372 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
373 struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
376 if ((ifa->ifa_flags & IFF_LOOPBACK))
379 if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_LINK)
384 gboolean found = FALSE;
387 if (strcmp (*p, ifa->ifa_name) == 0) {
398 if (sdl->sdl_alen != 6)
401 memcpy (mac_addr, LLADDR (sdl), sdl->sdl_alen);
403 clock_id_array[0] = mac_addr[0];
404 clock_id_array[1] = mac_addr[1];
405 clock_id_array[2] = mac_addr[2];
406 clock_id_array[3] = 0xff;
407 clock_id_array[4] = 0xfe;
408 clock_id_array[5] = mac_addr[3];
409 clock_id_array[6] = mac_addr[4];
410 clock_id_array[7] = mac_addr[5];
415 freeifaddrs (ifaddr);
418 #warning "Implement something to get MAC addresses of network interfaces"
422 g_warning ("can't get any MAC address, using random clock id");
423 clock_id = (((guint64) g_random_int ()) << 32) | (g_random_int ());
424 GST_WRITE_UINT64_BE (clock_id_array, clock_id);
425 clock_id_array[3] = 0xff;
426 clock_id_array[4] = 0xfe;
429 GST_WRITE_UINT64_BE (clock_id_array, clock_id);
432 /* Join multicast groups */
433 mcast_addr = g_inet_address_new_from_string (PTP_MULTICAST_GROUP);
435 gchar **ptr = ifaces;
436 gboolean success = FALSE;
440 if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, *ptr,
442 && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE))
443 g_warning ("Couldn't join multicast group on interface '%s': %s", *ptr,
447 g_clear_error (&err);
449 if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE,
451 && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE))
452 g_warning ("Couldn't join multicast group on interface '%s': %s", *ptr,
456 g_clear_error (&err);
464 /* Join multicast group without any interface */
465 if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, NULL,
467 g_error ("Couldn't join multicast group: %s", err->message);
468 g_clear_error (&err);
469 if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE,
471 g_error ("Couldn't join multicast group: %s", err->message);
472 g_clear_error (&err);
475 /* Join multicast group without any interface */
476 if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, NULL,
478 g_error ("Couldn't join multicast group: %s", err->message);
479 g_clear_error (&err);
480 if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE, NULL,
482 g_error ("Couldn't join multicast group: %s", err->message);
483 g_clear_error (&err);
486 event_saddr = g_inet_socket_address_new (mcast_addr, PTP_EVENT_PORT);
487 general_saddr = g_inet_socket_address_new (mcast_addr, PTP_GENERAL_PORT);
489 /* Create socket sources */
490 socket_event_source =
491 g_socket_create_source (socket_event, G_IO_IN | G_IO_PRI, NULL);
492 g_source_set_priority (socket_event_source, G_PRIORITY_HIGH);
493 g_source_set_callback (socket_event_source, (GSourceFunc) have_socket_data_cb,
495 g_source_attach (socket_event_source, NULL);
496 socket_general_source =
497 g_socket_create_source (socket_general, G_IO_IN | G_IO_PRI, NULL);
498 g_source_set_priority (socket_general_source, G_PRIORITY_DEFAULT);
499 g_source_set_callback (socket_general_source,
500 (GSourceFunc) have_socket_data_cb, NULL, NULL);
501 g_source_attach (socket_general_source, NULL);
503 g_strfreev (probed_ifaces);
507 drop_privileges (void)
509 #ifdef HAVE_PTP_HELPER_SETUID
510 /* Switch to the given user/group */
511 #ifdef HAVE_PTP_HELPER_SETUID_GROUP
515 grp = getgrnam (HAVE_PTP_HELPER_SETUID_GROUP);
517 g_error ("Failed to get group information '%s': %s",
518 HAVE_PTP_HELPER_SETUID_GROUP, g_strerror (errno));
520 if (setgid (grp->gr_gid) != 0)
521 g_error ("Failed to change to group '%s': %s",
522 HAVE_PTP_HELPER_SETUID_GROUP, g_strerror (errno));
526 #ifdef HAVE_PTP_HELPER_SETUID_USER
530 pwd = getpwnam (HAVE_PTP_HELPER_SETUID_USER);
532 g_error ("Failed to get user information '%s': %s",
533 HAVE_PTP_HELPER_SETUID_USER, g_strerror (errno));
535 #ifndef HAVE_PTP_HELPER_SETUID_GROUP
536 if (setgid (pwd->pw_gid) != 0)
537 g_error ("Failed to change to user group '%s': %s",
538 HAVE_PTP_HELPER_SETUID_USER, g_strerror (errno));
541 if (setuid (pwd->pw_uid) != 0)
542 g_error ("Failed to change to user '%s': %s", HAVE_PTP_HELPER_SETUID_USER,
547 #ifdef HAVE_PTP_HELPER_CAPABILITIES
548 /* Drop all capabilities */
552 caps = cap_get_proc ();
554 g_error ("Failed to get process caps: %s", g_strerror (errno));
555 if (cap_clear (caps) != 0)
556 g_error ("Failed to clear caps: %s", g_strerror (errno));
557 if (cap_set_proc (caps) != 0)
558 g_error ("Failed to set process caps: %s", g_strerror (errno));
564 setup_stdio_channels (void)
566 GSource *stdin_source;
568 /* Create stdin source */
569 stdin_channel = g_io_channel_unix_new (STDIN_FILENO);
570 if (g_io_channel_set_encoding (stdin_channel, NULL,
571 NULL) == G_IO_STATUS_ERROR)
572 g_error ("Failed to set stdin to binary encoding");
573 g_io_channel_set_buffered (stdin_channel, FALSE);
575 g_io_create_watch (stdin_channel, G_IO_IN | G_IO_PRI | G_IO_HUP);
576 g_source_set_priority (stdin_source, G_PRIORITY_DEFAULT);
577 g_source_set_callback (stdin_source, (GSourceFunc) have_stdin_data_cb, NULL,
579 g_source_attach (stdin_source, NULL);
581 /* Create stdout channel */
582 stdout_channel = g_io_channel_unix_new (STDOUT_FILENO);
583 if (g_io_channel_set_encoding (stdout_channel, NULL,
584 NULL) == G_IO_STATUS_ERROR)
585 g_error ("Failed to set stdout to binary encoding");
586 g_io_channel_set_buffered (stdout_channel, FALSE);
590 write_clock_id (void)
594 StdIOHeader header = { 0, };
597 /* Write clock id to stdout */
599 header.type = TYPE_CLOCK_ID;
602 g_io_channel_write_chars (stdout_channel, (gchar *) & header,
603 sizeof (header), &written, &err);
604 if (status == G_IO_STATUS_ERROR) {
605 g_error ("Failed to write to stdout: %s", err->message);
606 g_clear_error (&err);
607 } else if (status == G_IO_STATUS_EOF) {
608 g_message ("EOF on stdout");
610 } else if (status != G_IO_STATUS_NORMAL) {
611 g_error ("Unexpected stdout write status: %d", status);
612 } else if (written != sizeof (header)) {
613 g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
617 g_io_channel_write_chars (stdout_channel,
618 (const gchar *) clock_id_array, sizeof (clock_id_array), &written, &err);
619 if (status == G_IO_STATUS_ERROR) {
620 g_error ("Failed to write to stdout: %s", err->message);
621 g_clear_error (&err);
622 } else if (status == G_IO_STATUS_EOF) {
623 g_message ("EOF on stdout");
625 } else if (status != G_IO_STATUS_NORMAL) {
626 g_error ("Unexpected stdout write status: %d", status);
627 } else if (written != sizeof (clock_id_array)) {
628 g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
634 dummy_poll (GPollFD * fds, guint nfds, gint timeout)
636 return g_poll (fds, nfds, timeout);
641 main (gint argc, gchar ** argv)
643 GOptionContext *opt_ctx;
647 /* FIXME: Work around some side effects of the changes from
648 * https://bugzilla.gnome.org/show_bug.cgi?id=741054
650 * The modified poll function somehow calls setugid(), which
651 * then abort()s the application. Make sure that we use g_poll()
656 GMainContext *context = g_main_context_default ();
657 g_main_context_set_poll_func (context, dummy_poll);
661 #ifdef HAVE_PTP_HELPER_SETUID
663 g_error ("not running with superuser privileges");
666 opt_ctx = g_option_context_new ("- GStreamer PTP helper process");
667 g_option_context_add_main_entries (opt_ctx, opt_entries, NULL);
668 if (!g_option_context_parse (opt_ctx, &argc, &argv, &err))
669 g_error ("Error parsing options: %s", err->message);
670 g_clear_error (&err);
671 g_option_context_free (opt_ctx);
675 setup_stdio_channels ();
679 loop = g_main_loop_new (NULL, FALSE);
680 g_main_loop_run (loop);
682 /* We never exit cleanly, so don't do cleanup */
683 g_assert_not_reached ();