Example #1
0
bson_bool_t
_mongoc_sasl_step (mongoc_sasl_t      *sasl,
                   const bson_uint8_t *inbuf,
                   bson_uint32_t       inbuflen,
                   bson_uint8_t       *outbuf,
                   bson_uint32_t       outbufmax,
                   bson_uint32_t      *outbuflen,
                   bson_error_t       *error)
{
   const char *raw = NULL;
   unsigned rawlen = 0;
   int status;

   BSON_ASSERT (sasl);
   BSON_ASSERT (inbuf);
   BSON_ASSERT (outbuf);
   BSON_ASSERT (outbuflen);
   BSON_ASSERT (*outbuflen);

   sasl->step++;

   if (sasl->step == 1) {
      return _mongoc_sasl_start (sasl, outbuf, outbufmax, outbuflen,
                                 error);
   } else if (sasl->step >= 10) {
      bson_set_error (error,
                      MONGOC_ERROR_SASL,
                      SASL_NOTDONE,
                      "SASL Failure: maximum steps detected");
      return FALSE;
   }

   if (!inbuflen) {
      bson_set_error (error,
                      MONGOC_ERROR_SASL,
                      MONGOC_ERROR_CLIENT_AUTHENTICATE,
                      "SASL Failure: no payload provided from server.");
      return FALSE;
   }

   status = sasl_decode64 ((char *)inbuf, inbuflen, (char *)outbuf, outbufmax,
                           outbuflen);
   if (_mongoc_sasl_is_failure (status, error)) {
      return FALSE;
   }

   status = sasl_client_step (sasl->conn, (char *)outbuf, *outbuflen,
                              &sasl->interact, &raw, &rawlen);
   if (_mongoc_sasl_is_failure (status, error)) {
      return FALSE;
   }

   status = sasl_encode64 (raw, rawlen, (char *)outbuf, outbufmax, outbuflen);
   if (_mongoc_sasl_is_failure (status, error)) {
      return FALSE;
   }

   return TRUE;
}
Example #2
0
static bool
_mongoc_cursor_unwrap_failure (mongoc_cursor_t *cursor)
{
   bson_iter_t iter;
   bson_t b;

   ENTRY;

   bson_return_val_if_fail(cursor, false);

   if (cursor->rpc.header.opcode != MONGOC_OPCODE_REPLY) {
      bson_set_error(&cursor->error,
                     MONGOC_ERROR_PROTOCOL,
                     MONGOC_ERROR_PROTOCOL_INVALID_REPLY,
                     "Received rpc other than OP_REPLY.");
      RETURN(true);
   }

   if ((cursor->rpc.reply.flags & MONGOC_REPLY_QUERY_FAILURE)) {
      if (_mongoc_rpc_reply_get_first(&cursor->rpc.reply, &b)) {
         _mongoc_cursor_populate_error(cursor, &b, &cursor->error);
         bson_destroy(&b);
      } else {
         bson_set_error(&cursor->error,
                        MONGOC_ERROR_QUERY,
                        MONGOC_ERROR_QUERY_FAILURE,
                        "Unknown query failure.");
      }
      RETURN(true);
   } else if (cursor->is_command) {
      if (_mongoc_rpc_reply_get_first (&cursor->rpc.reply, &b)) {
         if (bson_iter_init_find (&iter, &b, "ok")) {
            if (bson_iter_as_bool (&iter)) {
               RETURN (false);
            } else {
               _mongoc_cursor_populate_error (cursor, &b, &cursor->error);
               bson_destroy (&b);
               RETURN (true);
            }
         }
      } else {
         bson_set_error (&cursor->error,
                         MONGOC_ERROR_BSON,
                         MONGOC_ERROR_BSON_INVALID,
                         "Failed to decode document from the server.");
         RETURN (true);
      }
   }

   if ((cursor->rpc.reply.flags & MONGOC_REPLY_CURSOR_NOT_FOUND)) {
      bson_set_error(&cursor->error,
                     MONGOC_ERROR_CURSOR,
                     MONGOC_ERROR_CURSOR_INVALID_CURSOR,
                     "The cursor is invalid or has expired.");
      RETURN(true);
   }

   RETURN(false);
}
Example #3
0
/* returns true if the reply is a server error */
static bool
_mongoc_rpc_parse_error (mongoc_rpc_t *rpc,
                         bool          is_command,
                         int32_t       error_api_version,
                         bson_error_t *error /* OUT */)
{
   bson_t b;
   bool r;

   ENTRY;

   BSON_ASSERT (rpc);

   if (rpc->header.opcode != MONGOC_OPCODE_REPLY) {
      bson_set_error(error,
                     MONGOC_ERROR_PROTOCOL,
                     MONGOC_ERROR_PROTOCOL_INVALID_REPLY,
                     "Received rpc other than OP_REPLY.");
      RETURN(true);
   }

   if (is_command) {
      if (_mongoc_rpc_reply_get_first (&rpc->reply, &b)) {
         r = _mongoc_populate_cmd_error (&b, error_api_version, error);
         bson_destroy(&b);
         RETURN (r);
      } else {
         bson_set_error (error,
                         MONGOC_ERROR_BSON,
                         MONGOC_ERROR_BSON_INVALID,
                         "Failed to decode document from the server.");
         RETURN (true);
      }
   } else if ((rpc->reply.flags & MONGOC_REPLY_QUERY_FAILURE)) {
      if (_mongoc_rpc_reply_get_first (&rpc->reply, &b)) {
         _mongoc_populate_query_error (&b, error_api_version, error);
         bson_destroy (&b);
      } else {
         bson_set_error (error,
                         MONGOC_ERROR_QUERY,
                         MONGOC_ERROR_QUERY_FAILURE,
                         "Unknown query failure.");
      }

      RETURN (true);
   }

   if ((rpc->reply.flags & MONGOC_REPLY_CURSOR_NOT_FOUND)) {
      bson_set_error(error,
                     MONGOC_ERROR_CURSOR,
                     MONGOC_ERROR_CURSOR_INVALID_CURSOR,
                     "The cursor is invalid or has expired.");
      RETURN(true);
   }

   RETURN(false);
}
Example #4
0
static bool
_mongoc_cyrus_is_failure (int status, bson_error_t *error)
{
   bool ret = (status < 0);

   TRACE ("Got status: %d ok is %d, continue=%d interact=%d\n",
          status,
          SASL_OK,
          SASL_CONTINUE,
          SASL_INTERACT);
   if (ret) {
      switch (status) {
      case SASL_NOMEM:
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "SASL Failure: insufficient memory.");
         break;
      case SASL_NOMECH: {
         bson_string_t *str = bson_string_new ("available mechanisms: ");
         const char **mechs = sasl_global_listmech ();
         int i = 0;

         for (i = 0; mechs[i]; i++) {
            bson_string_append (str, mechs[i]);
            if (mechs[i + 1]) {
               bson_string_append (str, ",");
            }
         }
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "SASL Failure: failure to negotiate mechanism (%s)",
                         str->str);
         bson_string_free (str, 0);
      } break;
      case SASL_BADPARAM:
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "Bad parameter supplied. Please file a bug "
                         "with mongo-c-driver.");
         break;
      default:
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "SASL Failure: (%d): %s",
                         status,
                         sasl_errstring (status, NULL, NULL));
         break;
      }
   }

   return ret;
}
Example #5
0
static mongoc_stream_t *
mongoc_client_connect_unix (const mongoc_uri_t       *uri,
                            const mongoc_host_list_t *host,
                            bson_error_t             *error)
{
#ifdef _WIN32
   ENTRY;
   bson_set_error (error,
                   MONGOC_ERROR_STREAM,
                   MONGOC_ERROR_STREAM_CONNECT,
                   "UNIX domain sockets not supported on win32.");
   RETURN (NULL);
#else
   struct sockaddr_un saddr;
   mongoc_socket_t *sock;
   mongoc_stream_t *ret = NULL;

   ENTRY;

   bson_return_val_if_fail (uri, NULL);
   bson_return_val_if_fail (host, NULL);

   memset (&saddr, 0, sizeof saddr);
   saddr.sun_family = AF_UNIX;
   bson_snprintf (saddr.sun_path, sizeof saddr.sun_path - 1,
                  "%s", host->host_and_port);

   sock = mongoc_socket_new (AF_UNIX, SOCK_STREAM, 0);

   if (sock == NULL) {
      bson_set_error (error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_SOCKET,
                      "Failed to create socket.");
      RETURN (NULL);
   }

   if (-1 == mongoc_socket_connect (sock,
                                    (struct sockaddr *)&saddr,
                                    sizeof saddr,
                                    -1)) {
      mongoc_socket_destroy (sock);
      bson_set_error (error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_CONNECT,
                      "Failed to connect to UNIX domain socket.");
      RETURN (NULL);
   }

   ret = mongoc_stream_socket_new (sock);

   RETURN (ret);
#endif
}
Example #6
0
bool
_mongoc_stream_writev_full (mongoc_stream_t *stream,
                            mongoc_iovec_t *iov,
                            size_t iovcnt,
                            int32_t timeout_msec,
                            bson_error_t *error)
{
   size_t total_bytes = 0;
   int i;
   ssize_t r;
   ENTRY;

   for (i = 0; i < iovcnt; i++) {
      total_bytes += iov[i].iov_len;
   }

   r = mongoc_stream_writev (stream, iov, iovcnt, timeout_msec);
   TRACE ("writev returned: %ld", r);

   if (r < 0) {
      if (error) {
         char buf[128];
         char *errstr;

         errstr = bson_strerror_r (errno, buf, sizeof (buf));

         bson_set_error (error,
                         MONGOC_ERROR_STREAM,
                         MONGOC_ERROR_STREAM_SOCKET,
                         "Failure during socket delivery: %s (%d)",
                         errstr,
                         errno);
      }

      RETURN (false);
   }

   if (r != total_bytes) {
      bson_set_error (error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_SOCKET,
                      "Failure to send all requested bytes (only sent: %" PRIu64
                      "/%" PRId64 " in %dms) during socket delivery",
                      (uint64_t) r,
                      (int64_t) total_bytes,
                      timeout_msec);

      RETURN (false);
   }

   RETURN (true);
}
Example #7
0
mongoc_async_cmd_result_t
_mongoc_async_cmd_phase_recv_len (mongoc_async_cmd_t *acmd)
{
   ssize_t bytes = _mongoc_buffer_try_append_from_stream (
      &acmd->buffer, acmd->stream, acmd->bytes_to_read, 0);
   uint32_t msg_len;

   if (bytes <= 0 && mongoc_stream_should_retry (acmd->stream)) {
      return MONGOC_ASYNC_CMD_IN_PROGRESS;
   }

   if (bytes < 0) {
      bson_set_error (&acmd->error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_SOCKET,
                      "Failed to receive length header from server.");
      return MONGOC_ASYNC_CMD_ERROR;
   }

   if (bytes == 0) {
      bson_set_error (&acmd->error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_SOCKET,
                      "Server closed connection.");
      return MONGOC_ASYNC_CMD_ERROR;
   }

   acmd->bytes_to_read = (size_t) (acmd->bytes_to_read - bytes);

   if (!acmd->bytes_to_read) {
      memcpy (&msg_len, acmd->buffer.data, 4);
      msg_len = BSON_UINT32_FROM_LE (msg_len);

      if (msg_len < 16 || msg_len > MONGOC_DEFAULT_MAX_MSG_SIZE ||
          msg_len < acmd->buffer.len) {
         bson_set_error (&acmd->error,
                         MONGOC_ERROR_PROTOCOL,
                         MONGOC_ERROR_PROTOCOL_INVALID_REPLY,
                         "Invalid reply from server.");
         return MONGOC_ASYNC_CMD_ERROR;
      }

      acmd->bytes_to_read = msg_len - acmd->buffer.len;
      acmd->state = MONGOC_ASYNC_CMD_RECV_RPC;

      return _mongoc_async_cmd_phase_recv_rpc (acmd);
   }

   return MONGOC_ASYNC_CMD_IN_PROGRESS;
}
mongoc_cursor_t *
_mongoc_cursor_cmd_new_from_reply (mongoc_client_t *client,
                                   const bson_t *cmd,
                                   const bson_t *opts,
                                   bson_t *reply)
{
   mongoc_cursor_t *cursor =
      _mongoc_cursor_cmd_new (client, NULL, cmd, opts, NULL, NULL, NULL);
   data_cmd_t *data = (data_cmd_t *) cursor->impl.data;

   data->reading_from = CMD_RESPONSE;
   cursor->state = IN_BATCH;

   bson_destroy (&data->response.reply);
   if (!bson_steal (&data->response.reply, reply)) {
      bson_destroy (&data->response.reply);
      BSON_ASSERT (bson_steal (&data->response.reply, bson_copy (reply)));
   }

   if (!_mongoc_cursor_start_reading_response (cursor, &data->response)) {
      bson_set_error (&cursor->error,
                      MONGOC_ERROR_CURSOR,
                      MONGOC_ERROR_CURSOR_INVALID_CURSOR,
                      "Couldn't parse cursor document");
   }
   return cursor;
}
Example #9
0
static void
_mongoc_populate_query_error (const bson_t *doc,
                              int32_t       error_api_version,
                              bson_error_t *error)
{
   mongoc_error_domain_t domain =
      error_api_version >= MONGOC_ERROR_API_VERSION_2
      ? MONGOC_ERROR_SERVER
      : MONGOC_ERROR_QUERY;
   uint32_t code = MONGOC_ERROR_QUERY_FAILURE;
   bson_iter_t iter;
   const char *msg = "Unknown query failure";

   ENTRY;

   BSON_ASSERT (doc);

   if (bson_iter_init_find (&iter, doc, "code") &&
       BSON_ITER_HOLDS_INT32 (&iter)) {
      code = (uint32_t) bson_iter_int32 (&iter);
   }

   if (bson_iter_init_find (&iter, doc, "$err") &&
       BSON_ITER_HOLDS_UTF8 (&iter)) {
      msg = bson_iter_utf8 (&iter, NULL);
   }

   bson_set_error (error, domain, code, "%s", msg);

   EXIT;
}
void
_mongoc_cursor_cursorid_init_with_reply (mongoc_cursor_t *cursor,
                                         bson_t          *reply,
                                         uint32_t         server_id)
{
   mongoc_cursor_cursorid_t *cid;

   cursor->sent = true;
   cursor->server_id = server_id;

   cid = (mongoc_cursor_cursorid_t *)cursor->iface_data;
   BSON_ASSERT (cid);

   bson_destroy (&cid->array);
   if (!bson_steal (&cid->array, reply)) {
      bson_steal (&cid->array, bson_copy (reply));
   }

   if (!_mongoc_cursor_cursorid_start_batch (cursor)) {
      bson_set_error (&cursor->error,
                      MONGOC_ERROR_CURSOR,
                      MONGOC_ERROR_CURSOR_INVALID_CURSOR,
                      "Couldn't parse cursor document");
   }
}
Example #11
0
bson_reader_t *
bson_reader_new_from_file (const char   *path,  /* IN */
                           bson_error_t *error) /* OUT */
{
   char errmsg[32];
   int fd;

   bson_return_val_if_fail (path, NULL);

#ifdef BSON_OS_WIN32
   fd = _open (path, (_O_RDONLY | _O_BINARY));
#else
   fd = open (path, O_RDONLY);
#endif

   if (fd == -1) {
      bson_strerror_r (errno, errmsg, sizeof errmsg);
      bson_set_error (error,
                      BSON_ERROR_READER,
                      BSON_ERROR_READER_BADFD,
                      "%s", errmsg);
      return NULL;
   }

   return bson_reader_new_from_fd (fd, true);
}
Example #12
0
bson_reader_t *
bson_reader_new_from_file (const char   *path,  /* IN */
                           bson_error_t *error) /* OUT */
{
   char errmsg_buf[BSON_ERROR_BUFFER_SIZE];
   char *errmsg;
   int fd;

   bson_return_val_if_fail (path, NULL);

#ifdef BSON_OS_WIN32
   if (_sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, 0) != 0) {
      fd = -1;
   }
