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