1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
33*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
34*7c478bd9Sstevel@tonic-gate #include <net/if.h>
35*7c478bd9Sstevel@tonic-gate #include <netinet/dhcp.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
38*7c478bd9Sstevel@tonic-gate #include <time.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>			/* memcpy */
40*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
41*7c478bd9Sstevel@tonic-gate #include <limits.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include "dhcp_hostconf.h"
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate static void		relativize_time(DHCP_OPT *, time_t, time_t);
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate  * ifname_to_hostconf(): converts an interface name into a hostconf file for
49*7c478bd9Sstevel@tonic-gate  *			 that interface
50*7c478bd9Sstevel@tonic-gate  *
51*7c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
52*7c478bd9Sstevel@tonic-gate  *  output: char *: the hostconf filename
53*7c478bd9Sstevel@tonic-gate  *    note: uses an internal static buffer (not threadsafe)
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate char *
57*7c478bd9Sstevel@tonic-gate ifname_to_hostconf(const char *ifname)
58*7c478bd9Sstevel@tonic-gate {
59*7c478bd9Sstevel@tonic-gate 	static char filename[sizeof (DHCP_HOSTCONF_TMPL) + IFNAMSIZ];
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	(void) snprintf(filename, sizeof (filename), "%s%s%s",
62*7c478bd9Sstevel@tonic-gate 	    DHCP_HOSTCONF_PREFIX, ifname, DHCP_HOSTCONF_SUFFIX);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	return (filename);
65*7c478bd9Sstevel@tonic-gate }
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate /*
68*7c478bd9Sstevel@tonic-gate  * remove_hostconf(): removes an interface.dhc file
69*7c478bd9Sstevel@tonic-gate  *
70*7c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
71*7c478bd9Sstevel@tonic-gate  *  output: int: 0 if the file is removed, -1 if it can't be removed
72*7c478bd9Sstevel@tonic-gate  *          (errno is set)
73*7c478bd9Sstevel@tonic-gate  */
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate int
76*7c478bd9Sstevel@tonic-gate remove_hostconf(const char *ifname)
77*7c478bd9Sstevel@tonic-gate {
78*7c478bd9Sstevel@tonic-gate 	return (unlink(ifname_to_hostconf(ifname)));
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * read_hostconf(): reads the contents of an <if>.dhc file into a PKT_LIST
83*7c478bd9Sstevel@tonic-gate  *
84*7c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
85*7c478bd9Sstevel@tonic-gate  *	    PKT_LIST **: a pointer to a PKT_LIST * to store the info in
86*7c478bd9Sstevel@tonic-gate  *	    uint_t: the length of the list of PKT_LISTs
87*7c478bd9Sstevel@tonic-gate  *  output: int: 0 if the file is read and loaded into the PKT_LIST *
88*7c478bd9Sstevel@tonic-gate  *	    successfully, -1 otherwise (errno is set)
89*7c478bd9Sstevel@tonic-gate  *    note: the PKT and PKT_LISTs are dynamically allocated here
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate int
93*7c478bd9Sstevel@tonic-gate read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	PKT_LIST	*plp = NULL;
96*7c478bd9Sstevel@tonic-gate 	PKT		*pkt = NULL;
97*7c478bd9Sstevel@tonic-gate 	int		fd;
98*7c478bd9Sstevel@tonic-gate 	time_t		orig_time, current_time = time(NULL);
99*7c478bd9Sstevel@tonic-gate 	uint32_t	lease;
100*7c478bd9Sstevel@tonic-gate 	uint32_t	magic;
101*7c478bd9Sstevel@tonic-gate 	int		pcnt = 0;
102*7c478bd9Sstevel@tonic-gate 	int		retval;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	fd = open(ifname_to_hostconf(ifname), O_RDONLY);
105*7c478bd9Sstevel@tonic-gate 	if (fd == -1)
106*7c478bd9Sstevel@tonic-gate 		return (-1);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
109*7c478bd9Sstevel@tonic-gate 		goto failure;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	if (magic != DHCP_HOSTCONF_MAGIC)
112*7c478bd9Sstevel@tonic-gate 		goto failure;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	if (read(fd, &orig_time, sizeof (orig_time)) != sizeof (orig_time))
115*7c478bd9Sstevel@tonic-gate 		goto failure;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	/*
118*7c478bd9Sstevel@tonic-gate 	 * read the packet back in from disk, and run it through
119*7c478bd9Sstevel@tonic-gate 	 * dhcp_options_scan(). note that we use calloc() since
120*7c478bd9Sstevel@tonic-gate 	 * dhcp_options_scan() relies on the packet being zeroed.
121*7c478bd9Sstevel@tonic-gate 	 */
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	for (pcnt = 0; pcnt < plplen; pcnt++) {
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 		plp = NULL;
126*7c478bd9Sstevel@tonic-gate 		pkt = NULL;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 		if ((plp = calloc(1, sizeof (PKT_LIST))) == NULL)
129*7c478bd9Sstevel@tonic-gate 			goto failure;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 		retval = read(fd, &plp->len, sizeof (plp->len));
132*7c478bd9Sstevel@tonic-gate 		if (retval == 0 && pcnt != 0) {
133*7c478bd9Sstevel@tonic-gate 			/*
134*7c478bd9Sstevel@tonic-gate 			 * Reached end of file on a boundary, but after
135*7c478bd9Sstevel@tonic-gate 			 * we've read at least one packet, so we consider
136*7c478bd9Sstevel@tonic-gate 			 * this successful, allowing us to use files from
137*7c478bd9Sstevel@tonic-gate 			 * older versions of the agent happily.
138*7c478bd9Sstevel@tonic-gate 			 */
139*7c478bd9Sstevel@tonic-gate 			free(plp);
140*7c478bd9Sstevel@tonic-gate 			break;
141*7c478bd9Sstevel@tonic-gate 		} else if (retval != sizeof (plp->len))
142*7c478bd9Sstevel@tonic-gate 			goto failure;
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 		if ((pkt = malloc(plp->len)) == NULL)
145*7c478bd9Sstevel@tonic-gate 			goto failure;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 		if (read(fd, pkt, plp->len) != plp->len)
148*7c478bd9Sstevel@tonic-gate 			goto failure;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 		plp->pkt = pkt;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 		plpp[pcnt] = plp;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 		if (dhcp_options_scan(plp, B_TRUE) != 0)
155*7c478bd9Sstevel@tonic-gate 			goto failure;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 		/*
158*7c478bd9Sstevel@tonic-gate 		 * First packet used to validate that we're interested,
159*7c478bd9Sstevel@tonic-gate 		 * the rest are presumed to be historical reference and
160*7c478bd9Sstevel@tonic-gate 		 * are not relativized
161*7c478bd9Sstevel@tonic-gate 		 */
162*7c478bd9Sstevel@tonic-gate 		if (pcnt == 0)
163*7c478bd9Sstevel@tonic-gate 			continue;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 		/*
166*7c478bd9Sstevel@tonic-gate 		 * make sure the lease is still valid.
167*7c478bd9Sstevel@tonic-gate 		 */
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		if (plp->opts[CD_LEASE_TIME] != NULL &&
170*7c478bd9Sstevel@tonic-gate 		    plp->opts[CD_LEASE_TIME]->len == sizeof (lease_t)) {
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 			(void) memcpy(&lease, plp->opts[CD_LEASE_TIME]->value,
173*7c478bd9Sstevel@tonic-gate 			    sizeof (lease_t));
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 			lease = ntohl(lease);
176*7c478bd9Sstevel@tonic-gate 			if ((lease != DHCP_PERM) &&
177*7c478bd9Sstevel@tonic-gate 			    (orig_time + lease) <= current_time)
178*7c478bd9Sstevel@tonic-gate 				goto failure;
179*7c478bd9Sstevel@tonic-gate 		}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 		relativize_time(plp->opts[CD_T1_TIME], orig_time, current_time);
182*7c478bd9Sstevel@tonic-gate 		relativize_time(plp->opts[CD_T2_TIME], orig_time, current_time);
183*7c478bd9Sstevel@tonic-gate 		relativize_time(plp->opts[CD_LEASE_TIME], orig_time,
184*7c478bd9Sstevel@tonic-gate 		    current_time);
185*7c478bd9Sstevel@tonic-gate 	}
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
188*7c478bd9Sstevel@tonic-gate 	return (pcnt);
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate failure:
191*7c478bd9Sstevel@tonic-gate 	free(pkt);
192*7c478bd9Sstevel@tonic-gate 	free(plp);
193*7c478bd9Sstevel@tonic-gate 	while (pcnt-- > 0) {
194*7c478bd9Sstevel@tonic-gate 		free(plpp[pcnt]->pkt);
195*7c478bd9Sstevel@tonic-gate 		free(plpp[pcnt]);
196*7c478bd9Sstevel@tonic-gate 	}
197*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
198*7c478bd9Sstevel@tonic-gate 	return (-1);
199*7c478bd9Sstevel@tonic-gate }
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate /*
202*7c478bd9Sstevel@tonic-gate  * write_hostconf(): writes the contents of a PKT_LIST into an <if>.dhc file
203*7c478bd9Sstevel@tonic-gate  *
204*7c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
205*7c478bd9Sstevel@tonic-gate  *	    PKT_LIST **: a list of pointers to PKT_LIST to write
206*7c478bd9Sstevel@tonic-gate  *	    int: length of the list of PKT_LIST pointers
207*7c478bd9Sstevel@tonic-gate  *	    time_t: a starting time to treat the relative lease times
208*7c478bd9Sstevel@tonic-gate  *		    in the first packet as relative to
209*7c478bd9Sstevel@tonic-gate  *  output: int: 0 if the file is written successfully, -1 otherwise
210*7c478bd9Sstevel@tonic-gate  *	    (errno is set)
211*7c478bd9Sstevel@tonic-gate  */
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate int
214*7c478bd9Sstevel@tonic-gate write_hostconf(
215*7c478bd9Sstevel@tonic-gate     const char *ifname,
216*7c478bd9Sstevel@tonic-gate     PKT_LIST *pl[],
217*7c478bd9Sstevel@tonic-gate     uint_t pllen,
218*7c478bd9Sstevel@tonic-gate     time_t relative_to)
219*7c478bd9Sstevel@tonic-gate {
220*7c478bd9Sstevel@tonic-gate 	int		fd;
221*7c478bd9Sstevel@tonic-gate 	struct iovec	iov[IOV_MAX];
222*7c478bd9Sstevel@tonic-gate 	int		retval;
223*7c478bd9Sstevel@tonic-gate 	uint32_t	magic = DHCP_HOSTCONF_MAGIC;
224*7c478bd9Sstevel@tonic-gate 	ssize_t		explen = 0; /* Expected length of write */
225*7c478bd9Sstevel@tonic-gate 	int		i, iovlen = 0;
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	fd = open(ifname_to_hostconf(ifname), O_WRONLY|O_CREAT|O_TRUNC, 0600);
228*7c478bd9Sstevel@tonic-gate 	if (fd == -1)
229*7c478bd9Sstevel@tonic-gate 		return (-1);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	/*
232*7c478bd9Sstevel@tonic-gate 	 * first write our magic number, then the relative time of the
233*7c478bd9Sstevel@tonic-gate 	 * leases, then for each packet we write the length of the packet
234*7c478bd9Sstevel@tonic-gate 	 * followed by the packet.  we will then use the relative time in
235*7c478bd9Sstevel@tonic-gate 	 * read_hostconf() to recalculate the lease times for the first packet.
236*7c478bd9Sstevel@tonic-gate 	 */
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	iov[iovlen].iov_base = (caddr_t)&magic;
239*7c478bd9Sstevel@tonic-gate 	explen += iov[iovlen++].iov_len  = sizeof (magic);
240*7c478bd9Sstevel@tonic-gate 	iov[iovlen].iov_base = (caddr_t)&relative_to;
241*7c478bd9Sstevel@tonic-gate 	explen += iov[iovlen++].iov_len  = sizeof (relative_to);
242*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < pllen && iovlen < (IOV_MAX - 1); i++) {
243*7c478bd9Sstevel@tonic-gate 		iov[iovlen].iov_base = (caddr_t)&pl[i]->len;
244*7c478bd9Sstevel@tonic-gate 		explen += iov[iovlen++].iov_len  = sizeof (pl[i]->len);
245*7c478bd9Sstevel@tonic-gate 		iov[iovlen].iov_base = (caddr_t)pl[i]->pkt;
246*7c478bd9Sstevel@tonic-gate 		explen += iov[iovlen++].iov_len  = pl[i]->len;
247*7c478bd9Sstevel@tonic-gate 	}
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	retval = writev(fd, iov, iovlen);
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	if (retval != explen)
254*7c478bd9Sstevel@tonic-gate 		return (-1);
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	return (0);
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate /*
260*7c478bd9Sstevel@tonic-gate  * relativize_time(): re-relativizes a time in a DHCP option
261*7c478bd9Sstevel@tonic-gate  *
262*7c478bd9Sstevel@tonic-gate  *   input: DHCP_OPT *: the DHCP option parameter to convert
263*7c478bd9Sstevel@tonic-gate  *	    time_t: the time the leases in the packet are currently relative to
264*7c478bd9Sstevel@tonic-gate  *	    time_t: the current time which leases will become relative to
265*7c478bd9Sstevel@tonic-gate  *  output: void
266*7c478bd9Sstevel@tonic-gate  */
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate static void
269*7c478bd9Sstevel@tonic-gate relativize_time(DHCP_OPT *option, time_t orig_time, time_t current_time)
270*7c478bd9Sstevel@tonic-gate {
271*7c478bd9Sstevel@tonic-gate 	uint32_t	pkt_time;
272*7c478bd9Sstevel@tonic-gate 	time_t		time_diff = current_time - orig_time;
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	if (option == NULL || option->len != sizeof (lease_t))
275*7c478bd9Sstevel@tonic-gate 		return;
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&pkt_time, option->value, option->len);
278*7c478bd9Sstevel@tonic-gate 	if (ntohl(pkt_time) != DHCP_PERM)
279*7c478bd9Sstevel@tonic-gate 		pkt_time = htonl(ntohl(pkt_time) - time_diff);
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	(void) memcpy(option->value, &pkt_time, option->len);
282*7c478bd9Sstevel@tonic-gate }
283