1 /* $NetBSD: filter.c,v 1.3 2021/08/14 16:14:56 christos Exp $ */
2
3 /* search.c */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
19 * All rights reserved.
20 */
21
22 #include <sys/cdefs.h>
23 __RCSID("$NetBSD: filter.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
24
25 #include "portable.h"
26
27 #include <stdio.h>
28
29 #include <ac/stdlib.h>
30
31 #include <ac/socket.h>
32 #include <ac/string.h>
33 #include <ac/time.h>
34
35 #include "ldap-int.h"
36
37 static int put_simple_vrFilter LDAP_P((
38 BerElement *ber,
39 char *str ));
40
41 static int put_vrFilter_list LDAP_P((
42 BerElement *ber,
43 char *str ));
44
45 static char *put_complex_filter LDAP_P((
46 BerElement *ber,
47 char *str,
48 ber_tag_t tag,
49 int not ));
50
51 static int put_simple_filter LDAP_P((
52 BerElement *ber,
53 char *str ));
54
55 static int put_substring_filter LDAP_P((
56 BerElement *ber,
57 char *type,
58 char *str,
59 char *nextstar ));
60
61 static int put_filter_list LDAP_P((
62 BerElement *ber,
63 char *str,
64 ber_tag_t tag ));
65
ldap_is_oid(const char * str)66 static int ldap_is_oid ( const char *str )
67 {
68 int i;
69
70 if( LDAP_ALPHA( str[0] )) {
71 for( i=1; str[i]; i++ ) {
72 if( !LDAP_LDH( str[i] )) {
73 return 0;
74 }
75 }
76 return 1;
77
78 } else if LDAP_DIGIT( str[0] ) {
79 int dot=0;
80 for( i=1; str[i]; i++ ) {
81 if( LDAP_DIGIT( str[i] )) {
82 dot=0;
83
84 } else if ( str[i] == '.' ) {
85 if( ++dot > 1 ) return 0;
86
87 } else {
88 return 0;
89 }
90 }
91 return !dot;
92 }
93
94 return 0;
95 }
96
ldap_is_desc(const char * str)97 static int ldap_is_desc ( const char *str )
98 {
99 int i;
100
101 if( LDAP_ALPHA( str[0] )) {
102 for( i=1; str[i]; i++ ) {
103 if( str[i] == ';' ) {
104 str = &str[i+1];
105 goto options;
106 }
107
108 if( !LDAP_LDH( str[i] )) {
109 return 0;
110 }
111 }
112 return 1;
113
114 } else if LDAP_DIGIT( str[0] ) {
115 int dot=0;
116 for( i=1; str[i]; i++ ) {
117 if( str[i] == ';' ) {
118 if( dot ) return 0;
119 str = &str[i+1];
120 goto options;
121 }
122
123 if( LDAP_DIGIT( str[i] )) {
124 dot=0;
125
126 } else if ( str[i] == '.' ) {
127 if( ++dot > 1 ) return 0;
128
129 } else {
130 return 0;
131 }
132 }
133 return !dot;
134 }
135
136 return 0;
137
138 options:
139 if( !LDAP_LDH( str[0] )) {
140 return 0;
141 }
142 for( i=1; str[i]; i++ ) {
143 if( str[i] == ';' ) {
144 str = &str[i+1];
145 goto options;
146 }
147 if( !LDAP_LDH( str[i] )) {
148 return 0;
149 }
150 }
151 return 1;
152 }
153
154 static char *
find_right_paren(char * s)155 find_right_paren( char *s )
156 {
157 int balance, escape;
158
159 balance = 1;
160 escape = 0;
161 while ( *s && balance ) {
162 if ( !escape ) {
163 if ( *s == '(' ) {
164 balance++;
165 } else if ( *s == ')' ) {
166 balance--;
167 }
168 }
169
170 escape = ( *s == '\\' && !escape );
171
172 if ( balance ) s++;
173 }
174
175 return *s ? s : NULL;
176 }
177
hex2value(int c)178 static int hex2value( int c )
179 {
180 if( c >= '0' && c <= '9' ) {
181 return c - '0';
182 }
183
184 if( c >= 'A' && c <= 'F' ) {
185 return c + (10 - (int) 'A');
186 }
187
188 if( c >= 'a' && c <= 'f' ) {
189 return c + (10 - (int) 'a');
190 }
191
192 return -1;
193 }
194
195 char *
ldap_pvt_find_wildcard(const char * s)196 ldap_pvt_find_wildcard( const char *s )
197 {
198 for( ; *s; s++ ) {
199 switch( *s ) {
200 case '*': /* found wildcard */
201 return (char *) s;
202
203 case '(':
204 case ')':
205 return NULL;
206
207 case '\\':
208 if( s[1] == '\0' ) return NULL;
209
210 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
211 s+=2;
212
213 } else switch( s[1] ) {
214 default:
215 return NULL;
216
217 /* allow RFC 1960 escapes */
218 case '*':
219 case '(':
220 case ')':
221 case '\\':
222 s++;
223 }
224 }
225 }
226
227 return (char *) s;
228 }
229
230 /* unescape filter value */
231 /* support both LDAP v2 and v3 escapes */
232 /* output can include nul characters! */
233 ber_slen_t
ldap_pvt_filter_value_unescape(char * fval)234 ldap_pvt_filter_value_unescape( char *fval )
235 {
236 ber_slen_t r, v;
237 int v1, v2;
238
239 for( r=v=0; fval[v] != '\0'; v++ ) {
240 switch( fval[v] ) {
241 case '(':
242 case ')':
243 case '*':
244 return -1;
245
246 case '\\':
247 /* escape */
248 v++;
249
250 if ( fval[v] == '\0' ) {
251 /* escape at end of string */
252 return -1;
253 }
254
255 if (( v1 = hex2value( fval[v] )) >= 0 ) {
256 /* LDAPv3 escape */
257 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
258 /* must be two digit code */
259 return -1;
260 }
261
262 fval[r++] = v1 * 16 + v2;
263 v++;
264
265 } else {
266 /* LDAPv2 escape */
267 switch( fval[v] ) {
268 case '(':
269 case ')':
270 case '*':
271 case '\\':
272 fval[r++] = fval[v];
273 break;
274 default:
275 /* illegal escape */
276 return -1;
277 }
278 }
279 break;
280
281 default:
282 fval[r++] = fval[v];
283 }
284 }
285
286 fval[r] = '\0';
287 return r;
288 }
289
290 static char *
put_complex_filter(BerElement * ber,char * str,ber_tag_t tag,int not)291 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
292 {
293 char *next;
294
295 /*
296 * We have (x(filter)...) with str sitting on
297 * the x. We have to find the paren matching
298 * the one before the x and put the intervening
299 * filters by calling put_filter_list().
300 */
301
302 /* put explicit tag */
303 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
304 return NULL;
305 }
306
307 str++;
308 if ( (next = find_right_paren( str )) == NULL ) {
309 return NULL;
310 }
311
312 *next = '\0';
313 if ( put_filter_list( ber, str, tag ) == -1 ) {
314 return NULL;
315 }
316
317 /* close the '(' */
318 *next++ = ')';
319
320 /* flush explicit tagged thang */
321 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
322 return NULL;
323 }
324
325 return next;
326 }
327
328 int
ldap_pvt_put_filter(BerElement * ber,const char * str_in)329 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
330 {
331 int rc;
332 char *freeme;
333 char *str;
334 char *next;
335 int parens, balance, escape;
336
337 /*
338 * A Filter looks like this (RFC 4511 as extended by RFC 4526):
339 * Filter ::= CHOICE {
340 * and [0] SET SIZE (0..MAX) OF filter Filter,
341 * or [1] SET SIZE (0..MAX) OF filter Filter,
342 * not [2] Filter,
343 * equalityMatch [3] AttributeValueAssertion,
344 * substrings [4] SubstringFilter,
345 * greaterOrEqual [5] AttributeValueAssertion,
346 * lessOrEqual [6] AttributeValueAssertion,
347 * present [7] AttributeDescription,
348 * approxMatch [8] AttributeValueAssertion,
349 * extensibleMatch [9] MatchingRuleAssertion,
350 * ... }
351 *
352 * SubstringFilter ::= SEQUENCE {
353 * type AttributeDescription,
354 * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
355 * initial [0] AssertionValue, -- only once
356 * any [1] AssertionValue,
357 * final [2] AssertionValue -- only once
358 * }
359 * }
360 *
361 * MatchingRuleAssertion ::= SEQUENCE {
362 * matchingRule [1] MatchingRuleId OPTIONAL,
363 * type [2] AttributeDescription OPTIONAL,
364 * matchValue [3] AssertionValue,
365 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
366 *
367 * Note: tags in a CHOICE are always explicit
368 */
369
370 Debug1( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in );
371
372 freeme = LDAP_STRDUP( str_in );
373 if( freeme == NULL ) return LDAP_NO_MEMORY;
374 str = freeme;
375
376 parens = 0;
377 while ( *str ) {
378 switch ( *str ) {
379 case '(': /*')'*/
380 str++;
381 parens++;
382
383 /* skip spaces */
384 while( LDAP_SPACE( *str ) ) str++;
385
386 switch ( *str ) {
387 case '&':
388 Debug0( LDAP_DEBUG_TRACE, "put_filter: AND\n" );
389
390 str = put_complex_filter( ber, str,
391 LDAP_FILTER_AND, 0 );
392 if( str == NULL ) {
393 rc = -1;
394 goto done;
395 }
396
397 parens--;
398 break;
399
400 case '|':
401 Debug0( LDAP_DEBUG_TRACE, "put_filter: OR\n" );
402
403 str = put_complex_filter( ber, str,
404 LDAP_FILTER_OR, 0 );
405 if( str == NULL ) {
406 rc = -1;
407 goto done;
408 }
409
410 parens--;
411 break;
412
413 case '!':
414 Debug0( LDAP_DEBUG_TRACE, "put_filter: NOT\n" );
415
416 str = put_complex_filter( ber, str,
417 LDAP_FILTER_NOT, 0 );
418 if( str == NULL ) {
419 rc = -1;
420 goto done;
421 }
422
423 parens--;
424 break;
425
426 case '(':
427 rc = -1;
428 goto done;
429
430 default:
431 Debug0( LDAP_DEBUG_TRACE, "put_filter: simple\n" );
432
433 balance = 1;
434 escape = 0;
435 next = str;
436
437 while ( *next && balance ) {
438 if ( escape == 0 ) {
439 if ( *next == '(' ) {
440 balance++;
441 } else if ( *next == ')' ) {
442 balance--;
443 }
444 }
445
446 if ( *next == '\\' && ! escape ) {
447 escape = 1;
448 } else {
449 escape = 0;
450 }
451
452 if ( balance ) next++;
453 }
454
455 if ( balance != 0 ) {
456 rc = -1;
457 goto done;
458 }
459
460 *next = '\0';
461
462 if ( put_simple_filter( ber, str ) == -1 ) {
463 rc = -1;
464 goto done;
465 }
466
467 *next++ = /*'('*/ ')';
468
469 str = next;
470 parens--;
471 break;
472 }
473 break;
474
475 case /*'('*/ ')':
476 Debug0( LDAP_DEBUG_TRACE, "put_filter: end\n" );
477 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
478 rc = -1;
479 goto done;
480 }
481 str++;
482 parens--;
483 break;
484
485 case ' ':
486 str++;
487 break;
488
489 default: /* assume it's a simple type=value filter */
490 Debug0( LDAP_DEBUG_TRACE, "put_filter: default\n" );
491 next = strchr( str, '\0' );
492 if ( put_simple_filter( ber, str ) == -1 ) {
493 rc = -1;
494 goto done;
495 }
496 str = next;
497 break;
498 }
499 if ( !parens )
500 break;
501 }
502
503 rc = ( parens || *str ) ? -1 : 0;
504
505 done:
506 LDAP_FREE( freeme );
507 return rc;
508 }
509
510 /*
511 * Put a list of filters like this "(filter1)(filter2)..."
512 */
513
514 static int
put_filter_list(BerElement * ber,char * str,ber_tag_t tag)515 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
516 {
517 char *next = NULL;
518 char save;
519
520 Debug1( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
521 str );
522
523 while ( *str ) {
524 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
525 str++;
526 }
527 if ( *str == '\0' ) break;
528
529 if ( (next = find_right_paren( str + 1 )) == NULL ) {
530 return -1;
531 }
532 save = *++next;
533
534 /* now we have "(filter)" with str pointing to it */
535 *next = '\0';
536 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
537 *next = save;
538 str = next;
539
540 if( tag == LDAP_FILTER_NOT ) break;
541 }
542
543 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
544 return -1;
545 }
546
547 return 0;
548 }
549
550 static int
put_simple_filter(BerElement * ber,char * str)551 put_simple_filter(
552 BerElement *ber,
553 char *str )
554 {
555 char *s;
556 char *value;
557 ber_tag_t ftype;
558 int rc = -1;
559
560 Debug1( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
561 str );
562
563 str = LDAP_STRDUP( str );
564 if( str == NULL ) return -1;
565
566 if ( (s = strchr( str, '=' )) == NULL ) {
567 goto done;
568 }
569
570 value = s + 1;
571 *s-- = '\0';
572
573 switch ( *s ) {
574 case '<':
575 ftype = LDAP_FILTER_LE;
576 *s = '\0';
577 break;
578
579 case '>':
580 ftype = LDAP_FILTER_GE;
581 *s = '\0';
582 break;
583
584 case '~':
585 ftype = LDAP_FILTER_APPROX;
586 *s = '\0';
587 break;
588
589 case ':':
590 /* RFC 4515 extensible filters are off the form:
591 * type [:dn] [:rule] := value
592 * or [:dn]:rule := value
593 */
594 ftype = LDAP_FILTER_EXT;
595 *s = '\0';
596
597 {
598 char *dn = strchr( str, ':' );
599 char *rule = NULL;
600
601 if( dn != NULL ) {
602 *dn++ = '\0';
603 rule = strchr( dn, ':' );
604
605 if( rule == NULL ) {
606 /* one colon */
607 if ( strcasecmp(dn, "dn") == 0 ) {
608 /* must have attribute */
609 if( !ldap_is_desc( str ) ) {
610 goto done;
611 }
612
613 rule = "";
614
615 } else {
616 rule = dn;
617 dn = NULL;
618 }
619
620 } else {
621 /* two colons */
622 *rule++ = '\0';
623
624 if ( strcasecmp(dn, "dn") != 0 ) {
625 /* must have "dn" */
626 goto done;
627 }
628 }
629
630 }
631
632 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
633 /* must have either type or rule */
634 goto done;
635 }
636
637 if ( *str != '\0' && !ldap_is_desc( str ) ) {
638 goto done;
639 }
640
641 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
642 goto done;
643 }
644
645 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
646
647 if( rc != -1 && rule && *rule != '\0' ) {
648 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
649 }
650
651 if( rc != -1 && *str != '\0' ) {
652 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
653 }
654
655 if( rc != -1 ) {
656 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
657
658 if( len >= 0 ) {
659 rc = ber_printf( ber, "to",
660 LDAP_FILTER_EXT_VALUE, value, len );
661 } else {
662 rc = -1;
663 }
664 }
665
666 if( rc != -1 && dn ) {
667 rc = ber_printf( ber, "tb",
668 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
669 }
670
671 if( rc != -1 ) {
672 rc = ber_printf( ber, /*"{"*/ "N}" );
673 }
674 }
675 goto done;
676
677 default:
678 if( !ldap_is_desc( str ) ) {
679 goto done;
680
681 } else {
682 char *nextstar = ldap_pvt_find_wildcard( value );
683
684 if ( nextstar == NULL ) {
685 goto done;
686
687 } else if ( *nextstar == '\0' ) {
688 ftype = LDAP_FILTER_EQUALITY;
689
690 } else if ( strcmp( value, "*" ) == 0 ) {
691 ftype = LDAP_FILTER_PRESENT;
692
693 } else {
694 rc = put_substring_filter( ber, str, value, nextstar );
695 goto done;
696 }
697 } break;
698 }
699
700 if( !ldap_is_desc( str ) ) goto done;
701
702 if ( ftype == LDAP_FILTER_PRESENT ) {
703 rc = ber_printf( ber, "ts", ftype, str );
704
705 } else {
706 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
707
708 if( len >= 0 ) {
709 rc = ber_printf( ber, "t{soN}",
710 ftype, str, value, len );
711 }
712 }
713
714 done:
715 if( rc != -1 ) rc = 0;
716 LDAP_FREE( str );
717 return rc;
718 }
719
720 static int
put_substring_filter(BerElement * ber,char * type,char * val,char * nextstar)721 put_substring_filter( BerElement *ber, char *type, char *val, char *nextstar )
722 {
723 int gotstar = 0;
724 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
725
726 Debug2( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
727 type, val );
728
729 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
730 return -1;
731 }
732
733 for( ; *val; val=nextstar ) {
734 if ( gotstar )
735 nextstar = ldap_pvt_find_wildcard( val );
736
737 if ( nextstar == NULL ) {
738 return -1;
739 }
740
741 if ( *nextstar == '\0' ) {
742 ftype = LDAP_SUBSTRING_FINAL;
743 } else {
744 *nextstar++ = '\0';
745 if ( gotstar++ == 0 ) {
746 ftype = LDAP_SUBSTRING_INITIAL;
747 } else {
748 ftype = LDAP_SUBSTRING_ANY;
749 }
750 }
751
752 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
753 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
754
755 if ( len <= 0 ) {
756 return -1;
757 }
758
759 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
760 return -1;
761 }
762 }
763 }
764
765 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
766 return -1;
767 }
768
769 return 0;
770 }
771
772 static int
put_vrFilter(BerElement * ber,const char * str_in)773 put_vrFilter( BerElement *ber, const char *str_in )
774 {
775 int rc;
776 char *freeme;
777 char *str;
778 char *next;
779 int parens, balance, escape;
780
781 /*
782 * A ValuesReturnFilter looks like this:
783 *
784 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
785 * SimpleFilterItem ::= CHOICE {
786 * equalityMatch [3] AttributeValueAssertion,
787 * substrings [4] SubstringFilter,
788 * greaterOrEqual [5] AttributeValueAssertion,
789 * lessOrEqual [6] AttributeValueAssertion,
790 * present [7] AttributeType,
791 * approxMatch [8] AttributeValueAssertion,
792 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
793 * }
794 *
795 * SubstringFilter ::= SEQUENCE {
796 * type AttributeType,
797 * SEQUENCE OF CHOICE {
798 * initial [0] IA5String,
799 * any [1] IA5String,
800 * final [2] IA5String
801 * }
802 * }
803 *
804 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
805 * matchingRule [1] MatchingRuleId OPTIONAL,
806 * type [2] AttributeDescription OPTIONAL,
807 * matchValue [3] AssertionValue }
808 *
809 * (Source: RFC 3876)
810 */
811
812 Debug1( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in );
813
814 freeme = LDAP_STRDUP( str_in );
815 if( freeme == NULL ) return LDAP_NO_MEMORY;
816 str = freeme;
817
818 parens = 0;
819 while ( *str ) {
820 switch ( *str ) {
821 case '(': /*')'*/
822 str++;
823 parens++;
824
825 /* skip spaces */
826 while( LDAP_SPACE( *str ) ) str++;
827
828 switch ( *str ) {
829 case '(':
830 if ( (next = find_right_paren( str )) == NULL ) {
831 rc = -1;
832 goto done;
833 }
834
835 *next = '\0';
836
837 if ( put_vrFilter_list( ber, str ) == -1 ) {
838 rc = -1;
839 goto done;
840 }
841
842 /* close the '(' */
843 *next++ = ')';
844
845 str = next;
846
847 parens--;
848 break;
849
850
851 default:
852 Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n" );
853
854 balance = 1;
855 escape = 0;
856 next = str;
857
858 while ( *next && balance ) {
859 if ( escape == 0 ) {
860 if ( *next == '(' ) {
861 balance++;
862 } else if ( *next == ')' ) {
863 balance--;
864 }
865 }
866
867 if ( *next == '\\' && ! escape ) {
868 escape = 1;
869 } else {
870 escape = 0;
871 }
872
873 if ( balance ) next++;
874 }
875
876 if ( balance != 0 ) {
877 rc = -1;
878 goto done;
879 }
880
881 *next = '\0';
882
883 if ( put_simple_vrFilter( ber, str ) == -1 ) {
884 rc = -1;
885 goto done;
886 }
887
888 *next++ = /*'('*/ ')';
889
890 str = next;
891 parens--;
892 break;
893 }
894 break;
895
896 case /*'('*/ ')':
897 Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: end\n" );
898 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
899 rc = -1;
900 goto done;
901 }
902 str++;
903 parens--;
904 break;
905
906 case ' ':
907 str++;
908 break;
909
910 default: /* assume it's a simple type=value filter */
911 Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: default\n" );
912 next = strchr( str, '\0' );
913 if ( put_simple_vrFilter( ber, str ) == -1 ) {
914 rc = -1;
915 goto done;
916 }
917 str = next;
918 break;
919 }
920 }
921
922 rc = parens ? -1 : 0;
923
924 done:
925 LDAP_FREE( freeme );
926 return rc;
927 }
928
929 int
ldap_put_vrFilter(BerElement * ber,const char * str_in)930 ldap_put_vrFilter( BerElement *ber, const char *str_in )
931 {
932 int rc =0;
933
934 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
935 return -1;
936 }
937
938 rc = put_vrFilter( ber, str_in );
939
940 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
941 rc = -1;
942 }
943
944 return rc;
945 }
946
947 static int
put_vrFilter_list(BerElement * ber,char * str)948 put_vrFilter_list( BerElement *ber, char *str )
949 {
950 char *next = NULL;
951 char save;
952
953 Debug1( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
954 str );
955
956 while ( *str ) {
957 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
958 str++;
959 }
960 if ( *str == '\0' ) break;
961
962 if ( (next = find_right_paren( str + 1 )) == NULL ) {
963 return -1;
964 }
965 save = *++next;
966
967 /* now we have "(filter)" with str pointing to it */
968 *next = '\0';
969 if ( put_vrFilter( ber, str ) == -1 ) return -1;
970 *next = save;
971 str = next;
972 }
973
974 return 0;
975 }
976
977 static int
put_simple_vrFilter(BerElement * ber,char * str)978 put_simple_vrFilter(
979 BerElement *ber,
980 char *str )
981 {
982 char *s;
983 char *value;
984 ber_tag_t ftype;
985 int rc = -1;
986
987 Debug1( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
988 str );
989
990 str = LDAP_STRDUP( str );
991 if( str == NULL ) return -1;
992
993 if ( (s = strchr( str, '=' )) == NULL ) {
994 goto done;
995 }
996
997 value = s + 1;
998 *s-- = '\0';
999
1000 switch ( *s ) {
1001 case '<':
1002 ftype = LDAP_FILTER_LE;
1003 *s = '\0';
1004 break;
1005
1006 case '>':
1007 ftype = LDAP_FILTER_GE;
1008 *s = '\0';
1009 break;
1010
1011 case '~':
1012 ftype = LDAP_FILTER_APPROX;
1013 *s = '\0';
1014 break;
1015
1016 case ':':
1017 /* According to ValuesReturnFilter control definition
1018 * extensible filters are off the form:
1019 * type [:rule] := value
1020 * or :rule := value
1021 */
1022 ftype = LDAP_FILTER_EXT;
1023 *s = '\0';
1024
1025 {
1026 char *rule = strchr( str, ':' );
1027
1028 if( rule == NULL ) {
1029 /* must have attribute */
1030 if( !ldap_is_desc( str ) ) {
1031 goto done;
1032 }
1033 rule = "";
1034 } else {
1035 *rule++ = '\0';
1036 }
1037
1038 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1039 /* must have either type or rule */
1040 goto done;
1041 }
1042
1043 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1044 goto done;
1045 }
1046
1047 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1048 goto done;
1049 }
1050
1051 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1052
1053 if( rc != -1 && rule && *rule != '\0' ) {
1054 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1055 }
1056
1057 if( rc != -1 && *str != '\0' ) {
1058 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1059 }
1060
1061 if( rc != -1 ) {
1062 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1063
1064 if( len >= 0 ) {
1065 rc = ber_printf( ber, "to",
1066 LDAP_FILTER_EXT_VALUE, value, len );
1067 } else {
1068 rc = -1;
1069 }
1070 }
1071
1072 if( rc != -1 ) {
1073 rc = ber_printf( ber, /*"{"*/ "N}" );
1074 }
1075 }
1076 goto done;
1077
1078 default:
1079 if( !ldap_is_desc( str ) ) {
1080 goto done;
1081
1082 } else {
1083 char *nextstar = ldap_pvt_find_wildcard( value );
1084
1085 if ( nextstar == NULL ) {
1086 goto done;
1087
1088 } else if ( *nextstar == '\0' ) {
1089 ftype = LDAP_FILTER_EQUALITY;
1090
1091 } else if ( strcmp( value, "*" ) == 0 ) {
1092 ftype = LDAP_FILTER_PRESENT;
1093
1094 } else {
1095 rc = put_substring_filter( ber, str, value, nextstar );
1096 goto done;
1097 }
1098 } break;
1099 }
1100
1101 if( !ldap_is_desc( str ) ) goto done;
1102
1103 if ( ftype == LDAP_FILTER_PRESENT ) {
1104 rc = ber_printf( ber, "ts", ftype, str );
1105
1106 } else {
1107 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1108
1109 if( len >= 0 ) {
1110 rc = ber_printf( ber, "t{soN}",
1111 ftype, str, value, len );
1112 }
1113 }
1114
1115 done:
1116 if( rc != -1 ) rc = 0;
1117 LDAP_FREE( str );
1118 return rc;
1119 }
1120
1121