1 /* $NetBSD: modify.c,v 1.1.1.4 2014/05/28 09:58:51 tron Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2014 The OpenLDAP Foundation. 7 * Portions Copyright 1999 Dmitry Kovalev. 8 * Portions Copyright 2002 Pierangelo Masarati. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 /* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Dmitry Kovalev for inclusion 21 * by OpenLDAP Software. Additional significant contributors include 22 * Pierangelo Masarati. 23 */ 24 25 #include "portable.h" 26 27 #include <stdio.h> 28 #include <sys/types.h> 29 #include "ac/string.h" 30 31 #include "slap.h" 32 #include "proto-sql.h" 33 34 int 35 backsql_modify( Operation *op, SlapReply *rs ) 36 { 37 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 38 SQLHDBC dbh = SQL_NULL_HDBC; 39 backsql_oc_map_rec *oc = NULL; 40 backsql_srch_info bsi = { 0 }; 41 Entry m = { 0 }, *e = NULL; 42 int manageDSAit = get_manageDSAit( op ); 43 SQLUSMALLINT CompletionType = SQL_ROLLBACK; 44 45 /* 46 * FIXME: in case part of the operation cannot be performed 47 * (missing mapping, SQL write fails or so) the entire operation 48 * should be rolled-back 49 */ 50 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): modifying entry \"%s\"\n", 51 op->o_req_ndn.bv_val, 0, 0 ); 52 53 rs->sr_err = backsql_get_db_conn( op, &dbh ); 54 if ( rs->sr_err != LDAP_SUCCESS ) { 55 Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " 56 "could not get connection handle - exiting\n", 57 0, 0, 0 ); 58 /* 59 * FIXME: we don't want to send back 60 * excessively detailed messages 61 */ 62 rs->sr_text = ( rs->sr_err == LDAP_OTHER ) 63 ? "SQL-backend error" : NULL; 64 goto done; 65 } 66 67 bsi.bsi_e = &m; 68 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, 69 LDAP_SCOPE_BASE, 70 (time_t)(-1), NULL, dbh, op, rs, 71 slap_anlist_all_attributes, 72 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); 73 switch ( rs->sr_err ) { 74 case LDAP_SUCCESS: 75 break; 76 77 case LDAP_REFERRAL: 78 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && 79 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) 80 { 81 rs->sr_err = LDAP_SUCCESS; 82 rs->sr_text = NULL; 83 rs->sr_matched = NULL; 84 if ( rs->sr_ref ) { 85 ber_bvarray_free( rs->sr_ref ); 86 rs->sr_ref = NULL; 87 } 88 break; 89 } 90 e = &m; 91 /* fallthru */ 92 93 default: 94 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): " 95 "could not retrieve modifyDN ID - no such entry\n", 96 0, 0, 0 ); 97 if ( !BER_BVISNULL( &m.e_nname ) ) { 98 /* FIXME: should always be true! */ 99 e = &m; 100 101 } else { 102 e = NULL; 103 } 104 goto done; 105 } 106 107 Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " 108 "modifying entry \"%s\" (id=" BACKSQL_IDFMT ")\n", 109 bsi.bsi_base_id.eid_dn.bv_val, 110 BACKSQL_IDARG(bsi.bsi_base_id.eid_id), 0 ); 111 112 if ( get_assert( op ) && 113 ( test_filter( op, &m, get_assertion( op ) ) 114 != LDAP_COMPARE_TRUE )) 115 { 116 rs->sr_err = LDAP_ASSERTION_FAILED; 117 e = &m; 118 goto done; 119 } 120 121 slap_mods_opattrs( op, &op->orm_modlist, 1 ); 122 123 assert( bsi.bsi_base_id.eid_oc != NULL ); 124 oc = bsi.bsi_base_id.eid_oc; 125 126 if ( !acl_check_modlist( op, &m, op->orm_modlist ) ) { 127 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 128 e = &m; 129 goto done; 130 } 131 132 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, 133 &bsi.bsi_base_id, op->orm_modlist ); 134 if ( rs->sr_err != LDAP_SUCCESS ) { 135 e = &m; 136 goto do_transact; 137 } 138 139 if ( BACKSQL_CHECK_SCHEMA( bi ) ) { 140 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 141 142 backsql_entry_clean( op, &m ); 143 144 bsi.bsi_e = &m; 145 rs->sr_err = backsql_id2entry( &bsi, &bsi.bsi_base_id ); 146 if ( rs->sr_err != LDAP_SUCCESS ) { 147 e = &m; 148 goto do_transact; 149 } 150 151 rs->sr_err = entry_schema_check( op, &m, NULL, 0, 0, NULL, 152 &rs->sr_text, textbuf, sizeof( textbuf ) ); 153 if ( rs->sr_err != LDAP_SUCCESS ) { 154 Debug( LDAP_DEBUG_TRACE, " backsql_modify(\"%s\"): " 155 "entry failed schema check -- aborting\n", 156 m.e_name.bv_val, 0, 0 ); 157 e = NULL; 158 goto do_transact; 159 } 160 } 161 162 do_transact:; 163 /* 164 * Commit only if all operations succeed 165 */ 166 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { 167 assert( e == NULL ); 168 CompletionType = SQL_COMMIT; 169 } 170 171 SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); 172 173 done:; 174 if ( e != NULL ) { 175 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, 176 ACL_DISCLOSE, NULL ) ) 177 { 178 rs->sr_err = LDAP_NO_SUCH_OBJECT; 179 rs->sr_text = NULL; 180 rs->sr_matched = NULL; 181 if ( rs->sr_ref ) { 182 ber_bvarray_free( rs->sr_ref ); 183 rs->sr_ref = NULL; 184 } 185 } 186 } 187 188 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { 189 rs->sr_err = LDAP_X_NO_OPERATION; 190 } 191 192 send_ldap_result( op, rs ); 193 slap_graduate_commit_csn( op ); 194 195 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { 196 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 197 } 198 199 if ( !BER_BVISNULL( &m.e_nname ) ) { 200 backsql_entry_clean( op, &m ); 201 } 202 203 if ( bsi.bsi_attrs != NULL ) { 204 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); 205 } 206 207 if ( rs->sr_ref ) { 208 ber_bvarray_free( rs->sr_ref ); 209 rs->sr_ref = NULL; 210 } 211 212 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 ); 213 214 return rs->sr_err; 215 } 216 217