xref: /reactos/base/services/dhcpcsvc/dhcp/dhclient.c (revision 033b6639)
1 /*	$OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $	*/
2 
3 /*
4  * Copyright 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 1995, 1996, 1997, 1998, 1999
6  * The Internet Software Consortium.    All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of The Internet Software Consortium nor the names
18  *    of its contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * This software has been written for the Internet Software Consortium
36  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37  * Enterprises.  To learn more about the Internet Software Consortium,
38  * see ``http://www.vix.com/isc''.  To learn more about Vixie
39  * Enterprises, see ``http://www.vix.com''.
40  *
41  * This client was substantially modified and enhanced by Elliot Poger
42  * for use on Linux while he was working on the MosquitoNet project at
43  * Stanford.
44  *
45  * The current version owes much to Elliot's Linux enhancements, but
46  * was substantially reorganized and partially rewritten by Ted Lemon
47  * so as to use the same networking framework that the Internet Software
48  * Consortium DHCP server uses.   Much system-specific configuration code
49  * was moved into a shell script so that as support for more operating
50  * systems is added, it will not be necessary to port and maintain
51  * system-specific configuration code to these operating systems - instead,
52  * the shell script can invoke the native tools to accomplish the same
53  * purpose.
54  */
55 
56 #include <rosdhcp.h>
57 
58 #define	PERIOD 0x2e
59 #define	hyphenchar(c) ((c) == 0x2d)
60 #define	bslashchar(c) ((c) == 0x5c)
61 #define	periodchar(c) ((c) == PERIOD)
62 #define	asterchar(c) ((c) == 0x2a)
63 #define	alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
64 	    ((c) >= 0x61 && (c) <= 0x7a))
65 #define	digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
66 
67 #define	borderchar(c) (alphachar(c) || digitchar(c))
68 #define	middlechar(c) (borderchar(c) || hyphenchar(c))
69 #define	domainchar(c) ((c) > 0x20 && (c) < 0x7f)
70 
71 unsigned long debug_trace_level = 0; /* DEBUG_ULTRA */
72 
73 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
74 char *path_dhclient_db = NULL;
75 
76 int log_perror = 1;
77 int privfd;
78 //int nullfd = -1;
79 
80 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
81 struct in_addr inaddr_any;
82 struct sockaddr_in sockaddr_broadcast;
83 
84 /*
85  * ASSERT_STATE() does nothing now; it used to be
86  * assert (state_is == state_shouldbe).
87  */
88 #define ASSERT_STATE(state_is, state_shouldbe) {}
89 
90 #define TIME_MAX 2147483647
91 
92 int		log_priority;
93 int		no_daemon;
94 int		unknown_ok = 1;
95 int		routefd;
96 
97 void		 usage(void);
98 int		 check_option(struct client_lease *l, int option);
99 int		 ipv4addrs(char * buf);
100 int		 res_hnok(const char *dn);
101 char		*option_as_string(unsigned int code, unsigned char *data, int len);
102 int		 fork_privchld(int, int);
103 int              check_arp( struct interface_info *ip, struct client_lease *lp );
104 
105 #define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
106 
107 time_t	scripttime;
108 
109 
110 int
init_client(void)111 init_client(void)
112 {
113     ApiInit();
114     AdapterInit();
115 
116     tzset();
117 
118     memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
119     sockaddr_broadcast.sin_family = AF_INET;
120     sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
121     sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
122     inaddr_any.s_addr = INADDR_ANY;
123     bootp_packet_handler = do_packet;
124 
125     return 1; // TRUE
126 }
127 
128 void
stop_client(void)129 stop_client(void)
130 {
131     // AdapterStop();
132     // ApiFree();
133     /* FIXME: Close pipe and kill pipe thread */
134 }
135 
136 /* XXX Implement me */
check_arp(struct interface_info * ip,struct client_lease * lp)137 int check_arp( struct interface_info *ip, struct client_lease *lp ) {
138     return 1;
139 }
140 
141 /*
142  * Individual States:
143  *
144  * Each routine is called from the dhclient_state_machine() in one of
145  * these conditions:
146  * -> entering INIT state
147  * -> recvpacket_flag == 0: timeout in this state
148  * -> otherwise: received a packet in this state
149  *
150  * Return conditions as handled by dhclient_state_machine():
151  * Returns 1, sendpacket_flag = 1: send packet, reset timer.
152  * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
153  * Returns 0: finish the nap which was interrupted for no good reason.
154  *
155  * Several per-interface variables are used to keep track of the process:
156  *   active_lease: the lease that is being used on the interface
157  *                 (null pointer if not configured yet).
158  *   offered_leases: leases corresponding to DHCPOFFER messages that have
159  *                   been sent to us by DHCP servers.
160  *   acked_leases: leases corresponding to DHCPACK messages that have been
161  *                 sent to us by DHCP servers.
162  *   sendpacket: DHCP packet we're trying to send.
163  *   destination: IP address to send sendpacket to
164  * In addition, there are several relevant per-lease variables.
165  *   T1_expiry, T2_expiry, lease_expiry: lease milestones
166  * In the active lease, these control the process of renewing the lease;
167  * In leases on the acked_leases list, this simply determines when we
168  * can no longer legitimately use the lease.
169  */
170 
171 void
state_reboot(void * ipp)172 state_reboot(void *ipp)
173 {
174 	struct interface_info *ip = ipp;
175 	ULONG foo = (ULONG) GetTickCount();
176 
177 	/* If we don't remember an active lease, go straight to INIT. */
178 	if (!ip->client->active || ip->client->active->is_bootp) {
179 		state_init(ip);
180 		return;
181 	}
182 
183 	/* We are in the rebooting state. */
184 	ip->client->state = S_REBOOTING;
185 
186 	/* make_request doesn't initialize xid because it normally comes
187 	   from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
188 	   so pick an xid now. */
189 	ip->client->xid = RtlRandom(&foo);
190 
191 	/* Make a DHCPREQUEST packet, and set appropriate per-interface
192 	   flags. */
193 	make_request(ip, ip->client->active);
194 	ip->client->destination = iaddr_broadcast;
195 	time(&ip->client->first_sending);
196 	ip->client->interval = ip->client->config->initial_interval;
197 
198 	/* Zap the medium list... */
199 	ip->client->medium = NULL;
200 
201 	/* Send out the first DHCPREQUEST packet. */
202 	send_request(ip);
203 }
204 
205 /*
206  * Called when a lease has completely expired and we've
207  * been unable to renew it.
208  */
209 void
state_init(void * ipp)210 state_init(void *ipp)
211 {
212 	struct interface_info *ip = ipp;
213 
214 	ASSERT_STATE(state, S_INIT);
215 
216 	/* Make a DHCPDISCOVER packet, and set appropriate per-interface
217 	   flags. */
218 	make_discover(ip, ip->client->active);
219 	ip->client->xid = ip->client->packet.xid;
220 	ip->client->destination = iaddr_broadcast;
221 	ip->client->state = S_SELECTING;
222 	time(&ip->client->first_sending);
223 	ip->client->interval = ip->client->config->initial_interval;
224 
225 	/* Add an immediate timeout to cause the first DHCPDISCOVER packet
226 	   to go out. */
227 	send_discover(ip);
228 }
229 
230 /*
231  * state_selecting is called when one or more DHCPOFFER packets
232  * have been received and a configurable period of time has passed.
233  */
234 void
state_selecting(void * ipp)235 state_selecting(void *ipp)
236 {
237 	struct interface_info *ip = ipp;
238 	struct client_lease *lp, *next, *picked;
239         time_t cur_time;
240 
241 	ASSERT_STATE(state, S_SELECTING);
242 
243         time(&cur_time);
244 
245 	/* Cancel state_selecting and send_discover timeouts, since either
246 	   one could have got us here. */
247 	cancel_timeout(state_selecting, ip);
248 	cancel_timeout(send_discover, ip);
249 
250 	/* We have received one or more DHCPOFFER packets.   Currently,
251 	   the only criterion by which we judge leases is whether or
252 	   not we get a response when we arp for them. */
253 	picked = NULL;
254 	for (lp = ip->client->offered_leases; lp; lp = next) {
255 		next = lp->next;
256 
257 		/* Check to see if we got an ARPREPLY for the address
258 		   in this particular lease. */
259 		if (!picked) {
260                     if( !check_arp(ip,lp) ) goto freeit;
261                     picked = lp;
262                     picked->next = NULL;
263 		} else {
264 freeit:
265 			free_client_lease(lp);
266 		}
267 	}
268 	ip->client->offered_leases = NULL;
269 
270 	/* If we just tossed all the leases we were offered, go back
271 	   to square one. */
272 	if (!picked) {
273 		ip->client->state = S_INIT;
274 		state_init(ip);
275 		return;
276 	}
277 
278 	/* If it was a BOOTREPLY, we can just take the address right now. */
279 	if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
280 		ip->client->new = picked;
281 
282 		/* Make up some lease expiry times
283 		   XXX these should be configurable. */
284 		ip->client->new->expiry = cur_time + 12000;
285 		ip->client->new->renewal += cur_time + 8000;
286 		ip->client->new->rebind += cur_time + 10000;
287 
288 		ip->client->state = S_REQUESTING;
289 
290 		/* Bind to the address we received. */
291 		bind_lease(ip);
292 		return;
293 	}
294 
295 	/* Go to the REQUESTING state. */
296 	ip->client->destination = iaddr_broadcast;
297 	ip->client->state = S_REQUESTING;
298 	ip->client->first_sending = cur_time;
299 	ip->client->interval = ip->client->config->initial_interval;
300 
301 	/* Make a DHCPREQUEST packet from the lease we picked. */
302 	make_request(ip, picked);
303 	ip->client->xid = ip->client->packet.xid;
304 
305 	/* Toss the lease we picked - we'll get it back in a DHCPACK. */
306 	free_client_lease(picked);
307 
308 	/* Add an immediate timeout to send the first DHCPREQUEST packet. */
309 	send_request(ip);
310 }
311 
312 /* state_requesting is called when we receive a DHCPACK message after
313    having sent out one or more DHCPREQUEST packets. */
314 
315 void
dhcpack(struct packet * packet)316 dhcpack(struct packet *packet)
317 {
318 	struct interface_info *ip = packet->interface;
319 	struct client_lease *lease;
320         time_t cur_time;
321 
322         time(&cur_time);
323 
324 	/* If we're not receptive to an offer right now, or if the offer
325 	   has an unrecognizable transaction id, then just drop it. */
326 	if (packet->interface->client->xid != packet->raw->xid ||
327 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
328 	    (memcmp(packet->interface->hw_address.haddr,
329 	    packet->raw->chaddr, packet->raw->hlen)))
330 		return;
331 
332 	if (ip->client->state != S_REBOOTING &&
333 	    ip->client->state != S_REQUESTING &&
334 	    ip->client->state != S_RENEWING &&
335 	    ip->client->state != S_REBINDING)
336 		return;
337 
338 	note("DHCPACK from %s", piaddr(packet->client_addr));
339 
340 	lease = packet_to_lease(packet);
341 	if (!lease) {
342 		note("packet_to_lease failed.");
343 		return;
344 	}
345 
346 	ip->client->new = lease;
347 
348 	/* Stop resending DHCPREQUEST. */
349 	cancel_timeout(send_request, ip);
350 
351 	/* Figure out the lease time. */
352 	if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
353 		ip->client->new->expiry = getULong(
354 		    ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
355 	else
356 		ip->client->new->expiry = DHCP_DEFAULT_LEASE_TIME;
357 	/* A number that looks negative here is really just very large,
358 	   because the lease expiry offset is unsigned. */
359 	if (ip->client->new->expiry < 0)
360 		ip->client->new->expiry = TIME_MAX;
361 	/* XXX should be fixed by resetting the client state */
362 	if (ip->client->new->expiry < 60)
363 		ip->client->new->expiry = 60;
364 
365 	/* Take the server-provided renewal time if there is one;
366 	   otherwise figure it out according to the spec. */
367 	if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
368 		ip->client->new->renewal = getULong(
369 		    ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
370 	else
371 		ip->client->new->renewal = ip->client->new->expiry / 2;
372 
373 	/* Same deal with the rebind time. */
374 	if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
375 		ip->client->new->rebind = getULong(
376 		    ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
377 	else
378 		ip->client->new->rebind = ip->client->new->renewal +
379 		    ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
380 
381 #ifdef __REACTOS__
382 	ip->client->new->obtained = cur_time;
383 #endif
384 	ip->client->new->expiry += cur_time;
385 	/* Lease lengths can never be negative. */
386 	if (ip->client->new->expiry < cur_time)
387 		ip->client->new->expiry = TIME_MAX;
388 	ip->client->new->renewal += cur_time;
389 	if (ip->client->new->renewal < cur_time)
390 		ip->client->new->renewal = TIME_MAX;
391 	ip->client->new->rebind += cur_time;
392 	if (ip->client->new->rebind < cur_time)
393 		ip->client->new->rebind = TIME_MAX;
394 
395 	bind_lease(ip);
396 }
397 
set_name_servers(PDHCP_ADAPTER Adapter,struct client_lease * new_lease)398 void set_name_servers( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
399     CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
400     HKEY RegKey;
401 
402     strcat(Buffer, Adapter->DhclientInfo.name);
403     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &RegKey ) != ERROR_SUCCESS)
404         return;
405 
406 
407     if( new_lease->options[DHO_DOMAIN_NAME_SERVERS].len ) {
408 
409         struct iaddr nameserver;
410         char *nsbuf;
411         int i, addrs =
412             new_lease->options[DHO_DOMAIN_NAME_SERVERS].len / sizeof(ULONG);
413 
414         nsbuf = malloc( addrs * sizeof(IP_ADDRESS_STRING) );
415 
416         if( nsbuf) {
417             nsbuf[0] = 0;
418             for( i = 0; i < addrs; i++ ) {
419                 nameserver.len = sizeof(ULONG);
420                 memcpy( nameserver.iabuf,
421                         new_lease->options[DHO_DOMAIN_NAME_SERVERS].data +
422                         (i * sizeof(ULONG)), sizeof(ULONG) );
423                 strcat( nsbuf, piaddr(nameserver) );
424                 if( i != addrs-1 ) strcat( nsbuf, "," );
425             }
426 
427             DH_DbgPrint(MID_TRACE,("Setting DhcpNameserver: %s\n", nsbuf));
428 
429             RegSetValueExA( RegKey, "DhcpNameServer", 0, REG_SZ,
430                            (LPBYTE)nsbuf, strlen(nsbuf) + 1 );
431             free( nsbuf );
432         }
433 
434     } else {
435             RegDeleteValueW( RegKey, L"DhcpNameServer" );
436     }
437 
438     RegCloseKey( RegKey );
439 
440 }
441 
442 void
set_domain(PDHCP_ADAPTER Adapter,struct client_lease * new_lease)443 set_domain(PDHCP_ADAPTER Adapter,
444            struct client_lease *new_lease)
445 {
446     CHAR Buffer1[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
447     CHAR Buffer2[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
448     HKEY RegKey1, RegKey2;
449 
450     strcat(Buffer1, Adapter->DhclientInfo.name);
451 
452     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer1, 0, KEY_WRITE, &RegKey1 ) != ERROR_SUCCESS)
453     {
454         return;
455     }
456 
457     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer2, 0, KEY_WRITE, &RegKey2 ) != ERROR_SUCCESS)
458     {
459         RegCloseKey(RegKey1);
460         return;
461     }
462 
463     if (new_lease->options[DHO_DOMAIN_NAME].len)
464     {
465         DH_DbgPrint(MID_TRACE, ("Setting DhcpDomain: %s\n", new_lease->options[DHO_DOMAIN_NAME].data));
466 
467         RegSetValueExA(RegKey1,
468                        "DhcpDomain",
469                        0,
470                        REG_SZ,
471                        (LPBYTE)new_lease->options[DHO_DOMAIN_NAME].data,
472                        new_lease->options[DHO_DOMAIN_NAME].len);
473 
474         RegSetValueExA(RegKey2,
475                        "DhcpDomain",
476                        0,
477                        REG_SZ,
478                        (LPBYTE)new_lease->options[DHO_DOMAIN_NAME].data,
479                        new_lease->options[DHO_DOMAIN_NAME].len);
480     }
481     else
482     {
483         RegDeleteValueW(RegKey1, L"DhcpDomain");
484         RegDeleteValueW(RegKey2, L"DhcpDomain");
485     }
486 
487     RegCloseKey(RegKey1);
488     RegCloseKey(RegKey2);
489 
490 }
491 
setup_adapter(PDHCP_ADAPTER Adapter,struct client_lease * new_lease)492 void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
493     CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
494     struct iaddr netmask;
495     HKEY hkey;
496     int i;
497     DWORD dwEnableDHCP;
498 
499     strcat(Buffer, Adapter->DhclientInfo.name);
500     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS)
501         hkey = NULL;
502 
503 
504     if( Adapter->NteContext )
505     {
506         DeleteIPAddress( Adapter->NteContext );
507         Adapter->NteContext = 0;
508     }
509 
510     /* Set up our default router if we got one from the DHCP server */
511     if( new_lease->options[DHO_SUBNET_MASK].len ) {
512         NTSTATUS Status;
513 
514         memcpy( netmask.iabuf,
515                 new_lease->options[DHO_SUBNET_MASK].data,
516                 new_lease->options[DHO_SUBNET_MASK].len );
517         Status = AddIPAddress
518             ( *((ULONG*)new_lease->address.iabuf),
519               *((ULONG*)netmask.iabuf),
520               Adapter->IfMib.dwIndex,
521               &Adapter->NteContext,
522               &Adapter->NteInstance );
523         if (hkey) {
524             RegSetValueExA(hkey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)piaddr(new_lease->address), strlen(piaddr(new_lease->address))+1);
525             Buffer[0] = '\0';
526             for(i = 0; i < new_lease->options[DHO_SUBNET_MASK].len; i++)
527             {
528                 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_SUBNET_MASK].data[i]);
529                 if (i + 1 < new_lease->options[DHO_SUBNET_MASK].len)
530                     strcat(Buffer, ".");
531             }
532             RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
533             dwEnableDHCP = 1;
534             RegSetValueExA(hkey, "EnableDHCP", 0, REG_DWORD, (LPBYTE)&dwEnableDHCP, sizeof(DWORD));
535         }
536 
537         if( !NT_SUCCESS(Status) )
538             warning("AddIPAddress: %lx\n", Status);
539     }
540 
541     if( new_lease->options[DHO_ROUTERS].len ) {
542         NTSTATUS Status;
543 
544         Adapter->RouterMib.dwForwardDest = 0; /* Default route */
545         Adapter->RouterMib.dwForwardMask = 0;
546         Adapter->RouterMib.dwForwardMetric1 = 1;
547         Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex;
548 
549         if( Adapter->RouterMib.dwForwardNextHop ) {
550             /* If we set a default route before, delete it before continuing */
551             DeleteIpForwardEntry( &Adapter->RouterMib );
552         }
553 
554         Adapter->RouterMib.dwForwardNextHop =
555             *((ULONG*)new_lease->options[DHO_ROUTERS].data);
556 
557         Status = CreateIpForwardEntry( &Adapter->RouterMib );
558 
559         if( !NT_SUCCESS(Status) )
560             warning("CreateIpForwardEntry: %lx\n", Status);
561 
562         if (hkey) {
563             Buffer[0] = '\0';
564             for(i = 0; i < new_lease->options[DHO_ROUTERS].len; i++)
565             {
566                 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_ROUTERS].data[i]);
567                 if (i + 1 < new_lease->options[DHO_ROUTERS].len)
568                     strcat(Buffer, ".");
569             }
570             RegSetValueExA(hkey, "DhcpDefaultGateway", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
571         }
572     }
573 
574     if (hkey)
575         RegCloseKey(hkey);
576 }
577 
578 
579 void
bind_lease(struct interface_info * ip)580 bind_lease(struct interface_info *ip)
581 {
582     PDHCP_ADAPTER Adapter;
583     struct client_lease *new_lease = ip->client->new;
584     time_t cur_time;
585 
586     time(&cur_time);
587 
588     /* Remember the medium. */
589     ip->client->new->medium = ip->client->medium;
590 
591     /* Replace the old active lease with the new one. */
592     if (ip->client->active)
593         free_client_lease(ip->client->active);
594     ip->client->active = ip->client->new;
595     ip->client->new = NULL;
596 
597     /* Set up a timeout to start the renewal process. */
598     /* Timeout of zero means no timeout (some implementations seem to use
599      * one day).
600      */
601     if( ip->client->active->renewal - cur_time )
602         add_timeout(ip->client->active->renewal, state_bound, ip);
603 
604     note("bound to %s -- renewal in %ld seconds.",
605          piaddr(ip->client->active->address),
606          (long int)(ip->client->active->renewal - cur_time));
607 
608     ip->client->state = S_BOUND;
609 
610     Adapter = AdapterFindInfo( ip );
611 
612     if( Adapter )  setup_adapter( Adapter, new_lease );
613     else {
614         warning("Could not find adapter for info %p\n", ip);
615         return;
616     }
617     set_name_servers( Adapter, new_lease );
618     set_domain( Adapter, new_lease );
619 }
620 
621 /*
622  * state_bound is called when we've successfully bound to a particular
623  * lease, but the renewal time on that lease has expired.   We are
624  * expected to unicast a DHCPREQUEST to the server that gave us our
625  * original lease.
626  */
627 void
state_bound(void * ipp)628 state_bound(void *ipp)
629 {
630 	struct interface_info *ip = ipp;
631 
632 	ASSERT_STATE(state, S_BOUND);
633 
634 	/* T1 has expired. */
635 	make_request(ip, ip->client->active);
636 	ip->client->xid = ip->client->packet.xid;
637 
638 	if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
639 		memcpy(ip->client->destination.iabuf, ip->client->active->
640 		    options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
641 		ip->client->destination.len = 4;
642 	} else
643 		ip->client->destination = iaddr_broadcast;
644 
645 	time(&ip->client->first_sending);
646 	ip->client->interval = ip->client->config->initial_interval;
647 	ip->client->state = S_RENEWING;
648 
649 	/* Send the first packet immediately. */
650 	send_request(ip);
651 }
652 
653 void
bootp(struct packet * packet)654 bootp(struct packet *packet)
655 {
656 	struct iaddrlist *ap;
657 
658 	if (packet->raw->op != BOOTREPLY)
659 		return;
660 
661 	/* If there's a reject list, make sure this packet's sender isn't
662 	   on it. */
663 	for (ap = packet->interface->client->config->reject_list;
664 	    ap; ap = ap->next) {
665 		if (addr_eq(packet->client_addr, ap->addr)) {
666 			note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
667 			return;
668 		}
669 	}
670 	dhcpoffer(packet);
671 }
672 
673 void
dhcp(struct packet * packet)674 dhcp(struct packet *packet)
675 {
676 	struct iaddrlist *ap;
677 	void (*handler)(struct packet *);
678 	char *type;
679 
680 	switch (packet->packet_type) {
681 	case DHCPOFFER:
682 		handler = dhcpoffer;
683 		type = "DHCPOFFER";
684 		break;
685 	case DHCPNAK:
686 		handler = dhcpnak;
687 		type = "DHCPNACK";
688 		break;
689 	case DHCPACK:
690 		handler = dhcpack;
691 		type = "DHCPACK";
692 		break;
693 	default:
694 		return;
695 	}
696 
697 	/* If there's a reject list, make sure this packet's sender isn't
698 	   on it. */
699 	for (ap = packet->interface->client->config->reject_list;
700 	    ap; ap = ap->next) {
701 		if (addr_eq(packet->client_addr, ap->addr)) {
702 			note("%s from %s rejected.", type, piaddr(ap->addr));
703 			return;
704 		}
705 	}
706 	(*handler)(packet);
707 }
708 
709 void
dhcpoffer(struct packet * packet)710 dhcpoffer(struct packet *packet)
711 {
712 	struct interface_info *ip = packet->interface;
713 	struct client_lease *lease, *lp;
714 	int i;
715 	int arp_timeout_needed = 0, stop_selecting;
716 	char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
717 	    "DHCPOFFER" : "BOOTREPLY";
718         time_t cur_time;
719 
720         time(&cur_time);
721 
722 	/* If we're not receptive to an offer right now, or if the offer
723 	   has an unrecognizable transaction id, then just drop it. */
724 	if (ip->client->state != S_SELECTING ||
725             packet->interface->client->xid != packet->raw->xid ||
726             (packet->interface->hw_address.hlen != packet->raw->hlen) ||
727 	    (memcmp(packet->interface->hw_address.haddr,
728 	    packet->raw->chaddr, packet->raw->hlen)))
729 		return;
730 
731 	note("%s from %s", name, piaddr(packet->client_addr));
732 
733 
734 	/* If this lease doesn't supply the minimum required parameters,
735 	   blow it off. */
736 	for (i = 0; ip->client->config->required_options[i]; i++) {
737 		if (!packet->options[ip->client->config->
738 		    required_options[i]].len) {
739 			note("%s isn't satisfactory.", name);
740 			return;
741 		}
742 	}
743 
744 	/* If we've already seen this lease, don't record it again. */
745 	for (lease = ip->client->offered_leases;
746 	    lease; lease = lease->next) {
747 		if (lease->address.len == sizeof(packet->raw->yiaddr) &&
748 		    !memcmp(lease->address.iabuf,
749 		    &packet->raw->yiaddr, lease->address.len)) {
750 			debug("%s already seen.", name);
751 			return;
752 		}
753 	}
754 
755 	lease = packet_to_lease(packet);
756 	if (!lease) {
757 		note("packet_to_lease failed.");
758 		return;
759 	}
760 
761 	/* If this lease was acquired through a BOOTREPLY, record that
762 	   fact. */
763 	if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
764 		lease->is_bootp = 1;
765 
766 	/* Record the medium under which this lease was offered. */
767 	lease->medium = ip->client->medium;
768 
769 	/* Send out an ARP Request for the offered IP address. */
770         if( !check_arp( ip, lease ) ) {
771             note("Arp check failed\n");
772             return;
773         }
774 
775 	/* Figure out when we're supposed to stop selecting. */
776 	stop_selecting =
777 	    ip->client->first_sending + ip->client->config->select_interval;
778 
779 	/* If this is the lease we asked for, put it at the head of the
780 	   list, and don't mess with the arp request timeout. */
781 	if (lease->address.len == ip->client->requested_address.len &&
782 	    !memcmp(lease->address.iabuf,
783 	    ip->client->requested_address.iabuf,
784 	    ip->client->requested_address.len)) {
785 		lease->next = ip->client->offered_leases;
786 		ip->client->offered_leases = lease;
787 	} else {
788 		/* If we already have an offer, and arping for this
789 		   offer would take us past the selection timeout,
790 		   then don't extend the timeout - just hope for the
791 		   best. */
792 		if (ip->client->offered_leases &&
793 		    (cur_time + arp_timeout_needed) > stop_selecting)
794 			arp_timeout_needed = 0;
795 
796 		/* Put the lease at the end of the list. */
797 		lease->next = NULL;
798 		if (!ip->client->offered_leases)
799 			ip->client->offered_leases = lease;
800 		else {
801 			for (lp = ip->client->offered_leases; lp->next;
802 			    lp = lp->next)
803 				;	/* nothing */
804 			lp->next = lease;
805 		}
806 	}
807 
808 	/* If we're supposed to stop selecting before we've had time
809 	   to wait for the ARPREPLY, add some delay to wait for
810 	   the ARPREPLY. */
811 	if (stop_selecting - cur_time < arp_timeout_needed)
812 		stop_selecting = cur_time + arp_timeout_needed;
813 
814 	/* If the selecting interval has expired, go immediately to
815 	   state_selecting().  Otherwise, time out into
816 	   state_selecting at the select interval. */
817 	if (stop_selecting <= 0)
818 		state_selecting(ip);
819 	else {
820 		add_timeout(stop_selecting, state_selecting, ip);
821 		cancel_timeout(send_discover, ip);
822 	}
823 }
824 
825 /* Allocate a client_lease structure and initialize it from the parameters
826    in the specified packet. */
827 
828 struct client_lease *
packet_to_lease(struct packet * packet)829 packet_to_lease(struct packet *packet)
830 {
831 	struct client_lease *lease;
832 	int i;
833 
834 	lease = malloc(sizeof(struct client_lease));
835 
836 	if (!lease) {
837 		warning("dhcpoffer: no memory to record lease.");
838 		return (NULL);
839 	}
840 
841 	memset(lease, 0, sizeof(*lease));
842 
843 	/* Copy the lease options. */
844 	for (i = 0; i < 256; i++) {
845 		if (packet->options[i].len) {
846 			lease->options[i].data =
847 			    malloc(packet->options[i].len + 1);
848 			if (!lease->options[i].data) {
849 				warning("dhcpoffer: no memory for option %d", i);
850 				free_client_lease(lease);
851 				return (NULL);
852 			} else {
853 				memcpy(lease->options[i].data,
854 				    packet->options[i].data,
855 				    packet->options[i].len);
856 				lease->options[i].len =
857 				    packet->options[i].len;
858 				lease->options[i].data[lease->options[i].len] =
859 				    0;
860 			}
861 			if (!check_option(lease,i)) {
862 				/* ignore a bogus lease offer */
863 				warning("Invalid lease option - ignoring offer");
864 				free_client_lease(lease);
865 				return (NULL);
866 			}
867 		}
868 	}
869 
870 	lease->address.len = sizeof(packet->raw->yiaddr);
871 	memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
872 #ifdef __REACTOS__
873 	lease->serveraddress.len = sizeof(packet->raw->siaddr);
874 	memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len);
875 #endif
876 
877 	/* If the server name was filled out, copy it. */
878 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
879 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
880 	    packet->raw->sname[0]) {
881 		lease->server_name = malloc(DHCP_SNAME_LEN + 1);
882 		if (!lease->server_name) {
883 			warning("dhcpoffer: no memory for server name.");
884 			free_client_lease(lease);
885 			return (NULL);
886 		}
887 		memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
888 		lease->server_name[DHCP_SNAME_LEN]='\0';
889 		if (!res_hnok(lease->server_name) ) {
890 			warning("Bogus server name %s",  lease->server_name );
891 			free_client_lease(lease);
892 			return (NULL);
893 		}
894 
895 	}
896 
897 	/* Ditto for the filename. */
898 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
899 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
900 	    packet->raw->file[0]) {
901 		/* Don't count on the NUL terminator. */
902 		lease->filename = malloc(DHCP_FILE_LEN + 1);
903 		if (!lease->filename) {
904 			warning("dhcpoffer: no memory for filename.");
905 			free_client_lease(lease);
906 			return (NULL);
907 		}
908 		memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
909 		lease->filename[DHCP_FILE_LEN]='\0';
910 	}
911 	return lease;
912 }
913 
914 void
dhcpnak(struct packet * packet)915 dhcpnak(struct packet *packet)
916 {
917 	struct interface_info *ip = packet->interface;
918 
919 	/* If we're not receptive to an offer right now, or if the offer
920 	   has an unrecognizable transaction id, then just drop it. */
921 	if (packet->interface->client->xid != packet->raw->xid ||
922 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
923 	    (memcmp(packet->interface->hw_address.haddr,
924 	    packet->raw->chaddr, packet->raw->hlen)))
925 		return;
926 
927 	if (ip->client->state != S_REBOOTING &&
928 	    ip->client->state != S_REQUESTING &&
929 	    ip->client->state != S_RENEWING &&
930 	    ip->client->state != S_REBINDING)
931 		return;
932 
933 	note("DHCPNAK from %s", piaddr(packet->client_addr));
934 
935 	if (!ip->client->active) {
936 		note("DHCPNAK with no active lease.\n");
937 		return;
938 	}
939 
940 	free_client_lease(ip->client->active);
941 	ip->client->active = NULL;
942 
943 	/* Stop sending DHCPREQUEST packets... */
944 	cancel_timeout(send_request, ip);
945 
946 	ip->client->state = S_INIT;
947 	state_init(ip);
948 }
949 
950 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
951    one after the right interval has expired.  If we don't get an offer by
952    the time we reach the panic interval, call the panic function. */
953 
954 void
send_discover(void * ipp)955 send_discover(void *ipp)
956 {
957 	struct interface_info *ip = ipp;
958 	int interval, increase = 1;
959         time_t cur_time;
960 
961         DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip));
962 
963         time(&cur_time);
964 
965 	/* Figure out how long it's been since we started transmitting. */
966 	interval = cur_time - ip->client->first_sending;
967 
968 	/* If we're past the panic timeout, call the script and tell it
969 	   we haven't found anything for this interface yet. */
970 	if (interval > ip->client->config->timeout) {
971 		state_panic(ip);
972         ip->client->first_sending = cur_time;
973 	}
974 
975 	/* If we're selecting media, try the whole list before doing
976 	   the exponential backoff, but if we've already received an
977 	   offer, stop looping, because we obviously have it right. */
978 	if (!ip->client->offered_leases &&
979 	    ip->client->config->media) {
980 		int fail = 0;
981 
982 		if (ip->client->medium) {
983 			ip->client->medium = ip->client->medium->next;
984 			increase = 0;
985 		}
986 		if (!ip->client->medium) {
987 			if (fail)
988 				error("No valid media types for %s!", ip->name);
989 			ip->client->medium = ip->client->config->media;
990 			increase = 1;
991 		}
992 
993 		note("Trying medium \"%s\" %d", ip->client->medium->string,
994 		    increase);
995                 /* XXX Support other media types eventually */
996 	}
997 
998 	/*
999 	 * If we're supposed to increase the interval, do so.  If it's
1000 	 * currently zero (i.e., we haven't sent any packets yet), set
1001 	 * it to one; otherwise, add to it a random number between zero
1002 	 * and two times itself.  On average, this means that it will
1003 	 * double with every transmission.
1004 	 */
1005 	if (increase) {
1006 		if (!ip->client->interval)
1007 			ip->client->interval =
1008 			    ip->client->config->initial_interval;
1009 		else {
1010 			ip->client->interval += (rand() >> 2) %
1011 			    (2 * ip->client->interval);
1012 		}
1013 
1014 		/* Don't backoff past cutoff. */
1015 		if (ip->client->interval >
1016 		    ip->client->config->backoff_cutoff)
1017 			ip->client->interval =
1018 				((ip->client->config->backoff_cutoff / 2)
1019 				 + ((rand() >> 2) %
1020 				    ip->client->config->backoff_cutoff));
1021 	} else if (!ip->client->interval)
1022 		ip->client->interval =
1023 			ip->client->config->initial_interval;
1024 
1025 	/* If the backoff would take us to the panic timeout, just use that
1026 	   as the interval. */
1027 	if (cur_time + ip->client->interval >
1028 	    ip->client->first_sending + ip->client->config->timeout)
1029 		ip->client->interval =
1030 			(ip->client->first_sending +
1031 			 ip->client->config->timeout) - cur_time + 1;
1032 
1033 	/* Record the number of seconds since we started sending. */
1034 	if (interval < 65536)
1035 		ip->client->packet.secs = htons(interval);
1036 	else
1037 		ip->client->packet.secs = htons(65535);
1038 	ip->client->secs = ip->client->packet.secs;
1039 
1040 	note("DHCPDISCOVER on %s to %s port %d interval %ld",
1041 	    ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1042 	    ntohs(sockaddr_broadcast.sin_port), (long int)ip->client->interval);
1043 
1044 	/* Send out a packet. */
1045 	(void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1046 	    inaddr_any, &sockaddr_broadcast, NULL);
1047 
1048         DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n",
1049                                cur_time, cur_time + ip->client->interval));
1050 
1051 	add_timeout(cur_time + ip->client->interval, send_discover, ip);
1052 }
1053 
1054 /*
1055  * state_panic gets called if we haven't received any offers in a preset
1056  * amount of time.   When this happens, we try to use existing leases
1057  * that haven't yet expired, and failing that, we call the client script
1058  * and hope it can do something.
1059  */
1060 void
state_panic(void * ipp)1061 state_panic(void *ipp)
1062 {
1063 	struct interface_info *ip = ipp;
1064 	uint16_t address_low;
1065 	int i;
1066     IPAddr IpAddress;
1067     ULONG Buffer[20];
1068     ULONG BufferSize;
1069     DWORD ret;
1070     PDHCP_ADAPTER Adapter = AdapterFindInfo(ip);
1071 
1072 	note("No DHCPOFFERS received.");
1073 
1074     if (!Adapter->NteContext)
1075     {
1076         /* Generate an automatic private address */
1077         DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
1078 
1079         /* FIXME: The address generation code sucks */
1080         srand(0);
1081 
1082         for (;;)
1083         {
1084             address_low = rand();
1085             for (i = 0; i < ip->hw_address.hlen; i++)
1086                 address_low += ip->hw_address.haddr[i];
1087 
1088             IpAddress = htonl(0xA9FE0000 | address_low);  // 169.254.X.X
1089 
1090             /* Send an ARP request to check if the IP address is already in use */
1091             BufferSize = sizeof(Buffer);
1092             ret = SendARP(IpAddress,
1093                           IpAddress,
1094                           Buffer,
1095                           &BufferSize);
1096             DH_DbgPrint(MID_TRACE,("DHCPCSVC: SendARP returned %lu\n", ret));
1097             if (ret != 0)
1098             {
1099                 /* The IP address is not in use */
1100                 DH_DbgPrint(MID_TRACE,("DHCPCSVC: Using automatic private address\n"));
1101                 AddIPAddress(IpAddress,
1102                              htonl(0xFFFF0000), // 255.255.0.0
1103                              Adapter->IfMib.dwIndex,
1104                              &Adapter->NteContext,
1105                              &Adapter->NteInstance);
1106                 return;
1107             }
1108         }
1109     }
1110 }
1111 
1112 void
send_request(void * ipp)1113 send_request(void *ipp)
1114 {
1115 	struct interface_info *ip = ipp;
1116 	struct sockaddr_in destination;
1117 	struct in_addr from;
1118 	int interval;
1119         time_t cur_time;
1120 
1121         time(&cur_time);
1122 
1123 	/* Figure out how long it's been since we started transmitting. */
1124 	interval = cur_time - ip->client->first_sending;
1125 
1126 	/* If we're in the INIT-REBOOT or REQUESTING state and we're
1127 	   past the reboot timeout, go to INIT and see if we can
1128 	   DISCOVER an address... */
1129 	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1130 	   means either that we're on a network with no DHCP server,
1131 	   or that our server is down.  In the latter case, assuming
1132 	   that there is a backup DHCP server, DHCPDISCOVER will get
1133 	   us a new address, but we could also have successfully
1134 	   reused our old address.  In the former case, we're hosed
1135 	   anyway.  This is not a win-prone situation. */
1136 	if ((ip->client->state == S_REBOOTING ||
1137 	    ip->client->state == S_REQUESTING) &&
1138 	    interval > ip->client->config->reboot_timeout) {
1139 		ip->client->state = S_INIT;
1140 		cancel_timeout(send_request, ip);
1141 		state_init(ip);
1142 		return;
1143 	}
1144 
1145 	/* If we're in the reboot state, make sure the media is set up
1146 	   correctly. */
1147 	if (ip->client->state == S_REBOOTING &&
1148 	    !ip->client->medium &&
1149 	    ip->client->active->medium ) {
1150 		/* If the medium we chose won't fly, go to INIT state. */
1151                 /* XXX Nothing for now */
1152 
1153 		/* Record the medium. */
1154 		ip->client->medium = ip->client->active->medium;
1155 	}
1156 
1157 	/* If the lease has expired, relinquish the address and go back
1158 	   to the INIT state. */
1159 	if (ip->client->state != S_REQUESTING &&
1160 	    cur_time > ip->client->active->expiry) {
1161             PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
1162             /* Run the client script with the new parameters. */
1163             /* No script actions necessary in the expiry case */
1164             /* Now do a preinit on the interface so that we can
1165                discover a new address. */
1166 
1167             if( Adapter )
1168             {
1169                 DeleteIPAddress( Adapter->NteContext );
1170                 Adapter->NteContext = 0;
1171             }
1172 
1173             ip->client->state = S_INIT;
1174             state_init(ip);
1175             return;
1176 	}
1177 
1178 	/* Do the exponential backoff... */
1179 	if (!ip->client->interval)
1180 		ip->client->interval = ip->client->config->initial_interval;
1181 	else
1182 		ip->client->interval += ((rand() >> 2) %
1183 		    (2 * ip->client->interval));
1184 
1185 	/* Don't backoff past cutoff. */
1186 	if (ip->client->interval >
1187 	    ip->client->config->backoff_cutoff)
1188 		ip->client->interval =
1189 		    ((ip->client->config->backoff_cutoff / 2) +
1190 		    ((rand() >> 2) % ip->client->interval));
1191 
1192 	/* If the backoff would take us to the expiry time, just set the
1193 	   timeout to the expiry time. */
1194 	if (ip->client->state != S_REQUESTING &&
1195 	    cur_time + ip->client->interval >
1196 	    ip->client->active->expiry)
1197 		ip->client->interval =
1198 		    ip->client->active->expiry - cur_time + 1;
1199 
1200 	/* If the lease T2 time has elapsed, or if we're not yet bound,
1201 	   broadcast the DHCPREQUEST rather than unicasting. */
1202 	memset(&destination, 0, sizeof(destination));
1203 	if (ip->client->state == S_REQUESTING ||
1204 	    ip->client->state == S_REBOOTING ||
1205 	    cur_time > ip->client->active->rebind)
1206 		destination.sin_addr.s_addr = INADDR_BROADCAST;
1207 	else
1208 		memcpy(&destination.sin_addr.s_addr,
1209 		    ip->client->destination.iabuf,
1210 		    sizeof(destination.sin_addr.s_addr));
1211 	destination.sin_port = htons(REMOTE_PORT);
1212 	destination.sin_family = AF_INET;
1213 //	destination.sin_len = sizeof(destination);
1214 
1215 	if (ip->client->state != S_REQUESTING)
1216 		memcpy(&from, ip->client->active->address.iabuf,
1217 		    sizeof(from));
1218 	else
1219 		from.s_addr = INADDR_ANY;
1220 
1221 	/* Record the number of seconds since we started sending. */
1222 	if (ip->client->state == S_REQUESTING)
1223 		ip->client->packet.secs = ip->client->secs;
1224 	else {
1225 		if (interval < 65536)
1226 			ip->client->packet.secs = htons(interval);
1227 		else
1228 			ip->client->packet.secs = htons(65535);
1229 	}
1230 
1231 	note("DHCPREQUEST on %s to %s port %d", ip->name,
1232 	    inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1233 
1234 	/* Send out a packet. */
1235 	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1236 	    from, &destination, NULL);
1237 
1238 	add_timeout(cur_time + ip->client->interval, send_request, ip);
1239 }
1240 
1241 void
send_decline(void * ipp)1242 send_decline(void *ipp)
1243 {
1244 	struct interface_info *ip = ipp;
1245 
1246 	note("DHCPDECLINE on %s to %s port %d", ip->name,
1247 	    inet_ntoa(sockaddr_broadcast.sin_addr),
1248 	    ntohs(sockaddr_broadcast.sin_port));
1249 
1250 	/* Send out a packet. */
1251 	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1252 	    inaddr_any, &sockaddr_broadcast, NULL);
1253 }
1254 
1255 void
make_discover(struct interface_info * ip,struct client_lease * lease)1256 make_discover(struct interface_info *ip, struct client_lease *lease)
1257 {
1258 	unsigned char discover = DHCPDISCOVER;
1259 	struct tree_cache *options[256];
1260 	struct tree_cache option_elements[256];
1261 	int i;
1262 	ULONG foo = (ULONG) GetTickCount();
1263 
1264 	memset(option_elements, 0, sizeof(option_elements));
1265 	memset(options, 0, sizeof(options));
1266 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1267 
1268 	/* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1269 	i = DHO_DHCP_MESSAGE_TYPE;
1270 	options[i] = &option_elements[i];
1271 	options[i]->value = &discover;
1272 	options[i]->len = sizeof(discover);
1273 	options[i]->buf_size = sizeof(discover);
1274 	options[i]->timeout = 0xFFFFFFFF;
1275 
1276 	/* Request the options we want */
1277 	i  = DHO_DHCP_PARAMETER_REQUEST_LIST;
1278 	options[i] = &option_elements[i];
1279 	options[i]->value = ip->client->config->requested_options;
1280 	options[i]->len = ip->client->config->requested_option_count;
1281 	options[i]->buf_size =
1282 		ip->client->config->requested_option_count;
1283 	options[i]->timeout = 0xFFFFFFFF;
1284 
1285 	/* If we had an address, try to get it again. */
1286 	if (lease) {
1287 		ip->client->requested_address = lease->address;
1288 		i = DHO_DHCP_REQUESTED_ADDRESS;
1289 		options[i] = &option_elements[i];
1290 		options[i]->value = lease->address.iabuf;
1291 		options[i]->len = lease->address.len;
1292 		options[i]->buf_size = lease->address.len;
1293 		options[i]->timeout = 0xFFFFFFFF;
1294 	} else
1295 		ip->client->requested_address.len = 0;
1296 
1297 	/* Send any options requested in the config file. */
1298 	for (i = 0; i < 256; i++)
1299 		if (!options[i] &&
1300 		    ip->client->config->send_options[i].data) {
1301 			options[i] = &option_elements[i];
1302 			options[i]->value =
1303 			    ip->client->config->send_options[i].data;
1304 			options[i]->len =
1305 			    ip->client->config->send_options[i].len;
1306 			options[i]->buf_size =
1307 			    ip->client->config->send_options[i].len;
1308 			options[i]->timeout = 0xFFFFFFFF;
1309 		}
1310 
1311 	/* Set up the option buffer... */
1312 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1313 	    options);
1314 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1315 		ip->client->packet_length = BOOTP_MIN_LEN;
1316 
1317 	ip->client->packet.op = BOOTREQUEST;
1318 	ip->client->packet.htype = ip->hw_address.htype;
1319 	ip->client->packet.hlen = ip->hw_address.hlen;
1320 	ip->client->packet.hops = 0;
1321 	ip->client->packet.xid = RtlRandom(&foo);
1322 	ip->client->packet.secs = 0; /* filled in by send_discover. */
1323 	ip->client->packet.flags = 0;
1324 
1325 	memset(&(ip->client->packet.ciaddr),
1326 	    0, sizeof(ip->client->packet.ciaddr));
1327 	memset(&(ip->client->packet.yiaddr),
1328 	    0, sizeof(ip->client->packet.yiaddr));
1329 	memset(&(ip->client->packet.siaddr),
1330 	    0, sizeof(ip->client->packet.siaddr));
1331 	memset(&(ip->client->packet.giaddr),
1332 	    0, sizeof(ip->client->packet.giaddr));
1333 	memcpy(ip->client->packet.chaddr,
1334 	    ip->hw_address.haddr, ip->hw_address.hlen);
1335 }
1336 
1337 
1338 void
make_request(struct interface_info * ip,struct client_lease * lease)1339 make_request(struct interface_info *ip, struct client_lease * lease)
1340 {
1341 	unsigned char request = DHCPREQUEST;
1342 	struct tree_cache *options[256];
1343 	struct tree_cache option_elements[256];
1344 	int i;
1345 
1346 	memset(options, 0, sizeof(options));
1347 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1348 
1349 	/* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1350 	i = DHO_DHCP_MESSAGE_TYPE;
1351 	options[i] = &option_elements[i];
1352 	options[i]->value = &request;
1353 	options[i]->len = sizeof(request);
1354 	options[i]->buf_size = sizeof(request);
1355 	options[i]->timeout = 0xFFFFFFFF;
1356 
1357 	/* Request the options we want */
1358 	i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1359 	options[i] = &option_elements[i];
1360 	options[i]->value = ip->client->config->requested_options;
1361 	options[i]->len = ip->client->config->requested_option_count;
1362 	options[i]->buf_size =
1363 		ip->client->config->requested_option_count;
1364 	options[i]->timeout = 0xFFFFFFFF;
1365 
1366 	/* If we are requesting an address that hasn't yet been assigned
1367 	   to us, use the DHCP Requested Address option. */
1368 	if (ip->client->state == S_REQUESTING) {
1369 		/* Send back the server identifier... */
1370 		i = DHO_DHCP_SERVER_IDENTIFIER;
1371 		options[i] = &option_elements[i];
1372 		options[i]->value = lease->options[i].data;
1373 		options[i]->len = lease->options[i].len;
1374 		options[i]->buf_size = lease->options[i].len;
1375 		options[i]->timeout = 0xFFFFFFFF;
1376 	}
1377 	if (ip->client->state == S_REQUESTING ||
1378 	    ip->client->state == S_REBOOTING) {
1379 		ip->client->requested_address = lease->address;
1380 		i = DHO_DHCP_REQUESTED_ADDRESS;
1381 		options[i] = &option_elements[i];
1382 		options[i]->value = lease->address.iabuf;
1383 		options[i]->len = lease->address.len;
1384 		options[i]->buf_size = lease->address.len;
1385 		options[i]->timeout = 0xFFFFFFFF;
1386 	} else
1387 		ip->client->requested_address.len = 0;
1388 
1389 	/* Send any options requested in the config file. */
1390 	for (i = 0; i < 256; i++)
1391 		if (!options[i] &&
1392 		    ip->client->config->send_options[i].data) {
1393 			options[i] = &option_elements[i];
1394 			options[i]->value =
1395 			    ip->client->config->send_options[i].data;
1396 			options[i]->len =
1397 			    ip->client->config->send_options[i].len;
1398 			options[i]->buf_size =
1399 			    ip->client->config->send_options[i].len;
1400 			options[i]->timeout = 0xFFFFFFFF;
1401 		}
1402 
1403 	/* Set up the option buffer... */
1404 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1405 	    options);
1406 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1407 		ip->client->packet_length = BOOTP_MIN_LEN;
1408 
1409 	ip->client->packet.op = BOOTREQUEST;
1410 	ip->client->packet.htype = ip->hw_address.htype;
1411 	ip->client->packet.hlen = ip->hw_address.hlen;
1412 	ip->client->packet.hops = 0;
1413 	ip->client->packet.xid = ip->client->xid;
1414 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1415 
1416 	/* If we own the address we're requesting, put it in ciaddr;
1417 	   otherwise set ciaddr to zero. */
1418 	if (ip->client->state == S_BOUND ||
1419 	    ip->client->state == S_RENEWING ||
1420 	    ip->client->state == S_REBINDING) {
1421 		memcpy(&ip->client->packet.ciaddr,
1422 		    lease->address.iabuf, lease->address.len);
1423 		ip->client->packet.flags = 0;
1424 	} else {
1425 		memset(&ip->client->packet.ciaddr, 0,
1426 		    sizeof(ip->client->packet.ciaddr));
1427 		ip->client->packet.flags = 0;
1428 	}
1429 
1430 	memset(&ip->client->packet.yiaddr, 0,
1431 	    sizeof(ip->client->packet.yiaddr));
1432 	memset(&ip->client->packet.siaddr, 0,
1433 	    sizeof(ip->client->packet.siaddr));
1434 	memset(&ip->client->packet.giaddr, 0,
1435 	    sizeof(ip->client->packet.giaddr));
1436 	memcpy(ip->client->packet.chaddr,
1437 	    ip->hw_address.haddr, ip->hw_address.hlen);
1438 }
1439 
1440 void
make_decline(struct interface_info * ip,struct client_lease * lease)1441 make_decline(struct interface_info *ip, struct client_lease *lease)
1442 {
1443 	struct tree_cache *options[256], message_type_tree;
1444 	struct tree_cache requested_address_tree;
1445 	struct tree_cache server_id_tree, client_id_tree;
1446 	unsigned char decline = DHCPDECLINE;
1447 	int i;
1448 
1449 	memset(options, 0, sizeof(options));
1450 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1451 
1452 	/* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1453 	i = DHO_DHCP_MESSAGE_TYPE;
1454 	options[i] = &message_type_tree;
1455 	options[i]->value = &decline;
1456 	options[i]->len = sizeof(decline);
1457 	options[i]->buf_size = sizeof(decline);
1458 	options[i]->timeout = 0xFFFFFFFF;
1459 
1460 	/* Send back the server identifier... */
1461 	i = DHO_DHCP_SERVER_IDENTIFIER;
1462 	options[i] = &server_id_tree;
1463 	options[i]->value = lease->options[i].data;
1464 	options[i]->len = lease->options[i].len;
1465 	options[i]->buf_size = lease->options[i].len;
1466 	options[i]->timeout = 0xFFFFFFFF;
1467 
1468 	/* Send back the address we're declining. */
1469 	i = DHO_DHCP_REQUESTED_ADDRESS;
1470 	options[i] = &requested_address_tree;
1471 	options[i]->value = lease->address.iabuf;
1472 	options[i]->len = lease->address.len;
1473 	options[i]->buf_size = lease->address.len;
1474 	options[i]->timeout = 0xFFFFFFFF;
1475 
1476 	/* Send the uid if the user supplied one. */
1477 	i = DHO_DHCP_CLIENT_IDENTIFIER;
1478 	if (ip->client->config->send_options[i].len) {
1479 		options[i] = &client_id_tree;
1480 		options[i]->value = ip->client->config->send_options[i].data;
1481 		options[i]->len = ip->client->config->send_options[i].len;
1482 		options[i]->buf_size = ip->client->config->send_options[i].len;
1483 		options[i]->timeout = 0xFFFFFFFF;
1484 	}
1485 
1486 
1487 	/* Set up the option buffer... */
1488 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1489 	    options);
1490 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1491 		ip->client->packet_length = BOOTP_MIN_LEN;
1492 
1493 	ip->client->packet.op = BOOTREQUEST;
1494 	ip->client->packet.htype = ip->hw_address.htype;
1495 	ip->client->packet.hlen = ip->hw_address.hlen;
1496 	ip->client->packet.hops = 0;
1497 	ip->client->packet.xid = ip->client->xid;
1498 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1499 	ip->client->packet.flags = 0;
1500 
1501 	/* ciaddr must always be zero. */
1502 	memset(&ip->client->packet.ciaddr, 0,
1503 	    sizeof(ip->client->packet.ciaddr));
1504 	memset(&ip->client->packet.yiaddr, 0,
1505 	    sizeof(ip->client->packet.yiaddr));
1506 	memset(&ip->client->packet.siaddr, 0,
1507 	    sizeof(ip->client->packet.siaddr));
1508 	memset(&ip->client->packet.giaddr, 0,
1509 	    sizeof(ip->client->packet.giaddr));
1510 	memcpy(ip->client->packet.chaddr,
1511 	    ip->hw_address.haddr, ip->hw_address.hlen);
1512 }
1513 
1514 void
free_client_lease(struct client_lease * lease)1515 free_client_lease(struct client_lease *lease)
1516 {
1517 	int i;
1518 
1519 	if (lease->server_name)
1520 		free(lease->server_name);
1521 	if (lease->filename)
1522 		free(lease->filename);
1523 	for (i = 0; i < 256; i++) {
1524 		if (lease->options[i].len)
1525 			free(lease->options[i].data);
1526 	}
1527 	free(lease);
1528 }
1529 
1530 FILE *leaseFile;
1531 
1532 void
rewrite_client_leases(struct interface_info * ifi)1533 rewrite_client_leases(struct interface_info *ifi)
1534 {
1535 	struct client_lease *lp;
1536 
1537 	if (!leaseFile) {
1538 		leaseFile = fopen(path_dhclient_db, "w");
1539 		if (!leaseFile)
1540 			error("can't create %s", path_dhclient_db);
1541 	} else {
1542 		fflush(leaseFile);
1543 		rewind(leaseFile);
1544 	}
1545 
1546 	for (lp = ifi->client->leases; lp; lp = lp->next)
1547 		write_client_lease(ifi, lp, 1);
1548 	if (ifi->client->active)
1549 		write_client_lease(ifi, ifi->client->active, 1);
1550 
1551 	fflush(leaseFile);
1552 }
1553 
1554 void
write_client_lease(struct interface_info * ip,struct client_lease * lease,int rewrite)1555 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1556     int rewrite)
1557 {
1558 	static int leases_written;
1559 	struct tm *t;
1560 	int i;
1561 
1562 	if (!rewrite) {
1563 		if (leases_written++ > 20) {
1564 			rewrite_client_leases(ip);
1565 			leases_written = 0;
1566 		}
1567 	}
1568 
1569 	/* If the lease came from the config file, we don't need to stash
1570 	   a copy in the lease database. */
1571 	if (lease->is_static)
1572 		return;
1573 
1574 	if (!leaseFile) {	/* XXX */
1575 		leaseFile = fopen(path_dhclient_db, "w");
1576 		if (!leaseFile) {
1577 			error("can't create %s", path_dhclient_db);
1578                         return;
1579                 }
1580 	}
1581 
1582 	fprintf(leaseFile, "lease {\n");
1583 	if (lease->is_bootp)
1584 		fprintf(leaseFile, "  bootp;\n");
1585 	fprintf(leaseFile, "  interface \"%s\";\n", ip->name);
1586 	fprintf(leaseFile, "  fixed-address %s;\n", piaddr(lease->address));
1587 	if (lease->filename)
1588 		fprintf(leaseFile, "  filename \"%s\";\n", lease->filename);
1589 	if (lease->server_name)
1590 		fprintf(leaseFile, "  server-name \"%s\";\n",
1591 		    lease->server_name);
1592 	if (lease->medium)
1593 		fprintf(leaseFile, "  medium \"%s\";\n", lease->medium->string);
1594 	for (i = 0; i < 256; i++)
1595 		if (lease->options[i].len)
1596 			fprintf(leaseFile, "  option %s %s;\n",
1597 			    dhcp_options[i].name,
1598 			    pretty_print_option(i, lease->options[i].data,
1599 			    lease->options[i].len, 1, 1));
1600 
1601 	t = gmtime(&lease->renewal);
1602         if (t)
1603 	    fprintf(leaseFile, "  renew %d %d/%d/%d %02d:%02d:%02d;\n",
1604 	        t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1605 	        t->tm_hour, t->tm_min, t->tm_sec);
1606 	t = gmtime(&lease->rebind);
1607         if (t)
1608 	    fprintf(leaseFile, "  rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1609 	         t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1610 	         t->tm_hour, t->tm_min, t->tm_sec);
1611 	t = gmtime(&lease->expiry);
1612         if (t)
1613 	    fprintf(leaseFile, "  expire %d %d/%d/%d %02d:%02d:%02d;\n",
1614 	        t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1615 	        t->tm_hour, t->tm_min, t->tm_sec);
1616 	fprintf(leaseFile, "}\n");
1617 	fflush(leaseFile);
1618 }
1619 
1620 void
priv_script_init(struct interface_info * ip,char * reason,char * medium)1621 priv_script_init(struct interface_info *ip, char *reason, char *medium)
1622 {
1623 	if (ip) {
1624             // XXX Do we need to do anything?
1625         }
1626 }
1627 
1628 void
priv_script_write_params(struct interface_info * ip,char * prefix,struct client_lease * lease)1629 priv_script_write_params(struct interface_info *ip, char *prefix, struct client_lease *lease)
1630 {
1631 	u_int8_t dbuf[1500];
1632 	int i, len = 0;
1633 
1634 #if 0
1635 	script_set_env(ip->client, prefix, "ip_address",
1636 	    piaddr(lease->address));
1637 #endif
1638 
1639 	if (lease->options[DHO_SUBNET_MASK].len &&
1640 	    (lease->options[DHO_SUBNET_MASK].len <
1641 	    sizeof(lease->address.iabuf))) {
1642 		struct iaddr netmask, subnet, broadcast;
1643 
1644 		memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data,
1645 		    lease->options[DHO_SUBNET_MASK].len);
1646 		netmask.len = lease->options[DHO_SUBNET_MASK].len;
1647 
1648 		subnet = subnet_number(lease->address, netmask);
1649 		if (subnet.len) {
1650 #if 0
1651 			script_set_env(ip->client, prefix, "network_number",
1652 			    piaddr(subnet));
1653 #endif
1654 			if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1655 				broadcast = broadcast_addr(subnet, netmask);
1656 				if (broadcast.len)
1657 #if 0
1658 					script_set_env(ip->client, prefix,
1659 					    "broadcast_address",
1660 					    piaddr(broadcast));
1661 #else
1662                                 ;
1663 #endif
1664 			}
1665 		}
1666 	}
1667 
1668 #if 0
1669 	if (lease->filename)
1670 		script_set_env(ip->client, prefix, "filename", lease->filename);
1671 	if (lease->server_name)
1672 		script_set_env(ip->client, prefix, "server_name",
1673 		    lease->server_name);
1674 #endif
1675 
1676 	for (i = 0; i < 256; i++) {
1677 		u_int8_t *dp = NULL;
1678 
1679 		if (ip->client->config->defaults[i].len) {
1680 			if (lease->options[i].len) {
1681 				switch (
1682 				    ip->client->config->default_actions[i]) {
1683 				case ACTION_DEFAULT:
1684 					dp = lease->options[i].data;
1685 					len = lease->options[i].len;
1686 					break;
1687 				case ACTION_SUPERSEDE:
1688 supersede:
1689 					dp = ip->client->
1690 						config->defaults[i].data;
1691 					len = ip->client->
1692 						config->defaults[i].len;
1693 					break;
1694 				case ACTION_PREPEND:
1695 					len = ip->client->
1696 					    config->defaults[i].len +
1697 					    lease->options[i].len;
1698 					if (len >= sizeof(dbuf)) {
1699 						warning("no space to %s %s",
1700 						    "prepend option",
1701 						    dhcp_options[i].name);
1702 						goto supersede;
1703 					}
1704 					dp = dbuf;
1705 					memcpy(dp,
1706 						ip->client->
1707 						config->defaults[i].data,
1708 						ip->client->
1709 						config->defaults[i].len);
1710 					memcpy(dp + ip->client->
1711 						config->defaults[i].len,
1712 						lease->options[i].data,
1713 						lease->options[i].len);
1714 					dp[len] = '\0';
1715 					break;
1716 				case ACTION_APPEND:
1717 					len = ip->client->
1718 					    config->defaults[i].len +
1719 					    lease->options[i].len + 1;
1720 					if (len > sizeof(dbuf)) {
1721 						warning("no space to %s %s",
1722 						    "append option",
1723 						    dhcp_options[i].name);
1724 						goto supersede;
1725 					}
1726 					dp = dbuf;
1727 					memcpy(dp,
1728 						lease->options[i].data,
1729 						lease->options[i].len);
1730 					memcpy(dp + lease->options[i].len,
1731 						ip->client->
1732 						config->defaults[i].data,
1733 						ip->client->
1734 						config->defaults[i].len);
1735 					dp[len-1] = '\0';
1736 				}
1737 			} else {
1738 				dp = ip->client->
1739 					config->defaults[i].data;
1740 				len = ip->client->
1741 					config->defaults[i].len;
1742 			}
1743 		} else if (lease->options[i].len) {
1744 			len = lease->options[i].len;
1745 			dp = lease->options[i].data;
1746 		} else {
1747 			len = 0;
1748 		}
1749 #if 0
1750 		if (len) {
1751 			char name[256];
1752 
1753 			if (dhcp_option_ev_name(name, sizeof(name),
1754 			    &dhcp_options[i]))
1755 				script_set_env(ip->client, prefix, name,
1756 				    pretty_print_option(i, dp, len, 0, 0));
1757 		}
1758 #endif
1759 	}
1760 #if 0
1761 	snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
1762 	script_set_env(ip->client, prefix, "expiry", tbuf);
1763 #endif
1764 }
1765 
1766 int
dhcp_option_ev_name(char * buf,size_t buflen,struct dhcp_option * option)1767 dhcp_option_ev_name(char *buf, size_t buflen, struct dhcp_option *option)
1768 {
1769 	int i;
1770 
1771 	for (i = 0; option->name[i]; i++) {
1772 		if (i + 1 == buflen)
1773 			return 0;
1774 		if (option->name[i] == '-')
1775 			buf[i] = '_';
1776 		else
1777 			buf[i] = option->name[i];
1778 	}
1779 
1780 	buf[i] = 0;
1781 	return 1;
1782 }
1783 
1784 #if 0
1785 void
1786 go_daemon(void)
1787 {
1788 	static int state = 0;
1789 
1790 	if (no_daemon || state)
1791 		return;
1792 
1793 	state = 1;
1794 
1795 	/* Stop logging to stderr... */
1796 	log_perror = 0;
1797 
1798 	if (daemon(1, 0) == -1)
1799 		error("daemon");
1800 
1801 	/* we are chrooted, daemon(3) fails to open /dev/null */
1802 	if (nullfd != -1) {
1803 		dup2(nullfd, STDIN_FILENO);
1804 		dup2(nullfd, STDOUT_FILENO);
1805 		dup2(nullfd, STDERR_FILENO);
1806 		close(nullfd);
1807 		nullfd = -1;
1808 	}
1809 }
1810 #endif
1811 
1812 int
check_option(struct client_lease * l,int option)1813 check_option(struct client_lease *l, int option)
1814 {
1815 	char *opbuf;
1816 	char *sbuf;
1817 
1818 	/* we use this, since this is what gets passed to dhclient-script */
1819 
1820 	opbuf = pretty_print_option(option, l->options[option].data,
1821 	    l->options[option].len, 0, 0);
1822 
1823 	sbuf = option_as_string(option, l->options[option].data,
1824 	    l->options[option].len);
1825 
1826 	switch (option) {
1827 	case DHO_SUBNET_MASK:
1828 	case DHO_TIME_SERVERS:
1829 	case DHO_NAME_SERVERS:
1830 	case DHO_ROUTERS:
1831 	case DHO_DOMAIN_NAME_SERVERS:
1832 	case DHO_LOG_SERVERS:
1833 	case DHO_COOKIE_SERVERS:
1834 	case DHO_LPR_SERVERS:
1835 	case DHO_IMPRESS_SERVERS:
1836 	case DHO_RESOURCE_LOCATION_SERVERS:
1837 	case DHO_SWAP_SERVER:
1838 	case DHO_BROADCAST_ADDRESS:
1839 	case DHO_NIS_SERVERS:
1840 	case DHO_NTP_SERVERS:
1841 	case DHO_NETBIOS_NAME_SERVERS:
1842 	case DHO_NETBIOS_DD_SERVER:
1843 	case DHO_FONT_SERVERS:
1844 	case DHO_DHCP_SERVER_IDENTIFIER:
1845 		if (!ipv4addrs(opbuf)) {
1846                         warning("Invalid IP address in option(%d): %s", option, opbuf);
1847 			return (0);
1848 		}
1849 		return (1)  ;
1850 	case DHO_HOST_NAME:
1851 	case DHO_DOMAIN_NAME:
1852 	case DHO_NIS_DOMAIN:
1853 		if (!res_hnok(sbuf))
1854 			warning("Bogus Host Name option %d: %s (%s)", option,
1855 			    sbuf, opbuf);
1856 		return (1);
1857 	case DHO_PAD:
1858 	case DHO_TIME_OFFSET:
1859 	case DHO_BOOT_SIZE:
1860 	case DHO_MERIT_DUMP:
1861 	case DHO_ROOT_PATH:
1862 	case DHO_EXTENSIONS_PATH:
1863 	case DHO_IP_FORWARDING:
1864 	case DHO_NON_LOCAL_SOURCE_ROUTING:
1865 	case DHO_POLICY_FILTER:
1866 	case DHO_MAX_DGRAM_REASSEMBLY:
1867 	case DHO_DEFAULT_IP_TTL:
1868 	case DHO_PATH_MTU_AGING_TIMEOUT:
1869 	case DHO_PATH_MTU_PLATEAU_TABLE:
1870 	case DHO_INTERFACE_MTU:
1871 	case DHO_ALL_SUBNETS_LOCAL:
1872 	case DHO_PERFORM_MASK_DISCOVERY:
1873 	case DHO_MASK_SUPPLIER:
1874 	case DHO_ROUTER_DISCOVERY:
1875 	case DHO_ROUTER_SOLICITATION_ADDRESS:
1876 	case DHO_STATIC_ROUTES:
1877 	case DHO_TRAILER_ENCAPSULATION:
1878 	case DHO_ARP_CACHE_TIMEOUT:
1879 	case DHO_IEEE802_3_ENCAPSULATION:
1880 	case DHO_DEFAULT_TCP_TTL:
1881 	case DHO_TCP_KEEPALIVE_INTERVAL:
1882 	case DHO_TCP_KEEPALIVE_GARBAGE:
1883 	case DHO_VENDOR_ENCAPSULATED_OPTIONS:
1884 	case DHO_NETBIOS_NODE_TYPE:
1885 	case DHO_NETBIOS_SCOPE:
1886 	case DHO_X_DISPLAY_MANAGER:
1887 	case DHO_DHCP_REQUESTED_ADDRESS:
1888 	case DHO_DHCP_LEASE_TIME:
1889 	case DHO_DHCP_OPTION_OVERLOAD:
1890 	case DHO_DHCP_MESSAGE_TYPE:
1891 	case DHO_DHCP_PARAMETER_REQUEST_LIST:
1892 	case DHO_DHCP_MESSAGE:
1893 	case DHO_DHCP_MAX_MESSAGE_SIZE:
1894 	case DHO_DHCP_RENEWAL_TIME:
1895 	case DHO_DHCP_REBINDING_TIME:
1896 	case DHO_DHCP_CLASS_IDENTIFIER:
1897 	case DHO_DHCP_CLIENT_IDENTIFIER:
1898 	case DHO_DHCP_USER_CLASS_ID:
1899 	case DHO_END:
1900 		return (1);
1901 	default:
1902 		warning("unknown dhcp option value 0x%x", option);
1903 		return (unknown_ok);
1904 	}
1905 }
1906 
1907 int
res_hnok(const char * dn)1908 res_hnok(const char *dn)
1909 {
1910 	int pch = PERIOD, ch = *dn++;
1911 
1912 	while (ch != '\0') {
1913 		int nch = *dn++;
1914 
1915 		if (periodchar(ch)) {
1916 			;
1917 		} else if (periodchar(pch)) {
1918 			if (!borderchar(ch))
1919 				return (0);
1920 		} else if (periodchar(nch) || nch == '\0') {
1921 			if (!borderchar(ch))
1922 				return (0);
1923 		} else {
1924 			if (!middlechar(ch))
1925 				return (0);
1926 		}
1927 		pch = ch, ch = nch;
1928 	}
1929 	return (1);
1930 }
1931 
1932 /* Does buf consist only of dotted decimal ipv4 addrs?
1933  * return how many if so,
1934  * otherwise, return 0
1935  */
1936 int
ipv4addrs(char * buf)1937 ipv4addrs(char * buf)
1938 {
1939     char *tmp;
1940     struct in_addr jnk;
1941     int i = 0;
1942 
1943     note("Input: %s", buf);
1944 
1945     do {
1946         tmp = strtok(buf, " ");
1947         note("got %s", tmp);
1948 		if( tmp && inet_aton(tmp, &jnk) ) i++;
1949         buf = NULL;
1950     } while( tmp );
1951 
1952     return (i);
1953 }
1954 
1955 
1956 char *
option_as_string(unsigned int code,unsigned char * data,int len)1957 option_as_string(unsigned int code, unsigned char *data, int len)
1958 {
1959 	static char optbuf[32768]; /* XXX */
1960 	char *op = optbuf;
1961 	int opleft = sizeof(optbuf);
1962 	unsigned char *dp = data;
1963 
1964 	if (code > 255)
1965 		error("option_as_string: bad code %d", code);
1966 
1967 	for (; dp < data + len; dp++) {
1968 		if (!isascii(*dp) || !isprint(*dp)) {
1969 			if (dp + 1 != data + len || *dp != 0) {
1970 				_snprintf(op, opleft, "\\%03o", *dp);
1971 				op += 4;
1972 				opleft -= 4;
1973 			}
1974 		} else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
1975 		    *dp == '`' || *dp == '\\') {
1976 			*op++ = '\\';
1977 			*op++ = *dp;
1978 			opleft -= 2;
1979 		} else {
1980 			*op++ = *dp;
1981 			opleft--;
1982 		}
1983 	}
1984 	if (opleft < 1)
1985 		goto toobig;
1986 	*op = 0;
1987 	return optbuf;
1988 toobig:
1989 	warning("dhcp option too large");
1990 	return "<error>";
1991 }
1992 
1993