簡體   English   中英

如何在C中使用SMTP身份驗證?

[英]How to use SMTP Auth in C?

我正在嘗試與SMTP服務器建立簡單連接(需要身份驗證)。 我使用SSL(C中的OpenSSL庫)在端口587上連接到smtp.live.com。

我首先使用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);
}

首先,我希望您打算改進您的客戶端,以使其對服務器發送的內容做出實際反應。 例如,看起來在_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");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM