1/* $NetBSD$ */ 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 33const struct berval slap_EXOP_TXN_START = BER_BVC(LDAP_EXOP_X_TXN_START); 34const struct berval slap_EXOP_TXN_END = BER_BVC(LDAP_EXOP_X_TXN_END); 35 36int 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 76done: 77 /* release connection lock */ 78 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 79 return rc; 80} 81 82int 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 116int 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 203drain: 204 /* drain txn ops list */ 205 206settled: 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 212done: 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