File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / server / db.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 9 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* db.c
    2: 
    3:    Persistent database management routines for DHCPD... */
    4: 
    5: /*
    6:  * Copyright (c) 2004-2010,2012 by Internet Systems Consortium, Inc. ("ISC")
    7:  * Copyright (c) 1995-2003 by Internet Software Consortium
    8:  *
    9:  * Permission to use, copy, modify, and distribute this software for any
   10:  * purpose with or without fee is hereby granted, provided that the above
   11:  * copyright notice and this permission notice appear in all copies.
   12:  *
   13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   20:  *
   21:  *   Internet Systems Consortium, Inc.
   22:  *   950 Charter Street
   23:  *   Redwood City, CA 94063
   24:  *   <info@isc.org>
   25:  *   https://www.isc.org/
   26:  *
   27:  * This software has been written for Internet Systems Consortium
   28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
   29:  * To learn more about Internet Systems Consortium, see
   30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
   31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
   32:  * ``http://www.nominum.com''.
   33:  */
   34: 
   35: #include "dhcpd.h"
   36: #include <ctype.h>
   37: #include <errno.h>
   38: 
   39: #define LEASE_REWRITE_PERIOD 3600
   40: 
   41: static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd,
   42: 					char *prepend);
   43: 
   44: FILE *db_file;
   45: 
   46: static int counting = 0;
   47: static int count = 0;
   48: TIME write_time;
   49: int lease_file_is_corrupt = 0;
   50: 
   51: /* Write a single binding scope value in parsable format.
   52:  */
   53: 
   54: static isc_result_t
   55: write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend) {
   56: 	char *s;
   57: 
   58: 	if ((db_file == NULL) || (bnd == NULL) || (prepend == NULL))
   59: 		return ISC_R_INVALIDARG;
   60: 
   61: 	if (bnd->value->type == binding_data) {
   62: 		if (bnd->value->value.data.data != NULL) {
   63: 			s = quotify_buf(bnd->value->value.data.data,
   64: 					bnd->value->value.data.len, MDL);
   65: 			if (s != NULL) {
   66: 				errno = 0;
   67: 				fprintf(db_file, "%sset %s = \"%s\";",
   68: 					prepend, bnd->name, s);
   69: 				if (errno)
   70: 					return ISC_R_FAILURE;
   71: 
   72: 				dfree(s, MDL);
   73: 			} else {
   74: 			    return ISC_R_FAILURE;
   75: 			}
   76: 		}
   77: 	} else if (bnd->value->type == binding_numeric) {
   78: 		errno = 0;
   79: 		fprintf(db_file, "%sset %s = %%%ld;", prepend,
   80: 			bnd->name, bnd->value->value.intval);
   81: 		if (errno)
   82: 			return ISC_R_FAILURE;
   83: 	} else if (bnd->value->type == binding_boolean) {
   84: 		errno = 0;
   85: 		fprintf(db_file, "%sset %s = %s;", prepend, bnd->name,
   86: 			bnd->value->value.intval ? "true" : "false");
   87: 		if (errno)
   88: 			return ISC_R_FAILURE;
   89: 	} else if (bnd->value->type == binding_dns) {
   90: 		log_error("%s: persistent dns values not supported.",
   91: 			  bnd->name);
   92: 	} else if (bnd->value->type == binding_function) {
   93: 		log_error("%s: persistent functions not supported.",
   94: 			  bnd->name);
   95: 	} else {
   96: 		log_fatal("%s: unknown binding type %d", bnd->name,
   97: 			  bnd->value->type);
   98: 	}
   99: 
  100: 	return ISC_R_SUCCESS;
  101: }
  102: 
  103: /* Write the specified lease to the current lease database file. */
  104: 
  105: int write_lease (lease)
  106: 	struct lease *lease;
  107: {
  108: 	int errors = 0;
  109: 	struct binding *b;
  110: 	char *s;
  111: 	const char *tval;
  112: 
  113: 	/* If the lease file is corrupt, don't try to write any more leases
  114: 	   until we've written a good lease file. */
  115: 	if (lease_file_is_corrupt)
  116: 		if (!new_lease_file ())
  117: 			return 0;
  118: 
  119: 	if (counting)
  120: 		++count;
  121: 	errno = 0;
  122: 	fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr));
  123: 	if (errno) {
  124: 		++errors;
  125: 	}
  126: 
  127: 	if (lease->starts &&
  128: 	    ((tval = print_time(lease->starts)) == NULL ||
  129: 	     fprintf(db_file, "\n  starts %s", tval) < 0))
  130: 		++errors;
  131: 
  132: 	if (lease->ends &&
  133: 	    ((tval = print_time(lease->ends)) == NULL ||
  134: 	     fprintf(db_file, "\n  ends %s", tval) < 0))
  135: 		++errors;
  136: 
  137: 	if (lease->tstp &&
  138: 	    ((tval = print_time(lease->tstp)) == NULL ||
  139: 	     fprintf(db_file, "\n  tstp %s", tval) < 0))
  140: 		++errors;
  141: 
  142: 	if (lease->tsfp &&
  143: 	    ((tval = print_time(lease->tsfp)) == NULL ||
  144: 	     fprintf(db_file, "\n  tsfp %s", tval) < 0))
  145: 		++errors;
  146: 
  147: 	if (lease->atsfp &&
  148: 	    ((tval = print_time(lease->atsfp)) == NULL ||
  149: 	     fprintf(db_file, "\n  atsfp %s", tval) < 0))
  150: 		++errors;
  151: 
  152: 	if (lease->cltt &&
  153: 	    ((tval = print_time(lease->cltt)) == NULL ||
  154: 	     fprintf(db_file, "\n  cltt %s", tval) < 0))
  155: 		++errors;
  156: 
  157: 	if (fprintf (db_file, "\n  binding state %s;",
  158: 		 ((lease -> binding_state > 0 &&
  159: 		   lease -> binding_state <= FTS_LAST)
  160: 		  ? binding_state_names [lease -> binding_state - 1]
  161: 		  : "abandoned")) < 0)
  162:                 ++errors;
  163: 
  164: 	if (lease -> binding_state != lease -> next_binding_state)
  165: 		if (fprintf (db_file, "\n  next binding state %s;",
  166: 			 ((lease -> next_binding_state > 0 &&
  167: 			   lease -> next_binding_state <= FTS_LAST)
  168: 			  ? (binding_state_names
  169: 			     [lease -> next_binding_state - 1])
  170: 			  : "abandoned")) < 0)
  171:                         ++errors;
  172: 
  173: 	if (lease->flags & RESERVED_LEASE)
  174: 		if (fprintf(db_file, "\n  reserved;") < 0)
  175:                         ++errors;
  176: 
  177: 	if (lease->flags & BOOTP_LEASE)
  178: 		if (fprintf(db_file, "\n  dynamic-bootp;") < 0)
  179:                         ++errors;
  180: 
  181: 	/* If this lease is billed to a class and is still valid,
  182: 	   write it out. */
  183: 	if (lease -> billing_class && lease -> ends > cur_time) {
  184: 		if (!write_billing_class (lease -> billing_class)) {
  185: 			log_error ("unable to write class %s",
  186: 				   lease -> billing_class -> name);
  187: 			++errors;
  188: 		}
  189: 	}
  190: 
  191: 	if (lease -> hardware_addr.hlen) {
  192: 		errno = 0;
  193: 		fprintf (db_file, "\n  hardware %s %s;",
  194: 			 hardware_types [lease -> hardware_addr.hbuf [0]],
  195: 			 print_hw_addr (lease -> hardware_addr.hbuf [0],
  196: 					lease -> hardware_addr.hlen - 1,
  197: 					&lease -> hardware_addr.hbuf [1]));
  198: 		if (errno)
  199: 			++errors;
  200: 	}
  201: 	if (lease -> uid_len) {
  202: 		s = quotify_buf (lease -> uid, lease -> uid_len, MDL);
  203: 		if (s) {
  204: 			errno = 0;
  205: 			fprintf (db_file, "\n  uid \"%s\";", s);
  206: 			if (errno)
  207: 				++errors;
  208: 			dfree (s, MDL);
  209: 		} else
  210: 			++errors;
  211: 	}
  212: 
  213: 	if (lease->scope != NULL) {
  214: 	    for (b = lease->scope->bindings; b; b = b->next) {
  215: 		if (!b->value)
  216: 			continue;
  217: 
  218: 		if (write_binding_scope(db_file, b, "\n  ") != ISC_R_SUCCESS)
  219: 			++errors;
  220: 	    }
  221: 	}
  222: 
  223: 	if (lease -> agent_options) {
  224: 	    struct option_cache *oc;
  225: 	    struct data_string ds;
  226: 	    pair p;
  227: 
  228: 	    memset (&ds, 0, sizeof ds);
  229: 	    for (p = lease -> agent_options -> first; p; p = p -> cdr) {
  230: 	        oc = (struct option_cache *)p -> car;
  231: 	        if (oc -> data.len) {
  232: 	    	errno = 0;
  233: 	    	fprintf (db_file, "\n  option agent.%s %s;",
  234: 	    		 oc -> option -> name,
  235: 	    		 pretty_print_option (oc -> option, oc -> data.data,
  236: 				      		oc -> data.len, 1, 1));
  237: 	    	if (errno)
  238: 		    ++errors;
  239: 	        }
  240: 	    }
  241: 	}
  242: 	if (lease -> client_hostname &&
  243: 	    db_printable((unsigned char *)lease->client_hostname)) {
  244: 		s = quotify_string (lease -> client_hostname, MDL);
  245: 		if (s) {
  246: 			errno = 0;
  247: 			fprintf (db_file, "\n  client-hostname \"%s\";", s);
  248: 			if (errno)
  249: 				++errors;
  250: 			dfree (s, MDL);
  251: 		} else
  252: 			++errors;
  253: 	}
  254: 	if (lease -> on_expiry) {
  255: 		errno = 0;
  256: 		fprintf (db_file, "\n  on expiry%s {",
  257: 			 lease -> on_expiry == lease -> on_release
  258: 			 ? " or release" : "");
  259: 		write_statements (db_file, lease -> on_expiry, 4);
  260: 		/* XXX */
  261: 		fprintf (db_file, "\n  }");
  262: 		if (errno)
  263: 			++errors;
  264: 	}
  265: 	if (lease -> on_release && lease -> on_release != lease -> on_expiry) {
  266: 		errno = 0;
  267: 		fprintf (db_file, "\n  on release {");
  268: 		write_statements (db_file, lease -> on_release, 4);
  269: 		/* XXX */
  270: 		fprintf (db_file, "\n  }");
  271: 		if (errno)
  272: 			++errors;
  273: 	}
  274: 
  275: 	errno = 0;
  276: 	fputs ("\n}\n", db_file);
  277: 	if (errno)
  278: 		++errors;
  279: 
  280: 	if (errors) {
  281: 		log_info ("write_lease: unable to write lease %s",
  282: 		      piaddr (lease -> ip_addr));
  283: 		lease_file_is_corrupt = 1;
  284:         }
  285: 
  286: 	return !errors;
  287: }
  288: 
  289: int write_host (host)
  290: 	struct host_decl *host;
  291: {
  292: 	int errors = 0;
  293: 	int i;
  294: 	struct data_string ip_addrs;
  295: 
  296: 	/* If the lease file is corrupt, don't try to write any more leases
  297: 	   until we've written a good lease file. */
  298: 	if (lease_file_is_corrupt)
  299: 		if (!new_lease_file ())
  300: 			return 0;
  301: 
  302: 	if (!db_printable((unsigned char *)host->name))
  303: 		return 0;
  304: 
  305: 	if (counting)
  306: 		++count;
  307: 
  308: 	errno = 0;
  309: 	fprintf (db_file, "host %s {", host -> name);
  310: 	if (errno)
  311: 		++errors;
  312: 
  313: 	if (host -> flags & HOST_DECL_DYNAMIC) {
  314: 		errno = 0;
  315: 		fprintf (db_file, "\n  dynamic;");
  316: 		if (errno)
  317: 			++errors;
  318: 	}
  319: 
  320: 	if (host -> flags & HOST_DECL_DELETED) {
  321: 		errno = 0;
  322: 		fprintf (db_file, "\n  deleted;");
  323: 		if (errno)
  324: 			++errors;
  325: 	} else {
  326: 		if (host -> interface.hlen) {
  327: 			errno = 0;
  328: 			fprintf (db_file, "\n  hardware %s %s;",
  329: 				 hardware_types [host -> interface.hbuf [0]],
  330: 				 print_hw_addr (host -> interface.hbuf [0],
  331: 						host -> interface.hlen - 1,
  332: 						&host -> interface.hbuf [1]));
  333: 			if (errno)
  334: 				++errors;
  335: 		}
  336: 		if (host -> client_identifier.len) {
  337: 			int i;
  338: 			errno = 0;
  339: 			if (db_printable_len (host -> client_identifier.data,
  340: 					      host -> client_identifier.len)) {
  341: 				fprintf (db_file, "\n  uid \"%.*s\";",
  342: 					 (int)host -> client_identifier.len,
  343: 					 host -> client_identifier.data);
  344: 				if (errno)
  345: 					++errors;
  346: 			} else {
  347: 				fprintf (db_file,
  348: 					 "\n  uid %2.2x",
  349: 					 host -> client_identifier.data [0]);
  350: 				if (errno)
  351: 					++errors;
  352: 				for (i = 1;
  353: 				     i < host -> client_identifier.len; i++) {
  354: 					errno = 0;
  355: 					fprintf (db_file, ":%2.2x",
  356: 						 host ->
  357: 						 client_identifier.data [i]);
  358: 					if (errno)
  359: 						++errors;
  360: 				}
  361: 
  362:                                 errno = 0;
  363: 				fputc (';', db_file);
  364: 				if (errno)
  365: 					++errors;
  366: 			}
  367: 		}
  368: 		
  369: 		memset (&ip_addrs, 0, sizeof ip_addrs);
  370: 		if (host -> fixed_addr &&
  371: 		    evaluate_option_cache (&ip_addrs, (struct packet *)0,
  372: 					   (struct lease *)0,
  373: 					   (struct client_state *)0,
  374: 					   (struct option_state *)0,
  375: 					   (struct option_state *)0,
  376: 					   &global_scope,
  377: 					   host -> fixed_addr, MDL)) {
  378: 		
  379: 			errno = 0;
  380: 			fprintf (db_file, "\n  fixed-address ");
  381: 			if (errno)
  382: 				++errors;
  383: 			for (i = 0; i < ip_addrs.len - 3; i += 4) {
  384: 
  385: 				errno = 0;
  386: 				fprintf (db_file, "%u.%u.%u.%u%s",
  387: 					 ip_addrs.data [i] & 0xff,
  388: 					 ip_addrs.data [i + 1] & 0xff,
  389: 					 ip_addrs.data [i + 2] & 0xff,
  390: 					 ip_addrs.data [i + 3] & 0xff,
  391: 					 i + 7 < ip_addrs.len ? "," : "");
  392: 				if (errno)
  393: 					++errors;
  394: 			}
  395: 
  396: 			errno = 0;
  397: 			fputc (';', db_file);
  398: 			if (errno)
  399: 				++errors;
  400: 		}
  401: 
  402: 		if (host -> named_group) {
  403: 			errno = 0;
  404: 			fprintf (db_file, "\n  group \"%s\";",
  405: 				 host -> named_group -> name);
  406: 			if (errno)
  407: 				++errors;
  408: 		}
  409: 
  410: 		if (host -> group &&
  411: 		    (!host -> named_group ||
  412: 		     host -> group != host -> named_group -> group) &&
  413: 		    host -> group != root_group) {
  414: 			errno = 0;
  415: 			write_statements (db_file,
  416: 					  host -> group -> statements, 8);
  417: 			if (errno)
  418: 				++errors;
  419: 		}
  420: 	}
  421: 
  422: 	errno = 0;
  423: 	fputs ("\n}\n", db_file);
  424: 	if (errno)
  425: 		++errors;
  426: 
  427: 	if (errors) {
  428: 		log_info ("write_host: unable to write host %s",
  429: 			  host -> name);
  430: 		lease_file_is_corrupt = 1;
  431: 	}
  432: 
  433: 	return !errors;
  434: }
  435: 
  436: int write_group (group)
  437: 	struct group_object *group;
  438: {
  439: 	int errors = 0;
  440: 
  441: 	/* If the lease file is corrupt, don't try to write any more leases
  442: 	   until we've written a good lease file. */
  443: 	if (lease_file_is_corrupt)
  444: 		if (!new_lease_file ())
  445: 			return 0;
  446: 
  447: 	if (!db_printable((unsigned char *)group->name))
  448: 		return 0;
  449: 
  450: 	if (counting)
  451: 		++count;
  452: 
  453: 	errno = 0;
  454: 	fprintf (db_file, "group %s {", group -> name);
  455: 	if (errno)
  456: 		++errors;
  457: 
  458: 	if (group -> flags & GROUP_OBJECT_DYNAMIC) {
  459: 		errno = 0;
  460: 		fprintf (db_file, "\n  dynamic;");
  461: 		if (errno)
  462: 			++errors;
  463: 	}
  464: 
  465: 	if (group -> flags & GROUP_OBJECT_STATIC) {
  466: 		errno = 0;
  467: 		fprintf (db_file, "\n  static;");
  468: 		if (errno)
  469: 			++errors;
  470: 	}
  471: 
  472: 	if (group -> flags & GROUP_OBJECT_DELETED) {
  473: 		errno = 0;
  474: 		fprintf (db_file, "\n  deleted;");
  475: 		if (errno)
  476: 			++errors;
  477: 	} else {
  478: 		if (group -> group) {
  479: 			errno = 0;
  480: 			write_statements (db_file,
  481: 					  group -> group -> statements, 8);
  482: 			if (errno)
  483: 				++errors;
  484: 		}
  485: 	}
  486: 
  487: 	errno = 0;
  488: 	fputs ("\n}\n", db_file);
  489: 	if (errno)
  490: 		++errors;
  491: 
  492: 	if (errors) {
  493: 		log_info ("write_group: unable to write group %s",
  494: 			  group -> name);
  495: 		lease_file_is_corrupt = 1;
  496: 	}
  497: 
  498: 	return !errors;
  499: }
  500: 
  501: /*
  502:  * Write an IA and the options it has.
  503:  */
  504: int
  505: write_ia(const struct ia_xx *ia) {
  506: 	struct iasubopt *iasubopt;
  507: 	struct binding *bnd;
  508: 	int i;
  509: 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")];
  510: 	const char *binding_state;
  511: 	const char *tval;
  512: 	char *s;
  513: 	int fprintf_ret;
  514: 
  515: 	/* 
  516: 	 * If the lease file is corrupt, don't try to write any more 
  517: 	 * leases until we've written a good lease file. 
  518: 	 */
  519: 	if (lease_file_is_corrupt) {
  520: 		if (!new_lease_file()) {
  521: 			return 0;
  522: 		}
  523: 	}
  524: 
  525: 	if (counting) {
  526: 		++count;
  527: 	}
  528: 
  529: 	
  530: 	s = quotify_buf(ia->iaid_duid.data, ia->iaid_duid.len, MDL);
  531: 	if (s == NULL) {
  532: 		goto error_exit;
  533: 	}
  534: 	switch (ia->ia_type) {
  535: 	case D6O_IA_NA:
  536: 		fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s);
  537: 		break;
  538: 	case D6O_IA_TA:
  539: 		fprintf_ret = fprintf(db_file, "ia-ta \"%s\" {\n", s);
  540: 		break;
  541: 	case D6O_IA_PD:
  542: 		fprintf_ret = fprintf(db_file, "ia-pd \"%s\" {\n", s);
  543: 		break;
  544: 	default:
  545: 		log_error("Unknown ia type %u for \"%s\" at %s:%d",
  546: 			  (unsigned)ia->ia_type, s, MDL);
  547: 		fprintf_ret = -1;
  548: 	}
  549: 	dfree(s, MDL);
  550: 	if (fprintf_ret < 0) {
  551: 		goto error_exit;
  552: 	}
  553: 	if (ia->cltt != MIN_TIME) {
  554: 		tval = print_time(ia->cltt);
  555: 		if (tval == NULL) {
  556: 			goto error_exit;
  557: 		}
  558: 		if (fprintf(db_file, "  cltt %s\n", tval) < 0) {
  559: 			goto error_exit;
  560: 		}
  561: 	}
  562: 	for (i=0; i<ia->num_iasubopt; i++) {
  563: 		iasubopt = ia->iasubopt[i];
  564: 
  565: 		inet_ntop(AF_INET6, &iasubopt->addr,
  566: 			  addr_buf, sizeof(addr_buf));
  567: 		if ((ia->ia_type != D6O_IA_PD) &&
  568: 		    (fprintf(db_file, "  iaaddr %s {\n", addr_buf) < 0)) {
  569: 			goto error_exit;
  570: 		}
  571: 		if ((ia->ia_type == D6O_IA_PD) &&
  572: 		    (fprintf(db_file, "  iaprefix %s/%d {\n",
  573: 			     addr_buf, (int)iasubopt->plen) < 0)) {
  574: 			goto error_exit;
  575: 		}
  576: 		if ((iasubopt->state <= 0) || (iasubopt->state > FTS_LAST)) {
  577: 			log_fatal("Unknown iasubopt state %d at %s:%d", 
  578: 				  iasubopt->state, MDL);
  579: 		}
  580: 		binding_state = binding_state_names[iasubopt->state-1];
  581: 		if (fprintf(db_file, "    binding state %s;\n", 
  582: 			    binding_state) < 0) {
  583: 			goto error_exit;
  584: 		}
  585: 		if (fprintf(db_file, "    preferred-life %u;\n",
  586: 			    (unsigned)iasubopt->prefer) < 0) {
  587: 			goto error_exit;
  588: 		}
  589: 		if (fprintf(db_file, "    max-life %u;\n",
  590: 			    (unsigned)iasubopt->valid) < 0) {
  591: 			goto error_exit;
  592: 		}
  593: 
  594: 		/* Note that from here on out, the \n is prepended to the
  595: 		 * next write, rather than appended to the current write.
  596: 		 */
  597: 		if ((iasubopt->state == FTS_ACTIVE) ||
  598: 		    (iasubopt->state == FTS_ABANDONED) ||
  599: 		    (iasubopt->hard_lifetime_end_time != 0)) {
  600: 			tval = print_time(iasubopt->hard_lifetime_end_time);
  601: 		} else {
  602: 			tval = print_time(iasubopt->soft_lifetime_end_time);
  603: 		}
  604: 		if (tval == NULL) {
  605: 			goto error_exit;
  606: 		}
  607: 		if (fprintf(db_file, "    ends %s", tval) < 0) {
  608: 			goto error_exit;
  609: 		}
  610: 
  611: 		/* Write out any binding scopes: note that 'ends' above does
  612: 		 * not have \n on the end!  We want that.
  613: 		 */
  614: 		if (iasubopt->scope != NULL)
  615: 			bnd = iasubopt->scope->bindings;
  616: 		else
  617: 			bnd = NULL;
  618: 
  619: 		for (; bnd != NULL ; bnd = bnd->next) {
  620: 			if (bnd->value == NULL)
  621: 				continue;
  622: 
  623: 			/* We don't do a regular error_exit because the
  624: 			 * lease db is not corrupt in this case.
  625: 			 */
  626: 			if (write_binding_scope(db_file, bnd,
  627: 						"\n    ") != ISC_R_SUCCESS)
  628: 				goto error_exit;
  629: 				
  630: 		}
  631: 
  632: 		if (fprintf(db_file, "\n  }\n") < 0)
  633:                         goto error_exit;
  634: 	}
  635: 	if (fprintf(db_file, "}\n\n") < 0)
  636:                 goto error_exit;
  637: 
  638: 	fflush(db_file);
  639: 	return 1;
  640: 
  641: error_exit:
  642: 	log_info("write_ia: unable to write ia");
  643: 	lease_file_is_corrupt = 1;
  644: 	return 0;
  645: }
  646: 
  647: #ifdef DHCPv6
  648: /*
  649:  * Put a copy of the server DUID in the leases file.
  650:  */
  651: int
  652: write_server_duid(void) {
  653: 	struct data_string server_duid;
  654: 	char *s;
  655: 	int fprintf_ret;
  656: 
  657: 	/*
  658: 	 * Only write the DUID if it's been set.
  659: 	 */
  660: 	if (!server_duid_isset()) {
  661: 		return 1;
  662: 	}
  663: 
  664: 	/* 
  665: 	 * If the lease file is corrupt, don't try to write any more 
  666: 	 * leases until we've written a good lease file. 
  667: 	 */
  668: 	if (lease_file_is_corrupt) {
  669: 		if (!new_lease_file()) {
  670: 			return 0;
  671: 		}
  672: 	}
  673: 
  674: 	/*
  675: 	 * Get a copy of our server DUID and convert to a quoted string.
  676: 	 */
  677: 	memset(&server_duid, 0, sizeof(server_duid));
  678: 	copy_server_duid(&server_duid, MDL);
  679: 	s = quotify_buf(server_duid.data, server_duid.len, MDL);
  680: 	data_string_forget(&server_duid, MDL);
  681: 	if (s == NULL) {
  682: 		goto error_exit;
  683: 	}
  684: 
  685: 	/*
  686: 	 * Write to the leases file.
  687: 	 */
  688: 	fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s);
  689: 	dfree(s, MDL);
  690: 	if (fprintf_ret < 0) {
  691: 		goto error_exit;
  692: 	}
  693: 
  694: 	/*
  695: 	 * Check if we actually managed to write.
  696: 	 */
  697: 	fflush(db_file);
  698: 	return 1;
  699: 
  700: error_exit:
  701: 	log_info("write_server_duid: unable to write server-duid");
  702: 	lease_file_is_corrupt = 1;
  703: 	return 0;
  704: }
  705: #endif /* DHCPv6 */
  706: 
  707: #if defined (FAILOVER_PROTOCOL)
  708: int write_failover_state (dhcp_failover_state_t *state)
  709: {
  710: 	int errors = 0;
  711: 	const char *tval;
  712: 
  713: 	if (lease_file_is_corrupt)
  714: 		if (!new_lease_file ())
  715: 			return 0;
  716: 
  717: 	errno = 0;
  718: 	fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
  719: 	if (errno)
  720: 		++errors;
  721: 
  722: 	tval = print_time(state->me.stos);
  723: 	if (tval == NULL ||
  724: 	    fprintf(db_file, "\n  my state %s at %s",
  725: 		    (state->me.state == startup) ?
  726: 		    dhcp_failover_state_name_print(state->saved_state) :
  727: 		    dhcp_failover_state_name_print(state->me.state),
  728: 		    tval) < 0)
  729: 		++errors;
  730: 
  731: 	tval = print_time(state->partner.stos);
  732: 	if (tval == NULL ||
  733: 	    fprintf(db_file, "\n  partner state %s at %s",
  734: 		    dhcp_failover_state_name_print(state->partner.state),
  735: 		    tval) < 0)
  736: 		++errors;
  737: 
  738: 	if (state -> i_am == secondary) {
  739: 		errno = 0;
  740: 		fprintf (db_file, "\n  mclt %ld;",
  741: 			 (unsigned long)state -> mclt);
  742: 		if (errno)
  743: 			++errors;
  744: 	}
  745: 
  746:         errno = 0;
  747: 	fprintf (db_file, "\n}\n");
  748: 	if (errno)
  749: 		++errors;
  750: 
  751: 	if (errors) {
  752: 		log_info ("write_failover_state: unable to write state %s",
  753: 			  state -> name);
  754: 		lease_file_is_corrupt = 1;
  755: 		return 0;
  756: 	}
  757: 
  758: 	return 1;
  759: 
  760: }
  761: #endif
  762: 
  763: int db_printable (s)
  764: 	const unsigned char *s;
  765: {
  766: 	int i;
  767: 	for (i = 0; s [i]; i++)
  768: 		if (!isascii (s [i]) || !isprint (s [i])
  769: 		    || s [i] == '"' || s [i] == '\\')
  770: 			return 0;
  771: 	return 1;
  772: }
  773: 
  774: int db_printable_len (s, len)
  775: 	const unsigned char *s;
  776: 	unsigned len;
  777: {
  778: 	int i;
  779: 
  780: 	for (i = 0; i < len; i++)
  781: 		if (!isascii (s [i]) || !isprint (s [i]) ||
  782: 		    s [i] == '"' || s [i] == '\\')
  783: 			return 0;
  784: 	return 1;
  785: }
  786: 
  787: static int print_hash_string(FILE *fp, struct class *class)
  788: {
  789: 	int i;
  790: 
  791: 	for (i = 0 ; i < class->hash_string.len ; i++)
  792: 		if (!isascii(class->hash_string.data[i]) ||
  793: 		    !isprint(class->hash_string.data[i]))
  794: 			break;
  795: 
  796: 	if (i == class->hash_string.len) {
  797: 		if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len,
  798: 			    class->hash_string.data) <= 0) {
  799: 			log_error("Failure writing hash string: %m");
  800: 			return 0;
  801: 		}
  802: 	} else {
  803: 		if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) {
  804: 			log_error("Failure writing hash string: %m");
  805: 			return 0;
  806: 		}
  807: 		for (i = 1 ; i < class->hash_string.len ; i++) {
  808: 			if (fprintf(fp, ":%2.2x",
  809: 				    class->hash_string.data[i]) <= 0) {
  810: 				log_error("Failure writing hash string: %m");
  811: 				return 0;
  812: 			}
  813: 		}
  814: 	}
  815: 
  816: 	return 1;
  817: }
  818: 
  819: 
  820: isc_result_t
  821: write_named_billing_class(const void *key, unsigned len, void *object)
  822: {
  823: 	const unsigned char *name = key;
  824: 	struct class *class = object;
  825: 
  826: 	if (class->flags & CLASS_DECL_DYNAMIC) {
  827: 		numclasseswritten++;
  828: 		if (class->superclass == 0) {
  829: 			if (fprintf(db_file, "class \"%s\" {\n", name) <= 0)
  830: 				return ISC_R_IOERROR;
  831: 		} else {
  832: 			if (fprintf(db_file, "subclass \"%s\"",
  833: 				    class->superclass->name) <= 0)
  834: 				return ISC_R_IOERROR;
  835: 			if (!print_hash_string(db_file, class))
  836: 				return ISC_R_IOERROR;
  837: 			if (fprintf(db_file, " {\n") <= 0)
  838: 				return ISC_R_IOERROR;
  839: 		}
  840: 
  841: 		if ((class->flags & CLASS_DECL_DELETED) != 0) {
  842: 			if (fprintf(db_file, "  deleted;\n") <= 0)
  843: 				return ISC_R_IOERROR;
  844: 		} else {
  845: 			if (fprintf(db_file, "  dynamic;\n") <= 0)
  846: 				return ISC_R_IOERROR;
  847: 		}
  848: 	
  849: 		if (class->lease_limit > 0) {
  850: 			if (fprintf(db_file, "  lease limit %d;\n",
  851: 				    class->lease_limit) <= 0)
  852: 				return ISC_R_IOERROR;
  853: 		}
  854: 
  855: 		if (class->expr != 0) {
  856: 			if (fprintf(db_file, "  match if ") <= 0)
  857: 				return ISC_R_IOERROR;
  858: 
  859:                         errno = 0;                                       
  860: 			write_expression(db_file, class->expr, 5, 5, 0);
  861:                         if (errno)
  862:                                 return ISC_R_IOERROR;
  863: 
  864: 			if (fprintf(db_file, ";\n") <= 0)
  865: 				return ISC_R_IOERROR;
  866: 		}
  867: 
  868: 		if (class->submatch != 0) {
  869: 			if (class->spawning) {
  870: 				if (fprintf(db_file, "  spawn ") <= 0)
  871: 					return ISC_R_IOERROR;
  872: 			} else {
  873: 				if (fprintf(db_file, "  match ") <= 0)
  874: 					return ISC_R_IOERROR;
  875: 			}
  876: 
  877:                         errno = 0;
  878: 			write_expression(db_file, class->submatch, 5, 5, 0);
  879:                         if (errno)
  880:                                 return ISC_R_IOERROR;
  881: 
  882: 			if (fprintf(db_file, ";\n") <= 0)
  883: 				return ISC_R_IOERROR;
  884: 		}
  885: 	
  886: 		if (class->statements != 0) {
  887:                         errno = 0;
  888: 			write_statements(db_file, class->statements, 8);
  889:                         if (errno)
  890:                                 return ISC_R_IOERROR;
  891: 		}
  892: 
  893: 		/* XXXJAB this isn't right, but classes read in off the
  894: 		   leases file don't get the root group assigned to them
  895: 		   (due to clone_group() call). */
  896: 		if (class->group != 0 && class->group->authoritative != 0) {
  897:                         errno = 0;
  898: 			write_statements(db_file, class->group->statements, 8);
  899:                         if (errno)
  900:                                 return ISC_R_IOERROR;
  901:                 }
  902: 
  903: 		if (fprintf(db_file, "}\n\n") <= 0)
  904: 			return ISC_R_IOERROR;
  905: 	}
  906: 
  907: 	if (class->hash != NULL) {	/* yep. recursive. god help us. */
  908: 		/* XXX - cannot check error status of this...
  909: 		 * foo_hash_foreach returns a count of operations completed.
  910: 		 */
  911: 		class_hash_foreach(class->hash, write_named_billing_class);
  912: 	}
  913: 
  914: 	return ISC_R_SUCCESS;
  915: }
  916: 
  917: void write_billing_classes ()
  918: {
  919: 	struct collection *lp;
  920: 	struct class *cp;
  921: 
  922: 	for (lp = collections; lp; lp = lp -> next) {
  923: 	    for (cp = lp -> classes; cp; cp = cp -> nic) {
  924: 		if (cp -> spawning && cp -> hash) {
  925: 		    class_hash_foreach (cp -> hash, write_named_billing_class);
  926: 		}
  927: 	    }
  928: 	}
  929: }
  930: 
  931: /* Write a spawned class to the database file. */
  932: 
  933: int write_billing_class (class)
  934: 	struct class *class;
  935: {
  936: 	int errors = 0;
  937: 
  938: 	if (lease_file_is_corrupt)
  939: 		if (!new_lease_file ())
  940: 			return 0;
  941: 
  942: 	if (!class -> superclass) {
  943: 		errno = 0;
  944: 		fprintf (db_file, "\n  billing class \"%s\";", class -> name);
  945: 		return !errno;
  946: 	}
  947: 
  948: 	if (fprintf(db_file, "\n  billing subclass \"%s\"",
  949: 		    class -> superclass -> name) < 0)
  950: 		++errors;
  951: 
  952: 	if (!print_hash_string(db_file, class))
  953:                 ++errors;
  954: 
  955: 	if (fprintf(db_file, ";") < 0)
  956:                 ++errors;
  957: 
  958: 	class -> dirty = !errors;
  959: 	if (errors)
  960: 		lease_file_is_corrupt = 1;
  961: 
  962: 	return !errors;
  963: }
  964: 
  965: /* Commit leases after a timeout. */
  966: void commit_leases_timeout (void *foo)
  967: {
  968: 	commit_leases ();
  969: }
  970: 
  971: /* Commit any leases that have been written out... */
  972: 
  973: int commit_leases ()
  974: {
  975: 	/* Commit any outstanding writes to the lease database file.
  976: 	   We need to do this even if we're rewriting the file below,
  977: 	   just in case the rewrite fails. */
  978: 	if (fflush (db_file) == EOF) {
  979: 		log_info ("commit_leases: unable to commit: %m");
  980: 		return 0;
  981: 	}
  982: 	if (fsync (fileno (db_file)) < 0) {
  983: 		log_info ("commit_leases: unable to commit: %m");
  984: 		return 0;
  985: 	}
  986: 
  987: 	/* send out all deferred ACKs now */
  988: 	flush_ackqueue(NULL);
  989: 
  990: 	/* If we haven't rewritten the lease database in over an
  991: 	   hour, rewrite it now.  (The length of time should probably
  992: 	   be configurable. */
  993: 	if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) {
  994: 		count = 0;
  995: 		write_time = cur_time;
  996: 		new_lease_file ();
  997: 	}
  998: 	return 1;
  999: }
 1000: 
 1001: /*
 1002:  * rewrite the lease file about once an hour
 1003:  * This is meant as a quick patch for ticket 24887.  It allows
 1004:  * us to rotate the v6 lease file without adding too many fsync()
 1005:  * calls.  In the future wes should revisit this area and add
 1006:  * something similar to the delayed ack code for v4.
 1007:  */
 1008: int commit_leases_timed()
 1009: {
 1010: 	if ((count != 0) && (cur_time - write_time > LEASE_REWRITE_PERIOD)) {
 1011: 		return (commit_leases());
 1012: 	}
 1013: 	return (1);
 1014: }
 1015: 
 1016: void db_startup (testp)
 1017: 	int testp;
 1018: {
 1019: 	isc_result_t status;
 1020: 
 1021: #if defined (TRACING)
 1022: 	if (!trace_playback ()) {
 1023: #endif
 1024: 		/* Read in the existing lease file... */
 1025: 		status = read_conf_file (path_dhcpd_db,
 1026: 					 (struct group *)0, 0, 1);
 1027: 		if (status != ISC_R_SUCCESS) {
 1028: 			/* XXX ignore status? */
 1029: 			;
 1030: 		}
 1031: 
 1032: #if defined (TRACING)
 1033: 	}
 1034: #endif
 1035: 
 1036: #if defined (TRACING)
 1037: 	/* If we're playing back, there is no lease file, so we can't
 1038: 	   append it, so we create one immediately (maybe this isn't
 1039: 	   the best solution... */
 1040: 	if (trace_playback ()) {
 1041: 		new_lease_file ();
 1042: 	}
 1043: #endif
 1044: 	if (!testp) {
 1045: 		db_file = fopen (path_dhcpd_db, "a");
 1046: 		if (!db_file)
 1047: 			log_fatal ("Can't open %s for append.", path_dhcpd_db);
 1048: 		expire_all_pools ();
 1049: #if defined (TRACING)
 1050: 		if (trace_playback ())
 1051: 			write_time = cur_time;
 1052: 		else
 1053: #endif
 1054: 			time(&write_time);
 1055: 		new_lease_file ();
 1056: 	}
 1057: 
 1058: #if defined(REPORT_HASH_PERFORMANCE)
 1059: 	log_info("Host HW hash:   %s", host_hash_report(host_hw_addr_hash));
 1060: 	log_info("Host UID hash:  %s", host_hash_report(host_uid_hash));
 1061: 	log_info("Lease IP hash:  %s",
 1062: 		 lease_ip_hash_report(lease_ip_addr_hash));
 1063: 	log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash));
 1064: 	log_info("Lease HW hash:  %s",
 1065: 		 lease_id_hash_report(lease_hw_addr_hash));
 1066: #endif
 1067: }
 1068: 
 1069: int new_lease_file ()
 1070: {
 1071: 	char newfname [512];
 1072: 	char backfname [512];
 1073: 	TIME t;
 1074: 	int db_fd;
 1075: 	int db_validity;
 1076: 	FILE *new_db_file;
 1077: 
 1078: 	/* Make a temporary lease file... */
 1079: 	time(&t);
 1080: 
 1081: 	db_validity = lease_file_is_corrupt;
 1082: 
 1083: 	/* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
 1084: 	 * This should never happen since the path is a configuration
 1085: 	 * variable from build-time or command-line.  But if it should,
 1086: 	 * either by malice or ignorance, we panic, since the potential
 1087: 	 * for havoc is high.
 1088: 	 */
 1089: 	if (snprintf (newfname, sizeof newfname, "%s.%d",
 1090: 		     path_dhcpd_db, (int)t) >= sizeof newfname)
 1091: 		log_fatal("new_lease_file: lease file path too long");
 1092: 
 1093: 	db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
 1094: 	if (db_fd < 0) {
 1095: 		log_error ("Can't create new lease file: %m");
 1096: 		return 0;
 1097: 	}
 1098: 	if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
 1099: 		log_error("Can't fdopen new lease file: %m");
 1100: 		close(db_fd);
 1101: 		goto fdfail;
 1102: 	}
 1103: 
 1104: 	/* Close previous database, if any. */
 1105: 	if (db_file)
 1106: 		fclose(db_file);
 1107: 	db_file = new_db_file;
 1108: 
 1109: 	errno = 0;
 1110: 	fprintf (db_file, "# The format of this file is documented in the %s",
 1111: 		 "dhcpd.leases(5) manual page.\n");
 1112: 	if (errno)
 1113: 		goto fail;
 1114: 
 1115: 	fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
 1116: 		 PACKAGE_VERSION);
 1117: 	if (errno)
 1118: 		goto fail;
 1119: 
 1120: 	/* At this point we have a new lease file that, so far, could not
 1121: 	 * be described as either corrupt nor valid.
 1122: 	 */
 1123: 	lease_file_is_corrupt = 0;
 1124: 
 1125: 	/* Write out all the leases that we know of... */
 1126: 	counting = 0;
 1127: 	if (!write_leases ())
 1128: 		goto fail;
 1129: 
 1130: #if defined (TRACING)
 1131: 	if (!trace_playback ()) {
 1132: #endif
 1133: 	    /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
 1134: 	     * This should never happen since the path is a configuration
 1135: 	     * variable from build-time or command-line.  But if it should,
 1136: 	     * either by malice or ignorance, we panic, since the potential
 1137: 	     * for havoc is too high.
 1138: 	     */
 1139: 	    if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)
 1140: 			>= sizeof backfname)
 1141: 		log_fatal("new_lease_file: backup lease file path too long");
 1142: 
 1143: 	    /* Get the old database out of the way... */
 1144: 	    if (unlink (backfname) < 0 && errno != ENOENT) {
 1145: 		log_error ("Can't remove old lease database backup %s: %m",
 1146: 			   backfname);
 1147: 		goto fail;
 1148: 	    }
 1149: 	    if (link(path_dhcpd_db, backfname) < 0) {
 1150: 		if (errno == ENOENT) {
 1151: 			log_error("%s is missing - no lease db to backup.",
 1152: 				  path_dhcpd_db);
 1153: 		} else {
 1154: 			log_error("Can't backup lease database %s to %s: %m",
 1155: 				  path_dhcpd_db, backfname);
 1156: 			goto fail;
 1157: 		}
 1158: 	    }
 1159: #if defined (TRACING)
 1160: 	}
 1161: #endif
 1162: 	
 1163: 	/* Move in the new file... */
 1164: 	if (rename (newfname, path_dhcpd_db) < 0) {
 1165: 		log_error ("Can't install new lease database %s to %s: %m",
 1166: 			   newfname, path_dhcpd_db);
 1167: 		goto fail;
 1168: 	}
 1169: 
 1170: 	counting = 1;
 1171: 	return 1;
 1172: 
 1173:       fail:
 1174: 	lease_file_is_corrupt = db_validity;
 1175:       fdfail:
 1176: 	unlink (newfname);
 1177: 	return 0;
 1178: }
 1179: 
 1180: int group_writer (struct group_object *group)
 1181: {
 1182: 	if (!write_group (group))
 1183: 		return 0;
 1184: 	if (!commit_leases ())
 1185: 		return 0;
 1186: 	return 1;
 1187: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>