Esempio n. 1
0
// Check an embedded document of the form { "article/#": "r", "article/+/comments": "rw", "ballotbox": "w" }
bool be_mongo_check_acl_topics_map(const bson_iter_t *topics, const char *req_topic, int req_access, const char *clientid, const char *username)
{
	bson_iter_t iter;
	bson_iter_recurse(topics, &iter);
	bool granted = false;

	// Loop through mapped topics, allowing for the fact that a two different ACLs may have complementary permissions.
	while (bson_iter_next(&iter) && !granted) {
		const char *permitted_topic = bson_iter_key(&iter);
		bool topic_matches = false;

		char *expanded;

		t_expand(clientid, username, permitted_topic, &expanded);
		if (expanded && *expanded) {
			mosquitto_topic_matches_sub(expanded, req_topic, &topic_matches);
			free(expanded);

			if (topic_matches) {
				bson_type_t val_type = bson_iter_type(&iter);
				if (val_type == BSON_TYPE_UTF8) {
					// NOTE: can req_access be any other value than 1 or 2?
					// in that case this may not be correct:
					// e.g. req_access == 3 (rw) -> granted = (3 & 1 > 0) == true
					const char *permission = bson_iter_utf8(&iter, NULL);
					if (strcmp(permission, "r") == 0) {
						granted = (req_access & 1) > 0;
					} else if (strcmp(permission, "w") == 0) {
						granted = (req_access & 2) > 0;
					} else if (strcmp(permission, "rw") == 0) {
						granted = true;
					}
				}
			}
		}
	}
	return granted;
}
Esempio n. 2
0
// Check an embedded array of the form [ "public/#", "private/myid/#" ]
bool be_mongo_check_acl_topics_array(const bson_iter_t *topics, const char *req_topic, const char *clientid, const char *username)
{
	bson_iter_t iter;
	bson_iter_recurse(topics, &iter);

	while (bson_iter_next(&iter)) {
		const char *permitted_topic = bson_iter_utf8(&iter, NULL);
		bool topic_matches = false;

		char *expanded;

		t_expand(clientid, username, permitted_topic, &expanded);
		if (expanded && *expanded) {
			mosquitto_topic_matches_sub(expanded, req_topic, &topic_matches);
			free(expanded);

			if (topic_matches) {
				return true;
			}
		}
	}
	return false;
}
Esempio n. 3
0
int be_pg_aclcheck(void *handle, const char *clientid, const char *username, const char *topic, int acc)
{
	struct pg_backend *conf = (struct pg_backend *)handle;
	char *v = NULL;
	int match = 0;
	bool bf;
	PGresult *res = NULL;

	_log( LOG_DEBUG, "USERNAME: %s, TOPIC: %s, acc: %d", username, topic, acc );


	if (!conf || !conf->aclquery)
		return (FALSE);

	int localacc = htonl(acc);

	const char *values[2] = {username,(char*)&localacc};
	int lengths[2] = {strlen(username),sizeof(localacc)};
	int binary[2] = {0,1};

	res = PQexecParams(conf->conn, conf->aclquery, 2, NULL, values, lengths, binary, 0);

	if ( PQresultStatus(res) != PGRES_TUPLES_OK )
	{
		fprintf(stderr, "%s\n", PQresultErrorMessage(res));
		match = BACKEND_ERROR;
		goto out;
	}

	if (PQnfields(res) != 1) {
		fprintf(stderr, "numfields not ok\n");
		goto out;
	}

	int rec_count = PQntuples(res);
	int row = 0;
	for ( row = 0; row < rec_count; row++ ) {
		if ( (v = PQgetvalue(res,row,0) ) != NULL) {

			/* Check mosquitto_match_topic. If true,
			 * if true, set match and break out of loop. */

                        char *expanded;

                        t_expand(clientid, username, v, &expanded);
                        if (expanded && *expanded) {
                                mosquitto_topic_matches_sub(expanded, topic, &bf);
                                match |= bf;
                                _log(LOG_DEBUG, "  postgres: topic_matches(%s, %s) == %d",
                                        expanded, v, bf);

				free(expanded);
                        }
		}

		if ( match != 0 )
		{
			break;
		}
	}

out:

	PQclear(res);

	return (match);
}
Esempio n. 4
0
int be_pg_aclcheck(void *handle, const char *clientid, const char *username, const char *topic, int acc)
{
	struct pg_backend *conf = (struct pg_backend *)handle;
	char *v = NULL;
	int match = BACKEND_DEFER;
	bool bf;
	PGresult *res = NULL;

	_log(LOG_DEBUG, "USERNAME: %s, TOPIC: %s, acc: %d", username, topic, acc);


	if (!conf || !conf->aclquery)
		return BACKEND_DEFER;

	const int buflen = 11;
	//10 for 2^32 + 1
	char accbuffer[buflen];
	snprintf(accbuffer, buflen, "%d", acc);

	const char *values[2] = {username, accbuffer};
	int lengths[2] = {strlen(username), buflen};

	res = PQexecParams(conf->conn, conf->aclquery, 2, NULL, values, lengths, NULL, 0);

	if (PQresultStatus(res) != PGRES_TUPLES_OK) {
		fprintf(stderr, "%s\n", PQresultErrorMessage(res));
		match = BACKEND_ERROR;

		//try to reset connection if failing because of database connection lost
		if(PQstatus(conf->conn) == CONNECTION_BAD){
			_log(LOG_NOTICE, "Noticed a postgres connection loss. Trying to reconnect ...\n");
			//try to reinitiate the database connection
			PQreset(conf->conn);
		}

		goto out;
	}
	if (PQnfields(res) != 1) {
		fprintf(stderr, "numfields not ok\n");
		goto out;
	}
	int rec_count = PQntuples(res);
	int row = 0;
	for (row = 0; row < rec_count; row++) {
		if ((v = PQgetvalue(res, row, 0)) != NULL) {

			/*
			 * Check mosquitto_match_topic. If true, if true, set
			 * match and break out of loop.
			 */

			char *expanded;

			t_expand(clientid, username, v, &expanded);
			if (expanded && *expanded) {
				mosquitto_topic_matches_sub(expanded, topic, &bf);
				if (bf) match = BACKEND_ALLOW;
				_log(LOG_DEBUG, "  postgres: topic_matches(%s, %s) == %d",
				     expanded, v, bf);

				free(expanded);
			}
		}
		if (match != BACKEND_DEFER) {
			break;
		}
	}

out:

	PQclear(res);

	return (match);
}