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