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 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 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 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 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 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 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 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 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