/** * Authenticates a connection * * Returns 1 when it worked, or 0 when it didn't - with the error_message set. */ int mongo_connection_authenticate(mongo_con_manager *manager, mongo_connection *con, char *database, char *username, char *password, char *nonce, char **error_message) { mcon_str *packet; char *data_buffer, *errmsg; double ok; char *ptr; char *salted; int length; char *hash, *key; mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "authenticate: start"); /* Calculate hash=md5(${username}:mongo:${password}) */ length = strlen(username) + 7 + strlen(password) + 1; salted = malloc(length); snprintf(salted, length, "%s:mongo:%s", username, password); hash = mongo_util_md5_hex(salted, length - 1); /* -1 to chop off \0 */ free(salted); mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "authenticate: hash=md5(%s:mongo:%s) = %s", username, password, hash); /* Calculate key=md5(${nonce}${username}${hash}) */ length = strlen(nonce) + strlen(username) + strlen(hash) + 1; salted = malloc(length); snprintf(salted, length, "%s%s%s", nonce, username, hash); key = mongo_util_md5_hex(salted, length - 1); /* -1 to chop off \0 */ free(salted); mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "authenticate: key=md5(%s%s%s) = %s", nonce, username, hash, key); packet = bson_create_authenticate_packet(con, database, username, nonce, key); free(hash); free(key); if (!mongo_connect_send_packet(manager, con, packet, &data_buffer, error_message)) { free(data_buffer); return 0; } /* Find data fields */ ptr = data_buffer + sizeof(int32_t); /* Skip the length */ /* Find errmsg */ if (bson_find_field_as_double(ptr, "ok", &ok)) { if (ok > 0) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "authentication successful"); } else { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "authentication failed"); } } if (bson_find_field_as_string(ptr, "errmsg", &errmsg)) { *error_message = malloc(256); snprintf(*error_message, 256, "Authentication failed on database '%s' with username '%s': %s", database, username, errmsg); free(data_buffer); return 0; } free(data_buffer); return 1; }
/** * Sends the db.authenticate() command packet * * Returns: * 0: when it didn't work - with the error_message set (extracted from the 'errmsg' field if possible) * 1: when it worked */ int mongo_connection_authenticate_cmd(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, char *database, char *username, mcon_str *packet, char **error_message) { char *data_buffer, *errmsg; double ok; char *ptr; if (!mongo_connect_send_packet(manager, con, options, packet, &data_buffer, error_message)) { return 0; } /* Find data fields */ ptr = data_buffer + sizeof(int32_t); /* Skip the length */ /* Find errmsg */ if (bson_find_field_as_double(ptr, "ok", &ok)) { if (ok > 0) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "authentication successful"); } else { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "authentication failed"); } } if (bson_find_field_as_string(ptr, "errmsg", &errmsg)) { *error_message = malloc(256); snprintf(*error_message, 256, "Authentication failed on database '%s' with username '%s': %s", database, username, errmsg); free(data_buffer); return 0; } free(data_buffer); return 1; }
int mongo_connection_authenticate_saslcontinue(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, int32_t conversation_id, char *payload, int payload_len, char **out_payload, int *out_payload_len, unsigned char *done, char **error_message) { mcon_str *packet; char *data_buffer; char *ptr; double ok; char *errmsg; int32_t out_conversation_id; mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "connection_authenticate_saslcontinue: continuing SASL authentication to '%s'", con->hash); packet = bson_create_saslcontinue_packet(con, conversation_id, payload, payload_len); if (!mongo_connect_send_packet(manager, con, options, packet, &data_buffer, error_message)) { return 0; } /* Find data fields */ ptr = data_buffer + sizeof(int32_t); /* Skip the length */ if (bson_find_field_as_double(ptr, "ok", &ok)) { if (ok > 0) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "SASL continue successful"); } else { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "SASL continue failed"); if (bson_find_field_as_string(ptr, "errmsg", &errmsg)) { int errlen = strlen("SASL Authentication failed on database '': ") + strlen(server_def->db) + strlen(errmsg); *error_message = malloc(errlen); snprintf(*error_message, errlen, "SASL Authentication failed on database '%s': %s", server_def->db, errmsg); } else { int errlen = strlen("SASL Authentication failed on database ''") + strlen(server_def->db); *error_message = malloc(errlen); snprintf(*error_message, errlen, "SASL Authentication failed on database '%s'", server_def->db); } free(data_buffer); return 0; } } if (bson_find_field_as_int32(ptr, "conversationId", &out_conversation_id)) { if (out_conversation_id != conversation_id) { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "SASL continue failed: Got wrong conversation_id back! Expected %d but got %d", conversation_id, out_conversation_id); free(data_buffer); return 0; } bson_find_field_as_stringl(ptr, "payload", out_payload, out_payload_len, 1); bson_find_field_as_bool(ptr, "done", done); } free(data_buffer); return (int)ok; }
int mongo_connection_authenticate_saslstart(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, char *mechanism, char *payload, unsigned int payload_len, char **out_payload, int *out_payload_len, int32_t *out_conversation_id, char **error_message) { mcon_str *packet; char *data_buffer; char *ptr; char *smechanism; double ok; char *errmsg; mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "connection_authenticate_sasl: Starting SASL authentication process to '%s'", con->hash); if (server_def->mechanism == MONGO_AUTH_MECHANISM_MONGODB_CR) { *error_message = strdup("Invalid authentication mechanism. Expected SASL mechanism, got MongoDB-CR"); return 0; } packet = bson_create_saslstart_packet(con, server_def->authdb ? server_def->authdb : server_def->db, mechanism, payload, payload_len); if (!mongo_connect_send_packet(manager, con, options, packet, &data_buffer, error_message)) { return 0; } /* Find data fields */ ptr = data_buffer + sizeof(int32_t); /* Skip the length */ if (bson_find_field_as_double(ptr, "ok", &ok)) { if (ok > 0) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "SASL request successful"); } else { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "SASL request failed"); if (bson_find_field_as_string(ptr, "errmsg", &errmsg)) { *error_message = malloc(256); snprintf(*error_message, 256, "SASL Authentication failed on database '%s': %s", server_def->db, errmsg); } else { *error_message = "SASL Authentication failed"; } if (bson_find_field_as_document(ptr, "supportedMechanisms", (char**) &smechanism)) { /* TODO: Retrieve a list of supportedMechanisms and return it somehow */ } free(data_buffer); return 0; } } if (bson_find_field_as_int32(ptr, "conversationId", out_conversation_id)) { bson_find_field_as_stringl(ptr, "payload", out_payload, out_payload_len, 1); } free(data_buffer); return 1; }