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