/* * ldap_sasl_bind - authenticate to the ldap server. The dn, mechanism, * and credentials of the entry to which to bind are supplied. An LDAP * error code is returned and if LDAP_SUCCESS is returned *msgidp is set * to the id of the request initiated. * * Example: * struct berval creds; * LDAPControl **ctrls; * int err, msgid; * ... fill in creds with credentials ... * ... fill in ctrls with server controls ... * err = ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us", * "mechanismname", &creds, ctrls, NULL, &msgid ); */ int LDAP_CALL ldap_sasl_bind( LDAP *ld, const char *dn, const char *mechanism, const struct berval *cred, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp ) { BerElement *ber; int rc, simple, msgid, ldapversion; /* * The ldapv3 bind request looks like this: * BindRequest ::= SEQUENCE { * version INTEGER, * name DistinguishedName, -- who * authentication CHOICE { * simple [0] OCTET STRING, -- passwd * sasl [3] SaslCredentials -- v3 only * } * } * SaslCredentials ::= SEQUENCE { * mechanism LDAPString, * credentials OCTET STRING * } * all wrapped up in an LDAPMessage sequence. */ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 ); if ( msgidp == NULL ) { LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); return( LDAP_PARAM_ERROR ); } simple = ( mechanism == LDAP_SASL_SIMPLE ); ldapversion = NSLDAPI_LDAP_VERSION( ld ); /* only ldapv3 or higher can do sasl binds */ if ( !simple && ldapversion < LDAP_VERSION3 ) { LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL ); return( LDAP_NOT_SUPPORTED ); } LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); msgid = ++ld->ld_msgid; LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); if ( dn == NULL ) dn = ""; if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) { LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); if ( (rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn, cred, LDAP_AUTH_SASL )) != 0 ) { *msgidp = rc; LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); return( LDAP_SUCCESS ); } LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); } /* create a message to send */ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) { return( rc ); } /* fill it in */ if ( simple ) { /* simple bind; works in LDAPv2 or v3 */ struct berval tmpcred; if ( cred == NULL ) { tmpcred.bv_val = ""; tmpcred.bv_len = 0; cred = &tmpcred; } rc = ber_printf( ber, "{it{isto}", msgid, LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SIMPLE, cred->bv_val, (int)cred->bv_len /* XXX lossy cast */ ); } else { /* SASL bind; requires LDAPv3 or better */ if ( cred == NULL ) { rc = ber_printf( ber, "{it{ist{s}}", msgid, LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, mechanism ); } else { rc = ber_printf( ber, "{it{ist{so}}", msgid, LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, mechanism, cred->bv_val, (int)cred->bv_len /* XXX lossy cast */ ); } } if ( rc == -1 ) { LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); ber_free( ber, 1 ); return( LDAP_ENCODING_ERROR ); } if ( (rc = nsldapi_put_controls( ld, serverctrls, 1, ber )) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( rc ); } /* send the message */ rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND, (char *)dn, ber ); *msgidp = rc; return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS ); }
int LDAP_CALL ldap_extended_operation( LDAP *ld, const char *exoid, const struct berval *exdata, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp ) { BerElement *ber; int rc, msgid; /* * the ldapv3 extended operation request looks like this: * * ExtendedRequest ::= [APPLICATION 23] SEQUENCE { * requestName LDAPOID, * requestValue OCTET STRING * } * * all wrapped up in an LDAPMessage sequence. */ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 ); if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { return( LDAP_PARAM_ERROR ); } /* only ldapv3 or higher can do extended operations */ if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) { rc = LDAP_NOT_SUPPORTED; LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); return( rc ); } if ( msgidp == NULL || exoid == NULL || *exoid == '\0' ) { rc = LDAP_PARAM_ERROR; LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); return( rc ); } LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); msgid = ++ld->ld_msgid; LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); #if 0 if ( ld->ld_cache_on && ld->ld_cache_extendedop != NULL ) { LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); if ( (rc = (ld->ld_cache_extendedop)( ld, msgid, LDAP_REQ_EXTENDED, exoid, cred )) != 0 ) { LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); return( rc ); } LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); } #endif /* create a message to send */ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) { return( rc ); } /* fill it in */ if ( ber_printf( ber, "{it{tsto}", msgid, LDAP_REQ_EXTENDED, LDAP_TAG_EXOP_REQ_OID, exoid, LDAP_TAG_EXOP_REQ_VALUE, exdata->bv_val, (int)exdata->bv_len /* XXX lossy cast */ ) == -1 ) { rc = LDAP_ENCODING_ERROR; LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); ber_free( ber, 1 ); return( rc ); } if (( rc = nsldapi_put_controls( ld, serverctrls, 1, ber )) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( rc ); } /* send the message */ rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_EXTENDED, NULL, ber ); *msgidp = rc; return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS ); }
int LDAP_CALL ldap_modify_ext( LDAP *ld, const char *dn, LDAPMod **mods, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp ) { BerElement *ber; int i, rc, lderr; /* * A modify request looks like this: * ModifyRequet ::= SEQUENCE { * object DistinguishedName, * modifications SEQUENCE OF SEQUENCE { * operation ENUMERATED { * add (0), * delete (1), * replace (2) * }, * modification SEQUENCE { * type AttributeType, * values SET OF AttributeValue * } * } * } */ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_modify_ext\n", 0, 0, 0 ); if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { return( LDAP_PARAM_ERROR ); } if ( !NSLDAPI_VALID_LDAPMESSAGE_POINTER( msgidp )) { LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); return( LDAP_PARAM_ERROR ); } if ( !NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( mods )) { lderr = LDAP_PARAM_ERROR; LDAP_SET_LDERRNO( ld, lderr, NULL, NULL ); return( lderr ); } if ( dn == NULL ) { dn = ""; } LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); *msgidp = ++ld->ld_msgid; LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); /* see if we should add to the cache */ if ( ld->ld_cache_on && ld->ld_cache_modify != NULL ) { LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); if ( (rc = (ld->ld_cache_modify)( ld, *msgidp, LDAP_REQ_MODIFY, dn, mods )) != 0 ) { *msgidp = rc; LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); return( LDAP_SUCCESS ); } LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); } /* create a message to send */ if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) { return( lderr ); } if ( ber_printf( ber, "{it{s{", *msgidp, LDAP_REQ_MODIFY, dn ) == -1 ) { lderr = LDAP_ENCODING_ERROR; LDAP_SET_LDERRNO( ld, lderr, NULL, NULL ); ber_free( ber, 1 ); return( lderr ); } /* for each modification to be performed... */ for ( i = 0; mods[i] != NULL; i++ ) { if (( mods[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) { rc = ber_printf( ber, "{e{s[V]}}", mods[i]->mod_op & ~LDAP_MOD_BVALUES, mods[i]->mod_type, mods[i]->mod_bvalues ); } else { rc = ber_printf( ber, "{e{s[v]}}", mods[i]->mod_op, mods[i]->mod_type, mods[i]->mod_values ); } if ( rc == -1 ) { lderr = LDAP_ENCODING_ERROR; LDAP_SET_LDERRNO( ld, lderr, NULL, NULL ); ber_free( ber, 1 ); return( lderr ); } } if ( ber_printf( ber, "}}" ) == -1 ) { lderr = LDAP_ENCODING_ERROR; LDAP_SET_LDERRNO( ld, lderr, NULL, NULL ); ber_free( ber, 1 ); return( lderr ); } if (( lderr = nsldapi_put_controls( ld, serverctrls, 1, ber )) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( lderr ); } /* send the message */ rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_MODIFY, (char *)dn, ber ); *msgidp = rc; return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS ); }
/* * Abandon all outstanding requests for msgid (included child requests * spawned when chasing referrals). This function calls itself recursively. * No locking is done is this function so it must be done by the caller. * Returns an LDAP error code and sets it in LDAP *ld as well */ static int do_abandon(LDAP *ld, int origid, int msgid, LDAPControl **serverctrls, LDAPControl **clientctrls) { BerElement *ber; int i, bererr, lderr, sendabandon; LDAPRequest *lr = NULL; /* * An abandon request looks like this: * AbandonRequest ::= MessageID */ LDAPDebug(LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid, 0); /* optimistic */ lderr = LDAP_SUCCESS; /* * Find the request that we are abandoning. Don't send an * abandon message unless there is something to abandon. */ sendabandon = 0; for (lr = ld->ld_requests; lr != NULL; lr = lr->lr_next) { if (lr->lr_msgid == msgid) { /* this message */ if (origid == msgid && lr->lr_parent != NULL) { /* don't let caller abandon child requests! */ lderr = LDAP_PARAM_ERROR; goto set_errorcode_and_return; } if (lr->lr_status == LDAP_REQST_INPROGRESS) { /* * We only need to send an abandon message if * the request is in progress. */ sendabandon = 1; } break; } if (lr->lr_origid == msgid) { /* child: abandon it */ (void)do_abandon(ld, msgid, lr->lr_msgid, serverctrls, clientctrls); /* we ignore errors from child abandons... */ } } if (ldap_msgdelete(ld, msgid) == 0) { /* we had all the results and deleted them */ goto set_errorcode_and_return; } if (lr != NULL && sendabandon) { /* create a message to send */ if ((lderr = nsldapi_alloc_ber_with_options(ld, &ber)) == LDAP_SUCCESS) { int abandon_msgid; LDAP_MUTEX_LOCK(ld, LDAP_MSGID_LOCK); abandon_msgid = ++ld->ld_msgid; LDAP_MUTEX_UNLOCK(ld, LDAP_MSGID_LOCK); #ifdef CLDAP if (ld->ld_dbp->sb_naddr > 0) { bererr = ber_printf(ber, "{isti", abandon_msgid, ld->ld_cldapdn, LDAP_REQ_ABANDON, msgid); } else { #endif /* CLDAP */ bererr = ber_printf(ber, "{iti", abandon_msgid, LDAP_REQ_ABANDON, msgid); #ifdef CLDAP } #endif /* CLDAP */ if (bererr == -1 || (lderr = nsldapi_put_controls(ld, serverctrls, 1, ber)) != LDAP_SUCCESS) { lderr = LDAP_ENCODING_ERROR; ber_free(ber, 1); } else { /* try to send the message */ lderr = nsldapi_send_abandon_message(ld, lr->lr_conn, ber, abandon_msgid); } } } if (lr != NULL) { /* * Always call nsldapi_free_connection() so that the connection's * ref count is correctly decremented. It is OK to always pass * 1 for the "unbind" parameter because doing so will only affect * connections that resulted from a child request (because the * default connection's ref count never goes to zero). */ nsldapi_free_connection(ld, lr->lr_conn, NULL, NULL, 0 /* do not force */, 1 /* send unbind before closing */); /* * Free the entire request chain if we finished abandoning everything. */ if (origid == msgid) { nsldapi_free_request(ld, lr, 0); } } /* * Record the abandoned message ID (used to discard any server responses * that arrive later). */ LDAP_MUTEX_LOCK(ld, LDAP_ABANDON_LOCK); if (ld->ld_abandoned == NULL) { if ((ld->ld_abandoned = (int *)NSLDAPI_MALLOC(2 * sizeof(int))) == NULL) { lderr = LDAP_NO_MEMORY; LDAP_MUTEX_UNLOCK(ld, LDAP_ABANDON_LOCK); goto set_errorcode_and_return; } i = 0; } else { for (i = 0; ld->ld_abandoned[i] != -1; i++) ; /* NULL */ if ((ld->ld_abandoned = (int *)NSLDAPI_REALLOC( (char *)ld->ld_abandoned, (i + 2) * sizeof(int))) == NULL) { lderr = LDAP_NO_MEMORY; LDAP_MUTEX_UNLOCK(ld, LDAP_ABANDON_LOCK); goto set_errorcode_and_return; } } ld->ld_abandoned[i] = msgid; ld->ld_abandoned[i + 1] = -1; LDAP_MUTEX_UNLOCK(ld, LDAP_ABANDON_LOCK); set_errorcode_and_return: LDAP_SET_LDERRNO(ld, lderr, NULL, NULL); return (lderr); }
static int simple_bind_nolock( LDAP *ld, const char *dn, const char *passwd, int unlock_permitted ) { BerElement *ber; int rc, msgid; /* * 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. */ LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); msgid = ++ld->ld_msgid; LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); if ( dn == NULL ) dn = ""; if ( passwd == NULL ) passwd = ""; if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) { struct berval bv; bv.bv_val = (char *)passwd; bv.bv_len = strlen( passwd ); /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */ LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn, &bv, LDAP_AUTH_SIMPLE ); LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */ if ( rc != 0 ) { return( rc ); } } /* create a message to send */ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) { return( -1 ); } /* fill it in */ if ( ber_printf( ber, "{it{ists}", msgid, LDAP_REQ_BIND, NSLDAPI_LDAP_VERSION( ld ), dn, LDAP_AUTH_SIMPLE, passwd ) == -1 ) { LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); ber_free( ber, 1 ); return( -1 ); } if ( nsldapi_put_controls( ld, NULL, 1, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( -1 ); } /* send the message */ return( nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND, (char *)dn, ber )); }
/* returns an LDAP error code and also sets it in ld */ int nsldapi_build_search_req( LDAP *ld, const char *base, int scope, const char *filter, char **attrs, int attrsonly, LDAPControl **serverctrls, LDAPControl **clientctrls, /* not used for anything yet */ int timelimit, /* if -1, ld->ld_timelimit is used */ int sizelimit, /* if -1, ld->ld_sizelimit is used */ int msgid, BerElement **berp ) { BerElement *ber; int err; char *fdup; /* * Create the search request. It looks like this: * SearchRequest := [APPLICATION 3] SEQUENCE { * baseObject DistinguishedName, * scope ENUMERATED { * baseObject (0), * singleLevel (1), * wholeSubtree (2) * }, * derefAliases ENUMERATED { * neverDerefaliases (0), * derefInSearching (1), * derefFindingBaseObj (2), * alwaysDerefAliases (3) * }, * sizelimit INTEGER (0 .. 65535), * timelimit INTEGER (0 .. 65535), * attrsOnly BOOLEAN, * filter Filter, * attributes SEQUENCE OF AttributeType * } * wrapped in an ldap message. */ /* create a message to send */ if (( err = nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) { return( err ); } if ( base == NULL ) { base = ""; } if ( sizelimit == -1 ) { sizelimit = ld->ld_sizelimit; } if ( timelimit == -1 ) { timelimit = ld->ld_timelimit; } #ifdef CLDAP if ( ld->ld_sbp->sb_naddr > 0 ) { err = ber_printf( ber, "{ist{seeiib", msgid, ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref, sizelimit, timelimit, attrsonly ); } else { #endif /* CLDAP */ err = ber_printf( ber, "{it{seeiib", msgid, LDAP_REQ_SEARCH, base, scope, ld->ld_deref, sizelimit, timelimit, attrsonly ); #ifdef CLDAP } #endif /* CLDAP */ if ( err == -1 ) { LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); ber_free( ber, 1 ); return( LDAP_ENCODING_ERROR ); } fdup = nsldapi_strdup( filter ); err = put_filter( ber, fdup ); NSLDAPI_FREE( fdup ); if ( err == -1 ) { LDAP_SET_LDERRNO( ld, LDAP_FILTER_ERROR, NULL, NULL ); ber_free( ber, 1 ); return( LDAP_FILTER_ERROR ); } if ( ber_printf( ber, "{v}}", attrs ) == -1 ) { LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); ber_free( ber, 1 ); return( LDAP_ENCODING_ERROR ); } if ( (err = nsldapi_put_controls( ld, serverctrls, 1, ber )) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( err ); } *berp = ber; return( LDAP_SUCCESS ); }