- strncpy(host, inhost, sizeof(host) - 1);
- }
-
- sasl_pw_context[0] = host;
- sasl_pw_context[1] = user;
-
- callbacks[SM_SASL_N_CB_PASS].context = sasl_pw_context;
-
- result = sasl_client_init(callbacks);
-
- if (result != SASL_OK) {
- sm_ierror("SASL library initialization failed: %s",
- sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- result = sasl_client_new("smtp", host, NULL, NULL, NULL, 0, &conn);
-
- if (result != SASL_OK) {
- sm_ierror("SASL client initialization failed: %s",
- sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- /*
- * Initialize the security properties. But if TLS is active, then
- * don't negotiate encryption here.
- */
-
- memset(&secprops, 0, sizeof(secprops));
- secprops.maxbufsize = SASL_MAXRECVBUF;
- secprops.max_ssf = tls_active ? 0 : UINT_MAX;
-
- result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
-
- if (result != SASL_OK) {
- sm_ierror("SASL security property initialization failed: %s",
- sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- /*
- * Start the actual protocol. Feed the mech list into the library
- * and get out a possible initial challenge
- */
-
- result = sasl_client_start(conn, mechlist, NULL, (const char **) &buf,
- &buflen, (const char **) &chosen_mech);
-
- if (result != SASL_OK && result != SASL_CONTINUE) {
- sm_ierror("SASL client start failed: %s", sasl_errdetail(conn));
- return NOTOK;
- }
-
- /*
- * 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);