From 6b78264bcf4351d12b677343b3b011eaf1a28f7d Mon Sep 17 00:00:00 2001 From: Saud Alshareef Date: Fri, 12 Jun 2026 05:02:04 +0300 Subject: [PATCH] ldap: base64 encode binary LDIF values with WinLDAP The WinLDAP backend only base64 encoded LDAP values when the attribute name ended in ;binary. This made attributes such as jpegPhoto get written as raw bytes, producing malformed LDIF output. Match the OpenLDAP backend by also base64 encoding values with leading or trailing blanks or non-printable bytes. Fixes #21926 Reported-by: oreadvanthink on github Closes #21982 --- lib/ldap.c | 72 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/lib/ldap.c b/lib/ldap.c index d61ba8b5d1..ab1f118ec7 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -230,6 +230,27 @@ static ULONG ldap_win_bind(struct Curl_easy *data, LDAP *server, } #endif /* USE_WIN32_LDAP */ +static bool ldap_value_needs_base64(const char *attr, size_t attr_len, + const BerValue *val) +{ + ber_len_t j; + + if((attr_len > 7) && curl_strequal(";binary", attr + attr_len - 7)) + return TRUE; + + /* check for leading or trailing whitespace */ + if(val->bv_len && (ISBLANK(val->bv_val[0]) || + ISBLANK(val->bv_val[val->bv_len - 1]))) + return TRUE; + + /* check for unprintable characters */ + for(j = 0; j < val->bv_len; j++) + if(!ISPRINT(val->bv_val[j])) + return TRUE; + + return FALSE; +} + static CURLcode ldap_do(struct Curl_easy *data, bool *done) { CURLcode result = CURLE_OK; @@ -242,8 +263,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) struct connectdata *conn = data->conn; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; - char *val_b64 = NULL; - size_t val_b64_sz = 0; #ifdef LDAP_OPT_NETWORK_TIMEOUT struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ #endif @@ -505,7 +524,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } - result = Curl_client_write(data, CLIENTWRITE_BODY, ": ", 2); + result = Curl_client_write(data, CLIENTWRITE_BODY, ":", 1); if(result) { ldap_value_free_len(vals); FREE_ON_WINLDAP(attr); @@ -513,8 +532,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } - if((attr_len > 7) && - curl_strequal(";binary", attr + (attr_len - 7))) { + if(ldap_value_needs_base64(attr, attr_len, vals[i])) { + char *val_b64 = NULL; + size_t val_b64_sz = 0; + /* Binary attribute, encode to base64. */ if(vals[i]->bv_len) { result = curlx_base64_encode((uint8_t *)vals[i]->bv_val, @@ -526,23 +547,42 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) ldap_memfree(attribute); goto quit; } + } - if(val_b64_sz > 0) { - result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, - val_b64_sz); + result = Curl_client_write(data, CLIENTWRITE_BODY, ": ", 2); + if(result) { + curlx_free(val_b64); + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + goto quit; + } + + if(val_b64_sz) { + result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, + val_b64_sz); + if(result) { curlx_free(val_b64); - if(result) { - ldap_value_free_len(vals); - FREE_ON_WINLDAP(attr); - ldap_memfree(attribute); - goto quit; - } + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + goto quit; } } + + curlx_free(val_b64); } else { - result = Curl_client_write(data, CLIENTWRITE_BODY, vals[i]->bv_val, - vals[i]->bv_len); + result = Curl_client_write(data, CLIENTWRITE_BODY, " ", 1); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + goto quit; + } + + result = Curl_client_write(data, CLIENTWRITE_BODY, + vals[i]->bv_val, vals[i]->bv_len); if(result) { ldap_value_free_len(vals); FREE_ON_WINLDAP(attr);