]> git.sur5r.net Git - openldap/blob - servers/slapd/limits.c
Fix lint in previous commit
[openldap] / servers / slapd / limits.c
1 /* limits.c - routines to handle regex-based size and time limits */
2 /*
3  * Copyright 1998-2002 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 ) != 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                 {
156                         int rc;
157                         struct berval bv;
158                         bv.bv_val = (char *) pattern;
159                         bv.bv_len = strlen( pattern );
160
161                         rc = dnNormalize2( NULL, &bv, &lm->lm_dn_pat );
162                         if ( rc != LDAP_SUCCESS ) {
163                                 ch_free( lm );
164                                 return( -1 );
165                         }
166                 }
167                 break;
168                 
169         case SLAP_LIMITS_REGEX:
170         case SLAP_LIMITS_UNDEFINED:
171                 lm->lm_type = SLAP_LIMITS_REGEX;
172                 ber_str2bv( pattern, 0, 1, &lm->lm_dn_pat );
173                 if ( regcomp( &lm->lm_dn_regex, lm->lm_dn_pat.bv_val, 
174                                         REG_EXTENDED | REG_ICASE ) ) {
175                         free( lm->lm_dn_pat.bv_val );
176                         ch_free( lm );
177                         return( -1 );
178                 }
179                 break;
180
181         case SLAP_LIMITS_ANONYMOUS:
182         case SLAP_LIMITS_USERS:
183                 lm->lm_type = type;
184                 lm->lm_dn_pat.bv_val = NULL;
185                 lm->lm_dn_pat.bv_len = 0;
186                 break;
187         }
188
189         lm->lm_limits = *limit;
190
191         i = 0;
192         if ( be->be_limits != NULL ) {
193                 for ( ; be->be_limits[i]; i++ );
194         }
195
196         be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits,
197                         sizeof( struct slap_limits * ) * ( i + 2 ) );
198         be->be_limits[i] = lm;
199         be->be_limits[i+1] = NULL;
200         
201         return( 0 );
202 }
203
204 int
205 parse_limits(
206         Backend     *be,
207         const char  *fname,
208         int         lineno,
209         int         argc,
210         char        **argv
211 )
212 {
213         int     type = SLAP_LIMITS_UNDEFINED;
214         char    *pattern;
215         struct slap_limits_set limit;
216         int     i;
217
218         assert( be );
219
220         if ( argc < 3 ) {
221 #ifdef NEW_LOGGING
222                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
223                         "%s : line %d: missing arg(s) in "
224                         "\"limits <pattern> <limits>\" line.\n",
225                         fname, lineno ));
226 #else
227                 Debug( LDAP_DEBUG_ANY,
228                         "%s : line %d: missing arg(s) in "
229                         "\"limits <pattern> <limits>\" line.\n%s",
230                         fname, lineno, "" );
231 #endif
232                 return( -1 );
233         }
234
235         limit = be->be_def_limit;
236
237         /*
238          * syntax:
239          *
240          * "limits" <pattern> <limit> [ ... ]
241          * 
242          * 
243          * <pattern>:
244          * 
245          * "anonymous"
246          * "users"
247          * [ "dn" [ "." { "exact" | "base" | "one" | "sub" | children" 
248          *      | "regex" | "anonymous" } ] "=" ] <dn pattern>
249          *
250          * Note:
251          *      "exact" and "base" are the same (exact match);
252          *      "one" means exactly one rdn below, NOT including the pattern
253          *      "sub" means any rdn below, including the pattern
254          *      "children" means any rdn below, NOT including the pattern
255          *      
256          *      "anonymous" may be deprecated in favour 
257          *      of the pattern = "anonymous" form
258          *
259          *
260          * <limit>:
261          *
262          * "time" [ "." { "soft" | "hard" } ] "=" <integer>
263          *
264          * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer>
265          */
266         
267         pattern = argv[1];
268         if ( strcasecmp( pattern, "anonymous" ) == 0 ) {
269                 type = SLAP_LIMITS_ANONYMOUS;
270
271         } else if ( strcasecmp( pattern, "users" ) == 0 ) {
272                 type = SLAP_LIMITS_USERS;
273                 
274         } else if ( strncasecmp( pattern, "dn", 2 ) == 0 ) {
275                 pattern += 2;
276                 if ( pattern[0] == '.' ) {
277                         pattern++;
278                         if ( strncasecmp( pattern, "exact", 5 ) == 0 ) {
279                                 type = SLAP_LIMITS_EXACT;
280                                 pattern += 5;
281
282                         } else if ( strncasecmp( pattern, "base", 4 ) == 0 ) {
283                                 type = SLAP_LIMITS_BASE;
284                                 pattern += 4;
285
286                         } else if ( strncasecmp( pattern, "one", 3 ) == 0 ) {
287                                 type = SLAP_LIMITS_ONE;
288                                 pattern += 3;
289
290                         } else if ( strncasecmp( pattern, "subtree", 7 ) == 0 ) {
291                                 type = SLAP_LIMITS_SUBTREE;
292                                 pattern += 7;
293
294                         } else if ( strncasecmp( pattern, "children", 8 ) == 0 ) {
295                                 type = SLAP_LIMITS_CHILDREN;
296                                 pattern += 8;
297
298                         } else if ( strncasecmp( pattern, "regex", 5 ) == 0 ) {
299                                 type = SLAP_LIMITS_REGEX;
300                                 pattern += 5;
301
302                         /* 
303                          * this could be deprecated in favour
304                          * of the pattern = "anonymous" form
305                          */
306                         } else if ( strncasecmp( pattern, "anonymous", 9 ) == 0 ) {
307                                 type = SLAP_LIMITS_ANONYMOUS;
308                                 pattern = NULL;
309                         }
310                 }
311
312                 /* pre-check the data */
313                 switch ( type ) {
314                 case SLAP_LIMITS_ANONYMOUS:
315                 case SLAP_LIMITS_USERS:
316
317                         /* no need for pattern */
318                         pattern = NULL;
319                         break;
320
321                 default:
322                         if ( pattern[0] != '=' ) {
323 #ifdef NEW_LOGGING
324                                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
325                                         "%s : line %d: missing '=' in "
326                                         "\"dn[.{exact|base|one|subtree"
327                                         "|children|regex|anonymous}]"
328                                         "=<pattern>\" in "
329                                         "\"limits <pattern> <limits>\" line.\n",
330                                         fname, lineno ));
331 #else
332                                 Debug( LDAP_DEBUG_ANY,
333                                         "%s : line %d: missing '=' in "
334                                         "\"dn[.{exact|base|one|subtree"
335                                         "|children|regex|anonymous}]"
336                                         "=<pattern>\" in "
337                                         "\"limits <pattern> <limits>\" "
338                                         "line.\n%s",
339                                         fname, lineno, "" );
340 #endif
341                                 return( -1 );
342                         }
343
344                         /* skip '=' (required) */
345                         pattern++;
346                 }
347         }
348
349         /* get the limits */
350         for ( i = 2; i < argc; i++ ) {
351                 if ( parse_limit( argv[i], &limit ) ) {
352
353 #ifdef NEW_LOGGING
354                         LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
355                                 "%s : line %d: unknown limit type \"%s\" in "
356                                 "\"limits <pattern> <limits>\" line.\n",
357                         fname, lineno, argv[i] ));
358 #else
359                         Debug( LDAP_DEBUG_ANY,
360                                 "%s : line %d: unknown limit type \"%s\" in "
361                                 "\"limits <pattern> <limits>\" line.\n",
362                         fname, lineno, argv[i] );
363 #endif
364
365                         return( 1 );
366                 }
367         }
368
369         /*
370          * sanity checks ...
371          */
372         if ( limit.lms_t_hard > 0 && limit.lms_t_hard < limit.lms_t_soft ) {
373                 limit.lms_t_hard = limit.lms_t_soft;
374         }
375         
376         if ( limit.lms_s_hard > 0 && limit.lms_s_hard < limit.lms_s_soft ) {
377                 limit.lms_s_hard = limit.lms_s_soft;
378         }
379         
380         return( add_limits( be, type, pattern, &limit ) );
381 }
382
383 int
384 parse_limit(
385         const char              *arg,
386         struct slap_limits_set  *limit
387 )
388 {
389         assert( arg );
390         assert( limit );
391
392         if ( strncasecmp( arg, "time", 4 ) == 0 ) {
393                 arg += 4;
394
395                 if ( arg[0] == '.' ) {
396                         arg++;
397                         if ( strncasecmp( arg, "soft", 4 ) == 0 ) {
398                                 arg += 4;
399                                 if ( arg[0] != '=' ) {
400                                         return( 1 );
401                                 }
402                                 arg++;
403                                 limit->lms_t_soft = atoi( arg );
404                                 
405                         } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) {
406                                 arg += 4;
407                                 if ( arg[0] != '=' ) {
408                                         return( 1 );
409                                 }
410                                 arg++;
411                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
412                                         limit->lms_t_hard = 0;
413                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
414                                         limit->lms_t_hard = -1;
415                                 } else {
416                                         limit->lms_t_hard = atoi( arg );
417                                 }
418                                 
419                         } else {
420                                 return( 1 );
421                         }
422                         
423                 } else if ( arg[0] == '=' ) {
424                         limit->lms_t_soft = atoi( arg );
425                         limit->lms_t_hard = 0;
426                         
427                 } else {
428                         return( 1 );
429                 }
430
431         } else if ( strncasecmp( arg, "size", 4 ) == 0 ) {
432                 arg += 4;
433                 
434                 if ( arg[0] == '.' ) {
435                         arg++;
436                         if ( strncasecmp( arg, "soft", 4 ) == 0 ) {
437                                 arg += 4;
438                                 if ( arg[0] != '=' ) {
439                                         return( 1 );
440                                 }
441                                 arg++;
442                                 limit->lms_s_soft = atoi( arg );
443                                 
444                         } else if ( strncasecmp( arg, "hard", 4 ) == 0 ) {
445                                 arg += 4;
446                                 if ( arg[0] != '=' ) {
447                                         return( 1 );
448                                 }
449                                 arg++;
450                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
451                                         limit->lms_s_hard = 0;
452                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
453                                         limit->lms_s_hard = -1;
454                                 } else {
455                                         limit->lms_s_hard = atoi( arg );
456                                 }
457                                 
458                         } else if ( strncasecmp( arg, "unchecked", 9 ) == 0 ) {
459                                 arg += 9;
460                                 if ( arg[0] != '=' ) {
461                                         return( 1 );
462                                 }
463                                 arg++;
464                                 if ( strcasecmp( arg, "none" ) == 0 ) {
465                                         limit->lms_s_unchecked = -1;
466                                 } else {
467                                         limit->lms_s_unchecked = atoi( arg );
468                                 }
469                                 
470                         } else {
471                                 return( 1 );
472                         }
473                         
474                 } else if ( arg[0] == '=' ) {
475                         limit->lms_s_soft = atoi( arg );
476                         limit->lms_s_hard = 0;
477                         
478                 } else {
479                         return( 1 );
480                 }
481         }
482
483         return 0;
484 }
485