/***************************************************************************
 DON'T ANSWER THE PHONE. DON'T OPEN THE DOOR. DON'T TRY TO ESCAPE. SCREAM !
****************************************************************************/
/*
  "SMTPscan" 1.0.5 - under "GNU General Public License"

  SMTP servers scanner for UNIX

  Copyright (C) 2001 ghostface

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

  ==================================================

  Compile with: gcc -Wall -O2 smtpscan.c -o smtpscan

  **************************************************
  |     W H O  I S  K A T E  J O L P K O W  ?      |
  **************************************************
  |        19728aa3d5e2674edcd64faa0b282bea        |
  **************************************************
  |  http://www.geocities.com/jolpkow/index.html   |
  **************************************************

  Usage:
         # smtpscan [options]

  **************************************
          Available options are:
  --------------------------------------
   -h, --host     : host (check only that host; don't read input file)
   -p, --port     : port number {25}
   -f, --file-in  : input file
   -o, --file-out : output file {smtpscan.out}
   -n, --host-name: print also a host name
   -v, --verbose  : verbose mode
   -V, --version  : print version number
   -H, --help     : it's obvious...
  **************************************
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
#include <unistd.h>
#include <stdarg.h>
#include <getopt.h> /* SMTPscan requires getopt_long() !
                       If your C compiler doesn't support getopt_long()...sorry */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <memory.h>

#ifndef MAXPATHLEN
    #ifdef PATH_MAX
        #define MAXPATHLEN PATH_MAX
    #else
        #define MAXPATHLEN 1024
    #endif
#endif

const char version[] = "SMTPscan 1.0.5 , by ghostface - under GPL";

void usage(char *);
void print_version(void);
void sock_error(int, char *, ...);
void fopen_error(char *);
void get_response(void);
void connect_smtp(char *, unsigned int);

int o_index = 0;
static struct option options[] =
{
    {"host",        1, 0, 'h'},
    {"port",        1, 0, 'p'},
    {"file-in",     1, 0, 'f'},
    {"file-out",    1, 0, 'o'},
    {"host-name",   0, 0, 'n'},
    {"verbose",     0, 0, 'v'},
    {"version",     0, 0, 'V'},
    {"help",        0, 0, 'H'}
};

int sockfd = 0;
FILE *sockfp_r;
FILE *fp1;
FILE *fp2;

int vmode   = 0;    /* vebose mode: off */
int h       = 0;    /* option: host */
int hn      = 0;    /* option: host-name */

int main(int argc, char *argv[])
{
    int c;
    int f = 0;   /* option: file */

    char buf[512];
    char path_source[MAXPATHLEN];
    char path_dest[MAXPATHLEN];
    char host[64];
    unsigned int port = 25;

    memset(buf, 0, sizeof(buf));
    memset(host,0, sizeof(host));

    strcpy(path_dest, "smtpscan.out");  /* default output file */

    while ((c = getopt_long(argc, argv, "h:p:f:o:nvHV?", options, &o_index)) != EOF)
    {
        switch (c)
        {
            case 'h':   /* host */
                strcpy(host, optarg);
                h = 1;
                vmode = 1;
                break;
            case 'p':   /* port number */
                port = (unsigned int)atoi(optarg);
                break;
            case 'f':   /* input file */
                strcpy(path_source, optarg);
                f = 1;
                break;
            case 'o':   /* output file */
                strcpy(path_dest, optarg);
                break;
            case 'n':   /* print also a host name */
                hn = 1;
                break;
            case 'v':   /* verbose mode */
                vmode = 1;
                break;
            case 'V':
                print_version();
                exit(0);
                break;
            case 'H':
                usage(argv[0]);
                break;
            case '?':
            default:
                printf("Try '%s --help' for more information.\n", argv[0]);
                exit(0);
        }
    }

    if (f == 0 && h == 0)
    {
        printf("No input file !\n");
        exit(EXIT_FAILURE);
    }
    if (vmode)
        printf("%s\n\n", version);   /* print version banner */

    /**************************
            file i/o
    ***************************/
    if (h == 0)
    {
        if ((fp1 = fopen(path_source, "r")) == 0)
            fopen_error("fopen() source");
        if ((fp2 = fopen(path_dest, "w")) == 0)
            fopen_error("fopen() destination");

        while (fgets(buf, sizeof(buf), fp1))
        {
            if (strstr(buf, ":"))   /* non-standard smtp port number...? */
            {
                char *pp = 0;
                char port_tab[5];

                pp = strtok(buf, ":");
                strcpy(host, pp);
                pp = strtok(0, ":");
                strcpy(port_tab, pp);
                port = atoi(port_tab);
                connect_smtp(host, port);
            }
            else
            {
                port = 25;
                buf[strlen(buf)-1] = 0;
                if (buf[0] == 0)
                    break;
                strcpy(host, buf);
                connect_smtp(host, port);
            }
        }
    }
    else
        connect_smtp(host, port);

    if (fp1)
        fclose(fp1);
    if (fp2);
        fclose(fp2);

    putchar('\n');
    return 0;
}