#else
   fd = open (path, O_RDONLY);
#endif

   if (fd == -1) {
      errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf);
      bson_set_error (error,
                      BSON_ERROR_READER,
                      BSON_ERROR_READER_BADFD,
                      "%s", errmsg);
      return NULL;
   }

   return bson_reader_new_from_fd (fd, true);
}
Example #13
0
static void
_mongoc_cursor_populate_error (mongoc_cursor_t *cursor,
                               const bson_t    *doc,
                               bson_error_t    *error)
{
   bson_uint32_t code = MONGOC_ERROR_QUERY_FAILURE;
   bson_iter_t iter;
   const char *msg = "Unknown query failure";

   BSON_ASSERT (cursor);
   BSON_ASSERT (doc);
   BSON_ASSERT (error);

   if (bson_iter_init_find (&iter, doc, "code") &&
       BSON_ITER_HOLDS_INT32 (&iter)) {
      code = bson_iter_int32 (&iter);
   }

   if (bson_iter_init_find (&iter, doc, "$err") &&
       BSON_ITER_HOLDS_UTF8 (&iter)) {
      msg = bson_iter_utf8 (&iter, NULL);
   }

   if (cursor->is_command &&
       bson_iter_init_find (&iter, doc, "errmsg") &&
       BSON_ITER_HOLDS_UTF8 (&iter)) {
      msg = bson_iter_utf8 (&iter, NULL);
   }

   bson_set_error(error, MONGOC_ERROR_QUERY, code, "%s", msg);
}
Example #14
0
/*
 * If error is not set, set code from first document in array like
 * [{"code": 64, "errmsg": "duplicate"}, ...]. Format the error message
 * from all errors in array.
 */
