aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-05-03 14:28:44 -0700
committerGarrett D'Amore <garrett@damore.org>2018-05-03 15:14:45 -0700
commitafd555af4fba0acbf16c174dd9dece24181a1a38 (patch)
tree9d49fec85c58ecad9a034a98e092627968494bc0 /src
parentfa986e725f08e30eab68e16765b2cf71613b871c (diff)
downloadnng-afd555af4fba0acbf16c174dd9dece24181a1a38.tar.gz
nng-afd555af4fba0acbf16c174dd9dece24181a1a38.tar.bz2
nng-afd555af4fba0acbf16c174dd9dece24181a1a38.zip
fixes #383 Would like peerid for IPC
We offer uid, gid, process id, and even zone id where we have them. Docs and tests are provided.
Diffstat (limited to 'src')
-rw-r--r--src/core/platform.h15
-rw-r--r--src/platform/posix/posix_aio.h2
-rw-r--r--src/platform/posix/posix_ipc.c64
-rw-r--r--src/platform/posix/posix_pipedesc.c68
-rw-r--r--src/platform/windows/win_ipc.c60
-rw-r--r--src/transport/ipc/ipc.c68
-rw-r--r--src/transport/ipc/ipc.h19
7 files changed, 293 insertions, 3 deletions
diff --git a/src/core/platform.h b/src/core/platform.h
index 671556d8..6e7acdbf 100644
--- a/src/core/platform.h
+++ b/src/core/platform.h
@@ -341,6 +341,21 @@ extern void nni_plat_ipc_pipe_send(nni_plat_ipc_pipe *, nni_aio *);
// The platform may modify the iovs.
extern void nni_plat_ipc_pipe_recv(nni_plat_ipc_pipe *, nni_aio *);
+// nni_plat_ipc_pipe_get_peer_uid obtains the peer user id, if possible.
+// NB: Only POSIX systems support user IDs.
+extern int nni_plat_ipc_pipe_get_peer_uid(nni_plat_ipc_pipe *, uint64_t *);
+
+// nni_plat_ipc_pipe_get_peer_gid obtains the peer group id, if possible.
+// NB: Only POSIX systems support group IDs.
+extern int nni_plat_ipc_pipe_get_peer_gid(nni_plat_ipc_pipe *, uint64_t *);
+
+// nni_plat_ipc_pipe_get_peer_pid obtains the peer process id, if possible.
+extern int nni_plat_ipc_pipe_get_peer_pid(nni_plat_ipc_pipe *, uint64_t *);
+
+// nni_plat_ipc_pipe_get_peer_zoneid obtains the peer zone id, if possible.
+// NB: Only illumos & SunOS systems have the notion of "zones".
+extern int nni_plat_ipc_pipe_get_peer_zoneid(nni_plat_ipc_pipe *, uint64_t *);
+
//
// UDP support. UDP is not connection oriented, and only has the notion
// of being bound, sendto, and recvfrom. (It is possible to set up a
diff --git a/src/platform/posix/posix_aio.h b/src/platform/posix/posix_aio.h
index 3954f225..7d6a7231 100644
--- a/src/platform/posix/posix_aio.h
+++ b/src/platform/posix/posix_aio.h
@@ -33,6 +33,8 @@ extern int nni_posix_pipedesc_peername(nni_posix_pipedesc *, nni_sockaddr *);
extern int nni_posix_pipedesc_sockname(nni_posix_pipedesc *, nni_sockaddr *);
extern int nni_posix_pipedesc_set_nodelay(nni_posix_pipedesc *, bool);
extern int nni_posix_pipedesc_set_keepalive(nni_posix_pipedesc *, bool);
+extern int nni_posix_pipedesc_get_peerid(
+ nni_posix_pipedesc *, uint64_t *, uint64_t *, uint64_t *, uint64_t *);
extern int nni_posix_epdesc_init(nni_posix_epdesc **, int);
extern void nni_posix_epdesc_set_local(nni_posix_epdesc *, void *, size_t);
diff --git a/src/platform/posix/posix_ipc.c b/src/platform/posix/posix_ipc.c
index c1bb9292..5ba3c8fb 100644
--- a/src/platform/posix/posix_ipc.c
+++ b/src/platform/posix/posix_ipc.c
@@ -183,4 +183,68 @@ nni_plat_ipc_pipe_recv(nni_plat_ipc_pipe *p, nni_aio *aio)
nni_posix_pipedesc_recv((void *) p, aio);
}
+int
+nni_plat_ipc_pipe_get_peer_uid(nni_plat_ipc_pipe *p, uint64_t *uid)
+{
+ int rv;
+ uint64_t ignore;
+
+ if ((rv = nni_posix_pipedesc_get_peerid(
+ (void *) p, uid, &ignore, &ignore, &ignore)) != 0) {
+ return (rv);
+ }
+ return (0);
+}
+
+int
+nni_plat_ipc_pipe_get_peer_gid(nni_plat_ipc_pipe *p, uint64_t *gid)
+{
+ int rv;
+ uint64_t ignore;
+
+ if ((rv = nni_posix_pipedesc_get_peerid(
+ (void *) p, &ignore, gid, &ignore, &ignore)) != 0) {
+ return (rv);
+ }
+ return (0);
+}
+
+int
+nni_plat_ipc_pipe_get_peer_zoneid(nni_plat_ipc_pipe *p, uint64_t *zid)
+{
+ int rv;
+ uint64_t ignore;
+ uint64_t id;
+
+ if ((rv = nni_posix_pipedesc_get_peerid(
+ (void *) p, &ignore, &ignore, &ignore, &id)) != 0) {
+ return (rv);
+ }
+ if (id == (uint64_t) -1) {
+ // NB: -1 is not a legal zone id (illumos/Solaris)
+ return (NNG_ENOTSUP);
+ }
+ *zid = id;
+ return (0);
+}
+
+int
+nni_plat_ipc_pipe_get_peer_pid(nni_plat_ipc_pipe *p, uint64_t *pid)
+{
+ int rv;
+ uint64_t ignore;
+ uint64_t id;
+
+ if ((rv = nni_posix_pipedesc_get_peerid(
+ (void *) p, &ignore, &ignore, &id, &ignore)) != 0) {
+ return (rv);
+ }
+ if (id == (uint64_t) -1) {
+ // NB: -1 is not a legal process id
+ return (NNG_ENOTSUP);
+ }
+ *pid = id;
+ return (0);
+}
+
#endif // NNG_PLATFORM_POSIX
diff --git a/src/platform/posix/posix_pipedesc.c b/src/platform/posix/posix_pipedesc.c
index f9cbb94b..61005ca8 100644
--- a/src/platform/posix/posix_pipedesc.c
+++ b/src/platform/posix/posix_pipedesc.c
@@ -26,6 +26,12 @@
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
+#if defined(NNG_HAVE_GETPEERUCRED)
+#include <ucred.h>
+#elif defined(NNG_HAVE_LOCALPEERCRED)
+#include <sys/ucred.h>
+#include <sys/un.h>
+#endif
// nni_posix_pipedesc is a descriptor kept one per transport pipe (i.e. open
// file descriptor for TCP socket, etc.) This contains the list of pending
@@ -402,6 +408,68 @@ nni_posix_pipedesc_init(nni_posix_pipedesc **pdp, int fd)
return (0);
}
+int
+nni_posix_pipedesc_get_peerid(nni_posix_pipedesc *pd, uint64_t *euid,
+ uint64_t *egid, uint64_t *prid, uint64_t *znid)
+{
+ int fd = pd->node.fd;
+#if defined(NNG_HAVE_GETPEEREID)
+ uid_t uid;
+ gid_t gid;
+
+ if (getpeereid(fd, &uid, &gid) != 0) {
+ return (nni_plat_errno(errno));
+ }
+ *euid = uid;
+ *egid = gid;
+ *prid = (uint64_t) -1;
+ *znid = (uint64_t) -1;
+ return (0);
+#elif defined(NNG_HAVE_GETPEERUCRED)
+ ucred *ucp;
+ if (getpeerucred(fd, &ucp) != 0) {
+ return (nni_plat_errno(errno));
+ }
+ *euid = ucred_geteuid(ucp);
+ *egid = ucred_geteuid(ucp);
+ *prid = ucred_getpid(ucp);
+ *znid = ucred_getzoneid(ucp);
+ ucred_free(ucp);
+ return (0);
+#elif defined(NNG_HAVE_SOPEERCRED)
+ struct ucred uc;
+ socklen_t len = sizeof(uc);
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) != 0) {
+ return (nni_plat_errno(errno));
+ }
+ *euid = uc.uid;
+ *egid = uc.gid;
+ *prid = uc.pid;
+ *znid = (uint64_t) -1;
+ return (0);
+#elif defined(NNG_HAVE_LOCALPEERCRED)
+ struct xucred xu;
+ socklen_t len = sizeof(xu);
+ if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERCRED, &xu, &len) != 0) {
+ return (nni_plat_errno(errno));
+ }
+ *euid = xu.cr_uid;
+ *egid = xu.cr_gid;
+ *prid = (uint64_t) -1; // XXX: macOS has undocumented LOCAL_PEERPID...
+ *znid = (uint64_t) -1;
+ return (0);
+#else
+ if (fd < 0) {
+ return (NNG_ECLOSED);
+ }
+ NNI_ARG_UNUSED(euid);
+ NNI_ARG_UNUSED(egid);
+ NNI_ARG_UNUSED(prid);
+ NNI_ARG_UNUSED(znid);
+ return (NNG_ENOTSUP);
+#endif
+}
+
void
nni_posix_pipedesc_fini(nni_posix_pipedesc *pd)
{
diff --git a/src/platform/windows/win_ipc.c b/src/platform/windows/win_ipc.c
index 7d118672..c6376cc7 100644
--- a/src/platform/windows/win_ipc.c
+++ b/src/platform/windows/win_ipc.c
@@ -16,6 +16,7 @@
struct nni_plat_ipc_pipe {
HANDLE p;
+ int mode;
nni_win_event rcv_ev;
nni_win_event snd_ev;
};
@@ -128,7 +129,7 @@ nni_win_ipc_pipe_finish(nni_win_event *evt, nni_aio *aio)
}
static int
-nni_win_ipc_pipe_init(nni_plat_ipc_pipe **pipep, HANDLE p)
+nni_win_ipc_pipe_init(nni_plat_ipc_pipe **pipep, HANDLE p, int mode)
{
nni_plat_ipc_pipe *pipe;
int rv;
@@ -136,6 +137,7 @@ nni_win_ipc_pipe_init(nni_plat_ipc_pipe **pipep, HANDLE p)
if ((pipe = NNI_ALLOC_STRUCT(pipe)) == NULL) {
return (NNG_ENOMEM);
}
+ pipe->mode = mode;
rv = nni_win_event_init(&pipe->rcv_ev, &nni_win_ipc_pipe_ops, pipe);
if (rv != 0) {
nni_plat_ipc_pipe_fini(pipe);
@@ -189,6 +191,56 @@ nni_plat_ipc_pipe_fini(nni_plat_ipc_pipe *pipe)
}
int
+nni_plat_ipc_pipe_get_peer_uid(nni_plat_ipc_pipe *pipe, uint64_t *id)
+{
+ NNI_ARG_UNUSED(pipe);
+ NNI_ARG_UNUSED(id);
+ return (NNG_ENOTSUP);
+}
+
+int
+nni_plat_ipc_pipe_get_peer_gid(nni_plat_ipc_pipe *pipe, uint64_t *id)
+{
+ NNI_ARG_UNUSED(pipe);
+ NNI_ARG_UNUSED(id);
+ return (NNG_ENOTSUP);
+}
+
+int
+nni_plat_ipc_pipe_get_peer_zoneid(nni_plat_ipc_pipe *pipe, uint64_t *id)
+{
+ NNI_ARG_UNUSED(pipe);
+ NNI_ARG_UNUSED(id);
+ return (NNG_ENOTSUP);
+}
+
+// nni_plat_ipc_pipe_get_peer_gid obtains the peer group id, if possible.
+// NB: Only POSIX systems support group IDs.
+int
+nni_plat_ipc_pipe_get_peer_pid(nni_plat_ipc_pipe *pipe, uint64_t *pid)
+{
+ ULONG id;
+ switch (pipe->mode) {
+ case NNI_EP_MODE_DIAL:
+ if (!GetNamedPipeServerProcessId(pipe->p, &id)) {
+ return (nni_win_error(GetLastError()));
+ }
+ *pid = id;
+ break;
+ case NNI_EP_MODE_LISTEN:
+ if (!GetNamedPipeClientProcessId(pipe->p, &id)) {
+ return (nni_win_error(GetLastError()));
+ }
+ *pid = id;
+ break;
+ default:
+ // Should never occur!
+ return (NNG_EINVAL);
+ }
+ return (0);
+}
+
+int
nni_plat_ipc_ep_init(nni_plat_ipc_ep **epp, const nni_sockaddr *sa, int mode)
{
const char * path;
@@ -331,7 +383,8 @@ nni_win_ipc_acc_finish(nni_win_event *evt, nni_aio *aio)
oldp = ep->p;
ep->p = newp;
- if ((rv = nni_win_ipc_pipe_init(&pipe, oldp)) != 0) {
+ if ((rv = nni_win_ipc_pipe_init(&pipe, oldp, NNI_EP_MODE_LISTEN)) !=
+ 0) {
// The new pipe is already fine for us. Discard
// the old one, since failed to be able to use it.
DisconnectNamedPipe(oldp);
@@ -466,7 +519,8 @@ nni_win_ipc_conn_thr(void *arg)
}
goto fail;
}
- if (((rv = nni_win_ipc_pipe_init(&pipe, p)) != 0) ||
+ if (((rv = nni_win_ipc_pipe_init(
+ &pipe, p, NNI_EP_MODE_DIAL)) != 0) ||
((rv = nni_win_iocp_register(p)) != 0)) {
goto fail;
}
diff --git a/src/transport/ipc/ipc.c b/src/transport/ipc/ipc.c
index 3dbccb50..e5f3d533 100644
--- a/src/transport/ipc/ipc.c
+++ b/src/transport/ipc/ipc.c
@@ -537,6 +537,54 @@ nni_ipc_pipe_get_addr(void *arg, void *buf, size_t *szp, int typ)
return (nni_copyout_sockaddr(&p->sa, buf, szp, typ));
}
+static int
+nni_ipc_pipe_get_peer_uid(void *arg, void *buf, size_t *szp, int typ)
+{
+ nni_ipc_pipe *p = arg;
+ uint64_t id;
+ int rv;
+ if ((rv = nni_plat_ipc_pipe_get_peer_uid(p->ipp, &id)) != 0) {
+ return (rv);
+ }
+ return (nni_copyout_u64(id, buf, szp, typ));
+}
+
+static int
+nni_ipc_pipe_get_peer_gid(void *arg, void *buf, size_t *szp, int typ)
+{
+ nni_ipc_pipe *p = arg;
+ uint64_t id;
+ int rv;
+ if ((rv = nni_plat_ipc_pipe_get_peer_gid(p->ipp, &id)) != 0) {
+ return (rv);
+ }
+ return (nni_copyout_u64(id, buf, szp, typ));
+}
+
+static int
+nni_ipc_pipe_get_peer_pid(void *arg, void *buf, size_t *szp, int typ)
+{
+ nni_ipc_pipe *p = arg;
+ uint64_t id;
+ int rv;
+ if ((rv = nni_plat_ipc_pipe_get_peer_pid(p->ipp, &id)) != 0) {
+ return (rv);
+ }
+ return (nni_copyout_u64(id, buf, szp, typ));
+}
+
+static int
+nni_ipc_pipe_get_peer_zoneid(void *arg, void *buf, size_t *szp, int typ)
+{
+ nni_ipc_pipe *p = arg;
+ uint64_t id;
+ int rv;
+ if ((rv = nni_plat_ipc_pipe_get_peer_zoneid(p->ipp, &id)) != 0) {
+ return (rv);
+ }
+ return (nni_copyout_u64(id, buf, szp, typ));
+}
+
static void
nni_ipc_ep_fini(void *arg)
{
@@ -785,6 +833,26 @@ static nni_tran_pipe_option nni_ipc_pipe_options[] = {
.po_type = NNI_TYPE_SOCKADDR,
.po_getopt = nni_ipc_pipe_get_addr,
},
+ {
+ .po_name = NNG_OPT_IPC_PEER_UID,
+ .po_type = NNI_TYPE_UINT64,
+ .po_getopt = nni_ipc_pipe_get_peer_uid,
+ },
+ {
+ .po_name = NNG_OPT_IPC_PEER_GID,
+ .po_type = NNI_TYPE_UINT64,
+ .po_getopt = nni_ipc_pipe_get_peer_gid,
+ },
+ {
+ .po_name = NNG_OPT_IPC_PEER_PID,
+ .po_type = NNI_TYPE_UINT64,
+ .po_getopt = nni_ipc_pipe_get_peer_pid,
+ },
+ {
+ .po_name = NNG_OPT_IPC_PEER_ZONEID,
+ .po_type = NNI_TYPE_UINT64,
+ .po_getopt = nni_ipc_pipe_get_peer_zoneid,
+ },
// terminate list
{
.po_name = NULL,
diff --git a/src/transport/ipc/ipc.h b/src/transport/ipc/ipc.h
index 42cbdb08..497fb2b5 100644
--- a/src/transport/ipc/ipc.h
+++ b/src/transport/ipc/ipc.h
@@ -28,4 +28,23 @@ NNG_DECL int nng_ipc_register(void);
// this for security.
#define NNG_OPT_IPC_PERMISSIONS "ipc:permissions"
+// Peer UID. This is only available on POSIX style systems.
+#define NNG_OPT_IPC_PEER_UID "ipc:peer-uid"
+
+// Peer GID (primary group). This is only available on POSIX style systems.
+#define NNG_OPT_IPC_PEER_GID "ipc:peer-gid"
+
+// Peer process ID. Available on Windows, Linux, and SunOS.
+// In theory we could obtain this with the first message sent,
+// but we have elected not to do this for now. (Nice RFE for a FreeBSD
+// guru though.)
+#define NNG_OPT_IPC_PEER_PID "ipc:peer-pid"
+
+// Peer Zone ID. Only on SunOS systems. (Linux containers have no
+// definable kernel identity; they are a user-land fabrication made up
+// from various pieces of different namespaces. FreeBSD does have
+// something called JailIDs, but it isn't obvious how to determine this,
+// or even if processes can use IPC across jail boundaries.)
+#define NNG_OPT_IPC_PEER_ZONEID "ipc:peer-zoneid"
+
#endif // NNG_TRANSPORT_IPC_IPC_H