Update libgit2 AutoCRLF patches
[TortoiseGit.git] / src / TortoisePlink / Windows / winnps.c
blobaf69aca04ea9b2a1c0c747465504e51a1a0d7d70
1 /*
2 * Windows support module which deals with being a named-pipe server.
3 */
5 #include <stdio.h>
6 #include <assert.h>
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"
15 #if !defined NO_SECURITY
17 #include "winsecur.h"
19 Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, Plug plug,
20 int overlapped);
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 */
27 /* Parameters for (repeated) creation of named pipe objects */
28 PSECURITY_DESCRIPTOR psd;
29 PACL acl;
30 char *pipename;
32 /* The current named pipe object + attempt to connect to it */
33 HANDLE pipehandle;
34 OVERLAPPED connect_ovl;
36 /* PuTTY Socket machinery */
37 Plug plug;
38 char *error;
41 static Plug sk_namedpipeserver_plug(Socket s, Plug p)
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;
50 static void sk_namedpipeserver_close(Socket s)
52 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
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);
65 static const char *sk_namedpipeserver_socket_error(Socket s)
67 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
68 return ps->error;
71 static int create_named_pipe(Named_Pipe_Server_Socket ps, int first_instance)
73 SECURITY_ATTRIBUTES sa;
75 memset(&sa, 0, sizeof(sa));
76 sa.nLength = sizeof(sa);
77 sa.lpSecurityDescriptor = ps->psd;
78 sa.bInheritHandle = FALSE;
80 ps->pipehandle = CreateNamedPipe
81 (/* lpName */
82 ps->pipename,
84 /* dwOpenMode */
85 PIPE_ACCESS_DUPLEX |
86 FILE_FLAG_OVERLAPPED |
87 (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
89 /* dwPipeMode */
90 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT
91 #ifdef PIPE_REJECT_REMOTE_CLIENTS
92 | PIPE_REJECT_REMOTE_CLIENTS
93 #endif
96 /* nMaxInstances */
97 PIPE_UNLIMITED_INSTANCES,
99 /* nOutBufferSize, nInBufferSize */
100 4096, 4096, /* FIXME: think harder about buffer sizes? */
102 /* nDefaultTimeOut */
103 0 /* default timeout */,
105 /* lpSecurityAttributes */
106 &sa);
108 return ps->pipehandle != INVALID_HANDLE_VALUE;
111 static Socket named_pipe_accept(accept_ctx_t ctx, Plug plug)
113 HANDLE conn = (HANDLE)ctx.p;
115 return make_handle_socket(conn, conn, plug, TRUE);
119 * Dummy SockAddr type which just holds a named pipe address. Only
120 * used for calling plug_log from named_pipe_accept_loop() here.
122 SockAddr sk_namedpipe_addr(const char *pipename);
124 static void named_pipe_accept_loop(Named_Pipe_Server_Socket ps,
125 int got_one_already)
127 while (1) {
128 int error;
129 char *errmsg;
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 {
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.
142 if (ConnectNamedPipe(ps->pipehandle, &ps->connect_ovl))
143 error = 0;
144 else
145 error = GetLastError();
147 if (error == ERROR_IO_PENDING)
148 return;
151 if (error == 0 || error == ERROR_PIPE_CONNECTED) {
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.
159 HANDLE conn = ps->pipehandle;
160 accept_ctx_t actx;
162 actx.p = (void *)conn;
163 if (plug_accepting(ps->plug, named_pipe_accept, actx)) {
165 * If the plug didn't want the connection, might as
166 * well close this handle.
168 CloseHandle(conn);
171 if (!create_named_pipe(ps, FALSE)) {
172 error = GetLastError();
173 } else {
175 * Go round again to see if more connections can be
176 * got, or to begin waiting on the event object.
178 continue;
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;
191 static void named_pipe_connect_callback(void *vps)
193 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket)vps;
194 named_pipe_accept_loop(ps, TRUE);
197 Socket new_named_pipe_listener(const char *pipename, Plug plug)
200 * This socket type is only used for listening, so it should never
201 * be asked to write or flush or set_frozen.
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
214 Named_Pipe_Server_Socket ret;
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;
224 assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0);
225 assert(strchr(pipename + 9, '\\') == NULL);
227 if (!make_private_security_descriptor(GENERIC_READ | GENERIC_WRITE,
228 &ret->psd, &ret->acl, &ret->error)) {
229 goto cleanup;
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;
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);
244 cleanup:
245 return (Socket) ret;
248 #endif /* !defined NO_SECURITY */