Skip to content

Commit

Permalink
PHPC-1647: Use mongoc_client_new_from_uri_with_error
Browse files Browse the repository at this point in the history
This allows PHPC to defer entirely to libmongoc for cross-option URI validation

Bump libmongoc to 1.21-dev

Build changes are ported from upstream CMake changes (see: CDRIVER-4249)
  • Loading branch information
jmikola committed Jan 5, 2022
1 parent 968958f commit ab44b0c
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 175 deletions.
4 changes: 2 additions & 2 deletions config.m4
Expand Up @@ -294,6 +294,7 @@ if test "$PHP_MONGODB" != "no"; then
PHP_MONGODB_BUNDLED_CFLAGS="$STD_CFLAGS -DBSON_COMPILATION -DMONGOC_COMPILATION"
dnl TODO: MONGOCRYPT-219 makes the -std argument obsolete
PHP_MONGODB_LIBMONGOCRYPT_CFLAGS="-DKMS_MSG_STATIC -std=gnu99"
PHP_MONGODB_ZLIB_CFLAGS=""

dnl M4 doesn't know if we're building statically or as a shared module, so
dnl attempt to include both paths while ignoring errors. If neither path
Expand Down Expand Up @@ -430,8 +431,7 @@ if test "$PHP_MONGODB" != "no"; then
])

if test "x$bundled_zlib" = "xyes"; then
PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS"
AC_CHECK_HEADER([unistd.h], [PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_ZLIB_CFLAGS -DHAVE_UNISTD_H=1"], [])
PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_ZLIB_CFLAGS"
PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/zlib-1.2.11/], $PHP_MONGODB_ZLIB_SOURCES, $PHP_MONGODB_ZLIB_CFLAGS)
PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/zlib-1.2.11/])
PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/zlib-1.2.11/])
Expand Down
3 changes: 2 additions & 1 deletion config.w32
Expand Up @@ -147,7 +147,8 @@ if (PHP_MONGODB != "no") {
BSON_HAVE_SYSCALL_TID: 0,
BSON_HAVE_DECIMAL128: 0,
BSON_HAVE_GMTIME_R: 0,
BSON_HAVE_RAND_R: 0
BSON_HAVE_RAND_R: 0,
BSON_HAVE_ARC4RANDOM_BUF: 0
};

if (CHECK_FUNC_IN_HEADER("stdio.h", "_set_output_format")) {
Expand Down
153 changes: 9 additions & 144 deletions php_phongo.c
Expand Up @@ -1435,126 +1435,6 @@ static const char* php_phongo_bson_type_to_string(bson_type_t type) /* {{{ */
bson_iter_key(&(iter)), \
php_phongo_bson_type_to_string(bson_iter_type(&(iter))))

static bool php_phongo_uri_finalize_auth(mongoc_uri_t* uri) /* {{{ */
{
const bson_t* credentials = mongoc_uri_get_credentials(uri);
bson_iter_t iter;
const char* source = NULL;
const char* username = mongoc_uri_get_username(uri);
bool require_auth = username != NULL;

if (bson_iter_init_find_case(&iter, credentials, MONGOC_URI_AUTHSOURCE)) {
source = bson_iter_utf8(&iter, NULL);
require_auth = true;
}

/* authSource with GSSAPI or X509 should always be external */
if (mongoc_uri_get_auth_mechanism(uri)) {
if (!strcasecmp(mongoc_uri_get_auth_mechanism(uri), "GSSAPI") ||
!strcasecmp(mongoc_uri_get_auth_mechanism(uri), "MONGODB-X509")) {

if (source) {
if (strcasecmp(source, "$external")) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: GSSAPI and X509 require \"$external\" authSource.");
return false;
}
} else {
mongoc_uri_set_auth_source(uri, "$external");
}
}

/* Mechanisms other than MONGODB-X509 and MONGODB-AWS require a username */
if (strcasecmp(mongoc_uri_get_auth_mechanism(uri), "MONGODB-X509") &&
strcasecmp(mongoc_uri_get_auth_mechanism(uri), "MONGODB-AWS")) {
if (!mongoc_uri_get_username(uri) ||
!strcmp(mongoc_uri_get_username(uri), "")) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: '%s' authentication mechanism requires username.", mongoc_uri_get_auth_mechanism(uri));
return false;
}
}

