bool CyrusSasl::start()

in src/qpid/SaslFactory.cpp [245:330]


bool CyrusSasl::start(const std::string& mechanisms, std::string& response, const SecuritySettings* externalSettings)
{
    QPID_LOG(debug, "CyrusSasl::start(" << mechanisms << ")");
    int result = sasl_client_new(settings.service.c_str(),
                                 settings.host.c_str(),
                                 0, 0, /* Local and remote IP address strings */
                                 callbacks,
                                 0,          /* security flags */
                                 &conn);
    
    if (result != SASL_OK) throw InternalErrorException(QPID_MSG("Sasl error: " << sasl_errdetail(conn)));

    sasl_security_properties_t secprops;

    if (externalSettings) {
        sasl_ssf_t external_ssf = (sasl_ssf_t) externalSettings->ssf;
        if (external_ssf) {
            int result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &external_ssf);
            if (result != SASL_OK) {
                throw framing::InternalErrorException(QPID_MSG("SASL error: unable to set external SSF: " << result));
            }
            QPID_LOG(debug, "external SSF detected and set to " << external_ssf);
        }
        if (externalSettings->authid.size()) {
            const char* external_authid = externalSettings->authid.c_str();
            result = sasl_setprop(conn, SASL_AUTH_EXTERNAL, external_authid);
            if (result != SASL_OK) {
                throw framing::InternalErrorException(QPID_MSG("SASL error: unable to set external auth: " << result));
            }
            QPID_LOG(debug, "external auth detected and set to " << external_authid);
        }
    }

    secprops.min_ssf = settings.minSsf;
    secprops.max_ssf = settings.maxSsf;
    secprops.maxbufsize = 65535;

    QPID_LOG(debug, "min_ssf: " << secprops.min_ssf << ", max_ssf: " << secprops.max_ssf);

    secprops.property_names = 0;
    secprops.property_values = 0;
    secprops.security_flags = 0;//TODO: provide means for application to configure these

    result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
    if (result != SASL_OK) {
        throw framing::InternalErrorException(QPID_MSG("SASL error: " << sasl_errdetail(conn)));
    }

    sasl_interact_t* client_interact = 0;
    const char *out = 0;
    unsigned outlen = 0;
    const char *chosenMechanism = 0;

    do {        
        result = sasl_client_start(conn,
                                   mechanisms.c_str(),
                                   &client_interact,
                                   &out,
                                   &outlen,
                                   &chosenMechanism);
        
        if (result == SASL_INTERACT) {
            interact(client_interact);
        }        
    } while (result == SASL_INTERACT);

    if (result == SASL_NOMECH) {
        if (mechanisms.size()) {
            throw qpid::Exception(std::string("Can't authenticate using ") + mechanisms);
        } else {
            throw qpid::Exception("No mutually acceptable authentication mechanism");
        }
    } else if (result != SASL_CONTINUE && result != SASL_OK) {
        throw InternalErrorException(QPID_MSG("Sasl error: " << sasl_errdetail(conn)));
    }

    mechanism = std::string(chosenMechanism);
    QPID_LOG(debug, "CyrusSasl::start(" << mechanisms << "): selected "
             << mechanism << " response: '" << std::string(out, outlen) << "'");
    if (out) {
        response = std::string(out, outlen);
        return true;
    } else {
        return false;
    }
}