xref: /openbsd-src/usr.sbin/ldapd/filter.c (revision d59bb9942320b767f2a19aaa7690c8c6e30b724c)
1 /*	$OpenBSD: filter.c,v 1.4 2017/01/20 11:55:08 benno Exp $ */
2 
3 /*
4  * Copyright (c) 2009, 2010 Martin Hedenfalk <martinh@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/types.h>
21 
22 #include <string.h>
23 #include <stdint.h>
24 
25 #include "ldapd.h"
26 #include "log.h"
27 
28 static int	 ldap_filt_eq(struct ber_element *root, struct plan *plan);
29 static int	 ldap_filt_subs(struct ber_element *root, struct plan *plan);
30 static int	 ldap_filt_and(struct ber_element *root, struct plan *plan);
31 static int	 ldap_filt_or(struct ber_element *root, struct plan *plan);
32 static int	 ldap_filt_not(struct ber_element *root, struct plan *plan);
33 
34 static int
35 ldap_filt_eq(struct ber_element *root, struct plan *plan)
36 {
37 	char			*vs;
38 	struct ber_element	*a, *vals, *v;
39 
40 	if (plan->adesc != NULL)
41 		a = ldap_get_attribute(root, plan->adesc);
42 	else
43 		a = ldap_find_attribute(root, plan->at);
44 	if (a == NULL) {
45 		log_debug("no attribute [%s] found", plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
46 		return -1;
47 	}
48 
49 	vals = a->be_next;
50 	if (vals == NULL)
51 		return -1;
52 
53 	for (v = vals->be_sub; v; v = v->be_next) {
54 		if (ber_get_string(v, &vs) != 0)
55 			continue;
56 		if (strcasecmp(plan->assert.value, vs) == 0)
57 			return 0;
58 	}
59 
60 	return -1;
61 }
62 
63 static int
64 ldap_filt_subs_value(struct ber_element *v, struct ber_element *sub)
65 {
66 	int		 class;
67 	unsigned long	 type;
68 	const char	*cmpval;
69 	char		*vs, *p, *end;
70 
71 	if (ber_get_string(v, &vs) != 0)
72 		return -1;
73 
74 	for (; sub; sub = sub->be_next) {
75 		if (ber_scanf_elements(sub, "ts", &class, &type, &cmpval) != 0)
76 			return -1;
77 
78 		if (class != BER_CLASS_CONTEXT)
79 			return -1;
80 
81 		switch (type) {
82 		case LDAP_FILT_SUBS_INIT:
83 			if (strncasecmp(cmpval, vs, strlen(cmpval)) == 0)
84 				vs += strlen(cmpval);
85 			else
86 				return 1; /* no match */
87 			break;
88 		case LDAP_FILT_SUBS_ANY:
89 			if ((p = strcasestr(vs, cmpval)) != NULL)
90 				vs = p + strlen(cmpval);
91 			else
92 				return 1; /* no match */
93 			break;
94 		case LDAP_FILT_SUBS_FIN:
95 			if (strlen(vs) < strlen(cmpval))
96 				return 1; /* no match */
97 			end = vs + strlen(vs) - strlen(cmpval);
98 			if (strcasecmp(end, cmpval) == 0)
99 				vs = end + strlen(cmpval);
100 			else
101 				return 1; /* no match */
102 			break;
103 		default:
104 			log_warnx("invalid subfilter type %d", type);
105 			return -1;
106 		}
107 	}
108 
109 	return 0; /* match */
110 }
111 
112 static int
113 ldap_filt_subs(struct ber_element *root, struct plan *plan)
114 {
115 	const char		*attr;
116 	struct ber_element	*a, *v;
117 
118 	if (plan->adesc != NULL)
119 		a = ldap_get_attribute(root, plan->adesc);
120 	else
121 		a = ldap_find_attribute(root, plan->at);
122 	if (a == NULL) {
123 		log_debug("no attribute [%s] found", plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
124 		return -1;
125 	}
126 
127 	if (ber_scanf_elements(a, "s(e", &attr, &v) != 0)
128 		return -1; /* internal failure, false or undefined? */
129 
130 	/* Loop through all values, stop if any matches.
131 	 */
132 	for (; v; v = v->be_next) {
133 		/* All substrings must match. */
134 		switch (ldap_filt_subs_value(v, plan->assert.substring)) {
135 		case 0:
136 			return 0;
137 		case -1:
138 			return -1;
139 		default:
140 			break;
141 		}
142 	}
143 
144 	/* All values checked, no match. */
145 	return -1;
146 }
147 
148 static int
149 ldap_filt_and(struct ber_element *root, struct plan *plan)
150 {
151 	struct plan	*arg;
152 
153 	TAILQ_FOREACH(arg, &plan->args, next)
154 		if (ldap_matches_filter(root, arg) != 0)
155 			return -1;
156 
157 	return 0;
158 }
159 
160 static int
161 ldap_filt_or(struct ber_element *root, struct plan *plan)
162 {
163 	struct plan	*arg;
164 
165 	TAILQ_FOREACH(arg, &plan->args, next)
166 		if (ldap_matches_filter(root, arg) == 0)
167 			return 0;
168 
169 	return -1;
170 }
171 
172 static int
173 ldap_filt_not(struct ber_element *root, struct plan *plan)
174 {
175 	struct plan	*arg;
176 
177 	TAILQ_FOREACH(arg, &plan->args, next)
178 		if (ldap_matches_filter(root, arg) != 0)
179 			return 0;
180 
181 	return -1;
182 }
183 
184 static int
185 ldap_filt_presence(struct ber_element *root, struct plan *plan)
186 {
187 	struct ber_element	*a;
188 
189 	if (plan->adesc != NULL)
190 		a = ldap_get_attribute(root, plan->adesc);
191 	else
192 		a = ldap_find_attribute(root, plan->at);
193 	if (a == NULL) {
194 		log_debug("no attribute [%s] found", plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
195 		return -1;
196 	}
197 
198 	return 0;
199 }
200 
201 int
202 ldap_matches_filter(struct ber_element *root, struct plan *plan)
203 {
204 	if (plan == NULL)
205 		return 0;
206 
207 	switch (plan->op) {
208 	case LDAP_FILT_EQ:
209 	case LDAP_FILT_APPR:
210 		return ldap_filt_eq(root, plan);
211 	case LDAP_FILT_SUBS:
212 		return ldap_filt_subs(root, plan);
213 	case LDAP_FILT_AND:
214 		return ldap_filt_and(root, plan);
215 	case LDAP_FILT_OR:
216 		return ldap_filt_or(root, plan);
217 	case LDAP_FILT_NOT:
218 		return ldap_filt_not(root, plan);
219 	case LDAP_FILT_PRES:
220 		return ldap_filt_presence(root, plan);
221 	default:
222 		log_warnx("filter type %d not implemented", plan->op);
223 		return -1;
224 	}
225 }
226 
227