854
/* for AUTH DIGEST-MD5 challenge responses */
855
static CURLcode smtp_state_authdigest_resp(struct connectdata *conn,
859
static const char table16[] = "0123456789abcdef";
861
CURLcode result = CURLE_OK;
862
struct SessionHandle *data = conn->data;
863
char *chlg64 = data->state.buffer;
868
char *rplyb64 = NULL;
870
unsigned char digest[MD5_DIGEST_LEN];
871
char HA1_hex[2 * MD5_DIGEST_LEN + 1];
872
char HA2_hex[2 * MD5_DIGEST_LEN + 1];
873
char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
878
char nonceCount[] = "00000001";
879
char cnonce[] = "12345678"; /* will be changed */
880
char method[] = "AUTHENTICATE";
882
char uri[128] = "smtp/";
885
(void)instate; /* no use for this yet */
887
if(smtpcode != 334) {
888
failf(data, "Access denied: %d", smtpcode);
889
return CURLE_LOGIN_DENIED;
892
/* Get the challenge */
893
for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
896
chlg = (unsigned char *) NULL;
899
result = Curl_base64_decode(chlg64, &chlg, &chlglen);
904
/* Retrieve nonce string from the challenge */
905
if(!smtp_digest_get_key_value(chlg, "nonce=\"", nonce,
906
sizeof(nonce), '\"')) {
908
return CURLE_LOGIN_DENIED;
911
/* Retrieve realm string from the challenge */
912
if(!smtp_digest_get_key_value(chlg, "realm=\"", realm,
913
sizeof(realm), '\"')) {
914
/* Challenge does not have a realm, set empty string [RFC2831] page 6 */
918
/* Retrieve algorithm string from the challenge */
919
if(!smtp_digest_get_key_value(chlg, "algorithm=", alg, sizeof(alg), ',')) {
921
return CURLE_LOGIN_DENIED;
926
/* We do not support other algorithms */
927
if(strcmp(alg, "md5-sess") != 0)
928
return CURLE_LOGIN_DENIED;
930
/* Generate 64 bits of random data */
931
for(i = 0; i < 8; i++)
932
cnonce[i] = table16[Curl_rand()%16];
934
/* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
935
ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
937
return CURLE_OUT_OF_MEMORY;
939
Curl_MD5_update(ctxt, (const unsigned char *) conn->user,
940
curlx_uztoui(strlen(conn->user)));
941
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
942
Curl_MD5_update(ctxt, (const unsigned char *) realm,
943
curlx_uztoui(strlen(realm)));
944
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
945
Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
946
curlx_uztoui(strlen(conn->passwd)));
947
Curl_MD5_final(ctxt, digest);
949
ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
951
return CURLE_OUT_OF_MEMORY;
953
Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
954
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
955
Curl_MD5_update(ctxt, (const unsigned char *) nonce,
956
curlx_uztoui(strlen(nonce)));
957
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
958
Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
959
curlx_uztoui(strlen(cnonce)));
960
Curl_MD5_final(ctxt, digest);
962
/* Convert calculated 16 octet hex into 32 bytes string */
963
for(i = 0; i < MD5_DIGEST_LEN; i++)
964
snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
966
/* Orepare URL string, append realm to the protocol */
969
/* Calculate H(A2) */
970
ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
972
return CURLE_OUT_OF_MEMORY;
974
Curl_MD5_update(ctxt, (const unsigned char *) method,
975
curlx_uztoui(strlen(method)));
976
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
977
Curl_MD5_update(ctxt, (const unsigned char *) uri,
978
curlx_uztoui(strlen(uri)));
979
Curl_MD5_final(ctxt, digest);
981
for(i = 0; i < MD5_DIGEST_LEN; i++)
982
snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
984
/* Now calculate the response hash */
985
ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
987
return CURLE_OUT_OF_MEMORY;
989
Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
990
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
991
Curl_MD5_update(ctxt, (const unsigned char *) nonce,
992
curlx_uztoui(strlen(nonce)));
993
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
995
Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
996
curlx_uztoui(strlen(nonceCount)));
997
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
998
Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
999
curlx_uztoui(strlen(cnonce)));
1000
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
1001
Curl_MD5_update(ctxt, (const unsigned char *) qop,
1002
curlx_uztoui(strlen(qop)));
1003
Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
1005
Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
1006
Curl_MD5_final(ctxt, digest);
1008
for(i = 0; i < MD5_DIGEST_LEN; i++)
1009
snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
1011
strcpy(response, "username=\"");
1012
strcat(response, conn->user);
1013
strcat(response, "\",realm=\"");
1014
strcat(response, realm);
1015
strcat(response, "\",nonce=\"");
1016
strcat(response, nonce);
1017
strcat(response, "\",cnonce=\"");
1018
strcat(response, cnonce);
1019
strcat(response, "\",nc=");
1020
strcat(response, nonceCount);
1021
strcat(response, ",digest-uri=\"");
1022
strcat(response, uri);
1023
strcat(response, "\",response=");
1024
strcat(response, resp_hash_hex);
1026
/* Encode it to base64 and send it */
1027
result = Curl_base64_encode(data, response, 0, &rplyb64, &len);
1031
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
1034
state(conn, SMTP_AUTHDIGESTMD5_RESP);
1037
Curl_safefree(rplyb64);
1043
/* For AUTH DIGEST-MD5 challenge-response responses */
1044
static CURLcode smtp_state_authdigest_resp_resp(struct connectdata *conn,
1048
CURLcode result = CURLE_OK;
1049
struct SessionHandle *data = conn->data;
1051
(void)instate; /* no use for this yet */
1053
if(smtpcode != 334) {
1054
failf(data, "Authentication failed: %d", smtpcode);
1055
result = CURLE_LOGIN_DENIED;
1058
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "");
1061
state(conn, SMTP_AUTH);
801
/* for the AUTH NTLM (without initial response) response. */
1070
/* for the AUTH NTLM (without initial response) response */
802
1071
static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn,
804
1073
smtpstate instate)