Blame packet/packet.c

Packit b802ec
/*
Packit b802ec
    mtr  --  a network diagnostic tool
Packit b802ec
    Copyright (C) 2016  Matt Kimball
Packit b802ec
Packit b802ec
    This program is free software; you can redistribute it and/or modify
Packit b802ec
    it under the terms of the GNU General Public License version 2 as
Packit b802ec
    published by the Free Software Foundation.
Packit b802ec
Packit b802ec
    This program is distributed in the hope that it will be useful,
Packit b802ec
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b802ec
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b802ec
    GNU General Public License for more details.
Packit b802ec
Packit b802ec
    You should have received a copy of the GNU General Public License
Packit b802ec
    along with this program; if not, write to the Free Software
Packit b802ec
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit b802ec
*/
Packit b802ec
Packit b802ec
#include "config.h"
Packit b802ec
Packit b802ec
#include <errno.h>
Packit b802ec
#include <stdio.h>
Packit b802ec
#include <stdlib.h>
Packit b802ec
#include <string.h>
Packit b802ec
#include <unistd.h>
Packit b802ec
Packit b802ec
#ifdef HAVE_LIBCAP
Packit b802ec
#include <sys/capability.h>
Packit b802ec
#endif
Packit b802ec
Packit b802ec
#include "wait.h"
Packit b802ec
Packit b802ec
/*  Drop SUID privileges.  To be used after accquiring raw sockets.  */
Packit b802ec
static
Packit b802ec
int drop_elevated_permissions(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
#ifdef HAVE_LIBCAP
Packit b802ec
    cap_t cap;
Packit b802ec
#endif
Packit b802ec
Packit b802ec
    /*  Drop any suid permissions granted  */
Packit b802ec
    if (setgid(getgid()) || setuid(getuid())) {
Packit b802ec
        return -1;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (geteuid() != getuid() || getegid() != getgid()) {
Packit b802ec
        return -1;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    /*
Packit b802ec
       Drop all process capabilities.
Packit b802ec
       This will revoke anything granted by a commandline 'setcap'
Packit b802ec
     */
Packit b802ec
#ifdef HAVE_LIBCAP
Packit b802ec
    cap = cap_get_proc();
Packit b802ec
    if (cap == NULL) {
Packit b802ec
        return -1;
Packit b802ec
    }
Packit b802ec
    if (cap_clear(cap)) {
Packit b802ec
        return -1;
Packit b802ec
    }
Packit b802ec
    if (cap_set_proc(cap)) {
Packit b802ec
        return -1;
Packit b802ec
    }
Packit b802ec
#endif
Packit b802ec
Packit b802ec
    return 0;
Packit b802ec
}
Packit b802ec
Packit b802ec
int main(
Packit b802ec
    int argc,
Packit b802ec
    char **argv)
Packit b802ec
{
Packit b802ec
    bool command_pipe_open;
Packit b802ec
    struct command_buffer_t command_buffer;
Packit b802ec
    struct net_state_t net_state;
Packit b802ec
Packit b802ec
    /*
Packit b802ec
       To minimize security risk, the only thing done prior to 
Packit b802ec
       dropping SUID should be opening the network state for
Packit b802ec
       raw sockets.
Packit b802ec
     */
Packit b802ec
    init_net_state_privileged(&net_state);
Packit b802ec
    if (drop_elevated_permissions()) {
Packit b802ec
        perror("Unable to drop elevated permissions");
Packit b802ec
        exit(EXIT_FAILURE);
Packit b802ec
    }
Packit b802ec
    init_net_state(&net_state);
Packit b802ec
Packit b802ec
    init_command_buffer(&command_buffer, fileno(stdin));
Packit b802ec
Packit b802ec
    command_pipe_open = true;
Packit b802ec
Packit b802ec
    /*
Packit b802ec
       Dispatch commands and respond to probe replies until the
Packit b802ec
       command stream is closed.
Packit b802ec
     */
Packit b802ec
    while (true) {
Packit b802ec
        /*  Ensure any responses are written before waiting  */
Packit b802ec
        fflush(stdout);
Packit b802ec
        wait_for_activity(&command_buffer, &net_state);
Packit b802ec
Packit b802ec
        /*
Packit b802ec
           Receive replies first so that the timestamps are as
Packit b802ec
           close to the response arrival time as possible.
Packit b802ec
         */
Packit b802ec
        receive_replies(&net_state);
Packit b802ec
Packit b802ec
        if (command_pipe_open) {
Packit b802ec
            if (read_commands(&command_buffer)) {
Packit b802ec
                if (errno == EPIPE) {
Packit b802ec
                    command_pipe_open = false;
Packit b802ec
                }
Packit b802ec
            }
Packit b802ec
        }
Packit b802ec
Packit b802ec
        check_probe_timeouts(&net_state);
Packit b802ec
Packit b802ec
        /*
Packit b802ec
           Dispatch commands late so that the window between probe
Packit b802ec
           departure and arriving replies is as small as possible.
Packit b802ec
         */
Packit b802ec
        dispatch_buffer_commands(&command_buffer, &net_state);
Packit b802ec
Packit b802ec
        /*
Packit b802ec
           If the command pipe has been closed, exit after all
Packit b802ec
           in-flight probes have reported their status.
Packit b802ec
         */
Packit b802ec
        if (!command_pipe_open) {
Packit b802ec
            if (net_state.outstanding_probe_count == 0) {
Packit b802ec
                break;
Packit b802ec
            }
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return 0;
Packit b802ec
}