aboutsummaryrefslogtreecommitdiff
path: root/server/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/class.c')
-rw-r--r--server/class.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/server/class.c b/server/class.c
new file mode 100644
index 0000000..2f92255
--- /dev/null
+++ b/server/class.c
@@ -0,0 +1,308 @@
+/* class.c
+
+ Handling for client classes. */
+
+/*
+ * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ * This software has been written for Internet Systems Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about Internet Systems Consortium, see
+ * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include "dhcpd.h"
+
+struct collection default_collection = {
+ (struct collection *)0,
+ "default",
+ (struct class *)0,
+};
+
+struct collection *collections = &default_collection;
+struct executable_statement *default_classification_rules;
+
+int have_billing_classes;
+
+/* Build the default classification rule tree. */
+
+void classification_setup ()
+{
+ /* eval ... */
+ default_classification_rules = (struct executable_statement *)0;
+ if (!executable_statement_allocate (&default_classification_rules,
+ MDL))
+ log_fatal ("Can't allocate check of default collection");
+ default_classification_rules -> op = eval_statement;
+
+ /* check-collection "default" */
+ if (!expression_allocate (&default_classification_rules -> data.eval,
+ MDL))
+ log_fatal ("Can't allocate default check expression");
+ default_classification_rules -> data.eval -> op = expr_check;
+ default_classification_rules -> data.eval -> data.check =
+ &default_collection;
+}
+
+void classify_client (packet)
+ struct packet *packet;
+{
+ execute_statements ((struct binding_value **)0, packet,
+ (struct lease *)0, (struct client_state *)0,
+ packet -> options, (struct option_state *)0,
+ &global_scope, default_classification_rules);
+}
+
+int check_collection (packet, lease, collection)
+ struct packet *packet;
+ struct lease *lease;
+ struct collection *collection;
+{
+ struct class *class, *nc;
+ struct data_string data;
+ int matched = 0;
+ int status;
+ int ignorep;
+ int classfound;
+
+ for (class = collection -> classes; class; class = class -> nic) {
+#if defined (DEBUG_CLASS_MATCHING)
+ log_info ("checking against class %s...", class -> name);
+#endif
+ memset (&data, 0, sizeof data);
+
+ /* If there is a "match if" expression, check it. If
+ we get a match, and there's no subclass expression,
+ it's a match. If we get a match and there is a subclass
+ expression, then we check the submatch. If it's not a
+ match, that's final - we don't check the submatch. */
+
+ if (class -> expr) {
+ status = (evaluate_boolean_expression_result
+ (&ignorep, packet, lease,
+ (struct client_state *)0,
+ packet -> options, (struct option_state *)0,
+ lease ? &lease -> scope : &global_scope,
+ class -> expr));
+ if (status) {
+ if (!class -> submatch) {
+ matched = 1;
+#if defined (DEBUG_CLASS_MATCHING)
+ log_info ("matches class.");
+#endif
+ classify (packet, class);
+ continue;
+ }
+ } else
+ continue;
+ }
+
+ /* Check to see if the client matches an existing subclass.
+ If it doesn't, and this is a spawning class, spawn a new
+ subclass and put the client in it. */
+ if (class -> submatch) {
+ status = (evaluate_data_expression
+ (&data, packet, lease,
+ (struct client_state *)0,
+ packet -> options, (struct option_state *)0,
+ lease ? &lease -> scope : &global_scope,
+ class -> submatch, MDL));
+ if (status && data.len) {
+ nc = (struct class *)0;
+ classfound = class_hash_lookup (&nc, class -> hash,
+ (const char *)data.data, data.len, MDL);
+
+#ifdef LDAP_CONFIGURATION
+ if (!classfound && find_subclass_in_ldap (class, &nc, &data))
+ classfound = 1;
+#endif
+
+ if (classfound) {
+#if defined (DEBUG_CLASS_MATCHING)
+ log_info ("matches subclass %s.",
+ print_hex_1 (data.len,
+ data.data, 60));
+#endif
+ data_string_forget (&data, MDL);
+ classify (packet, nc);
+ matched = 1;
+ class_dereference (&nc, MDL);
+ continue;
+ }
+ if (!class -> spawning) {
+ data_string_forget (&data, MDL);
+ continue;
+ }
+ /* XXX Write out the spawned class? */
+#if defined (DEBUG_CLASS_MATCHING)
+ log_info ("spawning subclass %s.",
+ print_hex_1 (data.len, data.data, 60));
+#endif
+ status = class_allocate (&nc, MDL);
+ group_reference (&nc -> group,
+ class -> group, MDL);
+ class_reference (&nc -> superclass,
+ class, MDL);
+ nc -> lease_limit = class -> lease_limit;
+ nc -> dirty = 1;
+ if (nc -> lease_limit) {
+ nc -> billed_leases =
+ (dmalloc
+ (nc -> lease_limit *
+ sizeof (struct lease *),
+ MDL));
+ if (!nc -> billed_leases) {
+ log_error ("no memory for%s",
+ " billing");
+ data_string_forget
+ (&nc -> hash_string,
+ MDL);
+ class_dereference (&nc, MDL);
+ data_string_forget (&data,
+ MDL);
+ continue;
+ }
+ memset (nc -> billed_leases, 0,
+ (nc -> lease_limit *
+ sizeof nc -> billed_leases));
+ }
+ data_string_copy (&nc -> hash_string, &data,
+ MDL);
+ data_string_forget (&data, MDL);
+ if (!class -> hash)
+ class_new_hash(&class->hash,
+ SCLASS_HASH_SIZE, MDL);
+ class_hash_add (class -> hash,
+ (const char *)
+ nc -> hash_string.data,
+ nc -> hash_string.len,
+ nc, MDL);
+ classify (packet, nc);
+ class_dereference (&nc, MDL);
+ }
+ }
+ }
+ return matched;
+}
+
+void classify (packet, class)
+ struct packet *packet;
+ struct class *class;
+{
+ if (packet -> class_count < PACKET_MAX_CLASSES)
+ class_reference (&packet -> classes [packet -> class_count++],
+ class, MDL);
+ else
+ log_error ("too many classes match %s",
+ print_hw_addr (packet -> raw -> htype,
+ packet -> raw -> hlen,
+ packet -> raw -> chaddr));
+}
+
+
+isc_result_t unlink_class(struct class **class) {
+ struct collection *lp;
+ struct class *cp, *pp;
+
+ for (lp = collections; lp; lp = lp -> next) {
+ for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
+ if (cp == *class) {
+ if (pp == 0) {
+ lp->classes = cp->nic;
+ } else {
+ pp->nic = cp->nic;
+ }
+ cp->nic = 0;
+ class_dereference(class, MDL);
+
+ return ISC_R_SUCCESS;
+ }
+ }
+ return ISC_R_NOTFOUND;
+}
+
+
+isc_result_t find_class (struct class **class, const char *name,
+ const char *file, int line)
+{
+ struct collection *lp;
+ struct class *cp;
+
+ for (lp = collections; lp; lp = lp -> next) {
+ for (cp = lp -> classes; cp; cp = cp -> nic)
+ if (cp -> name && !strcmp (name, cp -> name)) {
+ return class_reference (class, cp, file, line);
+ }
+ }
+ return ISC_R_NOTFOUND;
+}
+
+int unbill_class (lease, class)
+ struct lease *lease;
+ struct class *class;
+{
+ int i;
+
+ for (i = 0; i < class -> lease_limit; i++)
+ if (class -> billed_leases [i] == lease)
+ break;
+ if (i == class -> lease_limit) {
+ log_error ("lease %s unbilled with no billing arrangement.",
+ piaddr (lease -> ip_addr));
+ return 0;
+ }
+ class_dereference (&lease -> billing_class, MDL);
+ lease_dereference (&class -> billed_leases [i], MDL);
+ class -> leases_consumed--;
+ return 1;
+}
+
+int bill_class (lease, class)
+ struct lease *lease;
+ struct class *class;
+{
+ int i;
+
+ if (lease -> billing_class) {
+ log_error ("lease billed with existing billing arrangement.");
+ unbill_class (lease, lease -> billing_class);
+ }
+
+ if (class -> leases_consumed == class -> lease_limit)
+ return 0;
+
+ for (i = 0; i < class -> lease_limit; i++)
+ if (!class -> billed_leases [i])
+ break;
+
+ if (i == class -> lease_limit) {
+ log_error ("class billing consumption disagrees with leases.");
+ return 0;
+ }
+
+ lease_reference (&class -> billed_leases [i], lease, MDL);
+ class_reference (&lease -> billing_class, class, MDL);
+ class -> leases_consumed++;
+ return 1;
+}