ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libptytty/src/proxy.C
Revision: 1.14
Committed: Wed Jan 18 12:19:31 2012 UTC (14 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +0 -3 lines
Log Message:
*** empty log message ***

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