]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/modify.c
Fix maxDeref directive
[openldap] / servers / slapd / back-bdb2 / modify.c
1 /* modify.c - bdb2 backend modify routine */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/string.h>
8 #include <ac/socket.h>
9
10 #include "slap.h"
11 #include "back-bdb2.h"
12 #include "proto-back-bdb2.h"
13
14
15 static void     add_lastmods(Operation *op, LDAPModList **ml);
16
17
18 static void
19 add_lastmods( Operation *op, LDAPModList **modlist )
20 {
21         char            buf[22];
22         struct berval   bv;
23         struct berval   *bvals[2];
24         LDAPModList             **m;
25         LDAPModList             *tmp;
26         struct tm       *ltm;
27         time_t          currenttime;
28
29         Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
30
31         bvals[0] = &bv;
32         bvals[1] = NULL;
33
34         /* remove any attempts by the user to modify these attrs */
35         for ( m = modlist; *m != NULL; m = &(*m)->ml_next ) {
36             if ( oc_check_no_usermod_attr( (*m)->ml_type ) ) {
37                 Debug( LDAP_DEBUG_TRACE,
38                                         "add_lastmods: found no user mod attr: %s\n",
39                                         (*m)->ml_type, 0, 0 );
40                 tmp = *m;
41                 *m = (*m)->ml_next;
42                 free( tmp->ml_type );
43                 if ( tmp->ml_bvalues != NULL ) {
44                     ber_bvecfree( tmp->ml_bvalues );
45                 }
46                 free( tmp );
47                 if (!*m)
48                     break;
49             }
50         }
51
52         if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
53                 bv.bv_val = "NULLDN";
54                 bv.bv_len = strlen( bv.bv_val );
55         } else {
56                 bv.bv_val = op->o_dn;
57                 bv.bv_len = strlen( bv.bv_val );
58         }
59         tmp = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
60         tmp->ml_type = ch_strdup( "modifiersname" );
61         tmp->ml_op = LDAP_MOD_REPLACE;
62         tmp->ml_bvalues = (struct berval **) ch_calloc(2, sizeof(struct berval *));
63         tmp->ml_bvalues[0] = ber_bvdup( &bv );
64         tmp->ml_next = *modlist;
65         *modlist = tmp;
66
67         currenttime = slap_get_time();
68         ldap_pvt_thread_mutex_lock( &gmtime_mutex );
69 #ifndef LDAP_LOCALTIME
70         ltm = gmtime( &currenttime );
71         strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
72 #else
73         ltm = localtime( &currenttime );
74         strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
75 #endif
76         ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
77
78         bv.bv_val = buf;
79         bv.bv_len = strlen( bv.bv_val );
80         tmp = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
81         tmp->ml_type = ch_strdup( "modifytimestamp" );
82         tmp->ml_op = LDAP_MOD_REPLACE;
83         tmp->ml_bvalues = (struct berval **) ch_calloc(2, sizeof(struct berval *));
84         tmp->ml_bvalues[0] = ber_bvdup( &bv );
85         tmp->ml_next = *modlist;
86         *modlist = tmp;
87
88 }
89
90 int
91 bdb2i_back_modify_internal(
92     BackendDB   *be,
93     Connection  *conn,
94     Operation   *op,
95     char        *dn,
96     LDAPModList *modlist,
97     Entry        *e
98 )
99 {
100         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
101         LDAPModList     *ml;
102         int             err;
103
104         Debug(LDAP_DEBUG_ARGS, "bdb2i_back_modify:\n", 0, 0, 0);
105
106         if ( (err = acl_check_modlist( be, conn, op, e, modlist )) != LDAP_SUCCESS ) {
107                 send_ldap_result( conn, op, err,
108                         NULL, NULL, NULL, NULL );
109                 goto error_return;
110         }
111
112         for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
113                 LDAPMod *mod = &ml->ml_mod;
114
115                 switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
116                 case LDAP_MOD_ADD:
117                         err = bdb2i_add_values( e, mod, op->o_ndn );
118                         break;
119
120                 case LDAP_MOD_DELETE:
121                         err = bdb2i_delete_values( e, mod, op->o_ndn );
122                         break;
123
124                 case LDAP_MOD_REPLACE:
125                         err = bdb2i_replace_values( e, mod, op->o_ndn );
126                         break;
127                 
128                 case LDAP_MOD_SOFTADD:
129                         /* Avoid problems in index_add_mods()
130                          * We need to add index if necessary.
131                          */
132                         mod->mod_op = LDAP_MOD_ADD;
133                         if ( (err = bdb2i_add_values( e, mod, op->o_ndn ))
134                                 ==  LDAP_TYPE_OR_VALUE_EXISTS ) {
135  
136                                 err = LDAP_SUCCESS;
137                                 mod->mod_op = LDAP_MOD_SOFTADD;
138  
139                         }
140                         break;
141                 }
142
143                 if ( err != LDAP_SUCCESS ) {
144                         /* unlock entry, delete from cache */
145                         send_ldap_result( conn, op, err,
146                                 NULL, NULL, NULL, NULL );
147                         goto error_return;
148                 }
149         }
150
151         /* check that the entry still obeys the schema */
152         if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
153                 Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
154                 send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
155                         NULL, NULL, NULL, NULL );
156                 goto error_return;
157         }
158
159         /* check for abandon */
160         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
161         if ( op->o_abandon ) {
162                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
163                 goto error_return;
164         }
165         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
166
167         /* modify indexes */
168         if ( bdb2i_index_add_mods( be, modlist, e->e_id ) != 0 ) {
169                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
170                         NULL, NULL, NULL, NULL );
171                 goto error_return;
172         }
173
174         /* check for abandon */
175         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
176         if ( op->o_abandon ) {
177                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
178                 goto error_return;
179         }
180         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
181
182         /* change the entry itself */
183         if ( bdb2i_id2entry_add( be, e ) != 0 ) {
184                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
185                         NULL, NULL, NULL, NULL );
186                 goto error_return;
187         }
188
189         send_ldap_result( conn, op, LDAP_SUCCESS,
190                 NULL, NULL, NULL, NULL );
191         return( 0 );
192
193 error_return:;
194         return( -1 );
195 }
196
197
198 int
199 bdb2_back_modify(
200     BackendDB   *be,
201     Connection  *conn,
202     Operation   *op,
203     char        *dn,
204     LDAPModList *modlist
205 )
206 {
207         DB_LOCK         lock;
208         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
209         struct timeval  time1;
210         int             ret, manageDSAit;
211         Entry           *matched;
212         Entry           *e;
213
214         bdb2i_start_timing( be->bd_info, &time1 );
215
216         if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
217                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
218                         NULL, NULL, NULL, NULL );
219                 return( -1 );
220         }
221
222         /*  check, if a new default attribute index will be created,
223                 in which case we have to open the index file BEFORE TP  */
224         switch ( slapMode ) {
225                 case SLAP_SERVER_MODE:
226                 case SLAP_TIMEDSERVER_MODE:
227                 case SLAP_TOOL_MODE:
228                 case SLAP_TOOLID_MODE:
229                         bdb2i_check_default_attr_index_mod( li, modlist );
230                         break;
231         }
232
233         if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
234                 char *matched_dn = NULL;
235                 struct berval **refs = NULL;
236
237                 if ( matched != NULL ) {
238                         matched_dn = ch_strdup( matched->e_dn );
239                         refs = is_entry_referral( matched )
240                                 ? get_entry_referrals( be, conn, op, matched )
241                                 : NULL;
242                         bdb2i_cache_return_entry_r( &li->li_cache, matched );
243                 } else {
244                         refs = default_referral;
245                 }
246
247                 send_ldap_result( conn, op, LDAP_REFERRAL,
248                         matched_dn, NULL, refs, NULL );
249
250                 if( matched != NULL ) {
251                         ber_bvecfree( refs );
252                         free( matched_dn );
253                 }
254
255                 ret = -1;
256                 goto done;
257         }
258
259         if (!manageDSAit && is_entry_referral( e ) ) {
260                 /* entry is a referral, don't allow add */
261                 struct berval **refs = get_entry_referrals( be,
262                         conn, op, e );
263
264                 Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
265                         0, 0 );
266
267                 send_ldap_result( conn, op, LDAP_REFERRAL,
268                         e->e_dn, NULL, refs, NULL );
269
270                 bdb2i_cache_return_entry_w( &li->li_cache, e );
271
272                 ber_bvecfree( refs );
273
274                 ret = -1;
275                 goto done;
276         }
277
278         ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist, e );
279         bdb2i_cache_return_entry_w( &li->li_cache, e );
280
281 done:
282         (void) bdb2i_leave_backend_w( lock );
283         bdb2i_stop_timing( be->bd_info, time1, "MOD", conn, op );
284
285         return( ret );
286 }
287
288
289 int
290 bdb2i_add_values(
291     Entry       *e,
292     LDAPMod     *mod,
293     char        *dn
294 )
295 {
296         int             i;
297         Attribute       *a;
298
299         /* check if the values we're adding already exist */
300         if ( (a = attr_find( e->e_attrs, mod->mod_type )) != NULL ) {
301                 for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
302                         if ( value_find( a->a_vals, mod->mod_bvalues[i],
303                             a->a_syntax, 3 ) == 0 ) {
304                                 return( LDAP_TYPE_OR_VALUE_EXISTS );
305                         }
306                 }
307         }
308
309         /* no - add them */
310         if( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
311                 return( LDAP_CONSTRAINT_VIOLATION );
312         }
313
314         return( LDAP_SUCCESS );
315 }
316
317 int
318 bdb2i_delete_values(
319     Entry       *e,
320     LDAPMod     *mod,
321     char        *dn
322 )
323 {
324         int             i, j, k, found;
325         Attribute       *a;
326
327         /* delete the entire attribute */
328         if ( mod->mod_bvalues == NULL ) {
329                 Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
330                     mod->mod_type, 0, 0 );
331                 return( attr_delete( &e->e_attrs, mod->mod_type ) ?
332                     LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
333         }
334
335         /* delete specific values - find the attribute first */
336         if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) {
337                 Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n",
338                     mod->mod_type, 0, 0 );
339                 return( LDAP_NO_SUCH_ATTRIBUTE );
340         }
341
342         /* find each value to delete */
343         for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
344                 found = 0;
345                 for ( j = 0; a->a_vals[j] != NULL; j++ ) {
346                         if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j],
347                             a->a_syntax, 3 ) != 0 ) {
348                                 continue;
349                         }
350                         found = 1;
351
352                         /* found a matching value - delete it */
353                         ber_bvfree( a->a_vals[j] );
354                         for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
355                                 a->a_vals[k - 1] = a->a_vals[k];
356                         }
357                         a->a_vals[k - 1] = NULL;
358
359                         /* delete the entire attribute, if no values remain */
360                         if ( a->a_vals[0] == NULL) {
361                                 Debug( LDAP_DEBUG_ARGS,
362                                         "removing entire attribute %s\n",
363                                         mod->mod_type, 0, 0 );
364                                 if ( attr_delete( &e->e_attrs, mod->mod_type ) ) {
365                                         return LDAP_NO_SUCH_ATTRIBUTE;
366                                 }
367                         }
368
369                         break;
370                 }
371
372                 /* looked through them all w/o finding it */
373                 if ( ! found ) {
374                         Debug( LDAP_DEBUG_ARGS,
375                             "could not find value for attr %s\n",
376                             mod->mod_type, 0, 0 );
377                         return( LDAP_NO_SUCH_ATTRIBUTE );
378                 }
379         }
380
381         return( LDAP_SUCCESS );
382 }
383
384 int
385 bdb2i_replace_values(
386     Entry       *e,
387     LDAPMod     *mod,
388     char        *dn
389 )
390 {
391         (void) attr_delete( &e->e_attrs, mod->mod_type );
392
393         if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
394                 return( LDAP_CONSTRAINT_VIOLATION );
395         }
396
397         return( LDAP_SUCCESS );
398 }