/* NOTE: apache has an access.conf option to log these also */

/* Just a little utility to log information about who is exploiting us. */
/* Will mail it to root of local host, with the IP address, the web     */
/* browser, the query string, etc. It will then return a fake password  */
/* below which can be modified.                                         */
/*									*/
/* Shok (Matt Conover), shok@dataforce.net                              */

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>


/* List of defines */
#define ERROR -1

#define IP "206.71.69.243" /* Set this to your IP address. */

#define ADMIN "root" /* Set this to the user (or address) of the person    */
                     /* to get phf attempts.                               */

#define FINGERPROG "/usr/bin/finger" /* Set to path of 'finger'.           */
#define MAILPROG   "/bin/mail"       /* This does have to be the 'mail'    */
                                     /* program but this is to specify the */
                                     /* path.                              */

/* This returns a '404 File Not Found' to the client. */
#define PRNSERVERR() printf("Content-type: text/html\n\n");                \
          printf("<HTML><HEAD>\n");                                        \
          printf("<TITLE>404 File Not Found</TITLE>\n");                   \
          printf("</HEAD><BODY>\n");                                       \
                                                                           \
          printf("<H1>File Not Found</H1>\n");                             \
          printf("The requested URL was not found on this server.<P>\n");  \
                                                                           \
          printf("</BODY></HTML>\n");                                      \
                                                                           \
          fflush(stdin), fflush(stdout), fflush(stderr);                  

/* Free up our structures before exiting. */
#define FREEALL() free(buf), free(cmdarg), free(address);
/* ------------------ */

