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