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, 7 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

# User Rev Content
1 root 1.1 /*----------------------------------------------------------------------*
2     * File: proxy.C
3     *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6 sf-exg 1.9 * Copyright (c) 2006 Marc Lehmann <schmorp@schmorp.de>
7 root 1.1 *
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 sf-exg 1.8 #include "config.h"
24 root 1.1
25     #include "ptytty.h"
26    
27 sf-exg 1.16 #include "estl.h"
28 sf-exg 1.13
29 sf-exg 1.15 #include <stdio.h>
30     #include <string.h>
31     #include <signal.h>
32 root 1.1
33     #include <sys/types.h>
34     #include <sys/socket.h>
35     #include <unistd.h>
36     #include <fcntl.h>
37 root 1.4 #include <errno.h>
38 root 1.1
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 root 1.11 # define NEED_TOKEN read (lock_fd, &lock_fd, 1)
74     # define GIVE_TOKEN write (lock_fd, &lock_fd, 1)
75 root 1.1 #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 sf-exg 1.10 PTYTTY_FATAL ("protocol error while creating pty using helper process, aborting.\n");
93 root 1.1
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 sf-exg 1.10 PTYTTY_FATAL ("protocol error while reading pty/tty fds from helper process, aborting.\n");
103 root 1.1
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 ayin 1.3 close_tty ();
131    
132     if (pty >= 0)
133     close (pty);
134 ayin 1.2
135 root 1.1 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 sf-exg 1.10 PTYTTY_FATAL ("could not create socket to communicate with pty/sessiondb helper, aborting.\n");
234 root 1.1
235 sf-exg 1.12 #if PTYTTY_REENTRANT
236 root 1.1 int lv[2];
237    
238     if (socketpair (AF_UNIX, SOCK_STREAM, 0, lv))
239 sf-exg 1.10 PTYTTY_FATAL ("could not create socket to communicate with pty/sessiondb helper, aborting.\n");
240 root 1.1 #endif
241    
242     helper_pid = fork ();
243    
244     if (helper_pid < 0)
245 sf-exg 1.10 PTYTTY_FATAL ("could not create pty/sessiondb helper process, aborting.\n");
246 root 1.1
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 sf-exg 1.12 #if PTYTTY_REENTRANT
254 root 1.1 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 sf-exg 1.12 #if PTYTTY_REENTRANT
264 root 1.1 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 root 1.4 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 root 1.5 fd2 = open ("/dev/null", fd ? O_WRONLY : O_RDONLY);
312 root 1.4
313     if (fd2 != fd)
314 root 1.5 abort ();
315 root 1.4 }
316     }
317    
318     void
319 root 1.1 ptytty::init ()
320     {
321 root 1.4 sanitise_stdfd ();
322    
323 root 1.1 uid_t uid = getuid ();
324     gid_t gid = getgid ();
325 ayin 1.6
326 root 1.1 // 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 sf-exg 1.10 PTYTTY_WARN ("running setuid/setgid without pty helper compiled in, continuing unprivileged.\n", 0);
335 root 1.1 #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 sf-exg 1.10 PTYTTY_FATAL ("unable to drop privileges, aborting.\n");
364 root 1.1 }
365