diff --git a/configure b/configure index a7bcae77b98..d263b46594e 100755 --- a/configure +++ b/configure @@ -7427,6 +7427,7 @@ for ac_header in \ port.h \ pthread.h \ pwd.h \ + sasl/sasl.h \ sched.h \ scsi/scsi.h \ scsi/scsi_ioctl.h \ diff --git a/configure.ac b/configure.ac index b7bd7fb0798..9770be795c0 100644 --- a/configure.ac +++ b/configure.ac @@ -487,6 +487,7 @@ AC_CHECK_HEADERS(\ port.h \ pthread.h \ pwd.h \ + sasl/sasl.h \ sched.h \ scsi/scsi.h \ scsi/scsi_ioctl.h \ diff --git a/dlls/wldap32/bind.c b/dlls/wldap32/bind.c index 27fb286f501..63d4208eef8 100644 --- a/dlls/wldap32/bind.c +++ b/dlls/wldap32/bind.c @@ -25,10 +25,14 @@ #ifdef HAVE_LDAP_H #include #endif +#ifdef HAVE_SASL_SASL_H +#include +#endif #include "windef.h" #include "winbase.h" #include "winnls.h" +#include "rpc.h" #include "winldap_private.h" #include "wldap32.h" @@ -156,20 +160,67 @@ ULONG CDECL ldap_bind_sA( WLDAP32_LDAP *ld, PCHAR dn, PCHAR cred, ULONG method ) if (!dnW) goto exit; } if (cred) { - credW = strAtoW( cred ); - if (!credW) goto exit; + if (method == LDAP_AUTH_SIMPLE) + { + credW = strAtoW( cred ); + if (!credW) goto exit; + } + else + credW = (WCHAR *)cred /* SEC_WINNT_AUTH_IDENTITY_A */; } ret = ldap_bind_sW( ld, dnW, credW, method ); exit: strfreeW( dnW ); - strfreeW( credW ); + if (credW != (WCHAR *)cred) strfreeW( credW ); #endif return ret; } +#ifdef HAVE_LDAP_H + +static int sasl_interact( LDAP *ld, unsigned flags, void *defaults, void *interact ) +{ +#ifdef HAVE_SASL_SASL_H + SEC_WINNT_AUTH_IDENTITY_A *id = defaults; + sasl_interact_t *sasl = interact; + + TRACE( "%p,%08x,%p,%p\n", ld, flags, defaults, interact ); + + while (sasl->id != SASL_CB_LIST_END) + { + TRACE("sasl->id = %04lx\n", sasl->id); + + if (sasl->id == SASL_CB_GETREALM) + { + sasl->result = id->Domain; + sasl->len = id->DomainLength; + } + else if (sasl->id == SASL_CB_USER) + { + sasl->result = id->User; + sasl->len = id->UserLength; + } + else if (sasl->id == SASL_CB_PASS) + { + sasl->result = id->Password; + sasl->len = id->PasswordLength; + } + + sasl++; + } + + return LDAP_SUCCESS; +#else + FIXME( "%p,%08x,%p,%p: stub\n", ld, flags, defaults, interact ); + return LDAP_SUCCESS; +#endif /* HAVE_SASL_SASL_H */ +} + +#endif /* HAVE_LDAP_H */ + /*********************************************************************** * ldap_bind_sW (WLDAP32.@) * @@ -197,21 +248,71 @@ ULONG CDECL ldap_bind_sW( WLDAP32_LDAP *ld, PWCHAR dn, PWCHAR cred, ULONG method TRACE( "(%p, %s, %p, 0x%08x)\n", ld, debugstr_w(dn), cred, method ); if (!ld) return WLDAP32_LDAP_PARAM_ERROR; - if (method != LDAP_AUTH_SIMPLE) return WLDAP32_LDAP_PARAM_ERROR; - if (dn) { - dnU = strWtoU( dn ); - if (!dnU) goto exit; + if (method == LDAP_AUTH_SIMPLE) + { + if (dn) + { + dnU = strWtoU( dn ); + if (!dnU) goto exit; + } + if (cred) + { + credU = strWtoU( cred ); + if (!credU) goto exit; + + pwd.bv_len = strlen( credU ); + pwd.bv_val = credU; + } + + ret = map_error( ldap_sasl_bind_s( ld, dnU, LDAP_SASL_SIMPLE, &pwd, NULL, NULL, NULL )); } - if (cred) { - credU = strWtoU( cred ); - if (!credU) goto exit; + else if (method == WLDAP32_LDAP_AUTH_NEGOTIATE) + { + SEC_WINNT_AUTH_IDENTITY_A idU; + SEC_WINNT_AUTH_IDENTITY_W idW; + SEC_WINNT_AUTH_IDENTITY_W *id = (SEC_WINNT_AUTH_IDENTITY_W *)cred; - pwd.bv_len = strlen( credU ); - pwd.bv_val = credU; + memset( &idU, 0, sizeof(idU) ); + + if (id) + { + if (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) + { + idW.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + idW.Domain = (unsigned short *)strnAtoW( (char *)id->Domain, id->DomainLength, &idW.DomainLength ); + idW.User = (unsigned short *)strnAtoW( (char *)id->User, id->UserLength, &idW.UserLength ); + idW.Password = (unsigned short *)strnAtoW( (char *)id->Password, id->PasswordLength, &idW.PasswordLength ); + + id = &idW; + } + + idU.Domain = (unsigned char *)strnWtoU( id->Domain, id->DomainLength, &idU.DomainLength ); + idU.User = (unsigned char *)strnWtoU( id->User, id->UserLength, &idU.UserLength ); + idU.Password = (unsigned char *)strnWtoU( id->Password, id->PasswordLength, &idU.PasswordLength ); + } + + ret = map_error( ldap_sasl_interactive_bind_s( ld, + NULL /* server will ignore DN anyway */, + NULL /* query supportedSASLMechanisms */, + NULL, NULL, LDAP_SASL_QUIET, sasl_interact, &idU )); + + if (id && (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)) + { + strfreeW( (WCHAR *)idW.Domain ); + strfreeW( (WCHAR *)idW.User ); + strfreeW( (WCHAR *)idW.Password ); + } + + strfreeU( (char *)idU.Domain ); + strfreeU( (char *)idU.User ); + strfreeU( (char *)idU.Password ); + } + else + { + FIXME( "method %#x not supported\n", method ); + return WLDAP32_LDAP_PARAM_ERROR; } - - ret = map_error( ldap_sasl_bind_s( ld, dnU, LDAP_SASL_SIMPLE, &pwd, NULL, NULL, NULL )); exit: strfreeU( dnU ); diff --git a/dlls/wldap32/winldap_private.h b/dlls/wldap32/winldap_private.h index 74223029b7d..df257dafec9 100644 --- a/dlls/wldap32/winldap_private.h +++ b/dlls/wldap32/winldap_private.h @@ -101,6 +101,8 @@ typedef struct berelement #define WLDAP32_LDAP_OPT_SECURITY_CONTEXT 0x99 #define WLDAP32_LDAP_OPT_ROOTDSE_CACHE 0x9a +#define WLDAP32_LDAP_AUTH_NEGOTIATE 0x486 + typedef struct ldap { struct diff --git a/dlls/wldap32/wldap32.h b/dlls/wldap32/wldap32.h index 1d4052002ab..c329a5b76b5 100644 --- a/dlls/wldap32/wldap32.h +++ b/dlls/wldap32/wldap32.h @@ -93,6 +93,38 @@ static inline LPWSTR strUtoW( char *str ) return ret; } +static inline LPWSTR strnAtoW( LPCSTR str, DWORD inlen, DWORD *outlen ) +{ + LPWSTR ret = NULL; + *outlen = 0; + if (str) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, str, inlen, NULL, 0 ); + if ((ret = heap_alloc( len * sizeof(WCHAR) ))) + { + MultiByteToWideChar( CP_ACP, 0, str, inlen, ret, len ); + *outlen = len; + } + } + return ret; +} + +static inline char *strnWtoU( LPCWSTR str, DWORD inlen, DWORD *outlen ) +{ + LPSTR ret = NULL; + *outlen = 0; + if (str) + { + DWORD len = WideCharToMultiByte( CP_UTF8, 0, str, inlen, NULL, 0, NULL, NULL ); + if ((ret = heap_alloc( len ))) + { + WideCharToMultiByte( CP_UTF8, 0, str, inlen, ret, len, NULL, NULL ); + *outlen = len; + } + } + return ret; +} + static inline void strfreeA( LPSTR str ) { heap_free( str ); diff --git a/include/config.h.in b/include/config.h.in index 4fa805ef190..10149353878 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -779,6 +779,9 @@ /* Define to 1 if you have the `roundf' function. */ #undef HAVE_ROUNDF +/* Define to 1 if you have the header file. */ +#undef HAVE_SASL_SASL_H + /* Define to 1 if you have the header file. */ #undef HAVE_SCHED_H