]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/modrdn.c
Added provisions for a layer between the backend and the ODBC
[openldap] / servers / slapd / back-sql / modrdn.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2004 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
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 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Dmitry Kovalev for inclusion
18  * by OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #ifdef SLAPD_SQL
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include "ac/string.h"
28
29 #include "slap.h"
30 #include "ldap_pvt.h"
31 #include "proto-sql.h"
32
33 int
34 backsql_modrdn( Operation *op, SlapReply *rs )
35 {
36         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
37         SQLHDBC                 dbh;
38         SQLHSTMT                sth;
39         RETCODE                 rc;
40         backsql_entryID         e_id = BACKSQL_ENTRYID_INIT,
41                                 pe_id = BACKSQL_ENTRYID_INIT,
42                                 new_pid = BACKSQL_ENTRYID_INIT;
43         backsql_oc_map_rec      *oc = NULL;
44         struct berval           p_dn, p_ndn,
45                                 *new_pdn = NULL, *new_npdn = NULL,
46                                 new_dn, new_ndn;
47         LDAPRDN                 new_rdn = NULL;
48         LDAPRDN                 old_rdn = NULL;
49         Entry                   e;
50         Modifications           *mod;
51         struct berval           *newSuperior = op->oq_modrdn.rs_newSup;
52  
53         Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", "
54                         "newrdn=\"%s\", newSuperior=\"%s\"\n",
55                         op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val, 
56                         newSuperior ? newSuperior->bv_val : "(NULL)" );
57         rs->sr_err = backsql_get_db_conn( op, &dbh );
58         if ( rs->sr_err != LDAP_SUCCESS ) {
59                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
60                         "could not get connection handle - exiting\n", 
61                         0, 0, 0 );
62                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
63                         ?  "SQL-backend error" : NULL;
64                 send_ldap_result( op, rs );
65                 return 1;
66         }
67
68         rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn );
69         if ( rs->sr_err != LDAP_SUCCESS ) {
70                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
71                         "could not lookup entry id\n", 0, 0, 0 );
72                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
73                         ?  "SQL-backend error" : NULL;
74                 send_ldap_result( op, rs );
75                 return 1;
76         }
77
78 #ifdef BACKSQL_ARBITRARY_KEY
79         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): entry id=%s\n",
80                 e_id.eid_id.bv_val, 0, 0 );
81 #else /* ! BACKSQL_ARBITRARY_KEY */
82         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): entry id=%ld\n",
83                 e_id.eid_id, 0, 0 );
84 #endif /* ! BACKSQL_ARBITRARY_KEY */
85
86         if ( backsql_has_children( bi, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) {
87                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
88                         "entry \"%s\" has children\n",
89                         op->o_req_dn.bv_val, 0, 0 );
90                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
91                 rs->sr_text = "subtree rename not supported";
92                 send_ldap_result( op, rs );
93                 return 1;
94         }
95
96         dnParent( &op->o_req_dn, &p_dn );
97         dnParent( &op->o_req_ndn, &p_ndn );
98
99         /*
100          * namingContext "" is not supported
101          */
102         if ( p_dn.bv_len == 0 ) {
103                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
104                         "parent is \"\" - aborting\n", 0, 0, 0 );
105                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
106                 rs->sr_text = "not allowed within namingContext";
107                 send_ldap_result( op, rs );
108                 goto modrdn_return;
109         }
110
111         /*
112          * Check for children access to parent
113          */
114         e.e_attrs = NULL;
115         e.e_name = p_dn;
116         e.e_nname = p_ndn;
117         if ( !access_allowed( op, &e, slap_schema.si_ad_children, 
118                                 NULL, ACL_WRITE, NULL ) ) {
119                 Debug( LDAP_DEBUG_TRACE, "   no access to parent\n", 0, 0, 0 );
120                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
121                 goto modrdn_return;
122         }
123
124         if ( newSuperior ) {
125                 /*
126                  * namingContext "" is not supported
127                  */
128                 if ( newSuperior->bv_len == 0 ) {
129                         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
130                                 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
131                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
132                         rs->sr_text = "not allowed within namingContext";
133                         send_ldap_result( op, rs );
134                         goto modrdn_return;
135                 }
136
137                 new_pdn = newSuperior;
138                 new_npdn = op->oq_modrdn.rs_nnewSup;
139
140                 e.e_name = *new_pdn;
141                 e.e_nname = *new_npdn;
142
143                 /*
144                  * Check for children access to new parent
145                  */
146                 if ( !access_allowed( op, &e, slap_schema.si_ad_children, 
147                                         NULL, ACL_WRITE, NULL ) ) {
148                         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
149                                         "no access to new parent \"%s\"\n", 
150                                         new_pdn->bv_val, 0, 0 );
151                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
152                         goto modrdn_return;
153                 }
154
155         } else {
156                 new_pdn = &p_dn;
157                 new_npdn = &p_ndn;
158         }
159
160         if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
161                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
162                         "newSuperior is equal to old parent - ignored\n",
163                         0, 0, 0 );
164                 newSuperior = NULL;
165         }
166
167         if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) {
168                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
169                         "newSuperior is equal to entry being moved "
170                         "- aborting\n", 0, 0, 0 );
171                 rs->sr_err = LDAP_OTHER;
172                 rs->sr_text = "newSuperior is equal to old DN";
173                 send_ldap_result( op, rs );
174                 goto modrdn_return;
175         }
176
177         build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, NULL );
178         rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn,
179                 op->o_tmpmemctx );
180         if ( rs->sr_err != LDAP_SUCCESS ) {
181                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
182                         "new dn is invalid (\"%s\") - aborting\n",
183                         new_dn.bv_val, 0, 0 );
184                 rs->sr_text = "unable to build new DN";
185                 send_ldap_result( op, rs );
186                 goto modrdn_return;
187         }
188         
189         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): new entry dn is \"%s\"\n",
190                         new_dn.bv_val, 0, 0 );
191
192         rs->sr_err = backsql_dn2id( bi, &pe_id, dbh, &p_ndn );
193         if ( rs->sr_err != LDAP_SUCCESS ) {
194                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
195                         "could not lookup old parent entry id\n", 0, 0, 0 );
196                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
197                         ? "SQL-backend error" : NULL;
198                 send_ldap_result( op, rs );
199                 goto modrdn_return;
200         }
201
202 #ifdef BACKSQL_ARBITRARY_KEY
203         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
204                 "old parent entry id is %s\n", pe_id.eid_id.bv_val, 0, 0 );
205 #else /* ! BACKSQL_ARBITRARY_KEY */
206         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
207                 "old parent entry id is %ld\n", pe_id.eid_id, 0, 0 );
208 #endif /* ! BACKSQL_ARBITRARY_KEY */
209
210         backsql_free_entryID( &pe_id, 0 );
211
212         rs->sr_err = backsql_dn2id( bi, &new_pid, dbh, new_npdn );
213         if ( rs->sr_err != LDAP_SUCCESS ) {
214                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
215                         "could not lookup new parent entry id\n", 0, 0, 0 );
216                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
217                         ? "SQL-backend error" : NULL;
218                 send_ldap_result( op, rs );
219                 goto modrdn_return;
220         }
221
222 #ifdef BACKSQL_ARBITRARY_KEY
223         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
224                 "new parent entry id=%s\n", new_pid.eid_id.bv_val, 0, 0 );
225 #else /* ! BACKSQL_ARBITRARY_KEY */
226         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
227                 "new parent entry id=%ld\n", new_pid.eid_id, 0, 0 );
228 #endif /* ! BACKSQL_ARBITRARY_KEY */
229
230  
231         Debug(  LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
232                 "executing delentry_query\n", 0, 0, 0 );
233         SQLAllocStmt( dbh, &sth );
234 #ifdef BACKSQL_ARBITRARY_KEY
235         SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
236                         0, 0, e_id.eid_id.bv_val, 0, 0 );
237 #else /* ! BACKSQL_ARBITRARY_KEY */
238         SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
239                         0, 0, &e_id.eid_id, 0, 0 );
240 #endif /* ! BACKSQL_ARBITRARY_KEY */
241         rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
242         if ( rc != SQL_SUCCESS ) {
243                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
244                         "failed to delete record from ldap_entries\n",
245                         0, 0, 0 );
246                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
247                 rs->sr_err = LDAP_OTHER;
248                 rs->sr_text = "SQL-backend error";
249                 send_ldap_result( op, rs );
250                 goto modrdn_return;
251         }
252
253         SQLFreeStmt( sth, SQL_RESET_PARAMS );
254
255         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
256                 "executing insentry_query\n", 0, 0, 0 );
257         backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN );
258         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
259                         0, 0, &e_id.eid_oc_id, 0, 0 );
260 #ifdef BACKSQL_ARBITRARY_KEY
261         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
262                         0, 0, new_pid.eid_id.bv_val, 0, 0 );
263         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
264                         0, 0, e_id.eid_keyval.bv_val, 0, 0 );
265 #else /* ! BACKSQL_ARBITRARY_KEY */
266         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
267                         0, 0, &new_pid.eid_id, 0, 0 );
268         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
269                         0, 0, &e_id.eid_keyval, 0, 0 );
270 #endif /* ! BACKSQL_ARBITRARY_KEY */
271         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
272         if ( rc != SQL_SUCCESS ) {
273                 Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
274                         "could not insert ldap_entries record\n", 0, 0, 0 );
275                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
276                 rs->sr_err = LDAP_OTHER;
277                 rs->sr_text = "SQL-backend error";
278                 send_ldap_result( op, rs );
279                 goto modrdn_return;
280         }
281
282         /*
283          * Get attribute type and attribute value of our new rdn,
284          * we will need to add that to our new entry
285          */
286         if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn,
287                                 (char **)&rs->sr_text, 
288                                 LDAP_DN_FORMAT_LDAP ) ) {
289 #ifdef NEW_LOGGING
290                 LDAP_LOG ( OPERATION, ERR, 
291                         "   backsql_modrdn: can't figure out "
292                         "type(s)/values(s) of newrdn\n", 
293                         0, 0, 0 );
294 #else
295                 Debug( LDAP_DEBUG_TRACE,
296                         "   backsql_modrdn: can't figure out "
297                         "type(s)/values(s) of newrdn\n", 
298                         0, 0, 0 );
299 #endif
300                 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
301                 goto modrdn_return;
302         }
303
304 #ifdef NEW_LOGGING
305         LDAP_LOG ( OPERATION, RESULTS, 
306                 "   backsql_modrdn: new_rdn_type=\"%s\", "
307                 "new_rdn_val=\"%s\"\n",
308                 new_rdn[ 0 ]->la_attr.bv_val, 
309                 new_rdn[ 0 ]->la_value.bv_val, 0 );
310 #else
311         Debug( LDAP_DEBUG_TRACE,
312                 "   backsql_modrdn: new_rdn_type=\"%s\", "
313                 "new_rdn_val=\"%s\"\n",
314                 new_rdn[ 0 ]->la_attr.bv_val,
315                 new_rdn[ 0 ]->la_value.bv_val, 0 );
316 #endif
317
318         if ( op->oq_modrdn.rs_deleteoldrdn ) {
319                 if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn,
320                                         (char **)&rs->sr_text,
321                                         LDAP_DN_FORMAT_LDAP ) ) {
322 #ifdef NEW_LOGGING
323                         LDAP_LOG ( OPERATION, ERR, 
324                                 "   backsql_modrdn: can't figure out "
325                                 "type(s)/values(s) of old_rdn\n", 
326                                 0, 0, 0 );
327 #else
328                         Debug( LDAP_DEBUG_TRACE,
329                                 "   backsql_modrdn: can't figure out "
330                                 "the old_rdn type(s)/value(s)\n", 
331                                 0, 0, 0 );
332 #endif
333                         rs->sr_err = LDAP_OTHER;
334                         goto modrdn_return;             
335                 }
336         }
337
338         e.e_name = new_dn;
339         e.e_nname = new_ndn;
340         rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod );
341         if ( rs->sr_err != LDAP_SUCCESS ) {
342                 goto modrdn_return;
343         }
344
345         if ( !acl_check_modlist( op, &e, mod )) {
346                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
347                 goto modrdn_return;
348         }
349
350         oc = backsql_id2oc( bi, e_id.eid_oc_id );
351         rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod );
352
353         if ( rs->sr_err == LDAP_SUCCESS ) {
354
355                 /*
356                  * Commit only if all operations succeed
357                  */
358                 SQLTransact( SQL_NULL_HENV, dbh,
359                                 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
360         }
361
362 modrdn_return:
363         SQLFreeStmt( sth, SQL_DROP );
364
365         if ( new_dn.bv_val ) {
366                 ch_free( new_dn.bv_val );
367         }
368         
369         if ( new_ndn.bv_val ) {
370                 ch_free( new_ndn.bv_val );
371         }
372         
373         /* LDAP v2 supporting correct attribute handling. */
374         if ( new_rdn != NULL ) {
375                 ldap_rdnfree( new_rdn );
376         }
377         if ( old_rdn != NULL ) {
378                 ldap_rdnfree( old_rdn );
379         }
380         if ( mod != NULL ) {
381                 Modifications *tmp;
382                 for (; mod; mod=tmp ) {
383                         tmp = mod->sml_next;
384                         free( mod );
385                 }
386         }
387
388         if ( new_pid.eid_dn.bv_val ) {
389                 backsql_free_entryID( &pe_id, 0 );
390         }
391
392         send_ldap_result( op, rs );
393
394         Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
395         return op->o_noop;
396 }
397
398 #endif /* SLAPD_SQL */
399