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