]> git.sur5r.net Git - openldap/blob - servers/ldapd/result.c
merged with autoconf branch
[openldap] / servers / ldapd / result.c
1 /*
2  * Copyright (c) 1990 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/socket.h>
18 #include <ac/string.h>
19 #include <ac/syslog.h>
20
21 #include <quipu/dsap.h>
22 #include <quipu/dap2.h>
23 #include <quipu/dua.h>
24
25 #include "lber.h"
26 #include "ldap.h"
27 #include "common.h"
28
29 extern int      dosyslog;
30 #ifdef LDAP_COMPAT
31 extern int      ldap_compat;
32 #endif
33
34 /*
35  * dsa_response - called by do_queries() when there is activity on one of
36  * the DSA associations.  It is passed the association descriptor on which
37  * the activity occurred, and the client socket.  It figures out what kind
38  * of activity it was (e.g., result of a previously initiated operation,
39  * error return, etc), and calls the appropriate routine to send a response
40  * to the client, or to continue the operation in some cases (e.g., modify),
41  * or to chase a referral and retry an operation.
42  *
43  * If the client is actually given a response, dsa_response() removes the
44  * corresponding request from the queue of outstanding requests.  If the
45  * activity was an error referral, a connection is made to the referred to
46  * DSA (if possible), and do_request() is called to retry the request.
47  */
48
49 void
50 dsa_response(
51     struct conn *dsaconn,
52     Sockbuf     *clientsb
53 )
54 {
55         struct DAPindication    di;
56         struct DSResult         *dr;
57         struct DSError          *de;
58         struct DAPpreject       *dp;
59         struct DAPabort         *da;
60         struct msg              *m = NULL;
61         BerElement              *bercopy;
62         char                    *matched;
63         int                     incr, delete, rc, ldaperr;
64
65         Debug( LDAP_DEBUG_TRACE, "dsa_response on ad %d\n", dsaconn->c_ad, 0,
66             0 );
67         di.di_type = -1;
68         if ( (rc = DapInitWaitRequest( dsaconn->c_ad, OK, &di )) == DONE ) {
69                 Debug( LDAP_DEBUG_ANY, "DapInitWaitRequest: DONE\n", 0, 0, 0 );
70                 return;
71         }
72
73         Debug( LDAP_DEBUG_ARGS, "DapInitWaitRequest: result %d type %d\n", rc,
74             di.di_type, 0 );
75
76         delete = 1;
77         switch ( di.di_type ) {
78         case DI_RESULT:
79                 dr = &di.di_result.dr_res;
80                 if ( (m = get_msg( di.di_result.dr_id )) == NULL ) {
81                         Debug( LDAP_DEBUG_ANY, "DI_RESULT: can't find msg %d\n",
82                             di.di_result.dr_id, 0, 0 );
83                         return;
84                 }
85
86                 Debug( LDAP_DEBUG_ARGS, "DI_RESULT: type %d\n",
87                     dr->result_type, 0, 0 );
88
89                 switch ( dr->result_type ) {
90                 case OP_COMPARE:
91                         compare_result( clientsb, m, &dr->res_cm );
92                         break;
93
94                 case OP_SEARCH:
95                         search_result( clientsb, m, &dr->res_sr );
96                         break;
97
98                 case OP_ADDENTRY:
99                         add_result( clientsb, m );
100                         break;
101
102                 case OP_REMOVEENTRY:
103                         delete_result( clientsb, m );
104                         break;
105
106                 case OP_MODIFYENTRY:
107                         modify_result( clientsb, m );
108                         break;
109
110                 case OP_READ:
111                         if ( do_modify2( clientsb, m, &dr->res_rd ) != 0 )
112                                 delete = 0;
113                         break;
114
115                 case OP_MODIFYRDN:
116                         modrdn_result( clientsb, m );
117                         break;
118
119                 default:
120                         break;
121                 }
122                 ds_res_free( dr );
123                 break;
124
125         case DI_ERROR:
126                 de = &di.di_error.de_err;
127                 if ( (m = get_msg( di.di_error.de_id )) == NULL ) {
128                         Debug( LDAP_DEBUG_ANY, "DI_ERROR: can't find msg %d\n",
129                             di.di_error.de_id, 0, 0 );
130                         return;
131                 }
132                 if ( m->m_msgtype == LDAP_REQ_SEARCH 
133 #ifdef LDAP_COMPAT20
134                     || m->m_msgtype == OLD_LDAP_REQ_SEARCH
135 #endif
136                     )
137                         incr = 2;
138                 else if ( m->m_msgtype == LDAP_REQ_DELETE )
139                         incr = (LDAP_RES_DELETE - LDAP_REQ_DELETE);
140                 else
141                         incr = 1;
142
143                 Debug( LDAP_DEBUG_ARGS, "DI_ERROR\n", 0, 0, 0 );
144
145                 /* 
146                  * chase down referrals, retry operation there.  only do
147                  * this for modify-like operations, since we assume the
148                  * dsa should have been able to chase anything else that
149                  * wasn't really down.
150                  */
151
152                 if ( de->dse_type == DSE_REFERRAL ) {
153                         int     bound, rc;
154
155                         switch ( m->m_msgtype ) {
156 #ifdef LDAP_COMPAT20
157                         case OLD_LDAP_REQ_ADD:
158                         case OLD_LDAP_REQ_MODIFY:
159                         case OLD_LDAP_REQ_MODRDN:
160                         case OLD_LDAP_REQ_DELETE:
161                         case OLD_LDAP_REQ_COMPARE:
162                         case OLD_LDAP_REQ_SEARCH:
163 #endif
164 #ifdef LDAP_COMPAT30
165                         case LDAP_REQ_DELETE_30:
166 #endif
167                         case LDAP_REQ_ADD:
168                         case LDAP_REQ_MODIFY:
169                         case LDAP_REQ_MODRDN:
170                         case LDAP_REQ_DELETE:
171                         case LDAP_REQ_COMPARE:
172                         case LDAP_REQ_SEARCH:
173                                 /* chase down the referral */
174                                 if ( (rc = chase_referral( clientsb, m, de,
175                                     &matched )) != LDAP_SUCCESS ) {
176                                         send_ldap_msgresult( clientsb,
177                                             m->m_msgtype + incr, m, rc,
178                                             matched, "Can't chase referral" );
179                                         free( matched );
180                                         break;
181                                 }
182
183                                 /* now retry the operation */
184                                 bercopy = ber_dup( m->m_ber );
185                                 if ( do_request( clientsb, m, bercopy, &bound )
186                                     == 0 ) {
187                                         del_msg( m );
188                                 }
189                                 ber_free( bercopy, 0 );
190                                 return;
191                                 break;
192
193                         default:
194                                 send_ldap_msgresult( clientsb, m->m_msgtype +
195                                     incr, m, LDAP_UNAVAILABLE, NULL, "" );
196                                 break;
197                         }
198                         break;
199                 } else if ( de->dse_type == DSE_ABANDONED ) {
200                         return;
201                 }
202                 
203
204                 /* not a referral - convert the error and return to client */
205                 ldaperr = x500err2ldaperr( de, &matched );
206 #ifdef LDAP_DEBUG
207                 if ( ldap_debug )
208                         print_error( de );      /* prints, then calls free */
209                 else
210 #endif
211                         ds_error_free( de );
212
213                 send_ldap_msgresult( clientsb, m->m_msgtype + incr, m,
214                     ldaperr, matched, "" );
215                 free( matched );
216                 break;
217
218         case DI_PREJECT:
219                 dp = &di.di_preject;
220                 if ( (m = get_msg( dp->dp_id )) == NULL ) {
221                         Debug(LDAP_DEBUG_ANY, "DI_PREJECT: can't find msg %d\n",
222                             dp->dp_id, 0, 0 );
223                         return;
224                 }
225
226                 Debug( LDAP_DEBUG_ARGS, "DI_PREJECT src %d rson %d inf (%s)\n",
227                     dp->dp_source, dp->dp_reason, dp->dp_cc ? dp->dp_data
228                     : "" );
229
230                 send_ldap_msgresult( clientsb, m->m_msgtype, m,
231                     LDAP_UNAVAILABLE, NULL, "Got PREJECT from X.500" );
232
233                 dsaconn->c_ad = -1;
234                 break;
235
236         case DI_ABORT:
237                 da = &di.di_abort;
238
239                 Debug( LDAP_DEBUG_ARGS, "DI_ABORT src %d rson %d inf (%s)\n",
240                     da->da_source, da->da_reason, da->da_cc ? da->da_data
241                     : "" );
242
243                 /* assume this always means more stuff coming... */
244                 if ( da->da_reason == DA_ROS )
245                         return;
246
247                 /* moby hack - but how else do you tell the difference? */
248                 if ( isclosed( dsaconn->c_ad ) ) {
249                         send_msg( dsaconn, clientsb, LDAP_UNAVAILABLE,
250                             "Got ABORT from X.500" );
251                         return;
252                 }
253
254                 /* notify outstanding requests of the failure */
255                 send_msg( dsaconn, clientsb, LDAP_OPERATIONS_ERROR,
256                     "Got unknown ABORT from X.500" );
257
258                 dsaconn->c_ad = -1;
259                 return;
260                 break;
261
262         default:
263                 Debug( LDAP_DEBUG_ANY, "unknown result type %d\n", di.di_type,
264                     0, 0 );
265
266                 dsaconn->c_ad = -1;     /* better safe... */
267                 return;
268                 break;
269         }
270
271         if ( delete && m != NULL )
272                 del_msg( m );
273 }
274
275 int
276 send_ldap_msgresult(
277     Sockbuf             *sb,
278     unsigned long       tag,
279     struct msg          *m,
280     int                 err,
281     char                *matched,
282     char                *text
283 )
284 {
285 #ifdef LDAP_CONNECTIONLESS
286         if ( m->m_cldap ) {
287                 SAFEMEMCPY( (char *)sb->sb_useaddr, &m->m_clientaddr,
288                     sizeof( struct sockaddr ));
289                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
290                     inet_ntoa(((struct sockaddr_in *)
291                     sb->sb_useaddr)->sin_addr ),
292                     ((struct sockaddr_in *)sb->sb_useaddr)->sin_port, 0 );
293         }
294 #endif
295         return( send_ldap_result( sb, tag, m->m_msgid, err, matched, text ) );
296 }
297
298 int
299 send_ldap_result(
300     Sockbuf             *sb,
301     unsigned long       tag,
302     int                 msgid,
303     int                 err,
304     char                *matched,
305     char                *text
306 )
307 {
308         BerElement      *ber;
309         int             rc;
310 #ifdef LDAP_CONNECTIONLESS
311         int             cldap;
312 #endif
313         extern int      version;
314
315 #ifdef LDAP_CONNECTIONLESS
316         cldap = ( sb->sb_naddr > 0 );
317 #endif
318
319         Debug( LDAP_DEBUG_TRACE, "send_ldap_result\n", 0, 0, 0 );
320
321         if ( tag == LBER_DEFAULT )
322 #ifdef LDAP_COMPAT20
323                 tag = ldap_compat == 20 ? OLD_LBER_SEQUENCE : LBER_SEQUENCE;
324 #else
325                 tag = LBER_SEQUENCE;
326 #endif
327
328         if ( (ber = der_alloc()) == NULLBER ) {
329                 Debug( LDAP_DEBUG_ANY, "der_alloc failed\n", 0, 0, 0 );
330                 return( -1 );
331         }
332
333         if ( version != 1 ) {
334 #ifdef LDAP_COMPAT20
335                 if ( ldap_compat == 20 ) {
336                         rc = ber_printf( ber, "t{it{tess}}", OLD_LBER_SEQUENCE,
337                             msgid, tag, LBER_INTEGER, err,
338                             matched ? matched : "", text );
339                 } else
340 #endif
341 #ifdef LDAP_COMPAT30
342                 if ( ldap_compat == 30 ) {
343                         rc = ber_printf( ber, "{it{{ess}}}", msgid, tag, err,
344                             matched ? matched : "", text );
345                 } else
346 #endif
347 #ifdef LDAP_CONNECTIONLESS
348                 if ( cldap ) {
349                         rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
350                             err, matched ? matched : "", text );
351                 } else
352 #endif
353                 rc = ber_printf( ber, "{it{ess}}", msgid, tag, err, matched ?
354                     matched : "", text );
355         } else {
356                 /* version 1 always uses the broken stuff */
357                 rc = ber_printf( ber, "t{it{is}}", OLD_LBER_SEQUENCE, msgid,
358                     tag, err, text );
359         }
360
361         if ( rc == -1 ) {
362                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
363                 return( -1 );
364         }
365
366 #ifdef LDAP_DEBUG
367         if ( ldap_debug & LDAP_DEBUG_BER )
368                 trace_ber( 0, ber->ber_ptr - ber->ber_buf, ber->ber_buf,
369                     stderr, 0, 0 );
370 #endif
371
372         if ( ber_flush( sb, ber, 1 ) != 0 ) {
373                 Debug( LDAP_DEBUG_ANY, "ber_flush failed\n", 0, 0, 0 );
374                 return( -1 );
375         }
376
377         return( 0 );
378 }