1 /* $OpenBSD: filter.c,v 1.9 2019/10/24 12:39:26 tb 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
ldap_filt_eq(struct ber_element * root,struct plan * plan)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->undefined)
41 return -1;
42 else if (plan->adesc != NULL)
43 a = ldap_get_attribute(root, plan->adesc);
44 else
45 a = ldap_find_attribute(root, plan->at);
46 if (a == NULL) {
47 log_debug("no attribute [%s] found",
48 plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
49 return -1;
50 }
51
52 vals = a->be_next;
53 if (vals == NULL)
54 return -1;
55
56 for (v = vals->be_sub; v; v = v->be_next) {
57 if (ober_get_string(v, &vs) != 0)
58 continue;
59 if (strcasecmp(plan->assert.value, vs) == 0)
60 return 0;
61 }
62
63 return -1;
64 }
65
66 static int
ldap_filt_subs_value(struct ber_element * v,struct ber_element * sub)67 ldap_filt_subs_value(struct ber_element *v, struct ber_element *sub)
68 {
69 int class;
70 unsigned int type;
71 const char *cmpval;
72 char *vs, *p, *end;
73
74 if (ober_get_string(v, &vs) != 0)
75 return -1;
76
77 for (; sub; sub = sub->be_next) {
78 if (ober_scanf_elements(sub, "ts", &class, &type, &cmpval) != 0)
79 return -1;
80
81 if (class != BER_CLASS_CONTEXT)
82 return -1;
83
84 switch (type) {
85 case LDAP_FILT_SUBS_INIT:
86 if (strncasecmp(cmpval, vs, strlen(cmpval)) == 0)
87 vs += strlen(cmpval);
88 else
89 return 1; /* no match */
90 break;
91 case LDAP_FILT_SUBS_ANY:
92 if ((p = strcasestr(vs, cmpval)) != NULL)
93 vs = p + strlen(cmpval);
94 else
95 return 1; /* no match */
96 break;
97 case LDAP_FILT_SUBS_FIN:
98 if (strlen(vs) < strlen(cmpval))
99 return 1; /* no match */
100 end = vs + strlen(vs) - strlen(cmpval);
101 if (strcasecmp(end, cmpval) == 0)
102 vs = end + strlen(cmpval);
103 else
104 return 1; /* no match */
105 break;
106 default:
107 log_warnx("invalid subfilter type %u", type);
108 return -1;
109 }
110 }
111
112 return 0; /* match */
113 }
114
115 static int
ldap_filt_subs(struct ber_element * root,struct plan * plan)116 ldap_filt_subs(struct ber_element *root, struct plan *plan)
117 {
118 const char *attr;
119 struct ber_element *a, *v;
120
121 if (plan->undefined)
122 return -1;
123 else if (plan->adesc != NULL)
124 a = ldap_get_attribute(root, plan->adesc);
125 else
126 a = ldap_find_attribute(root, plan->at);
127 if (a == NULL) {
128 log_debug("no attribute [%s] found",
129 plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
130 return -1;
131 }
132
133 if (ober_scanf_elements(a, "s(e", &attr, &v) != 0)
134 return -1; /* internal failure, false or undefined? */
135
136 /* Loop through all values, stop if any matches.
137 */
138 for (; v; v = v->be_next) {
139 /* All substrings must match. */
140 switch (ldap_filt_subs_value(v, plan->assert.substring)) {
141 case 0:
142 return 0;
143 case -1:
144 return -1;
145 default:
146 break;
147 }
148 }
149
150 /* All values checked, no match. */
151 return -1;
152 }
153
154 static int
ldap_filt_and(struct ber_element * root,struct plan * plan)155 ldap_filt_and(struct ber_element *root, struct plan *plan)
156 {
157 struct plan *arg;
158
159 TAILQ_FOREACH(arg, &plan->args, next)
160 if (ldap_matches_filter(root, arg) != 0)
161 return -1;
162
163 return 0;
164 }
165
166 static int
ldap_filt_or(struct ber_element * root,struct plan * plan)167 ldap_filt_or(struct ber_element *root, struct plan *plan)
168 {
169 struct plan *arg;
170
171 TAILQ_FOREACH(arg, &plan->args, next)
172 if (ldap_matches_filter(root, arg) == 0)
173 return 0;
174
175 return -1;
176 }
177
178 static int
ldap_filt_not(struct ber_element * root,struct plan * plan)179 ldap_filt_not(struct ber_element *root, struct plan *plan)
180 {
181 struct plan *arg;
182
183 TAILQ_FOREACH(arg, &plan->args, next)
184 if (ldap_matches_filter(root, arg) != 0)
185 return 0;
186
187 return -1;
188 }
189
190 static int
ldap_filt_presence(struct ber_element * root,struct plan * plan)191 ldap_filt_presence(struct ber_element *root, struct plan *plan)
192 {
193 struct ber_element *a;
194
195 if (plan->undefined)
196 return -1;
197 else if (plan->adesc != NULL)
198 a = ldap_get_attribute(root, plan->adesc);
199 else
200 a = ldap_find_attribute(root, plan->at);
201 if (a == NULL) {
202 log_debug("no attribute [%s] found",
203 plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
204 return -1;
205 }
206
207 return 0;
208 }
209
210 int
ldap_matches_filter(struct ber_element * root,struct plan * plan)211 ldap_matches_filter(struct ber_element *root, struct plan *plan)
212 {
213 if (plan == NULL)
214 return 0;
215
216 switch (plan->op) {
217 case LDAP_FILT_EQ:
218 case LDAP_FILT_APPR:
219 return ldap_filt_eq(root, plan);
220 case LDAP_FILT_SUBS:
221 return ldap_filt_subs(root, plan);
222 case LDAP_FILT_AND:
223 return ldap_filt_and(root, plan);
224 case LDAP_FILT_OR:
225 return ldap_filt_or(root, plan);
226 case LDAP_FILT_NOT:
227 return ldap_filt_not(root, plan);
228 case LDAP_FILT_PRES:
229 return ldap_filt_presence(root, plan);
230 default:
231 log_warnx("filter type %d not implemented", plan->op);
232 return -1;
233 }
234 }
235
236