Bonjour à tous !

Je suis confronté à une difficulté depuis maintenant presque 2 semaines et, étant cours d'idée sur le sujet, je viens partager celui-ci avec vous.

Le sujet : développement d'un requêteur LDAP en c++. Jusque là rien de bien compliqué mais de multiples contraintes ont rendu ce projet sans-fin. Le serveur a requêter est un LDAP Lotus Domino en SSL. Le développement est fait avec Visual Studio 2013 Pro (chaque possibilité décrites ci-dessous ont aussi été testé avec VS 2008 Pro).

J'ai donc commencé par utiliser la librairie winldap. Le fonctionnement est Ok sur l'ensemble de mes serveurs de tests, mais sur le serveur cible cela ne fonctionnait que sur WinXP, pas Win7. Afin de valider le fonctionnement de l'outil, j'ai effectué les même tests avec deux soft du commerce : Softerra Ldap Browser 2.6 et Softerra Ldap Browser 4.5 (www.ldapbrowser.com)
Résultat des tests :
  • Softerra LDAP Browser 2.6 sur WinXP : OK
  • Softerra LDAP Browser 2.6 sur Win7 : OK
  • Softerra LDAP Browser 4.5 sur WinXP : OK
  • Softerra LDAP Browser 4.5 sur Win7 : KO
  • Mon outil sur WinXP : OK
  • Mon outil sur Win7 : KO


Lors d'un KO, le code erreur LDAP est 0x51 ==> LDAP_SERVER_DOWN.
Le message dans le journal d'activité windows est plus explicite :
Fatal alert 40, Internal error 107.

An SSL 3.0 connection request was received from a remote client application , but none of the cipher suites supported by the client application is supported by the server. The SSL connection request has failed.
Pour info, le certificat utilisé :
Key Info - RSA 2048-bit Signature Algorithm - SHA-1 with RSA Encryption Product Name - Digital ID Class 3 - VeriSign Global Server OnSite Two Year
Bon, déjà je me dit que mon outil n'est pas complètement naze, il fonctionne sur l'ensemble des serveurs quel que soit la plateforme sur lequel il est déployé, il fonctionne sur le serveur cible depuis WinXP mais surtout il a exactement le même comportement que le soft de Softerra.

Possibilité N°1 - Bascule sur Mozilla LDAP C-SDK
La question qui se pose après ces tests c'est pourquoi la 2.6 fonctionne quelle que soit la plateforme mais pas la 4.5 (et donc mon outils) ? Après quelques recherches, la 2.6 est basée sur Mozilla LDAP C-SDK contrairement à la version 4.5 basé sur winldap.
Ok, je vais donc migrer sur Mozilla LDAP C-SDK (https://wiki.mozilla.org/LDAP_C_SDK).

Les sources étant disponibles, il "suffit" de les compiler et j'aurais ma bibliothèque mais la compilation ne se passe pas aussi bien que je ne l'aurais voulu. Pour compiler j'ai utiliser cygwin et l'autoconf, mais un paquet d'erreur ne m'ont pas permit de continuer :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
sh ../../../config/cygwin-wrapper gcc -o decode.o -c -pipe -pthread -O -UDEBUG -DNDEBUG=1 -DXP_PC=1 -DWIN32=1 -D_WINDOWS=1 -DWINNT=1 -D_X86_=1 -DFORCE_PR_LOG -DUSE_WAITPID -DNEEDPROTOS -DNET_SSL -DNO_LIBLCACHE -DLDAP_REFERRALS -DNS_DOMESTIC -I../../../ldap/include -I../../../../../dist/./include decode.c
 
gcc: erreur: /ID:/mozldap-6.0.7/mozldap-6.0.7/c-sdk/ldap/include: No such file or directory
Et pourtant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
$ ls D:/mozldap-6.0.7/mozldap-6.0.7/c-sdk/ldap/included
isptmpl.h  lber.h    ldap.h      ldap-deprecated.h  ldaplog.h ldappr.h   ldap-standard-tmpl.h     ldif.h    Makefile.client  MANIFEST    proto-ntutil.h  srchpref.h iutil.h lcache.h  ldap_ssl.h  ldap-extension.h ldap-platform.h  ldaprot.h  ldap-to-be-deprecated.h  Makefile  Makefile.in portable.h  regex.h
Étonnant, et je n’arrive pas à me l'expliquer.

J'ai essayé de me tourner vers une version binaire de cette bibliothèque : ftp://ftp.mozilla.org/pub/mozilla.or...leases/v6.0.4/
Pas mieux, lors de l'exécution :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
Runtime Error!
 
R6034
 
An application has made an attempt to load the C runtime library incorrectly.
D'après le msdn il s'agit d'un problème de manifest, mais ma dll est bien déclaré (de plus j'ai essayé de compiler avec mingw mon code et le message d'erreur est le même).

Mon code de test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <ldap.h>
#include <sasl.h>
 
using namespace std;
 
static int sasl_flags = LDAP_SASL_QUIET;
static char *sasl_mech = "GSSAPI";
 
#define VALIDVAL(n) ((n >= SASL_CB_USER) && (n <= SASL_CB_GETREALM))
#define VAL(n) default_values[n-0x4001]
 
static int
example_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *prompts) {
    if (prompts == NULL) {
        return (LDAP_PARAM_ERROR);
    }
    return (LDAP_SUCCESS);
}
 
