11/*
22 * SPDX-License-Identifier: ISC
33 *
4- * Copyright (c) 2009-2024 Todd C. Miller <[email protected] > 4+ * Copyright (c) 2009-2025 Todd C. Miller <[email protected] > 55 *
66 * Permission to use, copy, modify, and distribute this software for any
77 * purpose with or without fee is hereby granted, provided that the above
@@ -63,44 +63,6 @@ static void sync_ttysize(struct exec_closure *ec);
6363static void schedule_signal (struct exec_closure * ec , int signo );
6464static void send_command_status (struct exec_closure * ec , int type , int val );
6565
66- /*
67- * Allocate a pty if /dev/tty is a tty.
68- * Fills in io_fds[SFD_USERTTY], io_fds[SFD_LEADER] and io_fds[SFD_FOLLOWER].
69- * Returns the dynamically allocated pty name on success, NULL on failure.
70- */
71- static char *
72- pty_setup (struct command_details * details )
73- {
74- char * ptyname = NULL ;
75- debug_decl (pty_setup , SUDO_DEBUG_EXEC );
76-
77- io_fds [SFD_USERTTY ] = open (_PATH_TTY , O_RDWR );
78- if (io_fds [SFD_USERTTY ] == -1 ) {
79- sudo_debug_printf (SUDO_DEBUG_INFO , "%s: no %s, not allocating a pty" ,
80- __func__ , _PATH_TTY );
81- debug_return_ptr (NULL );
82- }
83-
84- ptyname = get_pty (& io_fds [SFD_LEADER ], & io_fds [SFD_FOLLOWER ],
85- details -> cred .euid );
86- if (ptyname == NULL )
87- sudo_fatal ("%s" , U_ ("unable to allocate pty" ));
88-
89- /* Add entry to utmp/utmpx? */
90- if (ISSET (details -> flags , CD_SET_UTMP ))
91- utmp_login (details -> tty , ptyname , io_fds [SFD_FOLLOWER ], details -> utmp_user );
92-
93- /* Update tty name in command details (used by monitor, SELinux, AIX). */
94- details -> tty = ptyname ;
95-
96- sudo_debug_printf (SUDO_DEBUG_INFO ,
97- "%s: %s fd %d, pty leader fd %d, pty follower fd %d" ,
98- __func__ , _PATH_TTY , io_fds [SFD_USERTTY ], io_fds [SFD_LEADER ],
99- io_fds [SFD_FOLLOWER ]);
100-
101- debug_return_str (ptyname );
102- }
103-
10466/*
10567 * Restore user's terminal settings and update utmp, as needed.
10668 */
@@ -136,6 +98,49 @@ pty_cleanup_hook(void)
13698 pty_cleanup (& pty_ec , 0 );
13799}
138100
101+ /*
102+ * Allocate a pty if /dev/tty is a tty.
103+ * Fills in io_fds[SFD_USERTTY], io_fds[SFD_LEADER] and io_fds[SFD_FOLLOWER].
104+ * Returns the dynamically allocated pty name on success, NULL on failure.
105+ */
106+ static bool
107+ pty_setup (struct exec_closure * ec )
108+ {
109+ struct command_details * details = ec -> details ;
110+ debug_decl (pty_setup , SUDO_DEBUG_EXEC );
111+
112+ io_fds [SFD_USERTTY ] = open (_PATH_TTY , O_RDWR );
113+ if (io_fds [SFD_USERTTY ] == -1 ) {
114+ sudo_debug_printf (SUDO_DEBUG_INFO , "%s: no %s, not allocating a pty" ,
115+ __func__ , _PATH_TTY );
116+ debug_return_bool (false);
117+ }
118+
119+ ec -> ptyname = get_pty (& io_fds [SFD_LEADER ], & io_fds [SFD_FOLLOWER ],
120+ details -> cred .euid );
121+ if (ec -> ptyname == NULL )
122+ sudo_fatal ("%s" , U_ ("unable to allocate pty" ));
123+
124+ /* Add entry to utmp/utmpx? */
125+ if (ISSET (details -> flags , CD_SET_UTMP )) {
126+ utmp_login (details -> tty , ec -> ptyname , io_fds [SFD_FOLLOWER ],
127+ details -> utmp_user );
128+ }
129+
130+ /* Update tty name in command details (used by monitor, SELinux, AIX). */
131+ details -> tty = ec -> ptyname ;
132+
133+ /* Register cleanup function. */
134+ sudo_fatal_callback_register (pty_cleanup_hook );
135+
136+ sudo_debug_printf (SUDO_DEBUG_INFO ,
137+ "%s: %s fd %d, pty leader fd %d, pty follower fd %d" ,
138+ __func__ , _PATH_TTY , io_fds [SFD_USERTTY ], io_fds [SFD_LEADER ],
139+ io_fds [SFD_FOLLOWER ]);
140+
141+ debug_return_bool (true);
142+ }
143+
139144/*
140145 * Check whether sudo is running in the foreground.
141146 * Updates the foreground flag in the closure.
@@ -956,16 +961,14 @@ fwdchannel_cb(int sock, int what, void *v)
956961}
957962
958963/*
959- * Fill in the exec closure and setup initial exec events.
960- * Allocates events for the signal pipe and backchannel.
961- * Forwarded signals on the backchannel are enabled on demand.
964+ * Fill in the non-event part of the exec closure.
962965 */
963966static void
964- fill_exec_closure (struct exec_closure * ec , struct command_status * cstat ,
967+ init_exec_closure (struct exec_closure * ec , struct command_status * cstat ,
965968 struct command_details * details , const struct user_details * user_details ,
966- struct sudo_event_base * evbase , pid_t sudo_pid , pid_t ppgrp , int backchannel )
969+ pid_t sudo_pid , pid_t ppgrp )
967970{
968- debug_decl (fill_exec_closure , SUDO_DEBUG_EXEC );
971+ debug_decl (init_exec_closure , SUDO_DEBUG_EXEC );
969972
970973 /* Fill in the non-event part of the closure. */
971974 ec -> sudo_pid = sudo_pid ;
@@ -976,9 +979,18 @@ fill_exec_closure(struct exec_closure *ec, struct command_status *cstat,
976979 ec -> rows = user_details -> ts_rows ;
977980 ec -> cols = user_details -> ts_cols ;
978981
979- /* Reset cstat for running the command. */
980- cstat -> type = CMD_INVALID ;
981- cstat -> val = 0 ;
982+ debug_return ;
983+ }
984+
985+ /*
986+ * Allocate and set events for the signal pipe and backchannel.
987+ * Forwarded signals on the backchannel are enabled on demand.
988+ */
989+ static void
990+ init_exec_events (struct exec_closure * ec , struct sudo_event_base * evbase ,
991+ int backchannel )
992+ {
993+ debug_decl (init_exec_events , SUDO_DEBUG_EXEC );
982994
983995 /* Setup event base and events. */
984996 ec -> evbase = evbase ;
@@ -1099,23 +1111,22 @@ exec_pty(struct command_details *details,
10991111 int sv [2 ], intercept_sv [2 ] = { -1 , -1 };
11001112 struct exec_closure * ec = & pty_ec ;
11011113 struct plugin_container * plugin ;
1114+ const pid_t sudo_pid = getpid ();
1115+ const pid_t ppgrp = getpgrp ();
11021116 int evloop_retries = -1 ;
11031117 bool cmnd_foreground ;
11041118 sigset_t set , oset ;
11051119 struct sigaction sa ;
1106- pid_t ppgrp , sudo_pid ;
11071120 debug_decl (exec_pty , SUDO_DEBUG_EXEC );
11081121
11091122 /*
1110- * Allocate a pty if sudo is running in a terminal.
1123+ * Allocate a pty if sudo is running in a terminal. The exec
1124+ * closure must be set for pty_setup() and pty_cleanup_hook().
11111125 */
1112- ec -> ptyname = pty_setup ( details );
1113- if (ec -> ptyname == NULL )
1126+ init_exec_closure ( ec , cstat , details , user_details , sudo_pid , ppgrp );
1127+ if (! pty_setup ( ec ) )
11141128 debug_return_bool (false);
11151129
1116- /* Register cleanup function */
1117- sudo_fatal_callback_register (pty_cleanup_hook );
1118-
11191130 /*
11201131 * We communicate with the monitor over a bi-directional pair of sockets.
11211132 * Parent sends signal info to monitor and monitor sends back wait status.
@@ -1161,8 +1172,6 @@ exec_pty(struct command_details *details,
11611172 * to and from pty.
11621173 */
11631174 init_ttyblock ();
1164- ppgrp = getpgrp (); /* parent's pgrp, so child can signal us */
1165- sudo_pid = getpid ();
11661175
11671176 /* Determine whether any of std{in,out,err} should be logged. */
11681177 TAILQ_FOREACH (plugin , & io_plugins , entries ) {
@@ -1400,12 +1409,8 @@ exec_pty(struct command_details *details,
14001409 if (ISSET (details -> flags , CD_SET_TIMEOUT ))
14011410 alarm (details -> timeout );
14021411
1403- /*
1404- * Fill in exec closure, allocate event base, signal events and
1405- * the backchannel event.
1406- */
1407- fill_exec_closure (ec , cstat , details , user_details , evbase ,
1408- sudo_pid , ppgrp , sv [0 ]);
1412+ /* Allocate and set signal events and the backchannel event. */
1413+ init_exec_events (ec , evbase , sv [0 ]);
14091414
14101415 /* Create event and closure for intercept mode. */
14111416 if (ISSET (details -> flags , CD_INTERCEPT |CD_LOG_SUBCMDS )) {
@@ -1414,6 +1419,10 @@ exec_pty(struct command_details *details,
14141419 terminate_command (ec -> cmnd_pid , true);
14151420 }
14161421
1422+ /* Reset cstat for running the command. */
1423+ cstat -> type = CMD_INVALID ;
1424+ cstat -> val = 0 ;
1425+
14171426 /* Restore signal mask now that signal handlers are setup. */
14181427 sigprocmask (SIG_SETMASK , & oset , NULL );
14191428
0 commit comments