xref: /openbsd-src/usr.sbin/ldapd/filter.c (revision 696b58997f75587bd78112ed0b6cdec94a718911)
1*696b5899Stb /*	$OpenBSD: filter.c,v 1.9 2019/10/24 12:39:26 tb Exp $ */
25d465952Smartinh 
35d465952Smartinh /*
4012bb0c9Smartinh  * Copyright (c) 2009, 2010 Martin Hedenfalk <martinh@openbsd.org>
55d465952Smartinh  *
65d465952Smartinh  * Permission to use, copy, modify, and distribute this software for any
75d465952Smartinh  * purpose with or without fee is hereby granted, provided that the above
85d465952Smartinh  * copyright notice and this permission notice appear in all copies.
95d465952Smartinh  *
105d465952Smartinh  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
115d465952Smartinh  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
125d465952Smartinh  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
135d465952Smartinh  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
145d465952Smartinh  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
155d465952Smartinh  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
165d465952Smartinh  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
175d465952Smartinh  */
185d465952Smartinh 
195d465952Smartinh #include <sys/queue.h>
205d465952Smartinh #include <sys/types.h>
215d465952Smartinh 
225d465952Smartinh #include <string.h>
235d465952Smartinh #include <stdint.h>
245d465952Smartinh 
255d465952Smartinh #include "ldapd.h"
26fdd30f56Sbenno #include "log.h"
275d465952Smartinh 
28012bb0c9Smartinh static int	 ldap_filt_eq(struct ber_element *root, struct plan *plan);
29012bb0c9Smartinh static int	 ldap_filt_subs(struct ber_element *root, struct plan *plan);
30012bb0c9Smartinh static int	 ldap_filt_and(struct ber_element *root, struct plan *plan);
31012bb0c9Smartinh static int	 ldap_filt_or(struct ber_element *root, struct plan *plan);
32012bb0c9Smartinh static int	 ldap_filt_not(struct ber_element *root, struct plan *plan);
335d465952Smartinh 
345d465952Smartinh static int
ldap_filt_eq(struct ber_element * root,struct plan * plan)35012bb0c9Smartinh ldap_filt_eq(struct ber_element *root, struct plan *plan)
365d465952Smartinh {
37012bb0c9Smartinh 	char			*vs;
385d465952Smartinh 	struct ber_element	*a, *vals, *v;
395d465952Smartinh 
404103e180Sclaudio 	if (plan->undefined)
414103e180Sclaudio 		return -1;
424103e180Sclaudio 	else if (plan->adesc != NULL)
43012bb0c9Smartinh 		a = ldap_get_attribute(root, plan->adesc);
44012bb0c9Smartinh 	else
45012bb0c9Smartinh 		a = ldap_find_attribute(root, plan->at);
465d465952Smartinh 	if (a == NULL) {
4729a937b2Sclaudio 		log_debug("no attribute [%s] found",
4829a937b2Sclaudio 		    plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
495d465952Smartinh 		return -1;
505d465952Smartinh 	}
515d465952Smartinh 
525d465952Smartinh 	vals = a->be_next;
535d465952Smartinh 	if (vals == NULL)
545d465952Smartinh 		return -1;
555d465952Smartinh 
565d465952Smartinh 	for (v = vals->be_sub; v; v = v->be_next) {
57*696b5899Stb 		if (ober_get_string(v, &vs) != 0)
585d465952Smartinh 			continue;
59012bb0c9Smartinh 		if (strcasecmp(plan->assert.value, vs) == 0)
605d465952Smartinh 			return 0;
615d465952Smartinh 	}
625d465952Smartinh 
635d465952Smartinh 	return -1;
645d465952Smartinh }
655d465952Smartinh 
665d465952Smartinh static int
ldap_filt_subs_value(struct ber_element * v,struct ber_element * sub)675d465952Smartinh ldap_filt_subs_value(struct ber_element *v, struct ber_element *sub)
685d465952Smartinh {
695d465952Smartinh 	int		 class;
70f9444383Sclaudio 	unsigned int	 type;
715d465952Smartinh 	const char	*cmpval;
725d465952Smartinh 	char		*vs, *p, *end;
735d465952Smartinh 
74*696b5899Stb 	if (ober_get_string(v, &vs) != 0)
755d465952Smartinh 		return -1;
765d465952Smartinh 
775d465952Smartinh 	for (; sub; sub = sub->be_next) {
78*696b5899Stb 		if (ober_scanf_elements(sub, "ts", &class, &type, &cmpval) != 0)
795d465952Smartinh 			return -1;
805d465952Smartinh 
815d465952Smartinh 		if (class != BER_CLASS_CONTEXT)
825d465952Smartinh 			return -1;
835d465952Smartinh 
845d465952Smartinh 		switch (type) {
855d465952Smartinh 		case LDAP_FILT_SUBS_INIT:
865d465952Smartinh 			if (strncasecmp(cmpval, vs, strlen(cmpval)) == 0)
875d465952Smartinh 				vs += strlen(cmpval);
885d465952Smartinh 			else
895d465952Smartinh 				return 1; /* no match */
905d465952Smartinh 			break;
915d465952Smartinh 		case LDAP_FILT_SUBS_ANY:
925d465952Smartinh 			if ((p = strcasestr(vs, cmpval)) != NULL)
935d465952Smartinh 				vs = p + strlen(cmpval);
945d465952Smartinh 			else
955d465952Smartinh 				return 1; /* no match */
965d465952Smartinh 			break;
975d465952Smartinh 		case LDAP_FILT_SUBS_FIN:
985d465952Smartinh 			if (strlen(vs) < strlen(cmpval))
995d465952Smartinh 				return 1; /* no match */
1005d465952Smartinh 			end = vs + strlen(vs) - strlen(cmpval);
1015d465952Smartinh 			if (strcasecmp(end, cmpval) == 0)
1025d465952Smartinh 				vs = end + strlen(cmpval);
1035d465952Smartinh 			else
1045d465952Smartinh 				return 1; /* no match */
1055d465952Smartinh 			break;
1065d465952Smartinh 		default:
107f9444383Sclaudio 			log_warnx("invalid subfilter type %u", type);
1085d465952Smartinh 			return -1;
1095d465952Smartinh 		}
1105d465952Smartinh 	}
1115d465952Smartinh 
1125d465952Smartinh 	return 0; /* match */
1135d465952Smartinh }
1145d465952Smartinh 
1155d465952Smartinh static int
ldap_filt_subs(struct ber_element * root,struct plan * plan)116012bb0c9Smartinh ldap_filt_subs(struct ber_element *root, struct plan *plan)
1175d465952Smartinh {
118012bb0c9Smartinh 	const char		*attr;
119012bb0c9Smartinh 	struct ber_element	*a, *v;
1205d465952Smartinh 
1214103e180Sclaudio 	if (plan->undefined)
1224103e180Sclaudio 		return -1;
1234103e180Sclaudio 	else if (plan->adesc != NULL)
124012bb0c9Smartinh 		a = ldap_get_attribute(root, plan->adesc);
125012bb0c9Smartinh 	else
126012bb0c9Smartinh 		a = ldap_find_attribute(root, plan->at);
127012bb0c9Smartinh 	if (a == NULL) {
12829a937b2Sclaudio 		log_debug("no attribute [%s] found",
12929a937b2Sclaudio 		    plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
1305d465952Smartinh 		return -1;
131012bb0c9Smartinh 	}
1325d465952Smartinh 
133*696b5899Stb 	if (ober_scanf_elements(a, "s(e", &attr, &v) != 0)
1345d465952Smartinh 		return -1; /* internal failure, false or undefined? */
1355d465952Smartinh 
1365d465952Smartinh 	/* Loop through all values, stop if any matches.
1375d465952Smartinh 	 */
1385d465952Smartinh 	for (; v; v = v->be_next) {
1395d465952Smartinh 		/* All substrings must match. */
140012bb0c9Smartinh 		switch (ldap_filt_subs_value(v, plan->assert.substring)) {
1415d465952Smartinh 		case 0:
1425d465952Smartinh 			return 0;
1435d465952Smartinh 		case -1:
1445d465952Smartinh 			return -1;
1455d465952Smartinh 		default:
1465d465952Smartinh 			break;
1475d465952Smartinh 		}
1485d465952Smartinh 	}
1495d465952Smartinh 
1505d465952Smartinh 	/* All values checked, no match. */
1515d465952Smartinh 	return -1;
1525d465952Smartinh }
1535d465952Smartinh 
1545d465952Smartinh static int
ldap_filt_and(struct ber_element * root,struct plan * plan)155012bb0c9Smartinh ldap_filt_and(struct ber_element *root, struct plan *plan)
1565d465952Smartinh {
157012bb0c9Smartinh 	struct plan	*arg;
1585d465952Smartinh 
159012bb0c9Smartinh 	TAILQ_FOREACH(arg, &plan->args, next)
160012bb0c9Smartinh 		if (ldap_matches_filter(root, arg) != 0)
1615d465952Smartinh 			return -1;
1625d465952Smartinh 
1635d465952Smartinh 	return 0;
1645d465952Smartinh }
1655d465952Smartinh 
1665d465952Smartinh static int
ldap_filt_or(struct ber_element * root,struct plan * plan)167012bb0c9Smartinh ldap_filt_or(struct ber_element *root, struct plan *plan)
1685d465952Smartinh {
169012bb0c9Smartinh 	struct plan	*arg;
1705d465952Smartinh 
171012bb0c9Smartinh 	TAILQ_FOREACH(arg, &plan->args, next)
172012bb0c9Smartinh 		if (ldap_matches_filter(root, arg) == 0)
1735d465952Smartinh 			return 0;
1745d465952Smartinh 
1755d465952Smartinh 	return -1;
1765d465952Smartinh }
1775d465952Smartinh 
1785d465952Smartinh static int
ldap_filt_not(struct ber_element * root,struct plan * plan)179012bb0c9Smartinh ldap_filt_not(struct ber_element *root, struct plan *plan)
1805d465952Smartinh {
181012bb0c9Smartinh 	struct plan	*arg;
1825d465952Smartinh 
183012bb0c9Smartinh 	TAILQ_FOREACH(arg, &plan->args, next)
184012bb0c9Smartinh 		if (ldap_matches_filter(root, arg) != 0)
1855d465952Smartinh 			return 0;
1865d465952Smartinh 
1875d465952Smartinh 	return -1;
1885d465952Smartinh }
1895d465952Smartinh 
1905d465952Smartinh static int
ldap_filt_presence(struct ber_element * root,struct plan * plan)191012bb0c9Smartinh ldap_filt_presence(struct ber_element *root, struct plan *plan)
1925d465952Smartinh {
1935d465952Smartinh 	struct ber_element	*a;
1945d465952Smartinh 
1954103e180Sclaudio 	if (plan->undefined)
1964103e180Sclaudio 		return -1;
1974103e180Sclaudio 	else if (plan->adesc != NULL)
198012bb0c9Smartinh 		a = ldap_get_attribute(root, plan->adesc);
199012bb0c9Smartinh 	else
200012bb0c9Smartinh 		a = ldap_find_attribute(root, plan->at);
2015d465952Smartinh 	if (a == NULL) {
20229a937b2Sclaudio 		log_debug("no attribute [%s] found",
20329a937b2Sclaudio 		    plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
204012bb0c9Smartinh 		return -1;
2055d465952Smartinh 	}
2065d465952Smartinh 
2075d465952Smartinh 	return 0;
2085d465952Smartinh }
2095d465952Smartinh 
2105d465952Smartinh int
ldap_matches_filter(struct ber_element * root,struct plan * plan)211012bb0c9Smartinh ldap_matches_filter(struct ber_element *root, struct plan *plan)
2125d465952Smartinh {
213012bb0c9Smartinh 	if (plan == NULL)
2145d465952Smartinh 		return 0;
2155d465952Smartinh 
216012bb0c9Smartinh 	switch (plan->op) {
2175d465952Smartinh 	case LDAP_FILT_EQ:
2185d465952Smartinh 	case LDAP_FILT_APPR:
219012bb0c9Smartinh 		return ldap_filt_eq(root, plan);
2205d465952Smartinh 	case LDAP_FILT_SUBS:
221012bb0c9Smartinh 		return ldap_filt_subs(root, plan);
2225d465952Smartinh 	case LDAP_FILT_AND:
223012bb0c9Smartinh 		return ldap_filt_and(root, plan);
2245d465952Smartinh 	case LDAP_FILT_OR:
225012bb0c9Smartinh 		return ldap_filt_or(root, plan);
2265d465952Smartinh 	case LDAP_FILT_NOT:
227012bb0c9Smartinh 		return ldap_filt_not(root, plan);
2285d465952Smartinh 	case LDAP_FILT_PRES:
229012bb0c9Smartinh 		return ldap_filt_presence(root, plan);
2305d465952Smartinh 	default:
231012bb0c9Smartinh 		log_warnx("filter type %d not implemented", plan->op);
2325d465952Smartinh 		return -1;
2335d465952Smartinh 	}
2345d465952Smartinh }
2355d465952Smartinh 
236