static void
_set_error_from_response (bson_t *bson_array,
                          mongoc_error_domain_t domain,
                          const char *error_type,
                          bson_error_t *error /* OUT */)
{
   bson_iter_t array_iter;
   bson_iter_t doc_iter;
   bson_string_t *compound_err;
   const char *errmsg = NULL;
   int32_t code = 0;
   uint32_t n_keys, i;

   compound_err = bson_string_new (NULL);
   n_keys = bson_count_keys (bson_array);
   if (n_keys > 1) {
      bson_string_append_printf (
         compound_err, "Multiple %s errors: ", error_type);
   }

   if (!bson_empty0 (bson_array) && bson_iter_init (&array_iter, bson_array)) {
      /* get first code and all error messages */
      i = 0;

      while (bson_iter_next (&array_iter)) {
         if (BSON_ITER_HOLDS_DOCUMENT (&array_iter) &&
             bson_iter_recurse (&array_iter, &doc_iter)) {
            /* parse doc, which is like {"code": 64, "errmsg": "duplicate"} */
            while (bson_iter_next (&doc_iter)) {
               /* use the first error code we find */
               if (BSON_ITER_IS_KEY (&doc_iter, "code") && code == 0) {
                  code = bson_iter_int32 (&doc_iter);
               } else if (BSON_ITER_IS_KEY (&doc_iter, "errmsg")) {
                  errmsg = bson_iter_utf8 (&doc_iter, NULL);

                  /* build message like 'Multiple write errors: "foo", "bar"' */
                  if (n_keys > 1) {
                     bson_string_append_printf (compound_err, "\"%s\"", errmsg);
                     if (i < n_keys - 1) {
                        bson_string_append (compound_err, ", ");
                     }
                  } else {
                     /* single error message */
                     bson_string_append (compound_err, errmsg);
                  }
               }
            }

            i++;
         }
      }

      if (code && compound_err->len) {
         bson_set_error (
            error, domain, (uint32_t) code, "%s", compound_err->str);
      }
   }

   bson_string_free (compound_err, true);
}
Example #15
0
bool
_mongoc_scram_step (mongoc_scram_t *scram,
                    const uint8_t *inbuf,
                    uint32_t inbuflen,
                    uint8_t *outbuf,
                    uint32_t outbufmax,
                    uint32_t *outbuflen,
                    bson_error_t *error)
{
   BSON_ASSERT (scram);
   BSON_ASSERT (inbuf);
   BSON_ASSERT (outbuf);
   BSON_ASSERT (outbuflen);

   scram->step++;

   switch (scram->step) {
   case 1:
      return _mongoc_scram_start (scram, outbuf, outbufmax, outbuflen, error);
   case 2:
      return _mongoc_scram_step2 (
         scram, inbuf, inbuflen, outbuf, outbufmax, outbuflen, error);
   case 3:
      return _mongoc_scram_step3 (
         scram, inbuf, inbuflen, outbuf, outbufmax, outbuflen, error);
   default:
      bson_set_error (error,
                      MONGOC_ERROR_SCRAM,
                      MONGOC_ERROR_SCRAM_NOT_DONE,
                      "SCRAM Failure: maximum steps detected");
      return false;
   }
}
static bool
_mongoc_cursor_cursorid_refresh_from_command (mongoc_cursor_t *cursor,
                                              const bson_t    *command)
{
   mongoc_cursor_cursorid_t *cid;

   ENTRY;

   cid = (mongoc_cursor_cursorid_t *)cursor->iface_data;
   BSON_ASSERT (cid);

   bson_destroy (&cid->array);

   /* server replies to find / aggregate with {cursor: {id: N, firstBatch: []}},
    * to getMore command with {cursor: {id: N, nextBatch: []}}. */
   if (_mongoc_cursor_run_command (cursor, command, &cid->array) &&
       _mongoc_cursor_cursorid_start_batch (cursor)) {

      RETURN (true);
   } else {
      if (!cursor->error.domain) {
         bson_set_error (&cursor->error,
                         MONGOC_ERROR_PROTOCOL,
                         MONGOC_ERROR_PROTOCOL_INVALID_REPLY,
                         "Invalid reply to %s command.",
                         _mongoc_get_command_name (command));
      }

      RETURN (false);
   }
}
Example #17
0
uint32_t
_mongoc_client_sendv (mongoc_client_t              *client,
                      mongoc_rpc_t                 *rpcs,
                      size_t                        rpcs_len,
                      uint32_t                      hint,
                      const mongoc_write_concern_t *write_concern,
                      const mongoc_read_prefs_t    *read_prefs,
                      bson_error_t                 *error)
{
   size_t i;

   bson_return_val_if_fail(client, false);
   bson_return_val_if_fail(rpcs, false);
   bson_return_val_if_fail(rpcs_len, false);

   if (client->in_exhaust) {
      bson_set_error(error,
                     MONGOC_ERROR_CLIENT,
                     MONGOC_ERROR_CLIENT_IN_EXHAUST,
                     "A cursor derived from this client is in exhaust.");
      RETURN(false);
   }

   for (i = 0; i < rpcs_len; i++) {
      rpcs[i].header.msg_len = 0;
      rpcs[i].header.request_id = ++client->request_id;
   }

   switch (client->cluster.state) {
   case MONGOC_CLUSTER_STATE_BORN:
      return _mongoc_cluster_sendv(&client->cluster, rpcs, rpcs_len, hint,
                                   write_concern, read_prefs, error);
   case MONGOC_CLUSTER_STATE_HEALTHY:
   case MONGOC_CLUSTER_STATE_UNHEALTHY:
      return _mongoc_cluster_try_sendv(&client->cluster, rpcs, rpcs_len, hint,
                                       write_concern, read_prefs, error);
   case MONGOC_CLUSTER_STATE_DEAD:
      bson_set_error(error,
                     MONGOC_ERROR_CLIENT,
                     MONGOC_ERROR_CLIENT_NOT_READY,
                     "No healthy connections.");
      return false;
   default:
      BSON_ASSERT(false);
      return 0;
   }
}
static bool
_mongoc_sasl_start (mongoc_sasl_t      *sasl,
                    uint8_t       *outbuf,
                    uint32_t       outbufmax,
                    uint32_t      *outbuflen,
                    bson_error_t       *error)
{
   const char *service_name = "mongodb";
   const char *service_host = "";
   const char *mechanism = NULL;
   const char *raw = NULL;
   unsigned raw_len = 0;
   int status;

   BSON_ASSERT (sasl);
   BSON_ASSERT (outbuf);
   BSON_ASSERT (outbufmax);
   BSON_ASSERT (outbuflen);

   if (sasl->service_name) {
      service_name = sasl->service_name;
   }

   if (sasl->service_host) {
      service_host = sasl->service_host;
   }

   status = sasl_client_new (service_name, service_host, NULL, NULL,
                             sasl->callbacks, 0, &sasl->conn);
   if (_mongoc_sasl_is_failure (status, error)) {
      return false;
   }

   status = sasl_client_start (sasl->conn, sasl->mechanism,
                               &sasl->interact, &raw, &raw_len,
                               &mechanism);
   if (_mongoc_sasl_is_failure (status, error)) {
      return false;
   }

   if ((0 != strcasecmp (mechanism, "GSSAPI")) &&
       (0 != strcasecmp (mechanism, "PLAIN"))) {
      bson_set_error (error,
                      MONGOC_ERROR_SASL,
                      SASL_NOMECH,
                      "SASL Failure: invalid mechanism \"%s\"",
                      mechanism);
      return false;
   }


   status = sasl_encode64 (raw, raw_len, (char *)outbuf, outbufmax, outbuflen);
   if (_mongoc_sasl_is_failure (status, error)) {
      return false;
   }

   return true;
}
static mongoc_matcher_op_t *
_mongoc_matcher_parse (bson_iter_t  *iter,  /* IN */
                       bson_error_t *error) /* OUT */
{
   bson_iter_t child;
   const char *key;

   BSON_ASSERT (iter);

   key = bson_iter_key (iter);

   if (*key != '$') {
      return _mongoc_matcher_parse_compare (iter, key, error);
   } else {
      BSON_ASSERT (bson_iter_type(iter) == BSON_TYPE_ARRAY);

      if (!bson_iter_recurse (iter, &child)) {
         bson_set_error (error,
                         MONGOC_ERROR_MATCHER,
                         MONGOC_ERROR_MATCHER_INVALID,
                         "Invalid value for operator \"%s\"",
                         key);
         return NULL;
      }

      if (strcmp (key, "$or") == 0) {
         return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_OR,
                                               &child, false, error);
      } else if (strcmp(key, "$and") == 0) {
         return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_AND,
                                               &child, false, error);
      } else if (strcmp(key, "$nor") == 0) {
         return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_NOR,
                                               &child, false, error);
      }
   }

   bson_set_error (error,
                   MONGOC_ERROR_MATCHER,
                   MONGOC_ERROR_MATCHER_INVALID,
                   "Invalid operator \"%s\"",
                   key);

   return NULL;
}
static bool
txn_abort (mongoc_client_session_t *session, bson_t *reply, bson_error_t *error)
{
   bson_t cmd = BSON_INITIALIZER;
   bson_t opts = BSON_INITIALIZER;
   bson_error_t err_local;
   bson_error_t *err_ptr = error ? error : &err_local;
   bson_t reply_local = BSON_INITIALIZER;
   mongoc_write_err_type_t error_type;
   bool r = false;

   _mongoc_bson_init_if_set (reply);

   if (!mongoc_client_session_append (session, &opts, err_ptr)) {
      GOTO (done);
   }

   if (session->txn.opts.write_concern) {
      if (!mongoc_write_concern_append (session->txn.opts.write_concern,
                                        &opts)) {
         bson_set_error (err_ptr,
                         MONGOC_ERROR_TRANSACTION,
                         MONGOC_ERROR_TRANSACTION_INVALID_STATE,
                         "Invalid transaction write concern");
         GOTO (done);
      }
   }

   BSON_APPEND_INT32 (&cmd, "abortTransaction", 1);

   /* will be reinitialized by mongoc_client_write_command_with_opts */
   bson_destroy (&reply_local);
   r = mongoc_client_write_command_with_opts (
      session->client, "admin", &cmd, &opts, &reply_local, err_ptr);

   /* Transactions Spec: "Drivers MUST retry the commitTransaction command once
    * after it fails with a retryable error", same for abort */
   error_type = _mongoc_write_error_get_type (r, err_ptr, &reply_local);
   if (error_type == MONGOC_WRITE_ERR_RETRY) {
      bson_destroy (&reply_local);
      r = mongoc_client_write_command_with_opts (
         session->client, "admin", &cmd, &opts, &reply_local, err_ptr);
   }

   if (!r) {
      /* we won't return an error from abortTransaction, so warn */
      MONGOC_WARNING ("Error in abortTransaction: %s", err_ptr->message);
   }

done:
   bson_destroy (&reply_local);
   bson_destroy (&cmd);
   bson_destroy (&opts);

   return r;
}
Example #21
0
static void
test_bson_error_basic (void)
{
   bson_error_t error;

   bson_set_error(&error, 123, 456, "%s %u", "localhost", 27017);
   assert(!strcmp(error.message, "localhost 27017"));
   assert_cmpint(error.domain, ==, 123);
   assert_cmpint(error.code, ==, 456);
}
static bool
_mongoc_server_session_uuid (uint8_t *data /* OUT */, bson_error_t *error)
{
#ifdef MONGOC_ENABLE_CRYPTO
   /* https://tools.ietf.org/html/rfc4122#page-14
    *   o  Set the two most significant bits (bits 6 and 7) of the
    *      clock_seq_hi_and_reserved to zero and one, respectively.
    *
    *   o  Set the four most significant bits (bits 12 through 15) of the
    *      time_hi_and_version field to the 4-bit version number from
    *      Section 4.1.3.
    *
    *   o  Set all the other bits to randomly (or pseudo-randomly) chosen
    *      values.
    */

   if (!_mongoc_rand_bytes (data, 16)) {
      bson_set_error (error,
                      MONGOC_ERROR_CLIENT,
                      MONGOC_ERROR_CLIENT_SESSION_FAILURE,
                      "Could not generate UUID for logical session id");

      return false;
   }

   data[6] = (uint8_t) (0x40 | (data[6] & 0xf));
   data[8] = (uint8_t) (0x80 | (data[8] & 0x3f));

   return true;
#else
   /* no _mongoc_rand_bytes without a crypto library */
   bson_set_error (error,
                   MONGOC_ERROR_CLIENT,
                   MONGOC_ERROR_CLIENT_SESSION_FAILURE,
                   "Could not generate UUID for logical session id, we need a"
                   " cryptography library like libcrypto, Common Crypto, or"
                   " CNG");

   return false;
#endif
}
bool
_mongoc_read_prefs_validate (const mongoc_read_prefs_t *read_prefs, 
                             bson_error_t              *error)
{
   if (read_prefs && !mongoc_read_prefs_is_valid (read_prefs)) {
      bson_set_error (error, MONGOC_ERROR_COMMAND, 
                      MONGOC_ERROR_COMMAND_INVALID_ARG,
                      "Invalid mongoc_read_prefs_t");
      return false;
   }
   return true;
}
bool
_mongoc_write_concern_validate (const mongoc_write_concern_t *write_concern,
                                bson_error_t                 *error)
{
   if (write_concern && !mongoc_write_concern_is_valid (write_concern)) {
      bson_set_error (error, MONGOC_ERROR_COMMAND,
                      MONGOC_ERROR_COMMAND_INVALID_ARG,
                      "Invalid mongoc_write_concern_t");
      return false;
   }
   return true;
}
Example #25
0
static void
_bson_to_error (const bson_t *b,
                bson_error_t *error)
{
   bson_iter_t iter;
   int code = 0;

   BSON_ASSERT(b);

   if (!error) {
      return;
   }

   if (bson_iter_init_find(&iter, b, "code") && BSON_ITER_HOLDS_INT32(&iter)) {
      code = bson_iter_int32(&iter);
   }

   if (bson_iter_init_find(&iter, b, "$err") && BSON_ITER_HOLDS_UTF8(&iter)) {
      bson_set_error(error,
                     MONGOC_ERROR_QUERY,
                     code,
                     "%s",
                     bson_iter_utf8(&iter, NULL));
      return;
   }

   if (bson_iter_init_find(&iter, b, "errmsg") && BSON_ITER_HOLDS_UTF8(&iter)) {
      bson_set_error(error,
                     MONGOC_ERROR_QUERY,
                     code,
                     "%s",
                     bson_iter_utf8(&iter, NULL));
      return;
   }

   bson_set_error(error,
                  MONGOC_ERROR_QUERY,
                  MONGOC_ERROR_QUERY_FAILURE,
                  "An unknown error ocurred on the server.");
}
static bool
_mongoc_sasl_is_failure (int           status,
                         bson_error_t *error)
{
   bool ret = (status < 0);

   if (ret) {
      switch (status) {
      case SASL_NOMEM:
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "SASL Failrue: insufficient memory.");
         break;
      case SASL_NOMECH:
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "SASL Failure: failure to negotiate mechanism");
         break;
      case SASL_BADPARAM:
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "Bad parameter supplied. Please file a bug "
                         "with mongo-c-driver.");
         break;
      default:
         bson_set_error (error,
                         MONGOC_ERROR_SASL,
                         status,
                         "SASL Failure: (%d): %s",
                         status,
                         sasl_errstring (status, NULL, NULL));
         break;
      }
   }

   return ret;
}
Example #27
0
void
_empty_error (mongoc_write_command_t *command, bson_error_t *error)
{
   static const uint32_t codes[] = {MONGOC_ERROR_COLLECTION_DELETE_FAILED,
                                    MONGOC_ERROR_COLLECTION_INSERT_FAILED,
                                    MONGOC_ERROR_COLLECTION_UPDATE_FAILED};

   bson_set_error (error,
                   MONGOC_ERROR_COLLECTION,
                   codes[command->type],
                   "Cannot do an empty %s",
                   gCommandNames[command->type]);
}
/**
 * mongoc_buffer_append_from_stream:
 * @buffer; A mongoc_buffer_t.
 * @stream: The stream to read from.
 * @size: The number of bytes to read.
 * @timeout_msec: The number of milliseconds to wait or -1 for the default
 * @error: A location for a bson_error_t, or NULL.
 *
 * Reads from stream @size bytes and stores them in @buffer. This can be used
 * in conjunction with reading RPCs from a stream. You read from the stream
 * into this buffer and then scatter the buffer into the RPC.
 *
 * Returns: true if successful; otherwise false and @error is set.
 */
