Skip to content

Commit

Permalink
fixes nanomsg#556 Support security attributes for Windows IPC
Browse files Browse the repository at this point in the history
Allow passing security descriptor to the ipc channel in Windows.
The tunables NN_IPC_SEC_ATTR, as well as NN_IPC_OUTBUFSZ and
NN_IPC_INBUFSZ are exposed on Windows when using the named pipe
based IPC.
  • Loading branch information
TTimo authored and gdamore committed Dec 9, 2015
1 parent c0e92dd commit c621fb4
Show file tree
Hide file tree
Showing 12 changed files with 304 additions and 9 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ add_libnanomsg_test (zerocopy)
add_libnanomsg_test (shutdown)
add_libnanomsg_test (cmsg)
add_libnanomsg_test (bug328)
add_libnanomsg_test (win_sec_attr)

# Build the performance tests.

Expand Down
7 changes: 7 additions & 0 deletions src/aio/usock_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ struct nn_usock {
/* For now we allocate a new buffer for each write to a named pipe. */
void *pipesendbuf;

/* Pointer to the security attribute structure */
SECURITY_ATTRIBUTES *sec_attr;

/* Out Buffer and In Buffer size */
int outbuffersz;
int inbuffersz;

/* Errno remembered in NN_USOCK_ERROR state */
int errnum;
};
17 changes: 9 additions & 8 deletions src/aio/usock_win.inc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner)
/* NamedPipe-related stuff. */
memset (&self->pipename, 0, sizeof (self->pipename));
self->pipesendbuf = NULL;
memset (&self->sec_attr, 0, sizeof (SECURITY_ATTRIBUTES));

/* default size for both in and out buffers is 4096 */
self->outbuffersz = 4096;
self->inbuffersz = 4096;
}

void nn_usock_term (struct nn_usock *self)
Expand Down Expand Up @@ -501,22 +506,19 @@ static void nn_usock_create_io_completion (struct nn_usock *self)
static void nn_usock_create_pipe (struct nn_usock *self, const char *name)
{
char fullname [256];

/* First, create a fully qualified name for the named pipe. */
_snprintf(fullname, sizeof (fullname), "\\\\.\\pipe\\%s", name);

/* TODO: Expose custom nOutBufferSize, nInBufferSize, nDefaultTimeOut,
lpSecurityAttributes */
self->p = CreateNamedPipeA (
(char*) fullname,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
PIPE_UNLIMITED_INSTANCES,
4096,
4096,
self->outbuffersz,
self->inbuffersz,
0,
NULL);
self->sec_attr);

/* TODO: How to properly handle self->p == INVALID_HANDLE_VALUE? */
win_assert (self->p != INVALID_HANDLE_VALUE);
Expand All @@ -535,12 +537,11 @@ DWORD nn_usock_open_pipe (struct nn_usock *self, const char *name)
/* First, create a fully qualified name for the named pipe. */
_snprintf(fullname, sizeof (fullname), "\\\\.\\pipe\\%s", name);

/* TODO: Expose a way to pass lpSecurityAttributes */
self->p = CreateFileA (
fullname,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
self->sec_attr,
OPEN_ALWAYS,
FILE_FLAG_OVERLAPPED,
NULL);
Expand Down
6 changes: 6 additions & 0 deletions src/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ int nn_sock_init (struct nn_sock *self, struct nn_socktype *socktype, int fd)
/* Should be pretty much enough space for just the number */
sprintf(self->socket_name, "%d", fd);

/* Security attribute */
self->sec_attr = NULL;
self->sec_attr_size = 0;
self->inbuffersz = 4096;
self->outbuffersz = 4096;

/* The transport-specific options are not initialised immediately,
rather, they are allocated later on when needed. */
for (i = 0; i != NN_MAX_TRANSPORT; ++i)
Expand Down
7 changes: 7 additions & 0 deletions src/core/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ struct nn_sock

/* The socket name for statistics */
char socket_name[64];

/* Win32 Security Attribute */
void * sec_attr;
size_t sec_attr_size;
int outbuffersz;
int inbuffersz;

};

/* Initialise the socket. */
Expand Down
5 changes: 5 additions & 0 deletions src/ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ extern "C" {

#define NN_IPC -2

// The object set here must be valid as long as you are using the socket
#define NN_IPC_SEC_ATTR 1
#define NN_IPC_OUTBUFSZ 2
#define NN_IPC_INBUFSZ 3

#ifdef __cplusplus
}
#endif
Expand Down
9 changes: 9 additions & 0 deletions src/transports/ipc/aipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ int nn_aipc_isidle (struct nn_aipc *self)

void nn_aipc_start (struct nn_aipc *self, struct nn_usock *listener)
{
size_t sz;
nn_assert_state (self, NN_AIPC_STATE_IDLE);

/* Take ownership of the listener socket. */
Expand All @@ -89,6 +90,14 @@ void nn_aipc_start (struct nn_aipc *self, struct nn_usock *listener)
self->listener_owner.fsm = &self->fsm;
nn_usock_swap_owner (listener, &self->listener_owner);

#if defined NN_HAVE_WINDOWS
/* Get/Set security attribute pointer*/
nn_epbase_getopt (self->epbase, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz);

nn_epbase_getopt (self->epbase, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz);
nn_epbase_getopt (self->epbase, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz);
#endif

/* Start the state machine. */
nn_fsm_start (&self->fsm);
}
Expand Down
1 change: 1 addition & 0 deletions src/transports/ipc/aipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "sipc.h"

