Skip to content

Commit 389de7c

Browse files
committed
Fix #17776 LDAP_OPT_X_TLS_REQUIRE_CERT can't be overridden
1 parent 61f704f commit 389de7c

File tree

4 files changed

+141
-25
lines changed

4 files changed

+141
-25
lines changed

ext/ldap/ldap.c

+66-23
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,21 @@ static PHP_GINIT_FUNCTION(ldap)
835835
}
836836
/* }}} */
837837

838+
/* {{{ PHP_RINIT_FUNCTION */
839+
static PHP_RINIT_FUNCTION(ldap)
840+
{
841+
#if defined(COMPILE_DL_LDAP) && defined(ZTS)
842+
ZEND_TSRMLS_CACHE_UPDATE();
843+
#endif
844+
845+
/* needed before first connect and after TLS option changes */
846+
LDAPG(tls_newctx) = true;
847+
848+
return SUCCESS;
849+
}
850+
/* }}} */
851+
852+
838853
/* {{{ PHP_MINIT_FUNCTION */
839854
PHP_MINIT_FUNCTION(ldap)
840855
{
@@ -987,6 +1002,20 @@ PHP_FUNCTION(ldap_connect)
9871002
snprintf( url, urllen, "ldap://%s:" ZEND_LONG_FMT, host, port );
9881003
}
9891004

1005+
#ifdef LDAP_OPT_X_TLS_NEWCTX
1006+
if (LDAPG(tls_newctx) && url && !strncmp(url, "ldaps:", 6)) {
1007+
int val = 0;
1008+
1009+
/* ensure all pending TLS options are applied in a new context */
1010+
if (ldap_set_option(NULL, LDAP_OPT_X_TLS_NEWCTX, &val) != LDAP_OPT_SUCCESS) {
1011+
zval_ptr_dtor(return_value);
1012+
php_error_docref(NULL, E_WARNING, "Could not create new security context");
1013+
RETURN_FALSE;
1014+
}
1015+
LDAPG(tls_newctx) = false;
1016+
}
1017+
#endif
1018+
9901019
#ifdef LDAP_API_FEATURE_X_OPENLDAP
9911020
/* ldap_init() is deprecated, use ldap_initialize() instead.
9921021
*/
@@ -3172,15 +3201,7 @@ PHP_FUNCTION(ldap_set_option)
31723201
}
31733202

31743203
switch (option) {
3175-
/* options with int value */
3176-
case LDAP_OPT_DEREF:
3177-
case LDAP_OPT_SIZELIMIT:
3178-
case LDAP_OPT_TIMELIMIT:
3179-
case LDAP_OPT_PROTOCOL_VERSION:
3180-
case LDAP_OPT_ERROR_NUMBER:
3181-
#ifdef LDAP_OPT_DEBUG_LEVEL
3182-
case LDAP_OPT_DEBUG_LEVEL:
3183-
#endif
3204+
/* TLS options with int value */
31843205
#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
31853206
case LDAP_OPT_X_TLS_REQUIRE_CERT:
31863207
#endif
@@ -3189,6 +3210,18 @@ PHP_FUNCTION(ldap_set_option)
31893210
#endif
31903211
#ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
31913212
case LDAP_OPT_X_TLS_PROTOCOL_MIN:
3213+
#endif
3214+
/* TLS option change requires resetting TLS context */
3215+
LDAPG(tls_newctx) = true;
3216+
ZEND_FALLTHROUGH;
3217+
/* other options with int value */
3218+
case LDAP_OPT_DEREF:
3219+
case LDAP_OPT_SIZELIMIT:
3220+
case LDAP_OPT_TIMELIMIT:
3221+
case LDAP_OPT_PROTOCOL_VERSION:
3222+
case LDAP_OPT_ERROR_NUMBER:
3223+
#ifdef LDAP_OPT_DEBUG_LEVEL
3224+
case LDAP_OPT_DEBUG_LEVEL:
31923225
#endif
31933226
#ifdef LDAP_OPT_X_KEEPALIVE_IDLE
31943227
case LDAP_OPT_X_KEEPALIVE_IDLE:
@@ -3245,17 +3278,7 @@ PHP_FUNCTION(ldap_set_option)
32453278
}
32463279
} break;
32473280
#endif
3248-
/* options with string value */
3249-
case LDAP_OPT_ERROR_STRING:
3250-
#ifdef LDAP_OPT_HOST_NAME
3251-
case LDAP_OPT_HOST_NAME:
3252-
#endif
3253-
#ifdef HAVE_LDAP_SASL
3254-
case LDAP_OPT_X_SASL_MECH:
3255-
case LDAP_OPT_X_SASL_REALM:
3256-
case LDAP_OPT_X_SASL_AUTHCID:
3257-
case LDAP_OPT_X_SASL_AUTHZID:
3258-
#endif
3281+
/* TLS options with string value */
32593282
#if (LDAP_API_VERSION > 2000)
32603283
case LDAP_OPT_X_TLS_CACERTDIR:
32613284
case LDAP_OPT_X_TLS_CACERTFILE:
@@ -3269,6 +3292,20 @@ PHP_FUNCTION(ldap_set_option)
32693292
#endif
32703293
#ifdef LDAP_OPT_X_TLS_DHFILE
32713294
case LDAP_OPT_X_TLS_DHFILE:
3295+
#endif
3296+
/* TLS option change requires resetting TLS context */
3297+
LDAPG(tls_newctx) = true;
3298+
ZEND_FALLTHROUGH;
3299+
/* other options with string value */
3300+
case LDAP_OPT_ERROR_STRING:
3301+
#ifdef LDAP_OPT_HOST_NAME
3302+
case LDAP_OPT_HOST_NAME:
3303+
#endif
3304+
#ifdef HAVE_LDAP_SASL
3305+
case LDAP_OPT_X_SASL_MECH:
3306+
case LDAP_OPT_X_SASL_REALM:
3307+
case LDAP_OPT_X_SASL_AUTHCID:
3308+
case LDAP_OPT_X_SASL_AUTHZID:
32723309
#endif
32733310
#ifdef LDAP_OPT_MATCHED_DN
32743311
case LDAP_OPT_MATCHED_DN:
@@ -3688,6 +3725,9 @@ PHP_FUNCTION(ldap_start_tls)
36883725
zval *link;
36893726
ldap_linkdata *ld;
36903727
int rc, protocol = LDAP_VERSION3;
3728+
#ifdef LDAP_OPT_X_TLS_NEWCTX
3729+
int val = 0;
3730+
#endif
36913731

