]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
Fix the pcap version in tests/cve2015-0261-crash.pcap
[tcpdump] / tcpdump.c
index 1eb2e206b6ec1b9a6a12eebc8f576117983aa9b1..6a96ea94153906b1adf24d1efb90b76f0a18470a 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -56,13 +56,13 @@ The Regents of the University of California.  All rights reserved.\n";
 
 #include <tcpdump-stdinc.h>
 
-#ifdef WIN32
+#ifdef _WIN32
 #include "w32_fzs.h"
 extern int strcasecmp (const char *__s1, const char *__s2);
 extern int SIZE_BUF;
 #define off_t long
 #define uint UINT
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
 #ifdef USE_LIBSMI
 #include <smi.h>
@@ -94,17 +94,25 @@ extern int SIZE_BUF;
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
-#ifndef WIN32
+#ifndef _WIN32
 #include <sys/wait.h>
 #include <sys/resource.h>
 #include <pwd.h>
 #include <grp.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
-/* capabilities convinience library */
+/* capabilities convenience library */
+/* If a code depends on HAVE_LIBCAP_NG, it depends also on HAVE_CAP_NG_H.
+ * If HAVE_CAP_NG_H is not defined, undefine HAVE_LIBCAP_NG.
+ * Thus, the later tests are done only on HAVE_LIBCAP_NG.
+ */
+#ifdef HAVE_LIBCAP_NG
 #ifdef HAVE_CAP_NG_H
 #include <cap-ng.h>
+#else
+#undef HAVE_LIBCAP_NG
 #endif /* HAVE_CAP_NG_H */
+#endif /* HAVE_LIBCAP_NG */
 
 #include "netdissect.h"
 #include "interface.h"
@@ -505,7 +513,7 @@ show_tstamp_types_and_exit(const char *device, pcap_t *pd)
 static void
 show_dlts_and_exit(const char *device, pcap_t *pd)
 {
-       int n_dlts;
+       int n_dlts, i;
        int *dlts = 0;
        const char *dlt_name;
 
@@ -531,22 +539,22 @@ show_dlts_and_exit(const char *device, pcap_t *pd)
                (void) fprintf(stderr, "Data link types for %s (use option -y to set):\n",
                    device);
 
-       while (--n_dlts >= 0) {
-               dlt_name = pcap_datalink_val_to_name(dlts[n_dlts]);
+       for (i = 0; i < n_dlts; i++) {
+               dlt_name = pcap_datalink_val_to_name(dlts[i]);
                if (dlt_name != NULL) {
                        (void) fprintf(stderr, "  %s (%s)", dlt_name,
-                           pcap_datalink_val_to_description(dlts[n_dlts]));
+                           pcap_datalink_val_to_description(dlts[i]));
 
                        /*
                         * OK, does tcpdump handle that type?
                         */
-                       if (lookup_printer(dlts[n_dlts]) == NULL
-                            && lookup_ndo_printer(dlts[n_dlts]) == NULL)
+                       if (lookup_printer(dlts[i]) == NULL
+                            && lookup_ndo_printer(dlts[i]) == NULL)
                                (void) fprintf(stderr, " (printing not supported)");
                        fprintf(stderr, "\n");
                } else {
                        (void) fprintf(stderr, "  DLT %d (printing not supported)\n",
-                           dlts[n_dlts]);
+                           dlts[i]);
                }
        }
 #ifdef HAVE_PCAP_FREE_DATALINKS
@@ -599,19 +607,28 @@ show_devices_and_exit (void)
  *
  * OS X tcpdump uses -P to indicate that -w should write pcap-ng rather
  * than pcap files.
+ *
+ * OS X tcpdump also uses -Q to specify expressions that match packet
+ * metadata, including but not limited to the packet direction.
+ * The expression syntax is different from a simple "in|out|inout",
+ * and those expressions aren't accepted by OS X tcpdump, but the
+ * equivalents would be "in" = "dir=in", "out" = "dir=out", and
+ * "inout" = "dir=in or dir=out", and the parser could conceivably
+ * special-case "in", "out", and "inout" as expressions for backwards
+ * compatibility, so all is not (yet) lost.
  */
 
 /*
  * Set up flags that might or might not be supported depending on the
  * version of libpcap we're using.
  */
