3 * Copyright (c) 1990 Regents of the University of Michigan.
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and that due credit is given
8 * to the University of Michigan at Ann Arbor. The name of the University
9 * may not be used to endorse or promote products derived from this
10 * software without specific prior written permission. This software
11 * is provided ``as is'' without express or implied warranty.
18 #include <ac/socket.h>
19 #include <ac/string.h>
20 #include <ac/syslog.h>
22 #include <quipu/dsap.h>
23 #include <quipu/dap2.h>
24 #include <quipu/dua.h>
27 #include "../../libraries/liblber/lber-int.h" /* get struct berelement */
32 * dsa_response - called by do_queries() when there is activity on one of
33 * the DSA associations. It is passed the association descriptor on which
34 * the activity occurred, and the client socket. It figures out what kind
35 * of activity it was (e.g., result of a previously initiated operation,
36 * error return, etc), and calls the appropriate routine to send a response
37 * to the client, or to continue the operation in some cases (e.g., modify),
38 * or to chase a referral and retry an operation.
40 * If the client is actually given a response, dsa_response() removes the
41 * corresponding request from the queue of outstanding requests. If the
42 * activity was an error referral, a connection is made to the referred to
43 * DSA (if possible), and do_request() is called to retry the request.
52 struct DAPindication di;
55 struct DAPpreject *dp;
60 int incr, delete, rc, ldaperr;
62 Debug( LDAP_DEBUG_TRACE, "dsa_response on ad %d\n", dsaconn->c_ad, 0,
65 if ( (rc = DapInitWaitRequest( dsaconn->c_ad, OK, &di )) == DONE ) {
66 Debug( LDAP_DEBUG_ANY, "DapInitWaitRequest: DONE\n", 0, 0, 0 );
70 Debug( LDAP_DEBUG_ARGS, "DapInitWaitRequest: result %d type %d\n", rc,
74 switch ( di.di_type ) {
76 dr = &di.di_result.dr_res;
77 if ( (m = get_msg( di.di_result.dr_id )) == NULL ) {
78 Debug( LDAP_DEBUG_ANY, "DI_RESULT: can't find msg %d\n",
79 di.di_result.dr_id, 0, 0 );
83 Debug( LDAP_DEBUG_ARGS, "DI_RESULT: type %d\n",
84 dr->result_type, 0, 0 );
86 switch ( dr->result_type ) {
88 compare_result( clientsb, m, &dr->res_cm );
92 search_result( clientsb, m, &dr->res_sr );
96 add_result( clientsb, m );
100 delete_result( clientsb, m );
104 modify_result( clientsb, m );
108 if ( do_modify2( clientsb, m, &dr->res_rd ) != 0 )
113 modrdn_result( clientsb, m );
123 de = &di.di_error.de_err;
124 if ( (m = get_msg( di.di_error.de_id )) == NULL ) {
125 Debug( LDAP_DEBUG_ANY, "DI_ERROR: can't find msg %d\n",
126 di.di_error.de_id, 0, 0 );
129 if ( m->m_msgtype == LDAP_REQ_SEARCH
131 || m->m_msgtype == OLD_LDAP_REQ_SEARCH
135 else if ( m->m_msgtype == LDAP_REQ_DELETE )
136 incr = (LDAP_RES_DELETE - LDAP_REQ_DELETE);
140 Debug( LDAP_DEBUG_ARGS, "DI_ERROR\n", 0, 0, 0 );
143 * chase down referrals, retry operation there. only do
144 * this for modify-like operations, since we assume the
145 * dsa should have been able to chase anything else that
146 * wasn't really down.
149 if ( de->dse_type == DSE_REFERRAL ) {
152 switch ( m->m_msgtype ) {
154 case OLD_LDAP_REQ_ADD:
155 case OLD_LDAP_REQ_MODIFY:
156 case OLD_LDAP_REQ_MODRDN:
157 case OLD_LDAP_REQ_DELETE:
158 case OLD_LDAP_REQ_COMPARE:
159 case OLD_LDAP_REQ_SEARCH:
162 case LDAP_REQ_DELETE_30:
165 case LDAP_REQ_MODIFY:
166 case LDAP_REQ_MODRDN:
167 case LDAP_REQ_DELETE:
168 case LDAP_REQ_COMPARE:
169 case LDAP_REQ_SEARCH:
170 /* chase down the referral */
171 if ( (rc = chase_referral( clientsb, m, de,
172 &matched )) != LDAP_SUCCESS ) {
173 send_ldap_msgresult( clientsb,
174 m->m_msgtype + incr, m, rc,
175 matched, "Can't chase referral" );
180 /* now retry the operation */
181 bercopy = ber_dup( m->m_ber );
182 if ( do_request( clientsb, m, bercopy, &bound )
186 ber_free( bercopy, 0 );
191 send_ldap_msgresult( clientsb, m->m_msgtype +
192 incr, m, LDAP_UNAVAILABLE, NULL, "" );
196 } else if ( de->dse_type == DSE_ABANDONED ) {
201 /* not a referral - convert the error and return to client */
202 ldaperr = x500err2ldaperr( de, &matched );
205 print_error( de ); /* prints, then calls free */
210 send_ldap_msgresult( clientsb, m->m_msgtype + incr, m,
211 ldaperr, matched, "" );
217 if ( (m = get_msg( dp->dp_id )) == NULL ) {
218 Debug(LDAP_DEBUG_ANY, "DI_PREJECT: can't find msg %d\n",
223 Debug( LDAP_DEBUG_ARGS, "DI_PREJECT src %d rson %d inf (%s)\n",
224 dp->dp_source, dp->dp_reason, dp->dp_cc ? dp->dp_data
227 send_ldap_msgresult( clientsb, m->m_msgtype, m,
228 LDAP_UNAVAILABLE, NULL, "Got PREJECT from X.500" );
236 Debug( LDAP_DEBUG_ARGS, "DI_ABORT src %d rson %d inf (%s)\n",
237 da->da_source, da->da_reason, da->da_cc ? da->da_data
240 /* assume this always means more stuff coming... */
241 if ( da->da_reason == DA_ROS )
244 /* moby hack - but how else do you tell the difference? */
245 if ( isclosed( dsaconn->c_ad ) ) {
246 send_msg( dsaconn, clientsb, LDAP_UNAVAILABLE,
247 "Got ABORT from X.500" );
251 /* notify outstanding requests of the failure */
252 send_msg( dsaconn, clientsb, LDAP_OPERATIONS_ERROR,
253 "Got unknown ABORT from X.500" );
260 Debug( LDAP_DEBUG_ANY, "unknown result type %d\n", di.di_type,
263 dsaconn->c_ad = -1; /* better safe... */
268 if ( delete && m != NULL )
282 #ifdef LDAP_CONNECTIONLESS
284 ber_pvt_sb_udp_set_dst( &sb, &m->m_clientaddr );
286 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n",
287 inet_ntoa(((struct sockaddr_in *)
288 &m->m_clientaddr)->sin_addr ),
289 ((struct sockaddr_in *)&m->m_clientaddr)->sin_port, 0 );
292 return( send_ldap_result( sb, tag, m->m_msgid, err, matched, text ) );
307 #ifdef LDAP_CONNECTIONLESS
309 cldap = ( sb->sb_io == &ber_pvt_sb_io_udp );
312 Debug( LDAP_DEBUG_TRACE, "send_ldap_result\n", 0, 0, 0 );
314 if ( tag == LBER_DEFAULT )
316 tag = ldap_compat == 20 ? OLD_LBER_SEQUENCE : LBER_SEQUENCE;
321 if ( (ber = der_alloc()) == NULL ) {
322 Debug( LDAP_DEBUG_ANY, "der_alloc failed\n", 0, 0, 0 );
326 if ( version != 1 ) {
328 if ( ldap_compat == 20 ) {
329 rc = ber_printf( ber, "t{it{tess}}", OLD_LBER_SEQUENCE,
330 msgid, tag, LBER_INTEGER, err,
331 matched ? matched : "", text );
335 if ( ldap_compat == 30 ) {
336 rc = ber_printf( ber, "{it{{ess}}}", msgid, tag, err,
337 matched ? matched : "", text );
340 #ifdef LDAP_CONNECTIONLESS
342 rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
343 err, matched ? matched : "", text );
346 rc = ber_printf( ber, "{it{ess}}", msgid, tag, err, matched ?
347 matched : "", text );
349 /* version 1 always uses the broken stuff */
350 rc = ber_printf( ber, "t{it{is}}", OLD_LBER_SEQUENCE, msgid,
355 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
360 if ( ldap_debug & LDAP_DEBUG_BER )
361 trace_ber( 0, ber->ber_ptr - ber->ber_buf, ber->ber_buf,
365 if ( ber_flush( sb, ber, 1 ) != 0 ) {
366 Debug( LDAP_DEBUG_ANY, "ber_flush failed\n", 0, 0, 0 );