]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windows/winnps.c
Stop sending release events for mouse wheel 'buttons' in X mouse mode.
[PuTTY.git] / windows / winnps.c
1 /*
2  * Windows support module which deals with being a named-pipe server.
3  */
4
5 #include <stdio.h>
6 #include <assert.h>
7
8 #define DEFINE_PLUG_METHOD_MACROS
9 #include "tree234.h"
10 #include "putty.h"
11 #include "network.h"
12 #include "proxy.h"
13 #include "ssh.h"
14
15 #if !defined NO_SECURITY
16
17 #include "winsecur.h"
18
19 Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, Plug plug,
20                           int overlapped);
21
22 typedef struct Socket_named_pipe_server_tag *Named_Pipe_Server_Socket;
23 struct Socket_named_pipe_server_tag {
24     const struct socket_function_table *fn;
25     /* the above variable absolutely *must* be the first in this structure */
26
27     /* Parameters for (repeated) creation of named pipe objects */
28     PSECURITY_DESCRIPTOR psd;
29     PACL acl;
30     char *pipename;
31
32     /* The current named pipe object + attempt to connect to it */
33     HANDLE pipehandle;
34     OVERLAPPED connect_ovl;
35
36     /* PuTTY Socket machinery */
37     Plug plug;
38     char *error;
39 };
40
41 static Plug sk_namedpipeserver_plug(Socket s, Plug p)
42 {
43     Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
44     Plug ret = ps->plug;
45     if (p)
46         ps->plug = p;
47     return ret;
48 }
49
50 static void sk_namedpipeserver_close(Socket s)
51 {
52     Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
53
54     CloseHandle(ps->pipehandle);
55     CloseHandle(ps->connect_ovl.hEvent);
56     sfree(ps->error);
57     sfree(ps->pipename);
58     if (ps->acl)
59         LocalFree(ps->acl);
60     if (ps->psd)
61         LocalFree(ps->psd);
62     sfree(ps);
63 }
64
65 static const char *sk_namedpipeserver_socket_error(Socket s)
66 {
67     Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
68     return ps->error;
69 }
70
71 static int create_named_pipe(Named_Pipe_Server_Socket ps, int first_instance)
72 {
73     SECURITY_ATTRIBUTES sa;
74
75     memset(&sa, 0, sizeof(sa));
76     sa.nLength = sizeof(sa);
77     sa.lpSecurityDescriptor = ps->psd;
78     sa.bInheritHandle = FALSE;
79
80     ps->pipehandle = CreateNamedPipe
81         (/* lpName */
82          ps->pipename,
83
84          /* dwOpenMode */
85          PIPE_ACCESS_DUPLEX |
86          FILE_FLAG_OVERLAPPED |
87          (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
88
89          /* dwPipeMode */
90          PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT
91 #ifdef PIPE_REJECT_REMOTE_CLIENTS
92          | PIPE_REJECT_REMOTE_CLIENTS
93 #endif
94          ,
95
96          /* nMaxInstances */
97          PIPE_UNLIMITED_INSTANCES,
98
99          /* nOutBufferSize, nInBufferSize */
100          4096, 4096,     /* FIXME: think harder about buffer sizes? */
101
102          /* nDefaultTimeOut */
103          0 /* default timeout */,
104
105          /* lpSecurityAttributes */
106          &sa);
107
108     return ps->pipehandle != INVALID_HANDLE_VALUE;
109 }
110
111 static Socket named_pipe_accept(accept_ctx_t ctx, Plug plug)
112 {
113     HANDLE conn = (HANDLE)ctx.p;
114
115     return make_handle_socket(conn, conn, plug, TRUE);
116 }
117
118 /*
119  * Dummy SockAddr type which just holds a named pipe address. Only
120  * used for calling plug_log from named_pipe_accept_loop() here.
121  */
122 SockAddr sk_namedpipe_addr(const char *pipename);
123
124 static void named_pipe_accept_loop(Named_Pipe_Server_Socket ps,
125                                    int got_one_already)
126 {
127     while (1) {
128         int error;
129         char *errmsg;
130
131         if (got_one_already) {
132             /* If we were called with a connection already waiting,
133              * skip this step. */
134             got_one_already = FALSE;
135             error = 0;
136         } else {
137             /*
138              * Call ConnectNamedPipe, which might succeed or might
139              * tell us that an overlapped operation is in progress and
140              * we should wait for our event object.
141              */
142             if (ConnectNamedPipe(ps->pipehandle, &ps->connect_ovl))
143                 error = 0;
144             else
145                 error = GetLastError();
146
147             if (error == ERROR_IO_PENDING)
148                 return;
149         }
150
151         if (error == 0 || error == ERROR_PIPE_CONNECTED) {
152             /*
153              * We've successfully retrieved an incoming connection, so
154              * ps->pipehandle now refers to that connection. So
155              * convert that handle into a separate connection-type
156              * Socket, and create a fresh one to be the new listening
157              * pipe.
158              */
159             HANDLE conn = ps->pipehandle;
160             accept_ctx_t actx;
161
162             actx.p = (void *)conn;
163             if (plug_accepting(ps->plug, named_pipe_accept, actx)) {
164                 /*
165                  * If the plug didn't want the connection, might as
166                  * well close this handle.
167                  */
168                 CloseHandle(conn);
169             }
170
171             if (!create_named_pipe(ps, FALSE)) {
172                 error = GetLastError();
173             } else {
174                 /*
175                  * Go round again to see if more connections can be
176                  * got, or to begin waiting on the event object.
177                  */
178                 continue;
179             }
180         }
181
182         errmsg = dupprintf("Error while listening to named pipe: %s",
183                            win_strerror(error));
184         plug_log(ps->plug, 1, sk_namedpipe_addr(ps->pipename), 0,
185                  errmsg, error);
186         sfree(errmsg);
187         break;
188     }
189 }
190
191 static void named_pipe_connect_callback(void *vps)
192 {
193     Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket)vps;
194     named_pipe_accept_loop(ps, TRUE);
195 }
196
197 Socket new_named_pipe_listener(const char *pipename, Plug plug)
198 {
199     /*
200      * This socket type is only used for listening, so it should never
201      * be asked to write or flush or set_frozen.
202      */
203     static const struct socket_function_table socket_fn_table = {
204         sk_namedpipeserver_plug,
205         sk_namedpipeserver_close,
206         NULL /* write */,
207         NULL /* write_oob */,
208         NULL /* write_eof */,
209         NULL /* flush */,
210         NULL /* set_frozen */,
211         sk_namedpipeserver_socket_error
212     };
213
214     Named_Pipe_Server_Socket ret;
215
216     ret = snew(struct Socket_named_pipe_server_tag);
217     ret->fn = &socket_fn_table;
218     ret->plug = plug;
219     ret->error = NULL;
220     ret->psd = NULL;
221     ret->pipename = dupstr(pipename);
222     ret->acl = NULL;
223
224     assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0);
225     assert(strchr(pipename + 9, '\\') == NULL);
226
227     if (!make_private_security_descriptor(GENERIC_READ | GENERIC_WRITE,
228                                           &ret->psd, &ret->acl, &ret->error)) {
229         goto cleanup;
230     }
231
232     if (!create_named_pipe(ret, TRUE)) {
233         ret->error = dupprintf("unable to create named pipe '%s': %s",
234                                pipename, win_strerror(GetLastError()));
235         goto cleanup;
236     }
237
238     memset(&ret->connect_ovl, 0, sizeof(ret->connect_ovl));
239     ret->connect_ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
240     handle_add_foreign_event(ret->connect_ovl.hEvent,
241                              named_pipe_connect_callback, ret);
242     named_pipe_accept_loop(ret, FALSE);
243
244   cleanup:
245     return (Socket) ret;
246 }
247
248 #endif /* !defined NO_SECURITY */