bool _mongoc_cyrus_new_from_cluster (mongoc_cyrus_t *sasl, mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *hostname, bson_error_t *error) { const char *mechanism; char real_name[BSON_HOST_NAME_MAX + 1]; _mongoc_cyrus_init (sasl); mechanism = mongoc_uri_get_auth_mechanism (cluster->uri); if (!mechanism) { mechanism = "GSSAPI"; } if (!_mongoc_cyrus_set_mechanism (sasl, mechanism, error)) { _mongoc_cyrus_destroy (sasl); return false; } _mongoc_sasl_set_pass ((mongoc_sasl_t *) sasl, mongoc_uri_get_password (cluster->uri)); _mongoc_sasl_set_user ((mongoc_sasl_t *) sasl, mongoc_uri_get_username (cluster->uri)); _mongoc_sasl_set_properties ((mongoc_sasl_t *) sasl, cluster->uri); /* * If the URI requested canonicalizeHostname, we need to resolve the real * hostname for the IP Address and pass that to the SASL layer. Some * underlying GSSAPI layers will do this for us, but can be disabled in * their config (krb.conf). * * This allows the consumer to specify canonicalizeHostname=true in the URI * and have us do that for them. * * See CDRIVER-323 for more information. */ if (sasl->credentials.canonicalize_host_name && _mongoc_sasl_get_canonicalized_name ( stream, real_name, sizeof real_name)) { _mongoc_sasl_set_service_host ((mongoc_sasl_t *) sasl, real_name); } else { _mongoc_sasl_set_service_host ((mongoc_sasl_t *) sasl, hostname); } return true; }
bool _mongoc_cluster_auth_node_cyrus (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { mongoc_cmd_parts_t parts; uint32_t buflen = 0; mongoc_cyrus_t sasl; bson_iter_t iter; bool ret = false; const char *tmpstr; uint8_t buf[4096] = {0}; bson_t cmd; bson_t reply; int conv_id = 0; mongoc_server_stream_t *server_stream; BSON_ASSERT (cluster); BSON_ASSERT (stream); if (!_mongoc_cyrus_new_from_cluster ( &sasl, cluster, stream, sd->host.host, error)) { return false; } for (;;) { mongoc_cmd_parts_init ( &parts, cluster->client, "$external", MONGOC_QUERY_SLAVE_OK, &cmd); if (!_mongoc_cyrus_step ( &sasl, buf, buflen, buf, sizeof buf, &buflen, error)) { goto failure; } bson_init (&cmd); if (sasl.step == 1) { _mongoc_cluster_build_sasl_start ( &cmd, sasl.credentials.mechanism, (const char *) buf, buflen); } else { _mongoc_cluster_build_sasl_continue ( &cmd, conv_id, (const char *) buf, buflen); } TRACE ("SASL: authenticating (step %d)", sasl.step); server_stream = _mongoc_cluster_create_server_stream ( cluster->client->topology, sd->id, stream, error); if (!mongoc_cmd_parts_assemble (&parts, server_stream, error)) { mongoc_server_stream_cleanup (server_stream); bson_destroy (&cmd); goto failure; } if (!mongoc_cluster_run_command_private ( cluster, &parts.assembled, &reply, error)) { mongoc_server_stream_cleanup (server_stream); bson_destroy (&cmd); bson_destroy (&reply); goto failure; } mongoc_server_stream_cleanup (server_stream); bson_destroy (&cmd); if (bson_iter_init_find (&iter, &reply, "done") && bson_iter_as_bool (&iter)) { bson_destroy (&reply); break; } conv_id = _mongoc_cluster_get_conversation_id (&reply); if (!bson_iter_init_find (&iter, &reply, "payload") || !BSON_ITER_HOLDS_UTF8 (&iter)) { MONGOC_DEBUG ("SASL: authentication failed"); bson_destroy (&reply); bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Received invalid SASL reply from MongoDB server."); goto failure; } tmpstr = bson_iter_utf8 (&iter, &buflen); if (buflen > sizeof buf) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SASL reply from MongoDB is too large."); bson_destroy (&reply); goto failure; } memcpy (buf, tmpstr, buflen); bson_destroy (&reply); mongoc_cmd_parts_cleanup (&parts); } TRACE ("%s", "SASL: authenticated"); ret = true; failure: _mongoc_cyrus_destroy (&sasl); mongoc_cmd_parts_cleanup (&parts); return ret; }