xref: /minix3/external/bsd/dhcp/dist/server/class.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1*83ee113eSDavid van Moolenbroek /*	$NetBSD: class.c,v 1.1.1.3 2014/07/12 11:58:04 spz Exp $	*/
2*83ee113eSDavid van Moolenbroek /* class.c
3*83ee113eSDavid van Moolenbroek 
4*83ee113eSDavid van Moolenbroek    Handling for client classes. */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
9*83ee113eSDavid van Moolenbroek  * Copyright (c) 1998-2003 by Internet Software Consortium
10*83ee113eSDavid van Moolenbroek  *
11*83ee113eSDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
12*83ee113eSDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
13*83ee113eSDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
14*83ee113eSDavid van Moolenbroek  *
15*83ee113eSDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16*83ee113eSDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17*83ee113eSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18*83ee113eSDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*83ee113eSDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20*83ee113eSDavid van Moolenbroek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21*83ee113eSDavid van Moolenbroek  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22*83ee113eSDavid van Moolenbroek  *
23*83ee113eSDavid van Moolenbroek  *   Internet Systems Consortium, Inc.
24*83ee113eSDavid van Moolenbroek  *   950 Charter Street
25*83ee113eSDavid van Moolenbroek  *   Redwood City, CA 94063
26*83ee113eSDavid van Moolenbroek  *   <info@isc.org>
27*83ee113eSDavid van Moolenbroek  *   https://www.isc.org/
28*83ee113eSDavid van Moolenbroek  *
29*83ee113eSDavid van Moolenbroek  */
30*83ee113eSDavid van Moolenbroek 
31*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
32*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: class.c,v 1.1.1.3 2014/07/12 11:58:04 spz Exp $");
33*83ee113eSDavid van Moolenbroek 
34*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
35*83ee113eSDavid van Moolenbroek 
36*83ee113eSDavid van Moolenbroek struct collection default_collection = {
37*83ee113eSDavid van Moolenbroek 	(struct collection *)0,
38*83ee113eSDavid van Moolenbroek 	"default",
39*83ee113eSDavid van Moolenbroek 	(struct class *)0,
40*83ee113eSDavid van Moolenbroek };
41*83ee113eSDavid van Moolenbroek 
42*83ee113eSDavid van Moolenbroek struct collection *collections = &default_collection;
43*83ee113eSDavid van Moolenbroek struct executable_statement *default_classification_rules;
44*83ee113eSDavid van Moolenbroek 
45*83ee113eSDavid van Moolenbroek int have_billing_classes;
46*83ee113eSDavid van Moolenbroek 
47*83ee113eSDavid van Moolenbroek /* Build the default classification rule tree. */
48*83ee113eSDavid van Moolenbroek 
classification_setup()49*83ee113eSDavid van Moolenbroek void classification_setup ()
50*83ee113eSDavid van Moolenbroek {
51*83ee113eSDavid van Moolenbroek 	/* eval ... */
52*83ee113eSDavid van Moolenbroek 	default_classification_rules = (struct executable_statement *)0;
53*83ee113eSDavid van Moolenbroek 	if (!executable_statement_allocate (&default_classification_rules,
54*83ee113eSDavid van Moolenbroek 					    MDL))
55*83ee113eSDavid van Moolenbroek 		log_fatal ("Can't allocate check of default collection");
56*83ee113eSDavid van Moolenbroek 	default_classification_rules -> op = eval_statement;
57*83ee113eSDavid van Moolenbroek 
58*83ee113eSDavid van Moolenbroek 	/* check-collection "default" */
59*83ee113eSDavid van Moolenbroek 	if (!expression_allocate (&default_classification_rules -> data.eval,
60*83ee113eSDavid van Moolenbroek 				  MDL))
61*83ee113eSDavid van Moolenbroek 		log_fatal ("Can't allocate default check expression");
62*83ee113eSDavid van Moolenbroek 	default_classification_rules -> data.eval -> op = expr_check;
63*83ee113eSDavid van Moolenbroek 	default_classification_rules -> data.eval -> data.check =
64*83ee113eSDavid van Moolenbroek 		&default_collection;
65*83ee113eSDavid van Moolenbroek }
66*83ee113eSDavid van Moolenbroek 
classify_client(packet)67*83ee113eSDavid van Moolenbroek void classify_client (packet)
68*83ee113eSDavid van Moolenbroek 	struct packet *packet;
69*83ee113eSDavid van Moolenbroek {
70*83ee113eSDavid van Moolenbroek 	execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
71*83ee113eSDavid van Moolenbroek 			    &global_scope, default_classification_rules, NULL);
72*83ee113eSDavid van Moolenbroek }
73*83ee113eSDavid van Moolenbroek 
check_collection(packet,lease,collection)74*83ee113eSDavid van Moolenbroek int check_collection (packet, lease, collection)
75*83ee113eSDavid van Moolenbroek 	struct packet *packet;
76*83ee113eSDavid van Moolenbroek 	struct lease *lease;
77*83ee113eSDavid van Moolenbroek 	struct collection *collection;
78*83ee113eSDavid van Moolenbroek {
79*83ee113eSDavid van Moolenbroek 	struct class *class, *nc;
80*83ee113eSDavid van Moolenbroek 	struct data_string data;
81*83ee113eSDavid van Moolenbroek 	int matched = 0;
82*83ee113eSDavid van Moolenbroek 	int status;
83*83ee113eSDavid van Moolenbroek 	int ignorep;
84*83ee113eSDavid van Moolenbroek 	int classfound;
85*83ee113eSDavid van Moolenbroek 
86*83ee113eSDavid van Moolenbroek 	for (class = collection -> classes; class; class = class -> nic) {
87*83ee113eSDavid van Moolenbroek #if defined (DEBUG_CLASS_MATCHING)
88*83ee113eSDavid van Moolenbroek 		log_info ("checking against class %s...", class -> name);
89*83ee113eSDavid van Moolenbroek #endif
90*83ee113eSDavid van Moolenbroek 		memset (&data, 0, sizeof data);
91*83ee113eSDavid van Moolenbroek 
92*83ee113eSDavid van Moolenbroek 		/* If there is a "match if" expression, check it.   If
93*83ee113eSDavid van Moolenbroek 		   we get a match, and there's no subclass expression,
94*83ee113eSDavid van Moolenbroek 		   it's a match.   If we get a match and there is a subclass
95*83ee113eSDavid van Moolenbroek 		   expression, then we check the submatch.   If it's not a
96*83ee113eSDavid van Moolenbroek 		   match, that's final - we don't check the submatch. */
97*83ee113eSDavid van Moolenbroek 
98*83ee113eSDavid van Moolenbroek 		if (class -> expr) {
99*83ee113eSDavid van Moolenbroek 			status = (evaluate_boolean_expression_result
100*83ee113eSDavid van Moolenbroek 				  (&ignorep, packet, lease,
101*83ee113eSDavid van Moolenbroek 				   (struct client_state *)0,
102*83ee113eSDavid van Moolenbroek 				   packet -> options, (struct option_state *)0,
103*83ee113eSDavid van Moolenbroek 				   lease ? &lease -> scope : &global_scope,
104*83ee113eSDavid van Moolenbroek 				   class -> expr));
105*83ee113eSDavid van Moolenbroek 			if (status) {
106*83ee113eSDavid van Moolenbroek 				if (!class -> submatch) {
107*83ee113eSDavid van Moolenbroek 					matched = 1;
108*83ee113eSDavid van Moolenbroek #if defined (DEBUG_CLASS_MATCHING)
109*83ee113eSDavid van Moolenbroek 					log_info ("matches class.");
110*83ee113eSDavid van Moolenbroek #endif
111*83ee113eSDavid van Moolenbroek 					classify (packet, class);
112*83ee113eSDavid van Moolenbroek 					continue;
113*83ee113eSDavid van Moolenbroek 				}
114*83ee113eSDavid van Moolenbroek 			} else
115*83ee113eSDavid van Moolenbroek 				continue;
116*83ee113eSDavid van Moolenbroek 		}
117*83ee113eSDavid van Moolenbroek 
118*83ee113eSDavid van Moolenbroek 		/* Check to see if the client matches an existing subclass.
119*83ee113eSDavid van Moolenbroek 		   If it doesn't, and this is a spawning class, spawn a new
120*83ee113eSDavid van Moolenbroek 		   subclass and put the client in it. */
121*83ee113eSDavid van Moolenbroek 		if (class -> submatch) {
122*83ee113eSDavid van Moolenbroek 			status = (evaluate_data_expression
123*83ee113eSDavid van Moolenbroek 				  (&data, packet, lease,
124*83ee113eSDavid van Moolenbroek 				   (struct client_state *)0,
125*83ee113eSDavid van Moolenbroek 				   packet -> options, (struct option_state *)0,
126*83ee113eSDavid van Moolenbroek 				   lease ? &lease -> scope : &global_scope,
127*83ee113eSDavid van Moolenbroek 				   class -> submatch, MDL));
128*83ee113eSDavid van Moolenbroek 			if (status && data.len) {
129*83ee113eSDavid van Moolenbroek 				nc = (struct class *)0;
130*83ee113eSDavid van Moolenbroek 				classfound = class_hash_lookup (&nc, class -> hash,
131*83ee113eSDavid van Moolenbroek 					(const char *)data.data, data.len, MDL);
132*83ee113eSDavid van Moolenbroek 
133*83ee113eSDavid van Moolenbroek #ifdef LDAP_CONFIGURATION
134*83ee113eSDavid van Moolenbroek 				if (!classfound && find_subclass_in_ldap (class, &nc, &data))
135*83ee113eSDavid van Moolenbroek 					classfound = 1;
136*83ee113eSDavid van Moolenbroek #endif
137*83ee113eSDavid van Moolenbroek 
138*83ee113eSDavid van Moolenbroek 				if (classfound) {
139*83ee113eSDavid van Moolenbroek #if defined (DEBUG_CLASS_MATCHING)
140*83ee113eSDavid van Moolenbroek 					log_info ("matches subclass %s.",
141*83ee113eSDavid van Moolenbroek 					      print_hex_1 (data.len,
142*83ee113eSDavid van Moolenbroek 							   data.data, 60));
143*83ee113eSDavid van Moolenbroek #endif
144*83ee113eSDavid van Moolenbroek 					data_string_forget (&data, MDL);
145*83ee113eSDavid van Moolenbroek 					classify (packet, nc);
146*83ee113eSDavid van Moolenbroek 					matched = 1;
147*83ee113eSDavid van Moolenbroek 					class_dereference (&nc, MDL);
148*83ee113eSDavid van Moolenbroek 					continue;
149*83ee113eSDavid van Moolenbroek 				}
150*83ee113eSDavid van Moolenbroek 				if (!class -> spawning) {
151*83ee113eSDavid van Moolenbroek 					data_string_forget (&data, MDL);
152*83ee113eSDavid van Moolenbroek 					continue;
153*83ee113eSDavid van Moolenbroek 				}
154*83ee113eSDavid van Moolenbroek 				/* XXX Write out the spawned class? */
155*83ee113eSDavid van Moolenbroek #if defined (DEBUG_CLASS_MATCHING)
156*83ee113eSDavid van Moolenbroek 				log_info ("spawning subclass %s.",
157*83ee113eSDavid van Moolenbroek 				      print_hex_1 (data.len, data.data, 60));
158*83ee113eSDavid van Moolenbroek #endif
159*83ee113eSDavid van Moolenbroek 				status = class_allocate (&nc, MDL);
160*83ee113eSDavid van Moolenbroek 				group_reference (&nc -> group,
161*83ee113eSDavid van Moolenbroek 						 class -> group, MDL);
162*83ee113eSDavid van Moolenbroek 				class_reference (&nc -> superclass,
163*83ee113eSDavid van Moolenbroek 						 class, MDL);
164*83ee113eSDavid van Moolenbroek 				nc -> lease_limit = class -> lease_limit;
165*83ee113eSDavid van Moolenbroek 				nc -> dirty = 1;
166*83ee113eSDavid van Moolenbroek 				if (nc -> lease_limit) {
167*83ee113eSDavid van Moolenbroek 					nc -> billed_leases =
168*83ee113eSDavid van Moolenbroek 						(dmalloc
169*83ee113eSDavid van Moolenbroek 						 (nc -> lease_limit *
170*83ee113eSDavid van Moolenbroek 						  sizeof (struct lease *),
171*83ee113eSDavid van Moolenbroek 						  MDL));
172*83ee113eSDavid van Moolenbroek 					if (!nc -> billed_leases) {
173*83ee113eSDavid van Moolenbroek 						log_error ("no memory for%s",
174*83ee113eSDavid van Moolenbroek 							   " billing");
175*83ee113eSDavid van Moolenbroek 						data_string_forget
176*83ee113eSDavid van Moolenbroek 							(&nc -> hash_string,
177*83ee113eSDavid van Moolenbroek 							 MDL);
178*83ee113eSDavid van Moolenbroek 						class_dereference (&nc, MDL);
179*83ee113eSDavid van Moolenbroek 						data_string_forget (&data,
180*83ee113eSDavid van Moolenbroek 								    MDL);
181*83ee113eSDavid van Moolenbroek 						continue;
182*83ee113eSDavid van Moolenbroek 					}
183*83ee113eSDavid van Moolenbroek 					memset (nc -> billed_leases, 0,
184*83ee113eSDavid van Moolenbroek 						(nc -> lease_limit *
185*83ee113eSDavid van Moolenbroek 						 sizeof (struct lease *)));
186*83ee113eSDavid van Moolenbroek 				}
187*83ee113eSDavid van Moolenbroek 				data_string_copy (&nc -> hash_string, &data,
188*83ee113eSDavid van Moolenbroek 						  MDL);
189*83ee113eSDavid van Moolenbroek 				data_string_forget (&data, MDL);
190*83ee113eSDavid van Moolenbroek 				if (!class -> hash)
191*83ee113eSDavid van Moolenbroek 				    class_new_hash(&class->hash,
192*83ee113eSDavid van Moolenbroek 						   SCLASS_HASH_SIZE, MDL);
193*83ee113eSDavid van Moolenbroek 				class_hash_add (class -> hash,
194*83ee113eSDavid van Moolenbroek 						(const char *)
195*83ee113eSDavid van Moolenbroek 						nc -> hash_string.data,
196*83ee113eSDavid van Moolenbroek 						nc -> hash_string.len,
197*83ee113eSDavid van Moolenbroek 						nc, MDL);
198*83ee113eSDavid van Moolenbroek 				classify (packet, nc);
199*83ee113eSDavid van Moolenbroek 				class_dereference (&nc, MDL);
200*83ee113eSDavid van Moolenbroek 			}
201*83ee113eSDavid van Moolenbroek 		}
202*83ee113eSDavid van Moolenbroek 	}
203*83ee113eSDavid van Moolenbroek 	return matched;
204*83ee113eSDavid van Moolenbroek }
205*83ee113eSDavid van Moolenbroek 
classify(packet,class)206*83ee113eSDavid van Moolenbroek void classify (packet, class)
207*83ee113eSDavid van Moolenbroek 	struct packet *packet;
208*83ee113eSDavid van Moolenbroek 	struct class *class;
209*83ee113eSDavid van Moolenbroek {
210*83ee113eSDavid van Moolenbroek 	if (packet -> class_count < PACKET_MAX_CLASSES)
211*83ee113eSDavid van Moolenbroek 		class_reference (&packet -> classes [packet -> class_count++],
212*83ee113eSDavid van Moolenbroek 				 class, MDL);
213*83ee113eSDavid van Moolenbroek 	else
214*83ee113eSDavid van Moolenbroek 		log_error ("too many classes match %s",
215*83ee113eSDavid van Moolenbroek 		      print_hw_addr (packet -> raw -> htype,
216*83ee113eSDavid van Moolenbroek 				     packet -> raw -> hlen,
217*83ee113eSDavid van Moolenbroek 				     packet -> raw -> chaddr));
218*83ee113eSDavid van Moolenbroek }
219*83ee113eSDavid van Moolenbroek 
220*83ee113eSDavid van Moolenbroek 
unlink_class(struct class ** class)221*83ee113eSDavid van Moolenbroek isc_result_t unlink_class(struct class **class) {
222*83ee113eSDavid van Moolenbroek 	struct collection *lp;
223*83ee113eSDavid van Moolenbroek 	struct class *cp, *pp;
224*83ee113eSDavid van Moolenbroek 
225*83ee113eSDavid van Moolenbroek 	for (lp = collections; lp; lp = lp -> next) {
226*83ee113eSDavid van Moolenbroek 		for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
227*83ee113eSDavid van Moolenbroek 			if (cp == *class) {
228*83ee113eSDavid van Moolenbroek 				if (pp == 0) {
229*83ee113eSDavid van Moolenbroek 					lp->classes = cp->nic;
230*83ee113eSDavid van Moolenbroek 				} else {
231*83ee113eSDavid van Moolenbroek 					pp->nic = cp->nic;
232*83ee113eSDavid van Moolenbroek 				}
233*83ee113eSDavid van Moolenbroek 				cp->nic = 0;
234*83ee113eSDavid van Moolenbroek 				class_dereference(class, MDL);
235*83ee113eSDavid van Moolenbroek 
236*83ee113eSDavid van Moolenbroek 				return ISC_R_SUCCESS;
237*83ee113eSDavid van Moolenbroek 			}
238*83ee113eSDavid van Moolenbroek 	}
239*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
240*83ee113eSDavid van Moolenbroek }
241*83ee113eSDavid van Moolenbroek 
242*83ee113eSDavid van Moolenbroek 
find_class(struct class ** class,const char * name,const char * file,int line)243*83ee113eSDavid van Moolenbroek isc_result_t find_class (struct class **class, const char *name,
244*83ee113eSDavid van Moolenbroek 			 const char *file, int line)
245*83ee113eSDavid van Moolenbroek {
246*83ee113eSDavid van Moolenbroek 	struct collection *lp;
247*83ee113eSDavid van Moolenbroek 	struct class *cp;
248*83ee113eSDavid van Moolenbroek 
249*83ee113eSDavid van Moolenbroek 	for (lp = collections; lp; lp = lp -> next) {
250*83ee113eSDavid van Moolenbroek 		for (cp = lp -> classes; cp; cp = cp -> nic)
251*83ee113eSDavid van Moolenbroek 			if (cp -> name && !strcmp (name, cp -> name)) {
252*83ee113eSDavid van Moolenbroek 				return class_reference (class, cp, file, line);
253*83ee113eSDavid van Moolenbroek 			}
254*83ee113eSDavid van Moolenbroek 	}
255*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
256*83ee113eSDavid van Moolenbroek }
257*83ee113eSDavid van Moolenbroek 
unbill_class(lease,class)258*83ee113eSDavid van Moolenbroek int unbill_class (lease, class)
259*83ee113eSDavid van Moolenbroek 	struct lease *lease;
260*83ee113eSDavid van Moolenbroek 	struct class *class;
261*83ee113eSDavid van Moolenbroek {
262*83ee113eSDavid van Moolenbroek 	int i;
263*83ee113eSDavid van Moolenbroek 
264*83ee113eSDavid van Moolenbroek 	for (i = 0; i < class -> lease_limit; i++)
265*83ee113eSDavid van Moolenbroek 		if (class -> billed_leases [i] == lease)
266*83ee113eSDavid van Moolenbroek 			break;
267*83ee113eSDavid van Moolenbroek 	if (i == class -> lease_limit) {
268*83ee113eSDavid van Moolenbroek 		log_error ("lease %s unbilled with no billing arrangement.",
269*83ee113eSDavid van Moolenbroek 		      piaddr (lease -> ip_addr));
270*83ee113eSDavid van Moolenbroek 		return 0;
271*83ee113eSDavid van Moolenbroek 	}
272*83ee113eSDavid van Moolenbroek 	class_dereference (&lease -> billing_class, MDL);
273*83ee113eSDavid van Moolenbroek 	lease_dereference (&class -> billed_leases [i], MDL);
274*83ee113eSDavid van Moolenbroek 	class -> leases_consumed--;
275*83ee113eSDavid van Moolenbroek 	return 1;
276*83ee113eSDavid van Moolenbroek }
277*83ee113eSDavid van Moolenbroek 
bill_class(lease,class)278*83ee113eSDavid van Moolenbroek int bill_class (lease, class)
279*83ee113eSDavid van Moolenbroek 	struct lease *lease;
280*83ee113eSDavid van Moolenbroek 	struct class *class;
281*83ee113eSDavid van Moolenbroek {
282*83ee113eSDavid van Moolenbroek 	int i;
283*83ee113eSDavid van Moolenbroek 
284*83ee113eSDavid van Moolenbroek 	if (lease -> billing_class) {
285*83ee113eSDavid van Moolenbroek 		log_error ("lease billed with existing billing arrangement.");
286*83ee113eSDavid van Moolenbroek 		unbill_class (lease, lease -> billing_class);
287*83ee113eSDavid van Moolenbroek 	}
288*83ee113eSDavid van Moolenbroek 
289*83ee113eSDavid van Moolenbroek 	if (class -> leases_consumed == class -> lease_limit)
290*83ee113eSDavid van Moolenbroek 		return 0;
291*83ee113eSDavid van Moolenbroek 
292*83ee113eSDavid van Moolenbroek 	for (i = 0; i < class -> lease_limit; i++)
293*83ee113eSDavid van Moolenbroek 		if (!class -> billed_leases [i])
294*83ee113eSDavid van Moolenbroek 			break;
295*83ee113eSDavid van Moolenbroek 
296*83ee113eSDavid van Moolenbroek 	if (i == class -> lease_limit) {
297*83ee113eSDavid van Moolenbroek 		log_error ("class billing consumption disagrees with leases.");
298*83ee113eSDavid van Moolenbroek 		return 0;
299*83ee113eSDavid van Moolenbroek 	}
300*83ee113eSDavid van Moolenbroek 
301*83ee113eSDavid van Moolenbroek 	lease_reference (&class -> billed_leases [i], lease, MDL);
302*83ee113eSDavid van Moolenbroek 	class_reference (&lease -> billing_class, class, MDL);
303*83ee113eSDavid van Moolenbroek 	class -> leases_consumed++;
304*83ee113eSDavid van Moolenbroek 	return 1;
305*83ee113eSDavid van Moolenbroek }
306