Exemplo n.º 1
0
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;
}