Skip to content

Commit 8b2450e

Browse files
committed
Merge pull request #173 from dpejesh/socket
ipc: set gid on unix sockets
2 parents 2dd75de + 4f13125 commit 8b2450e

File tree

3 files changed

+162
-124
lines changed

3 files changed

+162
-124
lines changed

lib/ipc_int.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct qb_ipcc_funcs {
9191
struct qb_ipcc_connection {
9292
char name[NAME_MAX];
9393
int32_t needs_sock_for_poll;
94+
gid_t egid;
9495
struct qb_ipc_one_way setup;
9596
struct qb_ipc_one_way request;
9697
struct qb_ipc_one_way response;

lib/ipc_setup.c

Lines changed: 152 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ struct ipc_auth_ugp {
5151
struct ipc_auth_data {
5252
int32_t sock;
5353
struct qb_ipcs_service *s;
54-
struct qb_ipc_connection_request msg;
54+
union {
55+
struct qb_ipc_connection_request req;
56+
struct qb_ipc_connection_response res;
57+
} msg;
5558
struct msghdr msg_recv;
5659
struct iovec iov_recv;
5760
struct ipc_auth_ugp ugp;
@@ -311,12 +314,138 @@ qb_ipcc_us_sock_close(int32_t sock)
311314
close(sock);
312315
}
313316

317+
static int32_t
318+
qb_ipc_auth_creds(struct ipc_auth_data *data)
319+
{
320+
int32_t res = 0;
321+
322+
/*
323+
* currently support getpeerucred, getpeereid, and SO_PASSCRED credential
324+
* retrieval mechanisms for various Platforms
325+
*/
326+
#ifdef HAVE_GETPEERUCRED
327+
/*
328+
* Solaris and some BSD systems
329+
*/
330+
{
331+
ucred_t *uc = NULL;
332+
333+
if (getpeerucred(data->sock, &uc) == 0) {
334+
res = 0;
335+
data->ugp.uid = ucred_geteuid(uc);
336+
data->ugp.gid = ucred_getegid(uc);
337+
data->ugp.pid = ucred_getpid(uc);
338+
ucred_free(uc);
339+
} else {
340+
res = -errno;
341+
}
342+
}
343+
#elif defined(HAVE_GETPEEREID)
344+
/*
345+
* Usually MacOSX systems
346+
*/
347+
{
348+
/*
349+
* TODO get the peer's pid.
350+
* c->pid = ?;
351+
*/
352+
if (getpeereid(data->sock, &data->ugp.uid, &data->ugp.gid) == 0) {
353+
res = 0;
354+
} else {
355+
res = -errno;
356+
}
357+
}
358+
359+
#elif defined(SO_PASSCRED)
360+
/*
361+
* Usually Linux systems
362+
*/
363+
{
364+
struct ucred cred;
365+
struct cmsghdr *cmsg;
366+
367+
res = -EINVAL;
368+
for (cmsg = CMSG_FIRSTHDR(&data->msg_recv); cmsg != NULL;
369+
cmsg = CMSG_NXTHDR(&data->msg_recv, cmsg)) {
370+
if (cmsg->cmsg_type != SCM_CREDENTIALS)
371+
continue;
372+
373+
memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
374+
res = 0;
375+
data->ugp.pid = cred.pid;
376+
data->ugp.uid = cred.uid;
377+
data->ugp.gid = cred.gid;
378+
break;
379+
}
380+
}
381+
#else /* no credentials */
382+
data->ugp.pid = 0;
383+
data->ugp.uid = 0;
384+
data->ugp.gid = 0;
385+
res = -ENOTSUP;
386+
#endif /* no credentials */
387+
388+
return res;
389+
}
390+
391+
static void
392+
destroy_ipc_auth_data(struct ipc_auth_data *data)
393+
{
394+
if (data->s) {
395+
qb_ipcs_unref(data->s);
396+
}
397+
398+
#ifdef SO_PASSCRED
399+
free(data->cmsg_cred);
400+
#endif
401+
free(data);
402+
}
403+
404+
static struct ipc_auth_data *
405+
init_ipc_auth_data(int sock, size_t len)
406+
{
407+
struct ipc_auth_data *data = calloc(1, sizeof(struct ipc_auth_data));
408+
409+
if (data == NULL) {
410+
return NULL;
411+
}
412+
413+
data->msg_recv.msg_iov = &data->iov_recv;
414+
data->msg_recv.msg_iovlen = 1;
415+
data->msg_recv.msg_name = 0;
416+
data->msg_recv.msg_namelen = 0;
417+
418+
#ifdef SO_PASSCRED
419+
data->cmsg_cred = calloc(1, CMSG_SPACE(sizeof(struct ucred)));
420+
if (data->cmsg_cred == NULL) {
421+
destroy_ipc_auth_data(data);
422+
return NULL;
423+
}
424+
data->msg_recv.msg_control = (void *)data->cmsg_cred;
425+
data->msg_recv.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
426+
#endif
427+
#ifdef QB_SOLARIS
428+
data->msg_recv.msg_accrights = 0;
429+
data->msg_recv.msg_accrightslen = 0;
430+
#else
431+
data->msg_recv.msg_flags = 0;
432+
#endif /* QB_SOLARIS */
433+
434+
data->len = len;
435+
data->iov_recv.iov_base = &data->msg;
436+
data->iov_recv.iov_len = data->len;
437+
data->sock = sock;
438+
439+
return data;
440+
}
441+
314442
int32_t
315443
qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
316444
struct qb_ipc_connection_response *r)
317445
{
318446
int32_t res;
319447
struct qb_ipc_connection_request request;
448+
struct ipc_auth_data *data;
320449
#ifdef QB_LINUX
321450
int off = 0;
322451
int on = 1;
@@ -340,22 +469,33 @@ qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
340469
qb_ipcc_us_sock_close(c->setup.u.us.sock);
341470
return res;
342471
}
472+
473+
data = init_ipc_auth_data(c->setup.u.us.sock, sizeof(struct qb_ipc_connection_response));
474+
if (data == NULL) {
475+
qb_ipcc_us_sock_close(c->setup.u.us.sock);
476+
return -ENOMEM;
477+
}
478+
479+
qb_ipc_us_ready(&c->setup, NULL, -1, POLLIN);
480+
res = qb_ipc_us_recv_msghdr(data);
481+
343482
#ifdef QB_LINUX
344483
setsockopt(c->setup.u.us.sock, SOL_SOCKET, SO_PASSCRED, &off,
345484
sizeof(off));
346485
#endif
347486

348-
res =
349-
qb_ipc_us_recv(&c->setup, r,
350-
sizeof(struct qb_ipc_connection_response), -1);
351-
if (res < 0) {
487+
if (res != data->len) {
488+
destroy_ipc_auth_data(data);
352489
return res;
353490
}
354491

355-
if (r->hdr.error != 0) {
356-
return r->hdr.error;
357-
}
358-
return 0;
492+
memcpy(r, &data->msg.res, sizeof(struct qb_ipc_connection_response));
493+
494+
qb_ipc_auth_creds(data);
495+
c->egid = data->ugp.gid;
496+
497+
destroy_ipc_auth_data(data);
498+
return r->hdr.error;
359499
}
360500

361501
/*
@@ -568,19 +708,6 @@ handle_new_connection(struct qb_ipcs_service *s,
568708
return res;
569709
}
570710

571-
static void
572-
destroy_ipc_auth_data(struct ipc_auth_data *data)
573-
{
574-
if (data->s) {
575-
qb_ipcs_unref(data->s);
576-
}
577-
578-
#ifdef SO_PASSCRED
579-
free(data->cmsg_cred);
580-
#endif
581-
free(data);
582-
}
583-
584711
static int32_t
585712
process_auth(int32_t fd, int32_t revents, void *d)
586713
{
@@ -622,71 +749,7 @@ process_auth(int32_t fd, int32_t revents, void *d)
622749
goto cleanup_and_return;
623750
}
624751

625-
/*
626-
* currently support getpeerucred, getpeereid, and SO_PASSCRED credential
627-
* retrieval mechanisms for various Platforms
628-
*/
629-
#ifdef HAVE_GETPEERUCRED
630-
/*
631-
* Solaris and some BSD systems
632-
*/
633-
{
634-
ucred_t *uc = NULL;
635-
636-
if (getpeerucred(data->sock, &uc) == 0) {
637-
res = 0;
638-
data->ugp.uid = ucred_geteuid(uc);
639-
data->ugp.gid = ucred_getegid(uc);
640-
data->ugp.pid = ucred_getpid(uc);
641-
ucred_free(uc);
642-
} else {
643-
res = -errno;
644-
}
645-
}
646-
#elif HAVE_GETPEEREID
647-
/*
648-
* Usually MacOSX systems
649-
*/
650-
{
651-
/*
652-
* TODO get the peer's pid.
653-
* c->pid = ?;
654-
*/
655-
if (getpeereid(data->sock, &data->ugp.uid, &data->ugp.gid) == 0) {
656-
res = 0;
657-
} else {
658-
res = -errno;
659-
}
660-
}
661-
662-
#elif SO_PASSCRED
663-
/*
664-
* Usually Linux systems
665-
*/
666-
{
667-
struct ucred cred;
668-
struct cmsghdr *cmsg;
669-
670-
res = -EINVAL;
671-
for (cmsg = CMSG_FIRSTHDR(&data->msg_recv); cmsg != NULL;
672-
cmsg = CMSG_NXTHDR(&data->msg_recv, cmsg)) {
673-
if (cmsg->cmsg_type != SCM_CREDENTIALS)
674-
continue;
675-
676-
memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
677-
res = 0;
678-
data->ugp.pid = cred.pid;
679-
data->ugp.uid = cred.uid;
680-
data->ugp.gid = cred.gid;
681-
break;
682-
}
683-
}
684-
#else /* no credentials */
685-
data->ugp.pid = 0;
686-
data->ugp.uid = 0;
687-
data->ugp.gid = 0;
688-
res = -ENOTSUP;
689-
#endif /* no credentials */
752+
res = qb_ipc_auth_creds(data);
690753

691754
cleanup_and_return:
692755
#ifdef SO_PASSCRED
@@ -697,7 +760,7 @@ process_auth(int32_t fd, int32_t revents, void *d)
697760

698761
if (res < 0) {
699762
close(data->sock);
700-
} else if (data->msg.hdr.id == QB_IPC_MSG_AUTHENTICATE) {
763+
} else if (data->msg.req.hdr.id == QB_IPC_MSG_AUTHENTICATE) {
701764
(void)handle_new_connection(data->s, res, data->sock, &data->msg, data->len, &data->ugp);
702765
} else {
703766
close(data->sock);
@@ -716,7 +779,7 @@ qb_ipcs_uc_recv_and_auth(int32_t sock, struct qb_ipcs_service *s)
716779
int on = 1;
717780
#endif
718781

719-
data = calloc(1, sizeof(struct ipc_auth_data));
782+
data = init_ipc_auth_data(sock, sizeof(struct qb_ipc_connection_request));
720783
if (data == NULL) {
721784
close(sock);
722785
/* -ENOMEM */
@@ -726,34 +789,6 @@ qb_ipcs_uc_recv_and_auth(int32_t sock, struct qb_ipcs_service *s)
726789
data->s = s;
727790
qb_ipcs_ref(data->s);
728791

729-
data->msg_recv.msg_iov = &data->iov_recv;
730-
data->msg_recv.msg_iovlen = 1;
731-
data->msg_recv.msg_name = 0;
732-
data->msg_recv.msg_namelen = 0;
733-
734-
#ifdef SO_PASSCRED
735-
data->cmsg_cred = calloc(1,CMSG_SPACE(sizeof(struct ucred)));
736-
if (data->cmsg_cred == NULL) {
737-
close(sock);
738-
destroy_ipc_auth_data(data);
739-
/* -ENOMEM */
740-
return;
741-
}
742-
data->msg_recv.msg_control = (void *)data->cmsg_cred;
743-
data->msg_recv.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
744-
#endif
745-
#ifdef QB_SOLARIS
746-
data->msg_recv.msg_accrights = 0;
747-
data->msg_recv.msg_accrightslen = 0;
748-
#else
749-
data->msg_recv.msg_flags = 0;
750-
#endif /* QB_SOLARIS */
751-
752-
data->len = sizeof(struct qb_ipc_connection_request);
753-
data->iov_recv.iov_base = &data->msg;
754-
data->iov_recv.iov_len = data->len;
755-
data->sock = sock;
756-
757792
#ifdef SO_PASSCRED
758793
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
759794
#endif

0 commit comments

Comments
 (0)