1 // This file is part of libptytty. Do not make local modifications.
2 // http://software.schmorp.de/pkg/libptytty
4 /*----------------------------------------------------------------------*
6 *----------------------------------------------------------------------*
8 * All portions of code are copyright by their respective author/s.
9 * Copyright (c) 2006 Marc Lehmann <pcg@goof.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *---------------------------------------------------------------------*/
26 #include "../config.h"
34 #include <sys/types.h>
35 #include <sys/socket.h>
40 // helper/proxy support
44 static int sock_fd = -1, lock_fd = -1;
45 static int helper_pid, owner_pid;
49 enum { get, login, destroy } type;
55 char hostname[512]; // arbitrary, but should be plenty
58 struct ptytty_proxy : ptytty
70 void login (int cmd_pid, bool login_shell, const char *hostname);
74 # define NEED_TOKEN do { char ch; read (lock_fd, &ch, 1); } while (0)
75 # define GIVE_TOKEN do { char ch; write (lock_fd, &ch, 1); } while (0)
77 # define NEED_TOKEN (void)0
78 # define GIVE_TOKEN (void)0
88 cmd.type = command::get;
90 write (sock_fd, &cmd, sizeof (cmd));
92 if (read (sock_fd, &id, sizeof (id)) != sizeof (id))
93 ptytty_fatal ("protocol error while creating pty using helper process, aborting.\n");
101 if ((pty = recv_fd (sock_fd)) < 0
102 || (tty = recv_fd (sock_fd)) < 0)
103 ptytty_fatal ("protocol error while reading pty/tty fds from helper process, aborting.\n");
110 ptytty_proxy::login (int cmd_pid, bool login_shell, const char *hostname)
116 cmd.type = command::login;
118 cmd.cmd_pid = cmd_pid;
119 cmd.login_shell = login_shell;
120 strncpy (cmd.hostname, hostname, sizeof (cmd.hostname));
122 write (sock_fd, &cmd, sizeof (cmd));
127 ptytty_proxy::~ptytty_proxy ()
140 cmd.type = command::destroy;
143 write (sock_fd, &cmd, sizeof (cmd));
153 vector<ptytty *> ptys;
159 if (read (sock_fd, &cmd, sizeof (command)) != sizeof (command))
162 if (cmd.type == command::get)
165 cmd.id = new ptytty_unix;
169 write (sock_fd, &cmd.id, sizeof (cmd.id));
170 ptys.push_back (cmd.id);
172 ptytty::send_fd (sock_fd, cmd.id->pty);
173 ptytty::send_fd (sock_fd, cmd.id->tty);
179 write (sock_fd, &cmd.id, sizeof (cmd.id));
182 else if (cmd.type == command::login)
185 if (find (ptys.begin (), ptys.end (), cmd.id) != ptys.end ())
187 cmd.hostname[sizeof (cmd.hostname) - 1] = 0;
188 cmd.id->login (cmd.cmd_pid, cmd.login_shell, cmd.hostname);
192 else if (cmd.type == command::destroy)
194 vector<ptytty *>::iterator pty = find (ptys.begin (), ptys.end (), cmd.id);
196 if (pty != ptys.end ())
209 for (vector<ptytty *>::iterator i = ptys.end (); i-- > ptys.begin (); )
214 ptytty::use_helper ()
216 #ifndef PTYTTY_NO_PID_CHECK
221 #ifndef PTYTTY_NO_PID_CHECK
227 #ifndef PTYTTY_NO_PID_CHECK
233 if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv))
234 ptytty_fatal ("could not create socket to communicate with pty/sessiondb helper, aborting.\n");
236 #ifdef PTYTTY_REENTRANT
239 if (socketpair (AF_UNIX, SOCK_STREAM, 0, lv))
240 ptytty_fatal ("could not create socket to communicate with pty/sessiondb helper, aborting.\n");
243 helper_pid = fork ();
246 ptytty_fatal ("could not create pty/sessiondb helper process, aborting.\n");
253 fcntl (sock_fd, F_SETFD, FD_CLOEXEC);
254 #ifdef PTYTTY_REENTRANT
257 fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
262 // server, pty-helper
264 #ifdef PTYTTY_REENTRANT
270 signal (SIGHUP, SIG_IGN);
271 signal (SIGTERM, SIG_IGN);
272 signal (SIGINT, SIG_IGN);
273 signal (SIGPIPE, SIG_IGN);
275 for (int fd = 0; fd < 1023; fd++)
276 if (fd != sock_fd && fd != lock_fd)
280 _exit (EXIT_SUCCESS);
291 # ifndef PTYTTY_NO_PID_CHECK
292 && getpid () == owner_pid
295 // use helper process
296 return new ptytty_proxy;
299 return new ptytty_unix;
303 ptytty::sanitise_stdfd ()
305 // sanitise stdin/stdout/stderr to point to *something*.
306 for (int fd = 0; fd <= 2; ++fd)
307 if (fcntl (fd, F_GETFL) < 0 && errno == EBADF)
309 int fd2 = open ("/dev/tty", fd ? O_WRONLY : O_RDONLY);
312 fd2 = open ("/dev/null", fd ? O_WRONLY : O_RDONLY);
324 uid_t uid = getuid ();
325 gid_t gid = getgid ();
327 // before doing anything else, check for setuid/setgid operation,
328 // start the helper process and drop privileges
329 if (uid != geteuid ()
330 || gid != getegid ())
335 ptytty_warn ("running setuid/setgid without pty helper compiled in, continuing unprivileged.\n", 0);
343 ptytty::drop_privileges ()
345 uid_t uid = getuid ();
346 gid_t gid = getgid ();
350 setresgid (gid, gid, gid);
351 setresuid (uid, uid, uid);
359 # error no way to drop privileges, configure failed?
362 if (uid != geteuid ()
363 || gid != getegid ())
364 ptytty_fatal ("unable to drop privileges, aborting.\n");