FreeBSD/usr.sbin/ypldap/aldap.c
/*
 * Translate RFC4515 search filter string into ber_element tree
 *
 * returns:
 *	struct ber_element *, ber_element tree
 *	NULL, parse failed
 *
 * notes:
 *	when cp is passed to a recursive invocation, it is updated
 *	    to point one character beyond the filter that was passed
 *	    i.e., cp jumps to "(filter)" upon return
 *	                               ^
 *	goto's used to discriminate error-handling based on error type
 *	doesn't handle extended filters (yet)
 *
 */
Translate RFC4515 search filter string into ber_element tree
returns:
struct ber_element *, ber_element tree
NULL, parse failed

when cp is passed to a recursive invocation, it is updated
to point one character beyond the filter that was passed
i.e., cp jumps to "(filter)" upon return
^
goto's used to discriminate error-handling based on error type
doesn't handle extended filters (yet)
Translate RFC4515 search filter string into ber_element tree returns : struct ber_element * ber_element tree NULL parse failed when cp is passed to a recursive invocation it is updated to point one character beyond the filter that was passed i . e . cp jumps to " ( filter ) " upon return ^ goto ' s used to discriminate error - handling based on error type doesn ' t handle extended filters ( yet )
static struct ber_element *
ldap_do_parse_search_filter(struct ber_element *prev, char **cpp)
{
	struct ber_element *elm, *root = NULL;
	char *attr_desc, *attr_val, *parsed_val, *cp;
	size_t len;
	unsigned long type;
	root = NULL;
	cp = *cpp;
	if (*cp != '(')
		goto syntaxfail;
	switch (*++cp) {
	case '&':		
	case '|':		
		if (*cp == '&')
			type = LDAP_FILT_AND;
		else
			type = LDAP_FILT_OR;
		if ((elm = ber_add_set(prev)) == NULL)
			goto callfail;
		root = elm;
		ber_set_header(elm, BER_CLASS_CONTEXT, type);
		if (*++cp != '(')		
			goto syntaxfail;
		while (*cp == '(') {
			if ((elm =
			    ldap_do_parse_search_filter(elm, &cp)) == NULL)
				goto bad;
		}
		if (*cp != ')')			
			goto syntaxfail;
		break;
	case '!':		
		if ((root = ber_add_sequence(prev)) == NULL)
			goto callfail;
		ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT);
		cp++;				
		if ((elm = ldap_do_parse_search_filter(root, &cp)) == NULL)
			goto bad;
		if (*cp != ')')			
			goto syntaxfail;
		break;
	default:	
		attr_desc = cp;
		len = strcspn(cp, "()<>~=");
		cp += len;
		switch (*cp) {
		case '~':
			type = LDAP_FILT_APPR;
			cp++;
			break;
		case '<':
			type = LDAP_FILT_LE;
			cp++;
			break;
		case '>':
			type = LDAP_FILT_GE;
			cp++;
			break;
		case '=':
			type = LDAP_FILT_EQ;	
			break;
		case '(':
		case ')':
		default:
			goto syntaxfail;
		}
		attr_val = ++cp;
		if (strncmp(attr_val, "*)", 2) == 0) {
			cp++;			
			if ((root =
			    ber_add_nstring(prev, attr_desc, len)) == NULL)
				goto bad;
			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES);
			break;
		}
		if ((root = ber_add_sequence(prev)) == NULL)
			goto callfail;
		ber_set_header(root, BER_CLASS_CONTEXT, type);
		if ((elm = ber_add_nstring(root, attr_desc, len)) == NULL)
			goto callfail;
		len = strcspn(attr_val, "*)");
		if (len == 0 && *cp != '*')
			goto syntaxfail;
		cp += len;
		if (*cp == '\0')
			goto syntaxfail;
		if (*cp == '*') {	
			int initial;
			cp = attr_val;
			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS);
			if ((elm = ber_add_sequence(elm)) == NULL)
				goto callfail;
			for (initial = 1;; cp++, initial = 0) {
				attr_val = cp;
				len = strcspn(attr_val, "*)");
				if (len == 0) {
					if (*cp == ')')
						break;
					else
						continue;
				}
				cp += len;
				if (*cp == '\0')
					goto syntaxfail;
				if (initial)
					type = LDAP_FILT_SUBS_INIT;
				else if (*cp == ')')
					type = LDAP_FILT_SUBS_FIN;
				else
					type = LDAP_FILT_SUBS_ANY;
				if ((parsed_val = parseval(attr_val, len)) ==
				    NULL)
					goto callfail;
				elm = ber_add_nstring(elm, parsed_val,
				    strlen(parsed_val));
				free(parsed_val);
				if (elm == NULL)
					goto callfail;
				ber_set_header(elm, BER_CLASS_CONTEXT, type);
				if (type == LDAP_FILT_SUBS_FIN)
					break;
			}
			break;
		}
		if ((parsed_val = parseval(attr_val, len)) == NULL)
			goto callfail;
		elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val));
		free(parsed_val);
		if (elm == NULL)
			goto callfail;
		break;
	}
	cp++;		
	*cpp = cp;
	return (root);
