1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

winnpc.c: add low-level connect_to_named_pipe() function.

This contains most of the guts of the previously monolithic function
new_named_pipe_client(), but it directly returns the HANDLE to the
opened pipe, or a string error message on failure.

new_named_pipe_client() is now a thin veneer on top of that, which
returns a Socket * by wrapping up the HANDLE into a HandleSocket or
the error message into an ErrorSocket as appropriate.

So it's now possible to connect to a named pipe, using all our usual
infrastructure (including in particular the ownership check of the
server, to defend against spoofing attacks), without having to have a
Socket-capable event loop in progress.
This commit is contained in:
Simon Tatham 2020-01-01 18:58:11 +00:00
parent e305974313
commit 39248737a4
4 changed files with 39 additions and 14 deletions

View File

@ -55,7 +55,7 @@ static const SocketVtable ErrorSocket_sockvt = {
sk_error_peer_info, sk_error_peer_info,
}; };
static Socket *new_error_socket_internal(char *errmsg, Plug *plug) Socket *new_error_socket_consume_string(Plug *plug, char *errmsg)
{ {
ErrorSocket *es = snew(ErrorSocket); ErrorSocket *es = snew(ErrorSocket);
es->sock.vt = &ErrorSocket_sockvt; es->sock.vt = &ErrorSocket_sockvt;
@ -73,5 +73,5 @@ Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...)
msg = dupvprintf(fmt, ap); msg = dupvprintf(fmt, ap);
va_end(ap); va_end(ap);
return new_error_socket_internal(msg, plug); return new_error_socket_consume_string(plug, msg);
} }

View File

@ -264,8 +264,12 @@ char *get_hostname(void);
/* /*
* Trivial socket implementation which just stores an error. Found in * Trivial socket implementation which just stores an error. Found in
* errsock.c. * errsock.c.
*
* The consume_string variant takes an already-formatted dynamically
* allocated string, and takes over ownership of that string.
*/ */
Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...); Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...);
Socket *new_error_socket_consume_string(Plug *plug, char *errmsg);
/* /*
* Trivial plug that does absolutely nothing. Found in nullplug.c. * Trivial plug that does absolutely nothing. Found in nullplug.c.

View File

@ -15,7 +15,7 @@
#include "winsecur.h" #include "winsecur.h"
Socket *new_named_pipe_client(const char *pipename, Plug *plug) HANDLE connect_to_named_pipe(const char *pipename, char **err)
{ {
HANDLE pipehandle; HANDLE pipehandle;
PSID usersid, pipeowner; PSID usersid, pipeowner;
@ -33,9 +33,10 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug)
break; break;
if (GetLastError() != ERROR_PIPE_BUSY) { if (GetLastError() != ERROR_PIPE_BUSY) {
return new_error_socket_fmt( *err = dupprintf(
plug, "Unable to open named pipe '%s': %s", "Unable to open named pipe '%s': %s",
pipename, win_strerror(GetLastError())); pipename, win_strerror(GetLastError()));
return INVALID_HANDLE_VALUE;
} }
/* /*
@ -46,16 +47,18 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug)
* take excessively long.) * take excessively long.)
*/ */
if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT)) { if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT)) {
return new_error_socket_fmt( *err = dupprintf(
plug, "Error waiting for named pipe '%s': %s", "Error waiting for named pipe '%s': %s",
pipename, win_strerror(GetLastError())); pipename, win_strerror(GetLastError()));
return INVALID_HANDLE_VALUE;
} }
} }
if ((usersid = get_user_sid()) == NULL) { if ((usersid = get_user_sid()) == NULL) {
CloseHandle(pipehandle); CloseHandle(pipehandle);
return new_error_socket_fmt( *err = dupprintf(
plug, "Unable to get user SID: %s", win_strerror(GetLastError())); "Unable to get user SID: %s", win_strerror(GetLastError()));
return INVALID_HANDLE_VALUE;
} }
if (p_GetSecurityInfo(pipehandle, SE_KERNEL_OBJECT, if (p_GetSecurityInfo(pipehandle, SE_KERNEL_OBJECT,
@ -63,21 +66,33 @@ Socket *new_named_pipe_client(const char *pipename, Plug *plug)
&pipeowner, NULL, NULL, NULL, &pipeowner, NULL, NULL, NULL,
&psd) != ERROR_SUCCESS) { &psd) != ERROR_SUCCESS) {
CloseHandle(pipehandle); CloseHandle(pipehandle);
return new_error_socket_fmt( *err = dupprintf(
plug, "Unable to get named pipe security information: %s", "Unable to get named pipe security information: %s",
win_strerror(GetLastError())); win_strerror(GetLastError()));
return INVALID_HANDLE_VALUE;
} }
if (!EqualSid(pipeowner, usersid)) { if (!EqualSid(pipeowner, usersid)) {
CloseHandle(pipehandle); CloseHandle(pipehandle);
LocalFree(psd); LocalFree(psd);
return new_error_socket_fmt( *err = dupprintf(
plug, "Owner of named pipe '%s' is not us", pipename); "Owner of named pipe '%s' is not us", pipename);
return INVALID_HANDLE_VALUE;
} }
LocalFree(psd); LocalFree(psd);
return make_handle_socket(pipehandle, pipehandle, NULL, plug, true); return pipehandle;
}
Socket *new_named_pipe_client(const char *pipename, Plug *plug)
{
char *err = NULL;
HANDLE pipehandle = connect_to_named_pipe(pipename, &err);
if (pipehandle == INVALID_HANDLE_VALUE)
return new_error_socket_consume_string(plug, err);
else
return make_handle_socket(pipehandle, pipehandle, NULL, plug, true);
} }
#endif /* !defined NO_SECURITY */ #endif /* !defined NO_SECURITY */

View File

@ -373,6 +373,12 @@ Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H,
Socket *new_named_pipe_client(const char *pipename, Plug *plug); /* winnpc */ Socket *new_named_pipe_client(const char *pipename, Plug *plug); /* winnpc */
Socket *new_named_pipe_listener(const char *pipename, Plug *plug); /* winnps */ Socket *new_named_pipe_listener(const char *pipename, Plug *plug); /* winnps */
/* A lower-level function in winnpc.c, which does most of the work of
* new_named_pipe_client (including checking the ownership of what
* it's connected to), but returns a plain HANDLE instead of wrapping
* it into a Socket. */
HANDLE connect_to_named_pipe(const char *pipename, char **err);
/* /*
* Exports from winctrls.c. * Exports from winctrls.c.
*/ */