-#if defined(HAVE_PCAP_CREATE) || defined(WIN32)
+#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
 #define B_FLAG         "B:"
 #define B_FLAG_USAGE   " [ -B size ]"
-#else /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */
+#else /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */
 #define B_FLAG
 #define B_FLAG_USAGE
-#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */
+#endif /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */
 
 #ifdef HAVE_PCAP_CREATE
 #define I_FLAG         "I"
@@ -647,6 +664,8 @@ show_devices_and_exit (void)
 #define Q_FLAG
 #endif
 
+#define SHORTOPTS "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpq" Q_FLAG "r:Rs:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#"
+
 /*
  * Long options.
  *
@@ -672,7 +691,7 @@ show_devices_and_exit (void)
 #define OPTION_IMMEDIATE_MODE  130
 
 static const struct option longopts[] = {
-#if defined(HAVE_PCAP_CREATE) || defined(WIN32)
+#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
        { "buffer-size", required_argument, NULL, 'B' },
 #endif
        { "list-interfaces", no_argument, NULL, 'D' },
@@ -713,7 +732,7 @@ static const struct option longopts[] = {
        { NULL, 0, NULL, 0 }
 };
 
-#ifndef WIN32
+#ifndef _WIN32
 /* Drop root privileges and chroot if necessary */
 static void
 droproot(const char *username, const char *chroot_dir)
@@ -734,7 +753,7 @@ droproot(const char *username, const char *chroot_dir)
                                exit(1);
                        }
                }
-#ifdef HAVE_CAP_NG_H
+#ifdef HAVE_LIBCAP_NG
                int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG);
                if (ret < 0) {
                        fprintf(stderr, "error : ret %d\n", ret);
@@ -742,15 +761,6 @@ droproot(const char *username, const char *chroot_dir)
                else {
                        fprintf(stderr, "dropped privs to %s\n", username);
                }
-               /* We don't need CAP_SETUID and CAP_SETGID */
-               capng_updatev(
-                       CAPNG_DROP,
-                       CAPNG_EFFECTIVE | CAPNG_PERMITTED,
-                       CAP_SETUID,
-                       CAP_SETGID,
-                       -1);
-               capng_apply(CAPNG_SELECT_BOTH);
-
 #else
                if (initgroups(pw->pw_name, pw->pw_gid) != 0 ||
                    setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
@@ -764,15 +774,26 @@ droproot(const char *username, const char *chroot_dir)
                else {
                        fprintf(stderr, "dropped privs to %s\n", username);
                }
-#endif /* HAVE_CAP_NG_H */
+#endif /* HAVE_LIBCAP_NG */
        }
        else {
                fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n",
                    username);
                exit(1);
        }
+#ifdef HAVE_LIBCAP_NG
+       /* We don't need CAP_SETUID and CAP_SETGID any more. */
+       capng_updatev(
+               CAPNG_DROP,
+               CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+               CAP_SETUID,
+               CAP_SETGID,
+               -1);
+       capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
+
 }
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
 static int
 getWflagChars(int x)
@@ -904,6 +925,76 @@ tstamp_precision_to_string(int precision)
 }
 #endif
 
