2 * Windows support module which deals with being a named-pipe server.
8 #define DEFINE_PLUG_METHOD_MACROS
15 #if !defined NO_SECURITY
19 Socket make_handle_socket(HANDLE send_H, HANDLE recv_H, Plug plug,
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;
33 /* The current named pipe object + attempt to connect to it */
35 OVERLAPPED connect_ovl;
37 /* PuTTY Socket machinery */
43 static Plug sk_namedpipeserver_plug(Socket s, Plug p)
45 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
52 static void sk_namedpipeserver_close(Socket s)
54 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
56 CloseHandle(ps->pipehandle);
57 CloseHandle(ps->connect_ovl.hEvent);
61 LocalFree(ps->networksid);
69 static void sk_namedpipeserver_set_private_ptr(Socket s, void *ptr)
71 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
75 static void *sk_namedpipeserver_get_private_ptr(Socket s)
77 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
81 static const char *sk_namedpipeserver_socket_error(Socket s)
83 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket) s;
87 static int create_named_pipe(Named_Pipe_Server_Socket ps, int first_instance)
89 SECURITY_ATTRIBUTES sa;
91 memset(&sa, 0, sizeof(sa));
92 sa.nLength = sizeof(sa);
93 sa.lpSecurityDescriptor = ps->psd;
94 sa.bInheritHandle = FALSE;
96 ps->pipehandle = CreateNamedPipe
102 FILE_FLAG_OVERLAPPED |
103 (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
106 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT
107 #ifdef PIPE_REJECT_REMOTE_CLIENTS
108 | PIPE_REJECT_REMOTE_CLIENTS
113 PIPE_UNLIMITED_INSTANCES,
115 /* nOutBufferSize, nInBufferSize */
116 4096, 4096, /* FIXME: think harder about buffer sizes? */
118 /* nDefaultTimeOut */
119 0 /* default timeout */,
121 /* lpSecurityAttributes */
124 return ps->pipehandle != INVALID_HANDLE_VALUE;
127 static Socket named_pipe_accept(accept_ctx_t ctx, Plug plug)
129 HANDLE conn = (HANDLE)ctx.p;
131 return make_handle_socket(conn, conn, plug, TRUE);
134 static void named_pipe_accept_loop(Named_Pipe_Server_Socket ps,
141 if (got_one_already) {
142 /* If we were called with a connection already waiting,
144 got_one_already = FALSE;
148 * Call ConnectNamedPipe, which might succeed or might
149 * tell us that an overlapped operation is in progress and
150 * we should wait for our event object.
152 if (ConnectNamedPipe(ps->pipehandle, &ps->connect_ovl))
155 error = GetLastError();
157 if (error == ERROR_IO_PENDING)
161 if (error == 0 || error == ERROR_PIPE_CONNECTED) {
163 * We've successfully retrieved an incoming connection, so
164 * ps->pipehandle now refers to that connection. So
165 * convert that handle into a separate connection-type
166 * Socket, and create a fresh one to be the new listening
169 HANDLE conn = ps->pipehandle;
172 actx.p = (void *)conn;
173 if (plug_accepting(ps->plug, named_pipe_accept, actx)) {
175 * If the plug didn't want the connection, might as
176 * well close this handle.
181 if (!create_named_pipe(ps, FALSE)) {
182 error = GetLastError();
185 * Go round again to see if more connections can be
186 * got, or to begin waiting on the event object.
192 errmsg = dupprintf("Error while listening to named pipe: %s",
193 win_strerror(error));
194 plug_log(ps->plug, 1, NULL /* FIXME: appropriate kind of sockaddr */, 0,
201 static void named_pipe_connect_callback(void *vps)
203 Named_Pipe_Server_Socket ps = (Named_Pipe_Server_Socket)vps;
204 named_pipe_accept_loop(ps, TRUE);
207 Socket new_named_pipe_listener(const char *pipename, Plug plug)
210 * This socket type is only used for listening, so it should never
211 * be asked to write or flush or set_frozen.
213 static const struct socket_function_table socket_fn_table = {
214 sk_namedpipeserver_plug,
215 sk_namedpipeserver_close,
217 NULL /* write_oob */,
218 NULL /* write_eof */,
220 sk_namedpipeserver_set_private_ptr,
221 sk_namedpipeserver_get_private_ptr,
222 NULL /* set_frozen */,
223 sk_namedpipeserver_socket_error
226 Named_Pipe_Server_Socket ret;
227 SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
228 EXPLICIT_ACCESS ea[2];
230 ret = snew(struct Socket_named_pipe_server_tag);
231 ret->fn = &socket_fn_table;
236 ret->pipename = dupstr(pipename);
237 ret->networksid = NULL;
240 assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0);
241 assert(strchr(pipename + 9, '\\') == NULL);
243 if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID,
244 0, 0, 0, 0, 0, 0, 0, &ret->networksid)) {
245 ret->error = dupprintf("unable to construct SID for rejecting "
246 "remote pipe connections: %s",
247 win_strerror(GetLastError()));
251 memset(ea, 0, sizeof(ea));
252 ea[0].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE;
253 ea[0].grfAccessMode = GRANT_ACCESS;
254 ea[0].grfInheritance = NO_INHERITANCE;
255 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
256 ea[0].Trustee.ptstrName = "CURRENT_USER";
257 ea[1].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE;
258 ea[1].grfAccessMode = REVOKE_ACCESS;
259 ea[1].grfInheritance = NO_INHERITANCE;
260 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
261 ea[1].Trustee.ptstrName = (LPTSTR)ret->networksid;
263 if (SetEntriesInAcl(2, ea, NULL, &ret->acl) != ERROR_SUCCESS) {
264 ret->error = dupprintf("unable to construct ACL: %s",
265 win_strerror(GetLastError()));
269 ret->psd = (PSECURITY_DESCRIPTOR)
270 LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
272 ret->error = dupprintf("unable to allocate security descriptor: %s",
273 win_strerror(GetLastError()));
277 if (!InitializeSecurityDescriptor(ret->psd,SECURITY_DESCRIPTOR_REVISION)) {
278 ret->error = dupprintf("unable to initialise security descriptor: %s",
279 win_strerror(GetLastError()));
283 if (!SetSecurityDescriptorDacl(ret->psd, TRUE, ret->acl, FALSE)) {
284 ret->error = dupprintf("unable to set DACL in security descriptor: %s",
285 win_strerror(GetLastError()));
289 if (!create_named_pipe(ret, TRUE)) {
290 ret->error = dupprintf("unable to create named pipe '%s': %s",
291 pipename, win_strerror(GetLastError()));
295 memset(&ret->connect_ovl, 0, sizeof(ret->connect_ovl));
296 ret->connect_ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
297 handle_add_foreign_event(ret->connect_ovl.hEvent,
298 named_pipe_connect_callback, ret);
299 named_pipe_accept_loop(ret, FALSE);
305 #endif /* !defined NO_SECURITY */