bool
_mongoc_buffer_append_from_stream (mongoc_buffer_t *buffer,
                                   mongoc_stream_t *stream,
                                   size_t size,
                                   int32_t timeout_msec,
                                   bson_error_t *error)
{
   uint8_t *buf;
   ssize_t ret;

   ENTRY;

   BSON_ASSERT (buffer);
   BSON_ASSERT (stream);
   BSON_ASSERT (size);

   BSON_ASSERT (buffer->datalen);
   BSON_ASSERT ((buffer->datalen + size) < INT_MAX);

   if (!SPACE_FOR (buffer, size)) {
      if (buffer->len) {
         memmove (&buffer->data[0], &buffer->data[buffer->off], buffer->len);
      }
      buffer->off = 0;
      if (!SPACE_FOR (buffer, size)) {
         buffer->datalen =
            bson_next_power_of_two (size + buffer->len + buffer->off);
         buffer->data = (uint8_t *) buffer->realloc_func (
            buffer->data, buffer->datalen, NULL);
      }
   }

   buf = &buffer->data[buffer->off + buffer->len];

   BSON_ASSERT ((buffer->off + buffer->len + size) <= buffer->datalen);

   ret = mongoc_stream_read (stream, buf, size, size, timeout_msec);
   if (ret != size) {
      bson_set_error (error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_SOCKET,
                      "Failed to read %" PRIu64
                      " bytes: socket error or timeout",
                      (uint64_t) size);
      RETURN (false);
   }

   buffer->len += ret;

   RETURN (true);
}
void
_mongoc_write_command_execute (mongoc_write_command_t       *command,       /* IN */
                               mongoc_client_t              *client,        /* IN */
                               mongoc_server_stream_t       *server_stream, /* IN */
                               const char                   *database,      /* IN */
                               const char                   *collection,    /* IN */
                               const mongoc_write_concern_t *write_concern, /* IN */
                               uint32_t                      offset,        /* IN */
                               mongoc_write_result_t        *result)        /* OUT */
{
   ENTRY;

   BSON_ASSERT (command);
   BSON_ASSERT (client);
   BSON_ASSERT (server_stream);
   BSON_ASSERT (database);
   BSON_ASSERT (collection);
   BSON_ASSERT (result);

   if (!write_concern) {
      write_concern = client->write_concern;
   }

   if (!_mongoc_write_concern_is_valid(write_concern)) {
      bson_set_error (&result->error,
                      MONGOC_ERROR_COMMAND,
                      MONGOC_ERROR_COMMAND_INVALID_ARG,
                      "The write concern is invalid.");
      result->failed = true;
      EXIT;
   }

   if (!command->hint) {
      command->hint = server_stream->sd->id;
   } else {
      BSON_ASSERT (command->hint == server_stream->sd->id);
   }

   if (server_stream->sd->max_wire_version >= WIRE_VERSION_WRITE_CMD) {
      _mongoc_write_command (command, client, server_stream, database,
                             collection, write_concern, offset,
                             result, &result->error);
   } else {
      gLegacyWriteOps[command->type] (command, client, server_stream, database,
                                      collection, write_concern, offset,
                                      result, &result->error);
   }

   EXIT;
}
Example #30
0
static void
missing_chunk (mongoc_gridfs_file_t *file)
{
   bson_set_error (&file->error,
                   MONGOC_ERROR_GRIDFS,
                   MONGOC_ERROR_GRIDFS_CHUNK_MISSING,
                   "missing chunk number %" PRId32,
                   file->n);

   if (file->cursor) {
      mongoc_cursor_destroy (file->cursor);
      file->cursor = NULL;
   }
}