1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is free software; you can redistribute it and/or modify
4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   it under the terms of the GNU General Public License as published by
5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   the Free Software Foundation; version 2 dated June, 1991, or
6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   (at your option) version 3 dated 29 June, 2007.
7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is distributed in the hope that it will be useful,
9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   but WITHOUT ANY WARRANTY; without even the implied warranty of
10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   GNU General Public License for more details.
12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   You should have received a copy of the GNU General Public License
14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/
16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include "dnsmasq.h"
18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_DHCP
20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct dhcp_lease *leases = NULL, *old_leases = NULL;
22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int dns_dirty, file_dirty, leases_left;
23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_init(time_t now)
25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned long ei;
27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct in_addr addr;
28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int clid_len, hw_len, hw_type;
30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  FILE *leasestream;
31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* These two each hold a DHCP option max size 255
33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     and get a terminating zero added */
34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  daemon->dhcp_buff = safe_malloc(256);
35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  daemon->dhcp_buff2 = safe_malloc(256);
36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  leases_left = daemon->dhcp_max;
38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (daemon->options & OPT_LEASE_RO)
40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* run "<lease_change_script> init" once to get the
42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 initial state of the database. If leasefile-ro is
43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 set without a script, we just do without any
44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 lease database. */
45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SCRIPT
46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (daemon->lease_change_command)
47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  strcpy(daemon->dhcp_buff, daemon->lease_change_command);
49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  strcat(daemon->dhcp_buff, " init");
50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  leasestream = popen(daemon->dhcp_buff, "r");
51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat          file_dirty = dns_dirty = 0;
56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat          return;
57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat        }
58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* NOTE: need a+ mode to create file if it doesn't exist */
63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!leasestream)
66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* a+ mode leaves pointer at end. */
69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      rewind(leasestream);
70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* client-id max length is 255 which is 255*2 digits + 254 colons
73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     borrow DNS packet buffer which is always larger than 1000 bytes */
74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (leasestream)
75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    while (fscanf(leasestream, "%lu %255s %16s %255s %764s",
76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  &ei, daemon->dhcp_buff2, daemon->namebuff,
77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  daemon->dhcp_buff, daemon->packet) == 5)
78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	/* For backwards compatibility, no explict MAC address type means ether. */
81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (hw_type == 0 && hw_len != 0)
82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  hw_type = ARPHRD_ETHER;
83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	addr.s_addr = inet_addr(daemon->namebuff);
85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	/* decode hex in place */
87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	clid_len = 0;
88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (strcmp(daemon->packet, "*") != 0)
89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (!(lease = lease_allocate(addr)))
92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  die (_("too many stored leases"), NULL, EC_MISC);
93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC
95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (ei != 0)
96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  lease->expires = (time_t)ei + now;
97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	else
98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  lease->expires = (time_t)0;
99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->length = ei;
100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else
101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	/* strictly time_t is opaque, but this hack should work on all sane systems,
102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	   even when sizeof(time_t) == 8 */
103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->expires = (time_t)ei;
104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (strcmp(daemon->dhcp_buff, "*") !=  0)
109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  lease_set_hostname(lease, daemon->dhcp_buff, 0);
110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	/* set these correctly: the "old" events are generated later from
112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	   the startup synthesised SIGHUP. */
113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->new = lease->changed = 0;
114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SCRIPT
117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!daemon->lease_stream)
118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      int rc = 0;
120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* shell returns 127 for "command not found", 126 for bad permissions. */
122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (WEXITSTATUS(rc) == 127)
125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    errno = ENOENT;
126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else if (WEXITSTATUS(rc) == 126)
127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    errno = EACCES;
128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (WEXITSTATUS(rc) != 0)
132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* Some leases may have expired */
140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file_dirty = 0;
141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease_prune(NULL, now);
142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  dns_dirty = 1;
143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_update_from_configs(void)
146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* changes to the config may change current leases. */
148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_config *config;
151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *name;
152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (lease = leases; lease; lease = lease->next)
154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			      lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	(config->flags & CONFIG_NAME) &&
157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease_set_hostname(lease, config->hostname, 1);
159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    else if ((name = host_from_dns(lease->addr)))
160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease_set_hostname(lease, name, 1); /* updates auth flag only */
161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void ourprintf(int *errp, char *format, ...)
164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  va_list ap;
166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  va_start(ap, format);
168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    *errp = errno;
170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  va_end(ap);
171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_update_file(time_t now)
174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  time_t next_event;
177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int i, err = 0;
178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (file_dirty != 0 && daemon->lease_stream)
180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      errno = 0;
182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      rewind(daemon->lease_stream);
183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	err = errno;
185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      for (lease = leases; lease; lease = lease->next)
187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC
189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  ourprintf(&err, "%u ", lease->length);
190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else
191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  ourprintf(&err, "%lu ", (unsigned long)lease->expires);
192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    ourprintf(&err, "%.2x-", lease->hwaddr_type);
195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  for (i = 0; i < lease->hwaddr_len; i++)
196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      ourprintf(&err, "%.2x", lease->hwaddr[i]);
198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (i != lease->hwaddr_len - 1)
199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		ourprintf(&err, ":");
200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  ourprintf(&err, " %s ", inet_ntoa(lease->addr));
203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (lease->clid && lease->clid_len != 0)
206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      for (i = 0; i < lease->clid_len - 1; i++)
208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		ourprintf(&err, "%.2x:", lease->clid[i]);
209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      ourprintf(&err, "%.2x\n", lease->clid[i]);
210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else
212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    ourprintf(&err, "*\n");
213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (fflush(daemon->lease_stream) != 0 ||
216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  fsync(fileno(daemon->lease_stream)) < 0)
217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	err = errno;
218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!err)
220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	file_dirty = 0;
221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* Set alarm for when the first lease expires + slop. */
224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (next_event = 0, lease = leases; lease; lease = lease->next)
225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (lease->expires != 0 &&
226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	(next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      next_event = lease->expires + 10;
228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (err)
230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	next_event = LEASE_RETRY + now;
233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		daemon->lease_file, strerror(err),
236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		(unsigned int)difftime(next_event, now));
237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (next_event != 0)
240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    alarm((unsigned)difftime(next_event, now));
241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_update_dns(void)
244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (daemon->port != 0 && dns_dirty)
248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      cache_unhash_dhcp();
250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      for (lease = leases; lease; lease = lease->next)
252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (lease->fqdn)
254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
255ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
256ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (!(daemon->options & OPT_DHCP_FQDN) && lease->hostname)
257ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
258ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
259ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
260ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      dns_dirty = 0;
261ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
262ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
263ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
264ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_prune(struct dhcp_lease *target, time_t now)
265ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
266ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease, *tmp, **up;
267ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
268ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (lease = leases, up = &leases; lease; lease = tmp)
269ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
270ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      tmp = lease->next;
271ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
272ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
273ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  file_dirty = 1;
274ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (lease->hostname)
275ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    dns_dirty = 1;
276ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
277ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  *up = lease->next; /* unlink */
278ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
279ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* Put on old_leases list 'till we
280ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	     can run the script */
281ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  lease->next = old_leases;
282ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  old_leases = lease;
283ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
284ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  leases_left++;
285ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
286ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
287ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	up = &lease->next;
288ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
289ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
290ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
291ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
292ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
293ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat					unsigned char *clid, int clid_len)
294ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
295ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
296ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
297ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (clid)
298ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    for (lease = leases; lease; lease = lease->next)
299ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (lease->clid && clid_len == lease->clid_len &&
300ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  memcmp(clid, lease->clid, clid_len) == 0)
301ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return lease;
302ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
303ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (lease = leases; lease; lease = lease->next)
304ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if ((!lease->clid || !clid) &&
305ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	hw_len != 0 &&
306ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->hwaddr_len == hw_len &&
307ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->hwaddr_type == hw_type &&
308ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
309ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return lease;
310ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
311ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return NULL;
312ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
313ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
314ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_lease *lease_find_by_addr(struct in_addr addr)
315ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
316ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
317ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
318ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (lease = leases; lease; lease = lease->next)
319ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (lease->addr.s_addr == addr.s_addr)
320ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return lease;
321ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
322ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return NULL;
323ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
324ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
325ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
326ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_lease *lease_allocate(struct in_addr addr)
327ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
328ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
329ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
330ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return NULL;
331ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
332ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  memset(lease, 0, sizeof(struct dhcp_lease));
333ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->new = 1;
334ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->addr = addr;
335ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->hwaddr_len = 256; /* illegal value */
336ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->expires = 1;
337ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC
338ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->length = 0xffffffff; /* illegal value */
339ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
340ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->next = leases;
341ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  leases = lease;
342ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
343ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file_dirty = 1;
344ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  leases_left--;
345ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
346ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return lease;
347ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
348ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
349ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
350ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
351ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  time_t exp = now + (time_t)len;
352ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
353ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (len == 0xffffffff)
354ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
355ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      exp = 0;
356ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      len = 0;
357ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
358ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
359ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (exp != lease->expires)
360ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
361ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      dns_dirty = 1;
362ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->expires = exp;
363ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifndef HAVE_BROKEN_RTC
364ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->aux_changed = file_dirty = 1;
365ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
366ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
367ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
368ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_BROKEN_RTC
369ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (len != lease->length)
370ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
371ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->length = len;
372ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->aux_changed = file_dirty = 1;
373ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
374ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
375ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
376ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
377ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
378ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      unsigned char *clid, int hw_len, int hw_type, int clid_len)
379ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
380ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (hw_len != lease->hwaddr_len ||
381ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      hw_type != lease->hwaddr_type ||
382ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
383ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
384ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      memcpy(lease->hwaddr, hwaddr, hw_len);
385ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->hwaddr_len = hw_len;
386ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->hwaddr_type = hw_type;
387ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->changed = file_dirty = 1; /* run script on change */
388ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
389ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
390ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* only update clid when one is available, stops packets
391ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     without a clid removing the record. Lease init uses
392ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     clid_len == 0 for no clid. */
393ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (clid_len != 0 && clid)
394ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
395ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!lease->clid)
396ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->clid_len = 0;
397ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
398ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (lease->clid_len != clid_len)
399ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
400ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  lease->aux_changed = file_dirty = 1;
401ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease->clid);
402ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (!(lease->clid = whine_malloc(clid_len)))
403ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    return;
404ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
405ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else if (memcmp(lease->clid, clid, clid_len) != 0)
406ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->aux_changed = file_dirty = 1;
407ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
408ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->clid_len = clid_len;
409ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      memcpy(lease->clid, clid, clid_len);
410ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
411ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
412ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
413ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
414ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void kill_name(struct dhcp_lease *lease)
415ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
416ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* run script to say we lost our old name */
417ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
418ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* this shouldn't happen unless updates are very quick and the
419ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     script very slow, we just avoid a memory leak if it does. */
420ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  free(lease->old_hostname);
421ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
422ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* If we know the fqdn, pass that. The helper will derive the
423ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     unqualified name from it, free the unqulaified name here. */
424ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
425ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (lease->fqdn)
426ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
427ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->old_hostname = lease->fqdn;
428ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      free(lease->hostname);
429ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
430ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
431ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    lease->old_hostname = lease->hostname;
432ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
433ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->hostname = lease->fqdn = NULL;
434ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
435ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
436ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
437ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
438ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease_tmp;
439ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *new_name = NULL, *new_fqdn = NULL;
440ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
441ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (lease->hostname && name && hostname_isequal(lease->hostname, name))
442ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
443ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease->auth_name = auth;
444ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return;
445ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
446ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
447ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!name && !lease->hostname)
448ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
449ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
450ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* If a machine turns up on a new net without dropping the old lease,
451ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     or two machines claim the same name, then we end up with two interfaces with
452ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     the same name. Check for that here and remove the name from the old lease.
453ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     Don't allow a name from the client to override a name from dnsmasq config. */
454ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
455ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (name)
456ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
457ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if ((new_name = whine_malloc(strlen(name) + 1)))
458ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
459ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  char *suffix = get_domain(lease->addr);
460ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  strcpy(new_name, name);
461ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
462ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
463ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      strcpy(new_fqdn, name);
464ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      strcat(new_fqdn, ".");
465ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      strcat(new_fqdn, suffix);
466ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
467ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
468ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
469ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* Depending on mode, we check either unqualified name or FQDN. */
470ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
471ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
472ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (daemon->options & OPT_DHCP_FQDN)
473ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
474ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
475ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		continue;
476ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
477ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else
478ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
479ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
480ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		continue;
481ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
482ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
483ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (lease_tmp->auth_name && !auth)
484ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
485ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      free(new_name);
486ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      free(new_fqdn);
487ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      return;
488ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
489ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
490ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  kill_name(lease_tmp);
491ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  break;
492ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
493ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
494ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
495ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (lease->hostname)
496ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    kill_name(lease);
497ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
498ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->hostname = new_name;
499ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->fqdn = new_fqdn;
500ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->auth_name = auth;
501ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
502ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  file_dirty = 1;
503ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  dns_dirty = 1;
504ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->changed = 1; /* run script on change */
505ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
506ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
507ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid lease_set_interface(struct dhcp_lease *lease, int interface)
508ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
509ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (lease->last_interface == interface)
510ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
511ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
512ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->last_interface = interface;
513ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  lease->changed = 1;
514ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
515ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
516ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid rerun_scripts(void)
517ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
518ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
519ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
520ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (lease = leases; lease; lease = lease->next)
521ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    lease->changed = 1;
522ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
523ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
524ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* deleted leases get transferred to the old_leases list.
525ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   remove them here, after calling the lease change
526ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   script. Also run the lease change script on new/modified leases.
527ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
528ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   Return zero if nothing to do. */
529ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint do_script_run(time_t now)
530ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
531ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct dhcp_lease *lease;
532ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
533ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_DBUS
534ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* If we're going to be sending DBus signals, but the connection is not yet up,
535ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     delay everything until it is. */
536ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((daemon->options & OPT_DBUS) && !daemon->dbus)
537ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return 0;
538ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
539ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
540ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (old_leases)
541ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
542ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      lease = old_leases;
543ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
544ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* If the lease still has an old_hostname, do the "old" action on that first */
545ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (lease->old_hostname)
546ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
547ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SCRIPT
548ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
549ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
550ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease->old_hostname);
551ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  lease->old_hostname = NULL;
552ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  return 1;
553ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
554ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
555ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
556ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  kill_name(lease);
557ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SCRIPT
558ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  queue_script(ACTION_DEL, lease, lease->old_hostname, now);
559ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
560ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_DBUS
561ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
562ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
563ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  old_leases = lease->next;
564ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
565ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease->old_hostname);
566ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease->clid);
567ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease->vendorclass);
568ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease->userclass);
569ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease->supplied_hostname);
570ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free(lease);
571ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
572ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  return 1;
573ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
574ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
575ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
576ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* make sure we announce the loss of a hostname before its new location. */
577ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (lease = leases; lease; lease = lease->next)
578ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (lease->old_hostname)
579ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
580ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SCRIPT
581ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
582ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
583ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	free(lease->old_hostname);
584ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->old_hostname = NULL;
585ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return 1;
586ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
587ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
588ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (lease = leases; lease; lease = lease->next)
589ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (lease->new || lease->changed ||
590ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
591ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
592ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SCRIPT
593ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
594ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		     lease->fqdn ? lease->fqdn : lease->hostname, now);
595ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
596ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_DBUS
597ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	emit_dbus_signal(lease->new ? ACTION_ADD : ACTION_OLD, lease,
598ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 lease->fqdn ? lease->fqdn : lease->hostname);
599ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
600ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->new = lease->changed = lease->aux_changed = 0;
601ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
602ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	/* these are used for the "add" call, then junked, since they're not in the database */
603ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	free(lease->vendorclass);
604ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->vendorclass = NULL;
605ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
606ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	free(lease->userclass);
607ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->userclass = NULL;
608ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
609ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	free(lease->supplied_hostname);
610ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	lease->supplied_hostname = NULL;
611ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
612ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return 1;
613ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
614ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
615ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return 0; /* nothing to do */
616ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
617ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
618ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
619ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
620ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
621ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
622ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
623