int main() {
    int rc;
    LDAP *ld;
    LDAPControl     **ctrls = NULL;
    int ldversion = LDAP_VERSION3;
    int debuglevel = 0;
 
    ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debuglevel);
    if ((ld = ldap_init("10.5.97.2", 636)) == NULL) {
        return 1;
    }
 
    ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
 
    rc = ldap_sasl_interactive_bind_ext_s(ld, "", sasl_mech,
        NULL, NULL, sasl_flags,
        example_sasl_interact, NULL, &ctrls);
 
    if (rc != LDAP_SUCCESS) {
        ldap_perror(ld, "Bind Error");
    }
    else {
        sasl_ssf_t      ssf;
        unsigned long val = 0;
        if (!ldap_get_option(ld, LDAP_OPT_X_SASL_SSF, &ssf)) {
            val = (unsigned long)ssf;
        }
        cout << "Bind successful, security level is " << val << endl;
    }
 
    return 0;
}
J'aimerais arriver à compiler la bibliothèque, mais je sèche complètement sur le sujet.

Possibilité N°2 - Bascule sur SUN LDAP C-SDK
Après quelques recherches, SUN a la même chose que mozilla mais livre les binaires (c'est la même bibliothèque avec quelques modifications notamment sur la partie SSL, on y retrouve des référence à Mozilla) ==> https://oss.oracle.com/projects/sun-ldapcsdk/.
Malheureusemennt, ils fournissent les .dll, les .h mais pas de .lib ou de .o. J'ai donc voulu générer mes .lib via l'utilisation de expdef.exe (http://purefractalsolutions.com/show.php?a=utils/expdef) et de LIB.exe de VS2008.
J'ai commencé par m'attaquer à nsldap32v50.dll, un dumpbin.exe de cette DLL me donne (ceci n'est pas le résultat complet, juste une extraction) :
LIBRARY NSLDAP32V50.dll
EXPORTS
ldap_abandon @10
ldap_add @11
ldap_unbind @13
....
ldap_set_option @418
...
Un dumpbin.exe du .lib généré :
Dump of file nsldap32v50.lib
File Type: LIBRARY
Exports ordinal name
...
418 _ldap_set_option
...
Impec Un rapide code de test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <ldap.h>
int main(int argc, _TCHAR* argv[])
{
    LDAP        *ld;
    LDAPMessage *result, *e;
    BerElement  *ber;
    char        *a, *dn;
    char        **vals;
    int     i;
    int ldversion = LDAP_VERSION3;
    int debuglevel = 7;
    LDAPControl     **ctrls = NULL;
 
    ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debuglevel);
 
    std::cout << "Hellow World !" << std::endl;
    return 0;
}
Et je me prend un erreur lors du link :
TestLdapSun.obj : error LNK2001: unresolved external symbol _ldap_set_option@12
TestLdapSun.exe : fatal error LNK1120: 1 unresolved externals
La librairie est pourtant bien linké. Par contre le link recherche l'adresse de la fonction _ldap_set_option@12 alors que mes lib et dll sont au format _ldap_set_option.
Donc un problème de convention de nommage. En farfouillant dans les .h de SUN, je tombe là dessus :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
LDAP_API(int) LDAP_CALL ldap_set_option( LDAP *ld, int option, const void *optdata );
avec :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
#define LDAP_PASCAL __stdcall
#define LDAP_CALL LDAP_PASCAL
Ok, je change le DEFINE pour utiliser la "bonne" convention de nommage :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
#define LDAP_PASCAL __cdecl
#define LDAP_CALL LDAP_PASCAL
Et là, miracle, ça link
Mais lors de l'exécution :
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function pointer declared with a different calling convention.
Et oui, c'était trop beau et le changement de convention de nommage à la sauvage je le sentais moyen.
Pareil que pour la première possibilité, je sèche complètement là dessus.


Si vous avez des idées ou des pistes de réflexions sur l'une ou l'autre possibilité, je suis preneur.
Désolé pour la longueur du post, mais il me semblait important de vous présenter la démarche m'ayant conduit à ces résultats.

Merci d'avance à vous et bonne journée