/* MONGODB-X509 errors if a password is supplied. */
if (!strcasecmp(mongoc_uri_get_auth_mechanism(uri), "MONGODB-X509")) {
if (mongoc_uri_get_password(uri)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: X509 authentication mechanism does not accept a password.");
return false;
}
}
} else if (require_auth) {
if (source && strcmp(source, "$external") != 0 && (!username || strcmp(username, "") == 0)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: Default authentication mechanism requires username.");
return false;
}
}

return true;
} /* }}} */

static bool php_phongo_uri_finalize_directconnection(mongoc_uri_t* uri) /* {{{ */
{
const mongoc_host_list_t* hosts;

if (!mongoc_uri_get_option_as_bool(uri, MONGOC_URI_DIRECTCONNECTION, false)) {
return true;
}

/* Per the URI options spec, directConnection conflicts with multiple hosts
* and SRV URIs, which may resolve to multiple hosts. */
if (!strncmp(mongoc_uri_get_string(uri), "mongodb+srv://", 14)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: SRV URI not allowed with directConnection option.");
return false;
}

hosts = mongoc_uri_get_hosts(uri);

if (hosts && hosts->next) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: Multiple seeds not allowed with directConnection option.");
return false;
}

return true;
} /* }}} */

static bool php_phongo_uri_finalize_tls(mongoc_uri_t* uri) /* {{{ */
{
const bson_t* options;
bson_iter_t iter;

if (!(options = mongoc_uri_get_options(uri))) {
return true;
}

if (bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSINSECURE) &&
(bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES) ||
bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES) ||
bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK) ||
bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK))) {
phongo_throw_exception(
PHONGO_ERROR_INVALID_ARGUMENT,
"Failed to parse URI options: %s may not be combined with %s, %s, %s, or %s.",
MONGOC_URI_TLSINSECURE,
MONGOC_URI_TLSALLOWINVALIDCERTIFICATES,
MONGOC_URI_TLSALLOWINVALIDHOSTNAMES,
MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK,
MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK);
return false;
}

if (bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES) &&
(bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK) ||
bson_iter_init_find_case(&iter, options, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK))) {
phongo_throw_exception(
PHONGO_ERROR_INVALID_ARGUMENT,
"Failed to parse URI options: %s may not be combined with %s or %s.",
MONGOC_URI_TLSALLOWINVALIDCERTIFICATES,
MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK,
MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK);
return false;
}

return true;
} /* }}} */

static bool php_phongo_apply_options_to_uri(mongoc_uri_t* uri, bson_t* options) /* {{{ */
{
bson_iter_t iter;
Expand Down Expand Up @@ -1755,17 +1635,6 @@ static bool php_phongo_apply_options_to_uri(mongoc_uri_t* uri, bson_t* options)
}
}

/* Validate any interactions between URI options */
if (!php_phongo_uri_finalize_auth(uri)) {
/* Exception should already have been thrown */
return false;
}

if (!php_phongo_uri_finalize_directconnection(uri)) {
/* Exception should already have been thrown */
return false;
}

return true;
} /* }}} */

Expand Down Expand Up @@ -2566,7 +2435,9 @@ static void php_phongo_set_handshake_data(zval* driverOptions)

static mongoc_client_t* php_phongo_make_mongo_client(const mongoc_uri_t* uri, zval* driverOptions) /* {{{ */
{
const char *mongoc_version, *bson_version;
const char * mongoc_version, *bson_version;
mongoc_client_t* client;
bson_error_t error = { 0 };

#ifdef HAVE_SYSTEM_LIBMONGOC
mongoc_version = mongoc_get_version();
Expand All @@ -2592,7 +2463,11 @@ static mongoc_client_t* php_phongo_make_mongo_client(const mongoc_uri_t* uri, zv

php_phongo_set_handshake_data(driverOptions);

return mongoc_client_new_from_uri(uri);
if (!(client = mongoc_client_new_from_uri_with_error(uri, &error))) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: %s", error.message);
}

return client;
} /* }}} */

/* Adds a client to the appropriate registry. Persistent and request-scoped
Expand Down Expand Up @@ -3321,22 +3196,12 @@ void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string,
if (EG(exception)) {
goto cleanup;
}

if (!php_phongo_uri_finalize_tls(uri)) {
/* Exception should already have been thrown */
goto cleanup;
}
#else
if (mongoc_uri_get_tls(uri)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot create SSL client. SSL is not enabled in this build.");
goto cleanup;
}
#endif

manager->client = php_phongo_make_mongo_client(uri, driverOptions);

