ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/proxy.C
Revision: 1.14
Committed: Wed Jan 18 12:19:31 2012 UTC (14 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +0 -3 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 /*----------------------------------------------------------------------*
2     * File: proxy.C
3     *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6 sf-exg 1.9 * Copyright (c) 2006 Marc Lehmann <schmorp@schmorp.de>
7 root 1.1 *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *---------------------------------------------------------------------*/
22    
23 sf-exg 1.8 #include "config.h"
24 root 1.1
25     #include "ptytty.h"
26    
27 sf-exg 1.13 #if !PTYTTY_NO_LIBCPP
28     #include <vector>
29     #include <algorithm>
30     using namespace std;
31     #endif
32    
33 root 1.7 #include <cstdio>
34     #include <cstring>
35 root 1.1 #include <csignal>
36    
37     #include <sys/types.h>
38     #include <sys/socket.h>
39     #include <unistd.h>
40     #include <fcntl.h>
41 root 1.4 #include <errno.h>
42 root 1.1
43     // helper/proxy support
44    
45     #if PTYTTY_HELPER
46    
47     static int sock_fd = -1, lock_fd = -1;
48     static int helper_pid, owner_pid;
49    
50     struct command
51     {
52     enum { get, login, destroy } type;
53    
54     ptytty *id;
55    
56     bool login_shell;
57     int cmd_pid;
58     char hostname[512]; // arbitrary, but should be plenty
59     };
60    
61     struct ptytty_proxy : ptytty
62     {
63     ptytty *id;
64    
65     ptytty_proxy ()
66     : id(0)
67     {
68     }
69    
70     ~ptytty_proxy ();
71    
72     bool get ();
73     void login (int cmd_pid, bool login_shell, const char *hostname);
74     };
75    
76     #if PTYTTY_REENTRANT
77 root 1.11 # define NEED_TOKEN read (lock_fd, &lock_fd, 1)
78     # define GIVE_TOKEN write (lock_fd, &lock_fd, 1)
79 root 1.1 #else
80     # define NEED_TOKEN (void)0
81     # define GIVE_TOKEN (void)0
82     #endif
83    
84     bool
85     ptytty_proxy::get ()
86     {
87     NEED_TOKEN;
88    
89     command cmd;
90    
91     cmd.type = command::get;
92    
93     write (sock_fd, &cmd, sizeof (cmd));
94    
95     if (read (sock_fd, &id, sizeof (id)) != sizeof (id))
96 sf-exg 1.10 PTYTTY_FATAL ("protocol error while creating pty using helper process, aborting.\n");
97 root 1.1
98     if (!id)
99     {
100     GIVE_TOKEN;
101     return false;
102     }
103    
104     if ((pty = recv_fd (sock_fd)) < 0
105     || (tty = recv_fd (sock_fd)) < 0)
106 sf-exg 1.10 PTYTTY_FATAL ("protocol error while reading pty/tty fds from helper process, aborting.\n");
107 root 1.1
108     GIVE_TOKEN;
109     return true;
110     }
111    
112     void
113     ptytty_proxy::login (int cmd_pid, bool login_shell, const char *hostname)
114     {
115     NEED_TOKEN;
116    
117     command cmd;
118    
119     cmd.type = command::login;
120     cmd.id = id;
121     cmd.cmd_pid = cmd_pid;
122     cmd.login_shell = login_shell;
123     strncpy (cmd.hostname, hostname, sizeof (cmd.hostname));
124    
125     write (sock_fd, &cmd, sizeof (cmd));
126    
127     GIVE_TOKEN;
128     }
129    
130     ptytty_proxy::~ptytty_proxy ()
131     {
132     if (id)
133     {
134 ayin 1.3 close_tty ();
135    
136     if (pty >= 0)
137     close (pty);
138 ayin 1.2
139 root 1.1 NEED_TOKEN;
140    
141     command cmd;
142    
143     cmd.type = command::destroy;
144     cmd.id = id;
145    
146     write (sock_fd, &cmd, sizeof (cmd));
147    
148     GIVE_TOKEN;
149     }
150     }
151    
152     static
153     void serve ()
154     {
155     command cmd;
156     vector<ptytty *> ptys;
157    
158     for (;;)
159     {
160     GIVE_TOKEN;
161    
162     if (read (sock_fd, &cmd, sizeof (command)) != sizeof (command))
163     break;
164    
165     if (cmd.type == command::get)
166     {
167     // -> id ptyfd ttyfd
168     cmd.id = new ptytty_unix;
169    
170     if (cmd.id->get ())
171     {
172     write (sock_fd, &cmd.id, sizeof (cmd.id));
173     ptys.push_back (cmd.id);
174    
175     ptytty::send_fd (sock_fd, cmd.id->pty);
176     ptytty::send_fd (sock_fd, cmd.id->tty);
177     }
178     else
179     {
180     delete cmd.id;
181     cmd.id = 0;
182     write (sock_fd, &cmd.id, sizeof (cmd.id));
183     }
184     }
185     else if (cmd.type == command::login)
186     {
187     #if UTMP_SUPPORT
188     if (find (ptys.begin (), ptys.end (), cmd.id) != ptys.end ())
189     {
190     cmd.hostname[sizeof (cmd.hostname) - 1] = 0;
191     cmd.id->login (cmd.cmd_pid, cmd.login_shell, cmd.hostname);
192     }
193     #endif
194     }
195     else if (cmd.type == command::destroy)
196     {
197     vector<ptytty *>::iterator pty = find (ptys.begin (), ptys.end (), cmd.id);
198    
199     if (pty != ptys.end ())
200     {
201     delete *pty;
202     ptys.erase (pty);
203     }
204     }
205     else
206     break;
207    
208     NEED_TOKEN;
209     }
210    
211     // destroy all ptys
212     for (vector<ptytty *>::iterator i = ptys.end (); i-- > ptys.begin (); )
213     delete *i;
214     }
215    
216     void
217     ptytty::use_helper ()
218     {
219     #ifndef PTYTTY_NO_PID_CHECK
220     int pid = getpid ();
221     #endif
222    
223     if (sock_fd >= 0
224     #ifndef PTYTTY_NO_PID_CHECK
225     && pid == owner_pid
226     #endif
227     )
228     return;
229    
230     #ifndef PTYTTY_NO_PID_CHECK
231     owner_pid = pid;
232     #endif
233    
234     int sv[2];
235    
236     if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv))
237 sf-exg 1.10 PTYTTY_FATAL ("could not create socket to communicate with pty/sessiondb helper, aborting.\n");
238 root 1.1
239 sf-exg 1.12 #if PTYTTY_REENTRANT
240 root 1.1 int lv[2];
241    
242     if (socketpair (AF_UNIX, SOCK_STREAM, 0, lv))
243 sf-exg 1.10 PTYTTY_FATAL ("could not create socket to communicate with pty/sessiondb helper, aborting.\n");
244 root 1.1 #endif
245    
246     helper_pid = fork ();
247    
248     if (helper_pid < 0)
249 sf-exg 1.10 PTYTTY_FATAL ("could not create pty/sessiondb helper process, aborting.\n");
250 root 1.1
251     if (helper_pid)
252     {
253     // client, process
254     sock_fd = sv[0];
255     close (sv[1]);
256     fcntl (sock_fd, F_SETFD, FD_CLOEXEC);
257 sf-exg 1.12 #if PTYTTY_REENTRANT
258 root 1.1 lock_fd = lv[0];
259     close (lv[1]);
260     fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
261     #endif
262     }
263     else
264     {
265     // server, pty-helper
266     sock_fd = sv[1];
267 sf-exg 1.12 #if PTYTTY_REENTRANT
268 root 1.1 lock_fd = lv[1];
269     #endif
270    
271     chdir ("/");
272    
273     signal (SIGHUP, SIG_IGN);
274     signal (SIGTERM, SIG_IGN);
275     signal (SIGINT, SIG_IGN);
276     signal (SIGPIPE, SIG_IGN);
277    
278     for (int fd = 0; fd < 1023; fd++)
279     if (fd != sock_fd && fd != lock_fd)
280     close (fd);
281    
282     serve ();
283     _exit (EXIT_SUCCESS);
284     }
285     }
286    
287     #endif
288    
289     ptytty *
290     ptytty::create ()
291     {
292     #if PTYTTY_HELPER
293     if (helper_pid
294     # ifndef PTYTTY_NO_PID_CHECK
295     && getpid () == owner_pid
296     # endif
297     )
298     // use helper process
299     return new ptytty_proxy;
300     else
301     #endif
302     return new ptytty_unix;
303     }
304    
305     void
306 root 1.4 ptytty::sanitise_stdfd ()
307     {
308     // sanitise stdin/stdout/stderr to point to *something*.
309     for (int fd = 0; fd <= 2; ++fd)
310     if (fcntl (fd, F_GETFL) < 0 && errno == EBADF)
311     {
312     int fd2 = open ("/dev/tty", fd ? O_WRONLY : O_RDONLY);
313    
314     if (fd2 < 0)
315 root 1.5 fd2 = open ("/dev/null", fd ? O_WRONLY : O_RDONLY);
316 root 1.4
317     if (fd2 != fd)
318 root 1.5 abort ();
319 root 1.4 }
320     }
321    
322     void
323 root 1.1 ptytty::init ()
324     {
325 root 1.4 sanitise_stdfd ();
326    
327 root 1.1 uid_t uid = getuid ();
328     gid_t gid = getgid ();
329 ayin 1.6
330 root 1.1 // before doing anything else, check for setuid/setgid operation,
331     // start the helper process and drop privileges
332     if (uid != geteuid ()
333     || gid != getegid ())
334     {
335     #if PTYTTY_HELPER
336     use_helper ();
337     #else
338 sf-exg 1.10 PTYTTY_WARN ("running setuid/setgid without pty helper compiled in, continuing unprivileged.\n", 0);
339 root 1.1 #endif
340    
341     drop_privileges ();
342     }
343     }
344    
345     void
346     ptytty::drop_privileges ()
347     {
348     uid_t uid = getuid ();
349     gid_t gid = getgid ();
350    
351     // drop privileges
352     #if HAVE_SETRESUID
353     setresgid (gid, gid, gid);
354     setresuid (uid, uid, uid);
355     #elif HAVE_SETREUID
356     setregid (gid, gid);
357     setreuid (uid, uid);
358     #elif HAVE_SETUID
359     setgid (gid);
360     setuid (uid);
361     #else
362     # error no way to drop privileges, configure failed?
363     #endif
364    
365     if (uid != geteuid ()
366     || gid != getegid ())
367 sf-exg 1.10 PTYTTY_FATAL ("unable to drop privileges, aborting.\n");
368 root 1.1 }
369