diff --git a/RELNOTES b/RELNOTES index 04a16b2c..dabff9e6 100644 --- a/RELNOTES +++ b/RELNOTES @@ -69,6 +69,9 @@ work on other platforms. Please report any problems and suggested fixes to supported by ISC; however it may be useful to some users. [ISC-Bugs #20680] +- Add support in v6 for on-commit, on-expire and on-release. + [ISC-Bugs #27912 + Changes since 4.2.5 - Address static analysis warnings. diff --git a/client/dhc6.c b/client/dhc6.c index 8974e7a6..33397183 100644 --- a/client/dhc6.c +++ b/client/dhc6.c @@ -1,7 +1,7 @@ /* dhc6.c - DHCPv6 client routines. */ /* - * Copyright (c) 2012 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2012-2013 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2006-2010 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any @@ -4947,7 +4947,7 @@ make_client6_options(struct client_state *client, struct option_state **op, lease ? lease->options : NULL, *op, &global_scope, client->config->on_transmission, - NULL); + NULL, NULL); /* Rapid-commit is only for SOLICITs. */ if (message != DHCPV6_SOLICIT) diff --git a/client/dhclient.c b/client/dhclient.c index aac80844..6bb677f5 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -1727,13 +1727,10 @@ struct client_lease *packet_to_lease (packet, client) } } - execute_statements_in_scope ((struct binding_value **)0, - (struct packet *)packet, - (struct lease *)0, client, - lease -> options, lease -> options, - &global_scope, - client -> config -> on_receipt, - (struct group *)0); + execute_statements_in_scope(NULL, (struct packet *)packet, NULL, + client, lease->options, lease->options, + &global_scope, client->config->on_receipt, + NULL, NULL); return lease; } @@ -2377,14 +2374,12 @@ make_client_options(struct client_state *client, struct client_lease *lease, } /* Run statements that need to be run on transmission. */ - if (client -> config -> on_transmission) - execute_statements_in_scope - ((struct binding_value **)0, - (struct packet *)0, (struct lease *)0, client, - (lease ? lease -> options : (struct option_state *)0), - *op, &global_scope, - client -> config -> on_transmission, - (struct group *)0); + if (client->config->on_transmission) + execute_statements_in_scope(NULL, NULL, NULL, client, + (lease ? lease->options : NULL), + *op, &global_scope, + client->config->on_transmission, + NULL, NULL); } void make_discover (client, lease) diff --git a/common/execute.c b/common/execute.c index d4c8066d..6b0d16d1 100644 --- a/common/execute.c +++ b/common/execute.c @@ -39,7 +39,8 @@ #include int execute_statements (result, packet, lease, client_state, - in_options, out_options, scope, statements) + in_options, out_options, scope, statements, + on_star) struct binding_value **result; struct packet *packet; struct lease *lease; @@ -48,6 +49,7 @@ int execute_statements (result, packet, lease, client_state, struct option_state *out_options; struct binding_scope **scope; struct executable_statement *statements; + struct on_star *on_star; { struct executable_statement *r, *e, *next; int rc; @@ -59,14 +61,14 @@ int execute_statements (result, packet, lease, client_state, if (!statements) return 1; - r = (struct executable_statement *)0; - next = (struct executable_statement *)0; - e = (struct executable_statement *)0; + r = NULL; + next = NULL; + e = NULL; executable_statement_reference (&r, statements, MDL); while (r && !(result && *result)) { - if (r -> next) - executable_statement_reference (&next, r -> next, MDL); - switch (r -> op) { + if (r->next) + executable_statement_reference (&next, r->next, MDL); + switch (r->op) { case statements_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: statements"); @@ -74,7 +76,8 @@ int execute_statements (result, packet, lease, client_state, status = execute_statements (result, packet, lease, client_state, in_options, out_options, scope, - r -> data.statements); + r->data.statements, + on_star); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: statements returns %d", status); #endif @@ -83,42 +86,50 @@ int execute_statements (result, packet, lease, client_state, break; case on_statement: - if (lease) { - if (r -> data.on.evtypes & ON_EXPIRY) { + /* + * if we haven't been passed an on_star block but + * do have a lease, use the one from the lease + * This handles the previous v4 calls. + */ + if ((on_star == NULL) && (lease != NULL)) + on_star = &lease->on_star; + + if (on_star != NULL) { + if (r->data.on.evtypes & ON_EXPIRY) { #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: on expiry"); #endif - if (lease -> on_expiry) + if (on_star->on_expiry) executable_statement_dereference - (&lease -> on_expiry, MDL); - if (r -> data.on.statements) + (&on_star->on_expiry, MDL); + if (r->data.on.statements) executable_statement_reference - (&lease -> on_expiry, - r -> data.on.statements, MDL); + (&on_star->on_expiry, + r->data.on.statements, MDL); } - if (r -> data.on.evtypes & ON_RELEASE) { + if (r->data.on.evtypes & ON_RELEASE) { #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: on release"); #endif - if (lease -> on_release) + if (on_star->on_release) executable_statement_dereference - (&lease -> on_release, MDL); - if (r -> data.on.statements) + (&on_star->on_release, MDL); + if (r->data.on.statements) executable_statement_reference - (&lease -> on_release, - r -> data.on.statements, MDL); + (&on_star->on_release, + r->data.on.statements, MDL); } - if (r -> data.on.evtypes & ON_COMMIT) { + if (r->data.on.evtypes & ON_COMMIT) { #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: on commit"); #endif - if (lease -> on_commit) + if (on_star->on_commit) executable_statement_dereference - (&lease -> on_commit, MDL); - if (r -> data.on.statements) + (&on_star->on_commit, MDL); + if (r->data.on.statements) executable_statement_reference - (&lease -> on_commit, - r -> data.on.statements, MDL); + (&on_star->on_commit, + r->data.on.statements, MDL); } } break; @@ -130,15 +141,16 @@ int execute_statements (result, packet, lease, client_state, status = (find_matching_case (&e, packet, lease, client_state, in_options, out_options, scope, - r -> data.s_switch.expr, - r -> data.s_switch.statements)); + r->data.s_switch.expr, + r->data.s_switch.statements)); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: switch: case %lx", (unsigned long)e); #endif if (status) { if (!(execute_statements (result, packet, lease, client_state, - in_options, out_options, scope, e))) { + in_options, out_options, scope, e, + on_star))) { executable_statement_dereference (&e, MDL); return 0; @@ -156,7 +168,7 @@ int execute_statements (result, packet, lease, client_state, status = (evaluate_boolean_expression (&rc, packet, lease, client_state, in_options, - out_options, scope, r -> data.ie.expr)); + out_options, scope, r->data.ie.expr)); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: if %s", (status @@ -169,15 +181,15 @@ int execute_statements (result, packet, lease, client_state, if (!execute_statements (result, packet, lease, client_state, in_options, out_options, scope, - rc ? r -> data.ie.tc : r -> data.ie.fc)) + rc ? r->data.ie.tc : r->data.ie.fc, + on_star)) return 0; break; case eval_statement: status = evaluate_expression - ((struct binding_value **)0, - packet, lease, client_state, in_options, - out_options, scope, r -> data.eval, MDL); + (NULL, packet, lease, client_state, in_options, + out_options, scope, r->data.eval, MDL); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: evaluate: %s", (status ? "succeeded" : "failed")); @@ -281,11 +293,11 @@ int execute_statements (result, packet, lease, client_state, case add_statement: #if defined (DEBUG_EXPRESSIONS) - log_debug ("exec: add %s", (r -> data.add -> name - ? r -> data.add -> name + log_debug ("exec: add %s", (r->data.add->name + ? r->data.add->name : "")); #endif - classify (packet, r -> data.add); + classify (packet, r->data.add); break; case break_statement: @@ -298,35 +310,35 @@ int execute_statements (result, packet, lease, client_state, case send_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: %s option %s.%s", - (r -> op == supersede_option_statement + (r->op == supersede_option_statement ? "supersede" : "send"), - r -> data.option -> option -> universe -> name, - r -> data.option -> option -> name); + r->data.option->option->universe->name, + r->data.option->option->name); goto option_statement; #endif case default_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: default option %s.%s", - r -> data.option -> option -> universe -> name, - r -> data.option -> option -> name); + r->data.option->option->universe->name, + r->data.option->option->name); goto option_statement; #endif case append_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: append option %s.%s", - r -> data.option -> option -> universe -> name, - r -> data.option -> option -> name); + r->data.option->option->universe->name, + r->data.option->option->name); goto option_statement; #endif case prepend_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: prepend option %s.%s", - r -> data.option -> option -> universe -> name, - r -> data.option -> option -> name); + r->data.option->option->universe->name, + r->data.option->option->name); option_statement: #endif - set_option (r -> data.option -> option -> universe, - out_options, r -> data.option, r -> op); + set_option (r->data.option->option->universe, + out_options, r->data.option, r->op); break; case set_statement: @@ -407,16 +419,16 @@ int execute_statements (result, packet, lease, client_state, case unset_statement: if (!scope || !*scope) break; - binding = find_binding (*scope, r -> data.unset); + binding = find_binding (*scope, r->data.unset); if (binding) { - if (binding -> value) + if (binding->value) binding_value_dereference - (&binding -> value, MDL); + (&binding->value, MDL); status = 1; } else status = 0; #if defined (DEBUG_EXPRESSIONS) - log_debug ("exec: unset %s: %s", r -> data.unset, + log_debug ("exec: unset %s: %s", r->data.unset, (status ? "found" : "not found")); #else POST(status); @@ -482,10 +494,9 @@ int execute_statements (result, packet, lease, client_state, binding_scope_reference(&ns->outer, *scope, MDL); execute_statements - (result, packet, lease, - client_state, + (result, packet, lease, client_state, in_options, out_options, - &ns, e->data.let.statements); + &ns, e->data.let.statements, on_star); } if (ns) binding_scope_dereference(&ns, MDL); @@ -496,15 +507,14 @@ int execute_statements (result, packet, lease, client_state, status = (evaluate_data_expression (&ds, packet, lease, client_state, in_options, - out_options, scope, r -> data.log.expr, - MDL)); + out_options, scope, r->data.log.expr, MDL)); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: log"); #endif if (status) { - switch (r -> data.log.priority) { + switch (r->data.log.priority) { case log_priority_fatal: log_fatal ("%.*s", (int)ds.len, ds.data); @@ -550,7 +560,7 @@ int execute_statements (result, packet, lease, client_state, void execute_statements_in_scope (result, packet, lease, client_state, in_options, out_options, - scope, group, limiting_group) + scope, group, limiting_group, on_star) struct binding_value **result; struct packet *packet; struct lease *lease; @@ -560,6 +570,7 @@ void execute_statements_in_scope (result, packet, struct binding_scope **scope; struct group *group; struct group *limiting_group; + struct on_star *on_star; { struct group *limit; @@ -599,9 +610,10 @@ void execute_statements_in_scope (result, packet, execute_statements_in_scope (result, packet, lease, client_state, in_options, out_options, scope, - group -> next, limiting_group); + group->next, limiting_group, + on_star); execute_statements (result, packet, lease, client_state, in_options, - out_options, scope, group -> statements); + out_options, scope, group->statements, on_star); } /* Dereference or free any subexpressions of a statement being freed. */ @@ -1033,14 +1045,14 @@ int find_matching_case (struct executable_statement **ep, sub = (evaluate_data_expression (&cd, packet, lease, client_state, in_options, out_options, - scope, s -> data.c_case, MDL)); + scope, s->data.c_case, MDL)); if (sub && cd.len == ds.len && !memcmp (cd.data, ds.data, cd.len)) { data_string_forget (&cd, MDL); data_string_forget (&ds, MDL); executable_statement_reference - (ep, s -> next, MDL); + (ep, s->next, MDL); return 1; } data_string_forget (&cd, MDL); @@ -1056,15 +1068,15 @@ int find_matching_case (struct executable_statement **ep, scope, expr); if (status) { - for (s = stmt; s; s = s -> next) { + for (s = stmt; s; s = s->next) { if (s -> op == case_statement) { sub = (evaluate_numeric_expression (&c, packet, lease, client_state, in_options, out_options, - scope, s -> data.c_case)); + scope, s->data.c_case)); if (sub && n == c) { executable_statement_reference - (ep, s -> next, MDL); + (ep, s->next, MDL); return 1; } } @@ -1074,11 +1086,11 @@ int find_matching_case (struct executable_statement **ep, /* If we didn't find a matching case statement, look for a default statement and return the statement following it. */ - for (s = stmt; s; s = s -> next) - if (s -> op == default_statement) + for (s = stmt; s; s = s->next) + if (s->op == default_statement) break; if (s) { - executable_statement_reference (ep, s -> next, MDL); + executable_statement_reference (ep, s->next, MDL); return 1; } return 0; @@ -1093,17 +1105,17 @@ int executable_statement_foreach (struct executable_statement *stmt, struct executable_statement *foo; int ok = 0; - for (foo = stmt; foo; foo = foo -> next) { + for (foo = stmt; foo; foo = foo->next) { if ((*callback) (foo, vp, condp) != 0) ok = 1; - switch (foo -> op) { + switch (foo->op) { case null_statement: break; case if_statement: - if (executable_statement_foreach (foo -> data.ie.tc, + if (executable_statement_foreach (foo->data.ie.tc, callback, vp, 1)) ok = 1; - if (executable_statement_foreach (foo -> data.ie.fc, + if (executable_statement_foreach (foo->data.ie.fc, callback, vp, 1)) ok = 1; break; @@ -1125,17 +1137,17 @@ int executable_statement_foreach (struct executable_statement *stmt, break; case statements_statement: if ((executable_statement_foreach - (foo -> data.statements, callback, vp, condp))) + (foo->data.statements, callback, vp, condp))) ok = 1; break; case on_statement: if ((executable_statement_foreach - (foo -> data.on.statements, callback, vp, 1))) + (foo->data.on.statements, callback, vp, 1))) ok = 1; break; case switch_statement: if ((executable_statement_foreach - (foo -> data.s_switch.statements, callback, vp, 1))) + (foo->data.s_switch.statements, callback, vp, 1))) ok = 1; break; case case_statement: @@ -1148,7 +1160,7 @@ int executable_statement_foreach (struct executable_statement *stmt, break; case let_statement: if ((executable_statement_foreach - (foo -> data.let.statements, callback, vp, 0))) + (foo->data.let.statements, callback, vp, 0))) ok = 1; break; case define_statement: diff --git a/common/tree.c b/common/tree.c index b9a88b9f..33c5630d 100644 --- a/common/tree.c +++ b/common/tree.c @@ -618,7 +618,7 @@ int evaluate_expression (result, packet, lease, client_state, status = (execute_statements (&bv, packet, lease, client_state, in_options, cfg_options, &ns, - binding -> value -> value.fundef -> statements)); + binding->value->value.fundef->statements, NULL)); binding_scope_dereference (&ns, MDL); if (!bv) diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 4c5cef0c..0e96d5b3 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -497,6 +497,16 @@ typedef u_int8_t binding_state_t; /* FTS_LAST is the highest value that is valid for a lease binding state. */ #define FTS_LAST FTS_BACKUP +/* + * A block for the on statements so we can share the structure + * between v4 and v6 + */ +struct on_star { + struct executable_statement *on_expiry; + struct executable_statement *on_commit; + struct executable_statement *on_release; +}; + /* A dhcp lease declaration structure. */ struct lease { OMAPI_OBJECT_PREAMBLE; @@ -513,9 +523,8 @@ struct lease { struct class *billing_class; struct option_chain_head *agent_options; - struct executable_statement *on_expiry; - struct executable_statement *on_commit; - struct executable_statement *on_release; + /* insert the structure directly */ + struct on_star on_star; unsigned char *uid; unsigned short uid_len; @@ -1503,6 +1512,8 @@ struct iasubopt { */ struct dhcp_ddns_cb *ddns_cb; + /* space for the on * executable statements */ + struct on_star on_star; }; struct ia_xx { @@ -2079,7 +2090,8 @@ int evaluate_data_expression (struct data_string *, struct option_state *, struct option_state *, struct binding_scope **, - struct expression *, const char *, int); + struct expression *, + const char *, int); int evaluate_numeric_expression (unsigned long *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, @@ -2944,14 +2956,16 @@ int execute_statements (struct binding_value **result, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, - struct executable_statement *); + struct executable_statement *, + struct on_star *); void execute_statements_in_scope (struct binding_value **result, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, - struct group *, struct group *); + struct group *, struct group *, + struct on_star *); int executable_statement_dereference (struct executable_statement **, const char *, int); void write_statements (FILE *, struct executable_statement *, int); diff --git a/server/bootp.c b/server/bootp.c index f0b787c1..a0508ce4 100644 --- a/server/bootp.c +++ b/server/bootp.c @@ -3,7 +3,7 @@ BOOTP Protocol support. */ /* - * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2009,2012-2013 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * @@ -160,28 +160,26 @@ void bootp (packet) option_state_allocate (&options, MDL); /* Execute the subnet statements. */ - execute_statements_in_scope ((struct binding_value **)0, - packet, lease, (struct client_state *)0, - packet -> options, options, - &lease -> scope, lease -> subnet -> group, - (struct group *)0); + execute_statements_in_scope (NULL, packet, lease, NULL, + packet->options, options, + &lease->scope, lease->subnet->group, + NULL, NULL); /* Execute statements from class scopes. */ for (i = packet -> class_count; i > 0; i--) { - execute_statements_in_scope - ((struct binding_value **)0, - packet, lease, (struct client_state *)0, - packet -> options, options, - &lease -> scope, packet -> classes [i - 1] -> group, - lease -> subnet -> group); + execute_statements_in_scope(NULL, packet, lease, NULL, + packet->options, options, + &lease->scope, + packet->classes[i - 1]->group, + lease->subnet->group, NULL); } /* Execute the host statements. */ if (hp != NULL) { execute_statements_in_scope (NULL, packet, lease, NULL, packet->options, options, - &lease->scope, - hp->group, lease->subnet->group); + &lease->scope, hp->group, + lease->subnet->group, NULL); } /* Drop the request if it's not allowed for this client. */ @@ -340,10 +338,9 @@ void bootp (packet) } /* Execute the commit statements, if there are any. */ - execute_statements ((struct binding_value **)0, - packet, lease, (struct client_state *)0, - packet -> options, - options, &lease -> scope, lease -> on_commit); + execute_statements (NULL, packet, lease, NULL, packet->options, + options, &lease->scope, lease->on_star.on_commit, + NULL); /* We're done with the option state. */ option_state_dereference (&options, MDL); diff --git a/server/class.c b/server/class.c index b8eac87c..7bfb6b7e 100644 --- a/server/class.c +++ b/server/class.c @@ -3,7 +3,7 @@ Handling for client classes. */ /* - * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2009,2012-2013 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1998-2003 by Internet Software Consortium * @@ -69,10 +69,8 @@ void classification_setup () 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); + execute_statements (NULL, packet, NULL, NULL, packet->options, NULL, + &global_scope, default_classification_rules, NULL); } int check_collection (packet, lease, collection) diff --git a/server/confpars.c b/server/confpars.c index 97b42c84..3cd35a03 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -3248,19 +3248,19 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile) return 0; } seenbit = 0; - if ((on -> data.on.evtypes & ON_EXPIRY) && - on -> data.on.statements) { + if ((on->data.on.evtypes & ON_EXPIRY) && + on->data.on.statements) { seenbit |= 16384; executable_statement_reference - (&lease -> on_expiry, - on -> data.on.statements, MDL); + (&lease->on_star.on_expiry, + on->data.on.statements, MDL); } - if ((on -> data.on.evtypes & ON_RELEASE) && - on -> data.on.statements) { + if ((on->data.on.evtypes & ON_RELEASE) && + on->data.on.statements) { seenbit |= 32768; executable_statement_reference - (&lease -> on_release, - on -> data.on.statements, MDL); + (&lease->on_star.on_release, + on->data.on.statements, MDL); } executable_statement_dereference (&on, MDL); break; @@ -3400,31 +3400,31 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile) /* If no binding state is specified, make one up. */ if (!(seenmask & 256)) { - if (lease -> ends > cur_time || - lease -> on_expiry || lease -> on_release) - lease -> binding_state = FTS_ACTIVE; + if (lease->ends > cur_time || + lease->on_star.on_expiry || lease->on_star.on_release) + lease->binding_state = FTS_ACTIVE; #if defined (FAILOVER_PROTOCOL) - else if (lease -> pool && lease -> pool -> failover_peer) - lease -> binding_state = FTS_EXPIRED; + else if (lease->pool && lease->pool->failover_peer) + lease->binding_state = FTS_EXPIRED; #endif else - lease -> binding_state = FTS_FREE; - if (lease -> binding_state == FTS_ACTIVE) { + lease->binding_state = FTS_FREE; + if (lease->binding_state == FTS_ACTIVE) { #if defined (FAILOVER_PROTOCOL) - if (lease -> pool && lease -> pool -> failover_peer) - lease -> next_binding_state = FTS_EXPIRED; + if (lease->pool && lease->pool->failover_peer) + lease->next_binding_state = FTS_EXPIRED; else #endif - lease -> next_binding_state = FTS_FREE; + lease->next_binding_state = FTS_FREE; } else - lease -> next_binding_state = lease -> binding_state; + lease->next_binding_state = lease->binding_state; /* The most conservative rewind state implies no rewind. */ lease->rewind_binding_state = lease->binding_state; } if (!(seenmask & 65536)) - lease -> tstp = lease -> ends; + lease->tstp = lease->ends; lease_reference (lp, lease, MDL); lease_dereference (&lease, MDL); @@ -4146,9 +4146,11 @@ parse_ia_na_declaration(struct parse *cfile) { struct ipv6_pool *pool; char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; isc_boolean_t newbinding; - struct binding_scope *scope=NULL; + struct binding_scope *scope = NULL; struct binding *bnd; - struct binding_value *nv=NULL; + struct binding_value *nv = NULL; + struct executable_statement *on_star[2] = {NULL, NULL}; + int lose, i; if (local_family != AF_INET6) { parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode."); @@ -4409,6 +4411,41 @@ parse_ia_na_declaration(struct parse *cfile) { parse_semi(cfile); break; + case ON: + lose = 0; + /* + * Depending on the user config we may + * have one or two on statements. We + * need to save information about both + * of them until we allocate the + * iasubopt to hold them. + */ + if (on_star[0] == NULL) { + if (!parse_on_statement (&on_star[0], + cfile, + &lose)) { + parse_warn(cfile, + "corrupt lease " + "file; bad ON " + "statement"); + skip_to_rbrace (cfile, 1); + return; + } + } else { + if (!parse_on_statement (&on_star[1], + cfile, + &lose)) { + parse_warn(cfile, + "corrupt lease " + "file; bad ON " + "statement"); + skip_to_rbrace (cfile, 1); + return; + } + } + + break; + default: parse_warn(cfile, "corrupt lease file; " "expecting ia_na contents, " @@ -4446,6 +4483,30 @@ parse_ia_na_declaration(struct parse *cfile) { binding_scope_dereference(&scope, MDL); } + /* + * Check on both on statements. Because of how we write the + * lease file we know which is which if we have two but it's + * easier to write the code to be independent. We do assume + * that the statements won't overlap. + */ + for (i = 0; + (i < 2) && on_star[i] != NULL ; + i++) { + if ((on_star[i]->data.on.evtypes & ON_EXPIRY) && + on_star[i]->data.on.statements) { + executable_statement_reference + (&iaaddr->on_star.on_expiry, + on_star[i]->data.on.statements, MDL); + } + if ((on_star[i]->data.on.evtypes & ON_RELEASE) && + on_star[i]->data.on.statements) { + executable_statement_reference + (&iaaddr->on_star.on_release, + on_star[i]->data.on.statements, MDL); + } + executable_statement_dereference (&on_star[i], MDL); + } + /* find the pool this address is in */ pool = NULL; if (find_ipv6_pool(&pool, D6O_IA_NA, @@ -4527,9 +4588,11 @@ parse_ia_ta_declaration(struct parse *cfile) { struct ipv6_pool *pool; char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; isc_boolean_t newbinding; - struct binding_scope *scope=NULL; + struct binding_scope *scope = NULL; struct binding *bnd; - struct binding_value *nv=NULL; + struct binding_value *nv = NULL; + struct executable_statement *on_star[2] = {NULL, NULL}; + int lose, i; if (local_family != AF_INET6) { parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode."); @@ -4790,6 +4853,41 @@ parse_ia_ta_declaration(struct parse *cfile) { parse_semi(cfile); break; + case ON: + lose = 0; + /* + * Depending on the user config we may + * have one or two on statements. We + * need to save information about both + * of them until we allocate the + * iasubopt to hold them. + */ + if (on_star[0] == NULL) { + if (!parse_on_statement (&on_star[0], + cfile, + &lose)) { + parse_warn(cfile, + "corrupt lease " + "file; bad ON " + "statement"); + skip_to_rbrace (cfile, 1); + return; + } + } else { + if (!parse_on_statement (&on_star[1], + cfile, + &lose)) { + parse_warn(cfile, + "corrupt lease " + "file; bad ON " + "statement"); + skip_to_rbrace (cfile, 1); + return; + } + } + + break; + default: parse_warn(cfile, "corrupt lease file; " "expecting ia_ta contents, " @@ -4827,6 +4925,30 @@ parse_ia_ta_declaration(struct parse *cfile) { binding_scope_dereference(&scope, MDL); } + /* + * Check on both on statements. Because of how we write the + * lease file we know which is which if we have two but it's + * easier to write the code to be independent. We do assume + * that the statements won't overlap. + */ + for (i = 0; + (i < 2) && on_star[i] != NULL ; + i++) { + if ((on_star[i]->data.on.evtypes & ON_EXPIRY) && + on_star[i]->data.on.statements) { + executable_statement_reference + (&iaaddr->on_star.on_expiry, + on_star[i]->data.on.statements, MDL); + } + if ((on_star[i]->data.on.evtypes & ON_RELEASE) && + on_star[i]->data.on.statements) { + executable_statement_reference + (&iaaddr->on_star.on_release, + on_star[i]->data.on.statements, MDL); + } + executable_statement_dereference (&on_star[i], MDL); + } + /* find the pool this address is in */ pool = NULL; if (find_ipv6_pool(&pool, D6O_IA_TA, @@ -4909,9 +5031,11 @@ parse_ia_pd_declaration(struct parse *cfile) { struct ipv6_pool *pool; char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; isc_boolean_t newbinding; - struct binding_scope *scope=NULL; + struct binding_scope *scope = NULL; struct binding *bnd; - struct binding_value *nv=NULL; + struct binding_value *nv = NULL; + struct executable_statement *on_star[2] = {NULL, NULL}; + int lose, i; if (local_family != AF_INET6) { parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode."); @@ -5172,6 +5296,41 @@ parse_ia_pd_declaration(struct parse *cfile) { parse_semi(cfile); break; + case ON: + lose = 0; + /* + * Depending on the user config we may + * have one or two on statements. We + * need to save information about both + * of them until we allocate the + * iasubopt to hold them. + */ + if (on_star[0] == NULL) { + if (!parse_on_statement (&on_star[0], + cfile, + &lose)) { + parse_warn(cfile, + "corrupt lease " + "file; bad ON " + "statement"); + skip_to_rbrace (cfile, 1); + return; + } + } else { + if (!parse_on_statement (&on_star[1], + cfile, + &lose)) { + parse_warn(cfile, + "corrupt lease " + "file; bad ON " + "statement"); + skip_to_rbrace (cfile, 1); + return; + } + } + + break; + default: parse_warn(cfile, "corrupt lease file; " "expecting ia_pd contents, " @@ -5209,6 +5368,30 @@ parse_ia_pd_declaration(struct parse *cfile) { binding_scope_dereference(&scope, MDL); } + /* + * Check on both on statements. Because of how we write the + * lease file we know which is which if we have two but it's + * easier to write the code to be independent. We do assume + * that the statements won't overlap. + */ + for (i = 0; + (i < 2) && on_star[i] != NULL ; + i++) { + if ((on_star[i]->data.on.evtypes & ON_EXPIRY) && + on_star[i]->data.on.statements) { + executable_statement_reference + (&iapref->on_star.on_expiry, + on_star[i]->data.on.statements, MDL); + } + if ((on_star[i]->data.on.evtypes & ON_RELEASE) && + on_star[i]->data.on.statements) { + executable_statement_reference + (&iapref->on_star.on_release, + on_star[i]->data.on.statements, MDL); + } + executable_statement_dereference (&on_star[i], MDL); + } + /* find the pool this address is in */ pool = NULL; if (find_ipv6_pool(&pool, D6O_IA_PD, diff --git a/server/db.c b/server/db.c index de185293..94abfbde 100644 --- a/server/db.c +++ b/server/db.c @@ -3,7 +3,8 @@ Persistent database management routines for DHCPD... */ /* - * Copyright (c) 2004-2010,2012 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2012,2013 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any @@ -264,21 +265,22 @@ int write_lease (lease) } else ++errors; } - if (lease -> on_expiry) { + if (lease->on_star.on_expiry) { errno = 0; fprintf (db_file, "\n on expiry%s {", - lease -> on_expiry == lease -> on_release + lease->on_star.on_expiry == lease->on_star.on_release ? " or release" : ""); - write_statements (db_file, lease -> on_expiry, 4); + write_statements (db_file, lease->on_star.on_expiry, 4); /* XXX */ fprintf (db_file, "\n }"); if (errno) ++errors; } - if (lease -> on_release && lease -> on_release != lease -> on_expiry) { + if (lease->on_star.on_release && + lease->on_star.on_release != lease->on_star.on_expiry) { errno = 0; fprintf (db_file, "\n on release {"); - write_statements (db_file, lease -> on_release, 4); + write_statements (db_file, lease->on_star.on_release, 4); /* XXX */ fprintf (db_file, "\n }"); if (errno) @@ -642,6 +644,29 @@ write_ia(const struct ia_xx *ia) { } + if (iasubopt->on_star.on_expiry) { + if (fprintf(db_file, "\n on expiry%s {", + iasubopt->on_star.on_expiry == + iasubopt->on_star.on_release + ? " or release" : "") < 0) + goto error_exit; + write_statements(db_file, + iasubopt->on_star.on_expiry, 6); + if (fprintf(db_file, "\n }") < 0) + goto error_exit; + } + + if (iasubopt->on_star.on_release && + iasubopt->on_star.on_release != + iasubopt->on_star.on_expiry) { + if (fprintf(db_file, "\n on release {") < 0) + goto error_exit; + write_statements(db_file, + iasubopt->on_star.on_release, 6); + if (fprintf(db_file, "\n }") < 0) + goto error_exit; + } + if (fprintf(db_file, "\n }\n") < 0) goto error_exit; } diff --git a/server/ddns.c b/server/ddns.c index 80418721..74021fcd 100644 --- a/server/ddns.c +++ b/server/ddns.c @@ -4,7 +4,7 @@ /* * - * Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2009-2013 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2000-2003 by Internet Software Consortium * @@ -275,16 +275,20 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, So if the expiry and release events look like they're the same, run them. This should delete the old DDNS data. */ - if (old -> on_expiry == old -> on_release) { + if (old->on_star.on_expiry == + old->on_star.on_release) { execute_statements(NULL, NULL, lease, NULL, NULL, NULL, scope, - old->on_expiry); - if (old -> on_expiry) + old->on_star.on_expiry, + NULL); + if (old->on_star.on_expiry) executable_statement_dereference - (&old -> on_expiry, MDL); - if (old -> on_release) + (&old->on_star.on_expiry, + MDL); + if (old->on_star.on_release) executable_statement_dereference - (&old -> on_release, MDL); + (&old->on_star.on_release, + MDL); /* Now, install the DDNS data the new way. */ goto in; } diff --git a/server/dhcp.c b/server/dhcp.c index 81095521..29ab5109 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -907,21 +907,18 @@ void dhcpdecline (packet, ms_nulltp) /* Execute statements in scope starting with the subnet scope. */ if (lease) - execute_statements_in_scope ((struct binding_value **)0, - packet, (struct lease *)0, - (struct client_state *)0, - packet -> options, options, - &global_scope, - lease -> subnet -> group, - (struct group *)0); + execute_statements_in_scope(NULL, packet, NULL, NULL, + packet->options, options, + &global_scope, + lease->subnet->group, + NULL, NULL); /* Execute statements in the class scopes. */ for (i = packet -> class_count; i > 0; i--) { execute_statements_in_scope - ((struct binding_value **)0, packet, (struct lease *)0, - (struct client_state *)0, packet -> options, options, - &global_scope, packet -> classes [i - 1] -> group, - lease ? lease -> subnet -> group : (struct group *)0); + (NULL, packet, NULL, NULL, packet->options, options, + &global_scope, packet->classes[i - 1]->group, + lease ? lease->subnet->group : NULL, NULL); } /* Drop the request if dhcpdeclines are being ignored. */ @@ -1082,20 +1079,19 @@ void dhcpinform (packet, ms_nulltp) /* Execute statements in scope starting with the subnet scope. */ if (subnet) - execute_statements_in_scope ((struct binding_value **)0, - packet, (struct lease *)0, - (struct client_state *)0, - packet -> options, options, - &global_scope, subnet -> group, - (struct group *)0); + execute_statements_in_scope (NULL, packet, NULL, NULL, + packet->options, options, + &global_scope, subnet->group, + NULL, NULL); /* Execute statements in the class scopes. */ for (i = packet -> class_count; i > 0; i--) { - execute_statements_in_scope - ((struct binding_value **)0, packet, (struct lease *)0, - (struct client_state *)0, packet -> options, options, - &global_scope, packet -> classes [i - 1] -> group, - subnet ? subnet -> group : (struct group *)0); + execute_statements_in_scope(NULL, packet, NULL, NULL, + packet->options, options, + &global_scope, + packet->classes[i - 1]->group, + subnet ? subnet->group : NULL, + NULL); } /* Figure out the filename. */ @@ -1604,47 +1600,45 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) REQUEST our offer, it will expire in 2 minutes, overriding the expire time in the currently in force lease. We want the expire events to be executed at that point. */ - if (lease -> ends <= cur_time && offer != DHCPOFFER) { + if (lease->ends <= cur_time && offer != DHCPOFFER) { /* Get rid of any old expiry or release statements - by executing the statements below, we will be inserting new ones if there are any to insert. */ - if (lease -> on_expiry) - executable_statement_dereference (&lease -> on_expiry, - MDL); - if (lease -> on_commit) - executable_statement_dereference (&lease -> on_commit, - MDL); - if (lease -> on_release) - executable_statement_dereference (&lease -> on_release, - MDL); + if (lease->on_star.on_expiry) + executable_statement_dereference + (&lease->on_star.on_expiry, MDL); + if (lease->on_star.on_commit) + executable_statement_dereference + (&lease->on_star.on_commit, MDL); + if (lease->on_star.on_release) + executable_statement_dereference + (&lease->on_star.on_release, MDL); } /* Execute statements in scope starting with the subnet scope. */ - execute_statements_in_scope ((struct binding_value **)0, - packet, lease, (struct client_state *)0, - packet -> options, - state -> options, &lease -> scope, - lease -> subnet -> group, - (struct group *)0); + execute_statements_in_scope (NULL, packet, lease, + NULL, packet->options, + state->options, &lease->scope, + lease->subnet->group, NULL, NULL); /* If the lease is from a pool, run the pool scope. */ - if (lease -> pool) - (execute_statements_in_scope - ((struct binding_value **)0, packet, lease, - (struct client_state *)0, packet -> options, - state -> options, &lease -> scope, lease -> pool -> group, - lease -> pool -> shared_network -> group)); + if (lease->pool) + (execute_statements_in_scope(NULL, packet, lease, NULL, + packet->options, state->options, + &lease->scope, lease->pool->group, + lease->pool-> + shared_network->group, + NULL)); /* Execute statements from class scopes. */ for (i = packet -> class_count; i > 0; i--) { - execute_statements_in_scope - ((struct binding_value **)0, - packet, lease, (struct client_state *)0, - packet -> options, state -> options, - &lease -> scope, packet -> classes [i - 1] -> group, - (lease -> pool - ? lease -> pool -> group - : lease -> subnet -> group)); + execute_statements_in_scope(NULL, packet, lease, NULL, + packet->options, state->options, + &lease->scope, + packet->classes[i - 1]->group, + (lease->pool ? lease->pool->group + : lease->subnet->group), + NULL); } /* See if the client is only supposed to have one lease at a time, @@ -1829,7 +1823,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) host_dereference(&hp, MDL); } if (!host) { - find_hosts_by_option(&hp, packet, packet->options, MDL); + find_hosts_by_option(&hp, packet, + packet->options, MDL); for (h = hp; h; h = h -> n_ipaddr) { if (!h -> fixed_addr) break; @@ -1844,15 +1839,13 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) /* If we have a host_decl structure, run the options associated with its group. Whether the host decl struct is old or not. */ if (host) - execute_statements_in_scope ((struct binding_value **)0, - packet, lease, - (struct client_state *)0, - packet -> options, - state -> options, &lease -> scope, - host -> group, - (lease -> pool - ? lease -> pool -> group - : lease -> subnet -> group)); + execute_statements_in_scope (NULL, packet, lease, NULL, + packet->options, state->options, + &lease->scope, host->group, + (lease->pool + ? lease->pool->group + : lease->subnet->group), + NULL); /* Drop the request if it's not allowed for this client. By default, unknown clients are allowed. */ @@ -2485,15 +2478,13 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) /* If there are statements to execute when the lease is committed, execute them. */ - if (lease -> on_commit && (!offer || offer == DHCPACK)) { - execute_statements ((struct binding_value **)0, - packet, lt, (struct client_state *)0, - packet -> options, - state -> options, < -> scope, - lease -> on_commit); - if (lease -> on_commit) - executable_statement_dereference (&lease -> on_commit, - MDL); + if (lease->on_star.on_commit && (!offer || offer == DHCPACK)) { + execute_statements (NULL, packet, lt, NULL, packet->options, + state->options, <->scope, + lease->on_star.on_commit, NULL); + if (lease->on_star.on_commit) + executable_statement_dereference + (&lease->on_star.on_commit, MDL); } #ifdef NSUPDATE @@ -4593,13 +4584,13 @@ setup_server_source_address(struct in_addr *from, packet->options, sid_options, &global_scope, packet->shared_network->subnets->group, - NULL); + NULL, NULL); } else { execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, sid_options, &global_scope, packet->shared_network->group, - NULL); + NULL, NULL); } /* do the pool if there is one */ @@ -4608,7 +4599,8 @@ setup_server_source_address(struct in_addr *from, packet->options, sid_options, &global_scope, packet->shared_network->pools->group, - packet->shared_network->group); + packet->shared_network->group, + NULL); } /* currently we don't bother with classes or hosts as diff --git a/server/dhcpd.c b/server/dhcpd.c index 365a3d25..b5e11e5f 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -883,14 +883,9 @@ void postconf_initialization (int quiet) /* Now try to get the lease file name. */ option_state_allocate (&options, MDL); - execute_statements_in_scope ((struct binding_value **)0, - (struct packet *)0, - (struct lease *)0, - (struct client_state *)0, - (struct option_state *)0, - options, &global_scope, - root_group, - (struct group *)0); + execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, + options, &global_scope, root_group, + NULL, NULL); memset (&db, 0, sizeof db); oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME); if (oc && diff --git a/server/dhcpleasequery.c b/server/dhcpleasequery.c index 848611b9..0766b849 100644 --- a/server/dhcpleasequery.c +++ b/server/dhcpleasequery.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2011-2013 by Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2006-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any @@ -204,26 +204,16 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) { return; } - execute_statements_in_scope(NULL, - packet, - NULL, - NULL, - packet->options, - options, - &global_scope, - relay_group, - NULL); + execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, + options, &global_scope, relay_group, + NULL, NULL); for (i=packet->class_count-1; i>=0; i--) { - execute_statements_in_scope(NULL, - packet, - NULL, - NULL, - packet->options, - options, + execute_statements_in_scope(NULL, packet, NULL, NULL, + packet->options, options, &global_scope, packet->classes[i]->group, - relay_group); + relay_group, NULL); } /* @@ -1093,7 +1083,7 @@ dhcpv6_leasequery(struct data_string *reply_ret, struct packet *packet) { } execute_statements_in_scope(NULL, lq.packet, NULL, NULL, lq.packet->options, lq.reply_opts, - &global_scope, root_group, NULL); + &global_scope, root_group, NULL, NULL); lq.buf.reply.msg_type = DHCPV6_LEASEQUERY_REPLY; diff --git a/server/dhcpv6.c b/server/dhcpv6.c index 210ec2df..b47825f0 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -81,6 +81,9 @@ struct reply_state { /* Index into the data field that has been consumed. */ unsigned cursor; + /* Space for the on commit statements for a fixed host */ + struct on_star on_star; + union reply_buffer { unsigned char data[65536]; struct dhcpv6_packet reply; @@ -230,7 +233,8 @@ set_server_duid_from_option(void) { } execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, - opt_state, &global_scope, root_group, NULL); + opt_state, &global_scope, root_group, + NULL, NULL); oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID); if (oc == NULL) { @@ -820,7 +824,7 @@ start_reply(struct packet *packet, } execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, *opt_state, - &global_scope, root_group, NULL); + &global_scope, root_group, NULL, NULL); /* * A small bit of special handling for Solicit messages. @@ -1405,16 +1409,18 @@ lease_to_client(struct data_string *reply_ret, execute_statements_in_scope(NULL, reply.packet, NULL, NULL, reply.packet->options, reply.opt_state, &global_scope, - reply.shared->group, root_group); + reply.shared->group, root_group, + NULL); /* Bring in any configuration from a host record. */ if (reply.host != NULL) - execute_statements_in_scope(NULL, reply.packet, NULL, - NULL, reply.packet->options, + execute_statements_in_scope(NULL, reply.packet, + NULL, NULL, + reply.packet->options, reply.opt_state, &global_scope, reply.host->group, - reply.shared->group); + reply.shared->group, NULL); } /* @@ -1841,6 +1847,19 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) { renew_lease6(tmp->ipv6_pool, tmp); schedule_lease_timeout(tmp->ipv6_pool); + /* If we have anything to do on commit do it now */ + if (tmp->on_star.on_commit != NULL) { + execute_statements(NULL, reply->packet, + NULL, NULL, + reply->packet->options, + reply->opt_state, + &reply->lease->scope, + tmp->on_star.on_commit, + &tmp->on_star); + executable_statement_dereference + (&tmp->on_star.on_commit, MDL); + } + #if defined (NSUPDATE) /* * Perform ddns updates. @@ -1878,6 +1897,20 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) { write_ia(reply->ia); } + /* + * If this would be a hard binding for a static lease + * run any commit statements that we have + */ + if ((status != ISC_R_CANCELED) && reply->static_lease && + (reply->buf.reply.msg_type == DHCPV6_REPLY) && + (reply->on_star.on_commit != NULL)) { + execute_statements(NULL, reply->packet, NULL, NULL, + reply->packet->options, reply->opt_state, + NULL, reply->on_star.on_commit, NULL); + executable_statement_dereference + (&reply->on_star.on_commit, MDL); + } + cleanup: if (packet_ia != NULL) option_state_dereference(&packet_ia, MDL); @@ -1897,6 +1930,12 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) { data_string_forget(&reply->fixed, MDL); if (reply->subnet != NULL) subnet_dereference(&reply->subnet, MDL); + if (reply->on_star.on_expiry != NULL) + executable_statement_dereference + (&reply->on_star.on_expiry, MDL); + if (reply->on_star.on_release != NULL) + executable_statement_dereference + (&reply->on_star.on_release, MDL); /* * ISC_R_CANCELED is a status code used by the addr processing to @@ -2499,6 +2538,19 @@ reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) { renew_lease6(tmp->ipv6_pool, tmp); schedule_lease_timeout(tmp->ipv6_pool); + /* If we have anything to do on commit do it now */ + if (tmp->on_star.on_commit != NULL) { + execute_statements(NULL, reply->packet, + NULL, NULL, + reply->packet->options, + reply->opt_state, + &reply->lease->scope, + tmp->on_star.on_commit, + &tmp->on_star); + executable_statement_dereference + (&tmp->on_star.on_commit, MDL); + } + #if defined (NSUPDATE) /* * Perform ddns updates. @@ -2832,10 +2884,38 @@ reply_process_is_addressed(struct reply_state *reply, isc_result_t status = ISC_R_SUCCESS; struct data_string data; struct option_cache *oc; + struct option_state *tmp_options = NULL; + struct on_star *on_star; /* Initialize values we will cleanup. */ memset(&data, 0, sizeof(data)); + /* + * Find the proper on_star block to use. We use the + * one in the lease if we have a lease or the one in + * the reply if we don't have a lease because this is + * a static instance + */ + if (reply->lease) { + on_star = &reply->lease->on_star; + } else { + on_star = &reply->on_star; + } + + /* + * Bring in the root configuration. We only do this to bring + * in the on * statements, as we didn't have the lease available + * we did it the first time. + */ + option_state_allocate(&tmp_options, MDL); + execute_statements_in_scope(NULL, reply->packet, NULL, NULL, + reply->packet->options, tmp_options, + &global_scope, root_group, NULL, + on_star); + if (tmp_options != NULL) { + option_state_dereference(&tmp_options, MDL); + } + /* * Bring configured options into the root packet level cache - start * with the lease's closest enclosing group (passed in by the caller @@ -2843,7 +2923,7 @@ reply_process_is_addressed(struct reply_state *reply, */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, - scope, group, root_group); + scope, group, root_group, on_star); /* * If there is a host record, over-ride with values configured there, @@ -2854,7 +2934,8 @@ reply_process_is_addressed(struct reply_state *reply, execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, - reply->host->group, group); + reply->host->group, group, + on_star); /* Determine valid lifetime. */ if (reply->client_valid == 0) @@ -2960,7 +3041,7 @@ reply_process_is_addressed(struct reply_state *reply, /* Bring a copy of the relevant options into the IA scope. */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, - scope, group, root_group); + scope, group, root_group, NULL); /* * And bring in host record configuration, if any, but not to overlap @@ -2970,7 +3051,7 @@ reply_process_is_addressed(struct reply_state *reply, execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, scope, - reply->host->group, group); + reply->host->group, group, NULL); cleanup: if (data.data != NULL) @@ -3368,6 +3449,19 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) { /* Commit 'hard' bindings. */ renew_lease6(tmp->ipv6_pool, tmp); schedule_lease_timeout(tmp->ipv6_pool); + + /* If we have anything to do on commit do it now */ + if (tmp->on_star.on_commit != NULL) { + execute_statements(NULL, reply->packet, + NULL, NULL, + reply->packet->options, + reply->opt_state, + &reply->lease->scope, + tmp->on_star.on_commit, + &tmp->on_star); + executable_statement_dereference + (&tmp->on_star.on_commit, MDL); + } } /* Remove any old ia from the hash. */ @@ -3388,6 +3482,20 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) { write_ia(reply->ia); } + /* + * If this would be a hard binding for a static lease + * run any commit statements that we have + */ + if ((status != ISC_R_CANCELED) && reply->static_prefixes != 0 && + (reply->buf.reply.msg_type == DHCPV6_REPLY) && + (reply->on_star.on_commit != NULL)) { + execute_statements(NULL, reply->packet, NULL, NULL, + reply->packet->options, reply->opt_state, + NULL, reply->on_star.on_commit, NULL); + executable_statement_dereference + (&reply->on_star.on_commit, MDL); + } + cleanup: if (packet_ia != NULL) option_state_dereference(&packet_ia, MDL); @@ -3403,6 +3511,12 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) { ia_dereference(&reply->old_ia, MDL); if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); + if (reply->on_star.on_expiry != NULL) + executable_statement_dereference + (&reply->on_star.on_expiry, MDL); + if (reply->on_star.on_release != NULL) + executable_statement_dereference + (&reply->on_star.on_release, MDL); /* * ISC_R_CANCELED is a status code used by the prefix processing to @@ -3833,10 +3947,38 @@ reply_process_is_prefixed(struct reply_state *reply, isc_result_t status = ISC_R_SUCCESS; struct data_string data; struct option_cache *oc; + struct option_state *tmp_options = NULL; + struct on_star *on_star; /* Initialize values we will cleanup. */ memset(&data, 0, sizeof(data)); + /* + * Find the proper on_star block to use. We use the + * one in the lease if we have a lease or the one in + * the reply if we don't have a lease because this is + * a static instance + */ + if (reply->lease) { + on_star = &reply->lease->on_star; + } else { + on_star = &reply->on_star; + } + + /* + * Bring in the root configuration. We only do this to bring + * in the on * statements, as we didn't have the lease available + * we we did it the first time. + */ + option_state_allocate(&tmp_options, MDL); + execute_statements_in_scope(NULL, reply->packet, NULL, NULL, + reply->packet->options, tmp_options, + &global_scope, root_group, NULL, + on_star); + if (tmp_options != NULL) { + option_state_dereference(&tmp_options, MDL); + } + /* * Bring configured options into the root packet level cache - start * with the lease's closest enclosing group (passed in by the caller @@ -3844,7 +3986,7 @@ reply_process_is_prefixed(struct reply_state *reply, */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, - scope, group, root_group); + scope, group, root_group, on_star); /* * If there is a host record, over-ride with values configured there, @@ -3855,7 +3997,8 @@ reply_process_is_prefixed(struct reply_state *reply, execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, - reply->host->group, group); + reply->host->group, group, + on_star); /* Determine valid lifetime. */ if (reply->client_valid == 0) @@ -3946,7 +4089,7 @@ reply_process_is_prefixed(struct reply_state *reply, /* Bring a copy of the relevant options into the IA_PD scope. */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, - scope, group, root_group); + scope, group, root_group, NULL); /* * And bring in host record configuration, if any, but not to overlap @@ -3956,7 +4099,7 @@ reply_process_is_prefixed(struct reply_state *reply, execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, scope, - reply->host->group, group); + reply->host->group, group, NULL); cleanup: if (data.data != NULL) @@ -4683,7 +4826,7 @@ iterate_over_ia_na(struct data_string *reply_ret, } execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, opt_state, - &global_scope, root_group, NULL); + &global_scope, root_group, NULL, NULL); /* * RFC 3315, section 18.2.7 tells us which options to include. @@ -5197,7 +5340,7 @@ iterate_over_ia_pd(struct data_string *reply_ret, } execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, opt_state, - &global_scope, root_group, NULL); + &global_scope, root_group, NULL, NULL); /* * Loop through the IA_PD reported by the client, and deal with diff --git a/server/ldap.c b/server/ldap.c index 8a7d6955..efbc8744 100644 --- a/server/ldap.c +++ b/server/ldap.c @@ -628,10 +628,9 @@ ldap_start (void) options = NULL; option_state_allocate (&options, MDL); - execute_statements_in_scope ((struct binding_value **) NULL, - (struct packet *) NULL, (struct lease *) NULL, - (struct client_state *) NULL, (struct option_state *) NULL, - options, &global_scope, root_group, (struct group *) NULL); + execute_statements_in_scope (NULL, NULL, NULL, NULL, NULL + options, &global_scope, root_group, + NULL, NULL); ldap_server = _do_lookup_dhcp_string_option (options, SV_LDAP_SERVER); ldap_dhcp_server_cn = _do_lookup_dhcp_string_option (options, diff --git a/server/mdb.c b/server/mdb.c index 4793f4ac..53bf34dc 100644 --- a/server/mdb.c +++ b/server/mdb.c @@ -1191,28 +1191,29 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate) comp -> client_hostname = lease -> client_hostname; lease -> client_hostname = (char *)0; - if (lease -> on_expiry) { - if (comp -> on_expiry) - executable_statement_dereference (&comp -> on_expiry, - MDL); - executable_statement_reference (&comp -> on_expiry, - lease -> on_expiry, + if (lease->on_star.on_expiry) { + if (comp->on_star.on_expiry) + executable_statement_dereference + (&comp->on_star.on_expiry, MDL); + executable_statement_reference (&comp->on_star.on_expiry, + lease->on_star.on_expiry, MDL); } - if (lease -> on_commit) { - if (comp -> on_commit) - executable_statement_dereference (&comp -> on_commit, - MDL); - executable_statement_reference (&comp -> on_commit, - lease -> on_commit, + if (lease->on_star.on_commit) { + if (comp->on_star.on_commit) + executable_statement_dereference + (&comp->on_star.on_commit, MDL); + executable_statement_reference (&comp->on_star.on_commit, + lease->on_star.on_commit, MDL); } - if (lease -> on_release) { - if (comp -> on_release) - executable_statement_dereference (&comp -> on_release, - MDL); - executable_statement_reference (&comp -> on_release, - lease -> on_release, MDL); + if (lease->on_star.on_release) { + if (comp->on_star.on_release) + executable_statement_dereference + (&comp->on_star.on_release, MDL); + executable_statement_reference (&comp->on_star.on_release, + lease->on_star.on_release, + MDL); } /* Record the lease in the uid hash if necessary. */ @@ -1455,23 +1456,21 @@ void make_binding_state_transition (struct lease *lease) #if defined (NSUPDATE) (void) ddns_removals(lease, NULL, NULL, ISC_TRUE); #endif - if (lease -> on_expiry) { - execute_statements ((struct binding_value **)0, - (struct packet *)0, lease, - (struct client_state *)0, - (struct option_state *)0, - (struct option_state *)0, /* XXX */ - &lease -> scope, - lease -> on_expiry); - if (lease -> on_expiry) + if (lease->on_star.on_expiry) { + execute_statements(NULL, NULL, lease, + NULL, NULL, NULL, + &lease->scope, + lease->on_star.on_expiry, + NULL); + if (lease->on_star.on_expiry) executable_statement_dereference - (&lease -> on_expiry, MDL); + (&lease->on_star.on_expiry, MDL); } /* No sense releasing a lease after it's expired. */ - if (lease -> on_release) - executable_statement_dereference (&lease -> on_release, - MDL); + if (lease->on_star.on_release) + executable_statement_dereference + (&lease->on_star.on_release, MDL); /* Get rid of client-specific bindings that are only correct when the lease is active. */ if (lease -> billing_class) @@ -1521,22 +1520,20 @@ void make_binding_state_transition (struct lease *lease) */ (void) ddns_removals(lease, NULL, NULL, ISC_TRUE); #endif - if (lease -> on_release) { - execute_statements ((struct binding_value **)0, - (struct packet *)0, lease, - (struct client_state *)0, - (struct option_state *)0, - (struct option_state *)0, /* XXX */ - &lease -> scope, - lease -> on_release); - executable_statement_dereference (&lease -> on_release, - MDL); + if (lease->on_star.on_release) { + execute_statements(NULL, NULL, lease, + NULL, NULL, NULL, + &lease->scope, + lease->on_star.on_release, + NULL); + executable_statement_dereference + (&lease->on_star.on_release, MDL); } /* A released lease can't expire. */ - if (lease -> on_expiry) - executable_statement_dereference (&lease -> on_expiry, - MDL); + if (lease->on_star.on_expiry) + executable_statement_dereference + (&lease->on_star.on_expiry, MDL); /* Get rid of client-specific bindings that are only correct when the lease is active. */ @@ -1656,17 +1653,17 @@ int lease_copy (struct lease **lp, class_reference (< -> billing_class, lease -> billing_class, file, line); lt -> hardware_addr = lease -> hardware_addr; - if (lease -> on_expiry) - executable_statement_reference (< -> on_expiry, - lease -> on_expiry, + if (lease->on_star.on_expiry) + executable_statement_reference (<->on_star.on_expiry, + lease->on_star.on_expiry, file, line); - if (lease -> on_commit) - executable_statement_reference (< -> on_commit, - lease -> on_commit, + if (lease->on_star.on_commit) + executable_statement_reference (<->on_star.on_commit, + lease->on_star.on_commit, file, line); - if (lease -> on_release) - executable_statement_reference (< -> on_release, - lease -> on_release, + if (lease->on_star.on_release) + executable_statement_reference (<->on_star.on_release, + lease->on_star.on_release, file, line); lt->flags = lease->flags; lt->tstp = lease->tstp; @@ -1691,31 +1688,31 @@ void release_lease (lease, packet) #if defined (NSUPDATE) (void) ddns_removals(lease, NULL, NULL, ISC_FALSE); #endif - if (lease -> on_release) { - execute_statements ((struct binding_value **)0, - packet, lease, (struct client_state *)0, - packet -> options, - (struct option_state *)0, /* XXX */ - &lease -> scope, lease -> on_release); - if (lease -> on_release) - executable_statement_dereference (&lease -> on_release, - MDL); + if (lease->on_star.on_release) { + execute_statements (NULL, packet, lease, + NULL, packet->options, + NULL, &lease->scope, + lease->on_star.on_release, NULL); + if (lease->on_star.on_release) + executable_statement_dereference + (&lease->on_star.on_release, MDL); } /* We do either the on_release or the on_expiry events, but not both (it's possible that they could be the same, in any case). */ - if (lease -> on_expiry) - executable_statement_dereference (&lease -> on_expiry, MDL); + if (lease->on_star.on_expiry) + executable_statement_dereference + (&lease->on_star.on_expiry, MDL); if (lease -> binding_state != FTS_FREE && lease -> binding_state != FTS_BACKUP && lease -> binding_state != FTS_RELEASED && lease -> binding_state != FTS_EXPIRED && lease -> binding_state != FTS_RESET) { - if (lease -> on_commit) - executable_statement_dereference (&lease -> on_commit, - MDL); + if (lease->on_star.on_commit) + executable_statement_dereference + (&lease->on_star.on_commit, MDL); /* Blow away any bindings. */ if (lease -> scope) diff --git a/server/mdb6.c b/server/mdb6.c index 0e76264c..b98db428 100644 --- a/server/mdb6.c +++ b/server/mdb6.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2012 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2007-2013 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -197,6 +197,20 @@ iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) { if (tmp->scope != NULL) { binding_scope_dereference(&tmp->scope, file, line); } + + if (tmp->on_star.on_expiry != NULL) { + executable_statement_dereference + (&tmp->on_star.on_expiry, MDL); + } + if (tmp->on_star.on_commit != NULL) { + executable_statement_dereference + (&tmp->on_star.on_commit, MDL); + } + if (tmp->on_star.on_release != NULL) { + executable_statement_dereference + (&tmp->on_star.on_release, MDL); + } + dfree(tmp, file, line); } @@ -1309,6 +1323,38 @@ move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease, old_heap_index = lease->heap_index; insert_result = isc_heap_insert(pool->inactive_timeouts, lease); if (insert_result == ISC_R_SUCCESS) { + /* + * Handle expire and release statements + * To get here we must be active and have done a commit so + * we should run the proper statements if they exist, though + * that will change when we remove the inactive heap. + * In addition we get rid of the references for both as we + * can only do one (expire or release) on a lease + */ + if (lease->on_star.on_expiry != NULL) { + if (state == FTS_EXPIRED) { + execute_statements(NULL, NULL, NULL, + NULL, NULL, NULL, + &lease->scope, + lease->on_star.on_expiry, + &lease->on_star); + } + executable_statement_dereference + (&lease->on_star.on_expiry, MDL); + } + + if (lease->on_star.on_release != NULL) { + if (state == FTS_RELEASED) { + execute_statements(NULL, NULL, NULL, + NULL, NULL, NULL, + &lease->scope, + lease->on_star.on_release, + &lease->on_star); + } + executable_statement_dereference + (&lease->on_star.on_release, MDL); + } + #if defined (NSUPDATE) /* Process events upon expiration. */ if (pool->pool_type != D6O_IA_PD) { diff --git a/server/omapi.c b/server/omapi.c index 3ecf6a77..7e17ed55 100644 --- a/server/omapi.c +++ b/server/omapi.c @@ -408,71 +408,71 @@ isc_result_t dhcp_lease_destroy (omapi_object_t *h, const char *file, int line) { struct lease *lease; - if (h -> type != dhcp_type_lease) + if (h->type != dhcp_type_lease) return DHCP_R_INVALIDARG; lease = (struct lease *)h; - if (lease -> uid) + if (lease-> uid) uid_hash_delete (lease); hw_hash_delete (lease); - if (lease -> on_release) - executable_statement_dereference (&lease -> on_release, + if (lease->on_star.on_release) + executable_statement_dereference (&lease->on_star.on_release, file, line); - if (lease -> on_expiry) - executable_statement_dereference (&lease -> on_expiry, + if (lease->on_star.on_expiry) + executable_statement_dereference (&lease->on_star.on_expiry, file, line); - if (lease -> on_commit) - executable_statement_dereference (&lease -> on_commit, + if (lease->on_star.on_commit) + executable_statement_dereference (&lease->on_star.on_commit, file, line); - if (lease -> scope) - binding_scope_dereference (&lease -> scope, file, line); + if (lease->scope) + binding_scope_dereference (&lease->scope, file, line); - if (lease -> agent_options) - option_chain_head_dereference (&lease -> agent_options, + if (lease->agent_options) + option_chain_head_dereference (&lease->agent_options, file, line); - if (lease -> uid && lease -> uid != lease -> uid_buf) { - dfree (lease -> uid, MDL); - lease -> uid = &lease -> uid_buf [0]; - lease -> uid_len = 0; + if (lease->uid && lease->uid != lease->uid_buf) { + dfree (lease->uid, MDL); + lease->uid = &lease->uid_buf [0]; + lease->uid_len = 0; } - if (lease -> client_hostname) { - dfree (lease -> client_hostname, MDL); - lease -> client_hostname = (char *)0; + if (lease->client_hostname) { + dfree (lease->client_hostname, MDL); + lease->client_hostname = (char *)0; } - if (lease -> host) - host_dereference (&lease -> host, file, line); - if (lease -> subnet) - subnet_dereference (&lease -> subnet, file, line); - if (lease -> pool) - pool_dereference (&lease -> pool, file, line); + if (lease->host) + host_dereference (&lease->host, file, line); + if (lease->subnet) + subnet_dereference (&lease->subnet, file, line); + if (lease->pool) + pool_dereference (&lease->pool, file, line); - if (lease -> state) { - free_lease_state (lease -> state, file, line); - lease -> state = (struct lease_state *)0; + if (lease->state) { + free_lease_state (lease->state, file, line); + lease->state = (struct lease_state *)0; cancel_timeout (lease_ping_timeout, lease); --outstanding_pings; /* XXX */ } - if (lease -> billing_class) + if (lease->billing_class) class_dereference - (&lease -> billing_class, file, line); + (&lease->billing_class, file, line); #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) /* XXX we should never be destroying a lease with a next XXX pointer except on exit... */ - if (lease -> next) - lease_dereference (&lease -> next, file, line); - if (lease -> n_hw) - lease_dereference (&lease -> n_hw, file, line); - if (lease -> n_uid) - lease_dereference (&lease -> n_uid, file, line); - if (lease -> next_pending) - lease_dereference (&lease -> next_pending, file, line); + if (lease->next) + lease_dereference (&lease->next, file, line); + if (lease->n_hw) + lease_dereference (&lease->n_hw, file, line); + if (lease->n_uid) + lease_dereference (&lease->n_uid, file, line); + if (lease->next_pending) + lease_dereference (&lease->next_pending, file, line); #endif return ISC_R_SUCCESS;