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