smtpClient.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //
  2. // smtpClient.c - example SMTP Client shell to send HELO to SMTP server
  3. //
  4. // compile using: gcc -o smtpClient smtpClient.c
  5. // run using: ./smtpClient <mail host> [ port ]
  6. // example: ./smtpClient mailhost.ksu.edu 25
  7. //
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>
  14. #include <netdb.h> // for struct hostent
  15. #include <openssl/ssl.h>
  16. #include <openssl/err.h>
  17. #include "slitheen.h"
  18. #define MAX_REQUEST 1024
  19. #define MAX_REPLY BUFSIZ
  20. int getLine(int fd, char line[], int max);
  21. void apps_ssl_info_callback( SSL *s, int where, int ret )
  22. {
  23. char *str;
  24. int w;
  25. w=where& ~SSL_ST_MASK;
  26. if (w & SSL_ST_CONNECT) str="SSL_connect";
  27. else if (w & SSL_ST_ACCEPT) str="SSL_accept";
  28. else str="undefined";
  29. if (where & SSL_CB_LOOP)
  30. {
  31. fprintf(stderr,"%s: %s\n",str,SSL_state_string_long(s));
  32. }
  33. else if (where & SSL_CB_ALERT)
  34. {
  35. str=(where & SSL_CB_READ)?"read":"write";
  36. fprintf(stderr,"SSL3 alert %s:%s:%s\n",
  37. str,
  38. SSL_alert_type_string_long(ret),
  39. SSL_alert_desc_string_long(ret));
  40. }
  41. else if (where & SSL_CB_EXIT)
  42. {
  43. if (ret == 0)
  44. fprintf(stderr,"%s:failed in %s\n",
  45. str,SSL_state_string_long(s));
  46. else if (ret < 0)
  47. {
  48. fprintf(stderr,"%s:error in %s\n",
  49. str,SSL_state_string_long(s));
  50. }
  51. }
  52. }
  53. main(int argc, char **argv)
  54. {
  55. int sockfd;
  56. struct sockaddr_in serv_addr;
  57. char request[MAX_REQUEST+1];
  58. char reply[MAX_REPLY+1];
  59. unsigned int server_port = 25;
  60. struct hostent *hostptr;
  61. struct in_addr *ptr;
  62. unsigned short port_number;
  63. char userinput[801]; //MAX_IN is initialized to 800
  64. SSL_CTX *ctx = NULL;
  65. SSL *session = NULL;
  66. //TLS setup
  67. const SSL_METHOD *meth = TLSv1_2_client_method();
  68. //const SSL_METHOD *meth = SSLv23_client_method();
  69. if (meth == NULL) {
  70. fprintf( stderr, "no method. :(\n" ); exit(1);
  71. }
  72. SSL_load_error_strings();
  73. OpenSSL_add_ssl_algorithms();
  74. ctx = SSL_CTX_new( meth );
  75. if ( ctx == NULL ) { fprintf( stderr, "no context. :(\n" ); exit(1);
  76. ERR_print_errors_fp(stderr);
  77. }
  78. //SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384");
  79. //set Slitheen callbacks
  80. slitheen_init();
  81. SSL_CTX_set_client_hello_callback(ctx, slitheen_tag_hello);
  82. //SSL_CTX_set_generate_ec_key_callback(ctx, slitheen_ec_seed_from_tag);
  83. //SSL_CTX_set_generate_key_callback(ctx, slitheen_seed_from_tag);
  84. //SSL_CTX_set_finished_mac_callback(ctx, slitheen_finished_mac);
  85. /* Set up a callback for each state change so we can see what's
  86. * going on */
  87. SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
  88. // Read hostname and port from the command-line
  89. if (argc < 2)
  90. {
  91. printf("Usage: smtpClient <hostname> [port-number]\n");
  92. return(1);
  93. }
  94. if (argc > 2)
  95. port_number = atoi(argv[2]);
  96. else
  97. port_number = 25;
  98. if ( (hostptr = (struct hostent *) gethostbyname(argv[1])) == NULL) {
  99. perror("gethostbyname error for host");
  100. return(1);
  101. }
  102. ptr = (struct in_addr *) *(hostptr->h_addr_list);
  103. printf ("DEBUG: server address: %u %s\n",ptr->s_addr,inet_ntoa(*ptr));
  104. memset((char *) &serv_addr, 0, sizeof(serv_addr));
  105. serv_addr.sin_family = AF_INET;
  106. serv_addr.sin_addr.s_addr = ptr->s_addr;
  107. serv_addr.sin_port = htons(port_number);
  108. // Create communication endpoint.
  109. if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  110. perror("server: can't open stream socket");
  111. return(1);
  112. }
  113. // Connect to the server.
  114. if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
  115. perror("client: can't connect to server");
  116. return(1);
  117. }
  118. getLine(sockfd, reply, MAX_REPLY);
  119. puts(reply);
  120. printf("SENDING HELO %s\n", argv[1]);
  121. sprintf(request,"HELO %s\r\n", argv[1]);
  122. write(sockfd, request, strlen(request));
  123. read(sockfd, reply, BUFSIZ);
  124. puts(reply);
  125. printf("SENDING STARTTLS\n");
  126. sprintf(request, "STARTTLS\r\n");
  127. write(sockfd, request, strlen(request));
  128. getLine(sockfd, reply, MAX_REPLY);
  129. puts(reply);
  130. //set up ssl socket
  131. if (sockfd != -1){
  132. session = SSL_new( ctx );
  133. SSL_set_fd( session, sockfd );
  134. SSL_connect( session );
  135. }
  136. close(sockfd);
  137. return(0);
  138. }
  139. //
  140. // get a line of data from fd
  141. //
  142. int getLine(int fd, char* line, int lim)
  143. {
  144. int i;
  145. char c;
  146. i = 0;
  147. while (--lim > 0 && read(fd,&c,1)>0 && c!='\n' && c!='\0')
  148. {
  149. line[i++] = c;
  150. }
  151. if (c=='\n')
  152. line[i++] = c;
  153. line[i] = '\0';
  154. return i;
  155. }