+#ifdef HAVE_CAPSICUM
+/*
+ * Ensure that, on a dump file's descriptor, we have all the rights
+ * necessary to make the standard I/O library work with an fdopen()ed
+ * FILE * from that descriptor.
+ *
+ * A long time ago, in a galaxy far far away, AT&T decided that, instead
+ * of providing separate APIs for getting and setting the FD_ flags on a
+ * descriptor, getting and setting the O_ flags on a descriptor, and
+ * locking files, they'd throw them all into a kitchen-sink fcntl() call
+ * along the lines of ioctl(), the fact that ioctl() operations are
+ * largely specific to particular character devices but fcntl() operations
+ * are either generic to all descriptors or generic to all descriptors for
+ * regular files nonwithstanding.
+ *
+ * The Capsicum people decided that fine-grained control of descriptor
+ * operations was required, so that you need to grant permission for
+ * reading, writing, seeking, and fcntl-ing.  The latter, courtesy of
+ * AT&T's decision, means that "fcntl-ing" isn't a thing, but a motley
+ * collection of things, so there are *individual* fcntls for which
+ * permission needs to be granted.
+ *
+ * The FreeBSD standard I/O people implemented some optimizations that
+ * requires that the standard I/O routines be able to determine whether
+ * the descriptor for the FILE * is open append-only or not; as that
+ * descriptor could have come from an open() rather than an fopen(),
+ * that requires that it be able to do an F_GETFL fcntl() to read
+ * the O_ flags.
+ *
+ * Tcpdump uses ftell() to determine how much data has been written
+ * to a file in order to, when used with -C, determine when it's time
+ * to rotate capture files.  ftell() therefore needs to do an lseek()
+ * to find out the file offset and must, thanks to the aforementioned
+ * optimization, also know whether the descriptor is open append-only
+ * or not.
+ *
+ * The net result of all the above is that we need to grant CAP_SEEK,
+ * CAP_WRITE, and CAP_FCNTL with the CAP_FCNTL_GETFL subcapability.
+ *
+ * Perhaps this is the universe's way of saying that either
+ *
+ *     1) there needs to be an fopenat() call and a pcap_dump_openat() call
+ *        using it, so that Capsicum-capable tcpdump wouldn't need to do
+ *        an fdopen()
+ *
+ * or
+ *
+ *     2) there needs to be a cap_fdopen() call in the FreeBSD standard
+ *        I/O library that knows what rights are needed by the standard
+ *        I/O library, based on the open mode, and assigns them, perhaps
+ *        with an additional argument indicating, for example, whether
+ *        seeking should be allowed, so that tcpdump doesn't need to know
+ *        what the standard I/O library happens to require this week.
+ */
+static void
+set_dumper_capsicum_rights(pcap_dumper_t *p)
+{
+       int fd = fileno(pcap_dump_file(p));
+       cap_rights_t rights;
+
+       cap_rights_init(&rights, CAP_SEEK, CAP_WRITE, CAP_FCNTL);
+       if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) {
+               error("unable to limit dump descriptor");
+       }
+       if (cap_fcntls_limit(fd, CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) {
+               error("unable to limit dump descriptor fcntls");
+       }
+}
+#endif
+
 int
 main(int argc, char **argv)
 {
@@ -916,7 +1007,7 @@ main(int argc, char **argv)
        int new_dlt;
        const char *dlt_name;
        struct bpf_program fcode;
-#ifndef WIN32
+#ifndef _WIN32
        RETSIGTYPE (*oldhandler)(int);
 #endif
        struct print_info printinfo;
@@ -939,9 +1030,9 @@ main(int argc, char **argv)
        int cansandbox;
 #endif /* HAVE_CAPSICUM */
 
-#ifdef WIN32
+#ifdef _WIN32
        if(wsockinit() != 0) return 1;
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
        jflag=-1;       /* not set */
         gndo->ndo_Oflag=1;
@@ -982,7 +1073,7 @@ main(int argc, char **argv)
 #endif
 
        while (
-           (op = getopt_long(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpq" Q_FLAG "r:Rs:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#", longopts, NULL)) != -1)
+           (op = getopt_long(argc, argv, SHORTOPTS, longopts, NULL)) != -1)
                switch (op) {
 
                case 'a':
@@ -997,13 +1088,13 @@ main(int argc, char **argv)
                        ++bflag;
                        break;
 
-#if defined(HAVE_PCAP_CREATE) || defined(WIN32)
+#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
                case 'B':
                        Bflag = atoi(optarg)*1024;
                        if (Bflag <= 0)
                                error("invalid packet buffer size %s", optarg);
                        break;
-#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */
+#endif /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */
 
                case 'c':
                        cnt = atoi(optarg);
@@ -1133,24 +1224,24 @@ main(int argc, char **argv)
 #endif
 
                case 'l':
-#ifdef WIN32
+#ifdef _WIN32
                        /*
                         * _IOLBF is the same as _IOFBF in Microsoft's C
                         * libraries; the only alternative they offer
                         * is _IONBF.
                         *
                         * XXX - this should really be checking for MSVC++,
-                        * not WIN32, if, for example, MinGW has its own
+                        * not _WIN32, if, for example, MinGW has its own
                         * C library that is more UNIX-compatible.
                         */
                        setvbuf(stdout, NULL, _IONBF, 0);
-#else /* WIN32 */
+#else /* _WIN32 */
 #ifdef HAVE_SETLINEBUF
                        setlinebuf(stdout);
 #else
                        setvbuf(stdout, NULL, _IOLBF, 0);
 #endif
-#endif /* WIN32 */
+#endif /* _WIN32 */
                        break;
 
                case 'K':
@@ -1440,7 +1531,7 @@ main(int argc, char **argv)
                 * In either case, we're reading a savefile, not doing
                 * a live capture.
                 */
-#ifndef WIN32
+#ifndef _WIN32
                /*
                 * We don't need network access, so relinquish any set-UID
                 * or set-GID privileges we have (if any).
@@ -1452,7 +1543,7 @@ main(int argc, char **argv)
                 */
                if (setgid(getgid()) != 0 || setuid(getuid()) != 0 )
                        fprintf(stderr, "Warning: setgid/setuid failed !\n");
-#endif /* WIN32 */
+#endif /* _WIN32 */
                if (VFileName != NULL) {
                        if (VFileName[0] == '-' && VFileName[1] == '\0')
                                VFile = stdin;
@@ -1504,7 +1595,7 @@ main(int argc, char **argv)
                        if (device == NULL)
                                error("%s", ebuf);
                }
-#ifdef WIN32
+#ifdef _WIN32
                /*
                 * Print a message to the standard error on Windows.
                 * XXX - why do it here, with a different message?
@@ -1519,7 +1610,7 @@ main(int argc, char **argv)
                }
 
                fflush(stderr);
-#endif /* WIN32 */
+#endif /* _WIN32 */
 #ifdef HAVE_PCAP_CREATE
                pd = pcap_create(device, ebuf);
                if (pd == NULL)
@@ -1582,7 +1673,7 @@ main(int argc, char **argv)
                        status = pcap_set_tstamp_type(pd, jflag);
                        if (status < 0)
                                error("%s: Can't set time stamp type: %s",
-                                   device, pcap_statustostr(status));
+                                     device, pcap_statustostr(status));
                }
 #endif
                status = pcap_activate(pd);
@@ -1636,16 +1727,16 @@ main(int argc, char **argv)
                /*
                 * Let user own process after socket has been opened.
                 */
-#ifndef WIN32
+#ifndef _WIN32
                if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
                        fprintf(stderr, "Warning: setgid/setuid failed !\n");
-#endif /* WIN32 */
-#if !defined(HAVE_PCAP_CREATE) && defined(WIN32)
+#endif /* _WIN32 */
+#if !defined(HAVE_PCAP_CREATE) && defined(_WIN32)
                if(Bflag != 0)
                        if(pcap_setbuff(pd, Bflag)==-1){
                                error("%s", pcap_geterr(pd));
                        }
-#endif /* !defined(HAVE_PCAP_CREATE) && defined(WIN32) */
+#endif /* !defined(HAVE_PCAP_CREATE) && defined(_WIN32) */
                if (Lflag)
                        show_dlts_and_exit(device, pd);
                if (gndo->ndo_dlt >= 0) {
@@ -1695,21 +1786,21 @@ main(int argc, char **argv)
        init_addrtoname(gndo, localnet, netmask);
         init_checksum();
 
-#ifndef WIN32
+#ifndef _WIN32
        (void)setsignal(SIGPIPE, cleanup);
        (void)setsignal(SIGTERM, cleanup);
        (void)setsignal(SIGINT, cleanup);
-#endif /* WIN32 */
+#endif /* _WIN32 */
 #if defined(HAVE_FORK) || defined(HAVE_VFORK)
        (void)setsignal(SIGCHLD, child_cleanup);
 #endif
        /* Cooperate with nohup(1) */
-#ifndef WIN32
+#ifndef _WIN32
        if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
                (void)setsignal(SIGHUP, oldhandler);
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
-#ifndef WIN32
+#ifndef _WIN32
        /*
         * If a user name was specified with "-Z", attempt to switch to
         * that user's UID.  This would probably be used with sudo,
@@ -1729,27 +1820,32 @@ main(int argc, char **argv)
         */
 
        if (getuid() == 0 || geteuid() == 0) {
-#ifdef HAVE_CAP_NG_H
-               /* Drop all capabilities from effective set */
-               capng_clear(CAPNG_EFFECTIVE);
-               /* We are running as root and we will be writing to savefile */
-               if (WFileName  && username) {
-                       /* Add capabilities we will need*/
+#ifdef HAVE_LIBCAP_NG
+               /* Initialize capng */
+               capng_clear(CAPNG_SELECT_BOTH);
+               if (username) {
                        capng_updatev(
                                CAPNG_ADD,
                                CAPNG_PERMITTED | CAPNG_EFFECTIVE,
                                CAP_SETUID,
                                CAP_SETGID,
-                               CAP_DAC_OVERRIDE,
                                -1);
-                       capng_apply(CAPNG_SELECT_BOTH);
                }
-#endif /* HAVE_CAP_NG_H */
+
+               if (WFileName) {
+                       capng_update(
+                               CAPNG_ADD,
+                               CAPNG_PERMITTED | CAPNG_EFFECTIVE,
+                               CAP_DAC_OVERRIDE
+                               );
+               }
+               capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
                if (username || chroot_dir)
                        droproot(username, chroot_dir);
 
        }
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
        if (pcap_setfilter(pd, &fcode) < 0)
                error("%s", pcap_geterr(pd));
@@ -1783,18 +1879,23 @@ main(int argc, char **argv)
                  MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0);
 
                p = pcap_dump_open(pd, dumpinfo.CurrentFileName);
-#ifdef HAVE_CAP_NG_H
-        /* Give up capabilities, clear Effective set */
-        capng_clear(CAPNG_EFFECTIVE);
-#endif
+#ifdef HAVE_LIBCAP_NG
+               /* Give up CAP_DAC_OVERRIDE capability.
+                * Only allow it to be restored if the -C or -G flag have been
+                * set since we may need to create more files later on.
+                */
+               capng_update(
+                       CAPNG_DROP,
+                       (Cflag || Gflag ? 0 : CAPNG_PERMITTED)
+                               | CAPNG_EFFECTIVE,
+                       CAP_DAC_OVERRIDE
+                       );
+               capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
                if (p == NULL)
                        error("%s", pcap_geterr(pd));
 #ifdef HAVE_CAPSICUM
-               cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
-               if (cap_rights_limit(fileno(pcap_dump_file(p)), &rights) < 0 &&
-                   errno != ENOSYS) {
-                       error("unable to limit dump descriptor");
-               }
+               set_dumper_capsicum_rights(p);
 #endif
                if (Cflag != 0 || Gflag != 0) {
 #ifdef HAVE_CAPSICUM
@@ -1811,6 +1912,10 @@ main(int argc, char **argv)
                            errno != ENOSYS) {
                                error("unable to limit directory rights");
                        }
+                       if (cap_fcntls_limit(dumpinfo.dirfd, CAP_FCNTL_GETFL) < 0 &&
+                           errno != ENOSYS) {
+                               error("unable to limit dump descriptor fcntls");
+                       }
 #else  /* !HAVE_CAPSICUM */
                        dumpinfo.WFileName = WFileName;
 #endif
@@ -1858,7 +1963,7 @@ main(int argc, char **argv)
 #endif
        }
 
-#ifndef WIN32
+#ifndef _WIN32
        if (RFileName == NULL) {
                /*
                 * Live capture (if -V was specified, we set RFileName
@@ -1883,7 +1988,7 @@ main(int argc, char **argv)
                }
                (void)fflush(stderr);
        }
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
 #ifdef HAVE_CAPSICUM
        cansandbox = (nflag && VFileName == NULL && zflag == NULL);
@@ -2115,9 +2220,6 @@ static void
 dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 {
        struct dump_info *dump_info;
-#ifdef HAVE_CAPSICUM
-       cap_rights_t rights;
-#endif
 
        ++packets_captured;
 
@@ -2200,10 +2302,10 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                        else
                                MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0);
 
-#ifdef HAVE_CAP_NG_H
+#ifdef HAVE_LIBCAP_NG
                        capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
-                       capng_apply(CAPNG_EFFECTIVE);
-#endif /* HAVE_CAP_NG_H */
+                       capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
 #ifdef HAVE_CAPSICUM
                        fd = openat(dump_info->dirfd,
                            dump_info->CurrentFileName,
@@ -2221,18 +2323,14 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
 #else  /* !HAVE_CAPSICUM */
                        dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
 #endif
-#ifdef HAVE_CAP_NG_H
+#ifdef HAVE_LIBCAP_NG
                        capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
-                       capng_apply(CAPNG_EFFECTIVE);
-#endif /* HAVE_CAP_NG_H */
+                       capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
                        if (dump_info->p == NULL)
                                error("%s", pcap_geterr(pd));
 #ifdef HAVE_CAPSICUM
-                       cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
-                       if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
-                           &rights) < 0 && errno != ENOSYS) {
-                               error("unable to limit dump descriptor");
-                       }
+                       set_dumper_capsicum_rights(dump_info->p);
 #endif
                }
        }
