1 /* 2 * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 7 * 8 * The contents of this file are subject to the Netscape Public License 9 * Version 1.0 (the "NPL"); you may not use this file except in 10 * compliance with the NPL. You may obtain a copy of the NPL at 11 * http://www.mozilla.org/NPL/ 12 * 13 * Software distributed under the NPL is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 15 * for the specific language governing rights and limitations under the 16 * NPL. 17 * 18 * The Initial Developer of the Original Code is Netscape 19 * Communications Corporation. Portions created by Netscape are 20 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 21 * Rights Reserved. 22 * 23 * Contributor(s): 24 */ 25 #include "ldap-int.h" 26 27 /* 28 * ldap_sasl_bind - authenticate to the ldap server. The dn, mechanism, 29 * and credentials of the entry to which to bind are supplied. An LDAP 30 * error code is returned and if LDAP_SUCCESS is returned *msgidp is set 31 * to the id of the request initiated. 32 * 33 * Example: 34 * struct berval creds; 35 * LDAPControl **ctrls; 36 * int err, msgid; 37 * ... fill in creds with credentials ... 38 * ... fill in ctrls with server controls ... 39 * err = ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us", 40 * "mechanismname", &creds, ctrls, NULL, &msgid ); 41 */ 42 int 43 LDAP_CALL 44 ldap_sasl_bind( 45 LDAP *ld, 46 const char *dn, 47 const char *mechanism, 48 const struct berval *cred, 49 LDAPControl **serverctrls, 50 LDAPControl **clientctrls, 51 int *msgidp 52 ) 53 { 54 BerElement *ber; 55 int rc, simple, msgid, ldapversion; 56 57 /* 58 * The ldapv3 bind request looks like this: 59 * BindRequest ::= SEQUENCE { 60 * version INTEGER, 61 * name DistinguishedName, -- who 62 * authentication CHOICE { 63 * simple [0] OCTET STRING, -- passwd 64 * sasl [3] SaslCredentials -- v3 only 65 * } 66 * } 67 * SaslCredentials ::= SEQUENCE { 68 * mechanism LDAPString, 69 * credentials OCTET STRING 70 * } 71 * all wrapped up in an LDAPMessage sequence. 72 */ 73 74 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 ); 75 76 if ( msgidp == NULL ) { 77 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); 78 return( LDAP_PARAM_ERROR ); 79 } 80 81 simple = ( mechanism == LDAP_SASL_SIMPLE ); 82 ldapversion = NSLDAPI_LDAP_VERSION( ld ); 83 84 /* only ldapv3 or higher can do sasl binds */ 85 if ( !simple && ldapversion < LDAP_VERSION3 ) { 86 LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL ); 87 return( LDAP_NOT_SUPPORTED ); 88 } 89 90 LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); 91 msgid = ++ld->ld_msgid; 92 LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); 93 94 if ( dn == NULL ) 95 dn = ""; 96 97 if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) { 98 LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); 99 if ( (rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn, 100 cred, LDAP_AUTH_SASL )) != 0 ) { 101 *msgidp = rc; 102 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); 103 return( LDAP_SUCCESS ); 104 } 105 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); 106 } 107 108 /* create a message to send */ 109 if (( rc = nsldapi_alloc_ber_with_options( ld, &ber )) 110 != LDAP_SUCCESS ) { 111 return( rc ); 112 } 113 114 /* fill it in */ 115 if ( simple ) { /* simple bind; works in LDAPv2 or v3 */ 116 struct berval tmpcred; 117 118 if ( cred == NULL ) { 119 tmpcred.bv_val = ""; 120 tmpcred.bv_len = 0; 121 cred = &tmpcred; 122 } 123 rc = ber_printf( ber, "{it{isto}", msgid, LDAP_REQ_BIND, 124 ldapversion, dn, LDAP_AUTH_SIMPLE, cred->bv_val, 125 (int)cred->bv_len /* XXX lossy cast */ ); 126 127 } else { /* SASL bind; requires LDAPv3 or better */ 128 if ( cred == NULL ) { 129 rc = ber_printf( ber, "{it{ist{s}}", msgid, 130 LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, 131 mechanism ); 132 } else { 133 rc = ber_printf( ber, "{it{ist{so}}", msgid, 134 LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, 135 mechanism, cred->bv_val, 136 (int)cred->bv_len /* XXX lossy cast */ ); 137 } 138 } 139 140 if ( rc == -1 ) { 141 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); 142 ber_free( ber, 1 ); 143 return( LDAP_ENCODING_ERROR ); 144 } 145 146 if ( (rc = nsldapi_put_controls( ld, serverctrls, 1, ber )) 147 != LDAP_SUCCESS ) { 148 ber_free( ber, 1 ); 149 return( rc ); 150 } 151 152 /* send the message */ 153 rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND, 154 (char *)dn, ber ); 155 *msgidp = rc; 156 return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS ); 157 } 158 159 /* 160 * ldap_sasl_bind_s - bind to the ldap server using sasl authentication 161 * The dn, mechanism, and credentials of the entry to which to bind are 162 * supplied. LDAP_SUCCESS is returned upon success, the ldap error code 163 * otherwise. 164 * 165 * Example: 166 * struct berval creds; 167 * ... fill in creds with credentials ... 168 * ldap_sasl_bind_s( ld, "cn=manager, o=university of michigan, c=us", 169 * "mechanismname", &creds ) 170 */ 171 int 172 LDAP_CALL 173 ldap_sasl_bind_s( 174 LDAP *ld, 175 const char *dn, 176 const char *mechanism, 177 const struct berval *cred, 178 LDAPControl **serverctrls, 179 LDAPControl **clientctrls, 180 struct berval **servercredp 181 ) 182 { 183 int err, msgid; 184 LDAPMessage *result; 185 186 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 ); 187 188 if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) { 189 LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL ); 190 return( LDAP_NOT_SUPPORTED ); 191 } 192 193 if ( ( err = ldap_sasl_bind( ld, dn, mechanism, cred, serverctrls, 194 clientctrls, &msgid )) != LDAP_SUCCESS ) 195 return( err ); 196 197 if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 ) 198 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); 199 200 err = ldap_parse_sasl_bind_result( ld, result, servercredp, 0 ); 201 if (err != LDAP_SUCCESS && err != LDAP_SASL_BIND_IN_PROGRESS) { 202 ldap_msgfree( result ); 203 return( err ); 204 } 205 206 return( ldap_result2error( ld, result, 1 ) ); 207 } 208 209 210 /* returns an LDAP error code that indicates if parse succeeded or not */ 211 int 212 LDAP_CALL 213 ldap_parse_sasl_bind_result( 214 LDAP *ld, 215 LDAPMessage *res, 216 struct berval **servercredp, 217 int freeit 218 ) 219 { 220 BerElement ber; 221 int rc, err; 222 ber_int_t along; 223 ber_len_t len; 224 char *m, *e; 225 226 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 ); 227 228 /* 229 * the ldapv3 SASL bind response looks like this: 230 * 231 * BindResponse ::= [APPLICATION 1] SEQUENCE { 232 * COMPONENTS OF LDAPResult, 233 * serverSaslCreds [7] OCTET STRING OPTIONAL 234 * } 235 * 236 * all wrapped up in an LDAPMessage sequence. 237 */ 238 239 if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || 240 !NSLDAPI_VALID_LDAPMESSAGE_BINDRESULT_POINTER( res )) { 241 return( LDAP_PARAM_ERROR ); 242 } 243 244 /* only ldapv3 or higher can do sasl binds */ 245 if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) { 246 LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL ); 247 return( LDAP_NOT_SUPPORTED ); 248 } 249 250 if ( servercredp != NULL ) { 251 *servercredp = NULL; 252 } 253 254 ber = *(res->lm_ber); /* struct copy */ 255 256 /* skip past message id, matched dn, error message ... */ 257 rc = ber_scanf( &ber, "{iaa}", &along, &m, &e ); 258 259 if ( rc != LBER_ERROR && 260 ber_peek_tag( &ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) { 261 rc = ber_get_stringal( &ber, servercredp ); 262 } 263 264 if ( freeit ) { 265 ldap_msgfree( res ); 266 } 267 268 if ( rc == LBER_ERROR ) { 269 err = LDAP_DECODING_ERROR; 270 } else { 271 err = (int) along; 272 } 273 274 LDAP_SET_LDERRNO( ld, err, m, e ); 275 /* this is a little kludge for the 3.0 Barracuda/hammerhead relese */ 276 /* the docs state that the return is either LDAP_DECODING_ERROR */ 277 /* or LDAP_SUCCESS. Here we match the docs... it's cleaner in 3.1 */ 278 279 if ( LDAP_DECODING_ERROR == err ) { 280 return (LDAP_DECODING_ERROR); 281 } else { 282 return( LDAP_SUCCESS ); 283 } 284 } 285