]> git.sur5r.net Git - openldap/blob - servers/slapd/limits.c
import error message fix from HEAD
[openldap] / servers / slapd / limits.c
1 /* limits.c - routines to handle regex-based size and time limits */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20
21 #include <ac/regex.h>
22 #include <ac/string.h>
23
24 #include "slap.h"
25
26 int
27 get_limits( 
28         Operation               *op,
29         struct berval           *ndn, 
30         struct slap_limits_set  **limit
31 )
32 {
33         struct slap_limits **lm;
34
35         assert( op );
36         assert( limit );
37
38         /*
39          * default values
40          */
41         *limit = &op->o_bd->be_def_limit;
42
43         if ( op->o_bd->be_limits == NULL ) {
44                 return( 0 );
45         }
46
47         for ( lm = op->o_bd->be_limits; lm[0] != NULL; lm++ ) {
48                 unsigned        style = lm[0]->lm_flags & SLAP_LIMITS_MASK;
49                 unsigned        type = lm[0]->lm_flags & SLAP_LIMITS_TYPE_MASK;
50
51                 switch ( style ) {
52                 case SLAP_LIMITS_EXACT:
53                         if ( ndn->bv_len == 0 ) {
54                                 break;
55                         }
56
57                         if ( type == SLAP_LIMITS_TYPE_GROUP ) {
58                                 int     rc;
59
60                                 rc = backend_group( op, NULL,
61                                                 &lm[0]->lm_pat, ndn,
62                                                 lm[0]->lm_group_oc,
63                                                 lm[0]->lm_group_ad );
64                                 if ( rc == 0 ) {
65                                         *limit = &lm[0]->lm_limits;
66                                         return( 0 );
67                                 }
68                         }
69                         
70                         if ( dn_match( &lm[0]->lm_pat, ndn ) ) {
71                                 *limit = &lm[0]->lm_limits;
72                                 return( 0 );
73                         }
74                         break;
75
76                 case SLAP_LIMITS_ONE:
77                 case SLAP_LIMITS_SUBTREE:
78                 case SLAP_LIMITS_CHILDREN: {
79                         size_t d;
80                         
81                         if ( ndn->bv_len == 0 ) {
82                                 break;
83                         }
84
85                         /* ndn shorter than dn_pat */
86                         if ( ndn->bv_len < lm[0]->lm_pat.bv_len ) {
87                                 break;
88                         }
89                         d = ndn->bv_len - lm[0]->lm_pat.bv_len;
90
91                         /* allow exact match for SUBTREE only */
92                         if ( d == 0 ) {
93                                 if ( style != SLAP_LIMITS_SUBTREE ) {
94                                         break;
95                                 }
96                         } else {
97                                 /* check for unescaped rdn separator */
98                                 if ( !DN_SEPARATOR( ndn->bv_val[d-1] ) ) {
99                                         break;
100                                 }
101                         }
102
103                         /* in case of (sub)match ... */
104                         if ( lm[0]->lm_pat.bv_len == ( ndn->bv_len - d )
105                                         && strcmp( lm[0]->lm_pat.bv_val,
106                                                 &ndn->bv_val[d] ) == 0 )
107                         {
108                                 /* check for exactly one rdn in case of ONE */
109                                 if ( style == SLAP_LIMITS_ONE ) {
110                                         /*
111                                          * if ndn is more that one rdn
112                                          * below dn_pat, continue
113                                          */
114                                         if ( (size_t) dn_rdnlen( NULL, ndn )
115                                                         != d - 1 )
116                                         {
117                                                 break;
118                                         }
119                                 }
120
121                                 *limit = &lm[0]->lm_limits;
122                                 return( 0 );
123                         }
124
125                         break;
126                 }
127
128                 case SLAP_LIMITS_REGEX:
129                         if ( ndn->bv_len == 0 ) {
130                                 break;
131                         }
132                         if ( regexec( &lm[0]->lm_regex, ndn->bv_val,
133                                                 0, NULL, 0 ) == 0 )
134                         {
135                                 *limit = &lm[0]->lm_limits;
136                                 return( 0 );
137                         }
138                         break;
139
140                 case SLAP_LIMITS_ANONYMOUS:
141                         if ( ndn->bv_len == 0 ) {
142                                 *limit = &lm[0]->lm_limits;
143                                 return( 0 );
144                         }
145                         break;
146
147                 case SLAP_LIMITS_USERS:
148                         if ( ndn->bv_len != 0 ) {
149                                 *limit = &lm[0]->lm_limits;
150                                 return( 0 );
151                         }
152                         break;
153
154                 case SLAP_LIMITS_ANY:
155                         *limit = &lm[0]->lm_limits;
156                         return( 0 );
157
158                 default:
159                         assert( 0 );    /* unreachable */
160                         return( -1 );
161                 }
162         }
163
164         return( 0 );
165 }
166
167 static int
168 add_limits(
169         Backend                 *be,
170         unsigned                flags,
171         const char              *pattern,
172         ObjectClass             *group_oc,
173         AttributeDescription    *group_ad,
174         struct slap_limits_set  *limit
175 )
176 {
177         int                     i;
178         struct slap_limits      *lm;
179         unsigned                type, style;
180         
181         assert( be );
182         assert( limit );
183
184         type = flags & SLAP_LIMITS_TYPE_MASK;
185         style = flags & SLAP_LIMITS_MASK;
186
187         switch ( style ) {
188         case SLAP_LIMITS_ANONYMOUS:
189         case SLAP_LIMITS_USERS:
190         case SLAP_LIMITS_ANY:
191                 for ( i = 0; be->be_limits && be->be_limits[ i ]; i++ ) {
192                         if ( be->be_limits[ i ]->lm_flags == style ) {
193                                 return( -1 );
194                         }
195                 }
196                 break;
197         }
198
199
200         lm = ( struct slap_limits * )ch_calloc( sizeof( struct slap_limits ), 1 );
201
202         switch ( style ) {
203         case SLAP_LIMITS_UNDEFINED:
204                 style = SLAP_LIMITS_EXACT;
205                 /* continue to next cases */
206         case SLAP_LIMITS_EXACT:
207         case SLAP_LIMITS_ONE:
208         case SLAP_LIMITS_SUBTREE:
209         case SLAP_LIMITS_CHILDREN:
210                 lm->lm_flags = style | type;
211                 {
212                         int rc;
213                         struct berval bv;
214                         bv.bv_val = (char *) pattern;
215                         bv.bv_len = strlen( pattern );
216
217                         rc = dnNormalize( 0, NULL, NULL, &bv, &lm->lm_pat, NULL );
218                         if ( rc != LDAP_SUCCESS ) {
219                                 ch_free( lm );
220                                 return( -1 );
221                         }
222                 }
223                 break;
224                 
225         case SLAP_LIMITS_REGEX:
226                 lm->lm_flags = style | type;
227                 ber_str2bv( pattern, 0, 1, &lm->lm_pat );
228                 if ( regcomp( &lm->lm_regex, lm->lm_pat.bv_val, 
229                                         REG_EXTENDED | REG_ICASE ) ) {
230                         free( lm->lm_pat.bv_val );
231                         ch_free( lm );
232                         return( -1 );
233                 }
234                 break;
235
236         case SLAP_LIMITS_ANONYMOUS:
237         case SLAP_LIMITS_USERS:
238         case SLAP_LIMITS_ANY:
239                 lm->lm_flags = style | type;
240                 lm->lm_pat.bv_val = NULL;
241                 lm->lm_pat.bv_len = 0;
242                 break;
243         }
244
245         switch ( type ) {
246         case SLAP_LIMITS_TYPE_GROUP:
247                 assert( group_oc );
248                 assert( group_ad );
249                 lm->lm_group_oc = group_oc;
250                 lm->lm_group_ad = group_ad;
251                 break;
252         }
253
254         lm->lm_limits = *limit;
255
256         i = 0;
257         if ( be->be_limits != NULL ) {
258                 for ( ; be->be_limits[i]; i++ );
259         }
260
261         be->be_limits = ( struct slap_limits ** )ch_realloc( be->be_limits,
262                         sizeof( struct slap_limits * ) * ( i + 2 ) );
263         be->be_limits[i] = lm;
264         be->be_limits[i+1] = NULL;
265         
266         return( 0 );
267 }
268
269 int
270 parse_limits(
271         Backend     *be,
272         const char  *fname,
273         int         lineno,
274         int         argc,
275         char        **argv
276 )
277 {
278         int                     flags = SLAP_LIMITS_UNDEFINED;
279         char                    *pattern;
280         struct slap_limits_set  limit;
281         int                     i, rc = 0;
282         ObjectClass             *group_oc = NULL;
283         AttributeDescription    *group_ad = NULL;
284
285         assert( be );
286
287         if ( argc < 3 ) {
288 #ifdef NEW_LOGGING
289                 LDAP_LOG( CONFIG, CRIT, 
290                         "%s : line %d: missing arg(s) in "
291                         "\"limits <pattern> <limits>\" line.\n", fname, lineno, 0 );
292 #else
293                 Debug( LDAP_DEBUG_ANY,
294                         "%s : line %d: missing arg(s) in "
295                         "\"limits <pattern> <limits>\" line.\n%s",
296                         fname, lineno, "" );
297 #endif
298                 return( -1 );
299         }
300
301         limit = be->be_def_limit;
302
303         /*
304          * syntax:
305          *
306          * "limits" <pattern> <limit> [ ... ]
307          * 
308          * 
309          * <pattern>:
310          * 
311          * "anonymous"
312          * "users"
313          * [ "dn" [ "." { "exact" | "base" | "one" | "sub" | children" 
314          *      | "regex" | "anonymous" } ] "=" ] <dn pattern>
315          *
316          * Note:
317          *      "exact" and "base" are the same (exact match);
318          *      "one" means exactly one rdn below, NOT including the pattern
319          *      "sub" means any rdn below, including the pattern
320          *      "children" means any rdn below, NOT including the pattern
321          *      
322          *      "anonymous" may be deprecated in favour 
323          *      of the pattern = "anonymous" form
324          *
325          *
326          * <limit>:
327          *
328          * "time" [ "." { "soft" | "hard" } ] "=" <integer>
329          *
330          * "size" [ "." { "soft" | "hard" | "unchecked" } ] "=" <integer>
331          */
332         
333         pattern = argv[1];
334         if ( strcmp( pattern, "*" ) == 0) {
335                 flags = SLAP_LIMITS_ANY;
336
337         } else if ( strcasecmp( pattern, "anonymous" ) == 0 ) {
338                 flags = SLAP_LIMITS_ANONYMOUS;
339
340         } else if ( strcasecmp( pattern, "users" ) == 0 ) {
341                 flags = SLAP_LIMITS_USERS;
342                 
343         } else if ( strncasecmp( pattern, "dn", sizeof( "dn" ) - 1 ) == 0 ) {
344                 pattern += sizeof( "dn" ) - 1;
345                 if ( pattern[0] == '.' ) {
346                         pattern++;
347                         if ( strncasecmp( pattern, "exact", sizeof( "exact" ) - 1 ) == 0 ) {
348                                 flags = SLAP_LIMITS_EXACT;
349                                 pattern += sizeof( "exact" ) - 1;
350
351                         } else if ( strncasecmp( pattern, "base", sizeof( "base" ) - 1 ) == 0 ) {
352                                 flags = SLAP_LIMITS_BASE;
353                                 pattern += sizeof( "base" ) - 1;
354
355                         } else if ( strncasecmp( pattern, "one", sizeof( "one" ) - 1 ) == 0 ) {
356                                 flags = SLAP_LIMITS_ONE;
357                                 pattern += sizeof( "one" ) - 1;
358
359                         } else if ( strncasecmp( pattern, "subtree", sizeof( "subtree" ) - 1 ) == 0 ) {
360                                 flags = SLAP_LIMITS_SUBTREE;
361                                 pattern += sizeof( "subtree" ) - 1;
362
363                         } else if ( strncasecmp( pattern, "children", sizeof( "children" ) - 1 ) == 0 ) {
364                                 flags = SLAP_LIMITS_CHILDREN;
365                                 pattern += sizeof( "children" ) - 1;
366
367                         } else if ( strncasecmp( pattern, "regex", sizeof( "regex" ) - 1 ) == 0 ) {
368                                 flags = SLAP_LIMITS_REGEX;
369                                 pattern += sizeof( "regex" ) - 1;
370
371                         /* 
372                          * this could be deprecated in favour
373                          * of the pattern = "anonymous" form
374                          */
375                         } else if ( strncasecmp( pattern, "anonymous", sizeof( "anonymous" ) - 1 ) == 0 ) {
376                                 flags = SLAP_LIMITS_ANONYMOUS;
377                                 pattern = NULL;
378                         }
379                 }
380
381                 /* pre-check the data */
382                 switch ( flags ) {
383                 case SLAP_LIMITS_ANONYMOUS:
384                 case SLAP_LIMITS_USERS:
385
386                         /* no need for pattern */
387                         pattern = NULL;
388                         break;
389
390                 default:
391                         if ( pattern[0] != '=' ) {
392 #ifdef NEW_LOGGING
393                                 LDAP_LOG( CONFIG, CRIT, 
394                                         "%s : line %d: missing '=' in "
395                                         "\"dn[.{exact|base|one|subtree"
396                                         "|children|regex|anonymous}]" "=<pattern>\" in "
397                                         "\"limits <pattern> <limits>\" line.\n", fname, lineno, 0 );
398 #else
399                                 Debug( LDAP_DEBUG_ANY,
400                                         "%s : line %d: missing '=' in "
401                                         "\"dn[.{exact|base|one|subtree"
402                                         "|children|regex|anonymous}]"
403                                         "=<pattern>\" in "
404                                         "\"limits <pattern> <limits>\" "
405                                         "line.\n%s",
406                                         fname, lineno, "" );
407 #endif
408                                 return( -1 );
409                         }
410
411                         /* skip '=' (required) */
412                         pattern++;
413
414                         /* trim obvious cases */
415                         if ( strcmp( pattern, "*" ) == 0 ) {
416                                 flags = SLAP_LIMITS_ANY;
417                                 pattern = NULL;
418
419                         } else if ( flags == SLAP_LIMITS_REGEX
420                                         && strcmp( pattern, ".*" ) == 0 ) {
421                                 flags = SLAP_LIMITS_ANY;
422                                 pattern = NULL;
423                         }
424                 }
425
426         } else if (strncasecmp( pattern, "group", sizeof( "group" ) - 1 ) == 0 ) {
427                 pattern += sizeof( "group" ) - 1;
428
429                 if ( pattern[0] == '/' ) {
430                         struct berval   oc, ad;
431
432                         oc.bv_val = pattern + 1;
433
434                         ad.bv_val = strchr(pattern, '/');
435                         if ( ad.bv_val != NULL ) {
436                                 const char      *text = NULL;
437                                 int             rc;
438
439                                 oc.bv_len = ad.bv_val - oc.bv_val;
440
441                                 ad.bv_val++;
442                                 ad.bv_len = strlen( ad.bv_val );
443                                 rc = slap_bv2ad( &ad, &group_ad, &text );
444                                 if ( rc != LDAP_SUCCESS ) {
445                                         goto no_ad;
446                                 }
447
448                                 pattern = ad.bv_val + ad.bv_len;
449
450                         } else {
451                                 oc.bv_len = strlen( oc.bv_val );
452
453                                 pattern = oc.bv_val + oc.bv_len;
454                         }
455
456                         group_oc = oc_bvfind( &oc );
457                         if ( group_oc == NULL ) {
458                                 goto no_oc;
459                         }
460                 }
461
462                 if ( group_oc == NULL ) {
463                         group_oc = oc_find( SLAPD_GROUP_CLASS );
464                         if ( group_oc == NULL ) {
465 no_oc:;
466                                 return( -1 );
467                         }
468                 }
469
470                 if ( group_ad == NULL ) {
471                         const char      *text = NULL;
472                         int             rc;
473                         
474                         rc = slap_str2ad( SLAPD_GROUP_ATTR, &group_ad, &text );
475
476                         if ( rc != LDAP_SUCCESS ) {
477 no_ad:;
478                                 return( -1 );
479                         }
480                 }
481
482                 flags = SLAP_LIMITS_TYPE_GROUP | SLAP_LIMITS_EXACT;
483
484                 if ( pattern[0] != '=' ) {
485 #ifdef NEW_LOGGING
486                         LDAP_LOG( CONFIG, CRIT, 
487                                 "%s : line %d: missing '=' in "
488                                 "\"group[/objectClass[/attributeType]]"
489                                 "=<pattern>\" in "
490                                 "\"limits <pattern> <limits>\" line.\n",
491                                 fname, lineno, 0 );
492 #else
493                         Debug( LDAP_DEBUG_ANY,
494                                 "%s : line %d: missing '=' in "
495                                 "\"group[/objectClass[/attributeType]]"
496                                 "=<pattern>\" in "
497                                 "\"limits <pattern> <limits>\" line.\n",
498                                 fname, lineno, 0 );
499 #endif
500                         return( -1 );
501                 }
502
503                 /* skip '=' (required) */
504                 pattern++;
505         }
506
507         /* get the limits */
508         for ( i = 2; i < argc; i++ ) {
509                 if ( parse_limit( argv[i], &limit ) ) {
510
511 #ifdef NEW_LOGGING
512                         LDAP_LOG( CONFIG, CRIT, 
513                                 "%s : line %d: unknown limit values \"%s\" in "
514                                 "\"limits <pattern> <limits>\" line.\n",
515                                 fname, lineno, argv[i] );
516 #else
517                         Debug( LDAP_DEBUG_ANY,
518                                 "%s : line %d: unknown limit values \"%s\" in "
519                                 "\"limits <pattern> <limits>\" line.\n",
520                         fname, lineno, argv[i] );
521 #endif
522
523                         return( 1 );
524                 }
525         }
526
527         /*
528          * sanity checks ...
529          */
530         if ( limit.lms_t_hard > 0 && 
531                         ( limit.lms_t_hard < limit.lms_t_soft 
532                           || limit.lms_t_soft == -1 ) ) {
533                 limit.lms_t_hard = limit.lms_t_soft;
534         }
535         
536         if ( limit.lms_s_hard > 0 && 
537                         ( limit.lms_s_hard < limit.lms_s_soft 
538                           || limit.lms_s_soft == -1 ) ) {
539                 limit.lms_s_hard = limit.lms_s_soft;
540         }
541         
542         rc = add_limits( be, flags, pattern, group_oc, group_ad, &limit );
543         if ( rc ) {
544
545 #ifdef NEW_LOGGING
546                 LDAP_LOG( CONFIG, CRIT, 
547                         "%s : line %d: unable to add limit in "
548                         "\"limits <pattern> <limits>\" line.\n",
549                         fname, lineno, 0 );
550 #else
551                 Debug( LDAP_DEBUG_ANY,
552                         "%s : line %d: unable to add limit in "
553                         "\"limits <pattern> <limits>\" line.\n",
554                 fname, lineno, 0 );
555 #endif
556         }
557
558         return( rc );
559 }
560
561 int
562 parse_limit(
563         const char              *arg,
564         struct slap_limits_set  *limit
565 )
566 {
567         assert( arg );
568         assert( limit );
569
570         if ( strncasecmp( arg, "time", sizeof( "time" ) - 1 ) == 0 ) {
571                 arg += 4;
572
573                 if ( arg[0] == '.' ) {
574                         arg++;
575                         if ( strncasecmp( arg, "soft", sizeof( "soft" ) - 1 ) == 0 ) {
576                                 arg += 4;
577                                 if ( arg[0] != '=' ) {
578                                         return( 1 );
579                                 }
580                                 arg++;
581                                 if ( strcasecmp( arg, "none" ) == 0 ) {
582                                         limit->lms_t_soft = -1;
583                                 } else {
584                                         char    *next = NULL;
585
586                                         limit->lms_t_soft = 
587                                                 strtol( arg, &next, 10 );
588                                         if ( next == arg || limit->lms_t_soft < -1 ) {
589                                                 return( 1 );
590                                         }
591                                 }
592                                 
593                         } else if ( strncasecmp( arg, "hard", sizeof( "hard" ) - 1 ) == 0 ) {
594                                 arg += 4;
595                                 if ( arg[0] != '=' ) {
596                                         return( 1 );
597                                 }
598                                 arg++;
599                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
600                                         limit->lms_t_hard = 0;
601                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
602                                         limit->lms_t_hard = -1;
603                                 } else {
604                                         char    *next = NULL;
605
606                                         limit->lms_t_hard = 
607                                                 strtol( arg, &next, 10 );
608                                         if ( next == arg || limit->lms_t_hard < -1 ) {
609                                                 return( 1 );
610                                         }
611                                 }
612                                 
613                         } else {
614                                 return( 1 );
615                         }
616                         
617                 } else if ( arg[0] == '=' ) {
618                         arg++;
619                         if ( strcasecmp( arg, "none" ) == 0 ) {
620                                 limit->lms_t_soft = -1;
621                         } else {
622                                 char    *next = NULL;
623
624                                 limit->lms_t_soft = strtol( arg, &next, 10 );
625                                 if ( next == arg || limit->lms_t_soft < -1 ) {
626                                         return( 1 );
627                                 }
628                         }
629                         limit->lms_t_hard = 0;
630                         
631                 } else {
632                         return( 1 );
633                 }
634
635         } else if ( strncasecmp( arg, "size", sizeof( "size" ) - 1 ) == 0 ) {
636                 arg += 4;
637                 
638                 if ( arg[0] == '.' ) {
639                         arg++;
640                         if ( strncasecmp( arg, "soft", sizeof( "soft" ) - 1 ) == 0 ) {
641                                 arg += 4;
642                                 if ( arg[0] != '=' ) {
643                                         return( 1 );
644                                 }
645                                 arg++;
646                                 if ( strcasecmp( arg, "none" ) == 0 ) {
647                                         limit->lms_s_soft = -1;
648                                 } else {
649                                         char    *next = NULL;
650
651                                         limit->lms_s_soft = 
652                                                 strtol( arg, &next, 10 );
653                                         if ( next == arg || limit->lms_s_soft < -1 ) {
654                                                 return( 1 );
655                                         }
656                                 }
657                                 
658                         } else if ( strncasecmp( arg, "hard", sizeof( "hard" ) - 1 ) == 0 ) {
659                                 arg += 4;
660                                 if ( arg[0] != '=' ) {
661                                         return( 1 );
662                                 }
663                                 arg++;
664                                 if ( strcasecmp( arg, "soft" ) == 0 ) {
665                                         limit->lms_s_hard = 0;
666                                 } else if ( strcasecmp( arg, "none" ) == 0 ) {
667                                         limit->lms_s_hard = -1;
668                                 } else {
669                                         char    *next = NULL;
670
671                                         limit->lms_s_hard = 
672                                                 strtol( arg, &next, 10 );
673                                         if ( next == arg || limit->lms_s_hard < -1 ) {
674                                                 return( 1 );
675                                         }
676                                 }
677                                 
678                         } else if ( strncasecmp( arg, "unchecked", sizeof( "unchecked" ) - 1 ) == 0 ) {
679                                 arg += 9;
680                                 if ( arg[0] != '=' ) {
681                                         return( 1 );
682                                 }
683                                 arg++;
684                                 if ( strcasecmp( arg, "none" ) == 0 ) {
685                                         limit->lms_s_unchecked = -1;
686                                 } else {
687                                         char    *next = NULL;
688
689                                         limit->lms_s_unchecked = 
690                                                 strtol( arg, &next, 10 );
691                                         if ( next == arg || limit->lms_s_unchecked < -1 ) {
692                                                 return( 1 );
693                                         }
694                                 }
695
696                         } else if ( strncasecmp( arg, "pr", sizeof( "pr" ) - 1 ) == 0 ) {
697                                 arg += sizeof( "pr" ) - 1;
698                                 if ( arg[0] != '=' ) {
699                                         return( 1 );
700                                 }
701                                 arg++;
702                                 if ( strcasecmp( arg, "noEstimate" ) == 0 ) {
703                                         limit->lms_s_pr_hide = 1;
704                                 } else {
705                                         char    *next = NULL;
706
707                                         limit->lms_s_pr = 
708                                                 strtol( arg, &next, 10 );
709                                         if ( next == arg || limit->lms_s_pr < -1 ) {
710                                                 return( 1 );
711                                         }
712                                 }
713                                 
714                         } else {
715                                 return( 1 );
716                         }
717                         
718                 } else if ( arg[0] == '=' ) {
719                         arg++;
720                         if ( strcasecmp( arg, "none" ) == 0 ) {
721                                 limit->lms_s_soft = -1;
722                         } else {
723                                 char    *next = NULL;
724
725                                 limit->lms_s_soft = strtol( arg, &next, 10 );
726                                 if ( next == arg || limit->lms_s_soft < -1 ) {
727                                         return( 1 );
728                                 }
729                         }
730                         limit->lms_s_hard = 0;
731                         
732                 } else {
733                         return( 1 );
734                 }
735         }
736
737         return 0;
738 }
739