36923732
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &link, ldap_link_ce) != SUCCESS) {
36933733
RETURN_THROWS();
@@ -3697,13 +3737,16 @@ PHP_FUNCTION(ldap_start_tls)
36973737
VERIFY_LDAP_LINK_CONNECTED(ld);
36983738

36993739
if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) ||
3740+
#ifdef LDAP_OPT_X_TLS_NEWCTX
3741+
(LDAPG(tls_newctx) && (rc = ldap_set_option(ld->link, LDAP_OPT_X_TLS_NEWCTX, &val)) != LDAP_OPT_SUCCESS) ||
3742+
#endif
37003743
((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS)
37013744
) {
37023745
php_error_docref(NULL, E_WARNING,"Unable to start TLS: %s", ldap_err2string(rc));
37033746
RETURN_FALSE;
3704-
} else {
3705-
RETURN_TRUE;
37063747
}
3748+
LDAPG(tls_newctx) = false;
3749+
RETURN_TRUE;
37073750
}
37083751
/* }}} */
37093752
#endif
@@ -4218,7 +4261,7 @@ zend_module_entry ldap_module_entry = { /* {{{ */
42184261
ext_functions,
42194262
PHP_MINIT(ldap),
42204263
PHP_MSHUTDOWN(ldap),
4221-
NULL,
4264+
PHP_RINIT(ldap),
42224265
NULL,
42234266
PHP_MINFO(ldap),
42244267
PHP_LDAP_VERSION,

ext/ldap/php_ldap.h

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ PHP_MINFO_FUNCTION(ldap);
3939
ZEND_BEGIN_MODULE_GLOBALS(ldap)
4040
zend_long num_links;
4141
zend_long max_links;
42+
bool tls_newctx; /* create new TLS context before connect */
4243
ZEND_END_MODULE_GLOBALS(ldap)
4344

4445
#if defined(ZTS) && defined(COMPILE_DL_LDAP)

ext/ldap/tests/ldap_start_tls_basic.phpt

+19-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,28 @@ ldap
99
<?php require_once __DIR__ .'/skipifbindfailure.inc'; ?>
1010
--FILE--
1111
<?php
12-
require "connect.inc";
12+
require_once "connect.inc";
1313

14+
// CI uses self signed certificate
15+
16+
// No cert option - fails
17+
$link = ldap_connect($uri);
18+
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
19+
var_dump(@ldap_start_tls($link));
20+
21+
// No cert check - passes
22+
$link = ldap_connect($uri);
23+
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
24+
ldap_set_option($link, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);
25+
var_dump(@ldap_start_tls($link));
26+
27+
// With cert check - fails
1428
$link = ldap_connect($uri);
1529
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
16-
var_dump(ldap_start_tls($link));
30+
ldap_set_option($link, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_DEMAND);
31+
var_dump(@ldap_start_tls($link));
1732
?>
1833
--EXPECT--
34+
bool(false)
1935
bool(true)
36+
bool(false)

ext/ldap/tests/ldaps_basic.phpt

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--TEST--
2+
ldap_connect() - Basic ldaps test
3+
--EXTENSIONS--
4+
ldap
5+
--XFAIL--
6+
Passes locally but fails on CI - need investigation (configuration ?)
7+
--SKIPIF--
8+
<?php require_once __DIR__ .'/skipifbindfailure.inc'; ?>
9+
--FILE--
10+
<?php
11+
require_once "connect.inc";
12+
13+
$uri = "ldaps://$host:636";
14+
15+
// CI uses self signed certificate
16+
17+
// No cert option - fails
18+
$link = ldap_connect($uri);
19+
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
20+
var_dump(@ldap_bind($link, $user, $passwd));
21+
ldap_unbind($link);
22+
23+
// No cert check - passes
24+
ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_ALLOW);
25+
$link = ldap_connect($uri);
26+
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
27+
var_dump(@ldap_bind($link, $user, $passwd));
28+
ldap_unbind($link);
29+
30+
// No change to TLS options
31+
$link = ldap_connect($uri);
32+
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
33+
var_dump(@ldap_bind($link, $user, $passwd));
34+
ldap_unbind($link);
35+
36+
// With cert check - fails
37+
ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_DEMAND);
38+
$link = ldap_connect($uri);
39+
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
40+
var_dump(@ldap_bind($link, $user, $passwd));
41+
ldap_unbind($link);
42+
43+
// No change to TLS options
44+
$link = ldap_connect($uri);
45+
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
46+
var_dump(@ldap_bind($link, $user, $passwd));
47+
ldap_unbind($link);
48+
49+
?>
50+
--EXPECT--
51+
bool(false)
52+
bool(true)
53+
bool(true)
54+
bool(false)
55+
bool(false)

0 commit comments

Comments
 (0)