@@ -2242,59 +2340,70 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
         * larger than Cflag - the last packet written to the
         * file could put it over Cflag.
         */
-       if (Cflag != 0 && pcap_dump_ftell(dump_info->p) > Cflag) {
+       if (Cflag != 0) {
+               long size = pcap_dump_ftell(dump_info->p);
+
+               if (size == -1)
+                       error("ftell fails on output file");
+               if (size > Cflag) {
 #ifdef HAVE_CAPSICUM
-               FILE *fp;
-               int fd;
+                       FILE *fp;
+                       int fd;
 #endif
 
-               /*
-                * Close the current file and open a new one.
-                */
-               pcap_dump_close(dump_info->p);
+                       /*
+                        * Close the current file and open a new one.
+                        */
+                       pcap_dump_close(dump_info->p);
 
-               /*
-                * Compress the file we just closed, if the user asked for it
-                */
-               if (zflag != NULL)
-                       compress_savefile(dump_info->CurrentFileName);
+                       /*
+                        * Compress the file we just closed, if the user
+                        * asked for it.
+                        */
+                       if (zflag != NULL)
+                               compress_savefile(dump_info->CurrentFileName);
 
-               Cflag_count++;
-               if (Wflag > 0) {
-                       if (Cflag_count >= Wflag)
-                               Cflag_count = 0;
-               }
-               if (dump_info->CurrentFileName != NULL)
-                       free(dump_info->CurrentFileName);
-               dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1);
-               if (dump_info->CurrentFileName == NULL)
-                       error("dump_packet_and_trunc: malloc");
-               MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);
+                       Cflag_count++;
+                       if (Wflag > 0) {
+                               if (Cflag_count >= Wflag)
+                                       Cflag_count = 0;
+                       }
+                       if (dump_info->CurrentFileName != NULL)
+                               free(dump_info->CurrentFileName);
+                       dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1);
+                       if (dump_info->CurrentFileName == NULL)
+                               error("dump_packet_and_trunc: malloc");
+                       MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);
+#ifdef HAVE_LIBCAP_NG
+                       capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
+                       capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
 #ifdef HAVE_CAPSICUM
