ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/proxy.C
Revision: 1.8
Committed: Thu Aug 2 13:54:17 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-9_0, rel-8_5a, rel-8_9, rel-8_8, rel-8_4, rel-8_6, rel-8_7, rel-9_02, rel-9_01, rel-9_06, rel-9_05
Changes since 1.7: +1 -1 lines
Log Message:
inconsequential changes

File Contents

# Content
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 #include <errno.h>
37
38 // helper/proxy support
39
40 #if PTYTTY_HELPER
41
42 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 close_tty ();
130
131 if (pty >= 0)
132 close (pty);
133
134 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 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 ptytty::init ()
319 {
320 sanitise_stdfd ();
321
322 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 ptytty_warn ("running setuid/setgid without pty helper compiled in, continuing unprivileged.\n", 0);
334 #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 #else
357 # error no way to drop privileges, configure failed?
358 #endif
359
360 if (uid != geteuid ()
361 || gid != getegid ())
362 ptytty_fatal ("unable to drop privileges, aborting.\n");
363 }
364