OSDN Git Service

b3aaae59d53af2379a3633dbdb0f8bd28381b071
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygserver / transport_pipes.cc
1 /* transport_pipes.cc
2
3    Copyright 2001, 2002, 2003, 2004, 2009 Red Hat Inc.
4
5    Written by Robert Collins <rbtcollins@hotmail.com>
6
7 This file is part of Cygwin.
8
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
11 details. */
12
13 /* to allow this to link into cygwin and the .dll, a little magic is needed. */
14 #ifdef __OUTSIDE_CYGWIN__
15 #include "woutsup.h"
16 #else
17 #include "winsup.h"
18 #endif
19
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <netdb.h>
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <wchar.h>
27 #include <sys/cygwin.h>
28
29 #include "cygerrno.h"
30 #include "transport.h"
31 #include "transport_pipes.h"
32
33 #ifndef __INSIDE_CYGWIN__
34 #include "cygserver.h"
35 #include "cygserver_ipc.h"
36 #else
37 #include "security.h"
38 #endif
39
40 #ifdef __INSIDE_CYGWIN__
41 #define SET_ERRNO(err)  set_errno (err)
42 #else
43 #define SET_ERRNO(err)  errno = (err)
44 #endif
45
46 enum
47   {
48     MAX_WAIT_NAMED_PIPE_RETRY = 64,
49     WAIT_NAMED_PIPE_TIMEOUT = 10 // milliseconds
50   };
51
52 #ifndef __INSIDE_CYGWIN__
53
54 static pthread_once_t pipe_instance_lock_once = PTHREAD_ONCE_INIT;
55 static CRITICAL_SECTION pipe_instance_lock;
56 static long pipe_instance = 0;
57
58 static void
59 initialise_pipe_instance_lock ()
60 {
61   assert (pipe_instance == 0);
62   InitializeCriticalSection (&pipe_instance_lock);
63 }
64
65 #endif /* !__INSIDE_CYGWIN__ */
66
67 #ifndef __INSIDE_CYGWIN__
68
69 transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
70   : _hPipe (hPipe),
71     _is_accepted_endpoint (true),
72     _is_listening_endpoint (false)
73 {
74   assert (_hPipe);
75   assert (_hPipe != INVALID_HANDLE_VALUE);
76   _pipe_name[0] = L'\0';
77 }
78
79 #endif /* !__INSIDE_CYGWIN__ */
80
81 transport_layer_pipes::transport_layer_pipes ()
82   : _hPipe (NULL),
83     _is_accepted_endpoint (false),
84     _is_listening_endpoint (false)
85 {
86 #ifdef __INSIDE_CYGWIN__
87   extern WCHAR installation_key_buf[18];
88   wcpcpy (wcpcpy (wcpcpy (_pipe_name, PIPE_NAME_PREFIX), installation_key_buf),
89           PIPE_NAME_SUFFIX);
90 #else
91   wchar_t cyg_instkey[18];
92
93   wchar_t *p = wcpcpy (_pipe_name, PIPE_NAME_PREFIX);
94   if (!cygwin_internal (CW_GET_INSTKEY, cyg_instkey))
95     wcpcpy (wcpcpy (p, cyg_instkey), PIPE_NAME_SUFFIX);
96 #endif
97 }
98
99 transport_layer_pipes::~transport_layer_pipes ()
100 {
101   close ();
102 }
103
104 #ifndef __INSIDE_CYGWIN__
105
106 int
107 transport_layer_pipes::listen ()
108 {
109   assert (!_hPipe);
110   assert (!_is_accepted_endpoint);
111   assert (!_is_listening_endpoint);
112
113   _is_listening_endpoint = true;
114
115   /* no-op */
116   return 0;
117 }
118
119 class transport_layer_pipes *
120 transport_layer_pipes::accept (bool *const recoverable)
121 {
122   assert (!_hPipe);
123   assert (!_is_accepted_endpoint);
124   assert (_is_listening_endpoint);
125
126   pthread_once (&pipe_instance_lock_once, &initialise_pipe_instance_lock);
127
128   EnterCriticalSection (&pipe_instance_lock);
129
130   // Read: http://www.securityinternals.com/research/papers/namedpipe.php
131   // See also the Microsoft security bulletins MS00-053 and MS01-031.
132
133   // FIXME: Remove FILE_CREATE_PIPE_INSTANCE.
134
135   const bool first_instance = (pipe_instance == 0);
136
137   debug ("Try to create named pipe: %ls", _pipe_name);
138
139   const HANDLE accept_pipe =
140     CreateNamedPipeW (_pipe_name,
141                      (PIPE_ACCESS_DUPLEX
142                       | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0)),
143                      (PIPE_TYPE_BYTE | PIPE_WAIT),
144                      PIPE_UNLIMITED_INSTANCES,
145                      0, 0, 1000,
146                      &sec_all_nih);
147
148   const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE
149                           && pipe_instance == 0
150                           && GetLastError () == ERROR_ACCESS_DENIED);
151
152   if (accept_pipe != INVALID_HANDLE_VALUE)
153     InterlockedIncrement (&pipe_instance);
154
155   LeaveCriticalSection (&pipe_instance_lock);
156
157   if (duplicate)
158     {
159       *recoverable = false;
160       system_printf ("failed to create named pipe: "
161                      "is the daemon already running?");
162       return NULL;
163     }
164
165   if (accept_pipe == INVALID_HANDLE_VALUE)
166     {
167       debug_printf ("error creating pipe (%lu).", GetLastError ());
168       *recoverable = true;      // FIXME: case analysis?
169       return NULL;
170     }
171
172   assert (accept_pipe);
173
174   if (!ConnectNamedPipe (accept_pipe, NULL)
175       && GetLastError () != ERROR_PIPE_CONNECTED)
176     {
177       debug_printf ("error connecting to pipe (%lu)", GetLastError ());
178       (void) CloseHandle (accept_pipe);
179       *recoverable = true;      // FIXME: case analysis?
180       return NULL;
181     }
182
183   return new transport_layer_pipes (accept_pipe);
184 }
185
186 #endif /* !__INSIDE_CYGWIN__ */
187
188 void
189 transport_layer_pipes::close ()
190 {
191   // verbose: debug_printf ("closing pipe %p", _hPipe);
192
193   if (_hPipe)
194     {
195       assert (_hPipe != INVALID_HANDLE_VALUE);
196
197 #ifndef __INSIDE_CYGWIN__
198
199       if (_is_accepted_endpoint)
200         {
201           (void) FlushFileBuffers (_hPipe); // Blocks until client reads.
202           (void) DisconnectNamedPipe (_hPipe);
203           EnterCriticalSection (&pipe_instance_lock);
204           (void) CloseHandle (_hPipe);
205           assert (pipe_instance > 0);
206           InterlockedDecrement (&pipe_instance);
207           LeaveCriticalSection (&pipe_instance_lock);
208         }
209       else
210         (void) CloseHandle (_hPipe);
211
212 #else /* __INSIDE_CYGWIN__ */
213
214       assert (!_is_accepted_endpoint);
215       (void) ForceCloseHandle (_hPipe);
216
217 #endif /* __INSIDE_CYGWIN__ */
218
219       _hPipe = NULL;
220     }
221 }
222
223 ssize_t
224 transport_layer_pipes::read (void *const buf, const size_t len)
225 {
226   // verbose: debug_printf ("reading from pipe %p", _hPipe);
227
228   assert (_hPipe);
229   assert (_hPipe != INVALID_HANDLE_VALUE);
230   assert (!_is_listening_endpoint);
231
232   DWORD count;
233   if (!ReadFile (_hPipe, buf, len, &count, NULL))
234     {
235       debug_printf ("error reading from pipe (%lu)", GetLastError ());
236       SET_ERRNO (EINVAL);       // FIXME?
237       return -1;
238     }
239
240   return count;
241 }
242
243 ssize_t
244 transport_layer_pipes::write (void *const buf, const size_t len)
245 {
246   // verbose: debug_printf ("writing to pipe %p", _hPipe);
247
248   assert (_hPipe);
249   assert (_hPipe != INVALID_HANDLE_VALUE);
250   assert (!_is_listening_endpoint);
251
252   DWORD count;
253   if (!WriteFile (_hPipe, buf, len, &count, NULL))
254     {
255       debug_printf ("error writing to pipe, error = %lu", GetLastError ());
256       SET_ERRNO (EINVAL);       // FIXME?
257       return -1;
258     }
259
260   return count;
261 }
262
263 /*
264  * This routine holds a static variable, assume_cygserver, that is set
265  * if the transport has good reason to think that cygserver is
266  * running, i.e. if if successfully connected to it with the previous
267  * attempt.  If this is set, the code tries a lot harder to get a
268  * connection, making the assumption that any failures are just
269  * congestion and overloading problems.
270  */
271
272 int
273 transport_layer_pipes::connect ()
274 {
275   assert (!_hPipe);
276   assert (!_is_accepted_endpoint);
277   assert (!_is_listening_endpoint);
278
279   static bool assume_cygserver = false;
280
281   BOOL rc = TRUE;
282   int retries = 0;
283
284   debug_printf ("Try to connect to named pipe: %W", _pipe_name);
285   while (rc)
286     {
287       _hPipe = CreateFileW (_pipe_name,
288                             GENERIC_READ | GENERIC_WRITE,
289                             FILE_SHARE_READ | FILE_SHARE_WRITE,
290                             &sec_all_nih,
291                             OPEN_EXISTING,
292                             SECURITY_IMPERSONATION,
293                             NULL);
294
295       if (_hPipe != INVALID_HANDLE_VALUE)
296         {
297           assert (_hPipe);
298 #ifdef __INSIDE_CYGWIN__
299           ProtectHandle (_hPipe);
300 #endif
301           assume_cygserver = true;
302           return 0;
303         }
304
305       _hPipe = NULL;
306
307       if (!assume_cygserver && GetLastError () != ERROR_PIPE_BUSY)
308         {
309           debug_printf ("Error opening the pipe (%lu)", GetLastError ());
310           return -1;
311         }
312
313       /* Note: `If no instances of the specified named pipe exist, the
314        * WaitNamedPipe function returns immediately, regardless of the
315        * time-out value.'  Thus the explicit Sleep if the call fails
316        * with ERROR_FILE_NOT_FOUND.
317        */
318       while (retries != MAX_WAIT_NAMED_PIPE_RETRY
319              && !(rc = WaitNamedPipeW (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT)))
320         {
321           if (GetLastError () == ERROR_FILE_NOT_FOUND)
322             Sleep (0);          // Give the server a chance.
323
324           retries += 1;
325         }
326     }
327
328   assert (retries == MAX_WAIT_NAMED_PIPE_RETRY);
329
330   system_printf ("lost connection to cygserver, error = %lu",
331                  GetLastError ());
332
333   assume_cygserver = false;
334
335   return -1;
336 }
337
338 #ifndef __INSIDE_CYGWIN__
339
340 bool
341 transport_layer_pipes::impersonate_client ()
342 {
343   assert (_hPipe);
344   assert (_hPipe != INVALID_HANDLE_VALUE);
345   assert (_is_accepted_endpoint);
346
347   if (_hPipe && !ImpersonateNamedPipeClient (_hPipe))
348     {
349       debug_printf ("Failed to Impersonate client, (%lu)", GetLastError ());
350       return false;
351     }
352
353   return true;
354 }
355
356 bool
357 transport_layer_pipes::revert_to_self ()
358 {
359   assert (_is_accepted_endpoint);
360
361   if (!RevertToSelf ())
362     {
363       debug_printf ("Failed to RevertToSelf, (%lu)", GetLastError ());
364       return false;
365     }
366   return true;
367 }
368
369 #endif /* !__INSIDE_CYGWIN__ */