ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/proxy.C
Revision: 1.16
Committed: Sat Jan 21 13:40:30 2012 UTC (14 years, 8 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_6
Changes since 1.15: +1 -5 lines
Log Message:
Port find/vector implementation from urxvt and always use it in place of
stl.

File Contents

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