1 /*        $NetBSD: abandon.c,v 1.3 2021/08/14 16:14:55 christos Exp $ */
2 
3 /* abandon.c */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* Portions  Copyright (c) 1990 Regents of the University of Michigan.
19  * All rights reserved.
20  */
21 
22 #include <sys/cdefs.h>
23 __RCSID("$NetBSD: abandon.c,v 1.3 2021/08/14 16:14:55 christos Exp $");
24 
25 #include "portable.h"
26 
27 #include <stdio.h>
28 
29 #include <ac/stdlib.h>
30 
31 #include <ac/socket.h>
32 #include <ac/string.h>
33 #include <ac/time.h>
34 
35 #include "ldap-int.h"
36 
37 /*
38  * An abandon request looks like this:
39  *                  AbandonRequest ::= [APPLICATION 16] MessageID
40  * and has no response.  (Source: RFC 4511)
41  */
42 #include "lutil.h"
43 
44 static int
45 do_abandon(
46           LDAP *ld,
47           ber_int_t origid,
48           LDAPRequest *lr,
49           LDAPControl **sctrls,
50           int sendabandon );
51 
52 /*
53  * ldap_abandon_ext - perform an ldap extended abandon operation.
54  *
55  * Parameters:
56  *        ld                            LDAP descriptor
57  *        msgid               The message id of the operation to abandon
58  *        scntrls             Server Controls
59  *        ccntrls             Client Controls
60  *
61  * ldap_abandon_ext returns a LDAP error code.
62  *                  (LDAP_SUCCESS if everything went ok)
63  *
64  * Example:
65  *        ldap_abandon_ext( ld, msgid, scntrls, ccntrls );
66  */
67 int
ldap_abandon_ext(LDAP * ld,int msgid,LDAPControl ** sctrls,LDAPControl ** cctrls)68 ldap_abandon_ext(
69           LDAP *ld,
70           int msgid,
71           LDAPControl **sctrls,
72           LDAPControl **cctrls )
73 {
74           int       rc;
75 
76           Debug1( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid );
77 
78           /* check client controls */
79           LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
80 
81           rc = ldap_int_client_controls( ld, cctrls );
82           if ( rc == LDAP_SUCCESS ) {
83                     rc = do_abandon( ld, msgid, NULL, sctrls, 1 );
84           }
85 
86           LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
87 
88           return rc;
89 }
90 
91 
92 /*
93  * ldap_abandon - perform an ldap abandon operation. Parameters:
94  *
95  *        ld                  LDAP descriptor
96  *        msgid               The message id of the operation to abandon
97  *
98  * ldap_abandon returns 0 if everything went ok, -1 otherwise.
99  *
100  * Example:
101  *        ldap_abandon( ld, msgid );
102  */
103 int
ldap_abandon(LDAP * ld,int msgid)104 ldap_abandon( LDAP *ld, int msgid )
105 {
106           Debug1( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid );
107           return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS
108                     ? 0 : -1;
109 }
110 
111 
112 int
ldap_pvt_discard(LDAP * ld,ber_int_t msgid)113 ldap_pvt_discard(
114           LDAP *ld,
115           ber_int_t msgid )
116 {
117           int       rc;
118 
119           LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
120           rc = do_abandon( ld, msgid, NULL, NULL, 0 );
121           LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
122           return rc;
123 }
124 
125 static int
do_abandon(LDAP * ld,ber_int_t origid,LDAPRequest * lr,LDAPControl ** sctrls,int sendabandon)126 do_abandon(
127           LDAP *ld,
128           ber_int_t origid,
129           LDAPRequest *lr,
130           LDAPControl **sctrls,
131           int sendabandon )
132 {
133           BerElement          *ber;
134           int                 i, err;
135           ber_int_t msgid = origid;
136           Sockbuf             *sb;
137           LDAPRequest         needle = {0};
138 
139           needle.lr_msgid = origid;
140 
141           if ( lr != NULL ) {
142                     msgid = lr->lr_msgid;
143                     Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
144                                         origid, msgid );
145           } else if ( (lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp )) != NULL ) {
146                     Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
147                                         origid, msgid );
148                     if ( lr->lr_parent != NULL ) {
149                               /* don't let caller abandon child requests! */
150                               ld->ld_errno = LDAP_PARAM_ERROR;
151                               return( LDAP_PARAM_ERROR );
152                     }
153                     msgid = lr->lr_msgid;
154           }
155 
156           if ( lr != NULL ) {
157                     LDAPRequest **childp = &lr->lr_child;
158 
159                     needle.lr_msgid = lr->lr_msgid;
160 
161                     if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
162                               /* no need to send abandon message */
163                               sendabandon = 0;
164                     }
165 
166                     while ( *childp ) {
167                               /* Abandon children */
168                               LDAPRequest *child = *childp;
169 
170                               (void)do_abandon( ld, lr->lr_origid, child, sctrls, sendabandon );
171                               if ( *childp == child ) {
172                                         childp = &child->lr_refnext;
173                               }
174                     }
175           }
176 
177           /* ldap_msgdelete locks the res_mutex. Give up the req_mutex
178            * while we're in there.
179            */
180           LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
181           err = ldap_msgdelete( ld, msgid );
182           LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
183           if ( err == 0 ) {
184                     ld->ld_errno = LDAP_SUCCESS;
185                     return LDAP_SUCCESS;
186           }
187 
188           /* fetch again the request that we are abandoning */
189           if ( lr != NULL ) {
190                     lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp );
191           }
192 
193           err = 0;
194           if ( sendabandon ) {
195                     if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
196                               /* not connected */
197                               err = -1;
198                               ld->ld_errno = LDAP_SERVER_DOWN;
199 
200                     } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
201                               /* BER element allocation failed */
202                               err = -1;
203                               ld->ld_errno = LDAP_NO_MEMORY;
204 
205                     } else {
206                               /*
207                                * We already have the mutex in LDAP_R_COMPILE, so
208                                * don't try to get it again.
209                                *                  LDAP_NEXT_MSGID(ld, i);
210                                */
211 
212                               LDAP_NEXT_MSGID(ld, i);
213 #ifdef LDAP_CONNECTIONLESS
214                               if ( LDAP_IS_UDP(ld) ) {
215                                         struct sockaddr_storage sa = {0};
216                                         /* dummy, filled with ldo_peer in request.c */
217                                         err = ber_write( ber, (char *) &sa, sizeof(sa), 0 );
218                               }
219                               if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
220                                         LDAP_VERSION2 )
221                               {
222                                         char *dn;
223                                         LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
224                                         dn = ld->ld_options.ldo_cldapdn;
225                                         if (!dn) dn = "";
226                                         err = ber_printf( ber, "{isti",  /* '}' */
227                                                   i, dn,
228                                                   LDAP_REQ_ABANDON, msgid );
229                                         LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
230                               } else
231 #endif
232                               {
233                                         /* create a message to send */
234                                         err = ber_printf( ber, "{iti",  /* '}' */
235                                                   i,
236                                                   LDAP_REQ_ABANDON, msgid );
237                               }
238 
239                               if ( err == -1 ) {
240                                         /* encoding error */
241                                         ld->ld_errno = LDAP_ENCODING_ERROR;
242 
243                               } else {
244                                         /* Put Server Controls */
245                                         if ( ldap_int_put_controls( ld, sctrls, ber )
246                                                   != LDAP_SUCCESS )
247                                         {
248                                                   err = -1;
249 
250                                         } else {
251                                                   /* close '{' */
252                                                   err = ber_printf( ber, /*{*/ "N}" );
253 
254                                                   if ( err == -1 ) {
255                                                             /* encoding error */
256                                                             ld->ld_errno = LDAP_ENCODING_ERROR;
257                                                   }
258                                         }
259                               }
260 
261                               if ( err == -1 ) {
262                                         ber_free( ber, 1 );
263 
264                               } else {
265                                         /* send the message */
266                                         if ( lr != NULL ) {
267                                                   assert( lr->lr_conn != NULL );
268                                                   sb = lr->lr_conn->lconn_sb;
269                                         } else {
270                                                   sb = ld->ld_sb;
271                                         }
272 
273                                         if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) {
274                                                   ld->ld_errno = LDAP_SERVER_DOWN;
275                                                   err = -1;
276                                         } else {
277                                                   err = 0;
278                                         }
279                               }
280                     }
281           }
282 
283           if ( lr != NULL ) {
284                     LDAPConn *lc;
285                     int freeconn = 0;
286                     if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
287                               freeconn = 1;
288                               lc = lr->lr_conn;
289                     }
290                     if ( origid == msgid ) {
291                               ldap_free_request( ld, lr );
292 
293                     } else {
294                               lr->lr_abandoned = 1;
295                     }
296 
297                     if ( freeconn ) {
298                               /* release ld_req_mutex while grabbing ld_conn_mutex to
299                                * prevent deadlock.
300                                */
301                               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
302                               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
303                               ldap_free_connection( ld, lc, 0, 1 );
304                               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
305                               LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
306                     }
307           }
308 
309           LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
310 
311           /* use bisection */
312           i = 0;
313           if ( ld->ld_nabandoned == 0 ||
314                     ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 )
315           {
316                     ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i );
317           }
318 
319           if ( err != -1 ) {
320                     ld->ld_errno = LDAP_SUCCESS;
321           }
322 
323           LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
324           return( ld->ld_errno );
325 }
326 
327 /*
328  * ldap_int_bisect_find
329  *
330  * args:
331  *        v:        array of length n (in)
332  *        n:        length of array v (in)
333  *        id:       value to look for (in)
334  *        idxp:     pointer to location of value/insert point
335  *
336  * return:
337  *        0:        not found
338  *        1:        found
339  *        -1:       error
340  */
341 int
ldap_int_bisect_find(ber_int_t * v,ber_len_t n,ber_int_t id,int * idxp)342 ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
343 {
344           int                 begin,
345                               end,
346                               rc = 0;
347 
348           assert( id >= 0 );
349 
350           begin = 0;
351           end = n - 1;
352 
353                     if ( n <= 0 || id < v[ begin ] ) {
354                               *idxp = 0;
355 
356                     } else if ( id > v[ end ] ) {
357                               *idxp = n;
358 
359                     } else {
360                               int                 pos;
361                               ber_int_t curid;
362 
363                               do {
364                                         pos = (begin + end)/2;
365                                         curid = v[ pos ];
366 
367                                         if ( id < curid ) {
368                                                   end = pos - 1;
369 
370                                         } else if ( id > curid ) {
371                                                   begin = ++pos;
372 
373                                         } else {
374                                                   /* already abandoned? */
375                                                   rc = 1;
376                                                   break;
377                                         }
378                               } while ( end >= begin );
379 
380                               *idxp = pos;
381                     }
382 
383           return rc;
384 }
385 
386 /*
387  * ldap_int_bisect_insert
388  *
389  * args:
390  *        vp:       pointer to array of length *np (in/out)
391  *        np:       pointer to length of array *vp (in/out)
392  *        id:       value to insert (in)
393  *        idx:      location of insert point (as computed by ldap_int_bisect_find())
394  *
395  * return:
396  *        0:        inserted
397  *        -1:       error
398  */
399 int
ldap_int_bisect_insert(ber_int_t ** vp,ber_len_t * np,int id,int idx)400 ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
401 {
402           ber_int_t *v;
403           ber_len_t n;
404           int                 i;
405 
406           assert( vp != NULL );
407           assert( np != NULL );
408           assert( idx >= 0 );
409           assert( (unsigned) idx <= *np );
410 
411           n = *np;
412 
413           v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
414           if ( v == NULL ) {
415                     return -1;
416           }
417           *vp = v;
418 
419           for ( i = n; i > idx; i-- ) {
420                     v[ i ] = v[ i - 1 ];
421           }
422           v[ idx ] = id;
423           ++(*np);
424 
425           return 0;
426 }
427 
428 /*
429  * ldap_int_bisect_delete
430  *
431  * args:
432  *        vp:       pointer to array of length *np (in/out)
433  *        np:       pointer to length of array *vp (in/out)
434  *        id:       value to delete (in)
435  *        idx:      location of value to delete (as computed by ldap_int_bisect_find())
436  *
437  * return:
438  *        0:        deleted
439  */
440 int
ldap_int_bisect_delete(ber_int_t ** vp,ber_len_t * np,int id,int idx)441 ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
442 {
443           ber_int_t *v;
444           ber_len_t i, n;
445 
446           assert( vp != NULL );
447           assert( np != NULL );
448           assert( idx >= 0 );
449           assert( (unsigned) idx < *np );
450 
451           v = *vp;
452 
453           assert( v[ idx ] == id );
454 
455           --(*np);
456           n = *np;
457 
458           for ( i = idx; i < n; i++ ) {
459                     v[ i ] = v[ i + 1 ];
460           }
461 
462           return 0;
463 }
464