简体   繁体   中英

SMTP client in C blocks on SSL_read

I have been working on a small project which is a SMTP client written in C with SSL.

I am trying to get it working with GMail. I have enabled the allow unsecure apps in GMail settings.

When I try to authenticate using the OpenSSL CLI with the command openssl s_client -connect smtp.gmail.com:465 it works just fine I get proper responses for HELO and EHLO commands (see the output below)

220 smtp.gmail.com ESMTP o3-v6sm18136158pgv.53 - gsmtp
HELO smtp.gmail.com
250 smtp.gmail.com at your service
AUTH LOGIN
334 VXNlcm5hbWU6

But once I run this with my C client it hangs on SSL_read after I send HELO smtp.gmail.com and it does not even give me any output for HELO smtp.gmail.com .

But if I send just HELO I get a proper response from the server saying that empty HELO isn't allowed

MAIN

int main(int argc, char **argv) {
    setup("smtp.gmail.com", 465);
    printf("[INFO] -- %s\n", recv_secure());
    send_secure("HELO smtp.gmail.com\r\n");
    printf("[INFO] -- %s\n", recv_secure());
    send_secure("AUTH LOGIN\r\n");
    printf("[INFO] -- %s\n", recv_secure());
    close_secure();
    return 0;
}

setup

int setup(char *hostname, int port) {
    SSL_CTX *ctx = init();

    struct hostent *host;
    struct sockaddr_in addr;
    int sock_fd;

    if((host = gethostbyname(hostname)) == NULL) {
        fprintf(stderr, "[ERROR] Unable to get host by name: %s", hostname);
        return -1;
    }

    sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    bzero(&addr, sizeof(addr));

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = *(long*)host->h_addr_list[0];

    if(connect(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
        close(sock_fd);
        fprintf(stderr, "[ERROR] Unable to connect to remote server: %s\n", hostname);
        return -1;
    }

    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sock_fd);

    if(SSL_connect(ssl) == -1) {
        fprintf(stderr, "[ERROR] Unable to establish secure connection\n");
        close(sock_fd);
        return -1;
    }
    return sock_fd;
}

send_secure

void send_secure(const char* buffer){
    SSL_write(ssl, buffer, sizeof(buffer));
}

recv_secure

char* recv_secure() {

    int bytes = SSL_read(ssl, rbuffer, SIZE);
    rbuffer[bytes] = 0;
    fprintf(stderr, "[DEBUG] -- Received: %s\n", rbuffer);
    return rbuffer;
}

I ran ltrace with it and it seems to be blocked at SSL_read but SSL_pending return value is 0

I cannot seem to understand what am I missing here.

 void send_secure(const char* buffer){ SSL_write(ssl, mbuffer, sizeof(mbuffer)); } 

Assuming that mbuffer is a typo and buffer was meant instead, this will write either 8 or 4 bytes (the size of a pointer, depending on your platform), not the length of the buffer as you probably expected (which will be wrong, too since sizeof , when applied to a literal string, also includes the terminating null byte -- which will NOT be accepted by the smtp server).

Changing sizeof to strlen may let you proceed further, but your code has a lot of problems, for instance:

 int bytes = SSL_read(ssl, rbuffer, SIZE); rbuffer[bytes] = 0; 

If SSL_read returns -1, this will (in the best case ;-)) crash your program.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM