int LDAP_CALL ldap_bind( LDAP *ld, const char *dn, const char *passwd, int authmethod ) { /* * The bind request looks like this: * BindRequest ::= SEQUENCE { * version INTEGER, * name DistinguishedName, -- who * authentication CHOICE { * simple [0] OCTET STRING -- passwd * } * } * all wrapped up in an LDAPMessage sequence. */ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_bind\n", 0, 0, 0 ); if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { return( -1 ); } switch ( authmethod ) { case LDAP_AUTH_SIMPLE: return( ldap_simple_bind( ld, dn, passwd ) ); default: LDAP_SET_LDERRNO( ld, LDAP_AUTH_UNKNOWN, NULL, NULL ); return( -1 ); } }
/* * ldap_simple_bind - bind to the ldap server using simple * authentication. The dn and password of the entry to which to bind are * supplied. LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. * * Example: * ldap_simple_bind_s( ld, "cn=manager, o=university of michigan, c=us", * "secret" ) */ int LDAP_CALL ldap_simple_bind_s( LDAP *ld, const char *dn, const char *passwd ) { int msgid; LDAPMessage *result; LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n", 0, 0, 0 ); if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { return( LDAP_PARAM_ERROR ); } if ( (msgid = ldap_simple_bind( ld, dn, passwd )) == -1 ) return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 ) return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); return( ldap_result2error( ld, result, 1 ) ); }
/* * ldap_simple_bind - bind to the ldap server using simple * authentication. The dn and password of the entry to which to bind are * supplied. LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. * * Example: * ldap_simple_bind_s( ld, "cn=manager, o=university of michigan, c=us", * "secret" ) */ int LDAP_CALL ldap_simple_bind_s( LDAP *ld, const char *dn, const char *passwd ) { int msgid; LDAPMessage *result; LDAPDebug( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n", 0, 0, 0 ); if ( NSLDAPI_VALID_LDAP_POINTER( ld ) && ( ld->ld_options & LDAP_BITOPT_RECONNECT ) != 0 ) { return( simple_bindifnot_s( ld, dn, passwd )); } if ( (msgid = ldap_simple_bind( ld, dn, passwd )) == -1 ) return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 ) return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); return( ldap_result2error( ld, result, 1 ) ); }
int ldap_bind( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd, int authmethod ) { Debug( LDAP_DEBUG_TRACE, "ldap_bind\n", 0, 0, 0 ); switch ( authmethod ) { case LDAP_AUTH_SIMPLE: return( ldap_simple_bind( ld, dn, passwd ) ); #ifdef HAVE_GSSAPI case LDAP_AUTH_NEGOTIATE: return( ldap_gssapi_bind_s( ld, dn, passwd) ); #endif case LDAP_AUTH_SASL: /* user must use ldap_sasl_bind */ /* FALL-THRU */ default: ld->ld_errno = LDAP_AUTH_UNKNOWN; return( -1 ); } }
// wrapper for ldap_simple_bind() // NS_IMETHODIMP nsLDAPOperation::SimpleBind(const nsACString& passwd) { nsRefPtr<nsLDAPConnection> connection = mConnection; // There is a possibilty that mConnection can be cleared by another // thread. Grabbing a local reference to mConnection may avoid this. // See https://bugzilla.mozilla.org/show_bug.cgi?id=557928#c1 nsresult rv; nsCAutoString bindName; PRInt32 originalMsgID = mMsgID; // Ugly hack alert: // the first time we get called with a passwd, remember it. // Then, if we get called again w/o a password, use the // saved one. Getting called again means we're trying to // fall back to VERSION2. // Since LDAP operations are thrown away when done, it won't stay // around in memory. if (!passwd.IsEmpty()) mSavePassword = passwd; NS_PRECONDITION(mMessageListener != 0, "MessageListener not set"); rv = connection->GetBindName(bindName); if (NS_FAILED(rv)) return rv; PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, ("nsLDAPOperation::SimpleBind(): called; bindName = '%s'; ", bindName.get())); // If this is a second try at binding, remove the operation from pending ops // because msg id has changed... if (originalMsgID) connection->RemovePendingOperation(originalMsgID); mMsgID = ldap_simple_bind(mConnectionHandle, bindName.get(), PromiseFlatCString(mSavePassword).get()); if (mMsgID == -1) { // XXX Should NS_ERROR_LDAP_SERVER_DOWN cause a rebind here? return TranslateLDAPErrorToNSError(ldap_get_lderrno(mConnectionHandle, 0, 0)); } // make sure the connection knows where to call back once the messages // for this operation start coming in rv = connection->AddPendingOperation(mMsgID, this); switch (rv) { case NS_OK: break; // note that the return value of ldap_abandon_ext() is ignored, as // there's nothing useful to do with it case NS_ERROR_OUT_OF_MEMORY: (void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0); return NS_ERROR_OUT_OF_MEMORY; break; case NS_ERROR_UNEXPECTED: case NS_ERROR_ILLEGAL_VALUE: default: (void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0); return NS_ERROR_UNEXPECTED; } return NS_OK; }
static int do_bind (LDAP * ldap_connection, int timelimit) { int rc; int rv; struct timeval tv; LDAPMessage *result; /* * set timelimit in ld for select() call in ldap_pvt_connect() * function implemented in libldap2's os-ip.c */ tv.tv_sec = timelimit; tv.tv_usec = 0; DBG2("do_bind(): bind DN=\"%s\" pass=\"%s\"",binddn,passwd); /* LDAPv3 doesn't need bind at all, * nevertheless, if no binddn is given than bind anonymous */ if ( ! strncmp(binddn,"",1) ) { rv = ldap_simple_bind(ldap_connection, NULL, NULL); } else { rv = ldap_simple_bind(ldap_connection, binddn, passwd); } if (rv < 0) { DBG("do_bind: rv < 0"); #if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) if (ldap_get_option (ldap_connection, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS) { rc = LDAP_UNAVAILABLE; } #else rc = ldap_connection->ld_errno; #endif /* LDAP_OPT_ERROR_NUMBER */ /* Notify if we failed. */ DBG3("could not connect to LDAP server as %s - %d - %s", binddn, rc, ldap_err2string (rc)); return rc; } rc = ldap_result (ldap_connection, rv, 0, &tv, &result); if (rc > 0) { DBG1("do_bind rc=%d", rc); /* debug ("<== do_bind"); */ return ldap_result2error (ldap_connection, result, 1); } /* took too long */ if (rc == 0) { DBG("do_bind rc=0"); ldap_abandon (ldap_connection, rv); } DBG("do_bind return -1"); return -1; }
/* * ldap_sasl_interactive_bind_s - interactive SASL authentication * * This routine uses interactive callbacks. * * LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. */ int ldap_sasl_interactive_bind_s( LDAP *ld, LDAP_CONST char *dn, /* usually NULL */ LDAP_CONST char *mechs, LDAPControl **serverControls, LDAPControl **clientControls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults ) { int rc; #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex ); #endif #ifdef LDAP_CONNECTIONLESS if( LDAP_IS_UDP(ld) ) { /* Just force it to simple bind, silly to make the user * ask all the time. No, we don't ever actually bind, but I'll * let the final bind handler take care of saving the cdn. */ rc = ldap_simple_bind(ld, dn, NULL); return rc < 0 ? rc : 0; } else #endif if( mechs == NULL || *mechs == '\0' ) { char *smechs; rc = ldap_pvt_sasl_getmechs( ld, &smechs ); if( rc != LDAP_SUCCESS ) { goto done; } #ifdef NEW_LOGGING LDAP_LOG ( TRANSPORT, DETAIL1, "ldap_interactive_sasl_bind_s: server supports: %s\n", smechs, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "ldap_interactive_sasl_bind_s: server supports: %s\n", smechs, 0, 0 ); #endif mechs = smechs; } else { #ifdef NEW_LOGGING LDAP_LOG ( TRANSPORT, DETAIL1, "ldap_interactive_sasl_bind_s: user selected: %s\n", mechs, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "ldap_interactive_sasl_bind_s: user selected: %s\n", mechs, 0, 0 ); #endif } rc = ldap_int_sasl_bind( ld, dn, mechs, serverControls, clientControls, flags, interact, defaults ); done: #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex ); #endif return rc; }
/* * ldap_sasl_interactive_bind - interactive SASL authentication * * This routine uses interactive callbacks. * * LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. LDAP_SASL_BIND_IN_PROGRESS is returned if further * calls are needed. */ int ldap_sasl_interactive_bind( LDAP *ld, LDAP_CONST char *dn, /* usually NULL */ LDAP_CONST char *mechs, LDAPControl **serverControls, LDAPControl **clientControls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults, LDAPMessage *result, const char **rmech, int *msgid ) { char *smechs = NULL; int rc; #if defined( HAVE_CYRUS_SASL ) LDAP_MUTEX_LOCK( &ldap_int_sasl_mutex ); #endif #ifdef LDAP_CONNECTIONLESS if( LDAP_IS_UDP(ld) ) { /* Just force it to simple bind, silly to make the user * ask all the time. No, we don't ever actually bind, but I'll * let the final bind handler take care of saving the cdn. */ rc = ldap_simple_bind( ld, dn, NULL ); rc = rc < 0 ? rc : 0; goto done; } else #endif /* First time */ if ( !result ) { #ifdef HAVE_CYRUS_SASL if( mechs == NULL || *mechs == '\0' ) { mechs = ld->ld_options.ldo_def_sasl_mech; } #endif if( mechs == NULL || *mechs == '\0' ) { /* FIXME: this needs to be asynchronous too; * perhaps NULL should be disallowed for async usage? */ rc = ldap_pvt_sasl_getmechs( ld, &smechs ); if( rc != LDAP_SUCCESS ) { goto done; } Debug( LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind: server supports: %s\n", smechs, 0, 0 ); mechs = smechs; } else { Debug( LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind: user selected: %s\n", mechs, 0, 0 ); } } rc = ldap_int_sasl_bind( ld, dn, mechs, serverControls, clientControls, flags, interact, defaults, result, rmech, msgid ); done: #if defined( HAVE_CYRUS_SASL ) LDAP_MUTEX_UNLOCK( &ldap_int_sasl_mutex ); #endif if ( smechs ) LDAP_FREE( smechs ); return rc; }
void run_ldap_tests(service_t *ldaptest, int sslcertcheck, int querytimeout) { #ifdef HAVE_LDAP ldap_data_t *req; testitem_t *t; struct timespec starttime; struct timespec endtime; /* Pick a sensible default for the timeout setting */ if (querytimeout == 0) querytimeout = 30; for (t = ldaptest->items; (t); t = t->next) { LDAPURLDesc *ludp; LDAP *ld; int rc, finished; int msgID = -1; struct timeval ldaptimeout; struct timeval openldaptimeout; LDAPMessage *result; LDAPMessage *e; strbuffer_t *response; char buf[MAX_LINE_LEN]; req = (ldap_data_t *) t->privdata; if (req->skiptest) continue; ludp = (LDAPURLDesc *) req->ldapdesc; getntimer(&starttime); /* Initiate session with the LDAP server */ dbgprintf("Initiating LDAP session for host %s port %d\n", ludp->lud_host, ludp->lud_port); if( (ld = ldap_init(ludp->lud_host, ludp->lud_port)) == NULL ) { dbgprintf("ldap_init failed\n"); req->ldapstatus = XYMON_LDAP_INITFAIL; continue; } /* * There is apparently no standard way of defining a network * timeout for the initial connection setup. */ #if (LDAP_VENDOR == OpenLDAP) && defined(LDAP_OPT_NETWORK_TIMEOUT) /* * OpenLDAP has an undocumented ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv) */ openldaptimeout.tv_sec = querytimeout; openldaptimeout.tv_usec = 0; ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &openldaptimeout); #else /* * So using an alarm() to interrupt any pending operations * seems to be the least insane way of doing this. * * Note that we must do this right after ldap_init(), as * any operation on the session handle (ld) may trigger the * network connection to be established. */ connect_timeout = 0; signal(SIGALRM, ldap_alarmhandler); alarm(querytimeout); #endif /* * This is completely undocumented in the OpenLDAP docs. * But apparently it is documented in * http://www.ietf.org/proceedings/99jul/I-D/draft-ietf-ldapext-ldap-c-api-03.txt * * Both of these routines appear in the <ldap.h> file * from OpenLDAP 2.1.22. Their use to enable TLS has * been deciphered from the ldapsearch() utility * sourcecode. * * According to Manon Goo <*****@*****.**>, recent (Jan. 2005) * OpenLDAP implementations refuse to talk LDAPv2. */ #ifdef LDAP_OPT_PROTOCOL_VERSION { int protocol = LDAP_VERSION3; dbgprintf("Attempting to select LDAPv3\n"); if ((rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) { dbgprintf("Failed to select LDAPv3, trying LDAPv2\n"); protocol = LDAP_VERSION2; if ((rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) { req->output = strdup(ldap_err2string(rc)); req->ldapstatus = XYMON_LDAP_TLSFAIL; } continue; } } #endif if (req->usetls) { dbgprintf("Trying to enable TLS for session\n"); if ((rc = ldap_start_tls_s(ld, NULL, NULL)) != LDAP_SUCCESS) { dbgprintf("ldap_start_tls failed\n"); req->output = strdup(ldap_err2string(rc)); req->ldapstatus = XYMON_LDAP_TLSFAIL; continue; } } if (!connect_timeout) { msgID = ldap_simple_bind(ld, (t->host->ldapuser ? t->host->ldapuser : ""), (t->host->ldappasswd ? t->host->ldappasswd : "")); } /* Cancel any pending alarms */ alarm(0); signal(SIGALRM, SIG_DFL); /* Did we connect? */ if (connect_timeout || (msgID == -1)) { req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = "Cannot connect to server"; continue; } /* Wait for bind to complete */ rc = 0; finished = 0; ldaptimeout.tv_sec = querytimeout; ldaptimeout.tv_usec = 0L; while( ! finished ) { int rc2; rc = ldap_result(ld, msgID, LDAP_MSG_ONE, &ldaptimeout, &result); dbgprintf("ldap_result returned %d for ldap_simple_bind()\n", rc); if(rc == -1) { finished = 1; req->ldapstatus = XYMON_LDAP_BINDFAIL; if (result == NULL) { errprintf("LDAP library problem - NULL result returned\n"); req->output = strdup("LDAP BIND failed\n"); } else { rc2 = ldap_result2error(ld, result, 1); req->output = strdup(ldap_err2string(rc2)); } ldap_unbind(ld); } else if (rc == 0) { finished = 1; req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = strdup("Connection timeout"); ldap_unbind(ld); } else if( rc > 0 ) { finished = 1; if (result == NULL) { errprintf("LDAP library problem - got a NULL resultcode for status %d\n", rc); req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = strdup("LDAP library problem: ldap_result2error returned a NULL result for status %d\n"); ldap_unbind(ld); } else { rc2 = ldap_result2error(ld, result, 1); if(rc2 != LDAP_SUCCESS) { req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = strdup(ldap_err2string(rc)); ldap_unbind(ld); } } } } /* ... while() */ /* We're done connecting. If something went wrong, go to next query. */ if (req->ldapstatus != 0) continue; /* Now do the search. With a timeout */ ldaptimeout.tv_sec = querytimeout; ldaptimeout.tv_usec = 0L; rc = ldap_search_st(ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0, &ldaptimeout, &result); if(rc == LDAP_TIMEOUT) { req->ldapstatus = XYMON_LDAP_TIMEOUT; req->output = strdup(ldap_err2string(rc)); ldap_unbind(ld); continue; } if( rc != LDAP_SUCCESS ) { req->ldapstatus = XYMON_LDAP_SEARCHFAILED; req->output = strdup(ldap_err2string(rc)); ldap_unbind(ld); continue; } getntimer(&endtime); response = newstrbuffer(0); sprintf(buf, "Searching LDAP for %s yields %d results:\n\n", t->testspec, ldap_count_entries(ld, result)); addtobuffer(response, buf); for(e = ldap_first_entry(ld, result); (e != NULL); e = ldap_next_entry(ld, e) ) { char *dn; BerElement *ber; char *attribute; char **vals; dn = ldap_get_dn(ld, e); sprintf(buf, "DN: %s\n", dn); addtobuffer(response, buf); /* Addtributes and values */ for (attribute = ldap_first_attribute(ld, e, &ber); (attribute != NULL); attribute = ldap_next_attribute(ld, e, ber) ) { if ((vals = ldap_get_values(ld, e, attribute)) != NULL) { int i; for(i = 0; (vals[i] != NULL); i++) { sprintf(buf, "\t%s: %s\n", attribute, vals[i]); addtobuffer(response, buf); } } /* Free memory used to store values */ ldap_value_free(vals); } /* Free memory used to store attribute */ ldap_memfree(attribute); ldap_memfree(dn); if (ber != NULL) ber_free(ber, 0); addtobuffer(response, "\n"); } req->ldapstatus = XYMON_LDAP_OK; req->output = grabstrbuffer(response); tvdiff(&starttime, &endtime, &req->duration); ldap_msgfree(result); ldap_unbind(ld); ldap_free_urldesc(ludp); } #endif }