-               fd = openat(dump_info->dirfd, dump_info->CurrentFileName,
-                   O_CREAT | O_WRONLY | O_TRUNC, 0644);
-               if (fd < 0) {
-                       error("unable to open file %s",
-                           dump_info->CurrentFileName);
-               }
-               fp = fdopen(fd, "w");
-               if (fp == NULL) {
-                       error("unable to fdopen file %s",
-                           dump_info->CurrentFileName);
-               }
-               dump_info->p = pcap_dump_fopen(dump_info->pd, fp);
+                       fd = openat(dump_info->dirfd, dump_info->CurrentFileName,
+                           O_CREAT | O_WRONLY | O_TRUNC, 0644);
+                       if (fd < 0) {
+                               error("unable to open file %s",
+                                   dump_info->CurrentFileName);
+                       }
+                       fp = fdopen(fd, "w");
+                       if (fp == NULL) {
+                               error("unable to fdopen file %s",
+                                   dump_info->CurrentFileName);
+                       }
+                       dump_info->p = pcap_dump_fopen(dump_info->pd, fp);
 #else  /* !HAVE_CAPSICUM */
-               dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
+                       dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
 #endif
-               if (dump_info->p == NULL)
-                       error("%s", pcap_geterr(pd));
+#ifdef HAVE_LIBCAP_NG
+                       capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
+                       capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
+                       if (dump_info->p == NULL)
+                               error("%s", pcap_geterr(pd));
 #ifdef HAVE_CAPSICUM
