]> git.ipfire.org Git - thirdparty/dhcp.git/blame - server/class.c
Update RELNOTES
[thirdparty/dhcp.git] / server / class.c
CommitLineData
07378a2a
TL
1/* class.c
2
3 Handling for client classes. */
4
5/*
7512d88b 6 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1998-2003 by Internet Software Consortium
07378a2a 8 *
7512d88b
TM
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
07378a2a 12 *
98311e4b
DH
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
07378a2a 20 *
98311e4b 21 * Internet Systems Consortium, Inc.
429a56d7
TM
22 * PO Box 360
23 * Newmarket, NH 03857 USA
98311e4b 24 * <info@isc.org>
2c85ac9b 25 * https://www.isc.org/
49733f31 26 *
07378a2a
TL
27 */
28
07378a2a
TL
29#include "dhcpd.h"
30
adb7ed1a 31struct executable_statement *default_classification_rules;
07378a2a 32
ee7b5624
TL
33int have_billing_classes;
34
07378a2a
TL
35/* Build the default classification rule tree. */
36
37void classification_setup ()
38{
07378a2a 39 /* eval ... */
d758ad8c
TL
40 default_classification_rules = (struct executable_statement *)0;
41 if (!executable_statement_allocate (&default_classification_rules,
42 MDL))
8ae2d595 43 log_fatal ("Can't allocate check of default collection");
d758ad8c 44 default_classification_rules -> op = eval_statement;
07378a2a 45
dce08243 46 /* check-collection "default" */
d758ad8c
TL
47 if (!expression_allocate (&default_classification_rules -> data.eval,
48 MDL))
dce08243 49 log_fatal ("Can't allocate default check expression");
d758ad8c
TL
50 default_classification_rules -> data.eval -> op = expr_check;
51 default_classification_rules -> data.eval -> data.check =
52 &default_collection;
07378a2a
TL
53}
54
55void classify_client (packet)
56 struct packet *packet;
57{
a7341359
SR
58 execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
59 &global_scope, default_classification_rules, NULL);
07378a2a
TL
60}
61
da38df14 62int check_collection (packet, lease, collection)
07378a2a 63 struct packet *packet;
da38df14 64 struct lease *lease;
07378a2a
TL
65 struct collection *collection;
66{
67 struct class *class, *nc;
68 struct data_string data;
69 int matched = 0;
4af075a2 70 int status;
63f8b323 71 int ignorep;
33692791 72 int classfound;
07378a2a
TL
73
74 for (class = collection -> classes; class; class = class -> nic) {
74a2049e 75#if defined (DEBUG_CLASS_MATCHING)
8ae2d595 76 log_info ("checking against class %s...", class -> name);
74a2049e 77#endif
ee7b5624 78 memset (&data, 0, sizeof data);
56120203
TL
79
80 /* If there is a "match if" expression, check it. If
81 we get a match, and there's no subclass expression,
82 it's a match. If we get a match and there is a subclass
83 expression, then we check the submatch. If it's not a
84 match, that's final - we don't check the submatch. */
85
86 if (class -> expr) {
87 status = (evaluate_boolean_expression_result
88 (&ignorep, packet, lease,
9e383163 89 (struct client_state *)0,
56120203 90 packet -> options, (struct option_state *)0,
eaa84150
TL
91 lease ? &lease -> scope : &global_scope,
92 class -> expr));
56120203
TL
93 if (status) {
94 if (!class -> submatch) {
95 matched = 1;
96#if defined (DEBUG_CLASS_MATCHING)
97 log_info ("matches class.");
98#endif
99 classify (packet, class);
100 continue;
101 }
102 } else
103 continue;
104 }
105
106 /* Check to see if the client matches an existing subclass.
107 If it doesn't, and this is a spawning class, spawn a new
108 subclass and put the client in it. */
8b500185 109 if (class -> submatch) {
dce08243
TL
110 status = (evaluate_data_expression
111 (&data, packet, lease,
9e383163 112 (struct client_state *)0,
dce08243 113 packet -> options, (struct option_state *)0,
5b5fcc81 114 lease ? &lease -> scope : &global_scope,
d758ad8c 115 class -> submatch, MDL));
b767664e 116 if (status && data.len) {
20916cae 117 nc = (struct class *)0;
33692791
DH
118 classfound = class_hash_lookup (&nc, class -> hash,
119 (const char *)data.data, data.len, MDL);
120
121#ifdef LDAP_CONFIGURATION
122 if (!classfound && find_subclass_in_ldap (class, &nc, &data))
123 classfound = 1;
124#endif
125
126 if (classfound) {
74a2049e 127#if defined (DEBUG_CLASS_MATCHING)
8ae2d595 128 log_info ("matches subclass %s.",
ee7b5624
TL
129 print_hex_1 (data.len,
130 data.data, 60));
131#endif
12c9957e 132 data_string_forget (&data, MDL);
ee7b5624
TL
133 classify (packet, nc);
134 matched = 1;
a19e8a45 135 class_dereference (&nc, MDL);
ee7b5624
TL
136 continue;
137 }
12c9957e
TL
138 if (!class -> spawning) {
139 data_string_forget (&data, MDL);
8b500185 140 continue;
12c9957e 141 }
fea20b09 142 /* XXX Write out the spawned class? */
ee7b5624 143#if defined (DEBUG_CLASS_MATCHING)
8ae2d595 144 log_info ("spawning subclass %s.",
64e1dc1d 145 print_hex_1 (data.len, data.data, 60));
74a2049e 146#endif
a19e8a45
TL
147 status = class_allocate (&nc, MDL);
148 group_reference (&nc -> group,
149 class -> group, MDL);
150 class_reference (&nc -> superclass,
151 class, MDL);
ee7b5624
TL
152 nc -> lease_limit = class -> lease_limit;
153 nc -> dirty = 1;
154 if (nc -> lease_limit) {
155 nc -> billed_leases =
156 (dmalloc
157 (nc -> lease_limit *
158 sizeof (struct lease *),
12c9957e 159 MDL));
ee7b5624 160 if (!nc -> billed_leases) {
7e6f3635
TL
161 log_error ("no memory for%s",
162 " billing");
ee7b5624
TL
163 data_string_forget
164 (&nc -> hash_string,
12c9957e 165 MDL);
a19e8a45 166 class_dereference (&nc, MDL);
12c9957e
TL
167 data_string_forget (&data,
168 MDL);
ee7b5624
TL
169 continue;
170 }
171 memset (nc -> billed_leases, 0,
172 (nc -> lease_limit *
0f750c4f 173 sizeof (struct lease *)));
ee7b5624
TL
174 }
175 data_string_copy (&nc -> hash_string, &data,
12c9957e 176 MDL);
ee7b5624 177 if (!class -> hash)
f7fdb216
DH
178 class_new_hash(&class->hash,
179 SCLASS_HASH_SIZE, MDL);
20916cae
TL
180 class_hash_add (class -> hash,
181 (const char *)
182 nc -> hash_string.data,
183 nc -> hash_string.len,
184 nc, MDL);
ee7b5624 185 classify (packet, nc);
d758ad8c 186 class_dereference (&nc, MDL);
07378a2a 187 }
0cd94b5e
TM
188
189 data_string_forget (&data, MDL);
07378a2a 190 }
07378a2a
TL
191 }
192 return matched;
193}
194
195void classify (packet, class)
196 struct packet *packet;
197 struct class *class;
198{
199 if (packet -> class_count < PACKET_MAX_CLASSES)
20916cae
TL
200 class_reference (&packet -> classes [packet -> class_count++],
201 class, MDL);
07378a2a 202 else
d758ad8c 203 log_error ("too many classes match %s",
07378a2a
TL
204 print_hw_addr (packet -> raw -> htype,
205 packet -> raw -> hlen,
206 packet -> raw -> chaddr));
207}
208
899d754f
JB
209
210isc_result_t unlink_class(struct class **class) {
211 struct collection *lp;
212 struct class *cp, *pp;
213
214 for (lp = collections; lp; lp = lp -> next) {
215 for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
216 if (cp == *class) {
217 if (pp == 0) {
218 lp->classes = cp->nic;
219 } else {
220 pp->nic = cp->nic;
221 }
222 cp->nic = 0;
223 class_dereference(class, MDL);
224
225 return ISC_R_SUCCESS;
226 }
227 }
228 return ISC_R_NOTFOUND;
229}
230
6a39bcf0 231
20916cae
TL
232isc_result_t find_class (struct class **class, const char *name,
233 const char *file, int line)
adb7ed1a
TL
234{
235 struct collection *lp;
236 struct class *cp;
237
238 for (lp = collections; lp; lp = lp -> next) {
239 for (cp = lp -> classes; cp; cp = cp -> nic)
20916cae
TL
240 if (cp -> name && !strcmp (name, cp -> name)) {
241 return class_reference (class, cp, file, line);
242 }
adb7ed1a 243 }
20916cae 244 return ISC_R_NOTFOUND;
adb7ed1a 245}
ee7b5624 246
6a39bcf0
TM
247/* Removes the billing class from a lease
248 *
249 * Note that because classes can be created and removed dynamically, it is
250 * possible that the class to which a lease was billed has since been deleted.
251 * To cover the case where the lease is the last reference to a deleted class
252 * we remove the lease reference from the class first, then the class from the
253 * lease. To protect ourselves from the reverse situation, where the class is
254 * the last reference to the lease (unlikely), we create a guard reference to
255 * the lease, then remove it at the end.
256 */
257void unbill_class (lease)
ee7b5624 258 struct lease *lease;
ee7b5624
TL
259{
260 int i;
6a39bcf0
TM
261 struct class* class = lease->billing_class;
262 struct lease* refholder = NULL;
ee7b5624 263
6a39bcf0
TM
264 /* if there's no billing to remove, nothing to do */
265 if (class == NULL) {
266 return;
267 }
268
269 /* Find the lease in the list of the class's billed leases */
270 for (i = 0; i < class->lease_limit; i++) {
271 if (class->billed_leases[i] == lease)
ee7b5624 272 break;
6a39bcf0
TM
273 }
274
275 /* Create guard reference, so class cannot be last reference to lease */
276 lease_reference(&refholder, lease, MDL);
277
278 /* If the class doesn't have the lease, then something is broken
279 * programmatically. We'll log it but skip the lease dereference. */
280 if (i == class->lease_limit) {
8ae2d595 281 log_error ("lease %s unbilled with no billing arrangement.",
6a39bcf0
TM
282 piaddr(lease->ip_addr));
283 } else {
284 /* Remove the lease from the class */
285 lease_dereference(&class->billed_leases[i], MDL);
286 class->leases_consumed--;
ee7b5624 287 }
6a39bcf0
TM
288
289 /* Remove the class from the lease */
290 class_dereference(&lease->billing_class, MDL);
291
292 /* Ditch our guard reference */
293 lease_dereference(&refholder, MDL);
ee7b5624
TL
294}
295
296int bill_class (lease, class)
297 struct lease *lease;
298 struct class *class;
299{
300 int i;
301
bf7a9284
TL
302 if (lease -> billing_class) {
303 log_error ("lease billed with existing billing arrangement.");
6a39bcf0 304 unbill_class (lease);
bf7a9284
TL
305 }
306
ee7b5624
TL
307 if (class -> leases_consumed == class -> lease_limit)
308 return 0;
309
310 for (i = 0; i < class -> lease_limit; i++)
311 if (!class -> billed_leases [i])
312 break;
313
314 if (i == class -> lease_limit) {
8ae2d595 315 log_error ("class billing consumption disagrees with leases.");
ee7b5624
TL
316 return 0;
317 }
318
20916cae
TL
319 lease_reference (&class -> billed_leases [i], lease, MDL);
320 class_reference (&lease -> billing_class, class, MDL);
ee7b5624
TL
321 class -> leases_consumed++;
322 return 1;
323}