2013-03-09 23 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");