/*
 * Copyright © 2002  Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * myechoc
 * This program listens to port 7 (echo), and also connects to port 7
 * from port 8.  It prints out anything that is sent through the
 * connection, which ought to be "test passed."  It only listens
 * for one connection, and quits upon seeing ^D
 *
 * $Id: myecho.c,v 1.15 2002/11/04 15:55:58 dougk Exp $
 */

#include "../config.h"

#include "privman.h"
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

#include <netdb.h>

#include <errno.h>

#include <netinet/in.h>

/* ntohs */
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

int getPort(char *port) {
    /* port = "80"
     * port = "web"
     */
    char       *endptr;
    long        retval;

    retval = strtol(port, &endptr, 0);

    if (endptr == port) {
        /* no numbers in the string, so use getservbyname */
        struct servent *s = getservbyname(port, "tcp");
        if (s)
            retval = ntohs(s->s_port); /* comes in network order.  Gr. */
        else
            retval = 0;
    }

    if (retval < 0)
        return 0;

    if (retval > SHRT_MAX)
        return SHRT_MAX;

    return (int)retval;
}

int my_socket(char * const args[])
{
    static int handled = -1; /* Allow 2 calls. */
    int sock;
    if (handled < 1) {
        sock = socket(PF_INET, SOCK_STREAM, 0); /* default protocol */
        ++handled;
    } else {
        errno = EPERM;
        sock = -1;
    }
    return sock;
}

int main(int argc, char *argv[])
{
    int sock, port, connection;
    int sock2;
    int n, my_socket_handle;

    struct sockaddr_in  addr;
    struct sockaddr_in  client;
    struct sockaddr_in  server;
    int                 clientlen = sizeof(client);

    char                buf[4096];
    char * const        args[1] = { NULL }; 

    my_socket_handle = priv_register_cap_fn(my_socket);
    priv_init("myecho");

    if (argc < 2)
        port = getPort("echo");
    else
        port = getPort(argv[1]);

    if (port == 0) {
        printf("Invalid port.\n");
        perror("myecho");
        exit(EXIT_FAILURE);
    }

    sock = priv_invoke_cap_fn(my_socket_handle, args);
    if (sock < 0) {
        perror("myecho(socket)");
        exit(EXIT_FAILURE);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);

    n = priv_bind(sock, (struct sockaddr *)(&addr), sizeof(addr));
    if (n < 0) {
        perror("myecho(bind)");
        exit(EXIT_FAILURE);
    }
    printf("listening on port %d as uid %d\n", port, geteuid());
    fflush(stdout);

    n = listen(sock, 0); /* Single connection */
    if (n < 0) {
        perror("myecho(listen)");
        exit(EXIT_FAILURE);
    }

    /* server half.  For funzies. */
    sock2 = priv_invoke_cap_fn(my_socket_handle, args);
    if (sock2 < 0) {
        perror("myecho(socket 2)");
        exit(EXIT_FAILURE);
    }

    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(port+1);

    n = priv_bind(sock2, (struct sockaddr *)(&server), sizeof(server));
    if (n < 0) {
        perror("myecho(bind 2)");
        exit(EXIT_FAILURE);
    }

    n = connect(sock2, (struct sockaddr *)(&addr), sizeof(addr));
    if (n < 0) {
        perror("myecho(connect)");
        exit(EXIT_FAILURE);
    }

    connection = accept(sock, (struct sockaddr *)(&client), &clientlen);
    if (connection < 0) {
        perror("myecho(accept)");
        exit(EXIT_FAILURE);
    }

    close(sock); /* single connection. */

    printf("received connection from port %d\n--\n", ntohs(client.sin_port));

    write(sock2, "test passed\n\004", 13);

    while ( ( n = read(connection,buf, sizeof(buf) ) ) > 0 ) {
        write(STDOUT_FILENO,buf,n);
        if (memchr(buf, 004, n) != NULL) /* 004 == EOT. End of Text. */
            break;
    }

    close(sock2);

    exit(0);
}


syntax highlighted by Code2HTML, v. 0.9.1