if (!manager->client) {
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to create Manager from URI: '%s'", uri_string);
/* Exception should already have been thrown */
goto cleanup;
}

Expand Down
13 changes: 13 additions & 0 deletions scripts/autotools/libbson/FindDependencies.m4
@@ -1,3 +1,12 @@
if test "$os_win32" != "yes"; then
PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -D_DEFAULT_SOURCE"
fi

# Enable macOS extensions for strlcpy and arc4random

This comment has been minimized.

Copy link
@eramongodb

eramongodb Jan 5, 2022

@jmikola Is _DARWIN_C_SOURCE still necessary given _DEFAULT_SOURCE? It did not appear to be so given C driver Evergreen tasks.

This comment has been minimized.

Copy link
@jmikola

jmikola Jan 5, 2022

Author Member

Ah, I didn't realize you had removed this from mongodb/mongo-c-driver#920 before merging. We actually don't test macOS in CI at the moment, so I can't say for certain if this was required. I'm happy to remove it for now and we can revisit if it comes up down the line.

This comment has been minimized.

Copy link
@jmikola

jmikola Jan 5, 2022

Author Member

Removed in 91a1585.

if test "$os_darwin" = "yes"; then
PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -D_DARWIN_C_SOURCE=1"
fi

# Check for strnlen()
dnl AC_CHECK_FUNC isn't properly respecting _XOPEN_SOURCE for strnlen for unknown reason
AC_SUBST(BSON_HAVE_STRNLEN, 0)
Expand Down Expand Up @@ -79,6 +88,10 @@ AC_CHECK_FUNC(gmtime_r, [AC_SUBST(BSON_HAVE_GMTIME_R, 1)])
AC_SUBST(BSON_HAVE_RAND_R, 0)
AC_CHECK_FUNC(rand_r, [AC_SUBST(BSON_HAVE_RAND_R, 1)])

# Check for arc4random_buf()
AC_SUBST(BSON_HAVE_ARC4RANDOM_BUF, 0)
AC_CHECK_FUNC(arc4random_buf, [AC_SUBST(BSON_HAVE_ARC4RANDOM_BUF, 1)])

# Check for pthreads. We might need to make this better to handle mingw,
# but I actually think it is okay to just check for it even though we will
# use win32 primatives.
Expand Down
2 changes: 2 additions & 0 deletions scripts/autotools/libmongoc/CheckCompression.m4
Expand Up @@ -45,6 +45,8 @@ PKG_CHECK_MODULES([PHP_MONGODB_ZLIB],[zlib],[

dnl If zlib was not found, use libmongoc's bundled version
AS_IF([test "$found_zlib" != "yes"],[
AC_CHECK_HEADER([unistd.h],[PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_ZLIB_CFLAGS -DHAVE_UNISTD_H"])
AC_CHECK_HEADER([stdarg.h],[PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_ZLIB_CFLAGS -DHAVE_STDARG_H"])
bundled_zlib="yes"
])

Expand Down
2 changes: 1 addition & 1 deletion src/LIBMONGOC_VERSION_CURRENT
@@ -1 +1 @@
1.20.0
1.11.1-20220104+gite7e15002d6
2 changes: 1 addition & 1 deletion src/libmongoc
Submodule libmongoc updated 133 files
2 changes: 1 addition & 1 deletion tests/manager/manager-ctor-directconnection-error-001.phpt
Expand Up @@ -21,5 +21,5 @@ OK: Got MongoDB\Driver\Exception\InvalidArgumentException
Failed to parse MongoDB URI: 'mongodb://a.example.com,b.example.com/?directConnection=true'. Multiple seeds not allowed with directConnection option.

OK: Got MongoDB\Driver\Exception\InvalidArgumentException
Failed to parse URI options: Multiple seeds not allowed with directConnection option.
Failed to parse URI options: Multiple seeds not allowed with directConnection option
===DONE===
2 changes: 1 addition & 1 deletion tests/manager/manager-ctor-directconnection-error-002.phpt
Expand Up @@ -21,5 +21,5 @@ OK: Got MongoDB\Driver\Exception\InvalidArgumentException
Failed to parse MongoDB URI: 'mongodb+srv://a.example.com/?directConnection=true'. SRV URI not allowed with directConnection option.

OK: Got MongoDB\Driver\Exception\InvalidArgumentException
Failed to parse URI options: SRV URI not allowed with directConnection option.
Failed to parse URI options: SRV URI not allowed with directConnection option
===DONE===

0 comments on commit ab44b0c

Please sign in to comment.