Gisle Vanem:
Patch for ldap.c under Windows. It works with wldap32.dll as supplied with Win-98/ME/2000/XP, so no extra .dlls are required. I've mostly tested it against Verisign's ldap server. Added code in the case there are to many responses (rc = LDAP_SIZELIMIT_EXCEEDED) and print only those we got. E.g. curl ldap://directory.verisign.net/?cn,display-name,mail,info?subtree?(cn=*Nelson*) will print the first 10 results. My only problem with it is that ldap_search_s() fails with "filter error" when CURLDEBUG is defined ?! Maybe someone can spot the error.
This commit is contained in:
		
							
								
								
									
										542
									
								
								lib/ldap.c
									
									
									
									
									
								
							
							
						
						
									
										542
									
								
								lib/ldap.c
									
									
									
									
									
								
							| @@ -34,14 +34,18 @@ | |||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
|  |  | ||||||
| #if defined(WIN32) && !defined(__GNUC__) | #if defined(WIN32) | ||||||
| #else | # include <windows.h> | ||||||
| # ifdef HAVE_UNISTD_H | # include <malloc.h> | ||||||
|  | # include <WinLdap.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef HAVE_UNISTD_H | ||||||
| # include <unistd.h> | # include <unistd.h> | ||||||
| # endif | #endif | ||||||
| # ifdef HAVE_DLFCN_H |  | ||||||
|  | #ifdef HAVE_DLFCN_H | ||||||
| # include <dlfcn.h> | # include <dlfcn.h> | ||||||
| # endif |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include "urldata.h" | #include "urldata.h" | ||||||
| @@ -49,25 +53,67 @@ | |||||||
| #include "sendf.h" | #include "sendf.h" | ||||||
| #include "escape.h" | #include "escape.h" | ||||||
| #include "transfer.h" | #include "transfer.h" | ||||||
|  | #include "strequal.h" | ||||||
|  | #include "strtok.h" | ||||||
| #include "ldap.h" | #include "ldap.h" | ||||||
|  |  | ||||||
| #define _MPRINTF_REPLACE /* use our functions only */ | #define _MPRINTF_REPLACE /* use our functions only */ | ||||||
| #include <curl/mprintf.h> | #include <curl/mprintf.h> | ||||||
|  |  | ||||||
| typedef void * (*dynafunc)(void *input); | /* WLdcap.dll's ldap_search_s() return filter error with CURLDEBUG !? | ||||||
|  |  */ | ||||||
|  | #ifdef WIN32 | ||||||
|  | #undef CURLDEBUG | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #define DYNA_GET_FUNCTION(type, fnc) \ | #ifdef CURLDEBUG | ||||||
|  | #include "memdebug.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /* WLdap32.dll functions are *not* stdcall. Must call these via __cdecl | ||||||
|  |  * pointers in case libcurl was compiled as fastcall (-Gr). | ||||||
|  |  */ | ||||||
|  | #if !defined(WIN32) && !defined(__cdecl) | ||||||
|  | #define __cdecl | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef LDAP_SIZELIMIT_EXCEEDED | ||||||
|  | #define LDAP_SIZELIMIT_EXCEEDED -1 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define DLOPEN_MODE   RTLD_LAZY  /*! assume all dlopen() implementations have  | ||||||
|  |                                    this */ | ||||||
|  |  | ||||||
|  | #if defined(RTLD_LAZY_GLOBAL)	 /* It turns out some systems use this: */ | ||||||
|  | # undef  DLOPEN_MODE | ||||||
|  | # define DLOPEN_MODE  RTLD_LAZY_GLOBAL | ||||||
|  | #elif defined(RTLD_GLOBAL) | ||||||
|  | # undef  DLOPEN_MODE | ||||||
|  | # define DLOPEN_MODE  (RTLD_LAZY | RTLD_GLOBAL) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define DYNA_GET_FUNCTION(type, fnc) do { \ | ||||||
|           (fnc) = (type)DynaGetFunction(#fnc); \ |           (fnc) = (type)DynaGetFunction(#fnc); \ | ||||||
|   if ((fnc) == NULL) { \ |           if ((fnc) == NULL) \ | ||||||
|              return CURLE_FUNCTION_NOT_FOUND; \ |              return CURLE_FUNCTION_NOT_FOUND; \ | ||||||
|   } |         } while (0) | ||||||
|  |  | ||||||
|  | /*! CygWin etc. configure could set these, but we don't want it. | ||||||
|  |  * Must use WLdap32.dll code. | ||||||
|  |  */ | ||||||
|  | #if defined(WIN32) | ||||||
|  | #undef HAVE_DLOPEN | ||||||
|  | #undef HAVE_LIBDL | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef void * (*dynafunc)(void *input); | ||||||
|  |  | ||||||
| /*********************************************************************** | /*********************************************************************** | ||||||
|  */ |  */ | ||||||
| static void *libldap = NULL; | static void *libldap = NULL; | ||||||
| static void *liblber = NULL; | static void *liblber = NULL; | ||||||
|  |  | ||||||
| static void DynaOpen(void) | static int DynaOpen(const char **mod_name) | ||||||
| { | { | ||||||
| #if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) | #if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) | ||||||
|   if (libldap == NULL) { |   if (libldap == NULL) { | ||||||
| @@ -76,20 +122,26 @@ static void DynaOpen(void) | |||||||
|      * liblber.so automatically, but since it does not we will |      * liblber.so automatically, but since it does not we will | ||||||
|      * handle it here by opening liblber.so as global. |      * handle it here by opening liblber.so as global. | ||||||
|      */ |      */ | ||||||
|     liblber = dlopen("liblber.so", |     *mod_name = "liblber.so"; | ||||||
| #ifdef RTLD_LAZY_GLOBAL /* It turns out some systems use this: */ |     liblber = dlopen(*mod_name, DLOPEN_MODE); | ||||||
|            RTLD_LAZY_GLOBAL |  | ||||||
| #else |     /* Assume loading libldap.so will fail if loading of liblber.so failed | ||||||
| #ifdef RTLD_GLOBAL |      */ | ||||||
|            RTLD_LAZY | RTLD_GLOBAL |     if (liblber)  { | ||||||
| #else |       *mod_name = "libldap.so"; | ||||||
|            /* and some systems don't have the RTLD_GLOBAL symbol */ |       libldap = dlopen(*mod_name, RTLD_LAZY); | ||||||
|            RTLD_LAZY |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|            ); |  | ||||||
|     libldap = dlopen("libldap.so", RTLD_LAZY); |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |   return (libldap != NULL && liblber != NULL); | ||||||
|  |  | ||||||
|  | #elif defined(WIN32) | ||||||
|  |   *mod_name = "wldap32.dll"; | ||||||
|  |   if (!libldap) | ||||||
|  |     libldap = (void*)LoadLibrary(*mod_name); | ||||||
|  |   return (libldap != NULL); | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |   return (0); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -104,6 +156,11 @@ static void DynaClose(void) | |||||||
|     dlclose(liblber); |     dlclose(liblber); | ||||||
|     liblber=NULL; |     liblber=NULL; | ||||||
|   } |   } | ||||||
|  | #elif defined(WIN32) | ||||||
|  |   if (libldap) { | ||||||
|  |     FreeLibrary ((HMODULE)libldap); | ||||||
|  |     libldap = NULL; | ||||||
|  |   } | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -113,10 +170,13 @@ static dynafunc DynaGetFunction(const char *name) | |||||||
|  |  | ||||||
| #if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) | #if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) | ||||||
|   if (libldap) { |   if (libldap) { | ||||||
|     func = (dynafunc) dlsym(libldap, name); |     func = (dynafunc)dlsym(libldap, name); | ||||||
|  |   } | ||||||
|  | #elif defined(WIN32) | ||||||
|  |   if (libldap) { | ||||||
|  |     func = (dynafunc)GetProcAddress((HINSTANCE)libldap, name); | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|    |  | ||||||
|   return func; |   return func; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -135,137 +195,179 @@ typedef struct ldap_url_desc { | |||||||
|     int     lud_crit_exts; |     int     lud_crit_exts; | ||||||
| } LDAPURLDesc; | } LDAPURLDesc; | ||||||
|  |  | ||||||
|  | #ifdef WIN32 | ||||||
|  | static int  _ldap_url_parse (const struct connectdata *conn, | ||||||
|  |                              LDAPURLDesc **ludp); | ||||||
|  | static void _ldap_free_urldesc (LDAPURLDesc *ludp); | ||||||
|  |  | ||||||
|  | static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef DEBUG_LDAP | ||||||
|  |   #define LDAP_TRACE(x)   do { \ | ||||||
|  |                             _ldap_trace ("%u: ", __LINE__); \ | ||||||
|  |                             _ldap_trace x; \ | ||||||
|  |                           } while (0) | ||||||
|  |  | ||||||
|  |   static void _ldap_trace (const char *fmt, ...); | ||||||
|  | #else | ||||||
|  |   #define LDAP_TRACE(x)   ((void)0) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| CURLcode Curl_ldap(struct connectdata *conn) | CURLcode Curl_ldap(struct connectdata *conn) | ||||||
| { | { | ||||||
|   CURLcode status = CURLE_OK; |   CURLcode status = CURLE_OK; | ||||||
|   int rc; |   int rc = 0; | ||||||
|   void *(*ldap_init)(char *, int); | #ifndef WIN32 | ||||||
|   int (*ldap_simple_bind_s)(void *, char *, char *); |  | ||||||
|   int (*ldap_unbind_s)(void *); |  | ||||||
|   int    (*ldap_url_parse)(char *, LDAPURLDesc **); |   int    (*ldap_url_parse)(char *, LDAPURLDesc **); | ||||||
|   void   (*ldap_free_urldesc)(void *); |   void   (*ldap_free_urldesc)(void *); | ||||||
|   int (*ldap_search_s)(void *, char *, int, char *, char **, int, void **); | #endif | ||||||
|   int (*ldap_search_st)(void *, char *, int, char *, char **, int, void *, void **); |   void  *(__cdecl *ldap_init)(char *, int); | ||||||
|   void *(*ldap_first_entry)(void *, void *); |   int    (__cdecl *ldap_simple_bind_s)(void *, char *, char *); | ||||||
|   void *(*ldap_next_entry)(void *, void *); |   int    (__cdecl *ldap_unbind_s)(void *); | ||||||
|   char *(*ldap_err2string)(int); |   int    (__cdecl *ldap_search_s)(void *, char *, int, char *, char **, | ||||||
|   char *(*ldap_get_dn)(void *, void *); |                                   int, void **); | ||||||
|   char *(*ldap_first_attribute)(void *, void *, void **); |   void  *(__cdecl *ldap_first_entry)(void *, void *); | ||||||
|   char *(*ldap_next_attribute)(void *, void *, void *); |   void  *(__cdecl *ldap_next_entry)(void *, void *); | ||||||
|   char **(*ldap_get_values)(void *, void *, char *); |   char  *(__cdecl *ldap_err2string)(int); | ||||||
|   void (*ldap_value_free)(char **); |   char  *(__cdecl *ldap_get_dn)(void *, void *); | ||||||
|   void (*ldap_memfree)(void *); |   char  *(__cdecl *ldap_first_attribute)(void *, void *, void **); | ||||||
|   void (*ber_free)(void *, int); |   char  *(__cdecl *ldap_next_attribute)(void *, void *, void *); | ||||||
|  |   char **(__cdecl *ldap_get_values)(void *, void *, const char *); | ||||||
|  |   void   (__cdecl *ldap_value_free)(char **); | ||||||
|  |   void   (__cdecl *ldap_memfree)(void *); | ||||||
|  |   void   (__cdecl *ber_free)(void *, int); | ||||||
|  |  | ||||||
|   void *server; |   void *server; | ||||||
|   LDAPURLDesc *ludp; |   LDAPURLDesc *ludp = NULL; | ||||||
|  |   const char *mod_name; | ||||||
|   void *result; |   void *result; | ||||||
|   void *entryIterator; |   void *entryIterator;     /*! type should be 'LDAPMessage *' */ | ||||||
|   void *ber; |   int ldaptext, num = 0; | ||||||
|   void *attribute; |  | ||||||
|  |  | ||||||
|   struct SessionHandle *data=conn->data; |   struct SessionHandle *data=conn->data; | ||||||
|  |  | ||||||
|   infof(data, "LDAP: %s\n", data->change.url); |   infof(data, "LDAP local: %s\n", data->change.url); | ||||||
|  |  | ||||||
|   DynaOpen(); |   if (!DynaOpen(&mod_name)) { | ||||||
|   if (libldap == NULL) { |     failf(data, "The %s LDAP library/libraries couldn't be opened", mod_name); | ||||||
|     failf(data, "The needed LDAP library/libraries couldn't be opened"); |  | ||||||
|     return CURLE_LIBRARY_NOT_FOUND; |     return CURLE_LIBRARY_NOT_FOUND; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   ldaptext = data->set.ftp_ascii; /* This is a dirty hack */ | ||||||
|  |  | ||||||
|   /* The types are needed because ANSI C distinguishes between |   /* The types are needed because ANSI C distinguishes between | ||||||
|    * pointer-to-object (data) and pointer-to-function. |    * pointer-to-object (data) and pointer-to-function. | ||||||
|    */ |    */ | ||||||
|   DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_init); |   DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_init); | ||||||
|   DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s); |   DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s); | ||||||
|   DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s); |   DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s); | ||||||
|  | #ifndef WIN32 | ||||||
|   DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse); |   DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse); | ||||||
|   DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc); |   DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc); | ||||||
|   DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int, void **), ldap_search_s); | #endif | ||||||
|   DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int, void *, void **), ldap_search_st); |   DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int, | ||||||
|  |                             void **), ldap_search_s); | ||||||
|   DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry); |   DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry); | ||||||
|   DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry); |   DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry); | ||||||
|   DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string); |   DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string); | ||||||
|   DYNA_GET_FUNCTION(char *(*)(void *, void *), ldap_get_dn); |   DYNA_GET_FUNCTION(char *(*)(void *, void *), ldap_get_dn); | ||||||
|   DYNA_GET_FUNCTION(char *(*)(void *, void *, void **), ldap_first_attribute); |   DYNA_GET_FUNCTION(char *(*)(void *, void *, void **), ldap_first_attribute); | ||||||
|   DYNA_GET_FUNCTION(char *(*)(void *, void *, void *), ldap_next_attribute); |   DYNA_GET_FUNCTION(char *(*)(void *, void *, void *), ldap_next_attribute); | ||||||
|   DYNA_GET_FUNCTION(char **(*)(void *, void *, char *), ldap_get_values); |   DYNA_GET_FUNCTION(char **(*)(void *, void *, const char *), ldap_get_values); | ||||||
|   DYNA_GET_FUNCTION(void (*)(char **), ldap_value_free); |   DYNA_GET_FUNCTION(void (*)(char **), ldap_value_free); | ||||||
|   DYNA_GET_FUNCTION(void (*)(void *), ldap_memfree); |   DYNA_GET_FUNCTION(void (*)(void *), ldap_memfree); | ||||||
|   DYNA_GET_FUNCTION(void (*)(void *, int), ber_free); |   DYNA_GET_FUNCTION(void (*)(void *, int), ber_free); | ||||||
|  |  | ||||||
|   server = ldap_init(conn->host.name, conn->port); |   server = (*ldap_init)(conn->host.name, conn->port); | ||||||
|   if (server == NULL) { |   if (server == NULL) { | ||||||
|     failf(data, "LDAP: Cannot connect to %s:%d", |     failf(data, "LDAP local: Cannot connect to %s:%d", | ||||||
|           conn->host.name, conn->port); |           conn->host.name, conn->port); | ||||||
|     status = CURLE_COULDNT_CONNECT; |     status = CURLE_COULDNT_CONNECT; | ||||||
|  |     goto quit; | ||||||
|   } |   } | ||||||
|   else { |  | ||||||
|     rc = ldap_simple_bind_s(server, |   rc = (*ldap_simple_bind_s)(server, | ||||||
|                             conn->bits.user_passwd?conn->user:NULL, |                              conn->bits.user_passwd ? conn->user : NULL, | ||||||
|                             conn->bits.user_passwd?conn->passwd:NULL); |                              conn->bits.user_passwd ? conn->passwd : NULL); | ||||||
|   if (rc != 0) { |   if (rc != 0) { | ||||||
|       failf(data, "LDAP: %s", ldap_err2string(rc)); |      failf(data, "LDAP local: %s", (*ldap_err2string)(rc)); | ||||||
|      status = CURLE_LDAP_CANNOT_BIND; |      status = CURLE_LDAP_CANNOT_BIND; | ||||||
|  |      goto quit; | ||||||
|   } |   } | ||||||
|     else { |  | ||||||
|       rc = ldap_url_parse(data->change.url, &ludp); | #ifdef WIN32 | ||||||
|  |   rc = _ldap_url_parse(conn, &ludp); | ||||||
|  | #else | ||||||
|  |   rc = (*ldap_url_parse)(data->change.url, &ludp); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   if (rc != 0) { |   if (rc != 0) { | ||||||
| 	failf(data, "LDAP: %s", ldap_err2string(rc)); |      failf(data, "LDAP local: %s", (*ldap_err2string)(rc)); | ||||||
|      status = CURLE_LDAP_INVALID_URL; |      status = CURLE_LDAP_INVALID_URL; | ||||||
|  |      goto quit; | ||||||
|   } |   } | ||||||
|       else { |  | ||||||
| 	rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, |   rc = (*ldap_search_s)(server, ludp->lud_dn, ludp->lud_scope, | ||||||
|                         ludp->lud_filter, ludp->lud_attrs, 0, &result); |                         ludp->lud_filter, ludp->lud_attrs, 0, &result); | ||||||
| 	if (rc != 0) { |  | ||||||
| 	  failf(data, "LDAP: %s", ldap_err2string(rc)); |   if (rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { | ||||||
|  |     failf(data, "LDAP remote: %s", (*ldap_err2string)(rc)); | ||||||
|     status = CURLE_LDAP_SEARCH_FAILED; |     status = CURLE_LDAP_SEARCH_FAILED; | ||||||
|  |     goto quit; | ||||||
|   } |   } | ||||||
| 	else { |  | ||||||
| 	  for (entryIterator = ldap_first_entry(server, result); |   for(num = 0, entryIterator = (*ldap_first_entry)(server, result); | ||||||
|       entryIterator; |       entryIterator; | ||||||
| 	       entryIterator = ldap_next_entry(server, entryIterator)) { |       entryIterator = (*ldap_next_entry)(server, entryIterator), num++) | ||||||
|             char *dn = ldap_get_dn(server, entryIterator); |   { | ||||||
|             char **vals; |     void  *ber = NULL;      /*! is really 'BerElement **' */ | ||||||
|  |     void  *attribute;       /*! suspicious that this isn't 'const' */ | ||||||
|  |     char  *dn = (*ldap_get_dn)(server, entryIterator); | ||||||
|     int i; |     int i; | ||||||
|  |  | ||||||
|     Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4); |     Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4); | ||||||
|             Curl_client_write(data, CLIENTWRITE_BODY, dn, 0); |     Curl_client_write(data, CLIENTWRITE_BODY, (char *)dn, 0); | ||||||
|     Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); |     Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); | ||||||
|             for(attribute = ldap_first_attribute(server, entryIterator, |  | ||||||
|                                                  &ber);  |     for (attribute = (*ldap_first_attribute)(server, entryIterator, &ber); | ||||||
|          attribute; |          attribute; | ||||||
|                 attribute = ldap_next_attribute(server, entryIterator, |          attribute = (*ldap_next_attribute)(server, entryIterator, ber)) | ||||||
|                                                 ber) ) { |     { | ||||||
|               vals = ldap_get_values(server, entryIterator, attribute); |       char **vals = (*ldap_get_values)(server, entryIterator, attribute); | ||||||
|               if (vals != NULL) { |  | ||||||
|                 for(i = 0; (vals[i] != NULL); i++) { |       if (vals != NULL) | ||||||
|                   Curl_client_write(data, CLIENTWRITE_BODY, (char*)"\t", 1); |       { | ||||||
|                   Curl_client_write(data, CLIENTWRITE_BODY, attribute, 0); |         for (i = 0; (vals[i] != NULL); i++) | ||||||
|  |         { | ||||||
|  |           Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1); | ||||||
|  |           Curl_client_write(data, CLIENTWRITE_BODY, (char*) attribute, 0); | ||||||
|           Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2); |           Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2); | ||||||
|           Curl_client_write(data, CLIENTWRITE_BODY, vals[i], 0); |           Curl_client_write(data, CLIENTWRITE_BODY, vals[i], 0); | ||||||
|           Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0); |           Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0); | ||||||
|         } |         } | ||||||
|               } |  | ||||||
|  |  | ||||||
|         /* Free memory used to store values */ |         /* Free memory used to store values */ | ||||||
|               ldap_value_free(vals); |         (*ldap_value_free)(vals); | ||||||
|       } |       } | ||||||
|       Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); |       Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); | ||||||
|  |  | ||||||
|             ldap_memfree(attribute); |       (*ldap_memfree)(attribute); | ||||||
|             ldap_memfree(dn); |       (*ldap_memfree)(dn); | ||||||
|             if (ber) ber_free(ber, 0); |  | ||||||
|     } |     } | ||||||
|  |     if (ber) | ||||||
|  |        (*ber_free)(ber, 0); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 	ldap_free_urldesc(ludp); | quit: | ||||||
|       } |   LDAP_TRACE (("Received %d entries\n", num)); | ||||||
|       ldap_unbind_s(server); |   if (rc == LDAP_SIZELIMIT_EXCEEDED) | ||||||
|     } |      infof(data, "There are more than %d entries\n", num); | ||||||
|   } |   if (ludp) | ||||||
|  |      (*ldap_free_urldesc)(ludp); | ||||||
|  |   if (server) | ||||||
|  |      (*ldap_unbind_s)(server); | ||||||
|  |  | ||||||
|   DynaClose(); |   DynaClose(); | ||||||
|  |  | ||||||
|   /* no data to transfer */ |   /* no data to transfer */ | ||||||
| @@ -273,4 +375,258 @@ CURLcode Curl_ldap(struct connectdata *conn) | |||||||
|  |  | ||||||
|   return status; |   return status; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifdef DEBUG_LDAP | ||||||
|  | static void _ldap_trace (const char *fmt, ...) | ||||||
|  | { | ||||||
|  |   static int do_trace = -1; | ||||||
|  |   va_list args; | ||||||
|  |  | ||||||
|  |   if (do_trace == -1) { | ||||||
|  |     const char *env = getenv("CURL_TRACE"); | ||||||
|  |     do_trace = (env && atoi(env) > 0); | ||||||
|  |   } | ||||||
|  |   if (!do_trace) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   va_start (args, fmt); | ||||||
|  |   vfprintf (stderr, fmt, args); | ||||||
|  |   va_end (args); | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef WIN32 | ||||||
|  | /* | ||||||
|  |  * Return scope-value for a scope-string. | ||||||
|  |  */ | ||||||
|  | static int str2scope (const char *p) | ||||||
|  | { | ||||||
|  |   if (!stricmp(p, "one")) | ||||||
|  |      return LDAP_SCOPE_ONELEVEL; | ||||||
|  |   if (!stricmp(p, "onetree")) | ||||||
|  |      return LDAP_SCOPE_ONELEVEL; | ||||||
|  |   if (!stricmp(p, "base")) | ||||||
|  |      return LDAP_SCOPE_BASE; | ||||||
|  |   if (!stricmp(p, "sub")) | ||||||
|  |      return LDAP_SCOPE_SUBTREE; | ||||||
|  |   if (!stricmp( p, "subtree")) | ||||||
|  |      return LDAP_SCOPE_SUBTREE; | ||||||
|  |   return (-1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Split 'str' into strings separated by commas. | ||||||
|  |  * Note: res[] points into 'str'. | ||||||
|  |  */ | ||||||
|  | static char **split_str (char *str) | ||||||
|  | { | ||||||
|  |   char **res, *lasts, *s; | ||||||
|  |   int  i; | ||||||
|  |  | ||||||
|  |   for (i = 2, s = strchr(str,','); s; i++) | ||||||
|  |      s = strchr(++s,','); | ||||||
|  |  | ||||||
|  |   LDAP_TRACE(("split_str: %d strings\n", i)); | ||||||
|  |  | ||||||
|  |   res = calloc(i, sizeof(char*)); | ||||||
|  |   if (!res) | ||||||
|  |     return NULL; | ||||||
|  |  | ||||||
|  |   for (i = 0, s = strtok_r(str, ",", &lasts); s; | ||||||
|  |        s = strtok_r(NULL, ",", &lasts), i++) | ||||||
|  |     res[i] = s; | ||||||
|  |   return res; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Unescape the LDAP-URL components | ||||||
|  |  */ | ||||||
|  | static bool unescape_elements (LDAPURLDesc *ludp) | ||||||
|  | { | ||||||
|  |   int i; | ||||||
|  |  | ||||||
|  |   if (ludp->lud_dn) { | ||||||
|  |     char *dn = ludp->lud_dn; | ||||||
|  |     char *new_dn = curl_unescape(dn, 0); | ||||||
|  |  | ||||||
|  |     free(dn); | ||||||
|  |     if (!new_dn) | ||||||
|  |        return (FALSE); | ||||||
|  |     ludp->lud_dn = new_dn; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (ludp->lud_filter) { | ||||||
|  |     ludp->lud_filter = curl_unescape(ludp->lud_filter, 0); | ||||||
|  |     if (!ludp->lud_filter) | ||||||
|  |        return (FALSE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) { | ||||||
|  |     ludp->lud_attrs[i] = curl_unescape(ludp->lud_attrs[i], 0); | ||||||
|  |     if (!ludp->lud_attrs[i]) | ||||||
|  |        return (FALSE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) { | ||||||
|  |     ludp->lud_exts[i] = curl_unescape(ludp->lud_exts[i], 0); | ||||||
|  |     if (!ludp->lud_exts[i]) | ||||||
|  |        return (FALSE); | ||||||
|  |   } | ||||||
|  |   return (TRUE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Break apart the pieces of an LDAP URL. | ||||||
|  |  * Syntax: | ||||||
|  |  *   ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext> | ||||||
|  |  * | ||||||
|  |  * <hostname> already known from 'conn->host.name'. | ||||||
|  |  * <port>     already known from 'conn->remote_port'. | ||||||
|  |  * extract the rest from 'conn->path+1'. All fields are optional. e.g. | ||||||
|  |  *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter> yields ludp->lud_dn = "". | ||||||
|  |  * | ||||||
|  |  * Ref. http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm#2831915 | ||||||
|  |  */ | ||||||
|  | static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) | ||||||
|  | { | ||||||
|  |   char *p, *q; | ||||||
|  |   int i; | ||||||
|  |  | ||||||
|  |   if (!conn->path || conn->path[0] != '/' || | ||||||
|  |       !checkprefix(conn->protostr, conn->data->change.url)) | ||||||
|  |      return LDAP_INVALID_SYNTAX; | ||||||
|  |  | ||||||
|  |   ludp->lud_scope = LDAP_SCOPE_BASE; | ||||||
|  |   ludp->lud_port  = conn->remote_port; | ||||||
|  |   ludp->lud_host  = conn->host.name; | ||||||
|  |  | ||||||
|  |   LDAP_TRACE (("host '%s'\n", ludp->lud_host)); | ||||||
|  |  | ||||||
|  |   /* parse DN (Distinguished Name). | ||||||
|  |    */ | ||||||
|  |   ludp->lud_dn = strdup(conn->path+1); | ||||||
|  |   if (!ludp->lud_dn) | ||||||
|  |      return LDAP_NO_MEMORY; | ||||||
|  |  | ||||||
|  |   p = strchr(ludp->lud_dn, '?'); | ||||||
|  |   LDAP_TRACE (("DN '%.*s'\n", p ? (p-ludp->lud_dn) : strlen(ludp->lud_dn), | ||||||
|  |                ludp->lud_dn)); | ||||||
|  |  | ||||||
|  |   if (!p) | ||||||
|  |      goto success; | ||||||
|  |  | ||||||
|  |   *p++ = '\0'; | ||||||
|  |  | ||||||
|  |   /* parse attributes. skip "??". | ||||||
|  |    */ | ||||||
|  |   q = strchr(p, '?'); | ||||||
|  |   if (q) | ||||||
|  |      *q++ = '\0'; | ||||||
|  |  | ||||||
|  |   if (*p && *p != '?') { | ||||||
|  |     ludp->lud_attrs = split_str(p); | ||||||
|  |     if (!ludp->lud_attrs) | ||||||
|  |        return LDAP_NO_MEMORY; | ||||||
|  |  | ||||||
|  |     for (i = 0; ludp->lud_attrs[i]; i++) | ||||||
|  |         LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i])); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   p = q; | ||||||
|  |   if (!p) | ||||||
|  |      goto success; | ||||||
|  |  | ||||||
|  |   /* parse scope. skip "??" | ||||||
|  |    */ | ||||||
|  |   q = strchr(p, '?'); | ||||||
|  |   if (q) | ||||||
|  |      *q++ = '\0'; | ||||||
|  |  | ||||||
|  |   if (*p && *p != '?') { | ||||||
|  |     ludp->lud_scope = str2scope(p); | ||||||
|  |     if (ludp->lud_scope == -1) | ||||||
|  |        return LDAP_INVALID_SYNTAX; | ||||||
|  |     LDAP_TRACE (("scope %d\n", ludp->lud_scope)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   p = q; | ||||||
|  |   if (!p) | ||||||
|  |      goto success; | ||||||
|  |  | ||||||
|  |   /* parse filter | ||||||
|  |    */ | ||||||
|  |   q = strchr(p, '?'); | ||||||
|  |   if (q) | ||||||
|  |      *q++ = '\0'; | ||||||
|  |   if (!*p) | ||||||
|  |      return LDAP_INVALID_SYNTAX; | ||||||
|  |  | ||||||
|  |   ludp->lud_filter = p; | ||||||
|  |   LDAP_TRACE (("filter '%s'\n", ludp->lud_filter)); | ||||||
|  |  | ||||||
|  |   p = q; | ||||||
|  |   if (!p) | ||||||
|  |      goto success; | ||||||
|  |  | ||||||
|  |   /* parse extensions | ||||||
|  |    */ | ||||||
|  |   ludp->lud_exts = split_str(p); | ||||||
|  |   if (!ludp->lud_exts) | ||||||
|  |      return LDAP_NO_MEMORY; | ||||||
|  |  | ||||||
|  |   for (i = 0; ludp->lud_exts[i]; i++) | ||||||
|  |       LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i])); | ||||||
|  |  | ||||||
|  | success: | ||||||
|  |   if (!unescape_elements(ludp)) | ||||||
|  |      return LDAP_NO_MEMORY; | ||||||
|  |   return LDAP_SUCCESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int _ldap_url_parse (const struct connectdata *conn, | ||||||
|  |                             LDAPURLDesc **ludpp) | ||||||
|  | { | ||||||
|  |   LDAPURLDesc *ludp = calloc(sizeof(*ludp), 1); | ||||||
|  |   int rc; | ||||||
|  |  | ||||||
|  |   *ludpp = NULL; | ||||||
|  |   if (!ludp) | ||||||
|  |      return LDAP_NO_MEMORY; | ||||||
|  |  | ||||||
|  |   rc = _ldap_url_parse2 (conn, ludp); | ||||||
|  |   if (rc != LDAP_SUCCESS) { | ||||||
|  |     _ldap_free_urldesc(ludp); | ||||||
|  |     ludp = NULL; | ||||||
|  |   } | ||||||
|  |   *ludpp = ludp; | ||||||
|  |   return (rc); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void _ldap_free_urldesc (LDAPURLDesc *ludp) | ||||||
|  | { | ||||||
|  |   int i; | ||||||
|  |  | ||||||
|  |   if (!ludp) | ||||||
|  |      return; | ||||||
|  |  | ||||||
|  |   if (ludp->lud_dn) | ||||||
|  |      free(ludp->lud_dn); | ||||||
|  |  | ||||||
|  |   if (ludp->lud_filter) | ||||||
|  |      free(ludp->lud_filter); | ||||||
|  |  | ||||||
|  |   if (ludp->lud_attrs) { | ||||||
|  |     for (i = 0; ludp->lud_attrs[i]; i++) | ||||||
|  |        free(ludp->lud_attrs[i]); | ||||||
|  |     free(ludp->lud_attrs); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (ludp->lud_exts) { | ||||||
|  |     for (i = 0; ludp->lud_exts[i]; i++) | ||||||
|  |        free(ludp->lud_exts[i]); | ||||||
|  |     free(ludp->lud_exts); | ||||||
|  |   } | ||||||
|  |   free (ludp); | ||||||
|  | } | ||||||
|  | #endif	/* WIN32 */ | ||||||
|  | #endif	/* CURL_DISABLE_LDAP */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Daniel Stenberg
					Daniel Stenberg