1 /**	$MirOS: src/usr.sbin/dhcpd/db.c,v 1.2 2005/03/13 19:16:25 tg Exp $ */
2 /*	$OpenBSD: db.c,v 1.10 2004/09/16 18:35:42 deraadt Exp $	*/
3 
4 /*
5  * Persistent database management routines for DHCPD.
6  */
7 
8 /*
9  * Copyright (c) 1995, 1996 The Internet Software Consortium.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of The Internet Software Consortium nor the names
22  *    of its contributors may be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
26  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
27  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
30  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
33  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
34  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
36  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  * This software has been written for the Internet Software Consortium
40  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
41  * Enterprises.  To learn more about the Internet Software Consortium,
42  * see ``http://www.vix.com/isc''.  To learn more about Vixie
43  * Enterprises, see ``http://www.vix.com''.
44  */
45 
46 #include "dhcpd.h"
47 
48 __RCSID("$MirOS: src/usr.sbin/dhcpd/db.c,v 1.2 2005/03/13 19:16:25 tg Exp $");
49 
50 FILE *db_file;
51 
52 static int counting = 0;
53 static int count = 0;
54 time_t write_time;
55 
56 /*
57  * Write the specified lease to the current lease database file.
58  */
59 int
write_lease(struct lease * lease)60 write_lease(struct lease *lease)
61 {
62 	struct tm *t;
63 	char tbuf[64];
64 	int errors = 0;
65 	int i;
66 
67 	if (counting)
68 		++count;
69 	errno = 0;
70 	fprintf(db_file, "lease %s {\n", piaddr(lease->ip_addr));
71 	if (errno)
72 		++errors;
73 
74 	t = gmtime(&lease->starts);
75 	snprintf(tbuf, sizeof(tbuf), "%d %lld/%02d/%02d %02d:%02d:%02d;",
76 	    t->tm_wday, (int64_t)t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
77 	    t->tm_hour, t->tm_min, t->tm_sec);
78 
79 	errno = 0;
80 	fprintf(db_file, "\tstarts %s\n", tbuf);
81 	if (errno)
82 		++errors;
83 
84 	t = gmtime(&lease->ends);
85 	snprintf(tbuf, sizeof(tbuf), "%d %lld/%02d/%02d %02d:%02d:%02d;",
86 	    t->tm_wday, (int64_t)t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
87 	    t->tm_hour, t->tm_min, t->tm_sec);
88 
89 	errno = 0;
90 	fprintf(db_file, "\tends %s", tbuf);
91 	if (errno)
92 		++errors;
93 
94 	if (lease->hardware_addr.hlen) {
95 		errno = 0;
96 		fprintf(db_file, "\n\thardware %s %s;",
97 		    hardware_types[lease->hardware_addr.htype],
98 		    print_hw_addr(lease->hardware_addr.htype,
99 		    lease->hardware_addr.hlen,
100 		    lease->hardware_addr.haddr));
101 		if (errno)
102 			++errors;
103 	}
104 
105 	if (lease->uid_len) {
106 		int j;
107 
108 		errno = 0;
109 		fprintf(db_file, "\n\tuid %2.2x", lease->uid[0]);
110 		if (errno)
111 			++errors;
112 
113 		for (j = 1; j < lease->uid_len; j++) {
114 			errno = 0;
115 			fprintf(db_file, ":%2.2x", lease->uid[j]);
116 			if (errno)
117 				++errors;
118 		}
119 		putc(';', db_file);
120 	}
121 
122 	if (lease->flags & BOOTP_LEASE) {
123 		errno = 0;
124 		fprintf(db_file, "\n\tdynamic-bootp;");
125 		if (errno)
126 			++errors;
127 	}
128 
129 	if (lease->flags & ABANDONED_LEASE) {
130 		errno = 0;
131 		fprintf(db_file, "\n\tabandoned;");
132 		if (errno)
133 			++errors;
134 	}
135 
136 	if (lease->client_hostname) {
137 		for (i = 0; lease->client_hostname[i]; i++)
138 			if (lease->client_hostname[i] < 33 ||
139 			    lease->client_hostname[i] > 126)
140 				goto bad_client_hostname;
141 		errno = 0;
142 		fprintf(db_file, "\n\tclient-hostname \"%s\";",
143 		    lease->client_hostname);
144 		if (errno)
145 			++errors;
146 	}
147 
148 bad_client_hostname:
149 	if (lease->hostname) {
150 		for (i = 0; lease->hostname[i]; i++)
151 			if (lease->hostname[i] < 33 ||
152 			    lease->hostname[i] > 126)
153 				goto bad_hostname;
154 		errno = 0;
155 		fprintf(db_file, "\n\thostname \"%s\";",
156 		    lease->hostname);
157 		if (errno)
158 			++errors;
159 	}
160 
161 bad_hostname:
162 	errno = 0;
163 	fputs("\n}\n", db_file);
164 	if (errno)
165 		++errors;
166 
167 	if (errors)
168 		note("write_lease: unable to write lease %s",
169 		    piaddr(lease->ip_addr));
170 
171 	return (!errors);
172 }
173 
174 /*
175  * Commit any leases that have been written out...
176  */
177 int
commit_leases(void)178 commit_leases(void)
179 {
180 	/*
181 	 * Commit any outstanding writes to the lease database file. We need to
182 	 * do this even if we're rewriting the file below, just in case the
183 	 * rewrite fails.
184 	 */
185 	if (fflush(db_file) == EOF) {
186 		note("commit_leases: unable to commit: %m");
187 		return (0);
188 	}
189 
190 	if (fsync(fileno(db_file)) == -1) {
191 		note("commit_leases: unable to commit: %m");
192 		return (0);
193 	}
194 
195 	/*
196 	 * If we've written more than a thousand leases or if we haven't
197 	 * rewritten the lease database in over an hour, rewrite it now.
198 	 */
199 	if (count > 1000 || (count && cur_time - write_time > 3600)) {
200 		count = 0;
201 		write_time = cur_time;
202 		new_lease_file();
203 	}
204 
205 	return (1);
206 }
207 
208 void
db_startup(void)209 db_startup(void)
210 {
211 	int db_fd;
212 
213 	/* open lease file. once we dropped privs it has to stay open */
214 	db_fd = open(path_dhcpd_db, O_WRONLY|O_CREAT, 0664);
215 	if (db_fd == -1)
216 		error("Can't create new lease file: %m");
217 	if ((db_file = fdopen(db_fd, "w")) == NULL)
218 		error("Can't fdopen new lease file!");
219 
220 	/* Read in the existing lease file... */
221 	read_leases();
222 	time(&write_time);
223 
224 	new_lease_file();
225 }
226 
227 void
new_lease_file(void)228 new_lease_file(void)
229 {
230 	fflush(db_file);
231 	rewind(db_file);
232 
233 	/*
234 	 * Write an introduction so people don't complain about time being off.
235 	 */
236 	fprintf(db_file, "# All times in this file are in UTC (GMT), "
237 	    "not your local timezone.\n");
238 	fprintf(db_file, "# The format of this file is documented in "
239 	    "the dhcpd.leases(5) manual page.\n\n");
240 
241 	/* Write out all the leases that we know of... */
242 	counting = 0;
243 	write_leases();
244 
245 	fflush(db_file);
246 	ftruncate(fileno(db_file), ftello(db_file));
247 	fsync(fileno(db_file));
248 
249 	counting = 1;
250 }
251