summaryrefslogtreecommitdiff
path: root/sbin/pflogd
diff options
context:
space:
mode:
authorCan Erkin Acar <canacar@cvs.openbsd.org>2003-10-22 18:51:56 +0000
committerCan Erkin Acar <canacar@cvs.openbsd.org>2003-10-22 18:51:56 +0000
commit6e363212d16d26425498972bb2e01ed7035bb463 (patch)
tree1c2ab9e5b252d08ee7b6a0214c70019bb4b75e72 /sbin/pflogd
parent6693f734d4d99c32579a9cef43ff0f9a39e4dc62 (diff)
privilege seperated pflogd
_pflogd user and group must be created for proper operation. ok frantzen@ henning@ mcbride@ deraadt@
Diffstat (limited to 'sbin/pflogd')
-rw-r--r--sbin/pflogd/Makefile4
-rw-r--r--sbin/pflogd/pflogd.c116
-rw-r--r--sbin/pflogd/pflogd.h41
-rw-r--r--sbin/pflogd/privsep.c268
-rw-r--r--sbin/pflogd/privsep_fdpass.c120
5 files changed, 492 insertions, 57 deletions
diff --git a/sbin/pflogd/Makefile b/sbin/pflogd/Makefile
index 79902152951..31c795b00c3 100644
--- a/sbin/pflogd/Makefile
+++ b/sbin/pflogd/Makefile
@@ -1,11 +1,11 @@
-# $OpenBSD: Makefile,v 1.4 2003/03/01 06:11:20 cloder Exp $
+# $OpenBSD: Makefile,v 1.5 2003/10/22 18:51:55 canacar Exp $
CFLAGS+=-Wall -Werror -Wmissing-prototypes -Wshadow
LDADD+= -lpcap -lutil
DPAPP+= ${LIBPCAP} ${LIBUTIL}
PROG= pflogd
-SRCS= pflogd.c
+SRCS= pflogd.c privsep.c privsep_fdpass.c
MAN= pflogd.8
.include <bsd.prog.mk>
diff --git a/sbin/pflogd/pflogd.c b/sbin/pflogd/pflogd.c
index fea633e7ce6..a73ed438692 100644
--- a/sbin/pflogd/pflogd.c
+++ b/sbin/pflogd/pflogd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pflogd.c,v 1.22 2003/09/26 16:14:33 deraadt Exp $ */
+/* $OpenBSD: pflogd.c,v 1.23 2003/10/22 18:51:55 canacar Exp $ */
/*
* Copyright (c) 2001 Theo de Raadt
@@ -31,6 +31,7 @@
*/
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
@@ -45,15 +46,7 @@
#include <stdarg.h>
#include <fcntl.h>
#include <util.h>
-
-#define DEF_SNAPLEN 116 /* default plus allow for larger header of pflog */
-#define PCAP_TO_MS 500 /* pcap read timeout (ms) */
-#define PCAP_NUM_PKTS 1000 /* max number of packets to process at each loop */
-#define PCAP_OPT_FIL 0 /* filter optimization */
-#define FLUSH_DELAY 60 /* flush delay */
-
-#define PFLOGD_LOG_FILE "/var/log/pflog"
-#define PFLOGD_DEFAULT_IF "pflog0"
+#include "pflogd.h"
pcap_t *hpcap;
pcap_dumper_t *dpcap;
@@ -148,37 +141,47 @@ sig_alrm(int sig)
gotsig_alrm = 1;
}
-int
-init_pcap(void)
+void
+set_pcap_filter(void)
{
struct bpf_program bprog;
- pcap_t *oldhpcap = hpcap;
+ if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
+ logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
+ else {
+ if (pcap_setfilter(hpcap, &bprog) < 0)
+ logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
+ pcap_freecode(&bprog);
+ }
+}
+
+int
+init_pcap(void)
+{
hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
if (hpcap == NULL) {
logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
- hpcap = oldhpcap;
+ hpcap = NULL;
return (-1);
}
- if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
- logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
- else if (pcap_setfilter(hpcap, &bprog) < 0)
- logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
- if (filter != NULL)
- free(filter);
-
if (pcap_datalink(hpcap) != DLT_PFLOG) {
logmsg(LOG_ERR, "Invalid datalink type");
pcap_close(hpcap);
- hpcap = oldhpcap;
+ hpcap = NULL;
return (-1);
}
- if (oldhpcap)
- pcap_close(oldhpcap);
+ set_pcap_filter();
snaplen = pcap_snapshot(hpcap);
+
+ /* lock */
+ if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
+ logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
+ return (-1);
+ }
+
return (0);
}
@@ -187,7 +190,7 @@ reset_dump(void)
{
struct pcap_file_header hdr;
struct stat st;
- int tmpsnap;
+ int fd;
FILE *fp;
if (hpcap == NULL)
@@ -201,17 +204,18 @@ reset_dump(void)
* Basically reimplement pcap_dump_open() because it truncates
* files and duplicates headers and such.
*/
- fp = fopen(filename, "a+");
+ fd = priv_open_log();
+ if (fd < 0)
+ return (1);
+
+ fp = fdopen(fd, "a+");
+
if (fp == NULL) {
- snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
- filename, pcap_strerror(errno));
- logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap));
+ logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
return (1);
}
if (fstat(fileno(fp), &st) == -1) {
- snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
- filename, pcap_strerror(errno));
- logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap));
+ logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
return (1);
}
@@ -222,10 +226,9 @@ reset_dump(void)
if (st.st_size == 0) {
if (snaplen != pcap_snapshot(hpcap)) {
logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
- if (init_pcap()) {
- logmsg(LOG_ERR, "Failed to initialize");
- if (hpcap == NULL) return (-1);
- logmsg(LOG_NOTICE, "Using old settings");
+ if (priv_set_snaplen(snaplen)) {
+ logmsg(LOG_WARNING,
+ "Failed, using old settings");
}
}
hdr.magic = TCPDUMP_MAGIC;
@@ -259,22 +262,16 @@ reset_dump(void)
"Invalid/incompatible log file, move it away");
fclose(fp);
return (1);
- }
+ }
if (hdr.snaplen != snaplen) {
logmsg(LOG_WARNING,
- "Existing file specifies a snaplen of %u, using it",
+ "Existing file has different snaplen %u, using it",
hdr.snaplen);
- tmpsnap = snaplen;
- snaplen = hdr.snaplen;
- if (init_pcap()) {
- logmsg(LOG_ERR, "Failed to re-initialize");
- if (hpcap == 0)
- return (-1);
- logmsg(LOG_NOTICE,
- "Using old settings, offset: %llu",
- (unsigned long long)st.st_size);
+ if (priv_set_snaplen(hdr.snaplen)) {
+ logmsg(LOG_WARNING,
+ "Failed, using old settings, offset %llu",
+ (unsigned long long) st.st_size);
}
- snaplen = tmpsnap;
}
}
@@ -327,24 +324,33 @@ main(int argc, char **argv)
(void)umask(S_IRWXG | S_IRWXO);
- signal(SIGTERM, sig_close);
- signal(SIGINT, sig_close);
- signal(SIGQUIT, sig_close);
- signal(SIGALRM, sig_alrm);
- signal(SIGHUP, sig_hup);
- alarm(delay);
-
+ /* filter will be used by the privileged process */
if (argc) {
filter = copy_argv(argv);
if (filter == NULL)
logmsg(LOG_NOTICE, "Failed to form filter expression");
}
+ /* initialize pcap before dropping privileges */
if (init_pcap()) {
logmsg(LOG_ERR, "Exiting, init failure");
exit(1);
}
+ /* Privilege separation begins here */
+ if (priv_init()) {
+ logmsg(LOG_ERR, "unable to privsep");
+ exit(1);
+ }
+
+ /* Process is now unprivileged and inside a chroot */
+ signal(SIGTERM, sig_close);
+ signal(SIGINT, sig_close);
+ signal(SIGQUIT, sig_close);
+ signal(SIGALRM, sig_alrm);
+ signal(SIGHUP, sig_hup);
+ alarm(delay);
+
if (reset_dump()) {
logmsg(LOG_ERR, "Failed to open log file %s", filename);
pcap_close(hpcap);
diff --git a/sbin/pflogd/pflogd.h b/sbin/pflogd/pflogd.h
new file mode 100644
index 00000000000..765adb9a791
--- /dev/null
+++ b/sbin/pflogd/pflogd.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 Can Erkin Acar
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <pcap.h>
+
+#define DEF_SNAPLEN 116 /* default plus allow for larger header of pflog */
+#define PCAP_TO_MS 500 /* pcap read timeout (ms) */
+#define PCAP_NUM_PKTS 1000 /* max number of packets to process at each loop */
+#define PCAP_OPT_FIL 0 /* filter optimization */
+#define FLUSH_DELAY 60 /* flush delay */
+
+#define PFLOGD_LOG_FILE "/var/log/pflog"
+#define PFLOGD_DEFAULT_IF "pflog0"
+
+void logmsg(int priority, const char *message, ...);
+
+/* Privilege separation */
+int priv_init(void);
+int priv_set_snaplen(int snaplen);
+int priv_open_log(void);
+pcap_t *pcap_open_live_fd(int fd, int snaplen, char *ebuf);
+
+void set_pcap_filter(void);
+/* File descriptor send/recv */
+void send_fd(int, int);
+int receive_fd(int);
+
+extern int Debug;
diff --git a/sbin/pflogd/privsep.c b/sbin/pflogd/privsep.c
new file mode 100644
index 00000000000..5b72a705ffe
--- /dev/null
+++ b/sbin/pflogd/privsep.c
@@ -0,0 +1,268 @@
+/* $OpenBSD: privsep.c,v 1.1 2003/10/22 18:51:55 canacar Exp $ */
+
+/*
+ * Copyright (c) 2003 Can Erkin Acar
+ * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pcap.h>
+#include <pcap-int.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "pflogd.h"
+
+enum cmd_types {
+ PRIV_SET_SNAPLEN, /* set the snaplength */
+ PRIV_OPEN_LOG, /* open logfile for appending */
+};
+
+static int priv_fd = -1;
+static pid_t child_pid;
+
+volatile sig_atomic_t gotsig_chld = 0;
+
+static void sig_pass_to_chld(int);
+static void sig_chld(int);
+static void must_read(int, void *, size_t);
+static void must_write(int, void *, size_t);
+static int set_snaplen(int snap);
+
+/* bpf filter expression common to parent and child */
+extern char *filter;
+extern char *errbuf;
+extern char *filename;
+extern pcap_t *hpcap;
+
+/* based on syslogd privsep */
+int
+priv_init(void)
+{
+ int i, fd, socks[2], cmd;
+ int snaplen, ret;
+ struct passwd *pw;
+
+ /* Create sockets */
+ if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1)
+ err(1, "socketpair() failed");
+
+ pw = getpwnam("_pflogd");
+ if (pw == NULL)
+ errx(1, "unknown user _pflogd");
+
+ child_pid = fork();
+ if (child_pid < 0)
+ err(1, "fork() failed");
+
+ if (!child_pid) {
+ /* Child - drop privileges and return */
+ if (chroot(pw->pw_dir) != 0)
+ err(1, "unable to chroot");
+ chdir("/");
+ if (setegid(pw->pw_gid) == -1)
+ err(1, "setegid() failed");
+ if (setgid(pw->pw_gid) == -1)
+ err(1, "setgid() failed");
+ if (seteuid(pw->pw_uid) == -1)
+ err(1, "seteuid() failed");
+ if (setuid(pw->pw_uid) == -1)
+ err(1, "setuid() failed");
+ close(socks[0]);
+ priv_fd = socks[1];
+ return 0;
+ }
+
+ /* Father */
+ for (i = 1; i <= _NSIG; i++)
+ signal(i, SIG_DFL);
+
+ /* Pass ALRM/TERM/HUP through to child, and accept CHLD */
+ signal(SIGALRM, sig_pass_to_chld);
+ signal(SIGTERM, sig_pass_to_chld);
+ signal(SIGHUP, sig_pass_to_chld);
+ signal(SIGCHLD, sig_chld);
+
+ setproctitle("[priv]");
+ close(socks[1]);
+
+ while (!gotsig_chld) {
+ must_read(socks[0], &cmd, sizeof(int));
+ switch (cmd) {
+ case PRIV_SET_SNAPLEN:
+ logmsg(LOG_DEBUG,
+ "[priv]: msg PRIV_SET_SNAPLENGTH received");
+ must_read(socks[0], &snaplen, sizeof(int));
+
+ ret = set_snaplen(snaplen);
+ if (ret) {
+ logmsg(LOG_NOTICE,
+ "[priv]: set_snaplen failed for snaplen %d",
+ snaplen);
+ }
+
+ must_write(socks[0], &ret, sizeof(int));
+ break;
+
+ case PRIV_OPEN_LOG:
+ logmsg(LOG_DEBUG,
+ "[priv]: msg PRIV_OPEN_LOG received");
+
+ /* XXX */
+ fd = open(filename, O_RDWR|O_APPEND|O_NONBLOCK, 0);
+ if (fd < 0)
+ logmsg(LOG_NOTICE,
+ "[priv]: failed to open %s: %s",
+ filename, strerror(errno));
+ send_fd(socks[0], fd);
+ close(fd);
+ break;
+
+ default:
+ logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
+ _exit(1);
+ /* NOTREACHED */
+ }
+ }
+
+ _exit(1);
+}
+
+/* this is called from parent */
+static int
+set_snaplen(int snap)
+{
+ if (hpcap == NULL)
+ return (1);
+
+ hpcap->snapshot = snap;
+ set_pcap_filter();
+
+ return 0;
+}
+
+
+/*
+ * send the snaplength to privileged process
+ */
+int
+priv_set_snaplen(int snaplen)
+{
+ int cmd, ret;
+
+ if (priv_fd < 0)
+ errx(1, "%s: called from privileged portion", __func__);
+
+ cmd = PRIV_SET_SNAPLEN;
+
+ must_write(priv_fd, &cmd, sizeof(int));
+ must_write(priv_fd, &snaplen, sizeof(int));
+
+ must_read(priv_fd, &ret, sizeof(int));
+
+ /* also set hpcap->snapshot in child */
+ if (ret == 0)
+ hpcap->snapshot = snaplen;
+
+ return (ret);
+}
+
+/* Open log-file */
+int
+priv_open_log(void)
+{
+ int cmd, fd;
+
+ if (priv_fd < 0)
+ errx(1, "%s: called from privileged portion\n", __func__);
+
+ cmd = PRIV_OPEN_LOG;
+ must_write(priv_fd, &cmd, sizeof(int));
+ fd = receive_fd(priv_fd);
+
+ return (fd);
+}
+
+/* If priv parent gets a TERM or HUP, pass it through to child instead */
+static void
+sig_pass_to_chld(int sig)
+{
+ kill(child_pid, sig);
+}
+
+/* if parent gets a SIGCHLD, it will exit */
+static void
+sig_chld(int sig)
+{
+ gotsig_chld = 1;
+}
+
+/* Read data with the assertion that it all must come through, or
+ * else abort the process. Based on atomicio() from openssh. */
+static void
+must_read(int fd, void *buf, size_t n)
+{
+ char *s = buf;
+ ssize_t res, pos = 0;
+
+ while (n > pos) {
+ res = read(fd, s + pos, n - pos);
+ switch (res) {
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ case 0:
+ _exit(0);
+ default:
+ pos += res;
+ }
+ }
+}
+
+/* Write data with the assertion that it all has to be written, or
+ * else abort the process. Based on atomicio() from openssh. */
+static void
+must_write(int fd, void *buf, size_t n)
+{
+ char *s = buf;
+ ssize_t res, pos = 0;
+
+ while (n > pos) {
+ res = write(fd, s + pos, n - pos);
+ switch (res) {
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ case 0:
+ _exit(0);
+ default:
+ pos += res;
+ }
+ }
+}
diff --git a/sbin/pflogd/privsep_fdpass.c b/sbin/pflogd/privsep_fdpass.c
new file mode 100644
index 00000000000..166b6930b3b
--- /dev/null
+++ b/sbin/pflogd/privsep_fdpass.c
@@ -0,0 +1,120 @@
+/* $OpenBSD: privsep_fdpass.c,v 1.1 2003/10/22 18:51:55 canacar Exp $ */
+
+/*
+ * Copyright 2001 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Copyright (c) 2002 Matthieu Herrb
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "pflogd.h"
+
+void
+send_fd(int sock, int fd)
+{
+ struct msghdr msg;
+ char tmp[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ int result = 0;
+ ssize_t n;
+
+ memset(&msg, 0, sizeof(msg));
+
+ if (fd >= 0) {
+ msg.msg_control = (caddr_t)tmp;
+ msg.msg_controllen = CMSG_LEN(sizeof(int));
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *(int *)CMSG_DATA(cmsg) = fd;
+ } else {
+ result = errno;
+ }
+
+ vec.iov_base = &result;
+ vec.iov_len = sizeof(int);
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+
+ if ((n = sendmsg(sock, &msg, 0)) == -1)
+ warn("%s: sendmsg(%d)", __func__, sock);
+ if (n != sizeof(int))
+ warnx("%s: sendmsg: expected sent 1 got %ld",
+ __func__, (long)n);
+}
+
+int
+receive_fd(int sock)
+{
+ struct msghdr msg;
+ char tmp[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ ssize_t n;
+ int result;
+ int fd;
+
+ memset(&msg, 0, sizeof(msg));
+ vec.iov_base = &result;
+ vec.iov_len = sizeof(int);
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = tmp;
+ msg.msg_controllen = sizeof(tmp);
+
+ if ((n = recvmsg(sock, &msg, 0)) == -1)
+ warn("%s: recvmsg", __func__);
+ if (n != sizeof(int))
+ warnx("%s: recvmsg: expected received 1 got %ld",
+ __func__, (long)n);
+ if (result == 0) {
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg->cmsg_type != SCM_RIGHTS)
+ warnx("%s: expected type %d got %d", __func__,
+ SCM_RIGHTS, cmsg->cmsg_type);
+ fd = (*(int *)CMSG_DATA(cmsg));
+ return fd;
+ } else {
+ errno = result;
+ return -1;
+ }
+}