ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libptytty/src/proxy.C
Revision: 1.27
Committed: Sat Jun 26 14:31:15 2021 UTC (5 years, 2 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.26: +7 -9 lines
Log Message:
Remove PTYTTY_{WARN,FATAL} and throw on failure

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;
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 private:
60
61 ptytty *id;
62
63 public:
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 do { char ch; read (lock_fd, &ch , 1); } while (0)
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 throw ptytty_error ("protocol error while creating pty using helper process.\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 throw ptytty_error ("protocol error while reading pty/tty fds from helper process.\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 void
153 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 cmd.id->close_tty ();
179 }
180 else
181 {
182 delete cmd.id;
183 cmd.id = 0;
184 write (sock_fd, &cmd.id, sizeof (cmd.id));
185 }
186 }
187 else if (cmd.type == command::login)
188 {
189 #if UTMP_SUPPORT
190 if (find (ptys.begin (), ptys.end (), cmd.id) != ptys.end ())
191 {
192 cmd.hostname[sizeof (cmd.hostname) - 1] = 0;
193 cmd.id->login (cmd.cmd_pid, cmd.login_shell, cmd.hostname);
194 }
195 #endif
196 }
197 else if (cmd.type == command::destroy)
198 {
199 vector<ptytty *>::iterator pty = find (ptys.begin (), ptys.end (), cmd.id);
200
201 if (pty != ptys.end ())
202 {
203 delete *pty;
204 ptys.erase (pty);
205 }
206 }
207 else
208 break;
209
210 NEED_TOKEN;
211 }
212
213 // destroy all ptys
214 for (vector<ptytty *>::iterator i = ptys.end (); i-- > ptys.begin (); )
215 delete *i;
216 }
217
218 void
219 ptytty::use_helper ()
220 {
221 if (sock_fd >= 0)
222 return;
223
224 int sv[2];
225
226 if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv))
227 throw ptytty_error ("could not create socket to communicate with pty/sessiondb helper.\n");
228
229 #if PTYTTY_REENTRANT
230 int lv[2];
231
232 if (socketpair (AF_UNIX, SOCK_STREAM, 0, lv))
233 throw ptytty_error ("could not create socket to communicate with pty/sessiondb helper.\n");
234 #endif
235
236 helper_pid = fork ();
237
238 if (helper_pid < 0)
239 throw ptytty_error ("could not create pty/sessiondb helper process.\n");
240
241 if (helper_pid)
242 {
243 // client, process
244 sock_fd = sv[0];
245 close (sv[1]);
246 fcntl (sock_fd, F_SETFD, FD_CLOEXEC);
247 #if PTYTTY_REENTRANT
248 lock_fd = lv[0];
249 close (lv[1]);
250 fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
251 #endif
252 }
253 else
254 {
255 // server, pty-helper
256 sock_fd = sv[1];
257 #if PTYTTY_REENTRANT
258 lock_fd = lv[1];
259 #endif
260
261 chdir ("/");
262
263 signal (SIGHUP, SIG_IGN);
264 signal (SIGTERM, SIG_IGN);
265 signal (SIGINT, SIG_IGN);
266 signal (SIGPIPE, SIG_IGN);
267
268 for (int fd = 0; fd < 1023; fd++)
269 if (fd != sock_fd && fd != lock_fd)
270 close (fd);
271
272 serve ();
273 _exit (EXIT_SUCCESS);
274 }
275 }
276
277 #endif
278
279 ptytty *
280 ptytty::create ()
281 {
282 #if PTYTTY_HELPER
283 if (helper_pid)
284 // use helper process
285 return new ptytty_proxy;
286 else
287 #endif
288 return new ptytty_unix;
289 }
290
291 void
292 ptytty::sanitise_stdfd ()
293 {
294 // sanitise stdin/stdout/stderr to point to *something*.
295 for (int fd = 0; fd <= 2; ++fd)
296 if (fcntl (fd, F_GETFL) < 0 && errno == EBADF)
297 {
298 int fd2 = open ("/dev/tty", fd ? O_WRONLY : O_RDONLY);
299
300 if (fd2 < 0)
301 fd2 = open ("/dev/null", fd ? O_WRONLY : O_RDONLY);
302
303 if (fd2 != fd)
304 throw ptytty_error ("unable to sanitise fds.\n");
305 }
306 }
307
308 void
309 ptytty::init ()
310 {
311 sanitise_stdfd ();
312
313 uid_t uid = getuid ();
314 gid_t gid = getgid ();
315
316 // before doing anything else, check for setuid/setgid operation,
317 // start the helper process and drop privileges
318 if (uid != geteuid ()
319 || gid != getegid ())
320 {
321 #if PTYTTY_HELPER
322 use_helper ();
323 #endif
324
325 drop_privileges ();
326 }
327 }
328
329 void
330 ptytty::drop_privileges ()
331 {
332 uid_t uid = getuid ();
333 gid_t gid = getgid ();
334
335 // drop privileges
336 #if HAVE_SETRESUID
337 setresgid (gid, gid, gid);
338 setresuid (uid, uid, uid);
339 #elif HAVE_SETREUID
340 setregid (gid, gid);
341 setreuid (uid, uid);
342 #elif HAVE_SETUID
343 setgid (gid);
344 setuid (uid);
345 #else
346 # error no way to drop privileges, configure failed?
347 #endif
348
349 if (uid != geteuid ()
350 || gid != getegid ())
351 throw ptytty_error ("unable to drop privileges.\n");
352 }
353