/* idea from http://www.unix.com/302318231-post4.html * date 20160308-15:41:55 MEZ - 20160314-14:13:00 MEZ * * Description: * * 14 Different Applications to mail via sockets on two Operations Systems * SSL & NO-SSL , 3 Auth Modes on Linux. * SSL & NO-SSL , 4 Auth Modes on Windows. * * Clients can be made on Linux: * * sudo gcc main.c -o /usr/local/bin/mailer -DVERSION="\"T.E.D. - The Enemy Dail\"" * sudo gcc main.c -o /usr/local/bin/mailer -lssl -DVERSION="\"T.E.D. - The Enemy Dail\"" * sudo gcc main.c -o /usr/local/bin/mailer -lssl -lcrypto -DVERSION="\"T.E.D. - The Enemy Dail\"" * */ //CHOOSE SSL OR NOSSL #define SSLX /* ssl */ //#define SSLN /* no ssl */ //CHOOSE AUTH LOGIN , NOAUTH OR AUTH PLAIN #define AUTHLOGIN /* auth mech */ //#define AUTHPLAIN /* auth mech */ //#define AUTHNO /* auth mech */ //#define AUTHCMD5 /* auth mech WIN32 only */ //CHOOSE OS DO YOU HAVE #define LINUX /* define this if you are on linux */ //#define WIN32 /* define this if you are on windows */ /* * CONFIGURATION ENDS HERE */ #include //printf #include //strlen #include #include #include #include #include const char* Versionx() { #ifdef VERSION return VERSION; #else return ""; #endif } #ifdef SSLX #include #include // link with -lcrypto #include #include #include #endif #ifdef AUTHLOGIN || AUTHPLAIN #include #include // link with -lssl #include #endif #ifdef WIN32 #include #include /* WSAGetLastError, WSAStartUp */ #include #pragma comment(lib, "ws2_32.lib") #define snprintf _snprintf #include #ifndef CALG_HMAC #define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) #endif #ifndef CRYPT_IPSEC_HMAC_KEY #define CRYPT_IPSEC_HMAC_KEY 0x00000100 #endif #pragma comment(lib, "crypt32.lib") char * HMAC(char * str, char * password, DWORD AlgId); typedef struct _my_blob{ BLOBHEADER header; DWORD len; BYTE key[0]; }my_blob; #endif #ifdef LINUX #include /* gethostbyname */ #include /* htons */ #include /* sock */ #include #include #define PATH_MAX 4096 /* # chars in a path name including nul */ #endif #ifdef SSLX #define CHK_NULL(x) if ((x)==NULL) exit (1) #define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); } #define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); } /* define HOME to be dir for key and cert files... */ #ifdef LINUX #define HOME "/home/raven/" #elif WIN32 #define HOME "C:\\Users\\github\\mailer\\src\\" #else #error "CDK not support your OS!" #endif /* Make these what you want for cert & key files */ // openssl req -x509 -days 365 -nodes -newkey rsa:1024 -keyout valid-client-cakey.pem -out valid-client-ca.pem #define CERTF HOME "valid-client-ca.pem" #define KEYF HOME "valid-client-cakey.pem" #endif #ifndef __cplusplus typedef enum {false, true} bool; #endif #ifdef AUTHLOGIN || AUTHPLAIN bool ssl_init_count = 0; typedef struct { int sock; const char* address; unsigned short port; } sock_info; typedef struct { SSL* ssl; SSL_CTX* ctx; } ssl_info; typedef struct { char b64username[256]; char b64password[256]; } email; #endif static void sendmail_write( const int sock, const char *str, const char *arg ) { char buf[4096]; if (arg != NULL) snprintf(buf, sizeof(buf), str, arg); else snprintf(buf, sizeof(buf), str); send(sock, buf, strlen(buf), 0); } #ifdef WIN32 char * HMAC(char * str, char * password, DWORD AlgId = CALG_MD5){ HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; HCRYPTKEY hKey = 0; HCRYPTHASH hHmacHash = 0; BYTE * pbHash = 0; DWORD dwDataLen = 0; HMAC_INFO HmacInfo; int err = 0; ZeroMemory(&HmacInfo, sizeof(HmacInfo)); if (AlgId == CALG_MD5){ HmacInfo.HashAlgid = CALG_MD5; pbHash = new BYTE[16]; dwDataLen = 16; }else if(AlgId == CALG_SHA1){ HmacInfo.HashAlgid = CALG_SHA1; pbHash = new BYTE[20]; dwDataLen = 20; }else{ return 0; } ZeroMemory(pbHash, sizeof(dwDataLen)); char * res = new char[(dwDataLen * 2) + 1]; my_blob * kb = NULL; DWORD kbSize = sizeof(my_blob) + strlen(password); kb = (my_blob*)malloc(kbSize); kb->header.bType = PLAINTEXTKEYBLOB; kb->header.bVersion = CUR_BLOB_VERSION; kb->header.reserved = 0; kb->header.aiKeyAlg = CALG_RC2; memcpy(&kb->key, password, strlen(password)); kb->len = strlen(password); if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)){ err = 1; goto Exit; } if (!CryptImportKey(hProv, (BYTE*)kb, kbSize, 0, CRYPT_IPSEC_HMAC_KEY, &hKey)){ err = 1; goto Exit; } if (!CryptCreateHash(hProv, CALG_HMAC, hKey, 0, &hHmacHash)){ err = 1; goto Exit; } if (!CryptSetHashParam(hHmacHash, HP_HMAC_INFO, (BYTE*)&HmacInfo, 0)){ err = 1; goto Exit; } if (!CryptHashData(hHmacHash, (BYTE*)str, strlen(str), 0)){ err = 1; goto Exit; } if (!CryptGetHashParam(hHmacHash, HP_HASHVAL, pbHash, &dwDataLen, 0)){ err = 1; goto Exit; } ZeroMemory(res, dwDataLen * 2); char * temp; temp = new char[3]; ZeroMemory(temp, 3); for (unsigned int m = 0; m < dwDataLen; m++){ sprintf(temp, "%2x", pbHash[m]); if (temp [1] == ' ') temp [1] = '0'; // note these two: they are two CORRECTIONS to the conversion in HEX, sometimes the Zeros are if (temp [0] == ' ') temp [0] = '0'; // printed with a space, so we replace spaces with zeros; (this error occurs mainly in HMAC-SHA1) sprintf(res,"%s%s", res,temp); } delete [] temp; Exit: free(kb); if(hHmacHash) CryptDestroyHash(hHmacHash); if(hKey) CryptDestroyKey(hKey); if(hHash) CryptDestroyHash(hHash); if(hProv) CryptReleaseContext(hProv, 0); if (err == 1){ delete [] res; return ""; } return res; } #endif #ifdef AUTHLOGIN || AUTHPLAIN void initssl() { if (!ssl_init_count) { SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); } ++ssl_init_count; } void freessl() { if (!--ssl_init_count) { ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); } } void sslb64encode(const char* buffer, char* outbuffer) { char* b64str = NULL; BIO* b64 = BIO_new(BIO_f_base64()); BIO* mem = BIO_new(BIO_s_mem()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); b64 = BIO_push(b64, mem); BIO_write(b64, buffer, strlen(buffer)); BIO_flush(b64); int len = BIO_get_mem_data(mem, &b64str); memcpy(outbuffer, b64str, len); outbuffer[len] = '\0'; BIO_free_all(b64); } void initemail(const char* username, const char* password, email* outemail) { char ubuffer[256]; char pbuffer[256]; unsigned int bytes_written = 0; sslb64encode(username, &ubuffer[0]); sslb64encode(password, &pbuffer[0]); sprintf(outemail->b64username, "%s", ubuffer); sprintf(outemail->b64password, "%s", pbuffer); } #endif static int sendmail( const char *from, const char *passwordx, const char *to, const char *subject, const char *body, const char *hostname, const int port ) { #ifdef SSLX const char *serv = hostname; int err; int sd = 0; int read_size; struct sockaddr_in sa; SSL_CTX* ctx; SSL* ssl; X509* server_cert; char* str; char buf [PATH_MAX]; char server_reply[PATH_MAX]; const SSL_METHOD *meth; SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); meth = TLSv1_client_method(); ctx = SSL_CTX_new (meth); CHK_NULL(ctx); /* ----------------------------------------------- */ /* Load , Verify and use CERTF and KEYF for encrypt the connection */ if (!ctx) { fprintf(stdout,"There's NO Crypto Method choosen\n"); exit(2); } if (SSL_CTX_load_verify_locations(ctx,CERTF,HOME) <= 0) { fprintf(stdout,"Verify of the Cert FAILED!\n"); exit(3); } if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { fprintf(stdout,"PEM Cert File is NOT Valid\n"); exit(4); } if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { fprintf(stdout,"PEM CertKey File is NOT Valid\n"); exit(5); } if (!SSL_CTX_check_private_key(ctx)) { fprintf(stdout,"Private key does not match the certificate public key\n"); exit(6); } /* ----------------------------------------------- */ #ifdef WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { return -1; } #endif /* Create a socket and connect to server using normal socket calls. */ #ifdef LINUX #define SOCK_PATH "/tmp/socket-mailer" #endif //Create socket sd = socket(AF_INET , SOCK_STREAM , 0); if (sd == -1) { fprintf(stdout,"Could not create socket\n"); } CHK_ERR(sd, "socket"); fprintf(stdout,"Socket created\n"); memset(&sa, 0, sizeof(sa)); sa.sin_addr.s_addr = gethostbyname(serv); sa.sin_family = AF_INET; sa.sin_port = htons( port ); //Connect to remote server if ( err = connect(sd , (struct sockaddr *)&sa , sizeof(sa)) < 0) { fprintf(stdout,"connect failed. Error: %s\n",strerror(err)); return 1; } CHK_ERR(err, "connect"); fprintf(stdout,"Connected\n"); /* Now we have TCP conncetion. Start SSL negotiation. */ ssl = SSL_new(ctx); CHK_NULL(ssl); SSL_set_fd(ssl, sd); err = SSL_connect(ssl); CHK_SSL(err); /* Get the cipher - opt */ fprintf(stdout,"SSL connection using %s\n", SSL_get_cipher (ssl)); /* Get server's certificate (note: beware of dynamic allocation) - opt */ server_cert = SSL_get_peer_certificate (ssl); CHK_NULL(server_cert); fprintf(stdout,"Server certificate:\n"); str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0); CHK_NULL(str); fprintf(stdout,"\t subject: %s\n", str); OPENSSL_free (str); str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0); CHK_NULL(str); fprintf(stdout,"\t issuer: %s\n", str); OPENSSL_free (str); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ X509_free (server_cert); /* --------------------------------------------------- */ /* DATA EXCHANGE - Send a message and receive a reply. */ #endif #ifdef SSLN struct hostent *host; struct sockaddr_in saddr_in; int sock = 0; #ifdef WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { return -1; } #endif #ifdef LINUX #define SOCK_PATH "/tmp/socket-mailer" #endif char *err; sock = socket(AF_INET, SOCK_STREAM, 0); host = gethostbyname(hostname); saddr_in.sin_family = AF_INET; saddr_in.sin_port = htons((u_short)port); saddr_in.sin_addr.s_addr = 0; memcpy((char*)&(saddr_in.sin_addr), host->h_addr, host->h_length); if (err = connect(sock, (struct sockaddr*)&saddr_in, sizeof(saddr_in)) == -1) { return -2; } #endif #ifdef SSLX #ifdef AUTHLOGIN || AUTHPLAIN email em; char buffer[512]; unsigned int bufflen = sizeof(buffer); initemail(from, passwordx, &em); #endif while(read_size = SSL_read(ssl, server_reply, sizeof(server_reply) ) > 0){ sendmail_write(ssl, "HELO %s\r\n", from); // greeting #ifdef AUTHNO #endif #ifdef AUTHDMD5 #endif #ifdef AUTHCMD5 sendmail_write(ssl, "AUTH CRAM-MD5\r\n", NULL);// auth cmd5 char * hash_md5 = HMAC(from,passwordx,CALG_MD5); sendmail_write(ssl, "%s\r\n", hash_md5);// auth cmd5 #endif #ifdef AUTHPLAIN sendmail_write(ssl, "AUTH PLAIN %s\r\n", em.b64username);// auth plain sendmail_write(ssl, "%s\r\n", em.b64password);// auth plain #endif #ifdef AUTHLOGIN sendmail_write(ssl, "AUTH LOGIN\r\n", NULL); // auth login sendmail_write(ssl, "%s\r\n", em.b64username);// auth login sendmail_write(ssl, "%s\r\n", em.b64password);// auth login #endif sendmail_write(ssl, "MAIL FROM: %s\r\n", from); // from sendmail_write(ssl, "RCPT TO: %s\r\n", to); // to sendmail_write(ssl, "DATA\r\n", NULL); // begin data // next comes mail headers sendmail_write(ssl, "From: %s\r\n", from); sendmail_write(ssl, "To: %s\r\n", to); sendmail_write(ssl, "Subject: %s\r\n", subject); // next comes mail data sendmail_write(ssl, "\r\n", NULL); sendmail_write(ssl, " %s\r\n", body); // data sendmail_write(ssl, ".\r\n", NULL); // end data sendmail_write(ssl, "QUIT\r\n", NULL); // terminate if(read_size == 0) { fprintf(stdout,"Server disconnect's\n"); break; } else if(read_size == -1) { fprintf(stdout,"recv failed\n"); } } //while recv end SSL_shutdown(ssl); close(sd); SSL_free(ssl); SSL_CTX_free(ctx); #endif #ifdef SSLN #ifdef AUTHLOGIN || AUTHPLAIN email em; char buffer[512]; unsigned int bufflen = sizeof(buffer); initemail(from, passwordx, &em); #endif sendmail_write(sock, "HELO %s\r\n", from); // greeting #ifdef AUTHNO #endif #ifdef AUTHDMD5 #endif #ifdef AUTHCMD5 sendmail_write(sock, "AUTH CRAM-MD5\r\n", NULL);// auth cmd5 char * hash_md5 = HMAC(from,passwordx,CALG_MD5); sendmail_write(sock, "%s\r\n", hash_md5);// auth cmd5 #endif #ifdef AUTHPLAIN sendmail_write(sock, "AUTH PLAIN %s\r\n", em.b64username);// auth plain sendmail_write(sock, "%s\r\n", em.b64password);// auth plain #endif #ifdef AUTHLOGIN sendmail_write(sock, "AUTH LOGIN\r\n", NULL); // auth login sendmail_write(sock, "%s\r\n", em.b64username);// auth login sendmail_write(sock, "%s\r\n", em.b64password);// auth login #endif sendmail_write(sock, "MAIL FROM: %s\r\n", from); // from sendmail_write(sock, "RCPT TO: %s\r\n", to); // to sendmail_write(sock, "DATA\r\n", NULL); // begin data // next comes mail headers sendmail_write(sock, "From: %s\r\n", from); sendmail_write(sock, "To: %s\r\n", to); sendmail_write(sock, "Subject: %s\r\n", subject); // next comes mail data sendmail_write(sock, "\r\n", NULL); sendmail_write(sock, " %s\r\n", body); // data sendmail_write(sock, ".\r\n", NULL); // end data sendmail_write(sock, "QUIT\r\n", NULL); // terminate close(sock); #endif return 0; } int main(int argc, char *argv[]) { //freopen( "Smiril-mailer-error.log", "a+", stdout ); fprintf(stdout,"%s\n",Versionx()); int ret = sendmail( argv[1], /* from */ argv[2], /* password */ argv[3], /* to */ argv[4], /* subject */ argv[5], /* body */ argv[6], /* hostname */ atoi(argv[7]) /* port */ ); if (ret != 0) fprintf(stdout, "Failed to send mail (code: %i).\n", ret); else fprintf(stdout, "Mail successfully sent (code: 0).\n"); //fclose (stdout); return ret; }