1 /* abandon.c - decode and handle an ldap abandon operation */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2021 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26 
27 #include "portable.h"
28 
29 #include <stdio.h>
30 #include <ac/socket.h>
31 
32 #include "slap.h"
33 
34 int
do_abandon(Operation * op,SlapReply * rs)35 do_abandon( Operation *op, SlapReply *rs )
36 {
37 	ber_int_t	id;
38 	Operation	*o;
39 	const char	*msg;
40 
41 	Debug( LDAP_DEBUG_TRACE, "%s do_abandon\n",
42 		op->o_log_prefix );
43 
44 	/*
45 	 * Parse the abandon request.  It looks like this:
46 	 *
47 	 *	AbandonRequest := MessageID
48 	 */
49 
50 	if ( ber_scanf( op->o_ber, "i", &id ) == LBER_ERROR ) {
51 		Debug( LDAP_DEBUG_ANY, "%s do_abandon: ber_scanf failed\n",
52 			op->o_log_prefix );
53 		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
54 		return SLAPD_DISCONNECT;
55 	}
56 
57 	Debug( LDAP_DEBUG_STATS, "%s ABANDON msg=%ld\n",
58 		op->o_log_prefix, (long) id );
59 
60 	if( get_ctrls( op, rs, 0 ) != LDAP_SUCCESS ) {
61 		Debug( LDAP_DEBUG_ANY, "%s do_abandon: get_ctrls failed\n",
62 			op->o_log_prefix );
63 		return rs->sr_err;
64 	}
65 
66 	Debug( LDAP_DEBUG_ARGS, "%s do_abandon: id=%ld\n",
67 		op->o_log_prefix, (long) id );
68 
69 	if( id <= 0 ) {
70 		Debug( LDAP_DEBUG_ANY, "%s do_abandon: bad msgid %ld\n",
71 			op->o_log_prefix, (long) id );
72 		return LDAP_SUCCESS;
73 	}
74 
75 	ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
76 
77 	/* Find the operation being abandoned. */
78 	LDAP_STAILQ_FOREACH( o, &op->o_conn->c_ops, o_next ) {
79 		if ( o->o_msgid == id ) {
80 			break;
81 		}
82 	}
83 
84 	if ( o == NULL ) {
85 		msg = "not found";
86 		/* The operation is not active. Just discard it if found.  */
87 		LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) {
88 			if ( o->o_msgid == id ) {
89 				msg = "discarded";
90 				/* FIXME: This traverses c_pending_ops yet again. */
91 				LDAP_STAILQ_REMOVE( &op->o_conn->c_pending_ops,
92 					o, Operation, o_next );
93 				LDAP_STAILQ_NEXT(o, o_next) = NULL;
94 				op->o_conn->c_n_ops_pending--;
95 				slap_op_free( o, NULL );
96 				break;
97 			}
98 		}
99 
100 	} else if ( o->o_tag == LDAP_REQ_BIND
101 			|| o->o_tag == LDAP_REQ_UNBIND
102 			|| o->o_tag == LDAP_REQ_ABANDON ) {
103 		msg = "cannot be abandoned";
104 
105 #if 0 /* Would break o_abandon used as "suppress response" flag, ITS#6138 */
106 	} else if ( o->o_abandon ) {
107 		msg = "already being abandoned";
108 #endif
109 
110 	} else {
111 		msg = "found";
112 		/* Set the o_abandon flag in the to-be-abandoned operation.
113 		 * The backend can periodically check this flag and abort the
114 		 * operation at a convenient time.  However it should "send"
115 		 * the response anyway, with result code SLAPD_ABANDON.
116 		 * The functions in result.c will intercept the message.
117 		 */
118 		o->o_abandon = 1;
119 		op->orn_msgid = id;
120 		op->o_bd = frontendDB;
121 		rs->sr_err = frontendDB->be_abandon( op, rs );
122 	}
123 
124 	ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
125 
126 	Debug( LDAP_DEBUG_TRACE, "%s do_abandon: op=%ld %s\n",
127 		op->o_log_prefix, (long) id, msg );
128 	return rs->sr_err;
129 }
130 
131 int
fe_op_abandon(Operation * op,SlapReply * rs)132 fe_op_abandon( Operation *op, SlapReply *rs )
133 {
134 	LDAP_STAILQ_FOREACH( op->o_bd, &backendDB, be_next ) {
135 		if ( op->o_bd->be_abandon ) {
136 			(void)op->o_bd->be_abandon( op, rs );
137 		}
138 	}
139 
140 	return LDAP_SUCCESS;
141 }
142