mongo_cursor *mongo_find( mongo *conn, const char *ns, bson *query, bson *fields, int limit, int skip, int options ) { mongo_cursor *cursor = ( mongo_cursor * )bson_malloc( sizeof( mongo_cursor ) ); mongo_cursor_init( cursor, conn, ns ); cursor->flags |= MONGO_CURSOR_MUST_FREE; mongo_cursor_set_query( cursor, query ); mongo_cursor_set_fields( cursor, fields ); mongo_cursor_set_limit( cursor, limit ); mongo_cursor_set_skip( cursor, skip ); mongo_cursor_set_options( cursor, options ); if( mongo_cursor_op_query( cursor ) == MONGO_OK ) return cursor; else { mongo_cursor_destroy( cursor ); return NULL; } }
char * bson_strdup (const char *str) /* IN */ { long len; char *out; if (!str) { return NULL; } len = (long)strlen (str); out = bson_malloc (len + 1); if (!out) { return NULL; } memcpy (out, str, len + 1); return out; }
static ssize_t _mongoc_stream_socket_poll (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout_msec) { int i; ssize_t ret = -1; mongoc_socket_poll_t *sds; mongoc_stream_socket_t *ss; ENTRY; sds = (mongoc_socket_poll_t *) bson_malloc (sizeof (*sds) * nstreams); for (i = 0; i < nstreams; i++) { ss = (mongoc_stream_socket_t *) streams[i].stream; if (!ss->sock) { goto CLEANUP; } sds[i].socket = ss->sock; sds[i].events = streams[i].events; } ret = mongoc_socket_poll (sds, nstreams, timeout_msec); if (ret > 0) { for (i = 0; i < nstreams; i++) { streams[i].revents = sds[i].revents; } } CLEANUP: bson_free (sds); RETURN (ret); }
static void test_bson_writer_custom_realloc (void) { bson_writer_t *writer; uint8_t *buf = bson_malloc(0); size_t buflen = 0; bson_t *b; int x = 0; writer = bson_writer_new(&buf, &buflen, 0, test_bson_writer_custom_realloc_helper, &x); assert(bson_writer_begin(writer, &b)); assert(bson_append_utf8(b, "hello", -1, "world", -1)); bson_writer_end(writer); bson_writer_destroy(writer); assert_cmpint(x, >, 0); bson_free(buf); }
int mongo_read_response( mongo *conn, mongo_reply **reply ) { mongo_header head; /* header from network */ mongo_reply_fields fields; /* header from network */ mongo_reply *out; /* native endian */ unsigned int len; int res; mongo_read_socket( conn, &head, sizeof( head ) ); mongo_read_socket( conn, &fields, sizeof( fields ) ); bson_little_endian32( &len, &head.len ); if ( len < sizeof( head )+sizeof( fields ) || len > 64*1024*1024 ) return MONGO_READ_SIZE_ERROR; /* most likely corruption */ out = ( mongo_reply * )bson_malloc( len ); out->head.len = len; bson_little_endian32( &out->head.id, &head.id ); bson_little_endian32( &out->head.responseTo, &head.responseTo ); bson_little_endian32( &out->head.op, &head.op ); bson_little_endian32( &out->fields.flag, &fields.flag ); bson_little_endian64( &out->fields.cursorID, &fields.cursorID ); bson_little_endian32( &out->fields.start, &fields.start ); bson_little_endian32( &out->fields.num, &fields.num ); res = mongo_read_socket( conn, &out->objs, len-sizeof( head )-sizeof( fields ) ); if( res != MONGO_OK ) { bson_free( out ); return res; } *reply = out; return MONGO_OK; }
static void gridfs_setup (perf_test_t *test) { char *path; gridfs_test_t *gridfs_test; FILE *fp; perf_test_setup (test); gridfs_test = (gridfs_test_t *) test; gridfs_test->client = mongoc_client_new (NULL); path = bson_strdup_printf ("%s/SINGLE_DOCUMENT/GRIDFS_LARGE", g_test_dir); fp = fopen (path, "rb"); if (!fp) { perror ("cannot open GRIDFS_LARGE"); abort (); } /* get the file size */ if (0 != fseek (fp, 0L, SEEK_END)) { perror ("fseek"); abort(); } gridfs_test->data_sz = (size_t) ftell (fp); fseek(fp, 0L, SEEK_SET); /* read the file */ gridfs_test->data = bson_malloc (gridfs_test->data_sz); assert (gridfs_test->data); assert (gridfs_test->data_sz == fread (gridfs_test->data, 1, gridfs_test->data_sz, fp)); bson_free (path); }
static int mongo_cmd_get_error_helper( mongo *conn, const char *db, bson *realout, const char *cmdtype ) { bson out = {NULL,0}; bson_bool_t haserror = 0; /* Reset last error codes. */ conn->lasterrcode = 0; bson_free( conn->lasterrstr ); conn->lasterrstr = NULL; /* If there's an error, store its code and string in the connection object. */ if( mongo_simple_int_command( conn, db, cmdtype, 1, &out ) == MONGO_OK ) { bson_iterator it; haserror = ( bson_find( &it, &out, "err" ) != BSON_NULL ); if( haserror ) { conn->lasterrstr = ( char * )bson_malloc( bson_iterator_string_len( &it ) ); if( conn->lasterrstr ) { strcpy( conn->lasterrstr, bson_iterator_string( &it ) ); } if( bson_find( &it, &out, "code" ) != BSON_NULL ) conn->lasterrcode = bson_iterator_int( &it ); } } if( realout ) *realout = out; /* transfer of ownership */ else bson_destroy( &out ); if( haserror ) return MONGO_ERROR; else return MONGO_OK; }
/* Uses old way of querying system.namespaces. */ mongoc_cursor_t * _mongoc_database_find_collections_legacy (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) { mongoc_collection_t *col; mongoc_cursor_t *cursor = NULL; mongoc_read_prefs_t *read_prefs; uint32_t dbname_len; bson_t legacy_filter; bson_iter_t iter; const char *col_filter; bson_t q = BSON_INITIALIZER; mongoc_database_find_collections_legacy_ctx_t *ctx; BSON_ASSERT (database); col = mongoc_client_get_collection (database->client, database->name, "system.namespaces"); BSON_ASSERT (col); dbname_len = (uint32_t)strlen (database->name); ctx = bson_malloc (sizeof (*ctx)); ctx->dbname = database->name; ctx->dbname_len = dbname_len; /* Filtering on name needs to be handled differently for old servers. */ if (filter && bson_iter_init_find (&iter, filter, "name")) { bson_string_t *buf; /* on legacy servers, this must be a string (i.e. not a regex) */ if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_NAMESPACE_INVALID_FILTER_TYPE, "On legacy servers, a filter on name can only be a string."); goto cleanup_filter; } BSON_ASSERT (BSON_ITER_HOLDS_UTF8 (&iter)); col_filter = bson_iter_utf8 (&iter, NULL); bson_init (&legacy_filter); bson_copy_to_excluding_noinit (filter, &legacy_filter, "name", NULL); /* We must db-qualify filters on name. */ buf = bson_string_new (database->name); bson_string_append_c (buf, '.'); bson_string_append (buf, col_filter); BSON_APPEND_UTF8 (&legacy_filter, "name", buf->str); bson_string_free (buf, true); filter = &legacy_filter; } read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cursor = mongoc_collection_find (col, MONGOC_QUERY_NONE, 0, 0, 0, filter ? filter : &q, NULL, read_prefs); _mongoc_cursor_transform_init ( cursor, _mongoc_database_find_collections_legacy_filter, _mongoc_database_find_collections_legacy_mutate, &bson_free, ctx); mongoc_read_prefs_destroy (read_prefs); cleanup_filter: mongoc_collection_destroy (col); return cursor; }
char * _mongoc_sasl_prep_impl (const char *name, const char *in_utf8, int in_utf8_len, bson_error_t *err) { /* The flow is in_utf8 -> in_utf16 -> SASLPrep -> out_utf16 -> out_utf8. */ UChar *in_utf16, *out_utf16; char *out_utf8; int32_t in_utf16_len, out_utf16_len, out_utf8_len; UErrorCode error_code = U_ZERO_ERROR; UStringPrepProfile *prep; #define SASL_PREP_ERR_RETURN(msg) \ do { \ bson_set_error (err, \ MONGOC_ERROR_SCRAM, \ MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, \ (msg), \ name); \ return NULL; \ } while (0) /* 1. convert str to UTF-16. */ /* preflight to get the destination length. */ (void) u_strFromUTF8 ( NULL, 0, &in_utf16_len, in_utf8, in_utf8_len, &error_code); if (error_code != U_BUFFER_OVERFLOW_ERROR) { SASL_PREP_ERR_RETURN ("could not calculate UTF-16 length of %s"); } /* convert to UTF-16. */ error_code = U_ZERO_ERROR; in_utf16 = bson_malloc (sizeof (UChar) * (in_utf16_len + 1)); /* add one for null byte. */ (void) u_strFromUTF8 ( in_utf16, in_utf16_len + 1, NULL, in_utf8, in_utf8_len, &error_code); if (error_code) { bson_free (in_utf16); SASL_PREP_ERR_RETURN ("could not convert %s to UTF-16"); } /* 2. perform SASLPrep. */ prep = usprep_openByType (USPREP_RFC4013_SASLPREP, &error_code); if (error_code) { bson_free (in_utf16); SASL_PREP_ERR_RETURN ("could not start SASLPrep for %s"); } /* preflight. */ out_utf16_len = usprep_prepare ( prep, in_utf16, in_utf16_len, NULL, 0, USPREP_DEFAULT, NULL, &error_code); if (error_code != U_BUFFER_OVERFLOW_ERROR) { bson_free (in_utf16); usprep_close (prep); SASL_PREP_ERR_RETURN ("could not calculate SASLPrep length of %s"); } /* convert. */ error_code = U_ZERO_ERROR; out_utf16 = bson_malloc (sizeof (UChar) * (out_utf16_len + 1)); (void) usprep_prepare (prep, in_utf16, in_utf16_len, out_utf16, out_utf16_len + 1, USPREP_DEFAULT, NULL, &error_code); if (error_code) { bson_free (in_utf16); bson_free (out_utf16); usprep_close (prep); SASL_PREP_ERR_RETURN ("could not execute SASLPrep for %s"); } bson_free (in_utf16); usprep_close (prep); /* 3. convert back to UTF-8. */ /* preflight. */ (void) u_strToUTF8 ( NULL, 0, &out_utf8_len, out_utf16, out_utf16_len, &error_code); if (error_code != U_BUFFER_OVERFLOW_ERROR) { bson_free (out_utf16); SASL_PREP_ERR_RETURN ("could not calculate UTF-8 length of %s"); } /* convert. */ error_code = U_ZERO_ERROR; out_utf8 = (char *) bson_malloc ( sizeof (char) * (out_utf8_len + 1)); /* add one for null byte. */ (void) u_strToUTF8 ( out_utf8, out_utf8_len + 1, NULL, out_utf16, out_utf16_len, &error_code); if (error_code) { bson_free (out_utf8); bson_free (out_utf16); SASL_PREP_ERR_RETURN ("could not convert %s back to UTF-8"); } bson_free (out_utf16); return out_utf8; #undef SASL_PREP_ERR_RETURN }
static bool _mongoc_scram_step3 (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t *val_e = NULL; uint32_t val_e_len; uint8_t *val_v = NULL; uint32_t val_v_len; uint8_t **current_val; uint32_t *current_val_len; const uint8_t *ptr; const uint8_t *next_comma; bool rval = true; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); for (ptr = inbuf; ptr < inbuf + inbuflen;) { switch (*ptr) { case 'e': current_val = &val_e; current_val_len = &val_e_len; break; case 'v': current_val = &val_v; current_val_len = &val_v_len; break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unknown key (%c) in sasl step 3", *ptr); goto FAIL; break; } ptr++; if (*ptr != '=') { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid parse state in sasl step 3"); goto FAIL; } ptr++; next_comma = (const uint8_t *) memchr (ptr, ',', (inbuf + inbuflen) - ptr); if (next_comma) { *current_val_len = (uint32_t) (next_comma - ptr); } else { *current_val_len = (uint32_t) ((inbuf + inbuflen) - ptr); } *current_val = (uint8_t *) bson_malloc (*current_val_len + 1); memcpy (*current_val, ptr, *current_val_len); (*current_val)[*current_val_len] = '\0'; if (next_comma) { ptr = next_comma + 1; } else { break; } } *outbuflen = 0; if (val_e) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: authentication failure in sasl step 3 : %s", val_e); goto FAIL; } if (!val_v) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no v param in sasl step 3"); goto FAIL; } if (!_mongoc_scram_verify_server_signature (scram, val_v, val_v_len)) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not verify server signature in sasl step 3"); goto FAIL; } /* Update the cache if authentication succeeds */ _mongoc_scram_update_cache (scram); goto CLEANUP; FAIL: rval = false; CLEANUP: bson_free (val_e); bson_free (val_v); return rval; }
static void test_random_write2( void ) { mongo conn[1]; gridfs gfs[1]; gridfile gfile[1]; bson meta; char *buf = (char*)bson_malloc( LARGE ); char *zeroedbuf = (char*)bson_malloc( LARGE ); int n; if( buf == NULL ) { printf( "Failed to allocate" ); exit( 1 ); } srand( 123 ); // Init with a predictable value INIT_SOCKETS_FOR_WINDOWS; CONN_CLIENT_TEST; fill_buffer_randomly( buf, ( int64_t )LARGE ); memset( zeroedbuf, 0, LARGE ); bson_init_empty( &meta ); GFS_INIT; /* This portion of the test we will write zeroes by using new API gridfile_set_size function gridfile_expand tested implicitally by using gridfile_set_size making file larger */ gridfile_init( gfs, &meta, gfile ); gridfile_writer_init( gfile, gfs, "random_access", "text/html", 0 ); gridfile_set_size( gfile, LARGE ); // New API, this zero fills the file gridfile_writer_done( gfile ); test_gridfile( gfs, zeroedbuf, LARGE, "random_access", "text/html" ); // Test zero filled file /* This portion of the test we will write zeroes by using new API gridfile_set_size then we will truncate the file */ gridfile_init( gfs, &meta, gfile ); gridfile_writer_init( gfile, gfs, "random_access", "text/html", 0 ); gridfile_set_size( gfile, LARGE ); // New API, this zero fills the file with LARGE bytes gridfile_truncate( gfile, LARGE / 2 ); // Let's truncate the file now gridfile_writer_done( gfile ); test_gridfile( gfs, zeroedbuf, LARGE / 2, "random_access", "text/html" ); // Test zero filled file truncated by half /* Let's re-create the file, now let's randomly write real data */ gridfile_init( gfs, &meta, gfile ); gridfile_writer_init( gfile, gfs, "random_access", "text/html", 0 ); gridfile_set_size( gfile, LARGE ); // We need to reserve LARGE bytes on file before writing backwards /* Here we will write backwards the file with our random numbers. We will use a 3072 size buffer to cross over buffers given the fact 256K is not a multiple of 3072. Let's stress the buffering logic a little bit */ for( n = LARGE / 3072 - 1; n >= 0; n-- ) { gridfile_seek( gfile, 3072 * n ); ASSERT( gridfile_write_buffer( gfile, buf + ( n * 3072 ), 3072 ) == 3072 ); } gridfile_writer_done( gfile ); test_gridfile( gfs, buf, LARGE, "random_access", "text/html" ); gridfs_destroy( gfs ); mongo_destroy( conn ); free( buf ); free( zeroedbuf ); }
void mock_server_reply_multi (request_t *request, mongoc_reply_flags_t flags, const bson_t *docs, int n_docs, int64_t cursor_id) { const mongoc_rpc_t *request_rpc; mock_server_t *server; mongoc_stream_t *client; char *doc_json; bson_string_t *docs_json; mongoc_iovec_t *iov; mongoc_array_t ar; mongoc_rpc_t r = {{ 0 }}; size_t expected = 0; ssize_t n_written; int iovcnt; int i; uint8_t *buf; uint8_t *ptr; size_t len; BSON_ASSERT (request); BSON_ASSERT (docs); request_rpc = &request->request_rpc; server = request->server; client = request->client; docs_json = bson_string_new (""); for (i = 0; i < n_docs; i++) { doc_json = bson_as_json (&docs[i], NULL); bson_string_append (docs_json, doc_json); bson_free (doc_json); if (i < n_docs - 1) { bson_string_append (docs_json, ", "); } } if (mock_server_get_verbose (request->server)) { printf ("%5.2f %hu <- %hu \t%s\n", mock_server_get_uptime_sec (request->server), request->client_port, mock_server_get_port (request->server), docs_json->str); fflush (stdout); } len = 0; for (i = 0; i < n_docs; i++) { len += docs[i].len; } ptr = buf = bson_malloc (len); for (i = 0; i < n_docs; i++) { memcpy (ptr, bson_get_data (&docs[i]), docs[i].len); ptr += docs[i].len; } _mongoc_array_init (&ar, sizeof (mongoc_iovec_t)); if (!(request->opcode == MONGOC_OPCODE_QUERY && request_rpc->query.flags & MONGOC_QUERY_EXHAUST)) { server->last_response_id++; } mongoc_mutex_lock (&server->mutex); r.reply.request_id = server->last_response_id; mongoc_mutex_unlock (&server->mutex); r.reply.msg_len = 0; r.reply.response_to = request_rpc->header.request_id; r.reply.opcode = MONGOC_OPCODE_REPLY; r.reply.flags = flags; r.reply.cursor_id = cursor_id; r.reply.start_from = 0; r.reply.n_returned = 1; r.reply.documents = buf; r.reply.documents_len = (uint32_t)len; _mongoc_rpc_gather (&r, &ar); _mongoc_rpc_swab_to_le (&r); iov = (mongoc_iovec_t *)ar.data; iovcnt = (int) ar.len; for (i = 0; i < iovcnt; i++) { expected += iov[i].iov_len; } n_written = mongoc_stream_writev (client, iov, (size_t) iovcnt, -1); assert (n_written == expected); bson_string_free (docs_json, true); _mongoc_array_destroy (&ar); bson_free (buf); }
MONGO_EXPORT mongo_cursor* mongo_cursor_create() { return (mongo_cursor*)bson_malloc(sizeof(mongo_cursor)); }
MONGO_EXPORT mongo* mongo_create() { return (mongo*)bson_malloc(sizeof(mongo)); }
static void * bson_yajl_malloc_func (void *ctx, size_t sz) { return bson_malloc (sz); }
static void _mongoc_write_command_insert_legacy (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_write_result_t *result, bson_error_t *error) { uint32_t current_offset; mongoc_iovec_t *iov; const uint8_t *data; mongoc_rpc_t rpc; bson_iter_t iter; uint32_t len; bson_t *gle = NULL; uint32_t size = 0; bool has_more; char ns [MONGOC_NAMESPACE_MAX + 1]; bool r; uint32_t n_docs_in_batch; uint32_t idx = 0; int32_t max_msg_size; int32_t max_bson_obj_size; bool singly; ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (database); BSON_ASSERT (server_stream); BSON_ASSERT (collection); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_INSERT); current_offset = offset; max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream); max_msg_size = mongoc_server_stream_max_msg_size (server_stream); singly = !command->u.insert.allow_bulk_op_insert; r = bson_iter_init (&iter, command->documents); if (!r) { BSON_ASSERT (false); EXIT; } if (!command->n_documents || !bson_iter_next (&iter)) { bson_set_error (error, MONGOC_ERROR_COLLECTION, MONGOC_ERROR_COLLECTION_INSERT_FAILED, "Cannot do an empty insert."); result->failed = true; EXIT; } bson_snprintf (ns, sizeof ns, "%s.%s", database, collection); iov = (mongoc_iovec_t *)bson_malloc ((sizeof *iov) * command->n_documents); again: has_more = false; n_docs_in_batch = 0; size = (uint32_t)(sizeof (mongoc_rpc_header_t) + 4 + strlen (database) + 1 + strlen (collection) + 1); do { BSON_ASSERT (BSON_ITER_HOLDS_DOCUMENT (&iter)); BSON_ASSERT (n_docs_in_batch <= idx); BSON_ASSERT (idx < command->n_documents); bson_iter_document (&iter, &len, &data); BSON_ASSERT (data); BSON_ASSERT (len >= 5); if (len > max_bson_obj_size) { /* document is too large */ bson_t write_err_doc = BSON_INITIALIZER; too_large_error (error, idx, len, max_bson_obj_size, &write_err_doc); _mongoc_write_result_merge_legacy ( result, command, &write_err_doc, MONGOC_ERROR_COLLECTION_INSERT_FAILED, offset + idx); bson_destroy (&write_err_doc); if (command->flags.ordered) { /* send the batch so far (if any) and return the error */ break; } } else if ((n_docs_in_batch == 1 && singly) || size > (max_msg_size - len)) { /* batch is full, send it and then start the next batch */ has_more = true; break; } else { /* add document to batch and continue building the batch */ iov[n_docs_in_batch].iov_base = (void *) data; iov[n_docs_in_batch].iov_len = len; size += len; n_docs_in_batch++; } idx++; } while (bson_iter_next (&iter)); if (n_docs_in_batch) { rpc.insert.msg_len = 0; rpc.insert.request_id = 0; rpc.insert.response_to = 0; rpc.insert.opcode = MONGOC_OPCODE_INSERT; rpc.insert.flags = ( (command->flags.ordered) ? MONGOC_INSERT_NONE : MONGOC_INSERT_CONTINUE_ON_ERROR); rpc.insert.collection = ns; rpc.insert.documents = iov; rpc.insert.n_documents = n_docs_in_batch; if (!mongoc_cluster_sendv_to_server (&client->cluster, &rpc, 1, server_stream, write_concern, error)) { result->failed = true; GOTO (cleanup); } if (_mongoc_write_concern_needs_gle (write_concern)) { bool err = false; bson_iter_t citer; if (!_mongoc_client_recv_gle (client, server_stream, &gle, error)) { result->failed = true; GOTO (cleanup); } err = (bson_iter_init_find (&citer, gle, "err") && bson_iter_as_bool (&citer)); /* * Overwrite the "n" field since it will be zero. Otherwise, our * merge_legacy code will not know how many we tried in this batch. */ if (!err && bson_iter_init_find (&citer, gle, "n") && BSON_ITER_HOLDS_INT32 (&citer) && !bson_iter_int32 (&citer)) { bson_iter_overwrite_int32 (&citer, n_docs_in_batch); } } } cleanup: if (gle) { _mongoc_write_result_merge_legacy ( result, command, gle, MONGOC_ERROR_COLLECTION_INSERT_FAILED, current_offset); current_offset = offset + idx; bson_destroy (gle); gle = NULL; } if (has_more) { GOTO (again); } bson_free (iov); EXIT; }
static void test_split_insert (void) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; mongoc_collection_t *collection; mongoc_client_t *client; bson_oid_t oid; bson_t **docs; bson_t reply = BSON_INITIALIZER; bson_error_t error; mongoc_server_stream_t *server_stream; int i; bool r; client = test_framework_client_new (); assert (client); collection = get_test_collection (client, "test_split_insert"); assert (collection); docs = (bson_t **)bson_malloc (sizeof(bson_t*) * 3000); for (i = 0; i < 3000; i++) { docs [i] = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (docs [i], "_id", &oid); } _mongoc_write_result_init (&result); _mongoc_write_command_init_insert (&command, docs[0], write_flags, ++client->cluster.operation_id, true); for (i = 1; i < 3000; i++) { _mongoc_write_command_insert_append (&command, docs[i]); } server_stream = mongoc_cluster_stream_for_writes (&client->cluster, &error); ASSERT_OR_PRINT (server_stream, error); _mongoc_write_command_execute (&command, client, server_stream, collection->db, collection->collection, NULL, 0, &result); r = _mongoc_write_result_complete (&result, 2, collection->write_concern, &reply, &error); ASSERT_OR_PRINT (r, error); assert (result.nInserted == 3000); _mongoc_write_command_destroy (&command); _mongoc_write_result_destroy (&result); ASSERT_OR_PRINT (mongoc_collection_drop (collection, &error), error); for (i = 0; i < 3000; i++) { bson_destroy (docs [i]); } bson_free (docs); mongoc_server_stream_cleanup (server_stream); mongoc_collection_destroy (collection); mongoc_client_destroy (client); }
MONGO_EXPORT bson* bson_create( void ) { return (bson*)bson_malloc(sizeof(bson)); }
static void test_gridfile( gridfs *gfs, char *data_before, int64_t length, char *filename, char *content_type ) { gridfile gfile[1]; FILE *stream; #ifdef DYING mongo_md5_state_t pms[1]; mongo_md5_byte_t digest[16]; #endif char hex_digest[33]; int64_t i = length; int n; char *data_after = (char*)bson_malloc( LARGE ); int truncBytes; char* lowerName; ASSERT(gridfs_find_filename( gfs, filename, gfile ) == MONGO_OK); ASSERT( gridfile_exists( gfile ) ); stream = fopen( "output", "w+" ); gridfile_write_file( gfile, stream ); fseek( stream, 0, SEEK_SET ); ASSERT( fread( data_after, (size_t)length, sizeof( char ), stream ) ); fclose( stream ); ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 ); gridfile_read_buffer( gfile, data_after, length ); ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 ); lowerName = (char*) bson_malloc( (int)strlen( filename ) + 1); strcpy( lowerName, filename ); _strlwr( lowerName ); ASSERT( strcmp( gridfile_get_filename( gfile ), lowerName ) == 0 ); bson_free( lowerName ); ASSERT( gridfile_get_contentlength( gfile ) == (size_t)length ); ASSERT( gridfile_get_chunksize( gfile ) == DEFAULT_CHUNK_SIZE ); ASSERT( strcmp( gridfile_get_contenttype( gfile ), content_type ) == 0 ) ; ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 ); if( !( gfile->flags & GRIDFILE_COMPRESS ) ) { #ifdef DYING mongo_md5_init( pms ); n = 0; while( i > INT_MAX ) { mongo_md5_append( pms, ( const mongo_md5_byte_t * )data_before + ( n * INT_MAX ), INT_MAX ); i -= INT_MAX; n += 1; } if( i > 0 ) mongo_md5_append( pms, ( const mongo_md5_byte_t * )data_before + ( n * INT_MAX ), (int)i ); mongo_md5_finish( pms, digest ); digest2hex( digest, hex_digest ); #else { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE); const char * _digest = NULL; int xx; while( i > INT_MAX ) { xx = rpmDigestUpdate(ctx, (char *)data_before + (n*INT_MAX), INT_MAX); i -= INT_MAX; n += 1; } xx = rpmDigestFinal(ctx, &_digest, NULL, 1); strncpy(hex_digest, _digest, 32+1); hex_digest[32] = '\0'; _digest = _free(_digest); } #endif ASSERT( strcmp( gridfile_get_md5( gfile ), hex_digest ) == 0 ); } truncBytes = (int) (length > DEFAULT_CHUNK_SIZE * 4 ? length - DEFAULT_CHUNK_SIZE * 2 - 13 : 23); gridfile_writer_init( gfile, gfs, filename, content_type, GRIDFILE_DEFAULT); ASSERT( gridfile_truncate(gfile, (size_t)(length - truncBytes)) == (size_t)(length - truncBytes)); gridfile_writer_done( gfile ); gridfile_seek(gfile, 0); ASSERT( gridfile_get_contentlength( gfile ) == (size_t)(length - truncBytes) ); ASSERT( gridfile_read_buffer( gfile, data_after, length ) == (size_t)(length - truncBytes)); ASSERT( memcmp( data_before, data_after, (size_t)(length - truncBytes) ) == 0 ); gridfile_writer_init( gfile, gfs, filename, content_type, GRIDFILE_DEFAULT); gridfile_truncate(gfile, 0); gridfile_writer_done( gfile ); ASSERT( gridfile_get_contentlength( gfile ) == 0 ); ASSERT( gridfile_read_buffer( gfile, data_after, length ) == 0 ); gridfile_destroy( gfile ); ASSERT( gridfs_remove_filename( gfs, filename ) == MONGO_OK ); free( data_after ); gridfs_test_unlink( "output" ); }
static void test_large( void ) { mongo conn[1]; gridfs gfs[1]; gridfile gfile[1]; FILE *fd; size_t i, n; char *buffer = (char*)bson_malloc( LARGE ); char *read_buf = (char*)bson_malloc( LARGE ); gridfs_offset filesize = ( int64_t )1024 * ( int64_t )LARGE; mongo_write_concern wc; bson lastError; bson lastErrorCmd; srand( (unsigned int) time( NULL ) ); INIT_SOCKETS_FOR_WINDOWS; CONN_CLIENT_TEST; mongo_write_concern_init(&wc); wc.j = 1; mongo_write_concern_finish(&wc); mongo_set_write_concern(conn, &wc); GFS_INIT; fd = fopen( "bigfile", "r" ); if( fd ) { fclose( fd ); } else { /* Create a very large file */ fill_buffer_randomly( buffer, ( int64_t )LARGE ); fd = fopen( "bigfile", "w" ); for( i=0; i<1024; i++ ) { fwrite( buffer, 1, LARGE, fd ); } fclose( fd ); } /* Now read the file into GridFS */ gridfs_remove_filename( gfs, "bigfile" ); gridfs_store_file( gfs, "bigfile", "bigfile", "text/html", GRIDFILE_NOMD5 | GRIDFILE_COMPRESS); gridfs_find_filename( gfs, "bigfile", gfile ); ASSERT( strcmp( gridfile_get_filename( gfile ), "bigfile" ) == 0 ); ASSERT( gridfile_get_contentlength( gfile ) == filesize ); fd = fopen( "bigfile", "r" ); while( ( n = fread( buffer, 1, MEDIUM, fd ) ) != 0 ) { ASSERT( gridfile_read_buffer( gfile, read_buf, MEDIUM ) == n ); ASSERT( memcmp( buffer, read_buf, n ) == 0 ); } fclose( fd ); gridfile_destroy( gfile ); /* Read the file using the streaming interface */ gridfs_remove_filename( gfs, "bigfile" ); gridfs_remove_filename( gfs, "bigfile-stream" ); gridfile_writer_init( gfile, gfs, "bigfile-stream", "text/html", GRIDFILE_NOMD5 | GRIDFILE_COMPRESS ); mongo_write_concern_destroy( &wc ); mongo_write_concern_init(&wc); wc.j = 0; /* Let's reset write concern j field to zero, we will manually call getLastError with j = 1 */ mongo_write_concern_finish(&wc); mongo_set_write_concern(conn, &wc); fd = fopen( "bigfile", "r" ); i = 0; while( ( n = fread( buffer, 1, READ_WRITE_BUF_SIZE, fd ) ) != 0 ) { ASSERT( gridfile_write_buffer( gfile, buffer, n ) == n ); if(i++ % 10 == 0) { bson_init( &lastErrorCmd ); bson_append_int( &lastErrorCmd, "getLastError", 1); bson_append_int( &lastErrorCmd, "j", 1); bson_finish( &lastErrorCmd ); bson_init( &lastError ); mongo_run_command( conn, "test", &lastErrorCmd, &lastError ); bson_destroy( &lastError ); bson_destroy( &lastErrorCmd ); } } mongo_write_concern_destroy( &wc ); mongo_write_concern_init(&wc); wc.j = 1; /* Let's reset write concern j field to 1 */ mongo_write_concern_finish(&wc); mongo_set_write_concern(conn, &wc); fclose( fd ); gridfile_writer_done( gfile ); gridfs_find_filename( gfs, "bigfile-stream", gfile ); ASSERT( strcmp( gridfile_get_filename( gfile ), "bigfile-stream" ) == 0 ); ASSERT( gridfile_get_contentlength( gfile ) == filesize ); gridfs_remove_filename( gfs, "bigfile-stream" ); gridfs_destroy( gfs ); mongo_disconnect( conn ); mongo_destroy( conn ); bson_free( buffer ); bson_free( read_buf ); mongo_write_concern_destroy( &wc ); }
/* Parse server-first-message of the form: * r=client-nonce|server-nonce,s=user-salt,i=iteration-count * * Generate client-final-message of the form: * c=channel-binding(base64),r=client-nonce|server-nonce,p=client-proof */ static bool _mongoc_scram_step2 (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t *val_r = NULL; uint32_t val_r_len; uint8_t *val_s = NULL; uint32_t val_s_len; uint8_t *val_i = NULL; uint32_t val_i_len; uint8_t **current_val; uint32_t *current_val_len; const uint8_t *ptr; const uint8_t *next_comma; char *tmp; char *hashed_password; uint8_t decoded_salt[MONGOC_SCRAM_B64_HASH_MAX_SIZE] = {0}; int32_t decoded_salt_len; /* the decoded salt leaves four trailing bytes to add the int32 0x00000001 */ const int32_t expected_salt_length = _scram_hash_size (scram) - 4; bool rval = true; int iterations; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); if (scram->crypto.algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_1) { /* Auth spec for SCRAM-SHA-1: "The password variable MUST be the mongodb * hashed variant. The mongo hashed variant is computed as hash = HEX( * MD5( UTF8( username + ':mongo:' + plain_text_password )))" */ tmp = bson_strdup_printf ("%s:mongo:%s", scram->user, scram->pass); hashed_password = _mongoc_hex_md5 (tmp); bson_zero_free (tmp, strlen (tmp)); } else if (scram->crypto.algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_256) { /* Auth spec for SCRAM-SHA-256: "Passwords MUST be prepared with SASLprep, * per RFC 5802. Passwords are used directly for key derivation; they * MUST NOT be digested as they are in SCRAM-SHA-1." */ hashed_password = _mongoc_sasl_prep (scram->pass, (int) strlen (scram->pass), error); if (!hashed_password) { goto FAIL; } } else { BSON_ASSERT (false); } /* we need all of the incoming message for the final client proof */ if (!_mongoc_scram_buf_write ((char *) inbuf, inbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",", -1, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } for (ptr = inbuf; ptr < inbuf + inbuflen;) { switch (*ptr) { case 'r': current_val = &val_r; current_val_len = &val_r_len; break; case 's': current_val = &val_s; current_val_len = &val_s_len; break; case 'i': current_val = &val_i; current_val_len = &val_i_len; break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unknown key (%c) in sasl step 2", *ptr); goto FAIL; } ptr++; if (*ptr != '=') { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid parse state in sasl step 2"); goto FAIL; } ptr++; next_comma = (const uint8_t *) memchr (ptr, ',', (inbuf + inbuflen) - ptr); if (next_comma) { *current_val_len = (uint32_t) (next_comma - ptr); } else { *current_val_len = (uint32_t) ((inbuf + inbuflen) - ptr); } *current_val = (uint8_t *) bson_malloc (*current_val_len + 1); memcpy (*current_val, ptr, *current_val_len); (*current_val)[*current_val_len] = '\0'; if (next_comma) { ptr = next_comma + 1; } else { break; } } if (!val_r) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no r param in sasl step 2"); goto FAIL; } if (!val_s) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no s param in sasl step 2"); goto FAIL; } if (!val_i) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no i param in sasl step 2"); goto FAIL; } /* verify our nonce */ if (val_r_len < scram->encoded_nonce_len || mongoc_memcmp (val_r, scram->encoded_nonce, scram->encoded_nonce_len)) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: client nonce not repeated in sasl step 2"); } *outbuflen = 0; if (!_mongoc_scram_buf_write ( "c=biws,r=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ( (char *) val_r, val_r_len, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ((char *) outbuf, *outbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",p=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } decoded_salt_len = bson_b64_pton ((char *) val_s, decoded_salt, sizeof (decoded_salt)); if (-1 == decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to decode salt in sasl step2"); goto FAIL; } if (expected_salt_length != decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid salt length of %d in sasl step2", decoded_salt_len); goto FAIL; } iterations = (int) bson_ascii_strtoll ((char *) val_i, &tmp, 10); /* tmp holds the location of the failed to parse character. So if it's * null, we got to the end of the string and didn't have a parse error */ if (*tmp) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to parse iterations in sasl step2"); goto FAIL; } if (iterations < 0) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: iterations is negative in sasl step2"); goto FAIL; } /* drivers MUST enforce a minimum iteration count of 4096 and MUST error if * the authentication conversation specifies a lower count. This mitigates * downgrade attacks by a man-in-the-middle attacker. */ if (iterations < 4096) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: iterations must be at least 4096"); goto FAIL; } /* Save the presecrets for caching */ scram->hashed_password = bson_strdup (hashed_password); scram->iterations = iterations; memcpy (scram->decoded_salt, decoded_salt, sizeof (scram->decoded_salt)); if (scram->cache && _mongoc_scram_cache_has_presecrets (scram->cache, scram)) { _mongoc_scram_cache_apply_secrets (scram->cache, scram); } if (!*scram->salted_password) { _mongoc_scram_salt_password (scram, hashed_password, (uint32_t) strlen (hashed_password), decoded_salt, decoded_salt_len, (uint32_t) iterations); } _mongoc_scram_generate_client_proof (scram, outbuf, outbufmax, outbuflen); goto CLEANUP; BUFFER_AUTH: bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer auth message in sasl step2"); goto FAIL; BUFFER: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer sasl step2"); goto FAIL; FAIL: rval = false; CLEANUP: bson_free (val_r); bson_free (val_s); bson_free (val_i); if (hashed_password) { bson_zero_free (hashed_password, strlen (hashed_password)); } return rval; }
void gridfile_write_buffer( gridfile *gfile, const char *data, gridfs_offset length ) { int bytes_left = 0; int data_partial_len = 0; int chunks_to_write = 0; char *buffer; bson *oChunk; gridfs_offset to_write = length + gfile->pending_len; if ( to_write < DEFAULT_CHUNK_SIZE ) { /* Less than one chunk to write */ if( gfile->pending_data ) { gfile->pending_data = ( char * )bson_realloc( ( void * )gfile->pending_data, gfile->pending_len + to_write ); memcpy( gfile->pending_data + gfile->pending_len, data, length ); } else if ( to_write > 0 ) { gfile->pending_data = ( char * )bson_malloc( to_write ); memcpy( gfile->pending_data, data, length ); } gfile->pending_len += length; } else { /* At least one chunk of data to write */ /* If there's a pending chunk to be written, we need to combine * the buffer provided up to DEFAULT_CHUNK_SIZE. */ if ( gfile->pending_len > 0 ) { chunks_to_write = to_write / DEFAULT_CHUNK_SIZE; bytes_left = to_write % DEFAULT_CHUNK_SIZE; data_partial_len = DEFAULT_CHUNK_SIZE - gfile->pending_len; buffer = ( char * )bson_malloc( DEFAULT_CHUNK_SIZE ); memcpy( buffer, gfile->pending_data, gfile->pending_len ); memcpy( buffer + gfile->pending_len, data, data_partial_len ); oChunk = chunk_new( gfile->id, gfile->chunk_num, buffer, DEFAULT_CHUNK_SIZE ); mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk ); chunk_free( oChunk ); gfile->chunk_num++; gfile->length += DEFAULT_CHUNK_SIZE; data += data_partial_len; chunks_to_write--; bson_free( buffer ); } while( chunks_to_write > 0 ) { oChunk = chunk_new( gfile->id, gfile->chunk_num, data, DEFAULT_CHUNK_SIZE ); mongo_insert( gfile->gfs->client, gfile->gfs->chunks_ns, oChunk ); chunk_free( oChunk ); gfile->chunk_num++; chunks_to_write--; gfile->length += DEFAULT_CHUNK_SIZE; data += DEFAULT_CHUNK_SIZE; } bson_free( gfile->pending_data ); /* If there are any leftover bytes, store them as pending data. */ if( bytes_left == 0 ) gfile->pending_data = NULL; else { gfile->pending_data = ( char * )bson_malloc( bytes_left ); memcpy( gfile->pending_data, data, bytes_left ); } gfile->pending_len = bytes_left; } }
static int mongo_cursor_op_query( mongo_cursor *cursor ) { int res; bson empty; char *data; mongo_message *mm; bson temp; bson_iterator it; /* Clear any errors. */ bson_free( cursor->conn->lasterrstr ); cursor->conn->lasterrstr = NULL; cursor->conn->lasterrcode = 0; cursor->conn->err = 0; cursor->err = 0; /* Set up default values for query and fields, if necessary. */ if( ! cursor->query ) cursor->query = bson_empty( &empty ); else if( mongo_cursor_bson_valid( cursor, cursor->query ) != MONGO_OK ) return MONGO_ERROR; if( ! cursor->fields ) cursor->fields = bson_empty( &empty ); else if( mongo_cursor_bson_valid( cursor, cursor->fields ) != MONGO_OK ) return MONGO_ERROR; mm = mongo_message_create( 16 + /* header */ 4 + /* options */ strlen( cursor->ns ) + 1 + /* ns */ 4 + 4 + /* skip,return */ bson_size( cursor->query ) + bson_size( cursor->fields ) , 0 , 0 , MONGO_OP_QUERY ); data = &mm->data; data = mongo_data_append32( data , &cursor->options ); data = mongo_data_append( data , cursor->ns , strlen( cursor->ns ) + 1 ); data = mongo_data_append32( data , &cursor->skip ); data = mongo_data_append32( data , &cursor->limit ); data = mongo_data_append( data , cursor->query->data , bson_size( cursor->query ) ); if ( cursor->fields ) data = mongo_data_append( data , cursor->fields->data , bson_size( cursor->fields ) ); bson_fatal_msg( ( data == ( ( char * )mm ) + mm->head.len ), "query building fail!" ); res = mongo_message_send( cursor->conn , mm ); if( res != MONGO_OK ) { return MONGO_ERROR; } res = mongo_read_response( cursor->conn, ( mongo_reply ** )&( cursor->reply ) ); if( res != MONGO_OK ) { return MONGO_ERROR; } if( cursor->reply->fields.num == 1 ) { bson_init_data( &temp, &cursor->reply->objs ); if( bson_find( &it, &temp, "$err" ) ) { cursor->conn->lasterrstr = (char *)bson_malloc( bson_iterator_string_len( &it ) ); strcpy( cursor->conn->lasterrstr, bson_iterator_string( &it ) ); bson_find( &it, &temp, "code" ); cursor->conn->lasterrcode = bson_iterator_int( &it ); cursor->err = MONGO_CURSOR_QUERY_FAIL; return MONGO_ERROR; } } cursor->seen += cursor->reply->fields.num; cursor->flags |= MONGO_CURSOR_QUERY_SENT; return MONGO_OK; }
MONGO_EXPORT bson* bson_create( void ) { bson *b = (bson*)bson_malloc(sizeof(bson)); b->data = NULL; ASSIGN_SIGNATURE(b, MONGO_SIGNATURE); return b; }
static void * main_thread (void *data) { mock_server_t *server = (mock_server_t *)data; mongoc_socket_t *client_sock; bool stopped; uint16_t port; mongoc_stream_t *client_stream; worker_closure_t *closure; mongoc_thread_t thread; mongoc_array_t worker_threads; size_t i; mongoc_mutex_lock (&server->mutex); server->running = true; mongoc_cond_signal (&server->cond); mongoc_mutex_unlock (&server->mutex); for (; ;) { client_sock = mongoc_socket_accept_ex ( server->sock, bson_get_monotonic_time () + TIMEOUT, &port); mongoc_mutex_lock (&server->mutex); stopped = server->stopped; mongoc_mutex_unlock (&server->mutex); if (stopped) { break; } if (client_sock) { if (mock_server_get_verbose (server)) { printf ("%5.2f %hu -> server port %hu (connected)\n", mock_server_get_uptime_sec (server), port, server->port); fflush (stdout); } client_stream = mongoc_stream_socket_new (client_sock); #ifdef MONGOC_ENABLE_SSL mongoc_mutex_lock (&server->mutex); if (server->ssl) { server->ssl_opts.weak_cert_validation = 1; client_stream = mongoc_stream_tls_new (client_stream, &server->ssl_opts, 0); if (!client_stream) { mongoc_mutex_unlock (&server->mutex); perror ("Failed to attach tls stream"); break; } } mongoc_mutex_unlock (&server->mutex); #endif closure = (worker_closure_t *)bson_malloc (sizeof *closure); closure->server = server; closure->client_stream = client_stream; closure->port = port; mongoc_thread_create (&thread, worker_thread, closure); mongoc_mutex_lock (&server->mutex); _mongoc_array_append_val (&server->worker_threads, thread); mongoc_mutex_unlock (&server->mutex); } } /* copy list of worker threads and join them all */ _mongoc_array_init (&worker_threads, sizeof (mongoc_thread_t)); mongoc_mutex_lock (&server->mutex); _mongoc_array_copy (&worker_threads, &server->worker_threads); mongoc_mutex_unlock (&server->mutex); for (i = 0; i < worker_threads.len; i++) { mongoc_thread_join ( _mongoc_array_index (&worker_threads, mongoc_thread_t, i)); } _mongoc_array_destroy (&worker_threads); mongoc_mutex_lock (&server->mutex); server->running = false; mongoc_mutex_unlock (&server->mutex); return NULL; }
/* Parse server-first-message of the form: * r=client-nonce|server-nonce,s=user-salt,i=iteration-count * * Generate client-final-message of the form: * c=channel-binding(base64),r=client-nonce|server-nonce,p=client-proof */ static bool _mongoc_scram_step2 (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t *val_r = NULL; uint32_t val_r_len; uint8_t *val_s = NULL; uint32_t val_s_len; uint8_t *val_i = NULL; uint32_t val_i_len; uint8_t **current_val; uint32_t *current_val_len; const uint8_t *ptr; const uint8_t *next_comma; char *tmp; char *hashed_password; uint8_t decoded_salt[MONGOC_SCRAM_B64_HASH_SIZE] = {0}; int32_t decoded_salt_len; bool rval = true; int iterations; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); /* all our passwords go through md5 thanks to MONGODB-CR */ tmp = bson_strdup_printf ("%s:mongo:%s", scram->user, scram->pass); hashed_password = _mongoc_hex_md5 (tmp); bson_zero_free (tmp, strlen (tmp)); /* we need all of the incoming message for the final client proof */ if (!_mongoc_scram_buf_write ((char *) inbuf, inbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",", -1, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } for (ptr = inbuf; ptr < inbuf + inbuflen;) { switch (*ptr) { case 'r': current_val = &val_r; current_val_len = &val_r_len; break; case 's': current_val = &val_s; current_val_len = &val_s_len; break; case 'i': current_val = &val_i; current_val_len = &val_i_len; break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unknown key (%c) in sasl step 2", *ptr); goto FAIL; break; } ptr++; if (*ptr != '=') { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid parse state in sasl step 2"); goto FAIL; } ptr++; next_comma = (const uint8_t *) memchr (ptr, ',', (inbuf + inbuflen) - ptr); if (next_comma) { *current_val_len = (uint32_t) (next_comma - ptr); } else { *current_val_len = (uint32_t) ((inbuf + inbuflen) - ptr); } *current_val = (uint8_t *) bson_malloc (*current_val_len + 1); memcpy (*current_val, ptr, *current_val_len); (*current_val)[*current_val_len] = '\0'; if (next_comma) { ptr = next_comma + 1; } else { break; } } if (!val_r) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no r param in sasl step 2"); goto FAIL; } if (!val_s) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no s param in sasl step 2"); goto FAIL; } if (!val_i) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no i param in sasl step 2"); goto FAIL; } /* verify our nonce */ if (val_r_len < scram->encoded_nonce_len || mongoc_memcmp (val_r, scram->encoded_nonce, scram->encoded_nonce_len)) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: client nonce not repeated in sasl step 2"); } *outbuflen = 0; if (!_mongoc_scram_buf_write ( "c=biws,r=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ( (char *) val_r, val_r_len, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ((char *) outbuf, *outbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",p=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } decoded_salt_len = bson_b64_pton ((char *) val_s, decoded_salt, sizeof (decoded_salt)); if (-1 == decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to decode salt in sasl step2"); goto FAIL; } if (16 != decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid salt length of %d in sasl step2", decoded_salt_len); goto FAIL; } iterations = (int) bson_ascii_strtoll ((char *) val_i, &tmp, 10); /* tmp holds the location of the failed to parse character. So if it's * null, we got to the end of the string and didn't have a parse error */ if (*tmp) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to parse iterations in sasl step2"); goto FAIL; } if (iterations < 0) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: iterations is negative in sasl step2"); goto FAIL; } /* Save the presecrets for caching */ scram->hashed_password = bson_strdup (hashed_password); scram->iterations = iterations; memcpy (scram->decoded_salt, decoded_salt, sizeof (scram->decoded_salt)); if (scram->cache && _mongoc_scram_cache_has_presecrets (scram->cache, scram)) { _mongoc_scram_cache_apply_secrets (scram->cache, scram); } if (!*scram->salted_password) { _mongoc_scram_salt_password (scram, hashed_password, (uint32_t) strlen (hashed_password), decoded_salt, decoded_salt_len, (uint32_t) iterations); } _mongoc_scram_generate_client_proof (scram, outbuf, outbufmax, outbuflen); goto CLEANUP; BUFFER_AUTH: bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer auth message in sasl step2"); goto FAIL; BUFFER: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer sasl step2"); goto FAIL; FAIL: rval = false; CLEANUP: bson_free (val_r); bson_free (val_s); bson_free (val_i); if (hashed_password) { bson_zero_free (hashed_password, strlen (hashed_password)); } return rval; }
void bson_copy(bson* out, const bson* in){ if (!out) return; out->data = bson_malloc(bson_size(in)); out->owned = 1; memcpy(out->data, in->data, bson_size(in)); }
static void test_random_write(void) { mongo conn[1]; gridfs gfs[1]; gridfile* gfile; char *data_before = (char*)bson_malloc( UPPER ); char *random_data = (char*)bson_malloc( UPPER ); char *buf = (char*) bson_malloc( UPPER ); int64_t i; FILE *fd; srand((unsigned int) time( NULL ) ); INIT_SOCKETS_FOR_WINDOWS; CONN_CLIENT_TEST; GFS_INIT; fill_buffer_randomly( data_before, UPPER ); fill_buffer_randomly( random_data, UPPER ); for ( i = LOWER; i <= UPPER; i += DELTA ) { int64_t j = i / 2 - 3; gridfs_offset bytes_to_write_first; int n; /* Input from buffer */ gridfs_store_buffer( gfs, data_before, i, "input-buffer", "text/html", GRIDFILE_DEFAULT ); if ( i > DEFAULT_CHUNK_SIZE * 4 ) { n = DEFAULT_CHUNK_SIZE * 3 + 6; memcpy(&data_before[j], random_data, n); // Let's overwrite the buffer with bytes crossing multiple chunks bytes_to_write_first = 10; } else { n = 6; memcpy(random_data, "123456", n); strncpy(&data_before[j], random_data, n); // Let's overwrite the buffer with a few some bytes bytes_to_write_first = 0; } gfile = gridfile_create(); ASSERT(gridfs_find_filename(gfs, "input-buffer", gfile) == 0); gridfile_writer_init(gfile, gfs, "input-buffer", "text/html", GRIDFILE_DEFAULT ); gridfile_seek(gfile, j); // Seek into the same buffer position within the GridFS file if ( bytes_to_write_first ) { ASSERT( gridfile_write_buffer(gfile, random_data, bytes_to_write_first) == bytes_to_write_first ); // Let's write 10 bytes first, and later the rest } ASSERT( gridfile_write_buffer(gfile, &random_data[bytes_to_write_first], n - bytes_to_write_first) == n - bytes_to_write_first ); // Try to write to the existing GridFS file on the position given by j gridfile_seek(gfile, j); gridfile_read_buffer( gfile, buf, n ); ASSERT(memcmp( buf, &data_before[j], n) == 0); gridfile_writer_done(gfile); ASSERT(gfile->pos == (gridfs_offset)(j + n)); gridfile_dealloc(gfile); test_gridfile( gfs, data_before, j + n > i ? j + n : i, "input-buffer", "text/html" ); /* Input from file */ fd = fopen( "input-file", "w" ); fwrite( data_before, sizeof( char ), (size_t) (j + n > i ? j + n : i), fd ); fclose( fd ); gridfs_store_file( gfs, "input-file", "input-file", "text/html", GRIDFILE_DEFAULT ); test_gridfile( gfs, data_before, j + n > i ? j + n : i, "input-file", "text/html" ); } gridfs_destroy( gfs ); mongo_disconnect( conn ); mongo_destroy( conn ); free( data_before ); free( random_data ); free( buf ); /* Clean up files. */ gridfs_test_unlink( "input-file" ); gridfs_test_unlink( "output" ); }
int gridfs_init( mongo *client, const char *dbname, const char *prefix, gridfs *gfs ) { int options; bson b; bson_bool_t success; gfs->client = client; /* Allocate space to own the dbname */ gfs->dbname = ( const char * )bson_malloc( strlen( dbname )+1 ); strcpy( ( char * )gfs->dbname, dbname ); /* Allocate space to own the prefix */ if ( prefix == NULL ) prefix = "fs"; gfs->prefix = ( const char * )bson_malloc( strlen( prefix )+1 ); strcpy( ( char * )gfs->prefix, prefix ); /* Allocate space to own files_ns */ gfs->files_ns = ( const char * ) bson_malloc ( strlen( prefix )+strlen( dbname )+strlen( ".files" )+2 ); strcpy( ( char * )gfs->files_ns, dbname ); strcat( ( char * )gfs->files_ns, "." ); strcat( ( char * )gfs->files_ns, prefix ); strcat( ( char * )gfs->files_ns, ".files" ); /* Allocate space to own chunks_ns */ gfs->chunks_ns = ( const char * ) bson_malloc( strlen( prefix ) + strlen( dbname ) + strlen( ".chunks" ) + 2 ); strcpy( ( char * )gfs->chunks_ns, dbname ); strcat( ( char * )gfs->chunks_ns, "." ); strcat( ( char * )gfs->chunks_ns, prefix ); strcat( ( char * )gfs->chunks_ns, ".chunks" ); bson_init( &b ); bson_append_int( &b, "filename", 1 ); bson_finish( &b ); options = 0; success = ( mongo_create_index( gfs->client, gfs->files_ns, &b, options, NULL ) == MONGO_OK ); bson_destroy( &b ); if ( !success ) { bson_free( ( char * )gfs->dbname ); bson_free( ( char * )gfs->prefix ); bson_free( ( char * )gfs->files_ns ); bson_free( ( char * )gfs->chunks_ns ); return MONGO_ERROR; } bson_init( &b ); bson_append_int( &b, "files_id", 1 ); bson_append_int( &b, "n", 1 ); bson_finish( &b ); options = MONGO_INDEX_UNIQUE; success = ( mongo_create_index( gfs->client, gfs->chunks_ns, &b, options, NULL ) == MONGO_OK ); bson_destroy( &b ); if ( !success ) { bson_free( ( char * )gfs->dbname ); bson_free( ( char * )gfs->prefix ); bson_free( ( char * )gfs->files_ns ); bson_free( ( char * )gfs->chunks_ns ); return MONGO_ERROR; } return MONGO_OK; }
/* generate client-first-message: * n,a=authzid,n=encoded-username,r=client-nonce * * note that a= is optional, so we aren't dealing with that here */ static bool _mongoc_scram_start (mongoc_scram_t *scram, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t nonce[24]; const char *ptr; bool rval = true; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); if (!scram->user) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: username is not set"); goto FAIL; } /* auth message is as big as the outbuf just because */ scram->auth_message = (uint8_t *) bson_malloc (outbufmax); scram->auth_messagemax = outbufmax; /* the server uses a 24 byte random nonce. so we do as well */ if (1 != _mongoc_rand_bytes (nonce, sizeof (nonce))) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not generate a cryptographically " "secure nonce in sasl step 1"); goto FAIL; } scram->encoded_nonce_len = bson_b64_ntop (nonce, sizeof (nonce), scram->encoded_nonce, sizeof (scram->encoded_nonce)); if (-1 == scram->encoded_nonce_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not encode nonce"); goto FAIL; } if (!_mongoc_scram_buf_write ("n,,n=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } for (ptr = scram->user; *ptr; ptr++) { /* RFC 5802 specifies that ',' and '=' and encoded as '=2C' and '=3D' * respectively in the user name */ switch (*ptr) { case ',': if (!_mongoc_scram_buf_write ( "=2C", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; case '=': if (!_mongoc_scram_buf_write ( "=3D", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; default: if (!_mongoc_scram_buf_write (ptr, 1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; } } if (!_mongoc_scram_buf_write (",r=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write (scram->encoded_nonce, scram->encoded_nonce_len, outbuf, outbufmax, outbuflen)) { goto BUFFER; } /* we have to keep track of the conversation to create a client proof later * on. This copies the message we're crafting from the 'n=' portion onwards * into a buffer we're managing */ if (!_mongoc_scram_buf_write ((char *) outbuf + 3, *outbuflen - 3, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",", -1, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } goto CLEANUP; BUFFER_AUTH: bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer auth message in sasl step1"); goto FAIL; BUFFER: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer sasl step1"); goto FAIL; FAIL: rval = false; CLEANUP: return rval; }