Skip to content

Instantly share code, notes, and snippets.

@wjt
Created November 30, 2018 14:49
Show Gist options
  • Select an option

  • Save wjt/2692a39c42151b99fecd246910ca679b to your computer and use it in GitHub Desktop.

Select an option

Save wjt/2692a39c42151b99fecd246910ca679b to your computer and use it in GitHub Desktop.
ptygoop: ptygoop.c Makefile
gcc -o $@ $< `pkg-config --cflags --libs glib-2.0` -Wall -Wextra -Werror
#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