-               cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
-               if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
-                   &rights) < 0 && errno != ENOSYS) {
-                       error("unable to limit dump descriptor");
-               }
+                       set_dumper_capsicum_rights(dump_info->p);
 #endif
+               }
        }
 
        pcap_dump((u_char *)dump_info->p, h, sp);
@@ -2429,7 +2538,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
                info(0);
 }
 
-#ifdef WIN32
+#ifdef _WIN32
        /*
         * XXX - there should really be libpcap calls to get the version
         * number as a string (the string would be generated from #defines
@@ -2510,28 +2619,28 @@ print_version(void)
 {
        extern char version[];
 #ifndef HAVE_PCAP_LIB_VERSION
-#if defined(WIN32) || defined(HAVE_PCAP_VERSION)
+#if defined(_WIN32) || defined(HAVE_PCAP_VERSION)
        extern char pcap_version[];
-#else /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */
+#else /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */
        static char pcap_version[] = "unknown";
-#endif /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */
+#endif /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */
 #endif /* HAVE_PCAP_LIB_VERSION */
 
 #ifdef HAVE_PCAP_LIB_VERSION
-#ifdef WIN32
+#ifdef _WIN32
        (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version);
-#else /* WIN32 */
+#else /* _WIN32 */
        (void)fprintf(stderr, "%s version %s\n", program_name, version);
-#endif /* WIN32 */
+#endif /* _WIN32 */
        (void)fprintf(stderr, "%s\n",pcap_lib_version());
 #else /* HAVE_PCAP_LIB_VERSION */
-#ifdef WIN32
+#ifdef _WIN32
        (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version);
        (void)fprintf(stderr, "WinPcap version %s, based on libpcap version %s\n",Wpcap_version, pcap_version);
-#else /* WIN32 */
+#else /* _WIN32 */
        (void)fprintf(stderr, "%s version %s\n", program_name, version);
        (void)fprintf(stderr, "libpcap version %s\n", pcap_version);
-#endif /* WIN32 */
+#endif /* _WIN32 */
 #endif /* HAVE_PCAP_LIB_VERSION */
 
 #if defined(HAVE_LIBCRYPTO) && defined(SSLEAY_VERSION)