]> git.sur5r.net Git - openldap/blob - servers/ldapd/result.c
Add OpenLDAP RCSid to *.[ch] in clients, libraries, and servers.
[openldap] / servers / ldapd / result.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright (c) 1990 Regents of the University of Michigan.
4  * All rights reserved.
5  *
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.
12  */
13
14 #include "portable.h"
15
16 #include <stdio.h>
17
18 #include <ac/socket.h>
19 #include <ac/string.h>
20 #include <ac/syslog.h>
21
22 #include <quipu/dsap.h>
23 #include <quipu/dap2.h>
24 #include <quipu/dua.h>
25
26 #include "lber.h"
27 #include "../../libraries/liblber/lber-int.h"   /* get struct berelement */
28 #include "ldap.h"
29 #include "common.h"
30
31 /*
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.
39  *
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.
44  */
45
46 void
47 dsa_response(
48     struct conn *dsaconn,
49     Sockbuf     *clientsb
50 )
51 {
52         struct DAPindication    di;
53         struct DSResult         *dr;
54         struct DSError          *de;
55         struct DAPpreject       *dp;
56         struct DAPabort         *da;
57         struct msg              *m = NULL;
58         BerElement              *bercopy;
59         char                    *matched;
60         int                     incr, delete, rc, ldaperr;
61
62         Debug( LDAP_DEBUG_TRACE, "dsa_response on ad %d\n", dsaconn->c_ad, 0,
63             0 );
64         di.di_type = -1;
65         if ( (rc = DapInitWaitRequest( dsaconn->c_ad, OK, &di )) == DONE ) {
66                 Debug( LDAP_DEBUG_ANY, "DapInitWaitRequest: DONE\n", 0, 0, 0 );
67                 return;
68         }
69
70         Debug( LDAP_DEBUG_ARGS, "DapInitWaitRequest: result %d type %d\n", rc,
71             di.di_type, 0 );
72
73         delete = 1;
74         switch ( di.di_type ) {
75         case DI_RESULT:
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 );
80                         return;
81                 }
82
83                 Debug( LDAP_DEBUG_ARGS, "DI_RESULT: type %d\n",
84                     dr->result_type, 0, 0 );
85
86                 switch ( dr->result_type ) {
87                 case OP_COMPARE:
88                         compare_result( clientsb, m, &dr->res_cm );
89                         break;
90
91                 case OP_SEARCH:
92                         search_result( clientsb, m, &dr->res_sr );
93                         break;
94
95                 case OP_ADDENTRY:
96                         add_result( clientsb, m );
97                         break;
98
99                 case OP_REMOVEENTRY:
100                         delete_result( clientsb, m );
101                         break;
102
103                 case OP_MODIFYENTRY:
104                         modify_result( clientsb, m );
105                         break;
106
107                 case OP_READ:
108                         if ( do_modify2( clientsb, m, &dr->res_rd ) != 0 )
109                                 delete = 0;
110                         break;
111
112                 case OP_MODIFYRDN:
113                         modrdn_result( clientsb, m );
114                         break;
115
116                 default:
117                         break;
118                 }
119                 ds_res_free( dr );
120                 break;
121
122         case DI_ERROR:
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 );
127                         return;
128                 }
129                 if ( m->m_msgtype == LDAP_REQ_SEARCH 
130 #ifdef LDAP_COMPAT20
131                     || m->m_msgtype == OLD_LDAP_REQ_SEARCH
132 #endif
133                     )
134                         incr = 2;
135                 else if ( m->m_msgtype == LDAP_REQ_DELETE )
136                         incr = (LDAP_RES_DELETE - LDAP_REQ_DELETE);
137                 else
138                         incr = 1;
139
140                 Debug( LDAP_DEBUG_ARGS, "DI_ERROR\n", 0, 0, 0 );
141
142                 /* 
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.
147                  */
148
149                 if ( de->dse_type == DSE_REFERRAL ) {
150                         int     bound, rc;
151
152                         switch ( m->m_msgtype ) {
153 #ifdef LDAP_COMPAT20
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:
160 #endif
161 #ifdef LDAP_COMPAT30
162                         case LDAP_REQ_DELETE_30:
163 #endif
164                         case LDAP_REQ_ADD:
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" );
176                                         free( matched );
177                                         break;
178                                 }
179
180                                 /* now retry the operation */
181                                 bercopy = ber_dup( m->m_ber );
182                                 if ( do_request( clientsb, m, bercopy, &bound )
183                                     == 0 ) {
184                                         del_msg( m );
185                                 }
186                                 ber_free( bercopy, 0 );
187                                 return;
188                                 break;
189
190                         default:
191                                 send_ldap_msgresult( clientsb, m->m_msgtype +
192                                     incr, m, LDAP_UNAVAILABLE, NULL, "" );
193                                 break;
194                         }
195                         break;
196                 } else if ( de->dse_type == DSE_ABANDONED ) {
197                         return;
198                 }
199                 
200
201                 /* not a referral - convert the error and return to client */
202                 ldaperr = x500err2ldaperr( de, &matched );
203 #ifdef LDAP_DEBUG
204                 if ( ldap_debug )
205                         print_error( de );      /* prints, then calls free */
206                 else
207 #endif
208                         ds_error_free( de );
209
210                 send_ldap_msgresult( clientsb, m->m_msgtype + incr, m,
211                     ldaperr, matched, "" );
212                 free( matched );
213                 break;
214
215         case DI_PREJECT:
216                 dp = &di.di_preject;
217                 if ( (m = get_msg( dp->dp_id )) == NULL ) {
218                         Debug(LDAP_DEBUG_ANY, "DI_PREJECT: can't find msg %d\n",
219                             dp->dp_id, 0, 0 );
220                         return;
221                 }
222
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
225                     : "" );
226
227                 send_ldap_msgresult( clientsb, m->m_msgtype, m,
228                     LDAP_UNAVAILABLE, NULL, "Got PREJECT from X.500" );
229
230                 dsaconn->c_ad = -1;
231                 break;
232
233         case DI_ABORT:
234                 da = &di.di_abort;
235
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
238                     : "" );
239
240                 /* assume this always means more stuff coming... */
241                 if ( da->da_reason == DA_ROS )
242                         return;
243
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" );
248                         return;
249                 }
250
251                 /* notify outstanding requests of the failure */
252                 send_msg( dsaconn, clientsb, LDAP_OPERATIONS_ERROR,
253                     "Got unknown ABORT from X.500" );
254
255                 dsaconn->c_ad = -1;
256                 return;
257                 break;
258
259         default:
260                 Debug( LDAP_DEBUG_ANY, "unknown result type %d\n", di.di_type,
261                     0, 0 );
262
263                 dsaconn->c_ad = -1;     /* better safe... */
264                 return;
265                 break;
266         }
267
268         if ( delete && m != NULL )
269                 del_msg( m );
270 }
271
272 int
273 send_ldap_msgresult(
274     Sockbuf             *sb,
275     unsigned long       tag,
276     struct msg          *m,
277     int                 err,
278     char                *matched,
279     char                *text
280 )
281 {
282 #ifdef LDAP_CONNECTIONLESS
283         if ( m->m_cldap ) {
284                 ber_pvt_sb_udp_set_dst( &sb, &m->m_clientaddr );
285
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 );
290         }
291 #endif
292         return( send_ldap_result( sb, tag, m->m_msgid, err, matched, text ) );
293 }
294
295 int
296 send_ldap_result(
297     Sockbuf             *sb,
298     unsigned long       tag,
299     int                 msgid,
300     int                 err,
301     char                *matched,
302     char                *text
303 )
304 {
305         BerElement      *ber;
306         int             rc;
307 #ifdef LDAP_CONNECTIONLESS
308         int             cldap;
309         cldap = ( sb->sb_io == &ber_pvt_sb_io_udp );
310 #endif
311
312         Debug( LDAP_DEBUG_TRACE, "send_ldap_result\n", 0, 0, 0 );
313
314         if ( tag == LBER_DEFAULT )
315 #ifdef LDAP_COMPAT20
316                 tag = ldap_compat == 20 ? OLD_LBER_SEQUENCE : LBER_SEQUENCE;
317 #else
318                 tag = LBER_SEQUENCE;
319 #endif
320
321         if ( (ber = der_alloc()) == NULL ) {
322                 Debug( LDAP_DEBUG_ANY, "der_alloc failed\n", 0, 0, 0 );
323                 return( -1 );
324         }
325
326         if ( version != 1 ) {
327 #ifdef LDAP_COMPAT20
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 );
332                 } else
333 #endif
334 #ifdef LDAP_COMPAT30
335                 if ( ldap_compat == 30 ) {
336                         rc = ber_printf( ber, "{it{{ess}}}", msgid, tag, err,
337                             matched ? matched : "", text );
338                 } else
339 #endif
340 #ifdef LDAP_CONNECTIONLESS
341                 if ( cldap ) {
342                         rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
343                             err, matched ? matched : "", text );
344                 } else
345 #endif
346                 rc = ber_printf( ber, "{it{ess}}", msgid, tag, err, matched ?
347                     matched : "", text );
348         } else {
349                 /* version 1 always uses the broken stuff */
350                 rc = ber_printf( ber, "t{it{is}}", OLD_LBER_SEQUENCE, msgid,
351                     tag, err, text );
352         }
353
354         if ( rc == -1 ) {
355                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
356                 return( -1 );
357         }
358
359 #ifdef LDAP_DEBUG
360         if ( ldap_debug & LDAP_DEBUG_BER )
361                 trace_ber( 0, ber->ber_ptr - ber->ber_buf, ber->ber_buf,
362                     stderr, 0, 0 );
363 #endif
364
365         if ( ber_flush( sb, ber, 1 ) != 0 ) {
366                 Debug( LDAP_DEBUG_ANY, "ber_flush failed\n", 0, 0, 0 );
367                 return( -1 );
368         }
369
370         return( 0 );
371 }