xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/txn.c (revision 4fee23f98c45552038ad6b5bd05124a41302fb01)
1 /*	$NetBSD: txn.c,v 1.1.1.3 2010/12/12 15:22:52 adam Exp $	*/
2 
3 /* txn.c - LDAP Transactions */
4 /* OpenLDAP: pkg/ldap/servers/slapd/txn.c,v 1.6.2.5 2010/04/13 20:23:22 kurt Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2010 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 
19 #include "portable.h"
20 
21 #include <stdio.h>
22 
23 #include <ac/socket.h>
24 #include <ac/string.h>
25 #include <ac/unistd.h>
26 
27 #include "slap.h"
28 
29 #include <lber_pvt.h>
30 #include <lutil.h>
31 
32 #ifdef LDAP_X_TXN
33 const struct berval slap_EXOP_TXN_START = BER_BVC(LDAP_EXOP_X_TXN_START);
34 const struct berval slap_EXOP_TXN_END = BER_BVC(LDAP_EXOP_X_TXN_END);
35 
36 int txn_start_extop(
37 	Operation *op, SlapReply *rs )
38 {
39 	int rc;
40 	struct berval *bv;
41 
42 	Statslog( LDAP_DEBUG_STATS, "%s TXN START\n",
43 		op->o_log_prefix, 0, 0, 0, 0 );
44 
45 	if( op->ore_reqdata != NULL ) {
46 		rs->sr_text = "no request data expected";
47 		return LDAP_PROTOCOL_ERROR;
48 	}
49 
50 	op->o_bd = op->o_conn->c_authz_backend;
51 	if( backend_check_restrictions( op, rs,
52 		(struct berval *)&slap_EXOP_TXN_START ) != LDAP_SUCCESS )
53 	{
54 		return rs->sr_err;
55 	}
56 
57 	/* acquire connection lock */
58 	ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
59 
60 	if( op->o_conn->c_txn != CONN_TXN_INACTIVE ) {
61 		rs->sr_text = "Too many transactions";
62 		rc = LDAP_BUSY;
63 		goto done;
64 	}
65 
66 	assert( op->o_conn->c_txn_backend == NULL );
67 	op->o_conn->c_txn = CONN_TXN_SPECIFY;
68 
69 	bv = (struct berval *) ch_malloc( sizeof (struct berval) );
70 	bv->bv_len = 0;
71 	bv->bv_val = NULL;
72 
73 	rs->sr_rspdata = bv;
74 	rc = LDAP_SUCCESS;
75 
76 done:
77 	/* release connection lock */
78 	ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
79 	return rc;
80 }
81 
82 int txn_spec_ctrl(
83 	Operation *op, SlapReply *rs, LDAPControl *ctrl )
84 {
85 	if ( !ctrl->ldctl_iscritical ) {
86 		rs->sr_text = "txnSpec control must be marked critical";
87 		return LDAP_PROTOCOL_ERROR;
88 	}
89 	if( op->o_txnSpec ) {
90 		rs->sr_text = "txnSpec control provided multiple times";
91 		return LDAP_PROTOCOL_ERROR;
92 	}
93 
94 	if ( ctrl->ldctl_value.bv_val == NULL ) {
95 		rs->sr_text = "no transaction identifier provided";
96 		return LDAP_PROTOCOL_ERROR;
97 	}
98 	if ( ctrl->ldctl_value.bv_len != 0 ) {
99 		rs->sr_text = "invalid transaction identifier";
100 		return LDAP_X_TXN_ID_INVALID;
101 	}
102 
103 	if ( op->o_preread ) { /* temporary limitation */
104 		rs->sr_text = "cannot perform pre-read in transaction";
105 		return LDAP_UNWILLING_TO_PERFORM;
106 	}
107 	if ( op->o_postread ) { /* temporary limitation */
108 		rs->sr_text = "cannot perform post-read in transaction";
109 		return LDAP_UNWILLING_TO_PERFORM;
110 	}
111 
112 	op->o_txnSpec = SLAP_CONTROL_CRITICAL;
113 	return LDAP_SUCCESS;
114 }
115 
116 int txn_end_extop(
117 	Operation *op, SlapReply *rs )
118 {
119 	int rc;
120 	BerElementBuffer berbuf;
121 	BerElement *ber = (BerElement *)&berbuf;
122 	ber_tag_t tag;
123 	ber_len_t len;
124 	ber_int_t commit=1;
125 	struct berval txnid;
126 
127 	Statslog( LDAP_DEBUG_STATS, "%s TXN END\n",
128 		op->o_log_prefix, 0, 0, 0, 0 );
129 
130 	if( op->ore_reqdata == NULL ) {
131 		rs->sr_text = "request data expected";
132 		return LDAP_PROTOCOL_ERROR;
133 	}
134 	if( op->ore_reqdata->bv_len == 0 ) {
135 		rs->sr_text = "empty request data";
136 		return LDAP_PROTOCOL_ERROR;
137 	}
138 
139 	op->o_bd = op->o_conn->c_authz_backend;
140 	if( backend_check_restrictions( op, rs,
141 		(struct berval *)&slap_EXOP_TXN_END ) != LDAP_SUCCESS )
142 	{
143 		return rs->sr_err;
144 	}
145 
146 	ber_init2( ber, op->ore_reqdata, 0 );
147 
148 	tag = ber_scanf( ber, "{" /*}*/ );
149 	if( tag == LBER_ERROR ) {
150 		rs->sr_text = "request data decoding error";
151 		return LDAP_PROTOCOL_ERROR;
152 	}
153 
154 	tag = ber_peek_tag( ber, &len );
155 	if( tag == LBER_BOOLEAN ) {
156 		tag = ber_scanf( ber, "b", &commit );
157 		if( tag == LBER_ERROR ) {
158 			rs->sr_text = "request data decoding error";
159 			return LDAP_PROTOCOL_ERROR;
160 		}
161 	}
162 
163 	tag = ber_scanf( ber, /*{*/ "m}", &txnid );
164 	if( tag == LBER_ERROR ) {
165 		rs->sr_text = "request data decoding error";
166 		return LDAP_PROTOCOL_ERROR;
167 	}
168 
169 	if( txnid.bv_len ) {
170 		rs->sr_text = "invalid transaction identifier";
171 		return LDAP_X_TXN_ID_INVALID;
172 	}
173 
174 	/* acquire connection lock */
175 	ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
176 
177 	if( op->o_conn->c_txn != CONN_TXN_SPECIFY ) {
178 		rs->sr_text = "invalid transaction identifier";
179 		rc = LDAP_X_TXN_ID_INVALID;
180 		goto done;
181 	}
182 	op->o_conn->c_txn = CONN_TXN_SETTLE;
183 
184 	if( commit ) {
185 		if ( op->o_abandon ) {
186 		}
187 
188 		if( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) ) {
189 			/* no updates to commit */
190 			rs->sr_text = "no updates to commit";
191 			rc = LDAP_OPERATIONS_ERROR;
192 			goto settled;
193 		}
194 
195 		rs->sr_text = "not yet implemented";
196 		rc = LDAP_UNWILLING_TO_PERFORM;
197 
198 	} else {
199 		rs->sr_text = "transaction aborted";
200 		rc = LDAP_SUCCESS;;
201 	}
202 
203 drain:
204 	/* drain txn ops list */
205 
206 settled:
207 	assert( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) );
208 	assert( op->o_conn->c_txn == CONN_TXN_SETTLE );
209 	op->o_conn->c_txn = CONN_TXN_INACTIVE;
210 	op->o_conn->c_txn_backend = NULL;
211 
212 done:
213 	/* release connection lock */
214 	ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
215 
216 	return rc;
217 }
218 
219 #endif /* LDAP_X_TXN */
220