handle unix credentials
This commit is contained in:
@@ -49,6 +49,10 @@
|
|||||||
#include <krb5-types.h>
|
#include <krb5-types.h>
|
||||||
#include <asn1-common.h>
|
#include <asn1-common.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_UN_H
|
||||||
|
#include <sys/un.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <base64.h>
|
#include <base64.h>
|
||||||
|
|
||||||
#include <heim-ipc.h>
|
#include <heim-ipc.h>
|
||||||
|
162
lib/ipc/server.c
162
lib/ipc/server.c
@@ -456,6 +456,7 @@ struct client {
|
|||||||
#define INHERIT_MASK 0xffff0000
|
#define INHERIT_MASK 0xffff0000
|
||||||
#define INCLUDE_ERROR_CODE (1 << 16)
|
#define INCLUDE_ERROR_CODE (1 << 16)
|
||||||
#define ALLOW_HTTP (1<<17)
|
#define ALLOW_HTTP (1<<17)
|
||||||
|
#define UNIX_SOCKET (1<<18)
|
||||||
unsigned calls;
|
unsigned calls;
|
||||||
size_t ptr, len;
|
size_t ptr, len;
|
||||||
uint8_t *inmsg;
|
uint8_t *inmsg;
|
||||||
@@ -465,6 +466,11 @@ struct client {
|
|||||||
dispatch_source_t in;
|
dispatch_source_t in;
|
||||||
dispatch_source_t out;
|
dispatch_source_t out;
|
||||||
#endif
|
#endif
|
||||||
|
struct {
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
pid_t pid;
|
||||||
|
} unixrights;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef HAVE_GCD
|
#ifndef HAVE_GCD
|
||||||
@@ -476,6 +482,132 @@ static void handle_read(struct client *);
|
|||||||
static void handle_write(struct client *);
|
static void handle_write(struct client *);
|
||||||
static int maybe_close(struct client *);
|
static int maybe_close(struct client *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update peer credentials from socket.
|
||||||
|
*
|
||||||
|
* SCM_CREDS can only be updated the first time there is read data to
|
||||||
|
* read from the filedescriptor, so if we read do it before this
|
||||||
|
* point, the cred data might not be is not there yet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
update_client_creds(struct client *c)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_GETPEERUCRED
|
||||||
|
/* Solaris 10 */
|
||||||
|
{
|
||||||
|
ucred_t *peercred;
|
||||||
|
|
||||||
|
if (getpeerucred(c->fd, &peercred) != 0) {
|
||||||
|
c->unixrights.uid = ucred_geteuid(peercred);
|
||||||
|
c->unixrights.gid = ucred_getegid(peercred);
|
||||||
|
c->unixrights.pid = 0;
|
||||||
|
ucred_free(peercred);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_GETPEEREID
|
||||||
|
/* FreeBSD, OpenBSD */
|
||||||
|
{
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
|
||||||
|
if (getpeereid(c->fd, &uid, &gid) == 0) {
|
||||||
|
c->unixrights.uid = uid;
|
||||||
|
c->unixrights.gid = gid;
|
||||||
|
c->unixrights.pid = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef SO_PEERCRED
|
||||||
|
/* Linux */
|
||||||
|
{
|
||||||
|
struct ucred pc;
|
||||||
|
socklen_t pclen = sizeof(pc);
|
||||||
|
|
||||||
|
if (getsockopt(c->fd, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) {
|
||||||
|
c->unixrights.uid = pc.uid;
|
||||||
|
c->unixrights.gid = pc.gid;
|
||||||
|
c->unixrights.pid = pc.pid;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
|
||||||
|
{
|
||||||
|
struct xucred peercred;
|
||||||
|
socklen_t peercredlen = sizeof(peercred);
|
||||||
|
|
||||||
|
if (getsockopt(c->fd, LOCAL_PEERCRED, 1,
|
||||||
|
(void *)&peercred, &peercredlen) == 0
|
||||||
|
&& peercred.cr_version == XUCRED_VERSION)
|
||||||
|
{
|
||||||
|
c->unixrights.uid = peercred.cr_uid;
|
||||||
|
c->unixrights.gid = peercred.cr_gid;
|
||||||
|
c->unixrights.pid = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
|
||||||
|
/* NetBSD */
|
||||||
|
if (c->unixrights.uid == -1) {
|
||||||
|
struct msghdr msg;
|
||||||
|
socklen_t crmsgsize;
|
||||||
|
void *crmsg;
|
||||||
|
struct cmsghdr *cmp;
|
||||||
|
struct sockcred *sc;
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
|
||||||
|
if (crmsgsize == 0)
|
||||||
|
return 1 ;
|
||||||
|
|
||||||
|
crmsg = malloc(crmsgsize);
|
||||||
|
if (crmsg == NULL)
|
||||||
|
goto failed_scm_creds;
|
||||||
|
|
||||||
|
memset(crmsg, 0, crmsgsize);
|
||||||
|
|
||||||
|
msg.msg_control = crmsg;
|
||||||
|
msg.msg_controllen = crmsgsize;
|
||||||
|
|
||||||
|
if (recvmsg(c->fd, &msg, 0) < 0) {
|
||||||
|
free(crmsg);
|
||||||
|
goto failed_scm_creds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
|
||||||
|
free(crmsg);
|
||||||
|
goto failed_scm_creds;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp = CMSG_FIRSTHDR(&msg);
|
||||||
|
if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
|
||||||
|
free(crmsg);
|
||||||
|
goto failed_scm_creds;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
|
||||||
|
|
||||||
|
c->unixrights.uid = sc->sc_euid;
|
||||||
|
c->unixrights.gid = sc->sc_egid;
|
||||||
|
c->unixrights.pid = 0;
|
||||||
|
|
||||||
|
free(crmsg);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
/* we already got the cred, just return it */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
failed_scm_creds:
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct client *
|
static struct client *
|
||||||
add_new_socket(int fd,
|
add_new_socket(int fd,
|
||||||
int flags,
|
int flags,
|
||||||
@@ -569,6 +701,7 @@ maybe_close(struct client *c)
|
|||||||
struct socket_call {
|
struct socket_call {
|
||||||
heim_idata in;
|
heim_idata in;
|
||||||
struct client *c;
|
struct client *c;
|
||||||
|
heim_icred cred;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -616,7 +749,8 @@ socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->calls--;
|
c->calls--;
|
||||||
|
if (sc->cred)
|
||||||
|
heim_ipc_free_cred(sc->cred);
|
||||||
free(sc->in.data);
|
free(sc->in.data);
|
||||||
sc->c = NULL; /* so we can catch double complete */
|
sc->c = NULL; /* so we can catch double complete */
|
||||||
free(sc);
|
free(sc);
|
||||||
@@ -799,8 +933,15 @@ handle_read(struct client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->calls++;
|
c->calls++;
|
||||||
|
|
||||||
|
if ((c->flags & UNIX_SOCKET) != 0) {
|
||||||
|
if (update_client_creds(c))
|
||||||
|
_heim_ipc_create_cred(c->unixrights.uid, c->unixrights.gid,
|
||||||
|
c->unixrights.pid, -1, &cs->cred);
|
||||||
|
}
|
||||||
|
|
||||||
c->callback(c->userctx, &cs->in,
|
c->callback(c->userctx, &cs->in,
|
||||||
NULL, socket_complete,
|
cs->cred, socket_complete,
|
||||||
(heim_sipc_call)cs);
|
(heim_sipc_call)cs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -924,6 +1065,11 @@ heim_sipc_stream_listener(int fd, int type,
|
|||||||
|
|
||||||
ct->mech = c;
|
ct->mech = c;
|
||||||
ct->release = socket_release;
|
ct->release = socket_release;
|
||||||
|
|
||||||
|
c->unixrights.uid = (uid_t) -1;
|
||||||
|
c->unixrights.gid = (gid_t) -1;
|
||||||
|
c->unixrights.pid = (pid_t) 0;
|
||||||
|
|
||||||
*ctx = ct;
|
*ctx = ct;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -934,7 +1080,7 @@ heim_sipc_service_unix(const char *service,
|
|||||||
void *user, heim_sipc *ctx)
|
void *user, heim_sipc *ctx)
|
||||||
{
|
{
|
||||||
struct sockaddr_un un;
|
struct sockaddr_un un;
|
||||||
int fd;
|
int fd, ret;
|
||||||
|
|
||||||
un.sun_family = AF_UNIX;
|
un.sun_family = AF_UNIX;
|
||||||
|
|
||||||
@@ -966,8 +1112,14 @@ heim_sipc_service_unix(const char *service,
|
|||||||
|
|
||||||
chmod(un.sun_path, 0666);
|
chmod(un.sun_path, 0666);
|
||||||
|
|
||||||
return heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC,
|
ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC,
|
||||||
callback, user, ctx);
|
callback, user, ctx);
|
||||||
|
if (ret == 0) {
|
||||||
|
struct client *c = (*ctx)->mech;
|
||||||
|
c->flags |= UNIX_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user