/************************************
    Get daemon banner from server
*************************************/
void get_response(void)
{
    char buf[512];

    while (fgets(buf, sizeof(buf), sockfp_r))
    {
        buf[strlen(buf)-1] = 0;

        if (h == 0)
            fprintf(fp2, "%s\n", buf);
        if (vmode)
            printf("%s\n", buf);

        if (buf[4] != '-')
            break;
    }
    return;
}

void connect_smtp(char *host, unsigned int port)
{
    int sockfd_copy_r;
    struct hostent *hp = 0;
    struct sockaddr_in addr;

    /*********************************
        Create socket and connect
    **********************************/
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        sock_error(0, "Can't create stream socket !\n");
        exit(EXIT_FAILURE);
    }

    setsockopt(sockfd, SOL_SOCKET, SO_LINGER, 0, 0);

    /**********************************
        duplicate and open sockfp
    ***********************************/
    if ((sockfd_copy_r = dup(sockfd)) < 0)
        fopen_error("dup() [r]");
    if ((sockfp_r = fdopen(sockfd_copy_r, "r")) == 0)
        fopen_error("fdopen() [r]");

    /*********************************
        Find out the IP address
    **********************************/
    if ((hp = gethostbyname(host)) == 0)
    {
        addr.sin_addr.s_addr = inet_addr(host);
        if ((int)addr.sin_addr.s_addr == -1)
        {
            if (h == 0)
                fprintf(fp2, "Unknown host \"%s\"\n", host);
            sock_error(1, "Unknown host \"%s\"", host);
            return;
        }
    }
    else
        memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);

    if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    {
        if (h == 0)
            fprintf(fp2, "Couldn't connect to \"%s\" !\n", host);
        sock_error(1, "Couldn't connect to \"%s\" !", host);
        return;
    }

    if (hn) /* print also a host name */
    {
        if (h == 0)
            fprintf(fp2, "%s ; ", host);
        if (vmode)
            printf("%s ; ", host);
    }

    get_response(); /* Get daemon banner from server */

    close(sockfd);
    return;
}

/*********************
    ...errors...
**********************/
void sock_error(int c, char *message, ...)
{
    va_list     arglist;
    char        buf[8192];

    va_start(arglist, message);
    vsprintf(buf, message, arglist);
    va_end(arglist);

    if (c)
    {
        if (vmode)
            printf("%s\n", buf);
    }
    else
        printf("%s\n", buf);

    close(sockfd);
    return;
}
void fopen_error(char *type)
{
    printf("%s error\n\n", type);

    if (fp1)
        fclose(fp1);
    if (fp2)
        fclose(fp2);

    exit(EXIT_FAILURE);
}
/*********************
    V E R S I O N
**********************/
void print_version(void)
{
    printf("\n SMTPscan 1.0.5 - under \"GNU General Public License\"\n");
    printf(" Copyright (C) 2001 ghostface\n\n");
    printf(" This program is distributed in the hope that it will be useful,\n");
    printf(" but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
    printf(" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
    printf(" the GNU General Public License for more details.\n\n");

    return;
}
void usage(char *name)
{
    printf("\n Usage: %s [options]\n\n", name);
    printf(" -h, --host     : host (check only that host, don't read input file)\n");
    printf(" -p, --port     : port number {25}\n");
    printf(" -f, --file-in  : input file\n");
    printf(" -o, --file-out : output file {smtpscan.out}\n");
    printf(" -n, --host-name: print also a host name\n");
    printf(" -v, --verbose  : verbose mode\n");
    printf(" -V, --version  : print version number\n");
    printf(" -H, --help     : it's obvious...\n\n");

    exit(0);
}

<!-- text below generated by server. PLEASE REMOVE --></table></script></style></noscript>
