ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/proxy.C
Revision: 1.7
Committed: Mon Feb 12 17:34:58 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-8_2, rel-8_3
Changes since 1.6: +20 -0 lines
Log Message:
*** empty log message ***

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