#include "../../transport.h"
#include "../../ipc.h"

#include "../../aio/fsm.h"
#include "../../aio/usock.h"
Expand Down
8 changes: 8 additions & 0 deletions src/transports/ipc/cipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,14 @@ static void nn_cipc_start_connecting (struct nn_cipc *self)
ss.ss_family = AF_UNIX;
strncpy (un->sun_path, addr, sizeof (un->sun_path));

#if defined NN_HAVE_WINDOWS
/* Get/Set security attribute pointer*/
nn_epbase_getopt (&self->epbase, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz);

nn_epbase_getopt (&self->epbase, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz);
nn_epbase_getopt (&self->epbase, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz);
#endif

/* Start connecting. */
nn_usock_connect (&self->usock, (struct sockaddr*) &ss,
sizeof (struct sockaddr_un));
Expand Down
1 change: 1 addition & 0 deletions src/transports/ipc/cipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define NN_CIPC_INCLUDED

#include "../../transport.h"
#include "../../ipc.h"

/* State machine managing connected IPC socket. */

Expand Down
99 changes: 98 additions & 1 deletion src/transports/ipc/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "../../utils/alloc.h"
#include "../../utils/fast.h"
#include "../../utils/list.h"
#include "../../utils/cont.h"

#include <string.h>
#if defined NN_HAVE_WINDOWS
Expand All @@ -41,9 +42,32 @@
#include <unistd.h>
#endif

/* IPC-specific socket options. */
struct nn_ipc_optset {
struct nn_optset base;

/* Win32 Security Attribute */
void* sec_attr;

int outbuffersz;
int inbuffersz;
};

static void nn_ipc_optset_destroy (struct nn_optset *self);
static int nn_ipc_optset_setopt (struct nn_optset *self, int option,
const void *optval, size_t optvallen);
static int nn_ipc_optset_getopt (struct nn_optset *self, int option,
void *optval, size_t *optvallen);
static const struct nn_optset_vfptr nn_ipc_optset_vfptr = {
nn_ipc_optset_destroy,
nn_ipc_optset_setopt,
nn_ipc_optset_getopt
};

/* nn_transport interface. */
static int nn_ipc_bind (void *hint, struct nn_epbase **epbase);
static int nn_ipc_connect (void *hint, struct nn_epbase **epbase);
static struct nn_optset *nn_ipc_optset (void);

static struct nn_transport nn_ipc_vfptr = {
"ipc",
Expand All @@ -52,7 +76,7 @@ static struct nn_transport nn_ipc_vfptr = {
NULL,
nn_ipc_bind,
nn_ipc_connect,
NULL,
nn_ipc_optset,
NN_LIST_ITEM_INITIALIZER
};

Expand All @@ -68,3 +92,76 @@ static int nn_ipc_connect (void *hint, struct nn_epbase **epbase)
return nn_cipc_create (hint, epbase);
}

static struct nn_optset *nn_ipc_optset ()
{
struct nn_ipc_optset *optset;

optset = nn_alloc (sizeof (struct nn_ipc_optset), "optset (ipc)");
alloc_assert (optset);
optset->base.vfptr = &nn_ipc_optset_vfptr;

/* Default values for the IPC options */
optset->sec_attr = NULL;
optset->outbuffersz = 4096;
optset->inbuffersz = 4096;

return &optset->base;
}

static void nn_ipc_optset_destroy (struct nn_optset *self)
{
struct nn_ipc_optset *optset;

optset = nn_cont (self, struct nn_ipc_optset, base);
nn_free (optset);
}

static int nn_ipc_optset_setopt (struct nn_optset *self, int option,
const void *optval, size_t optvallen)
{
struct nn_ipc_optset *optset;

optset = nn_cont (self, struct nn_ipc_optset, base);
if (optvallen < sizeof (int)) {
return -EINVAL;
}

switch (option) {
case NN_IPC_SEC_ATTR:
optset->sec_attr = (void *)optval;
return 0;
case NN_IPC_OUTBUFSZ:
optset->outbuffersz = *(int *)optval;
return 0;
case NN_IPC_INBUFSZ:
optset->inbuffersz = *(int *)optval;
return 0;
default:
return -ENOPROTOOPT;
}
}

static int nn_ipc_optset_getopt (struct nn_optset *self, int option,
void *optval, size_t *optvallen)
{
struct nn_ipc_optset *optset;

optset = nn_cont (self, struct nn_ipc_optset, base);

switch (option) {
case NN_IPC_SEC_ATTR:
memcpy(optval, &optset->sec_attr, sizeof(optset->sec_attr));
*optvallen = sizeof(optset->sec_attr);
return 0;
case NN_IPC_OUTBUFSZ:
*(int *)optval = optset->outbuffersz;
*optvallen = sizeof (int);
return 0;
case NN_IPC_INBUFSZ:
*(int *)optval = optset->inbuffersz;
*optvallen = sizeof (int);
return 0;
default:
return -ENOPROTOOPT;
}
}
Loading

0 comments on commit c621fb4

Please sign in to comment.