ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libptytty/src/proxy.C
Revision: 1.13
Committed: Tue Dec 20 13:46:05 2011 UTC (14 years, 8 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-9_14, rel-1_5
Changes since 1.12: +6 -0 lines
Log Message:
change the semantic of PTYTTY_NO_LIBCPP from undef/def to 0/1 and move
the associated includes in proxy.C.

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