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 	} else if ( o->o_abandon ) {
106 		msg = "already being abandoned";
107 
108 	} else {
109 		msg = "found";
110 		/* Set the o_abandon flag in the to-be-abandoned operation.
111 		 * The backend can periodically check this flag and abort the
112 		 * operation at a convenient time.  However it should "send"
113 		 * the response anyway, with result code SLAPD_ABANDON.
114 		 * The functions in result.c will intercept the message.
115 		 */
116 		o->o_abandon = 1;
117 		op->orn_msgid = id;
118 		op->o_bd = frontendDB;
119 		rs->sr_err = frontendDB->be_abandon( op, rs );
120 	}
121 
122 	ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
123 
124 	Debug( LDAP_DEBUG_TRACE, "%s do_abandon: op=%ld %s\n",
125 		op->o_log_prefix, (long) id, msg );
126 	return rs->sr_err;
127 }
128 
129 int
fe_op_abandon(Operation * op,SlapReply * rs)130 fe_op_abandon( Operation *op, SlapReply *rs )
131 {
132 	LDAP_STAILQ_FOREACH( op->o_bd, &backendDB, be_next ) {
133 		if ( op->o_bd->be_abandon ) {
134 			(void)op->o_bd->be_abandon( op, rs );
135 		}
136 	}
137 
138 	return LDAP_SUCCESS;
139 }
140