1 /* 2 * The contents of this file are subject to the Netscape Public 3 * License Version 1.1 (the "License"); you may not use this file 4 * except in compliance with the License. You may obtain a copy of 5 * the License at http://www.mozilla.org/NPL/ 6 * 7 * Software distributed under the License is distributed on an "AS 8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 9 * implied. See the License for the specific language governing 10 * rights and limitations under the License. 11 * 12 * The Original Code is Mozilla Communicator client code, released 13 * March 31, 1998. 14 * 15 * The Initial Developer of the Original Code is Netscape 16 * Communications Corporation. Portions created by Netscape are 17 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 18 * Rights Reserved. 19 * 20 * Contributor(s): 21 */ 22 /* 23 * Copyright (c) 1993 Regents of the University of Michigan. 24 * All rights reserved. 25 */ 26 /* 27 * sbind.c 28 */ 29 30 #if 0 31 #ifndef lint 32 static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n"; 33 #endif 34 #endif 35 36 #include "ldap-int.h" 37 38 static int simple_bind_nolock( LDAP *ld, const char *dn, const char *passwd, 39 int unlock_permitted ); 40 static int simple_bindifnot_s( LDAP *ld, const char *dn, const char *passwd ); 41 42 /* 43 * ldap_simple_bind - bind to the ldap server. The dn and 44 * password of the entry to which to bind are supplied. The message id 45 * of the request initiated is returned. 46 * 47 * Example: 48 * ldap_simple_bind( ld, "cn=manager, o=university of michigan, c=us", 49 * "secret" ) 50 */ 51 52 int 53 LDAP_CALL 54 ldap_simple_bind( LDAP *ld, const char *dn, const char *passwd ) 55 { 56 int rc; 57 58 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind\n", 0, 0, 0 ); 59 60 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 61 return( -1 ); 62 } 63 64 rc = simple_bind_nolock( ld, dn, passwd, 1 ); 65 66 return( rc ); 67 } 68 69 70 static int 71 simple_bind_nolock( LDAP *ld, const char *dn, const char *passwd, 72 int unlock_permitted ) 73 { 74 BerElement *ber; 75 int rc, msgid; 76 77 /* 78 * The bind request looks like this: 79 * BindRequest ::= SEQUENCE { 80 * version INTEGER, 81 * name DistinguishedName, -- who 82 * authentication CHOICE { 83 * simple [0] OCTET STRING -- passwd 84 * } 85 * } 86 * all wrapped up in an LDAPMessage sequence. 87 */ 88 89 LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); 90 msgid = ++ld->ld_msgid; 91 LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); 92 93 if ( dn == NULL ) 94 dn = ""; 95 if ( passwd == NULL ) 96 passwd = ""; 97 98 if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) { 99 struct berval bv; 100 101 bv.bv_val = (char *)passwd; 102 bv.bv_len = strlen( passwd ); 103 /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */ 104 LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); 105 rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn, &bv, 106 LDAP_AUTH_SIMPLE ); 107 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); 108 /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */ 109 if ( rc != 0 ) { 110 return( rc ); 111 } 112 } 113 114 /* create a message to send */ 115 if (( rc = nsldapi_alloc_ber_with_options( ld, &ber )) 116 != LDAP_SUCCESS ) { 117 return( -1 ); 118 } 119 120 /* fill it in */ 121 if ( ber_printf( ber, "{it{ists}", msgid, LDAP_REQ_BIND, 122 NSLDAPI_LDAP_VERSION( ld ), dn, LDAP_AUTH_SIMPLE, passwd ) == -1 ) { 123 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); 124 ber_free( ber, 1 ); 125 return( -1 ); 126 } 127 128 if ( nsldapi_put_controls( ld, NULL, 1, ber ) != LDAP_SUCCESS ) { 129 ber_free( ber, 1 ); 130 return( -1 ); 131 } 132 133 /* send the message */ 134 return( nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND, 135 (char *)dn, ber )); 136 } 137 138 139 /* 140 * ldap_simple_bind - bind to the ldap server using simple 141 * authentication. The dn and password of the entry to which to bind are 142 * supplied. LDAP_SUCCESS is returned upon success, the ldap error code 143 * otherwise. 144 * 145 * Example: 146 * ldap_simple_bind_s( ld, "cn=manager, o=university of michigan, c=us", 147 * "secret" ) 148 */ 149 int 150 LDAP_CALL 151 ldap_simple_bind_s( LDAP *ld, const char *dn, const char *passwd ) 152 { 153 int msgid; 154 LDAPMessage *result; 155 156 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n", 0, 0, 0 ); 157 158 if ( NSLDAPI_VALID_LDAP_POINTER( ld ) && 159 ( ld->ld_options & LDAP_BITOPT_RECONNECT ) != 0 ) { 160 return( simple_bindifnot_s( ld, dn, passwd )); 161 } 162 163 if ( (msgid = ldap_simple_bind( ld, dn, passwd )) == -1 ) 164 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); 165 166 if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 ) 167 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); 168 169 return( ldap_result2error( ld, result, 1 ) ); 170 } 171 172 173 /* 174 * simple_bindifnot_s() is like ldap_simple_bind_s() except that it only does 175 * a bind if the default connection is not currently bound. 176 * If a successful bind using the same DN has already taken place we just 177 * return LDAP_SUCCESS without conversing with the server at all. 178 */ 179 static int 180 simple_bindifnot_s( LDAP *ld, const char *dn, const char *passwd ) 181 { 182 int msgid, rc; 183 LDAPMessage *result; 184 char *binddn; 185 186 LDAPDebug( LDAP_DEBUG_TRACE, "simple_bindifnot_s\n", 0, 0, 0 ); 187 188 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 189 return( LDAP_PARAM_ERROR ); 190 } 191 192 if ( dn == NULL ) { 193 dn = ""; /* to make comparisons simpler */ 194 } 195 196 /* 197 * if we are already bound using the same DN, just return LDAP_SUCCESS. 198 */ 199 if ( NULL != ( binddn = nsldapi_get_binddn( ld )) 200 && 0 == strcmp( dn, binddn )) { 201 rc = LDAP_SUCCESS; 202 LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); 203 return rc; 204 } 205 206 /* 207 * if the default connection has been lost and is now marked dead, 208 * dispose of the default connection so it will get re-established. 209 * 210 * if not, clear the bind DN and status to ensure that we don't 211 * report the wrong bind DN to a different thread while waiting 212 * for our bind result to return from the server. 213 */ 214 LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK ); 215 if ( NULL != ld->ld_defconn ) { 216 if ( LDAP_CONNST_DEAD == ld->ld_defconn->lconn_status ) { 217 nsldapi_free_connection( ld, ld->ld_defconn, NULL, NULL, 1, 0 ); 218 ld->ld_defconn = NULL; 219 } else if ( ld->ld_defconn->lconn_binddn != NULL ) { 220 NSLDAPI_FREE( ld->ld_defconn->lconn_binddn ); 221 ld->ld_defconn->lconn_binddn = NULL; 222 ld->ld_defconn->lconn_bound = 0; 223 } 224 } 225 LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); 226 227 /* 228 * finally, bind (this will open a new connection if necessary) 229 * 230 * do everything under the protection of the result lock to 231 * ensure that only one thread will be in this code at a time. 232 * XXXmcs: we should use a condition variable instead? 233 */ 234 LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK ); 235 if ( (msgid = simple_bind_nolock( ld, dn, passwd, 0 )) == -1 ) { 236 rc = LDAP_GET_LDERRNO( ld, NULL, NULL ); 237 goto unlock_and_return; 238 } 239 240 /* 241 * Note that at this point the bind request is on its way to the 242 * server and at any time now we will either be bound as the new 243 * DN (if the bind succeeded) or we will be bound as anonymous (if 244 * the bind failed). 245 */ 246 247 /* 248 * Wait for the bind result. Code inside result.c:read1msg() 249 * takes care of setting the connection's bind DN and status. 250 */ 251 if ( nsldapi_result_nolock( ld, msgid, 1, 0, (struct timeval *) 0, 252 &result ) == -1 ) { 253 rc = LDAP_GET_LDERRNO( ld, NULL, NULL ); 254 goto unlock_and_return; 255 } 256 257 rc = ldap_result2error( ld, result, 1 ); 258 259 unlock_and_return: 260 LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK ); 261 return( rc ); 262 } 263