ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/proxy.C
Revision: 1.12
Committed: Mon May 30 21:24:42 2011 UTC (12 years, 11 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.11: +0 -0 lines
State: FILE REMOVED
Log Message:
Embed libptytty.

File Contents

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