Created
November 30, 2018 14:49
-
-
Save wjt/2692a39c42151b99fecd246910ca679b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ptygoop: ptygoop.c Makefile | |
| gcc -o $@ $< `pkg-config --cflags --libs glib-2.0` -Wall -Wextra -Werror |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define _GNU_SOURCE | |
| #include <errno.h> | |
| #include <fcntl.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <sys/ioctl.h> | |
| #include <sys/types.h> | |
| #include <sys/wait.h> | |
| #include <termios.h> | |
| #include <unistd.h> | |
| #include <glib.h> | |
| static void | |
| set_controlling_tty_to_stdin (void *user_data G_GNUC_UNUSED) | |
| { | |
| setsid (); | |
| ioctl (0, TIOCSCTTY, 0); | |
| /* If this ioctl isn't supported, the other approach is to (re-)open() the | |
| * PTY slave device (without O_NOCTTY) | |
| */ | |
| } | |
| int | |
| main (int argc G_GNUC_UNUSED, | |
| char **argv G_GNUC_UNUSED) | |
| { | |
| g_autoptr(GError) error = NULL; | |
| /* Open the master & slave sides of a PTY pair */ | |
| int pt_master = posix_openpt (O_RDWR | O_NOCTTY); | |
| if (pt_master < 0) | |
| perror ("posix_openpt"); | |
| if (unlockpt (pt_master) < 0) | |
| perror ("unlockpt"); | |
| char *pt_slave_name = ptsname (pt_master); | |
| int pt_slave = open (pt_slave_name, O_RDWR); | |
| if (pt_slave < 0) | |
| perror ("open pt_slave_name"); | |
| /* Spawn a privileged worker process, setting its stdin to the slave side of | |
| * the PTY. | |
| */ | |
| char *sleep_argv[] = { "/usr/bin/pkexec", "dbus-monitor", "--system", NULL }; | |
| GPid child_pid = -1; | |
| gboolean ret = g_spawn_async_with_fds (NULL, | |
| sleep_argv, | |
| NULL, | |
| G_SPAWN_DO_NOT_REAP_CHILD, | |
| set_controlling_tty_to_stdin, | |
| NULL, | |
| &child_pid, | |
| pt_slave, | |
| -1, | |
| -1, | |
| &error); | |
| g_assert_no_error (error); | |
| g_assert_true (ret); | |
| /* Give the user time to approve the polkit request */ | |
| g_message ("spawned %d; please approve the polkit request quickly!", child_pid); | |
| g_usleep (30 * G_USEC_PER_SEC); | |
| /* signal (child_pid, SIGINT) would fail with EPERM because the target is | |
| * running as a different uid (and we are not root), but we can send ^C over | |
| * the TTY and the kernel will do what has to be done. | |
| */ | |
| g_message ("Sending ^C to %d via PTY", child_pid); | |
| char ctrl_c = '\x03'; | |
| if (write (pt_master, &ctrl_c, 1) != 1) | |
| perror ("write"); | |
| int wstatus; | |
| if (waitpid (child_pid, &wstatus, 0) < 0) | |
| perror ("waitpid"); | |
| else if (WIFEXITED (wstatus)) | |
| g_message ("exited %d", WEXITSTATUS (wstatus)); | |
| else if (WIFSIGNALED (wstatus) && WTERMSIG (wstatus) != SIGINT) | |
| g_message ("signalled %d (expected %d)", WTERMSIG (wstatus), SIGINT); | |
| else if (WIFSIGNALED (wstatus)) | |
| g_message ("signalled %d, as hoped", WTERMSIG (wstatus)); | |
| else | |
| g_message ("weird hex but ok %x", wstatus); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment