int ldap_initialize( LDAP **ldp, LDAP_CONST char *url ) { int rc; LDAP *ld; *ldp = NULL; rc = ldap_create(&ld); if ( rc != LDAP_SUCCESS ) return rc; if (url != NULL) { rc = ldap_set_option(ld, LDAP_OPT_URI, url); if ( rc != LDAP_SUCCESS ) { ldap_ld_free(ld, 1, NULL, NULL); return rc; } #ifdef LDAP_CONNECTIONLESS if (ldap_is_ldapc_url(url)) LDAP_IS_UDP(ld) = 1; #endif } *ldp = ld; return LDAP_SUCCESS; }
/* sets needed mutexes - no mutexes set to this point */ ber_int_t ldap_send_initial_request( LDAP *ld, ber_tag_t msgtype, const char *dn, BerElement *ber, ber_int_t msgid) { int rc = 1; ber_socket_t sd = AC_SOCKET_INVALID; Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) { /* not connected yet */ rc = ldap_open_defconn( ld ); } if ( ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING ) rc = ldap_int_check_async_open( ld, sd ); if( rc < 0 ) { ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( -1 ); } else if ( rc == 0 ) { Debug( LDAP_DEBUG_TRACE, "ldap_open_defconn: successful\n", 0, 0, 0 ); } #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { if (msgtype == LDAP_REQ_BIND) { LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); if (ld->ld_options.ldo_cldapdn) ldap_memfree(ld->ld_options.ldo_cldapdn); ld->ld_options.ldo_cldapdn = ldap_strdup(dn); ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return 0; } if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH) { ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return LDAP_PARAM_ERROR; } } #endif LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); rc = ldap_send_server_request( ld, ber, msgid, NULL, NULL, NULL, NULL, 0, 0 ); LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return(rc); }
ber_int_t ldap_send_initial_request( LDAP *ld, ber_tag_t msgtype, const char *dn, BerElement *ber, ber_int_t msgid) { int rc = 1; Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected yet */ rc = ldap_open_defconn( ld ); } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif if( rc < 0 ) { ber_free( ber, 1 ); return( -1 ); } else if ( rc == 0 ) { Debug( LDAP_DEBUG_TRACE, "ldap_open_defconn: successful\n", 0, 0, 0 ); } #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { if (msgtype == LDAP_REQ_BIND) { if (ld->ld_options.ldo_cldapdn) ldap_memfree(ld->ld_options.ldo_cldapdn); ld->ld_options.ldo_cldapdn = ldap_strdup(dn); return 0; } if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH) return LDAP_PARAM_ERROR; } #endif #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif rc = ldap_send_server_request( ld, ber, msgid, NULL, NULL, NULL, NULL ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif return(rc); }
/* FIXME: this function is called only by ldap_free_connection(), * which, most of the times, is called with ld_req_mutex locked */ int ldap_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **sctrls, LDAPControl **cctrls ) { BerElement *ber; ber_int_t id; Debug( LDAP_DEBUG_TRACE, "ldap_send_unbind\n", 0, 0, 0 ); #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) return LDAP_SUCCESS; #endif /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( ld->ld_errno ); } LDAP_NEXT_MSGID(ld, id); /* fill it in */ if ( ber_printf( ber, "{itn" /*}*/, id, LDAP_REQ_UNBIND ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( ld->ld_errno ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return ld->ld_errno; } if ( ber_printf( ber, /*{*/ "N}", LDAP_REQ_UNBIND ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( ld->ld_errno ); } ld->ld_errno = LDAP_SUCCESS; /* send the message */ if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) == -1 ) { ld->ld_errno = LDAP_SERVER_DOWN; } return( ld->ld_errno ); }
/* * 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 ) { const char *rmech = NULL; LDAPMessage *result = NULL; int rc, msgid; do { rc = ldap_sasl_interactive_bind( ld, dn, mechs, serverControls, clientControls, flags, interact, defaults, result, &rmech, &msgid ); ldap_msgfree( result ); if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) break; #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { break; } #endif if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { return( ld->ld_errno ); /* ldap_result sets ld_errno */ } } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); return rc; }
int ldap_send_server_request( LDAP *ld, BerElement *ber, ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc **srvlist, LDAPConn *lc, LDAPreqinfo *bind, int m_noconn, int m_res ) { LDAPRequest *lr; int incparent, rc; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 ); incparent = 0; ld->ld_errno = LDAP_SUCCESS; /* optimistic */ LDAP_CONN_LOCK_IF(m_noconn); if ( lc == NULL ) { if ( srvlist == NULL ) { lc = ld->ld_defconn; } else { lc = find_connection( ld, *srvlist, 1 ); if ( lc == NULL ) { if ( (bind != NULL) && (parentreq != NULL) ) { /* Remember the bind in the parent */ incparent = 1; ++parentreq->lr_outrefcnt; } lc = ldap_new_connection( ld, srvlist, 0, 1, bind, 1, m_res ); } } } /* async connect... */ if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) { ber_socket_t sd = AC_SOCKET_ERROR; struct timeval tv = { 0 }; ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd ); /* poll ... */ switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) { case 0: /* go on! */ lc->lconn_status = LDAP_CONNST_CONNECTED; break; case -2: /* async only occurs if a network timeout is set */ /* honor network timeout */ LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec ) { /* caller will have to call again */ ld->ld_errno = LDAP_X_CONNECTING; } LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); /* fallthru */ default: /* error */ break; } } if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) { if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_SERVER_DOWN; } ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_CONN_UNLOCK_IF(m_noconn); return( -1 ); } use_connection( ld, lc ); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP( ld )) { BerElement tmpber = *ber; ber_rewind( &tmpber ); LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); rc = ber_write( &tmpber, ld->ld_options.ldo_peer, sizeof( struct sockaddr_storage ), 0 ); LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; LDAP_CONN_UNLOCK_IF(m_noconn); return rc; } } #endif /* If we still have an incomplete write, try to finish it before * dealing with the new request. If we don't finish here, return * LDAP_BUSY and let the caller retry later. We only allow a single * request to be in WRITING state. */ rc = 0; if ( ld->ld_requests && ld->ld_requests->lr_status == LDAP_REQST_WRITING && ldap_int_flush_request( ld, ld->ld_requests ) < 0 ) { rc = -1; } if ( rc ) { LDAP_CONN_UNLOCK_IF(m_noconn); return rc; } lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) ); if ( lr == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; ldap_free_connection( ld, lc, 0, 0 ); ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_CONN_UNLOCK_IF(m_noconn); return( -1 ); } lr->lr_msgid = msgid; lr->lr_status = LDAP_REQST_INPROGRESS; lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */ lr->lr_ber = ber; lr->lr_conn = lc; if ( parentreq != NULL ) { /* sub-request */ if ( !incparent ) { /* Increment if we didn't do it before the bind */ ++parentreq->lr_outrefcnt; } lr->lr_origid = parentreq->lr_origid; lr->lr_parentcnt = ++parentreq->lr_parentcnt; lr->lr_parent = parentreq; lr->lr_refnext = parentreq->lr_child; parentreq->lr_child = lr; } else { /* original request */ lr->lr_origid = lr->lr_msgid; } /* Extract requestDN for future reference */ #ifdef LDAP_CONNECTIONLESS if ( !LDAP_IS_UDP(ld) ) #endif { BerElement tmpber = *ber; ber_int_t bint; ber_tag_t tag, rtag; ber_reset( &tmpber, 1 ); rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag ); switch ( tag ) { case LDAP_REQ_BIND: rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint ); break; case LDAP_REQ_DELETE: break; default: rtag = ber_scanf( &tmpber, "{" /*}*/ ); case LDAP_REQ_ABANDON: break; } if ( tag != LDAP_REQ_ABANDON ) { ber_skip_tag( &tmpber, &lr->lr_dn.bv_len ); lr->lr_dn.bv_val = tmpber.ber_ptr; } } lr->lr_prev = NULL; lr->lr_next = ld->ld_requests; if ( lr->lr_next != NULL ) { lr->lr_next->lr_prev = lr; } ld->ld_requests = lr; ld->ld_errno = LDAP_SUCCESS; if ( ldap_int_flush_request( ld, lr ) == -1 ) { msgid = -1; } LDAP_CONN_UNLOCK_IF(m_noconn); return( msgid ); }
int ldap_int_open_connection( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv, int async ) { int rc = -1; char *host; int port, proto; Debug( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n", 0, 0, 0 ); switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) { case LDAP_PROTO_TCP: port = srv->lud_port; if ( srv->lud_host == NULL || *srv->lud_host == 0 ) { host = NULL; } else { host = srv->lud_host; } if( !port ) { if( strcmp(srv->lud_scheme, "ldaps") == 0 ) { port = LDAPS_PORT; } else { port = LDAP_PORT; } } rc = ldap_connect_to_host( ld, conn->lconn_sb, proto, host, port, async ); if ( rc == -1 ) return rc; #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #ifdef LDAP_CONNECTIONLESS case LDAP_PROTO_UDP: port = srv->lud_port; if ( srv->lud_host == NULL || *srv->lud_host == 0 ) { host = NULL; } else { host = srv->lud_host; } if( !port ) port = LDAP_PORT; LDAP_IS_UDP(ld) = 1; rc = ldap_connect_to_host( ld, conn->lconn_sb, proto, host, port, async ); if ( rc == -1 ) return rc; #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp, LBER_SBIOD_LEVEL_PROVIDER, NULL ); ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #endif case LDAP_PROTO_IPC: #ifdef LDAP_PF_LOCAL /* only IPC mechanism supported is PF_LOCAL (PF_UNIX) */ rc = ldap_connect_to_path( ld, conn->lconn_sb, srv->lud_host, async ); if ( rc == -1 ) return rc; #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #endif /* LDAP_PF_LOCAL */ default: return -1; break; } conn->lconn_created = time( NULL ); #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, INT_MAX, (void *)"ldap_" ); #endif #ifdef LDAP_CONNECTIONLESS if( proto == LDAP_PROTO_UDP ) return 0; #endif #ifdef HAVE_TLS if (ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD || strcmp( srv->lud_scheme, "ldaps" ) == 0 ) { ++conn->lconn_refcnt; /* avoid premature free */ rc = ldap_int_tls_start( ld, conn, srv ); --conn->lconn_refcnt; if (rc != LDAP_SUCCESS) { return -1; } } #endif return( 0 ); }
BerElement * ldap_build_search_req( LDAP *ld, LDAP_CONST char *base, ber_int_t scope, LDAP_CONST char *filter, char **attrs, ber_int_t attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t timelimit, ber_int_t sizelimit ) { BerElement *ber; int err; /* * 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 ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } if ( base == NULL ) { /* no base provided, use session default base */ base = ld->ld_options.ldo_defbase; if ( base == NULL ) { /* no session default base, use top */ base = ""; } } #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { err = ber_write( ber, ld->ld_options.ldo_peer, sizeof(struct sockaddr), 0); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { char *dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid, dn, LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref, (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, (timelimit < 0) ? ld->ld_timelimit : timelimit, attrsonly ); } else #endif { err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid, LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref, (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, (timelimit < 0) ? ld->ld_timelimit : timelimit, attrsonly ); } if ( err == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } if( filter == NULL ) { filter = "(objectclass=*)"; } err = ldap_pvt_put_filter( ber, filter ); if ( err == -1 ) { ld->ld_errno = LDAP_FILTER_ERROR; ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); }
BerElement * ldap_build_search_req( LDAP *ld, LDAP_CONST char *base, ber_int_t scope, LDAP_CONST char *filter, char **attrs, ber_int_t attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t timelimit, ber_int_t sizelimit, ber_int_t deref, ber_int_t *idp) { BerElement *ber; int err; /* * 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 ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } if ( base == NULL ) { /* no base provided, use session default base */ base = ld->ld_options.ldo_defbase; if ( base == NULL ) { /* no session default base, use top */ base = ""; } } LDAP_NEXT_MSGID( ld, *idp ); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { struct sockaddr sa = {0}; /* dummy, filled with ldo_peer in request.c */ err = ber_write( ber, &sa, sizeof( sa ), 0 ); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { char *dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{ist{seeiib", *idp, dn, LDAP_REQ_SEARCH, base, (ber_int_t) scope, (deref < 0) ? ld->ld_deref : deref, (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, (timelimit < 0) ? ld->ld_timelimit : timelimit, attrsonly ); } else #endif { err = ber_printf( ber, "{it{seeiib", *idp, LDAP_REQ_SEARCH, base, (ber_int_t) scope, (deref < 0) ? ld->ld_deref : deref, (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, (timelimit < 0) ? ld->ld_timelimit : timelimit, attrsonly ); } if ( err == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } if( filter == NULL ) { filter = "(objectclass=*)"; } err = ldap_pvt_put_filter( ber, filter ); if ( err == -1 ) { ld->ld_errno = LDAP_FILTER_ERROR; ber_free( ber, 1 ); return( NULL ); } #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_ARGS ) { char buf[ BUFSIZ ], *ptr = " *"; if ( attrs != NULL ) { int i, len, rest = sizeof( buf ); for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) { ptr = &buf[ sizeof( buf ) - rest ]; len = snprintf( ptr, rest, " %s", attrs[ i ] ); rest -= (len >= 0 ? len : (int) sizeof( buf )); } if ( rest <= 0 ) { AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ], "...(truncated)", STRLENOF( "...(truncated)" ) + 1 ); } ptr = buf; } Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 ); } #endif /* LDAP_DEBUG */ if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); }
static int do_abandon( LDAP *ld, ber_int_t origid, ber_int_t msgid, LDAPControl **sctrls, int sendabandon ) { BerElement *ber; int i, err; Sockbuf *sb; LDAPRequest *lr; Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid, 0 ); /* find the request that we are abandoning */ start_again:; lr = ld->ld_requests; while ( lr != NULL ) { /* this message */ if ( lr->lr_msgid == msgid ) { break; } /* child: abandon it */ if ( lr->lr_origid == msgid && !lr->lr_abandoned ) { (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid, sctrls, sendabandon ); /* restart, as lr may now be dangling... */ goto start_again; } lr = lr->lr_next; } if ( lr != NULL ) { if ( origid == msgid && lr->lr_parent != NULL ) { /* don't let caller abandon child requests! */ ld->ld_errno = LDAP_PARAM_ERROR; return( LDAP_PARAM_ERROR ); } if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { /* no need to send abandon message */ sendabandon = 0; } } /* ldap_msgdelete locks the res_mutex. Give up the req_mutex * while we're in there. */ #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif err = ldap_msgdelete( ld, msgid ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif if ( err == 0 ) { ld->ld_errno = LDAP_SUCCESS; return LDAP_SUCCESS; } /* fetch again the request that we are abandoning */ if ( lr != NULL ) { for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { /* this message */ if ( lr->lr_msgid == msgid ) { break; } } } err = 0; if ( sendabandon ) { if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected */ err = -1; ld->ld_errno = LDAP_SERVER_DOWN; } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { /* BER element allocation failed */ err = -1; ld->ld_errno = LDAP_NO_MEMORY; } else { /* * We already have the mutex in LDAP_R_COMPILE, so * don't try to get it again. * LDAP_NEXT_MSGID(ld, i); */ i = ++(ld)->ld_msgid; #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { struct sockaddr sa = {0}; /* dummy, filled with ldo_peer in request.c */ err = ber_write( ber, &sa, sizeof(sa), 0 ); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2 ) { char *dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{isti", /* '}' */ i, dn, LDAP_REQ_ABANDON, msgid ); } else #endif { /* create a message to send */ err = ber_printf( ber, "{iti", /* '}' */ i, LDAP_REQ_ABANDON, msgid ); } if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } else { /* Put Server Controls */ if ( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { err = -1; } else { /* close '{' */ err = ber_printf( ber, /*{*/ "N}" ); if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } } } if ( err == -1 ) { ber_free( ber, 1 ); } else { /* send the message */ if ( lr != NULL ) { assert( lr->lr_conn != NULL ); sb = lr->lr_conn->lconn_sb; } else { sb = ld->ld_sb; } if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { ld->ld_errno = LDAP_SERVER_DOWN; err = -1; } else { err = 0; } } } } if ( lr != NULL ) { if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { ldap_free_connection( ld, lr->lr_conn, 0, 1 ); } if ( origid == msgid ) { ldap_free_request( ld, lr ); } else { lr->lr_abandoned = 1; } } #ifdef LDAP_R_COMPILE /* ld_abandoned is actually protected by the ld_res_mutex; * give up the ld_req_mutex and get the other */ ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex ); #endif /* use bisection */ i = 0; if ( ld->ld_nabandoned == 0 || ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) { ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); } if ( err != -1 ) { ld->ld_errno = LDAP_SUCCESS; } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif return( ld->ld_errno ); }
/* * 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; }
int ldap_sasl_bind_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *mechanism, struct berval *cred, LDAPControl **sctrls, LDAPControl **cctrls, struct berval **servercredp ) { int rc, msgid; LDAPMessage *result; struct berval *scredp = NULL; #ifdef NEW_LOGGING LDAP_LOG ( TRANSPORT, ENTRY, "ldap_sasl_bind_s\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 ); #endif /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ if( servercredp != NULL ) { if (ld->ld_version < LDAP_VERSION3) { ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } *servercredp = NULL; } rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid ); if ( rc != LDAP_SUCCESS ) { return( rc ); } #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { return( rc ); } #endif if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) { return( ld->ld_errno ); /* ldap_result sets ld_errno */ } /* parse the results */ scredp = NULL; if( servercredp != NULL ) { rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 ); } if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { ldap_msgfree( result ); return( rc ); } rc = ldap_result2error( ld, result, 1 ); if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) { if( servercredp != NULL ) { *servercredp = scredp; scredp = NULL; } } if ( scredp != NULL ) { ber_bvfree(scredp); } return rc; }
static ber_tag_t try_read1msg( LDAP *ld, ber_int_t msgid, int all, LDAPConn **lcp, LDAPMessage **result ) { BerElement *ber; LDAPMessage *newmsg, *l, *prev; ber_int_t id; int idx; ber_tag_t tag; ber_len_t len; int foundit = 0; LDAPRequest *lr, *tmplr, dummy_lr = { 0 }; LDAPConn *lc; BerElement tmpber; int rc, refer_cnt, hadref, simple_request; ber_int_t lderr; #ifdef LDAP_CONNECTIONLESS LDAPMessage *tmp = NULL, *chain_head = NULL; int moremsgs = 0, isv2 = 0; #endif assert( ld != NULL ); assert( lcp != NULL ); assert( *lcp != NULL ); #ifdef LDAP_R_COMPILE LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); #endif Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n", (void *)ld, msgid, all ); lc = *lcp; retry: if ( lc->lconn_ber == NULL ) { lc->lconn_ber = ldap_alloc_ber_with_options( ld ); if ( lc->lconn_ber == NULL ) { return -1; } } ber = lc->lconn_ber; assert( LBER_VALID (ber) ); /* get the next message */ sock_errset(0); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { struct sockaddr from; ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) ); if ( ld->ld_options.ldo_version == LDAP_VERSION2 ) isv2 = 1; } nextresp3: #endif tag = ber_get_next( lc->lconn_sb, &len, ber ); switch ( tag ) { case LDAP_TAG_MESSAGE: /* * We read a complete message. * The connection should no longer need this ber. */ lc->lconn_ber = NULL; break; case LBER_DEFAULT: #ifdef LDAP_DEBUG Debug( LDAP_DEBUG_CONNS, "ber_get_next failed.\n", 0, 0, 0 ); #endif #ifdef EWOULDBLOCK if ( sock_errno() == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING; #endif #ifdef EAGAIN if ( sock_errno() == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; #endif ld->ld_errno = LDAP_SERVER_DOWN; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif ldap_free_connection( ld, lc, 1, 0 ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif lc = *lcp = NULL; return -1; default: ld->ld_errno = LDAP_LOCAL_ERROR; return -1; } /* message id */ if ( ber_get_int( ber, &id ) == LBER_ERROR ) { ber_free( ber, 1 ); ld->ld_errno = LDAP_DECODING_ERROR; return( -1 ); } /* id == 0 iff unsolicited notification message (RFC 4511) */ /* if it's been abandoned, toss it */ if ( id > 0 ) { if ( ldap_abandoned( ld, id, &idx ) ) { /* the message type */ tag = ber_peek_tag( ber, &len ); switch ( tag ) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: case LBER_ERROR: break; default: /* there's no need to keep the id * in the abandoned list any longer */ ldap_mark_abandoned( ld, id, idx ); break; } Debug( LDAP_DEBUG_ANY, "abandoned/discarded ld %p msgid %ld message type %s\n", (void *)ld, (long)id, ldap_int_msgtype2str( tag ) ); retry_ber: ber_free( ber, 1 ); if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { goto retry; } return( LDAP_MSG_X_KEEP_LOOKING ); /* continue looking */ } lr = ldap_find_request_by_msgid( ld, id ); if ( lr == NULL ) { const char *msg = "unknown"; /* the message type */ tag = ber_peek_tag( ber, &len ); switch ( tag ) { case LBER_ERROR: break; default: msg = ldap_int_msgtype2str( tag ); break; } Debug( LDAP_DEBUG_ANY, "no request for response on ld %p msgid %ld message type %s (tossing)\n", (void *)ld, (long)id, msg ); goto retry_ber; } #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) && isv2 ) { ber_scanf(ber, "x{"); } nextresp2: #endif } /* the message type */ tag = ber_peek_tag( ber, &len ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( -1 ); } Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %ld message type %s\n", (void *)ld, (long)lr->lr_msgid, ldap_int_msgtype2str( tag ) ); if ( id == 0 ) { /* unsolicited notification message (RFC 4511) */ if ( tag != LDAP_RES_EXTENDED ) { /* toss it */ goto retry_ber; /* strictly speaking, it's an error; from RFC 4511: 4.4. Unsolicited Notification An unsolicited notification is an LDAPMessage sent from the server to the client that is not in response to any LDAPMessage received by the server. It is used to signal an extraordinary condition in the server or in the LDAP session between the client and the server. The notification is of an advisory nature, and the server will not expect any response to be returned from the client. The unsolicited notification is structured as an LDAPMessage in which the messageID is zero and protocolOp is set to the extendedResp choice using the ExtendedResponse type (See Section 4.12). The responseName field of the ExtendedResponse always contains an LDAPOID that is unique for this notification. * however, since unsolicited responses * are of advisory nature, better * toss it, right now */ #if 0 ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( -1 ); #endif } lr = &dummy_lr; } id = lr->lr_origid; refer_cnt = 0; hadref = simple_request = 0; rc = LDAP_MSG_X_KEEP_LOOKING; /* default is to keep looking (no response found) */ lr->lr_res_msgtype = tag; /* * Check for V3 search reference */ if ( tag == LDAP_RES_SEARCH_REFERENCE ) { if ( ld->ld_version > LDAP_VERSION2 ) { /* This is a V3 search reference */ if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) || lr->lr_parent != NULL ) { char **refs = NULL; tmpber = *ber; /* Get the referral list */ if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) { rc = LDAP_DECODING_ERROR; } else { /* Note: refs array is freed by ldap_chase_v3referrals */ refer_cnt = ldap_chase_v3referrals( ld, lr, refs, 1, &lr->lr_res_error, &hadref ); if ( refer_cnt > 0 ) { /* successfully chased reference */ /* If haven't got end search, set chasing referrals */ if ( lr->lr_status != LDAP_REQST_COMPLETED ) { lr->lr_status = LDAP_REQST_CHASINGREFS; Debug( LDAP_DEBUG_TRACE, "read1msg: search ref chased, " "mark request chasing refs, " "id = %d\n", lr->lr_msgid, 0, 0 ); } } } } } } else if ( tag != LDAP_RES_SEARCH_ENTRY && tag != LDAP_RES_INTERMEDIATE ) { /* All results that just return a status, i.e. don't return data * go through the following code. This code also chases V2 referrals * and checks if all referrals have been chased. */ char *lr_res_error = NULL; tmpber = *ber; /* struct copy */ if ( ber_scanf( &tmpber, "{eAA", &lderr, &lr->lr_res_matched, &lr_res_error ) != LBER_ERROR ) { if ( lr_res_error != NULL ) { if ( lr->lr_res_error != NULL ) { (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error ); LDAP_FREE( (char *)lr_res_error ); } else { lr->lr_res_error = lr_res_error; } lr_res_error = NULL; } /* Do we need to check for referrals? */ if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) || lr->lr_parent != NULL ) { char **refs = NULL; ber_len_t len; /* Check if V3 referral */ if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) { if ( ld->ld_version > LDAP_VERSION2 ) { /* Get the referral list */ if ( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) { rc = LDAP_DECODING_ERROR; lr->lr_status = LDAP_REQST_COMPLETED; Debug( LDAP_DEBUG_TRACE, "read1msg: referral decode error, " "mark request completed, ld %p msgid %d\n", (void *)ld, lr->lr_msgid, 0 ); } else { /* Chase the referral * refs array is freed by ldap_chase_v3referrals */ refer_cnt = ldap_chase_v3referrals( ld, lr, refs, 0, &lr->lr_res_error, &hadref ); lr->lr_status = LDAP_REQST_COMPLETED; Debug( LDAP_DEBUG_TRACE, "read1msg: referral %s chased, " "mark request completed, ld %p msgid %d\n", refer_cnt > 0 ? "" : "not", (void *)ld, lr->lr_msgid); if ( refer_cnt < 0 ) { refer_cnt = 0; } } } } else { switch ( lderr ) { case LDAP_SUCCESS: case LDAP_COMPARE_TRUE: case LDAP_COMPARE_FALSE: break; default: if ( lr->lr_res_error == NULL ) { break; } /* pedantic, should never happen */ if ( lr->lr_res_error[ 0 ] == '\0' ) { LDAP_FREE( lr->lr_res_error ); lr->lr_res_error = NULL; break; } /* V2 referrals are in error string */ refer_cnt = ldap_chase_referrals( ld, lr, &lr->lr_res_error, -1, &hadref ); lr->lr_status = LDAP_REQST_COMPLETED; Debug( LDAP_DEBUG_TRACE, "read1msg: V2 referral chased, " "mark request completed, id = %d\n", lr->lr_msgid, 0, 0 ); break; } } } /* save errno, message, and matched string */ if ( !hadref || lr->lr_res_error == NULL ) { lr->lr_res_errno = lderr == LDAP_PARTIAL_RESULTS ? LDAP_SUCCESS : lderr; } else if ( ld->ld_errno != LDAP_SUCCESS ) { lr->lr_res_errno = ld->ld_errno; } else { lr->lr_res_errno = LDAP_PARTIAL_RESULTS; } } /* in any case, don't leave any lr_res_error 'round */ if ( lr_res_error ) { LDAP_FREE( lr_res_error ); } Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p %d new referrals\n", (void *)ld, refer_cnt, 0 ); if ( refer_cnt != 0 ) { /* chasing referrals */ ber_free( ber, 1 ); ber = NULL; if ( refer_cnt < 0 ) { ldap_return_request( ld, lr, 0 ); return( -1 ); /* fatal error */ } lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */ } else { if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) { /* request without any referrals */ simple_request = ( hadref ? 0 : 1 ); } else { /* request with referrals or child request */ ber_free( ber, 1 ); ber = NULL; } lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */ Debug( LDAP_DEBUG_TRACE, "read1msg: mark request completed, ld %p msgid %d\n", (void *)ld, lr->lr_msgid, 0); while ( lr->lr_parent != NULL ) { merge_error_info( ld, lr->lr_parent, lr ); lr = lr->lr_parent; if ( --lr->lr_outrefcnt > 0 ) { break; /* not completely done yet */ } } /* Check if all requests are finished, lr is now parent */ tmplr = lr; if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) { for ( tmplr = lr->lr_child; tmplr != NULL; tmplr = tmplr->lr_refnext ) { if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break; } } /* This is the parent request if the request has referrals */ if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL && tmplr == NULL ) { id = lr->lr_msgid; tag = lr->lr_res_msgtype; Debug( LDAP_DEBUG_TRACE, "request done: ld %p msgid %ld\n", (void *)ld, (long) id, 0 ); Debug( LDAP_DEBUG_TRACE, "res_errno: %d, res_error: <%s>, " "res_matched: <%s>\n", lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "", lr->lr_res_matched ? lr->lr_res_matched : "" ); if ( !simple_request ) { ber_free( ber, 1 ); ber = NULL; if ( build_result_ber( ld, &ber, lr ) == LBER_ERROR ) { rc = -1; /* fatal error */ } } if ( lr != &dummy_lr ) { ldap_return_request( ld, lr, 1 ); } lr = NULL; } /* * RF 4511 unsolicited (id == 0) responses * shouldn't necessarily end the connection */ if ( lc != NULL && id != 0 ) { #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif ldap_free_connection( ld, lc, 0, 1 ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif lc = *lcp = NULL; } } } if ( lr != NULL ) { if ( lr != &dummy_lr ) { ldap_return_request( ld, lr, 0 ); } lr = NULL; } if ( ber == NULL ) { return( rc ); } /* try to handle unsolicited responses as appropriate */ if ( id == 0 && msgid > LDAP_RES_UNSOLICITED ) { int is_nod = 0; tag = ber_peek_tag( &tmpber, &len ); /* we have a res oid */ if ( tag == LDAP_TAG_EXOP_RES_OID ) { static struct berval bv_nod = BER_BVC( LDAP_NOTICE_OF_DISCONNECTION ); struct berval resoid = BER_BVNULL; if ( ber_scanf( &tmpber, "m", &resoid ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return -1; } assert( !BER_BVISEMPTY( &resoid ) ); is_nod = ber_bvcmp( &resoid, &bv_nod ) == 0; tag = ber_peek_tag( &tmpber, &len ); } #if 0 /* don't need right now */ /* we have res data */ if ( tag == LDAP_TAG_EXOP_RES_VALUE ) { struct berval resdata; if ( ber_scanf( &tmpber, "m", &resdata ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; } /* use it... */ } #endif /* handle RFC 4511 "Notice of Disconnection" locally */ if ( is_nod ) { if ( tag == LDAP_TAG_EXOP_RES_VALUE ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return -1; } /* get rid of the connection... */ if ( lc != NULL ) { #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif ldap_free_connection( ld, lc, 0, 1 ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif lc = *lcp = NULL; } /* need to return -1, because otherwise * a valid result is expected */ return -1; } } /* make a new ldap message */ newmsg = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ); if ( newmsg == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } newmsg->lm_msgid = (int)id; newmsg->lm_msgtype = tag; newmsg->lm_ber = ber; newmsg->lm_chain_tail = newmsg; #ifdef LDAP_CONNECTIONLESS /* CLDAP replies all fit in a single datagram. In LDAPv2 RFC1798 * the responses are all a sequence wrapped in one message. In * LDAPv3 each response is in its own message. The datagram must * end with a SearchResult. We can't just parse each response in * separate calls to try_read1msg because the header info is only * present at the beginning of the datagram, not at the beginning * of each response. So parse all the responses at once and queue * them up, then pull off the first response to return to the * caller when all parsing is complete. */ if ( LDAP_IS_UDP(ld) ) { /* If not a result, look for more */ if ( tag != LDAP_RES_SEARCH_RESULT ) { int ok = 0; moremsgs = 1; if (isv2) { /* LDAPv2: dup the current ber, skip past the current * response, and see if there are any more after it. */ ber = ber_dup( ber ); ber_scanf( ber, "x" ); if ( ber_peek_tag( ber, &len ) != LBER_DEFAULT ) { /* There's more - dup the ber buffer so they can all be * individually freed by ldap_msgfree. */ struct berval bv; ber_get_option( ber, LBER_OPT_BER_REMAINING_BYTES, &len ); bv.bv_val = LDAP_MALLOC( len ); if ( bv.bv_val ) { ok = 1; ber_read( ber, bv.bv_val, len ); bv.bv_len = len; ber_init2( ber, &bv, ld->ld_lberoptions ); } } } else { /* LDAPv3: Just allocate a new ber. Since this is a buffered * datagram, if the sockbuf is readable we still have data * to parse. */ ber = ldap_alloc_ber_with_options( ld ); if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) ok = 1; } /* set up response chain */ if ( tmp == NULL ) { newmsg->lm_next = ld->ld_responses; ld->ld_responses = newmsg; chain_head = newmsg; } else { tmp->lm_chain = newmsg; } chain_head->lm_chain_tail = newmsg; tmp = newmsg; /* "ok" means there's more to parse */ if ( ok ) { if ( isv2 ) { goto nextresp2; } else { goto nextresp3; } } else { /* got to end of datagram without a SearchResult. Free * our dup'd ber, but leave any buffer alone. For v2 case, * the previous response is still using this buffer. For v3, * the new ber has no buffer to free yet. */ ber_free( ber, 0 ); return -1; } } else if ( moremsgs ) { /* got search result, and we had multiple responses in 1 datagram. * stick the result onto the end of the chain, and then pull the * first response off the head of the chain. */ tmp->lm_chain = newmsg; chain_head->lm_chain_tail = newmsg; *result = chkResponseList( ld, msgid, all ); ld->ld_errno = LDAP_SUCCESS; return( (*result)->lm_msgtype ); } } #endif /* LDAP_CONNECTIONLESS */ /* is this the one we're looking for? */ if ( msgid == LDAP_RES_ANY || id == msgid ) { if ( all == LDAP_MSG_ONE || ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY && newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) ) { *result = newmsg; ld->ld_errno = LDAP_SUCCESS; return( tag ); } else if ( newmsg->lm_msgtype == LDAP_RES_SEARCH_RESULT) { foundit = 1; /* return the chain later */ } } /* * if not, we must add it to the list of responses. if * the msgid is already there, it must be part of an existing * search response. */ prev = NULL; for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) { if ( l->lm_msgid == newmsg->lm_msgid ) { break; } prev = l; } /* not part of an existing search response */ if ( l == NULL ) { if ( foundit ) { *result = newmsg; goto exit; } newmsg->lm_next = ld->ld_responses; ld->ld_responses = newmsg; goto exit; } Debug( LDAP_DEBUG_TRACE, "adding response ld %p msgid %ld type %ld:\n", (void *)ld, (long) newmsg->lm_msgid, (long) newmsg->lm_msgtype ); /* part of a search response - add to end of list of entries */ l->lm_chain_tail->lm_chain = newmsg; l->lm_chain_tail = newmsg; /* return the whole chain if that's what we were looking for */ if ( foundit ) { if ( prev == NULL ) { ld->ld_responses = l->lm_next; } else { prev->lm_next = l->lm_next; } *result = l; } exit: if ( foundit ) { ld->ld_errno = LDAP_SUCCESS; return( tag ); } if ( lc && ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { goto retry; } return( LDAP_MSG_X_KEEP_LOOKING ); /* continue looking */ } static ber_tag_t build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr ) { ber_len_t len; ber_tag_t tag; ber_int_t along; BerElement *ber; *bp = NULL; ber = ldap_alloc_ber_with_options( ld ); if( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return LBER_ERROR; } if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid, lr->lr_res_msgtype, lr->lr_res_errno, lr->lr_res_matched ? lr->lr_res_matched : "", lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } ber_reset( ber, 1 ); if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } if ( ber_get_enum( ber, &along ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } tag = ber_peek_tag( ber, &len ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } *bp = ber; return tag; }
/* * 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; }
static int do_abandon( LDAP *ld, ber_int_t origid, ber_int_t msgid, LDAPControl **sctrls, LDAPControl **cctrls) { BerElement *ber; int i, err, sendabandon; ber_int_t *old_abandon; Sockbuf *sb; LDAPRequest *lr; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ARGS, "do_abandon %d, msgid %d\n", origid, msgid, 0 ); #else Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid, 0 ); #endif sendabandon = 1; /* find the request that we are abandoning */ for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { if ( lr->lr_msgid == msgid ) { /* this message */ break; } if ( lr->lr_origid == msgid ) {/* child: abandon it */ (void) do_abandon( ld, msgid, lr->lr_msgid, sctrls, cctrls ); } } if ( lr != NULL ) { if ( origid == msgid && lr->lr_parent != NULL ) { /* don't let caller abandon child requests! */ ld->ld_errno = LDAP_PARAM_ERROR; return( LDAP_PARAM_ERROR ); } if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { /* no need to send abandon message */ sendabandon = 0; } } if ( ldap_msgdelete( ld, msgid ) == 0 ) { ld->ld_errno = LDAP_SUCCESS; return LDAP_SUCCESS; } err = 0; if ( sendabandon ) { if( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected */ err = -1; ld->ld_errno = LDAP_SERVER_DOWN; } else if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { /* BER element alocation failed */ err = -1; ld->ld_errno = LDAP_NO_MEMORY; } else { #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { err = ber_write( ber, ld->ld_options.ldo_peer, sizeof(struct sockaddr), 0); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { char *dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{isti", /* '}' */ ++ld->ld_msgid, dn, LDAP_REQ_ABANDON, msgid ); } else #endif { /* create a message to send */ err = ber_printf( ber, "{iti", /* '}' */ ++ld->ld_msgid, LDAP_REQ_ABANDON, msgid ); } if( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } else { /* Put Server Controls */ if ( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { err = -1; } else { /* close '{' */ err = ber_printf( ber, /*{*/ "N}" ); if( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } } } if ( err == -1 ) { ber_free( ber, 1 ); } else { /* send the message */ if ( lr != NULL ) { sb = lr->lr_conn->lconn_sb; } else { sb = ld->ld_sb; } if ( ber_flush( sb, ber, 1 ) != 0 ) { ld->ld_errno = LDAP_SERVER_DOWN; err = -1; } else { err = 0; } } } } if ( lr != NULL ) { if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { ldap_free_connection( ld, lr->lr_conn, 0, 1 ); } if ( origid == msgid ) { ldap_free_request( ld, lr ); } } i = 0; if ( ld->ld_abandoned != NULL ) { for ( ; ld->ld_abandoned[i] != -1; i++ ) ; /* NULL */ } old_abandon = ld->ld_abandoned; ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *) ld->ld_abandoned, (i + 2) * sizeof(ber_int_t) ); if ( ld->ld_abandoned == NULL ) { ld->ld_abandoned = old_abandon; ld->ld_errno = LDAP_NO_MEMORY; return( ld->ld_errno ); } ld->ld_abandoned[i] = msgid; ld->ld_abandoned[i + 1] = -1; if ( err != -1 ) { ld->ld_errno = LDAP_SUCCESS; } return( ld->ld_errno ); }