/* expnbrute.c by CoKi <coki@nosystem.com.ar>

  This program tries to find users in a SMTP server
  through command EXPN, using a list of user names

  Use: ./expnbrute <list> <host>

  No System Group - http://www.nosystem.com.ar
  coki@nosystem.com.ar

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define DATAMAX 300
#define ERROR -1
#define TIMEOUT 3
#define PORT 25

void use(char *program);
int connect_timeout(int sfd, struct sockaddr *serv_addr, socklen_t addrlen,
  int timeout);

int main(int argc, char *argv[]) {

  FILE *list;
  int sockfd, cant=0, cant_u=0;
  char buf[DATAMAX], sendstr[DATAMAX];
  char user[30];
  struct hostent *he;
  struct sockaddr_in dest_dir;
  struct timeval timeout;
  fd_set readfds;

  if(argc != 3)
    use(argv[0]);

  printf("\n expnbrute by CoKi <coki@nosystem.com.ar>\n\n");

  printf(" [1] verifying list:\t");
  fflush(stdout);
  
  if((list=fopen(argv[1], "r")) == NULL) {
    printf("Failed\n\n");
    exit(1);
  }              
  
  while(!feof(list)) if('\n' == fgetc(list)) cant++;
  rewind(list);
      
  printf("OK (%d users)\n", cant);

  printf(" [2] host:\t\t");
  fflush(stdout);
      
  if((he=gethostbyname(argv[2])) == NULL) {
    herror("Error");
    printf("\n");
    exit(1);
  } 

  printf("OK\n");

  printf(" [3] connecting:\t");
  fflush(stdout);

  if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == ERROR) {
    perror("Error");
    printf("\n");
    exit(1);
  }

  dest_dir.sin_family = AF_INET;
  dest_dir.sin_port = htons(PORT);
  dest_dir.sin_addr = *((struct in_addr *)he->h_addr);
  bzero(&(dest_dir.sin_zero), 8);
    
  if(connect_timeout(sockfd, (struct sockaddr *)&dest_dir, sizeof(struct sockaddr), TIMEOUT) == ERROR) {
    printf("Closed\n\n");
    exit(1);
  }

  printf("OK\n");

  printf(" [4] verifying expn:\t");
  fflush(stdout);

  timeout.tv_sec = TIMEOUT;
  timeout.tv_usec = 0;
  FD_ZERO(&readfds);
  FD_SET(sockfd, &readfds);
        
  select(sockfd+1, &readfds, NULL, NULL, &timeout);
          
  if(!FD_ISSET(sockfd, &readfds)) {
    printf("timeout\n\n");
    exit(1);
  }
                      
  recv(sockfd, buf, sizeof(buf), 0);
  bzero(buf, sizeof(buf));
  sprintf(sendstr, "EXPN root\n");
  send(sockfd, sendstr, strlen(sendstr), 0);
  recv(sockfd, buf, sizeof(buf), 0);

  if(strstr(buf, "250")) printf("OK\n");

  else {
    printf("OFF\n\n");
    exit(1);
  }
  
  printf(" [5] searching for system accounts...\n");
  fflush(stdout);
  
  while(!feof(list)) {
    if(fgets(user, sizeof(user), list) == NULL) break;
    user[strlen(user)-1] = '\0';
    printf("     %s\t=> ", user);
    fflush(stdout);
    bzero(buf, sizeof(buf));
    sprintf(sendstr, "EXPN %s\n", user);
    send(sockfd, sendstr, strlen(sendstr), 0);
    recv(sockfd, buf, sizeof(buf), 0);
    if(strstr(buf, "250")) {
      printf("OK\n");
      cant_u++;
    }
    else printf("NO\n");
  }
  
  if(cant_u == 0) printf("\t\t None\n");                            
  printf("\n");
  close(sockfd);
  fclose(list);
}

void use(char *program) {
  printf("Use: %s <list> <host>\n", program);
  exit(1);
}

int connect_timeout(int sfd, struct sockaddr *serv_addr, socklen_t addrlen,
  int timeout) {

  int res, slen, flags;
  struct timeval tv;
  struct sockaddr_in addr;
  fd_set rdf, wrf;

  fcntl(sfd, F_SETFL, O_NONBLOCK);

  res = connect(sfd, serv_addr, addrlen);

  if (res >= 0) return res;

  FD_ZERO(&rdf);
  FD_ZERO(&wrf);

  FD_SET(sfd, &rdf);
  FD_SET(sfd, &wrf);
  bzero(&tv, sizeof(tv));
  tv.tv_sec = timeout;

  if (select(sfd + 1, &rdf, &wrf, 0, &tv) <= 0)
    return -1;

  if (FD_ISSET(sfd, &wrf) || FD_ISSET(sfd, &rdf)) {
    slen = sizeof(addr);
    if (getpeername(sfd, (struct sockaddr*)&addr, &slen) == -1)
    return -1;

    flags = fcntl(sfd, F_GETFL, NULL);
    fcntl(sfd, F_SETFL, flags & ~O_NONBLOCK);

    return 0;
  }

  return -1;
}

