File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / ldap.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years, 6 months ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>