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