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

# 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 <schmorp@schmorp.de>
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 <cstdio>
31 #include <cstring>
32 #include <csignal>
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39
40 // helper/proxy support
41
42 #if PTYTTY_HELPER
43
44 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 close_tty ();
132
133 if (pty >= 0)
134 close (pty);
135
136 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 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 ptytty::init ()
321 {
322 sanitise_stdfd ();
323
324 uid_t uid = getuid ();
325 gid_t gid = getgid ();
326
327 // 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 ptytty_warn ("running setuid/setgid without pty helper compiled in, continuing unprivileged.\n", 0);
336 #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 #else
359 # error no way to drop privileges, configure failed?
360 #endif
361
362 if (uid != geteuid ()
363 || gid != getegid ())
364 ptytty_fatal ("unable to drop privileges, aborting.\n");
365 }
366