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