- /*
- * If we got an initial challenge, send it as part of the AUTH
- * command; otherwise, just send a plain AUTH command.
- */
-
- if (buflen) {
- status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
- if (status != SASL_OK) {
- sm_ierror("SASL base64 encode failed: %s",
- sasl_errstring(status, NULL, NULL));
- return NOTOK;
- }
-
- status = smtalk(SM_AUTH, "AUTH %s %s", chosen_mech, outbuf);
- } else
- status = smtalk(SM_AUTH, "AUTH %s", chosen_mech);
-
- /*
- * Now we loop until we either fail, get a SASL_OK, or a 235
- * response code. Receive the challenges and process them until
- * we're all done.
- */
-
- while (result == SASL_CONTINUE) {
-
- /*
- * If we get a 235 response, that means authentication has
- * succeeded and we need to break out of the loop (yes, even if
- * we still get SASL_CONTINUE from sasl_client_step()).
- *
- * Otherwise, if we get a message that doesn't seem to be a
- * valid response, then abort
- */
-
- if (status == 235)
- break;
- else if (status < 300 || status > 399)
- return RP_BHST;
-
- /*
- * Special case; a zero-length response from the SMTP server
- * is returned as a single =. If we get that, then set buflen
- * to be zero. Otherwise, just decode the response.
- */
-
- if (strcmp("=", sm_reply.text) == 0) {
- outlen = 0;
- } else {
- result = sasl_decode64(sm_reply.text, sm_reply.length,
- outbuf, sizeof(outbuf), &outlen);
-
- if (result != SASL_OK) {
- smtalk(SM_AUTH, "*");
- sm_ierror("SASL base64 decode failed: %s",
- sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
- }
-
- result = sasl_client_step(conn, outbuf, outlen, NULL,
- (const char **) &buf, &buflen);
-
- if (result != SASL_OK && result != SASL_CONTINUE) {
- smtalk(SM_AUTH, "*");
- sm_ierror("SASL client negotiation failed: %s",
- sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
-
- if (status != SASL_OK) {
- smtalk(SM_AUTH, "*");
- sm_ierror("SASL base64 encode failed: %s",
- sasl_errstring(status, NULL, NULL));
- return NOTOK;
- }
-
- status = smtalk(SM_AUTH, outbuf);
- }
-
- /*
- * Make sure that we got the correct response
- */
-
- if (status < 200 || status > 299)
- return RP_BHST;
-
- /*
- * We _should_ have completed the authentication successfully.
- * Get a few properties from the authentication exchange.
- */
-
- result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &outbufmax);
-
- if (result != SASL_OK) {
- sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
- sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- maxoutbuf = *outbufmax;
-
- result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf);
-
- sasl_ssf = *ssf;
-
- if (result != SASL_OK) {
- sm_ierror("Cannot retrieve SASL negotiated security strength "
- "factor: %s", sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- if (sasl_ssf > 0) {
- sasl_outbuffer = malloc(maxoutbuf);
-
- if (sasl_outbuffer == NULL) {
- sm_ierror("Unable to allocate %d bytes for SASL output "
- "buffer", maxoutbuf);
- return NOTOK;
- }
- sasl_outbuflen = 0;
- sasl_inbuflen = 0;
- sasl_inptr = sasl_inbuffer;
- } else {
- sasl_outbuffer = NULL;
- /* Don't NULL out sasl_inbuffer because it could be used in
- sm_fgetc (). */
- }
-
- sasl_complete = 1;
-
- return RP_OK;