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