void main()
{ 
  FILE *tmpfile, *fingerinfo;

  int pid;
  int fd[2];
  register int errors = 0;

  char *buf     = malloc(4096);
  char *cmdarg  = malloc(512);
  char *address = malloc(256);

  char *host         = getenv("REMOTE_HOST");
  char *addr         = getenv("REMOTE_ADDR");
  char *browser      = getenv("HTTP_USER_AGENT");
  char *query_string = getenv("QUERY_STRING"); 


  /* We check each malloc seperately so we can free */ 
  /* any previously malloc()'d buffers.             */
  if (buf == NULL) {
     perror("malloc");
     PRNSERVERR();
     exit(ERROR);
  } else memset(buf, 0, sizeof(buf));

  if (cmdarg == NULL) {
     perror("malloc");
     PRNSERVERR();
     free(buf);
     exit(ERROR);
  } else memset(cmdarg, 0, sizeof(cmdarg));

  if (address == NULL) {
     perror("malloc");
     PRNSERVERR();
     free(buf), free(cmdarg);
     exit(ERROR);
  } else memset(address, 0, sizeof(address));
  /* ----------------------------- */


  if (pipe(fd) == ERROR) {
     perror("pipe");
     PRNSERVERR();
     FREEALL();
     exit(ERROR);
  }

  bzero(buf, sizeof(buf));

  if ((pid = fork()) == ERROR) {

     openlog("phf", LOG_PID, LOG_USER);
     syslog(LOG_ERR, "Unable to fork().");
     closelog();

     PRNSERVERR();
     FREEALL();
     exit(ERROR);
  }

  if (pid == 0) {
     close(fileno(stdout)), close(fileno(stderr)), close(fd[0]);
     dup2(fd[1], fileno(stdout)); /* Send all output to the pipe's output. */
     dup2(fd[1], fileno(stderr)); /* Send all errors to the pipe.          */

     sprintf(address, "@%.*s", 256 - 1, host); 

     /* Log information. */
     printf("The following person used phf!!\n\n");
     printf("\tHost: %s\n", host);
     printf("\tAddress: %s\n", addr);
     printf("\tBrowser type: %s\n", browser);
     printf("\tQuery String (i.e. command entered): %s\n\n", query_string); 

     printf("Information collected from fingering host (if any):\n");
     printf("---------------------------------------------------\n\n"); 
     fflush(stdout);

     if ((strcmp(addr, IP) != 0) && (strcmp(addr, "127.0.0.1") != 0)) 
        execl(FINGERPROG, "finger", address, (char *)NULL);
     else
        printf("[from the localhost (%s)]\n", IP);

     printf(".\n"); /* Terminate 'mail'. */
    /* --------------- */

     FREEALL();
     exit(0);
  } else { 

     close(fileno(stdin)), close(fileno(stderr)), close(fd[1]);
     dup2(fd[0], fileno(stdin)); /* Send all input to the pipe's input. */
     dup2(fd[1], fileno(stderr)); /* Send all errors to the pipe.          */

     wait(NULL); /* Wait for child to completely finish before starting. */

     /* Setup the subject to send to mail. */
     sprintf(cmdarg, "-s \"PHF ATTEMPT FROM %.*s!\"", 
             sizeof(cmdarg) - 19, host);
 
     /* fork() another child to execute the mail program. */
     if ((pid = fork()) == ERROR) 
     {
        perror("fork")
        PRNSERVERR();
        FREEALL();
        exit(ERROR);
    }

    if (pid == 0) execl(MAILPROG, "mail", cmdarg, ADMIN, (char *)NULL);
  }

  /* Send a fake password file.. if there is a "cat" and "/etc/passwd" */
  /* in the QUERY_STRING. Otherwise report file not found (this can    */
  /* cause problems if they first send a cat /etc/passwd and then send */
  /* an xterm request for example.                                     */

  if (strstr(query_string, "cat") && strstr(query_string, "/etc/passwd")) {
     printf("Content-type: text/html\n\n");
     printf("<HTML><HEAD>\n");
     printf("<TITLE>Query Results</TITLE>\n");
     printf("<H1>Query Results</H1>\n"); 
     printf("</HEAD><BODY>\n");

     printf("<P>\n");
     printf("/usr/local/bin/ph -m  alias=x \n");
     printf("cat /etc/passwd\n");
     printf("<PRE>\n");
     printf("root:x3DgdbFdn:0:1:Operator:/:/bin/csh\n");
     printf("nobody:*:65534:65534::/:\n");
     printf("daemon:*:1:1::/:\n");
     printf("sys:*:2:2::/:/bin/csh\n");
     printf("bin:*:3:3::/bin:\n");
     printf("uucp:*:9:9::/var/spool/uucppublic:\n");
     printf("news:*:6:6::/var/spool/news:/bin/csh\n");
     printf("mail:*:8:8::/:\n");
     printf("audit:*:11:11::/usr/sbin/audit:/bin/csh\n");
     printf("slip::25:25:SLIP:/tmp:/usr/sbin/sliplogin\n");
     printf("sync::1:1::/:/bin/sync\n");
     printf("sysdiag:*:0:1:System Diagnostic:/usr/diag/sysdiag:/usr/diag/sysdiag/sysdiag\n");
     printf("sundiag:*:0:1:System Diagnostic:/usr/diag/sundiag:/usr/diag/sundiag/sundiag\n");
     printf("ftp:*:10:20:ftp:/home/ftp:/usr/bin/bash\n");
     printf("www:*:50:50:World Wide Web:/home/www:/usr/bin/bash\n");
     printf("pop:*:60:60:Post Office Protocol:/var/spool/pop:/usr/bin/bash\n");
     printf("pcguest::7454:100:Guest Account:/tmp:/usr/bin/sh\n");
     printf("majordomo:*:405:20:Majordomo server:/dev/null:/bin/startdomo\n");
     printf("listserv:*:567:20:Listserv server:/dev/null:/bin/sh\n");
     printf("guest:*:8999:110:Guest:/home/guest:/usr/local/bin/tcsh\n");
     printf("</PRE>");

     printf("</BODY></HTML>\n");
  } else {
     PRNSERVERR();
     FREEALL();
  }

  FREEALL();
}
