source: filezilla/trunk/fuentes/src/putty/windows/winnps.c @ 3185

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 2 years ago

Update new version: 3.15.02

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