1/* 2 * 3 * Copyright 2000 Sun Microsystems, Inc. All rights reserved. 4 * Use is subject to license terms. 5 * 6 * 7 * Comments: 8 * 9 */ 10 11#pragma ident "%Z%%M% %I% %E% SMI" 12 13#include <stdio.h> 14#include <string.h> 15 16#include "lber.h" 17#include "ldap.h" 18#include "ldap-private.h" 19#include "ldap-int.h" 20#include "sec.h" 21#include <strings.h> 22 23BerElement * ldap_build_sasl_bind_req( LDAP *ld, char *dn, char *mechanism, struct berval *creds, LDAPControl ** serverctrls) 24{ 25 BerElement *ber = NULL; 26 int err; 27 28 /* Create a Bind Request for SASL authentication. 29 * It look like this : 30 * BindRequest := [APPLICATION 0] SEQUENCE { 31 * version INTEGER, 32 * name LDAPDN, 33 * authentication CHOICE { 34 * sasl [3] SEQUENCE { 35 * mechanism LDAPString, 36 * credential OCTET STRING OPTIONAL 37 * } 38 * } 39 * } 40 * all wrapped up in an LDAPMessage sequence. 41 */ 42 43 if (dn == NULL || *dn == '\0'){ 44 ld->ld_errno = LDAP_PARAM_ERROR; 45 return (NULLBER); 46 } 47 48 49 if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) { 50 return (NULLBER); 51 } 52 if ( ber_printf( ber, "{it{ist{s", ++ld->ld_msgid, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_SASL, mechanism) == -1){ 53 ld->ld_errno = LDAP_ENCODING_ERROR; 54 ber_free(ber, 1); 55 return (NULLBER); 56 } 57 if (creds != NULL && creds->bv_val != NULL) { 58 if (ber_printf(ber, "o", creds->bv_val, creds->bv_len) == -1){ 59 ld->ld_errno = LDAP_ENCODING_ERROR; 60 ber_free(ber, 1); 61 return (NULLBER); 62 } 63 } 64 if (ber_printf(ber, "}}") == -1){ 65 ld->ld_errno = LDAP_ENCODING_ERROR; 66 ber_free( ber, 1 ); 67 return( NULLBER ); 68 } 69 /* LDAPv3 */ 70 /* Code controls if any */ 71 if (serverctrls && serverctrls[0]) { 72 if (ldap_controls_code(ber, serverctrls) != LDAP_SUCCESS){ 73 ld->ld_errno = LDAP_ENCODING_ERROR; 74 ber_free( ber, 1 ); 75 return( NULLBER ); 76 } 77 } else if (ld->ld_srvctrls && ld->ld_srvctrls[0]) { 78 /* Otherwise, is there any global server ctrls ? */ 79 if (ldap_controls_code(ber, ld->ld_srvctrls) != LDAP_SUCCESS){ 80 ld->ld_errno = LDAP_ENCODING_ERROR; 81 ber_free( ber, 1 ); 82 return( NULLBER ); 83 } 84 } 85 86 if ( ber_printf( ber, "}" ) == -1 ) { 87 ld->ld_errno = LDAP_ENCODING_ERROR; 88 ber_free( ber, 1 ); 89 return( NULLBER ); 90 } 91 92 return (ber); 93} 94 95/* 96 * ldap_sasl_bind - bind to the ldap server (and X.500). 97 * dn, mechanism, cred, serverctrls, and clientctrls are supplied. 98 * the message id of the request is returned in msgid 99 * Returns LDAP_SUCCESS or an error code. 100 */ 101 102int ldap_sasl_bind( 103 LDAP *ld, 104 char *dn, 105 char *mechanism, 106 struct berval *cred, 107 LDAPControl **serverctrls, 108 LDAPControl **clientctrls, 109 int *msgidp) 110{ 111 int theErr = LDAP_SUCCESS; 112 int rv; 113 BerElement *ber = NULL; 114 115 Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0); 116 117#ifdef _REENTRANT 118 LOCK_LDAP(ld); 119#endif 120 if (strcasecmp(mechanism, LDAP_SASL_SIMPLE) == 0){ 121 /* Simple bind */ 122 if ( (ber = ldap_build_simple_bind_req(ld, dn, cred->bv_val, serverctrls)) == NULLBER){ 123 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 124#ifdef _REENTRANT 125 UNLOCK_LDAP(ld); 126#endif 127 return (theErr); 128 } 129 } 130 131 if (strcasecmp(mechanism, LDAP_SASL_CRAM_MD5) == 0){ 132 if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_CRAM_MD5, cred, serverctrls)) == NULLBER) { 133 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 134#ifdef _REENTRANT 135 UNLOCK_LDAP(ld); 136#endif 137 return (theErr); 138 } 139 } 140 141 if (strcasecmp(mechanism, LDAP_SASL_EXTERNAL) == 0){ 142 if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_EXTERNAL, cred, serverctrls)) == NULLBER) { 143 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 144#ifdef _REENTRANT 145 UNLOCK_LDAP(ld); 146#endif 147 return (theErr); 148 } 149 } 150 151 if (strcasecmp(mechanism, LDAP_SASL_X511_PROTECTED) == 0){ 152#ifdef _REENTRANT 153 UNLOCK_LDAP(ld); 154#endif 155 return (LDAP_NOT_SUPPORTED); 156/* 157 * if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) { 158 * ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 159 *#ifdef _REENTRANT 160 * UNLOCK_LDAP(ld); 161 *#endif 162 * return (theErr); 163 * } 164 */ 165 } 166 if (strcasecmp(mechanism, LDAP_SASL_X511_STRONG) == 0){ 167#ifdef _REENTRANT 168 UNLOCK_LDAP(ld); 169#endif 170 return (LDAP_NOT_SUPPORTED); 171/* 172 * if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) { 173 * ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 174 *#ifdef _REENTRANT 175 * UNLOCK_LDAP(ld); 176 *#endif 177 * return (theErr); 178 * } 179 */ 180 } 181 if (strcasecmp(mechanism, LDAP_SASL_KERBEROS_V4) == 0){ 182#ifdef _REENTRANT 183 UNLOCK_LDAP(ld); 184#endif 185 return (LDAP_NOT_SUPPORTED); 186/* 187 * if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) { 188 * ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 189 *#ifdef _REENTRANT 190 * UNLOCK_LDAP(ld); 191 *#endif 192 * return (theErr); 193 * } 194 */ 195 } 196 if (strcasecmp(mechanism, LDAP_SASL_GSSAPI) == 0){ 197#ifdef _REENTRANT 198 UNLOCK_LDAP(ld); 199#endif 200 return (LDAP_NOT_SUPPORTED); 201/* 202 * if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) { 203 * ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 204 *#ifdef _REENTRANT 205 * UNLOCK_LDAP(ld); 206 *#endif 207 * return (theErr); 208 * } 209 */ 210 } 211 if (strcasecmp(mechanism, LDAP_SASL_SKEY) == 0){ 212#ifdef _REENTRANT 213 UNLOCK_LDAP(ld); 214#endif 215 return (LDAP_NOT_SUPPORTED); 216/* 217 * if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) { 218 * ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr); 219 *#ifdef _REENTRANT 220 * UNLOCK_LDAP(ld); 221 *#endif 222 * return (theErr); 223 * } 224 */ 225 } 226 if (ber == NULL){ 227#ifdef _REENTRANT 228 UNLOCK_LDAP(ld); 229#endif 230 return (LDAP_PARAM_ERROR); 231 } 232 233#ifndef NO_CACHE 234 if ( ld->ld_cache != NULL ) { 235 ldap_flush_cache( ld ); 236 } 237#endif /* !NO_CACHE */ 238 239 /* send the message */ 240 rv = send_initial_request( ld, LDAP_REQ_BIND, dn, ber ); 241 if (rv == -1){ 242 rv = ld->ld_errno; 243 if (rv == LDAP_SUCCESS){ 244 rv = LDAP_OTHER; 245 } 246#ifdef _REENTRANT 247 UNLOCK_LDAP(ld); 248#endif 249 return (rv); 250 } 251 *msgidp = rv; 252#ifdef _REENTRANT 253 UNLOCK_LDAP(ld); 254#endif 255 return ( LDAP_SUCCESS ); 256} 257 258/* 259 * ldap_sasl_bind_s - bind to the ldap server (and X.500). 260 * dn, mechanism, cred, serverctrls, and clientctrls are supplied. 261 * the message id of the request is returned in msgid 262 * Returns LDAP_SUCCESS or an error code. 263 */ 264 265int ldap_sasl_bind_s( 266 LDAP *ld, 267 char *dn, 268 char *mechanism, 269 struct berval *cred, 270 LDAPControl **serverctrls, 271 LDAPControl **clientctrls, 272 struct berval **servercredp) 273{ 274 int msgid; 275 int retcode; 276 LDAPMessage *res; 277 278 Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0); 279 280 if ((retcode = ldap_sasl_bind(ld, dn, mechanism, cred, serverctrls, clientctrls, &msgid)) != LDAP_SUCCESS) 281 return (retcode); 282 if (ldap_result(ld, msgid, 1, (struct timeval *)NULL, &res ) == -1) 283 return (ld->ld_errno ); 284 285 return (ldap_parse_sasl_bind_result(ld, res, servercredp, 1)); 286} 287 288int ldap_sasl_cram_md5_bind_s( 289 LDAP *ld, 290 char *dn, 291 struct berval *cred, 292 LDAPControl **serverctrls, 293 LDAPControl **clientctrls ) 294{ 295 int res; 296 struct berval *challenge = NULL; 297 struct berval resp; 298 unsigned char digest[16]; 299 char *theHDigest; 300 301 if (dn == NULL){ 302 return (LDAP_PARAM_ERROR); 303 } 304 305 bzero(digest, sizeof (digest)); 306 307 if ((res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, NULL, serverctrls, clientctrls, &challenge)) 308 != LDAP_SASL_BIND_INPROGRESS){ 309 return (res); 310 } 311 if (challenge == NULL){ 312 return (LDAP_PARAM_ERROR); 313 } 314 315 Debug (LDAP_DEBUG_TRACE, "SASL challenge: %s\n", challenge->bv_val, 0, 0); 316 317 hmac_md5((unsigned char *)challenge->bv_val, challenge->bv_len, 318 (unsigned char *)cred->bv_val, cred->bv_len, digest); 319 ber_bvfree(challenge); 320 challenge = NULL; 321 322 theHDigest = hexa_print(digest, 16); 323 if (theHDigest == NULL){ 324 return (LDAP_NO_MEMORY); 325 } 326 327 resp.bv_len = (strlen(dn) + 32 + 1); 328 if ((resp.bv_val = (char *)malloc(resp.bv_len+1)) == NULL) { 329 return(LDAP_NO_MEMORY); 330 } 331 332 sprintf(resp.bv_val, "%s %s", dn, theHDigest); 333 free(theHDigest); 334 335 Debug (LDAP_DEBUG_TRACE, "SASL response: %s\n", resp.bv_val, 0, 0); 336 res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, &resp, serverctrls, clientctrls, &challenge); 337 338 free(resp.bv_val); 339 return (res); 340} 341