]> git.sur5r.net Git - openldap/blob - servers/slapd/limits.c
More struct berval fixes for modrdn
[openldap] / servers / slapd / limits.c
1 /* limits.c - routines to handle regex-based size and time limits */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/regex.h>
12 #include <ac/string.h>
13
14 #include "slap.h"
15
16 int
17 get_limits( 
18         Backend                 *be, 
19         struct berval           *ndn, 
20         struct slap_limits_set  **limit
21 )
22 {
23         struct slap_limits **lm;
24
25         assert( be );
26         assert( limit );
27
28         /*
29          * default values
30          */
31         *limit = &be->be_def_limit;
32
33         if ( be->be_limits == NULL ) {
34                 return( 0 );
35         }
36
37         for ( lm = be->be_limits; lm[0] != NULL; lm++ ) {
38                 switch ( lm[0]->lm_type ) {
39                 case SLAP_LIMITS_EXACT:
40                         if ( ndn->bv_len == 0 ) {
41                                 break;
42                         }
43                         if ( strcmp( lm[0]->lm_dn_pat->bv_val, ndn->bv_val ) == 0 ) {
44                                 *limit = &lm[0]->lm_limits;
45                                 return( 0 );
46                         }
47                         break;
48
49                 case SLAP_LIMITS_ONE:
50                 case SLAP_LIMITS_SUBTREE:
51                 case SLAP_LIMITS_CHILDREN: {
52                         size_t d;
53                         
54                         if ( ndn->bv_len == 0 ) {
55                                 break;
56                         }
57
58                         d = ndn->bv_len - lm[0]->lm_dn_pat->bv_len;
59                         /* ndn shorter than dn_pat */
60                         if ( d < 0 ) {
61                                 break;
62                         }
63
64                         /* allow exact match for SUBTREE only */
65                         if ( d == 0 ) {
66                                 if ( lm[0]->lm_type != SLAP_LIMITS_SUBTREE ) {
67                                         break;
68                                 }
69                         } else {
70                                 /* check for unescaped rdn separator */
71                                 if ( !DN_SEPARATOR( ndn->bv_val[d-1] )
72                                         || DN_ESCAPE( ndn->bv_val[d-2] ) )
73                                 {
74                                         break;
75                                 }
76                         }
77
78                         /* in case of (sub)match ... */
79                         if ( strcmp( lm[0]->lm_dn_pat->bv_val, &ndn->bv_val[d] ) == 0 ) {
80                                 /* check for exactly one rdn in case of ONE */
81                                 if ( lm[0]->lm_type == SLAP_LIMITS_ONE ) {
82                                         /*
83                                          * if ndn is more that one rdn
84                                          * below dn_pat, continue
85                                          */
86                                         if ( (size_t) dn_rdnlen( NULL, ndn->bv_val ) != d - 1 ) {
87                                                 break;
88                                         }
89                                 }
90
91                                 *limit = &lm[0]->lm_limits;
92                                 return( 0 );
93                         }
94
95                         break;
96                 }
97
98                 case SLAP_LIMITS_REGEX:
99                         if ( ndn->bv_len == 0 ) {
100                                 break;
101                         }
102                         if ( regexec( &lm[0]->lm_dn_regex, ndn->bv_val, 0, NULL, 0 )
103                                 == 0 )
104                         {
105                                 *limit = &lm[0]->lm_limits;
106                                 return( 0 );
107                         }
108                         break;
109
110                 case SLAP_LIMITS_ANONYMOUS:
111                         if ( ndn->bv_len == 0 ) {
112                                 *limit = &lm[0]->lm_limits;
113                                 return( 0 );
114                         }
115                         break;
116
117                 case SLAP_LIMITS_USERS:
118                         if ( ndn->bv_len != 0 ) {
119                                 *limit = &lm[0]->lm_limits;
120                                 return( 0 );
121                         }
122                         break;
123
124                 default:
125                         assert( 0 );    /* unreachable */
126                         return( -1 );
127                 }
128         }
129
130         return( 0 );
131 }
132
133 static int
134 add_limits(
135         Backend                 *be,
136         int                     type,
137         const char              *pattern,
138         struct slap_limits_set  *limit
139 )
140 {
141         int                     i;
142         struct slap_limits      *lm;
143         
144         assert( be );
145         assert( limit );
146
147         lm = ( struct slap_limits * )ch_calloc( sizeof( struct slap_limits ), 1 );
148
149         switch ( type ) {
150         case SLAP_LIMITS_EXACT:
151         case SLAP_LIMITS_ONE:
152         case SLAP_LIMITS_SUBTREE:
153         case SLAP_LIMITS_CHILDREN:
154                 lm->lm_type = type;
155                 lm->lm_dn_pat = ber_bvstrdup( pattern );
156                 if ( dn_normalize( lm->lm_dn_pat->bv_val ) == NULL ) {
157                         ber_bvfree( lm->lm_dn_pat );
158                         ch_free( lm );
159                         return( -1 );
160                 }
161                 break;
162                 
163         case SLAP_LIMITS_REGEX:
164         case SLAP_LIMITS_UNDEFINED:
165                 lm->lm_type = SLAP_LIMITS_REGEX;
166                 lm->lm_dn_pat = ber_bvstrdup( pattern );
167                 if ( regcomp( &lm->lm_dn_regex, lm->lm_dn_pat->bv_val, 
168                                         REG_EXTENDED | REG_ICASE ) ) {
169                         ber_bvfree( lm->lm_dn_pat );
170                         ch_free( lm );
171                         return( -1 );
172                 }
173                 break;
174
175         case SLAP_LIMITS_ANONYMOUS:
176         case SLAP_LIMITS_USERS:
177                 lm->lm_type = type;
178                 lm->lm_dn_pat = NULL;
179                 break;
180         }
181
182         lm->lm_limits = *limit;
183
184         i = 0;
185         if ( be->be_limits != NULL ) {
186                 for ( ; be->be_limits[i]; i++ );
187         }
188
189         be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits,
190                         sizeof( struct slap_limits * ) * ( i + 2 ) );
191         be->be_limits[i] = lm;
192         be->be_limits[i+1] = NULL;
193         
194         return( 0 );
195 }
196
197 int
198 parse_limits(
199         Backend     *be,
200         const char  *fname,
201         int         lineno,
202         int         argc,
203         char        **argv
204 )
205 {
206         int     type = SLAP_LIMITS_UNDEFINED;
207         char    *pattern;
208         struct slap_limits_set limit;
209         int     i;
210
211         assert( be );
212
213         if ( argc < 3 ) {
214 #ifdef NEW_LOGGING
215                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
216                         "%s : line %d: missing arg(s) in "
217                         "\"limits <pattern> <limits>\" line.\n",
218                         fname, lineno ));
219 #else
220                 Debug( LDAP_DEBUG_ANY,
221                         "%s : line %d: missing arg(s) in "
222                         "\"limits <pattern> <limits>\" line.\n%s",
223                         fname, lineno, "" );
224 #endif
225                 return( -1 );
226         }
227
228         limit = be->be_def_limit;
229
230         /*
231          * syntax:
232          *
233          * "limits" <pattern> <limit> [ ... ]
234          * 
235          * 
236          * <pattern>:
237          * 
238          * "anonymous"
239          * "users"
240          * [ "dn" [ "." { "exact" | "base" | "one" | "sub" | children" 
241          *      | "regex" | "anonymous" } ] "=" ] <dn pattern>
242          *
243          * Note:
244          *      "exact" and "base" are the same (exact match);
245          *      "one" means exactly one rdn below, NOT including the pattern
246          *      "sub" means any rdn below, including the pattern
247          *      "children" means any rdn below, NOT including the pattern
248          *      
249          *      "anonymous" may be deprecated in favour 
250          *      of the pattern = "anonymous" form
251          *
252          *
253          * <limit>:
254          *
255          * "time" [ "." { "soft" | "hard" } ] "=" <integer>
256          *
257          * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer>
258          */
259         
260         pattern = argv[1];
261         if ( strcasecmp( pattern, "anonymous" ) == 0 ) {
262                 type = SLAP_LIMITS_ANONYMOUS;
263
264         } else if ( strcasecmp( pattern, "users" ) == 0 ) {
265                 type = SLAP_LIMITS_USERS;
266                 
267         } else if ( strncasecmp( pattern, "dn", 2 ) == 0 ) {
268                 pattern += 2;
269                 if ( pattern[0] == '.' ) {
270                         pattern++;
271                         if ( strncasecmp( pattern, "exact", 5 ) == 0 ) {
272                                 type = SLAP_LIMITS_EXACT;
273                                 pattern += 5;
274
275                         } else if ( strncasecmp( pattern, "base", 4 ) == 0 ) {
276                                 type = SLAP_LIMITS_BASE;
277                                 pattern += 4;
278
279                         } else if ( strncasecmp( pattern, "one", 3 ) == 0 ) {
280                                 type = SLAP_LIMITS_ONE;
281                                 pattern += 3;
282
283                         } else if ( strncasecmp( pattern, "subtree", 7 ) == 0 ) {
284                                 type = SLAP_LIMITS_SUBTREE;
285                                 pattern += 7;
286
287                         } else if ( strncasecmp( pattern, "children", 8 ) == 0 ) {
288                                 type = SLAP_LIMITS_CHILDREN;
289                                 pattern += 8;
290
291                         } else if ( strncasecmp( pattern, "regex", 5 ) == 0 ) {
292                                 type = SLAP_LIMITS_REGEX;
293                                 pattern += 5;
294
295                         /* 
296                          * this could be deprecated in favour
297                          * of the pattern = "anonymous" form
298                          */
299                         } else if ( strncasecmp( pattern, "anonymous", 9 ) == 0 ) {
300                                 type = SLAP_LIMITS_ANONYMOUS;
301                                 pattern = NULL;
302                         }
303                 }
304
305                 /* pre-check the data */
306                 switch ( type ) {
307                 case SLAP_LIMITS_ANONYMOUS:
308                 case SLAP_LIMITS_USERS:
309
310                         /* no need for pattern */
311                         pattern = NULL;
312                         break;
313
314                 default:
315                         if ( pattern[0] != '=' ) {
316 #ifdef NEW_LOGGING
317                                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
318                                         "%s : line %d: missing '=' in "
319                                         "\"dn[.{exact|base|one|subtree"
320                                         "|children|regex|anonymous}]"
321                                         "=<pattern>\" in "
322                                         "\"limits <pattern> <limits>\" line.\n",
323                                         fname, lineno ));
324 #else
325                                 Debug( LDAP_DEBUG_ANY,
326                                         "%s : line %d: missing '=' in "
327                                         "\"dn[.{exact|base|one|subtree"
328                                         "|children|regex|anonymous}]"
329                                         "=<pattern>\" in "
330                                         "\"limits <pattern> <limits>\" "
331                                         "line.\n%s",
332                                         fname, lineno, "" );
333 #endif
334                                 return( -1 );
335                         }
336
337                         /* skip '=' (required) */
338                         pattern++;
339                 }
340         }
341
342         /* get the limits */
343         for ( i = 2; i < argc; i++ ) {
344                 if ( parse_limit( argv[i], &limit ) ) {
345
346 #ifdef NEW_LOGGING
347                         LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
348                                 "%s : line %d: unknown limit type \"%s\" in "
349                                 "\"limits <pattern> <limits>\" line.\n",
350                         fname, lineno, argv[i] ));
351 #else
352                         Debug( LDAP_DEBUG_ANY,
353                                 "%s : line %d: unknown limit type \"%s\" in "
354                                 "\"limits <pattern> <limits>\" line.\n",
355                         fname, lineno, argv[i] );
356 #endif
357
358                         return( 1 );
359                 }
360         }
361
362         /*
363          * sanity checks ...
364          */
365         if ( limit.lms_t_hard > 0 && limit.lms_t_hard < limit.lms_t_soft ) {
366                 limit.lms_t_hard = limit.lms_t_soft;
367         }
368         
369         if ( limit.lms_s_hard > 0 && limit.lms_s_hard < limit.lms_s_soft ) {
370                 limit.lms_s_hard = limit.lms_s_soft;
371         }
372         
373         return( add_limits( be, type, pattern, &limit ) );
374 }
375
376 int
377 parse_limit(
378         const char              *arg,
379         struct slap_limits_set  *limit
380 )
381 {
382         assert( arg );
383         assert( limit );
384
385         if ( strncasecmp( arg, "time", 4 ) == 0 ) {
386                 arg += 4;
387
388                 if ( arg[0] == '.' ) {
389                         arg++;
390                         if ( strncasecmp( arg, "soft", 4 ) == 0 ) {
391                                 arg += 4;
392                                 if ( arg[0] != '=' ) {
393                                         return( 1 );
394                                 }
395                                 arg++;
396                                 limit->lms_t_soft = atoi( arg );
397                                 
398                         } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) {
399                                 arg += 4;
400                                 if ( arg[0] != '=' ) {
401                                         return( 1 );
402                                 }
403                                 arg++;
404                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
405                                         limit->lms_t_hard = 0;
406                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
407                                         limit->lms_t_hard = -1;
408                                 } else {
409                                         limit->lms_t_hard = atoi( arg );
410                                 }
411                                 
412                         } else {
413                                 return( 1 );
414                         }
415                         
416                 } else if ( arg[0] == '=' ) {
417                         limit->lms_t_soft = atoi( arg );
418                         limit->lms_t_hard = 0;
419                         
420                 } else {
421                         return( 1 );
422                 }
423
424         } else if ( strncasecmp( arg, "size", 4 ) == 0 ) {
425                 arg += 4;
426                 
427                 if ( arg[0] == '.' ) {
428                         arg++;
429                         if ( strncasecmp( arg, "soft", 4 ) == 0 ) {
430                                 arg += 4;
431                                 if ( arg[0] != '=' ) {
432                                         return( 1 );
433                                 }
434                                 arg++;
435                                 limit->lms_s_soft = atoi( arg );
436                                 
437                         } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) {
438                                 arg += 4;
439                                 if ( arg[0] != '=' ) {
440                                         return( 1 );
441                                 }
442                                 arg++;
443                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
444                                         limit->lms_s_hard = 0;
445                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
446                                         limit->lms_s_hard = -1;
447                                 } else {
448                                         limit->lms_s_hard = atoi( arg );
449                                 }
450                                 
451                         } else if ( strncasecmp( arg, "unchecked", 9 ) == 0 ) {
452                                 arg += 9;
453                                 if ( arg[0] != '=' ) {
454                                         return( 1 );
455                                 }
456                                 arg++;
457                                 if ( strcasecmp( arg, "none" ) == 0 ) {
458                                         limit->lms_s_unchecked = -1;
459                                 } else {
460                                         limit->lms_s_unchecked = atoi( arg );
461                                 }
462                                 
463                         } else {
464                                 return( 1 );
465                         }
466                         
467                 } else if ( arg[0] == '=' ) {
468                         limit->lms_s_soft = atoi( arg );
469                         limit->lms_s_hard = 0;
470                         
471                 } else {
472                         return( 1 );
473                 }
474         }
475
476         return 0;
477 }
478