* NTLM authentication support with the ntlm library, in Unix systems.
[alpine.git] / ldap / kbind.c
blobff6279c976a760de03684d5cccd14d0deb0e390d
1 /*
2 * Copyright (c) 1993 Regents of the University of Michigan.
3 * All rights reserved.
5 * kbind.c
6 */
8 #ifndef lint
9 static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
10 #endif
12 #ifdef KERBEROS
14 #include <stdio.h>
15 #include <string.h>
17 #ifdef MACOS
18 #include <stdlib.h>
19 #include "macos.h"
20 #else /* MACOS */
21 #ifdef DOS
22 #include "msdos.h"
23 #endif /* DOS */
24 #include <krb.h>
25 #include <stdlib.h>
26 #if !defined(DOS) && !defined( _WIN32 )
27 #include <sys/types.h>
28 #endif /* !DOS && !_WIN32 */
29 #include <sys/time.h>
30 #include <sys/socket.h>
31 #endif /* MACOS */
33 #include "lber.h"
34 #include "ldap.h"
35 #include "ldap-int.h"
40 * ldap_kerberos_bind1 - initiate a bind to the ldap server using
41 * kerberos authentication. The dn is supplied. It is assumed the user
42 * already has a valid ticket granting ticket. The msgid of the
43 * request is returned on success (suitable for passing to ldap_result()),
44 * -1 is returned if there's trouble.
46 * Example:
47 * ldap_kerberos_bind1( ld, "cn=manager, o=university of michigan, c=us" )
49 int
50 ldap_kerberos_bind1( LDAP *ld, char *dn )
52 BerElement *ber;
53 char *cred;
54 int rc, credlen;
55 char *get_kerberosv4_credentials();
56 #ifdef STR_TRANSLATION
57 int str_translation_on;
58 #endif /* STR_TRANSLATION */
61 * The bind request looks like this:
62 * BindRequest ::= SEQUENCE {
63 * version INTEGER,
64 * name DistinguishedName,
65 * authentication CHOICE {
66 * krbv42ldap [1] OCTET STRING
67 * krbv42dsa [2] OCTET STRING
68 * }
69 * }
70 * all wrapped up in an LDAPMessage sequence.
73 Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind1\n", 0, 0, 0 );
75 if ( dn == NULL )
76 dn = "";
78 if ( (cred = get_kerberosv4_credentials( ld, dn, "ldapserver",
79 &credlen )) == NULL ) {
80 return( -1 ); /* ld_errno should already be set */
83 /* create a message to send */
84 if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
85 free( cred );
86 return( -1 );
89 #ifdef STR_TRANSLATION
90 if (( str_translation_on = (( ber->ber_options &
91 LBER_TRANSLATE_STRINGS ) != 0 ))) { /* turn translation off */
92 ber->ber_options &= ~LBER_TRANSLATE_STRINGS;
94 #endif /* STR_TRANSLATION */
96 /* fill it in */
97 rc = ber_printf( ber, "{it{isto}}", ++ld->ld_msgid, LDAP_REQ_BIND,
98 ld->ld_version, dn, LDAP_AUTH_KRBV41, cred, credlen );
100 #ifdef STR_TRANSLATION
101 if ( str_translation_on ) { /* restore translation */
102 ber->ber_options |= LBER_TRANSLATE_STRINGS;
104 #endif /* STR_TRANSLATION */
106 if ( rc == -1 ) {
107 free( cred );
108 ber_free( ber, 1 );
109 ld->ld_errno = LDAP_ENCODING_ERROR;
110 return( -1 );
113 free( cred );
115 #ifndef NO_CACHE
116 if ( ld->ld_cache != NULL ) {
117 ldap_flush_cache( ld );
119 #endif /* !NO_CACHE */
121 /* send the message */
122 return ( send_initial_request( ld, LDAP_REQ_BIND, dn, ber ));
126 ldap_kerberos_bind1_s( LDAP *ld, char *dn )
128 int msgid;
129 LDAPMessage *res;
131 Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind1_s\n", 0, 0, 0 );
133 /* initiate the bind */
134 if ( (msgid = ldap_kerberos_bind1( ld, dn )) == -1 )
135 return( ld->ld_errno );
137 /* wait for a result */
138 if ( ldap_result( ld, ld->ld_msgid, 1, (struct timeval *) 0, &res )
139 == -1 ) {
140 return( ld->ld_errno ); /* ldap_result sets ld_errno */
143 return( ldap_result2error( ld, res, 1 ) );
147 * ldap_kerberos_bind2 - initiate a bind to the X.500 server using
148 * kerberos authentication. The dn is supplied. It is assumed the user
149 * already has a valid ticket granting ticket. The msgid of the
150 * request is returned on success (suitable for passing to ldap_result()),
151 * -1 is returned if there's trouble.
153 * Example:
154 * ldap_kerberos_bind2( ld, "cn=manager, o=university of michigan, c=us" )
157 ldap_kerberos_bind2( LDAP *ld, char *dn )
159 BerElement *ber;
160 char *cred;
161 int rc, credlen;
162 char *get_kerberosv4_credentials();
163 #ifdef STR_TRANSLATION
164 int str_translation_on;
165 #endif /* STR_TRANSLATION */
167 Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind2\n", 0, 0, 0 );
169 if ( dn == NULL )
170 dn = "";
172 if ( (cred = get_kerberosv4_credentials( ld, dn, "x500dsa", &credlen ))
173 == NULL ) {
174 return( -1 ); /* ld_errno should already be set */
177 /* create a message to send */
178 if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
179 free( cred );
180 return( -1 );
183 #ifdef STR_TRANSLATION
184 if (( str_translation_on = (( ber->ber_options &
185 LBER_TRANSLATE_STRINGS ) != 0 ))) { /* turn translation off */
186 ber->ber_options &= ~LBER_TRANSLATE_STRINGS;
188 #endif /* STR_TRANSLATION */
190 /* fill it in */
191 rc = ber_printf( ber, "{it{isto}}", ++ld->ld_msgid, LDAP_REQ_BIND,
192 ld->ld_version, dn, LDAP_AUTH_KRBV42, cred, credlen );
195 #ifdef STR_TRANSLATION
196 if ( str_translation_on ) { /* restore translation */
197 ber->ber_options |= LBER_TRANSLATE_STRINGS;
199 #endif /* STR_TRANSLATION */
201 free( cred );
203 if ( rc == -1 ) {
204 ber_free( ber, 1 );
205 ld->ld_errno = LDAP_ENCODING_ERROR;
206 return( -1 );
209 /* send the message */
210 return ( send_initial_request( ld, LDAP_REQ_BIND, dn, ber ));
213 /* synchronous bind to DSA using kerberos */
215 ldap_kerberos_bind2_s( LDAP *ld, char *dn )
217 int msgid;
218 LDAPMessage *res;
220 Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind2_s\n", 0, 0, 0 );
222 /* initiate the bind */
223 if ( (msgid = ldap_kerberos_bind2( ld, dn )) == -1 )
224 return( ld->ld_errno );
226 /* wait for a result */
227 if ( ldap_result( ld, ld->ld_msgid, 1, (struct timeval *) 0, &res )
228 == -1 ) {
229 return( ld->ld_errno ); /* ldap_result sets ld_errno */
232 return( ldap_result2error( ld, res, 1 ) );
235 /* synchronous bind to ldap and DSA using kerberos */
237 ldap_kerberos_bind_s( LDAP *ld, char *dn )
239 int err;
241 Debug( LDAP_DEBUG_TRACE, "ldap_kerberos_bind_s\n", 0, 0, 0 );
243 if ( (err = ldap_kerberos_bind1_s( ld, dn )) != LDAP_SUCCESS )
244 return( err );
246 return( ldap_kerberos_bind2_s( ld, dn ) );
250 #ifndef AUTHMAN
251 #ifdef WINDOWS
252 #define FreeWindowsLibrary() FreeLibrary(instKrbv4DLL);instKrbv4DLL = (HINSTANCE)NULL;
253 #else /* WINDOWS */
254 #define FreeWindowsLibrary() /* do nothing */
255 #endif /* WINDOWS */
257 * get_kerberosv4_credentials - obtain kerberos v4 credentials for ldap.
258 * The dn of the entry to which to bind is supplied. It's assumed the
259 * user already has a tgt.
262 char *
263 get_kerberosv4_credentials( LDAP *ld, char *who, char *service, int *len )
265 KTEXT_ST ktxt;
266 int err;
267 char realm[REALM_SZ], *cred, *krbinstance;
268 #ifdef WINDOWS
269 typedef int (_cdecl* pfn_krb_get_tf_realm) (char FAR *,char FAR *);
270 typedef int (PASCAL* pfn_krb_mk_req) (KTEXT,LPSTR,LPSTR,LPSTR,long);
271 typedef char * (_cdecl* pfn_tkt_string) ();
273 static HINSTANCE instKrbv4DLL = (HINSTANCE)NULL;
274 pfn_krb_get_tf_realm fptr_krb_get_tf_realm = NULL;
275 pfn_krb_mk_req fptr_krb_mk_req = NULL;
276 pfn_tkt_string fptr_tkt_string = NULL;
277 char* p_tkt_string = NULL;
278 KTEXT pKt = &ktxt;
279 #endif
281 Debug( LDAP_DEBUG_TRACE, "get_kerberosv4_credentials\n", 0, 0, 0 );
283 #ifdef WINDOWS
285 * The goal is to gracefully survive the absence of krbv4win.dll
286 * and thus wshelper.dll. User's won't be able to use kerberos,
287 * but they shouldn't see a message box everytime libldap.dll loads.
289 if ( !instKrbv4DLL ) {
290 unsigned int prevMode = SetErrorMode( SEM_NOOPENFILEERRORBOX ); // don't whine at user if you can't find it
291 instKrbv4DLL = LoadLibrary("Krbv4win.DLL");
292 SetErrorMode( prevMode );
294 if ( instKrbv4DLL < HINSTANCE_ERROR ) { // can't find authlib
295 ld->ld_errno = LDAP_AUTH_UNKNOWN;
296 return( NULL );
299 fptr_krb_get_tf_realm = (pfn_krb_get_tf_realm)GetProcAddress( instKrbv4DLL, "_krb_get_tf_realm" );
300 fptr_krb_mk_req = (pfn_krb_mk_req)GetProcAddress( instKrbv4DLL, "krb_mk_req" );
301 fptr_tkt_string = (pfn_tkt_string)GetProcAddress( instKrbv4DLL, "_tkt_string" );
303 // verify that we found all the routines we need
304 if (!(fptr_krb_mk_req && fptr_krb_get_tf_realm && fptr_tkt_string)) {
305 FreeWindowsLibrary();
306 ld->ld_errno = LDAP_AUTH_UNKNOWN;
307 return( NULL );
311 p_tkt_string = (fptr_tkt_string)( );
312 if ( (err = (fptr_krb_get_tf_realm)( p_tkt_string, realm )) != KSUCCESS ) {
313 #else /* WINDOWS */
314 if ( (err = krb_get_tf_realm( tkt_string(), realm )) != KSUCCESS ) {
315 #endif /* WINDOWS */
316 #ifndef NO_USERINTERFACE
317 fprintf( stderr, "krb_get_tf_realm failed (%s)\n",
318 krb_err_txt[err] );
319 #endif /* NO_USERINTERFACE */
320 ld->ld_errno = LDAP_INVALID_CREDENTIALS;
321 FreeWindowsLibrary();
322 return( NULL );
325 #ifdef LDAP_REFERRALS
326 krbinstance = ld->ld_defconn->lconn_krbinstance;
327 #else /* LDAP_REFERRALS */
328 krbinstance = ld->ld_host;
329 #endif /* LDAP_REFERRALS */
331 #ifdef WINDOWS
332 if ( !krbinstance ) { // if we don't know name of service host, no chance for service tickets
333 FreeWindowsLibrary();
334 ld->ld_errno = LDAP_LOCAL_ERROR;
335 WSASetLastError(WSANO_ADDRESS);
336 return( NULL );
338 #endif /* WINDOWS */
340 #ifdef WINDOWS
341 if ( (err = (fptr_krb_mk_req)( pKt, service, krbinstance, realm, 0 ))
342 #else /* WINDOWS */
343 if ( (err = krb_mk_req( &ktxt, service, krbinstance, realm, 0 ))
344 #endif /* WINDOWS */
345 != KSUCCESS ) {
346 #ifndef NO_USERINTERFACE
347 fprintf( stderr, "krb_mk_req failed (%s)\n", krb_err_txt[err] );
348 #endif /* NO_USERINTERFACE */
349 ld->ld_errno = LDAP_INVALID_CREDENTIALS;
350 FreeWindowsLibrary();
351 return( NULL );
354 if ( ( cred = malloc( ktxt.length )) == NULL ) {
355 ld->ld_errno = LDAP_NO_MEMORY;
356 FreeWindowsLibrary();
357 return( NULL );
360 *len = ktxt.length;
361 memcpy( cred, ktxt.dat, ktxt.length );
363 FreeWindowsLibrary();
364 return( cred );
367 #endif /* !AUTHMAN */
368 #endif /* KERBEROS */