/*********************************************************************** * * smtp_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL * authentication mechanism. */ static CURLcode smtp_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; saslprogress progress; /* Check we have enough data to authenticate with, and the server supports authentiation, and end the connect phase if not */ if(!smtpc->auth_supported || !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { state(conn, SMTP_STOP); return result; } /* Calculate the SASL login details */ result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress); if(!result) { if(progress == SASL_INPROGRESS) state(conn, SMTP_AUTH); else { /* Other mechanisms not supported */ infof(conn->data, "No known authentication mechanisms supported!\n"); result = CURLE_LOGIN_DENIED; } } return result; }
/*********************************************************************** * * pop3_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL * authentication mechanism, falling back to APOP and clear text should a * common mechanism not be available between the client and server. */ static CURLcode pop3_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; saslprogress progress = SASL_IDLE; /* Check we have enough data to authenticate with and end the connect phase if we don't */ if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) { state(conn, POP3_STOP); return result; } if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { /* Calculate the SASL login details */ result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); if(!result) if(progress == SASL_INPROGRESS) state(conn, POP3_AUTH); } if(!result && progress == SASL_IDLE) { #ifndef CURL_DISABLE_CRYPTO_AUTH if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) /* Perform APOP authentication */ result = pop3_perform_apop(conn); else #endif if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) /* Perform clear text authentication */ result = pop3_perform_user(conn); else { /* Other mechanisms not supported */ infof(conn->data, "No known authentication mechanisms supported!\n"); result = CURLE_LOGIN_DENIED; } } return result; }
/* * Curl_sasl_continue() * * Continue the authentication. */ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, int code, saslprogress *progress) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; saslstate newstate = SASL_FINAL; char *resp = NULL; #if !defined(CURL_DISABLE_CRYPTO_AUTH) char *serverdata; char *chlg = NULL; size_t chlglen = 0; #endif size_t len = 0; *progress = SASL_INPROGRESS; if(sasl->state == SASL_FINAL) { if(code != sasl->params->finalcode) result = CURLE_LOGIN_DENIED; *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return result; } if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP && code != sasl->params->contcode) { *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return CURLE_LOGIN_DENIED; } switch(sasl->state) { case SASL_STOP: *progress = SASL_DONE; return result; case SASL_PLAIN: result = Curl_auth_create_plain_message(data, conn->user, conn->passwd, &resp, &len); break; case SASL_LOGIN: result = Curl_auth_create_login_message(data, conn->user, &resp, &len); newstate = SASL_LOGIN_PASSWD; break; case SASL_LOGIN_PASSWD: result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len); break; case SASL_EXTERNAL: result = Curl_auth_create_external_message(data, conn->user, &resp, &len); break; #ifndef CURL_DISABLE_CRYPTO_AUTH case SASL_CRAMMD5: sasl->params->getmessage(data->state.buffer, &serverdata); result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen); if(!result) result = Curl_auth_create_cram_md5_message(data, chlg, conn->user, conn->passwd, &resp, &len); free(chlg); break; case SASL_DIGESTMD5: sasl->params->getmessage(data->state.buffer, &serverdata); result = Curl_auth_create_digest_md5_message(data, serverdata, conn->user, conn->passwd, sasl->params->service, &resp, &len); newstate = SASL_DIGESTMD5_RESP; break; case SASL_DIGESTMD5_RESP: resp = strdup(""); if(!resp) result = CURLE_OUT_OF_MEMORY; break; #endif #ifdef USE_NTLM case SASL_NTLM: /* Create the type-1 message */ result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd, &conn->ntlm, &resp, &len); newstate = SASL_NTLM_TYPE2MSG; break; case SASL_NTLM_TYPE2MSG: /* Decode the type-2 message */ sasl->params->getmessage(data->state.buffer, &serverdata); result = Curl_auth_decode_ntlm_type2_message(data, serverdata, &conn->ntlm); if(!result) result = Curl_auth_create_ntlm_type3_message(data, conn->user, conn->passwd, &conn->ntlm, &resp, &len); break; #endif #if defined(USE_KERBEROS5) case SASL_GSSAPI: result = Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, sasl->params->service, data->easy_conn->host.name, sasl->mutual_auth, NULL, &conn->krb5, &resp, &len); newstate = SASL_GSSAPI_TOKEN; break; case SASL_GSSAPI_TOKEN: sasl->params->getmessage(data->state.buffer, &serverdata); if(sasl->mutual_auth) { /* Decode the user token challenge and create the optional response message */ result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, NULL, NULL, sasl->mutual_auth, serverdata, &conn->krb5, &resp, &len); newstate = SASL_GSSAPI_NO_DATA; } else /* Decode the security challenge and create the response message */ result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; case SASL_GSSAPI_NO_DATA: sasl->params->getmessage(data->state.buffer, &serverdata); /* Decode the security challenge and create the response message */ result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; #endif case SASL_OAUTH2: /* Create the authorisation message */ if(sasl->authused == SASL_MECH_OAUTHBEARER) { result = Curl_auth_create_oauth_bearer_message(data, conn->user, conn->host.name, conn->port, conn->oauth_bearer, &resp, &len); /* Failures maybe sent by the server as continuations for OAUTHBEARER */ newstate = SASL_OAUTH2_RESP; } else result = Curl_auth_create_oauth_bearer_message(data, conn->user, NULL, 0, conn->oauth_bearer, &resp, &len); break; case SASL_OAUTH2_RESP: /* The continuation is optional so check the response code */ if(code == sasl->params->finalcode) { /* Final response was received so we are done */ *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return result; } else if(code == sasl->params->contcode) { /* Acknowledge the continuation by sending a 0x01 response base64 encoded */ resp = strdup("AQ=="); if(!resp) result = CURLE_OUT_OF_MEMORY; break; } else { *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return CURLE_LOGIN_DENIED; } case SASL_CANCEL: /* Remove the offending mechanism from the supported list */ sasl->authmechs ^= sasl->authused; /* Start an alternative SASL authentication */ result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress); newstate = sasl->state; /* Use state from Curl_sasl_start() */ break; default: failf(data, "Unsupported SASL authentication mechanism"); result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ break; } switch(result) { case CURLE_BAD_CONTENT_ENCODING: /* Cancel dialog */ result = sasl->params->sendcont(conn, "*"); newstate = SASL_CANCEL; break; case CURLE_OK: if(resp) result = sasl->params->sendcont(conn, resp); break; default: newstate = SASL_STOP; /* Stop on error */ *progress = SASL_DONE; break; } free(resp); state(sasl, conn, newstate); return result; }