Annotation of embedaddon/curl/lib/ldap.c, revision 1.1.1.1

1.1       misho       1: /***************************************************************************
                      2:  *                      _   _ ____  _
                      3:  *  Project         ___| | | |  _ \| |
                      4:  *                 / __| | | | |_) | |
                      5:  *                | (__| |_| |  _ <| |___
                      6:  *                 \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
                      9:  *
                     10:  * This software is licensed as described in the file COPYING, which
                     11:  * you should have received as part of this distribution. The terms
                     12:  * are also available at https://curl.haxx.se/docs/copyright.html.
                     13:  *
                     14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
                     15:  * copies of the Software, and permit persons to whom the Software is
                     16:  * furnished to do so, under the terms of the COPYING file.
                     17:  *
                     18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
                     19:  * KIND, either express or implied.
                     20:  *
                     21:  ***************************************************************************/
                     22: 
                     23: #include "curl_setup.h"
                     24: 
                     25: #if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP)
                     26: 
                     27: /*
                     28:  * Notice that USE_OPENLDAP is only a source code selection switch. When
                     29:  * libcurl is built with USE_OPENLDAP defined the libcurl source code that
                     30:  * gets compiled is the code from openldap.c, otherwise the code that gets
                     31:  * compiled is the code from ldap.c.
                     32:  *
                     33:  * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
                     34:  * might be required for compilation and runtime. In order to use ancient
                     35:  * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
                     36:  */
                     37: 
                     38: #ifdef USE_WIN32_LDAP           /* Use Windows LDAP implementation. */
                     39: # include <winldap.h>
                     40: # ifndef LDAP_VENDOR_NAME
                     41: #  error Your Platform SDK is NOT sufficient for LDAP support! \
                     42:          Update your Platform SDK, or disable LDAP support!
                     43: # else
                     44: #  include <winber.h>
                     45: # endif
                     46: #else
                     47: # define LDAP_DEPRECATED 1      /* Be sure ldap_init() is defined. */
                     48: # ifdef HAVE_LBER_H
                     49: #  include <lber.h>
                     50: # endif
                     51: # include <ldap.h>
                     52: # if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H))
                     53: #  include <ldap_ssl.h>
                     54: # endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */
                     55: #endif
                     56: 
                     57: #include "urldata.h"
                     58: #include <curl/curl.h>
                     59: #include "sendf.h"
                     60: #include "escape.h"
                     61: #include "progress.h"
                     62: #include "transfer.h"
                     63: #include "strcase.h"
                     64: #include "strtok.h"
                     65: #include "curl_ldap.h"
                     66: #include "curl_multibyte.h"
                     67: #include "curl_base64.h"
                     68: #include "connect.h"
                     69: /* The last 3 #include files should be in this order */
                     70: #include "curl_printf.h"
                     71: #include "curl_memory.h"
                     72: #include "memdebug.h"
                     73: 
                     74: #ifndef HAVE_LDAP_URL_PARSE
                     75: 
                     76: /* Use our own implementation. */
                     77: 
                     78: typedef struct {
                     79:   char   *lud_host;
                     80:   int     lud_port;
                     81: #if defined(USE_WIN32_LDAP)
                     82:   TCHAR  *lud_dn;
                     83:   TCHAR **lud_attrs;
                     84: #else
                     85:   char   *lud_dn;
                     86:   char  **lud_attrs;
                     87: #endif
                     88:   int     lud_scope;
                     89: #if defined(USE_WIN32_LDAP)
                     90:   TCHAR  *lud_filter;
                     91: #else
                     92:   char   *lud_filter;
                     93: #endif
                     94:   char  **lud_exts;
                     95:   size_t    lud_attrs_dups; /* how many were dup'ed, this field is not in the
                     96:                                "real" struct so can only be used in code
                     97:                                without HAVE_LDAP_URL_PARSE defined */
                     98: } CURL_LDAPURLDesc;
                     99: 
                    100: #undef LDAPURLDesc
                    101: #define LDAPURLDesc             CURL_LDAPURLDesc
                    102: 
                    103: static int  _ldap_url_parse(const struct connectdata *conn,
                    104:                             LDAPURLDesc **ludp);
                    105: static void _ldap_free_urldesc(LDAPURLDesc *ludp);
                    106: 
                    107: #undef ldap_free_urldesc
                    108: #define ldap_free_urldesc       _ldap_free_urldesc
                    109: #endif
                    110: 
                    111: #ifdef DEBUG_LDAP
                    112:   #define LDAP_TRACE(x)   do { \
                    113:                             _ldap_trace("%u: ", __LINE__); \
                    114:                             _ldap_trace x; \
                    115:                           } while(0)
                    116: 
                    117:   static void _ldap_trace(const char *fmt, ...);
                    118: #else
                    119:   #define LDAP_TRACE(x)   Curl_nop_stmt
                    120: #endif
                    121: 
                    122: #if defined(USE_WIN32_LDAP) && defined(ldap_err2string)
                    123: /* Use ansi error strings in UNICODE builds */
                    124: #undef ldap_err2string
                    125: #define ldap_err2string ldap_err2stringA
                    126: #endif
                    127: 
                    128: 
                    129: static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
                    130: 
                    131: /*
                    132:  * LDAP protocol handler.
                    133:  */
                    134: 
                    135: const struct Curl_handler Curl_handler_ldap = {
                    136:   "LDAP",                               /* scheme */
                    137:   ZERO_NULL,                            /* setup_connection */
                    138:   Curl_ldap,                            /* do_it */
                    139:   ZERO_NULL,                            /* done */
                    140:   ZERO_NULL,                            /* do_more */
                    141:   ZERO_NULL,                            /* connect_it */
                    142:   ZERO_NULL,                            /* connecting */
                    143:   ZERO_NULL,                            /* doing */
                    144:   ZERO_NULL,                            /* proto_getsock */
                    145:   ZERO_NULL,                            /* doing_getsock */
                    146:   ZERO_NULL,                            /* domore_getsock */
                    147:   ZERO_NULL,                            /* perform_getsock */
                    148:   ZERO_NULL,                            /* disconnect */
                    149:   ZERO_NULL,                            /* readwrite */
                    150:   ZERO_NULL,                            /* connection_check */
                    151:   PORT_LDAP,                            /* defport */
                    152:   CURLPROTO_LDAP,                       /* protocol */
                    153:   PROTOPT_NONE                          /* flags */
                    154: };
                    155: 
                    156: #ifdef HAVE_LDAP_SSL
                    157: /*
                    158:  * LDAPS protocol handler.
                    159:  */
                    160: 
                    161: const struct Curl_handler Curl_handler_ldaps = {
                    162:   "LDAPS",                              /* scheme */
                    163:   ZERO_NULL,                            /* setup_connection */
                    164:   Curl_ldap,                            /* do_it */
                    165:   ZERO_NULL,                            /* done */
                    166:   ZERO_NULL,                            /* do_more */
                    167:   ZERO_NULL,                            /* connect_it */
                    168:   ZERO_NULL,                            /* connecting */
                    169:   ZERO_NULL,                            /* doing */
                    170:   ZERO_NULL,                            /* proto_getsock */
                    171:   ZERO_NULL,                            /* doing_getsock */
                    172:   ZERO_NULL,                            /* domore_getsock */
                    173:   ZERO_NULL,                            /* perform_getsock */
                    174:   ZERO_NULL,                            /* disconnect */
                    175:   ZERO_NULL,                            /* readwrite */
                    176:   ZERO_NULL,                            /* connection_check */
                    177:   PORT_LDAPS,                           /* defport */
                    178:   CURLPROTO_LDAPS,                      /* protocol */
                    179:   PROTOPT_SSL                           /* flags */
                    180: };
                    181: #endif
                    182: 
                    183: #if defined(USE_WIN32_LDAP)
                    184: 
                    185: #if defined(USE_WINDOWS_SSPI)
                    186: static int ldap_win_bind_auth(LDAP *server, const char *user,
                    187:                               const char *passwd, unsigned long authflags)
                    188: {
                    189:   ULONG method = 0;
                    190:   SEC_WINNT_AUTH_IDENTITY cred;
                    191:   int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
                    192: 
                    193:   memset(&cred, 0, sizeof(cred));
                    194: 
                    195: #if defined(USE_SPNEGO)
                    196:   if(authflags & CURLAUTH_NEGOTIATE) {
                    197:     method = LDAP_AUTH_NEGOTIATE;
                    198:   }
                    199:   else
                    200: #endif
                    201: #if defined(USE_NTLM)
                    202:   if(authflags & CURLAUTH_NTLM) {
                    203:     method = LDAP_AUTH_NTLM;
                    204:   }
                    205:   else
                    206: #endif
                    207: #if !defined(CURL_DISABLE_CRYPTO_AUTH)
                    208:   if(authflags & CURLAUTH_DIGEST) {
                    209:     method = LDAP_AUTH_DIGEST;
                    210:   }
                    211:   else
                    212: #endif
                    213:   {
                    214:     /* required anyway if one of upper preprocessor definitions enabled */
                    215:   }
                    216: 
                    217:   if(method && user && passwd) {
                    218:     rc = Curl_create_sspi_identity(user, passwd, &cred);
                    219:     if(!rc) {
                    220:       rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
                    221:       Curl_sspi_free_identity(&cred);
                    222:     }
                    223:   }
                    224:   else {
                    225:     /* proceed with current user credentials */
                    226:     method = LDAP_AUTH_NEGOTIATE;
                    227:     rc = ldap_bind_s(server, NULL, NULL, method);
                    228:   }
                    229:   return rc;
                    230: }
                    231: #endif /* #if defined(USE_WINDOWS_SSPI) */
                    232: 
                    233: static int ldap_win_bind(struct connectdata *conn, LDAP *server,
                    234:                          const char *user, const char *passwd)
                    235: {
                    236:   int rc = LDAP_INVALID_CREDENTIALS;
                    237: 
                    238:   PTCHAR inuser = NULL;
                    239:   PTCHAR inpass = NULL;
                    240: 
                    241:   if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) {
                    242:     inuser = Curl_convert_UTF8_to_tchar((char *) user);
                    243:     inpass = Curl_convert_UTF8_to_tchar((char *) passwd);
                    244: 
                    245:     rc = ldap_simple_bind_s(server, inuser, inpass);
                    246: 
                    247:     Curl_unicodefree(inuser);
                    248:     Curl_unicodefree(inpass);
                    249:   }
                    250: #if defined(USE_WINDOWS_SSPI)
                    251:   else {
                    252:     rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth);
                    253:   }
                    254: #endif
                    255: 
                    256:   return rc;
                    257: }
                    258: #endif /* #if defined(USE_WIN32_LDAP) */
                    259: 
                    260: static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
                    261: {
                    262:   CURLcode result = CURLE_OK;
                    263:   int rc = 0;
                    264:   LDAP *server = NULL;
                    265:   LDAPURLDesc *ludp = NULL;
                    266:   LDAPMessage *ldapmsg = NULL;
                    267:   LDAPMessage *entryIterator;
                    268:   int num = 0;
                    269:   struct Curl_easy *data = conn->data;
                    270:   int ldap_proto = LDAP_VERSION3;
                    271:   int ldap_ssl = 0;
                    272:   char *val_b64 = NULL;
                    273:   size_t val_b64_sz = 0;
                    274:   curl_off_t dlsize = 0;
                    275: #ifdef LDAP_OPT_NETWORK_TIMEOUT
                    276:   struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */
                    277: #endif
                    278: #if defined(USE_WIN32_LDAP)
                    279:   TCHAR *host = NULL;
                    280: #else
                    281:   char *host = NULL;
                    282: #endif
                    283:   char *user = NULL;
                    284:   char *passwd = NULL;
                    285: 
                    286:   *done = TRUE; /* unconditionally */
                    287:   infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
                    288:           LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
                    289:   infof(data, "LDAP local: %s\n", data->change.url);
                    290: 
                    291: #ifdef HAVE_LDAP_URL_PARSE
                    292:   rc = ldap_url_parse(data->change.url, &ludp);
                    293: #else
                    294:   rc = _ldap_url_parse(conn, &ludp);
                    295: #endif
                    296:   if(rc != 0) {
                    297:     failf(data, "LDAP local: %s", ldap_err2string(rc));
                    298:     result = CURLE_LDAP_INVALID_URL;
                    299:     goto quit;
                    300:   }
                    301: 
                    302:   /* Get the URL scheme (either ldap or ldaps) */
                    303:   if(conn->given->flags & PROTOPT_SSL)
                    304:     ldap_ssl = 1;
                    305:   infof(data, "LDAP local: trying to establish %s connection\n",
                    306:           ldap_ssl ? "encrypted" : "cleartext");
                    307: 
                    308: #if defined(USE_WIN32_LDAP)
                    309:   host = Curl_convert_UTF8_to_tchar(conn->host.name);
                    310:   if(!host) {
                    311:     result = CURLE_OUT_OF_MEMORY;
                    312: 
                    313:     goto quit;
                    314:   }
                    315: #else
                    316:   host = conn->host.name;
                    317: #endif
                    318: 
                    319:   if(conn->bits.user_passwd) {
                    320:     user = conn->user;
                    321:     passwd = conn->passwd;
                    322:   }
                    323: 
                    324: #ifdef LDAP_OPT_NETWORK_TIMEOUT
                    325:   ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
                    326: #endif
                    327:   ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
                    328: 
                    329:   if(ldap_ssl) {
                    330: #ifdef HAVE_LDAP_SSL
                    331: #ifdef USE_WIN32_LDAP
                    332:     /* Win32 LDAP SDK doesn't support insecure mode without CA! */
                    333:     server = ldap_sslinit(host, (int)conn->port, 1);
                    334:     ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
                    335: #else
                    336:     int ldap_option;
                    337:     char *ldap_ca = conn->ssl_config.CAfile;
                    338: #if defined(CURL_HAS_NOVELL_LDAPSDK)
                    339:     rc = ldapssl_client_init(NULL, NULL);
                    340:     if(rc != LDAP_SUCCESS) {
                    341:       failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
                    342:       result = CURLE_SSL_CERTPROBLEM;
                    343:       goto quit;
                    344:     }
                    345:     if(conn->ssl_config.verifypeer) {
                    346:       /* Novell SDK supports DER or BASE64 files. */
                    347:       int cert_type = LDAPSSL_CERT_FILETYPE_B64;
                    348:       if((data->set.ssl.cert_type) &&
                    349:          (strcasecompare(data->set.ssl.cert_type, "DER")))
                    350:         cert_type = LDAPSSL_CERT_FILETYPE_DER;
                    351:       if(!ldap_ca) {
                    352:         failf(data, "LDAP local: ERROR %s CA cert not set!",
                    353:               (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
                    354:         result = CURLE_SSL_CERTPROBLEM;
                    355:         goto quit;
                    356:       }
                    357:       infof(data, "LDAP local: using %s CA cert '%s'\n",
                    358:               (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
                    359:               ldap_ca);
                    360:       rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
                    361:       if(rc != LDAP_SUCCESS) {
                    362:         failf(data, "LDAP local: ERROR setting %s CA cert: %s",
                    363:                 (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
                    364:                 ldap_err2string(rc));
                    365:         result = CURLE_SSL_CERTPROBLEM;
                    366:         goto quit;
                    367:       }
                    368:       ldap_option = LDAPSSL_VERIFY_SERVER;
                    369:     }
                    370:     else
                    371:       ldap_option = LDAPSSL_VERIFY_NONE;
                    372:     rc = ldapssl_set_verify_mode(ldap_option);
                    373:     if(rc != LDAP_SUCCESS) {
                    374:       failf(data, "LDAP local: ERROR setting cert verify mode: %s",
                    375:               ldap_err2string(rc));
                    376:       result = CURLE_SSL_CERTPROBLEM;
                    377:       goto quit;
                    378:     }
                    379:     server = ldapssl_init(host, (int)conn->port, 1);
                    380:     if(server == NULL) {
                    381:       failf(data, "LDAP local: Cannot connect to %s:%ld",
                    382:             conn->host.dispname, conn->port);
                    383:       result = CURLE_COULDNT_CONNECT;
                    384:       goto quit;
                    385:     }
                    386: #elif defined(LDAP_OPT_X_TLS)
                    387:     if(conn->ssl_config.verifypeer) {
                    388:       /* OpenLDAP SDK supports BASE64 files. */
                    389:       if((data->set.ssl.cert_type) &&
                    390:          (!strcasecompare(data->set.ssl.cert_type, "PEM"))) {
                    391:         failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
                    392:         result = CURLE_SSL_CERTPROBLEM;
                    393:         goto quit;
                    394:       }
                    395:       if(!ldap_ca) {
                    396:         failf(data, "LDAP local: ERROR PEM CA cert not set!");
                    397:         result = CURLE_SSL_CERTPROBLEM;
                    398:         goto quit;
                    399:       }
                    400:       infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
                    401:       rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
                    402:       if(rc != LDAP_SUCCESS) {
                    403:         failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
                    404:                 ldap_err2string(rc));
                    405:         result = CURLE_SSL_CERTPROBLEM;
                    406:         goto quit;
                    407:       }
                    408:       ldap_option = LDAP_OPT_X_TLS_DEMAND;
                    409:     }
                    410:     else
                    411:       ldap_option = LDAP_OPT_X_TLS_NEVER;
                    412: 
                    413:     rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
                    414:     if(rc != LDAP_SUCCESS) {
                    415:       failf(data, "LDAP local: ERROR setting cert verify mode: %s",
                    416:               ldap_err2string(rc));
                    417:       result = CURLE_SSL_CERTPROBLEM;
                    418:       goto quit;
                    419:     }
                    420:     server = ldap_init(host, (int)conn->port);
                    421:     if(server == NULL) {
                    422:       failf(data, "LDAP local: Cannot connect to %s:%ld",
                    423:             conn->host.dispname, conn->port);
                    424:       result = CURLE_COULDNT_CONNECT;
                    425:       goto quit;
                    426:     }
                    427:     ldap_option = LDAP_OPT_X_TLS_HARD;
                    428:     rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
                    429:     if(rc != LDAP_SUCCESS) {
                    430:       failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
                    431:               ldap_err2string(rc));
                    432:       result = CURLE_SSL_CERTPROBLEM;
                    433:       goto quit;
                    434:     }
                    435: /*
                    436:     rc = ldap_start_tls_s(server, NULL, NULL);
                    437:     if(rc != LDAP_SUCCESS) {
                    438:       failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
                    439:               ldap_err2string(rc));
                    440:       result = CURLE_SSL_CERTPROBLEM;
                    441:       goto quit;
                    442:     }
                    443: */
                    444: #else
                    445:     /* we should probably never come up to here since configure
                    446:        should check in first place if we can support LDAP SSL/TLS */
                    447:     failf(data, "LDAP local: SSL/TLS not supported with this version "
                    448:             "of the OpenLDAP toolkit\n");
                    449:     result = CURLE_SSL_CERTPROBLEM;
                    450:     goto quit;
                    451: #endif
                    452: #endif
                    453: #endif /* CURL_LDAP_USE_SSL */
                    454:   }
                    455:   else {
                    456:     server = ldap_init(host, (int)conn->port);
                    457:     if(server == NULL) {
                    458:       failf(data, "LDAP local: Cannot connect to %s:%ld",
                    459:             conn->host.dispname, conn->port);
                    460:       result = CURLE_COULDNT_CONNECT;
                    461:       goto quit;
                    462:     }
                    463:   }
                    464: #ifdef USE_WIN32_LDAP
                    465:   ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
                    466: #endif
                    467: 
                    468: #ifdef USE_WIN32_LDAP
                    469:   rc = ldap_win_bind(conn, server, user, passwd);
                    470: #else
                    471:   rc = ldap_simple_bind_s(server, user, passwd);
                    472: #endif
                    473:   if(!ldap_ssl && rc != 0) {
                    474:     ldap_proto = LDAP_VERSION2;
                    475:     ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
                    476: #ifdef USE_WIN32_LDAP
                    477:     rc = ldap_win_bind(conn, server, user, passwd);
                    478: #else
                    479:     rc = ldap_simple_bind_s(server, user, passwd);
                    480: #endif
                    481:   }
                    482:   if(rc != 0) {
                    483: #ifdef USE_WIN32_LDAP
                    484:     failf(data, "LDAP local: bind via ldap_win_bind %s",
                    485:           ldap_err2string(rc));
                    486: #else
                    487:     failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
                    488:           ldap_err2string(rc));
                    489: #endif
                    490:     result = CURLE_LDAP_CANNOT_BIND;
                    491:     goto quit;
                    492:   }
                    493: 
                    494:   rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
                    495:                      ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
                    496: 
                    497:   if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
                    498:     failf(data, "LDAP remote: %s", ldap_err2string(rc));
                    499:     result = CURLE_LDAP_SEARCH_FAILED;
                    500:     goto quit;
                    501:   }
                    502: 
                    503:   for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
                    504:       entryIterator;
                    505:       entryIterator = ldap_next_entry(server, entryIterator), num++) {
                    506:     BerElement *ber = NULL;
                    507: #if defined(USE_WIN32_LDAP)
                    508:     TCHAR *attribute;
                    509: #else
                    510:     char  *attribute;       /*! suspicious that this isn't 'const' */
                    511: #endif
                    512:     int i;
                    513: 
                    514:     /* Get the DN and write it to the client */
                    515:     {
                    516:       char *name;
                    517:       size_t name_len;
                    518: #if defined(USE_WIN32_LDAP)
                    519:       TCHAR *dn = ldap_get_dn(server, entryIterator);
                    520:       name = Curl_convert_tchar_to_UTF8(dn);
                    521:       if(!name) {
                    522:         ldap_memfree(dn);
                    523: 
                    524:         result = CURLE_OUT_OF_MEMORY;
                    525: 
                    526:         goto quit;
                    527:       }
                    528: #else
                    529:       char *dn = name = ldap_get_dn(server, entryIterator);
                    530: #endif
                    531:       name_len = strlen(name);
                    532: 
                    533:       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
                    534:       if(result) {
                    535: #if defined(USE_WIN32_LDAP)
                    536:         Curl_unicodefree(name);
                    537: #endif
                    538:         ldap_memfree(dn);
                    539: 
                    540:         goto quit;
                    541:       }
                    542: 
                    543:       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name,
                    544:                                  name_len);
                    545:       if(result) {
                    546: #if defined(USE_WIN32_LDAP)
                    547:         Curl_unicodefree(name);
                    548: #endif
                    549:         ldap_memfree(dn);
                    550: 
                    551:         goto quit;
                    552:       }
                    553: 
                    554:       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
                    555:       if(result) {
                    556: #if defined(USE_WIN32_LDAP)
                    557:         Curl_unicodefree(name);
                    558: #endif
                    559:         ldap_memfree(dn);
                    560: 
                    561:         goto quit;
                    562:       }
                    563: 
                    564:       dlsize += name_len + 5;
                    565: 
                    566: #if defined(USE_WIN32_LDAP)
                    567:       Curl_unicodefree(name);
                    568: #endif
                    569:       ldap_memfree(dn);
                    570:     }
                    571: 
                    572:     /* Get the attributes and write them to the client */
                    573:     for(attribute = ldap_first_attribute(server, entryIterator, &ber);
                    574:         attribute;
                    575:         attribute = ldap_next_attribute(server, entryIterator, ber)) {
                    576:       BerValue **vals;
                    577:       size_t attr_len;
                    578: #if defined(USE_WIN32_LDAP)
                    579:       char *attr = Curl_convert_tchar_to_UTF8(attribute);
                    580:       if(!attr) {
                    581:         if(ber)
                    582:           ber_free(ber, 0);
                    583: 
                    584:         result = CURLE_OUT_OF_MEMORY;
                    585: 
                    586:         goto quit;
                    587:     }
                    588: #else
                    589:       char *attr = attribute;
                    590: #endif
                    591:       attr_len = strlen(attr);
                    592: 
                    593:       vals = ldap_get_values_len(server, entryIterator, attribute);
                    594:       if(vals != NULL) {
                    595:         for(i = 0; (vals[i] != NULL); i++) {
                    596:           result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
                    597:           if(result) {
                    598:             ldap_value_free_len(vals);
                    599: #if defined(USE_WIN32_LDAP)
                    600:             Curl_unicodefree(attr);
                    601: #endif
                    602:             ldap_memfree(attribute);
                    603:             if(ber)
                    604:               ber_free(ber, 0);
                    605: 
                    606:             goto quit;
                    607:           }
                    608: 
                    609:           result = Curl_client_write(conn, CLIENTWRITE_BODY,
                    610:                                      (char *) attr, attr_len);
                    611:           if(result) {
                    612:             ldap_value_free_len(vals);
                    613: #if defined(USE_WIN32_LDAP)
                    614:             Curl_unicodefree(attr);
                    615: #endif
                    616:             ldap_memfree(attribute);
                    617:             if(ber)
                    618:               ber_free(ber, 0);
                    619: 
                    620:             goto quit;
                    621:           }
                    622: 
                    623:           result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
                    624:           if(result) {
                    625:             ldap_value_free_len(vals);
                    626: #if defined(USE_WIN32_LDAP)
                    627:             Curl_unicodefree(attr);
                    628: #endif
                    629:             ldap_memfree(attribute);
                    630:             if(ber)
                    631:               ber_free(ber, 0);
                    632: 
                    633:             goto quit;
                    634:           }
                    635: 
                    636:           dlsize += attr_len + 3;
                    637: 
                    638:           if((attr_len > 7) &&
                    639:              (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) {
                    640:             /* Binary attribute, encode to base64. */
                    641:             result = Curl_base64_encode(data,
                    642:                                         vals[i]->bv_val,
                    643:                                         vals[i]->bv_len,
                    644:                                         &val_b64,
                    645:                                         &val_b64_sz);
                    646:             if(result) {
                    647:               ldap_value_free_len(vals);
                    648: #if defined(USE_WIN32_LDAP)
                    649:               Curl_unicodefree(attr);
                    650: #endif
                    651:               ldap_memfree(attribute);
                    652:               if(ber)
                    653:                 ber_free(ber, 0);
                    654: 
                    655:               goto quit;
                    656:             }
                    657: 
                    658:             if(val_b64_sz > 0) {
                    659:               result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
                    660:                                          val_b64_sz);
                    661:               free(val_b64);
                    662:               if(result) {
                    663:                 ldap_value_free_len(vals);
                    664: #if defined(USE_WIN32_LDAP)
                    665:                 Curl_unicodefree(attr);
                    666: #endif
                    667:                 ldap_memfree(attribute);
                    668:                 if(ber)
                    669:                   ber_free(ber, 0);
                    670: 
                    671:                 goto quit;
                    672:               }
                    673: 
                    674:               dlsize += val_b64_sz;
                    675:             }
                    676:           }
                    677:           else {
                    678:             result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
                    679:                                        vals[i]->bv_len);
                    680:             if(result) {
                    681:               ldap_value_free_len(vals);
                    682: #if defined(USE_WIN32_LDAP)
                    683:               Curl_unicodefree(attr);
                    684: #endif
                    685:               ldap_memfree(attribute);
                    686:               if(ber)
                    687:                 ber_free(ber, 0);
                    688: 
                    689:               goto quit;
                    690:             }
                    691: 
                    692:             dlsize += vals[i]->bv_len;
                    693:           }
                    694: 
                    695:           result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
                    696:           if(result) {
                    697:             ldap_value_free_len(vals);
                    698: #if defined(USE_WIN32_LDAP)
                    699:             Curl_unicodefree(attr);
                    700: #endif
                    701:             ldap_memfree(attribute);
                    702:             if(ber)
                    703:               ber_free(ber, 0);
                    704: 
                    705:             goto quit;
                    706:           }
                    707: 
                    708:           dlsize++;
                    709:         }
                    710: 
                    711:         /* Free memory used to store values */
                    712:         ldap_value_free_len(vals);
                    713:       }
                    714: 
                    715:       /* Free the attribute as we are done with it */
                    716: #if defined(USE_WIN32_LDAP)
                    717:       Curl_unicodefree(attr);
                    718: #endif
                    719:       ldap_memfree(attribute);
                    720: 
                    721:       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
                    722:       if(result)
                    723:         goto quit;
                    724:       dlsize++;
                    725:       Curl_pgrsSetDownloadCounter(data, dlsize);
                    726:     }
                    727: 
                    728:     if(ber)
                    729:        ber_free(ber, 0);
                    730:   }
                    731: 
                    732: quit:
                    733:   if(ldapmsg) {
                    734:     ldap_msgfree(ldapmsg);
                    735:     LDAP_TRACE(("Received %d entries\n", num));
                    736:   }
                    737:   if(rc == LDAP_SIZELIMIT_EXCEEDED)
                    738:     infof(data, "There are more than %d entries\n", num);
                    739:   if(ludp)
                    740:     ldap_free_urldesc(ludp);
                    741:   if(server)
                    742:     ldap_unbind_s(server);
                    743: #if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
                    744:   if(ldap_ssl)
                    745:     ldapssl_client_deinit();
                    746: #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
                    747: 
                    748: #if defined(USE_WIN32_LDAP)
                    749:   Curl_unicodefree(host);
                    750: #endif
                    751: 
                    752:   /* no data to transfer */
                    753:   Curl_setup_transfer(data, -1, -1, FALSE, -1);
                    754:   connclose(conn, "LDAP connection always disable re-use");
                    755: 
                    756:   return result;
                    757: }
                    758: 
                    759: #ifdef DEBUG_LDAP
                    760: static void _ldap_trace(const char *fmt, ...)
                    761: {
                    762:   static int do_trace = -1;
                    763:   va_list args;
                    764: 
                    765:   if(do_trace == -1) {
                    766:     const char *env = getenv("CURL_TRACE");
                    767:     do_trace = (env && strtol(env, NULL, 10) > 0);
                    768:   }
                    769:   if(!do_trace)
                    770:     return;
                    771: 
                    772:   va_start(args, fmt);
                    773:   vfprintf(stderr, fmt, args);
                    774:   va_end(args);
                    775: }
                    776: #endif
                    777: 
                    778: #ifndef HAVE_LDAP_URL_PARSE
                    779: 
                    780: /*
                    781:  * Return scope-value for a scope-string.
                    782:  */
                    783: static int str2scope(const char *p)
                    784: {
                    785:   if(strcasecompare(p, "one"))
                    786:     return LDAP_SCOPE_ONELEVEL;
                    787:   if(strcasecompare(p, "onetree"))
                    788:     return LDAP_SCOPE_ONELEVEL;
                    789:   if(strcasecompare(p, "base"))
                    790:     return LDAP_SCOPE_BASE;
                    791:   if(strcasecompare(p, "sub"))
                    792:     return LDAP_SCOPE_SUBTREE;
                    793:   if(strcasecompare(p, "subtree"))
                    794:     return LDAP_SCOPE_SUBTREE;
                    795:   return (-1);
                    796: }
                    797: 
                    798: /*
                    799:  * Split 'str' into strings separated by commas.
                    800:  * Note: out[] points into 'str'.
                    801:  */
                    802: static bool split_str(char *str, char ***out, size_t *count)
                    803: {
                    804:   char **res;
                    805:   char *lasts;
                    806:   char *s;
                    807:   size_t  i;
                    808:   size_t items = 1;
                    809: 
                    810:   s = strchr(str, ',');
                    811:   while(s) {
                    812:     items++;
                    813:     s = strchr(++s, ',');
                    814:   }
                    815: 
                    816:   res = calloc(items, sizeof(char *));
                    817:   if(!res)
                    818:     return FALSE;
                    819: 
                    820:   for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items;
                    821:       s = strtok_r(NULL, ",", &lasts), i++)
                    822:     res[i] = s;
                    823: 
                    824:   *out = res;
                    825:   *count = items;
                    826: 
                    827:   return TRUE;
                    828: }
                    829: 
                    830: /*
                    831:  * Break apart the pieces of an LDAP URL.
                    832:  * Syntax:
                    833:  *   ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
                    834:  *
                    835:  * <hostname> already known from 'conn->host.name'.
                    836:  * <port>     already known from 'conn->remote_port'.
                    837:  * extract the rest from 'conn->data->state.path+1'. All fields are optional.
                    838:  * e.g.
                    839:  *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
                    840:  * yields ludp->lud_dn = "".
                    841:  *
                    842:  * Defined in RFC4516 section 2.
                    843:  */
                    844: static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
                    845: {
                    846:   int rc = LDAP_SUCCESS;
                    847:   char *p;
                    848:   char *path;
                    849:   char *q = NULL;
                    850:   char *query = NULL;
                    851:   size_t i;
                    852: 
                    853:   if(!conn->data ||
                    854:      !conn->data->state.up.path ||
                    855:      conn->data->state.up.path[0] != '/' ||
                    856:      !strncasecompare("LDAP", conn->data->state.up.scheme, 4))
                    857:     return LDAP_INVALID_SYNTAX;
                    858: 
                    859:   ludp->lud_scope = LDAP_SCOPE_BASE;
                    860:   ludp->lud_port  = conn->remote_port;
                    861:   ludp->lud_host  = conn->host.name;
                    862: 
                    863:   /* Duplicate the path */
                    864:   p = path = strdup(conn->data->state.up.path + 1);
                    865:   if(!path)
                    866:     return LDAP_NO_MEMORY;
                    867: 
                    868:   /* Duplicate the query if present */
                    869:   if(conn->data->state.up.query) {
                    870:     q = query = strdup(conn->data->state.up.query);
                    871:     if(!query) {
                    872:       free(path);
                    873:       return LDAP_NO_MEMORY;
                    874:     }
                    875:   }
                    876: 
                    877:   /* Parse the DN (Distinguished Name) */
                    878:   if(*p) {
                    879:     char *dn = p;
                    880:     char *unescaped;
                    881:     CURLcode result;
                    882: 
                    883:     LDAP_TRACE(("DN '%s'\n", dn));
                    884: 
                    885:     /* Unescape the DN */
                    886:     result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE);
                    887:     if(result) {
                    888:       rc = LDAP_NO_MEMORY;
                    889: 
                    890:       goto quit;
                    891:     }
                    892: 
                    893: #if defined(USE_WIN32_LDAP)
                    894:     /* Convert the unescaped string to a tchar */
                    895:     ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped);
                    896: 
                    897:     /* Free the unescaped string as we are done with it */
                    898:     Curl_unicodefree(unescaped);
                    899: 
                    900:     if(!ludp->lud_dn) {
                    901:       rc = LDAP_NO_MEMORY;
                    902: 
                    903:       goto quit;
                    904:     }
                    905: #else
                    906:     ludp->lud_dn = unescaped;
                    907: #endif
                    908:   }
                    909: 
                    910:   p = q;
                    911:   if(!p)
                    912:     goto quit;
                    913: 
                    914:   /* Parse the attributes. skip "??" */
                    915:   q = strchr(p, '?');
                    916:   if(q)
                    917:     *q++ = '\0';
                    918: 
                    919:   if(*p) {
                    920:     char **attributes;
                    921:     size_t count = 0;
                    922: 
                    923:     /* Split the string into an array of attributes */
                    924:     if(!split_str(p, &attributes, &count)) {
                    925:       rc = LDAP_NO_MEMORY;
                    926: 
                    927:       goto quit;
                    928:     }
                    929: 
                    930:     /* Allocate our array (+1 for the NULL entry) */
                    931: #if defined(USE_WIN32_LDAP)
                    932:     ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *));
                    933: #else
                    934:     ludp->lud_attrs = calloc(count + 1, sizeof(char *));
                    935: #endif
                    936:     if(!ludp->lud_attrs) {
                    937:       free(attributes);
                    938: 
                    939:       rc = LDAP_NO_MEMORY;
                    940: 
                    941:       goto quit;
                    942:     }
                    943: 
                    944:     for(i = 0; i < count; i++) {
                    945:       char *unescaped;
                    946:       CURLcode result;
                    947: 
                    948:       LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i]));
                    949: 
                    950:       /* Unescape the attribute */
                    951:       result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL,
                    952:                               FALSE);
                    953:       if(result) {
                    954:         free(attributes);
                    955: 
                    956:         rc = LDAP_NO_MEMORY;
                    957: 
                    958:         goto quit;
                    959:       }
                    960: 
                    961: #if defined(USE_WIN32_LDAP)
                    962:       /* Convert the unescaped string to a tchar */
                    963:       ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped);
                    964: 
                    965:       /* Free the unescaped string as we are done with it */
                    966:       Curl_unicodefree(unescaped);
                    967: 
                    968:       if(!ludp->lud_attrs[i]) {
                    969:         free(attributes);
                    970: 
                    971:         rc = LDAP_NO_MEMORY;
                    972: 
                    973:         goto quit;
                    974:       }
                    975: #else
                    976:       ludp->lud_attrs[i] = unescaped;
                    977: #endif
                    978: 
                    979:       ludp->lud_attrs_dups++;
                    980:     }
                    981: 
                    982:     free(attributes);
                    983:   }
                    984: 
                    985:   p = q;
                    986:   if(!p)
                    987:     goto quit;
                    988: 
                    989:   /* Parse the scope. skip "??" */
                    990:   q = strchr(p, '?');
                    991:   if(q)
                    992:     *q++ = '\0';
                    993: 
                    994:   if(*p) {
                    995:     ludp->lud_scope = str2scope(p);
                    996:     if(ludp->lud_scope == -1) {
                    997:       rc = LDAP_INVALID_SYNTAX;
                    998: 
                    999:       goto quit;
                   1000:     }
                   1001:     LDAP_TRACE(("scope %d\n", ludp->lud_scope));
                   1002:   }
                   1003: 
                   1004:   p = q;
                   1005:   if(!p)
                   1006:     goto quit;
                   1007: 
                   1008:   /* Parse the filter */
                   1009:   q = strchr(p, '?');
                   1010:   if(q)
                   1011:     *q++ = '\0';
                   1012: 
                   1013:   if(*p) {
                   1014:     char *filter = p;
                   1015:     char *unescaped;
                   1016:     CURLcode result;
                   1017: 
                   1018:     LDAP_TRACE(("filter '%s'\n", filter));
                   1019: 
                   1020:     /* Unescape the filter */
                   1021:     result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE);
                   1022:     if(result) {
                   1023:       rc = LDAP_NO_MEMORY;
                   1024: 
                   1025:       goto quit;
                   1026:     }
                   1027: 
                   1028: #if defined(USE_WIN32_LDAP)
                   1029:     /* Convert the unescaped string to a tchar */
                   1030:     ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped);
                   1031: 
                   1032:     /* Free the unescaped string as we are done with it */
                   1033:     Curl_unicodefree(unescaped);
                   1034: 
                   1035:     if(!ludp->lud_filter) {
                   1036:       rc = LDAP_NO_MEMORY;
                   1037: 
                   1038:       goto quit;
                   1039:     }
                   1040: #else
                   1041:     ludp->lud_filter = unescaped;
                   1042: #endif
                   1043:   }
                   1044: 
                   1045:   p = q;
                   1046:   if(p && !*p) {
                   1047:     rc = LDAP_INVALID_SYNTAX;
                   1048: 
                   1049:     goto quit;
                   1050:   }
                   1051: 
                   1052: quit:
                   1053:   free(path);
                   1054:   free(query);
                   1055: 
                   1056:   return rc;
                   1057: }
                   1058: 
                   1059: static int _ldap_url_parse(const struct connectdata *conn,
                   1060:                            LDAPURLDesc **ludpp)
                   1061: {
                   1062:   LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
                   1063:   int rc;
                   1064: 
                   1065:   *ludpp = NULL;
                   1066:   if(!ludp)
                   1067:      return LDAP_NO_MEMORY;
                   1068: 
                   1069:   rc = _ldap_url_parse2(conn, ludp);
                   1070:   if(rc != LDAP_SUCCESS) {
                   1071:     _ldap_free_urldesc(ludp);
                   1072:     ludp = NULL;
                   1073:   }
                   1074:   *ludpp = ludp;
                   1075:   return (rc);
                   1076: }
                   1077: 
                   1078: static void _ldap_free_urldesc(LDAPURLDesc *ludp)
                   1079: {
                   1080:   if(!ludp)
                   1081:     return;
                   1082: 
                   1083:   free(ludp->lud_dn);
                   1084:   free(ludp->lud_filter);
                   1085: 
                   1086:   if(ludp->lud_attrs) {
                   1087:     size_t i;
                   1088:     for(i = 0; i < ludp->lud_attrs_dups; i++)
                   1089:       free(ludp->lud_attrs[i]);
                   1090:     free(ludp->lud_attrs);
                   1091:   }
                   1092: 
                   1093:   free(ludp);
                   1094: }
                   1095: #endif  /* !HAVE_LDAP_URL_PARSE */
                   1096: #endif  /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>