2013-03-09 20 views
2

我试图做一个简单的连接到SMTP服务器(需要认证)。 我使用SSL(C中的OpenSSL库)在端口587上连接到smtp.live.com。如何在C中使用SMTP身份验证?

我首先用socket()函数初始化我的套接字,然后用connect()连接到服务器。然后我启动SSL通道,然后尝试登录。

这里是我的壳输出:

server : 220 BLU0-SMTP261.phx.gbl Microsoft ESMTP MAIL Service, Version: 6.0.3790.4675  ready at Sat, 9 Mar 2013 07:25:17 -0800 

EHLO [127.0.0.1] 
server : 250-BLU0-SMTP261.phx.gbl Hello [163.5.221.45] 
250-TURN 
250-SIZE 41943040 
250-ETRN 
250-PIPELINING 
250-DSN 
250-ENHANCEDSTATUSCODES 
250-8bitmime 
250-BINARYMIME 
250-CHUNKING 
250-VRFY 
250-TLS 
250-STARTTLS 
250 OK 

STARTTLS 
server : 220 2.0.0 SMTP server ready 

EHLO [127.0.0.1] 
server : 250-BLU0-SMTP261.phx.gbl Hello [163.5.221.45] 
250-TURN 
250-SIZE 41943040 
250-ETRN 
250-PIPELINING 
250-DSN 
250-ENHANCEDSTATUSCODES 
250-8bitmime 
250-BINARYMIME 
250-CHUNKING 
250-VRFY 
250-AUTH LOGIN PLAIN 
250 OK 

AUTH LOGIN 
server : 334 VXNlcm5hbWU6 

Y2hlcmGhvdXXXXXXXXXXXuY29tXHJcbg0K 
serveur : 
U2hsYWXXXXXXXXXXXwblxyXG4NCg0K 
server : 

正如你所看到的,用户名和密码是用base64编码两种(没有\ r \ n)的。我不明白为什么服务器不答什么...(我试图把一个sleep()读取套接字之前,但我得到了同样的结果)

代码连接到服务器:

static int    _connect_IPV4(int socket, struct hostent *host) 
{ 
    struct sockaddr_in addr; 

    addr.sin_port = htons(587); 
    addr.sin_family = AF_INET; 
    addr.sin_addr = *(struct in_addr *)host->h_addr; 
    bzero(&addr.sin_zero, 8); 
    if (connect(socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1) 
    printf("%s\n", strerror(errno)); 
    else 
    return (socket); 
} 

代码开始SSL:

static void  _launch_ssl(int socket) 
{ 
    read_socket(socket); 
    write_socket(socket, "EHLO [127.0.0.1]\r\n"); 
    read_socket(socket); 
    write_socket(socket, "STARTTLS\r\n"); 
    read_socket(socket); 
} 

代码连接SSL:

connection  *ssl_connect() 
{ 
    connection *c; 

    c = malloc(sizeof(connection)); 
    c->ssl_handle = NULL; 
    c->ssl_context = NULL; 
    c->socket = connect_TCP_IP(); 
    _launch_ssl(c->socket); 
    if (c->socket != -1) 
    { 
     SSL_load_error_strings(); 
     SSL_library_init(); 

     SSL_CTX_new(SSLv23_client_method()); 
     SSL_new(c->ssl_context); 
     SSL_set_fd(c->ssl_handle, c->socket); 
     SSL_connect(c->ssl_handle); 
    } 
    return (c); 
} 

主营:

int    main() 
{ 
    connection *c; 

    c = ssl_connect(); 
    ssl_write_socket(c, "EHLO [127.0.0.1]\r\n"); 
    ssl_read_socket(c); 
    ssl_write_socket(c, "AUTH LOGIN\r\n"); 
    ssl_read_socket(c); 
    ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29tXHJcbg0K"); 
    printf("\n"); 
    ssl_read_socket(c); 
    ssl_write_socket(c, "U2hsYWdldHRvUHIwblxyXG4NCg0K"); 
    printf("\n"); 
    ssl_read_socket(c); 
} 
+0

您需要向我们展示你的代码... – 2013-03-09 15:43:17

回答

1

首先,我希望您打算改进您的客户端,以便它实际上对服务器发送的内容做出反应。例如,它看起来像在您的_launch_ssl函数中,您实际上并未检查服务器对EHLO的回复,以确保STARTTLS在您尝试使用它之前作为选项提供。该函数的伪代码应为:

  1. 发送EHLO(最好不要用毫无意义的东西像[127.0.0.1]!)
  2. 检查服务器的答复
  3. 如果STARTTLS是不提供的选项中,保释
  4. 如果STARTTLS是所提供的选项之一,请发送STARTTLS并继续。

相若方式,在main(),你需要EHLO服务器实际上已经回应250后检查,并AUTH服务器实际上已经回答334

否则检查后,这个问题似乎是你请在回复后发送\r\n。换句话说:

ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29tXHJcbg0K"); 

应该是:

ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29tXHJcbg0K\r\n"); 

此外,您的base64字符串包含嵌入内的一个\\r\\n\r\n(反斜杠+ 'R' +反斜杠+ 'N' + CR + LF)字符串好像\\r\\n\r\n是用户名的一部分。假设是错的,那么,实际上,你的代码也许应该实际阅读:

ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29t\r\n");