syntaxfail:		
callfail:
bad:
	if (root != NULL)
		ber_free_elements(root);
	ber_link_elements(prev, NULL);
	return (NULL);
}
static struct ber_element * ldap_do_parse_search_filter ( struct ber_element * prev , char * * cpp ) { struct ber_element * elm , * root = NULL ; char * attr_desc , * attr_val , * parsed_val , * cp ; size_t len ; unsigned long type ; root = NULL ; cp = * cpp ; if ( * cp != ' ' ) goto syntaxfail ; switch ( * ++ cp ) { case ' ' : case ' ' : if ( * cp == ' ' ) type = LDAP_FILT_AND ; else type = LDAP_FILT_OR ; if ( ( elm = ber_add_set ( prev ) ) == NULL ) goto callfail ; root = elm ; ber_set_header ( elm , BER_CLASS_CONTEXT , type ) ; if ( * ++ cp != ' ' ) goto syntaxfail ; while ( * cp == ' ' ) { if ( ( elm = ldap_do_parse_search_filter ( elm , & cp ) ) == NULL ) goto bad ; } if ( * cp != ' ' ) goto syntaxfail ; break ; case ' ' : if ( ( root = ber_add_sequence ( prev ) ) == NULL ) goto callfail ; ber_set_header ( root , BER_CLASS_CONTEXT , LDAP_FILT_NOT ) ; cp ++ ; if ( ( elm = ldap_do_parse_search_filter ( root , & cp ) ) == NULL ) goto bad ; if ( * cp != ' ' ) goto syntaxfail ; break ; default : attr_desc = cp ; len = strcspn ( cp , " " ) ; cp += len ; switch ( * cp ) { case ' ' : type = LDAP_FILT_APPR ; cp ++ ; break ; case ' ' : type = LDAP_FILT_LE ; cp ++ ; break ; case ' ' : type = LDAP_FILT_GE ; cp ++ ; break ; case ' ' : type = LDAP_FILT_EQ ; break ; case ' ' : case ' ' : default : goto syntaxfail ; } attr_val = ++ cp ; if ( strncmp ( attr_val , " " , 2 ) == 0 ) { cp ++ ; if ( ( root = ber_add_nstring ( prev , attr_desc , len ) ) == NULL ) goto bad ; ber_set_header ( root , BER_CLASS_CONTEXT , LDAP_FILT_PRES ) ; break ; } if ( ( root = ber_add_sequence ( prev ) ) == NULL ) goto callfail ; ber_set_header ( root , BER_CLASS_CONTEXT , type ) ; if ( ( elm = ber_add_nstring ( root , attr_desc , len ) ) == NULL ) goto callfail ; len = strcspn ( attr_val , " " ) ; if ( len == 0 && * cp != ' ' ) goto syntaxfail ; cp += len ; if ( * cp == ' \0 ' ) goto syntaxfail ; if ( * cp == ' ' ) { int initial ; cp = attr_val ; ber_set_header ( root , BER_CLASS_CONTEXT , LDAP_FILT_SUBS ) ; if ( ( elm = ber_add_sequence ( elm ) ) == NULL ) goto callfail ; for ( initial = 1 ; ; cp ++ , initial = 0 ) { attr_val = cp ; len = strcspn ( attr_val , " " ) ; if ( len == 0 ) { if ( * cp == ' ' ) break ; else continue ; } cp += len ; if ( * cp == ' \0 ' ) goto syntaxfail ; if ( initial ) type = LDAP_FILT_SUBS_INIT ; else if ( * cp == ' ' ) type = LDAP_FILT_SUBS_FIN ; else type = LDAP_FILT_SUBS_ANY ; if ( ( parsed_val = parseval ( attr_val , len ) ) == NULL ) goto callfail ; elm = ber_add_nstring ( elm , parsed_val , strlen ( parsed_val ) ) ; free ( parsed_val ) ; if ( elm == NULL ) goto callfail ; ber_set_header ( elm , BER_CLASS_CONTEXT , type ) ; if ( type == LDAP_FILT_SUBS_FIN ) break ; } break ; } if ( ( parsed_val = parseval ( attr_val , len ) ) == NULL ) goto callfail ; elm = ber_add_nstring ( elm , parsed_val , strlen ( parsed_val ) ) ; free ( parsed_val ) ; if ( elm == NULL ) goto callfail ; break ; } cp ++ ; * cpp = cp ; return ( root ) ; syntaxfail : callfail : bad : if ( root != NULL ) ber_free_elements ( root ) ; ber_link_elements ( prev , NULL ) ; return ( NULL ) ; }
Translate RFC4515 search filter string into ber_element tree
 returns:
      struct ber_element *, ber_element tree
      NULL, parse failed
Translate RFC4515 search filter string into ber_element tree returns : struct ber_element * ber_element tree NULL parse failed
/* cpp should pass in pointer to opening parenthesis of "(filter)" */ /* AND */ /* OR */ /* opening `(` of filter */ /* trailing `)` of filter */ /* NOT */ /* now points to sub-filter */ /* trailing `)` of filter */ /* SIMPLE || PRESENCE */ /* assume EQ until disproven */ /* presence filter */ /* point to trailing `)` */ /* substring filter */ /* now points one char beyond the trailing `)` */ /* XXX -- error reporting */