File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / rfc2131.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:31:38 2014 UTC (10 years ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_71, HEAD
dnsmasq 2.71

    1: /* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: #include "dnsmasq.h"
   18: 
   19: #ifdef HAVE_DHCP
   20: 
   21: #define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
   22: #define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
   23: 
   24: #ifdef HAVE_SCRIPT
   25: static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
   26: #endif
   27: 
   28: static int sanitise(unsigned char *opt, char *buf);
   29: static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
   30: static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
   31: static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
   32: static void option_put_string(struct dhcp_packet *mess, unsigned char *end, 
   33: 			      int opt, char *string, int null_term);
   34: static struct in_addr option_addr(unsigned char *opt);
   35: static unsigned int option_uint(unsigned char *opt, int i, int size);
   36: static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
   37: 		       int mac_len, char *interface, char *string, char *err, u32 xid);
   38: static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
   39: static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
   40: static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
   41: static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
   42: static int in_list(unsigned char *list, int opt);
   43: static void do_options(struct dhcp_context *context,
   44: 		       struct dhcp_packet *mess,
   45: 		       unsigned char *real_end, 
   46: 		       unsigned char *req_options,
   47: 		       char *hostname, 
   48: 		       char *config_domain,
   49: 		       struct dhcp_netid *netid,
   50: 		       struct in_addr subnet_addr, 
   51: 		       unsigned char fqdn_flags,
   52: 		       int null_term, int pxearch,
   53: 		       unsigned char *uuid,
   54: 		       int vendor_class_len,
   55: 		       time_t now);
   56: 
   57: 
   58: static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); 
   59: static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
   60: static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
   61: static int prune_vendor_opts(struct dhcp_netid *netid);
   62: static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
   63: struct dhcp_boot *find_boot(struct dhcp_netid *netid);
   64: 
   65:   
   66: size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
   67: 		  size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
   68: {
   69:   unsigned char *opt, *clid = NULL;
   70:   struct dhcp_lease *ltmp, *lease = NULL;
   71:   struct dhcp_vendor *vendor;
   72:   struct dhcp_mac *mac;
   73:   struct dhcp_netid_list *id_list;
   74:   int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;
   75:   struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
   76:   unsigned char *end = (unsigned char *)(mess + 1); 
   77:   unsigned char *real_end = (unsigned char *)(mess + 1); 
   78:   char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
   79:   int hostname_auth = 0, borken_opt = 0;
   80:   unsigned char *req_options = NULL;
   81:   char *message = NULL;
   82:   unsigned int time;
   83:   struct dhcp_config *config;
   84:   struct dhcp_netid *netid, *tagif_netid;
   85:   struct in_addr subnet_addr, override;
   86:   unsigned short fuzz = 0;
   87:   unsigned int mess_type = 0;
   88:   unsigned char fqdn_flags = 0;
   89:   unsigned char *agent_id = NULL, *uuid = NULL;
   90:   unsigned char *emac = NULL;
   91:   int vendor_class_len = 0, emac_len = 0;
   92:   struct dhcp_netid known_id, iface_id, cpewan_id;
   93:   struct dhcp_opt *o;
   94:   unsigned char pxe_uuid[17];
   95:   unsigned char *oui = NULL, *serial = NULL;
   96: #ifdef HAVE_SCRIPT
   97:   unsigned char *class = NULL;
   98: #endif
   99: 
  100:   subnet_addr.s_addr = override.s_addr = 0;
  101: 
  102:   /* set tag with name == interface */
  103:   iface_id.net = iface_name;
  104:   iface_id.next = NULL;
  105:   netid = &iface_id; 
  106:   
  107:   if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
  108:     return 0;
  109:    
  110:   if (mess->htype == 0 && mess->hlen != 0)
  111:     return 0;
  112: 
  113:   /* check for DHCP rather than BOOTP */
  114:   if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
  115:     {
  116:       u32 cookie = htonl(DHCP_COOKIE);
  117:       
  118:       /* only insist on a cookie for DHCP. */
  119:       if (memcmp(mess->options, &cookie, sizeof(u32)) != 0)
  120: 	return 0;
  121:       
  122:       mess_type = option_uint(opt, 0, 1);
  123:       
  124:       /* two things to note here: expand_buf may move the packet,
  125: 	 so reassign mess from daemon->packet. Also, the size
  126: 	 sent includes the IP and UDP headers, hence the magic "-28" */
  127:       if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE, 2)))
  128: 	{
  129: 	  size_t size = (size_t)option_uint(opt, 0, 2) - 28;
  130: 	  
  131: 	  if (size > DHCP_PACKET_MAX)
  132: 	    size = DHCP_PACKET_MAX;
  133: 	  else if (size < sizeof(struct dhcp_packet))
  134: 	    size = sizeof(struct dhcp_packet);
  135: 	  
  136: 	  if (expand_buf(&daemon->dhcp_packet, size))
  137: 	    {
  138: 	      mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
  139: 	      real_end = end = ((unsigned char *)mess) + size;
  140: 	    }
  141: 	}
  142: 
  143:       /* Some buggy clients set ciaddr when they shouldn't, so clear that here since
  144: 	 it can affect the context-determination code. */
  145:       if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
  146: 	mess->ciaddr.s_addr = 0;
  147: 
  148:       /* search for device identity from CPEWAN devices, we pass this through to the script */
  149:       if ((opt = option_find(mess, sz, OPTION_VENDOR_IDENT_OPT, 5)))
  150: 	{
  151: 	  unsigned  int elen, offset, len = option_len(opt);
  152: 	  
  153: 	  for (offset = 0; offset < (len - 5); offset += elen + 5)
  154: 	    {
  155: 	      elen = option_uint(opt, offset + 4 , 1);
  156: 	      if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
  157: 		{
  158: 		  unsigned char *x = option_ptr(opt, offset + 5);
  159: 		  unsigned char *y = option_ptr(opt, offset + elen + 5);
  160: 		  oui = option_find1(x, y, 1, 1);
  161: 		  serial = option_find1(x, y, 2, 1);
  162: #ifdef HAVE_SCRIPT
  163: 		  class = option_find1(x, y, 3, 1);		  
  164: #endif
  165: 		  /* If TR069-id is present set the tag "cpewan-id" to facilitate echoing 
  166: 		     the gateway id back. Note that the device class is optional */
  167: 		  if (oui && serial)
  168: 		    {
  169: 		      cpewan_id.net = "cpewan-id";
  170: 		      cpewan_id.next = netid;
  171: 		      netid = &cpewan_id;
  172: 		    }
  173: 		  break;
  174: 		}
  175: 	    }
  176: 	}
  177:       
  178:       if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
  179: 	{
  180: 	  /* Any agent-id needs to be copied back out, verbatim, as the last option
  181: 	     in the packet. Here, we shift it to the very end of the buffer, if it doesn't
  182: 	     get overwritten, then it will be shuffled back at the end of processing.
  183: 	     Note that the incoming options must not be overwritten here, so there has to 
  184: 	     be enough free space at the end of the packet to copy the option. */
  185: 	  unsigned char *sopt;
  186: 	  unsigned int total = option_len(opt) + 2;
  187: 	  unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0);
  188: 	  if (last_opt && last_opt < end - total)
  189: 	    {
  190: 	      end -= total;
  191: 	      agent_id = end;
  192: 	      memcpy(agent_id, opt, total);
  193: 	    }
  194: 
  195: 	  /* look for RFC3527 Link selection sub-option */
  196: 	  if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
  197: 	    subnet_addr = option_addr(sopt);
  198: 
  199: 	  /* look for RFC5107 server-identifier-override */
  200: 	  if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
  201: 	    override = option_addr(sopt);
  202: 	  
  203: 	  /* if a circuit-id or remote-is option is provided, exact-match to options. */ 
  204: 	  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
  205: 	    {
  206: 	      int search;
  207: 	      
  208: 	      if (vendor->match_type == MATCH_CIRCUIT)
  209: 		search = SUBOPT_CIRCUIT_ID;
  210: 	      else if (vendor->match_type == MATCH_REMOTE)
  211: 		search = SUBOPT_REMOTE_ID;
  212: 	      else if (vendor->match_type == MATCH_SUBSCRIBER)
  213: 		search = SUBOPT_SUBSCR_ID;
  214: 	      else 
  215: 		continue;
  216: 
  217: 	      if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
  218: 		  vendor->len == option_len(sopt) &&
  219: 		  memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
  220: 		{
  221: 		  vendor->netid.next = netid;
  222: 		  netid = &vendor->netid;
  223: 		} 
  224: 	    }
  225: 	}
  226: 
  227:       /* Check for RFC3011 subnet selector - only if RFC3527 one not present */
  228:       if (subnet_addr.s_addr == 0 && (opt = option_find(mess, sz, OPTION_SUBNET_SELECT, INADDRSZ)))
  229: 	subnet_addr = option_addr(opt);
  230:       
  231:       /* If there is no client identifier option, use the hardware address */
  232:       if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
  233: 	{
  234: 	  clid_len = option_len(opt);
  235: 	  clid = option_ptr(opt, 0);
  236: 	}
  237: 
  238:       /* do we have a lease in store? */
  239:       lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
  240: 
  241:       /* If this request is missing a clid, but we've seen one before, 
  242: 	 use it again for option matching etc. */
  243:       if (lease && !clid && lease->clid)
  244: 	{
  245: 	  clid_len = lease->clid_len;
  246: 	  clid = lease->clid;
  247: 	}
  248: 
  249:       /* find mac to use for logging and hashing */
  250:       emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len);
  251:     }
  252:   
  253:   for (mac = daemon->dhcp_macs; mac; mac = mac->next)
  254:     if (mac->hwaddr_len == mess->hlen &&
  255: 	(mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0) &&
  256: 	memcmp_masked(mac->hwaddr, mess->chaddr, mess->hlen, mac->mask))
  257:       {
  258: 	mac->netid.next = netid;
  259: 	netid = &mac->netid;
  260:       }
  261:   
  262:   /* Determine network for this packet. Our caller will have already linked all the 
  263:      contexts which match the addresses of the receiving interface but if the 
  264:      machine has an address already, or came via a relay, or we have a subnet selector, 
  265:      we search again. If we don't have have a giaddr or explicit subnet selector, 
  266:      use the ciaddr. This is necessary because a  machine which got a lease via a 
  267:      relay won't use the relay to renew. If matching a ciaddr fails but we have a context 
  268:      from the physical network, continue using that to allow correct DHCPNAK generation later. */
  269:   if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
  270:     {
  271:       struct dhcp_context *context_tmp, *context_new = NULL;
  272:       struct in_addr addr;
  273:       int force = 0;
  274:       
  275:       if (subnet_addr.s_addr)
  276: 	{
  277: 	  addr = subnet_addr;
  278: 	  force = 1;
  279: 	}
  280:       else if (mess->giaddr.s_addr)
  281: 	{
  282: 	  addr = mess->giaddr;
  283: 	  force = 1;
  284: 	}
  285:       else
  286: 	{
  287: 	  /* If ciaddr is in the hardware derived set of contexts, leave that unchanged */
  288: 	  addr = mess->ciaddr;
  289: 	  for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
  290: 	    if (context_tmp->netmask.s_addr && 
  291: 		is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
  292: 		is_same_net(addr, context_tmp->end, context_tmp->netmask))
  293: 	      {
  294: 		context_new = context;
  295: 		break;
  296: 	      }
  297: 	} 
  298: 		
  299:       if (!context_new)
  300: 	for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
  301: 	  {
  302: 	    struct in_addr netmask = context_tmp->netmask;
  303: 
  304: 	    /* guess the netmask for relayed networks */
  305: 	    if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
  306: 	      {
  307: 		if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
  308: 		  netmask.s_addr = htonl(0xff000000);
  309: 		else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
  310: 		  netmask.s_addr = htonl(0xffff0000);
  311: 		else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
  312: 		  netmask.s_addr = htonl(0xffffff00); 
  313: 	      }
  314: 	    
  315: 	    /* This section fills in context mainly when a client which is on a remote (relayed)
  316: 	       network renews a lease without using the relay, after dnsmasq has restarted. */
  317: 	    if (netmask.s_addr != 0  && 
  318: 		is_same_net(addr, context_tmp->start, netmask) &&
  319: 		is_same_net(addr, context_tmp->end, netmask))
  320: 	      {
  321: 		context_tmp->netmask = netmask;
  322: 		if (context_tmp->local.s_addr == 0)
  323: 		  context_tmp->local = fallback;
  324: 		if (context_tmp->router.s_addr == 0)
  325: 		  context_tmp->router = mess->giaddr;
  326: 	   
  327: 		/* fill in missing broadcast addresses for relayed ranges */
  328: 		if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
  329: 		  context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
  330: 		
  331: 		context_tmp->current = context_new;
  332: 		context_new = context_tmp;
  333: 	      }
  334: 	  }
  335:       
  336:       if (context_new || force)
  337: 	context = context_new; 
  338:     }
  339:   
  340:   if (!context)
  341:     {
  342:       my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"), 
  343: 		subnet_addr.s_addr ? _("with subnet selector") : _("via"),
  344: 		subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
  345:       return 0;
  346:     }
  347: 
  348:   if (option_bool(OPT_LOG_OPTS))
  349:     {
  350:       struct dhcp_context *context_tmp;
  351:       for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
  352: 	{
  353: 	  strcpy(daemon->namebuff, inet_ntoa(context_tmp->start));
  354: 	  if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
  355: 	    my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"),
  356: 		      ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask));
  357: 	  else
  358: 	    my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"), 
  359: 		      ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
  360: 	}
  361:     }
  362:   
  363:   /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
  364:      Otherwise assume the option is an array, and look for a matching element. 
  365:      If no data given, existance of the option is enough. This code handles 
  366:      rfc3925 V-I classes too. */
  367:   for (o = daemon->dhcp_match; o; o = o->next)
  368:     {
  369:       unsigned int len, elen, match = 0;
  370:       size_t offset, o2;
  371: 
  372:       if (o->flags & DHOPT_RFC3925)
  373: 	{
  374: 	  if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
  375: 	    continue;
  376: 	  
  377: 	  for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
  378: 	    {
  379: 	      len = option_uint(opt, offset + 4 , 1);
  380: 	      /* Need to take care that bad data can't run us off the end of the packet */
  381: 	      if ((offset + len + 5 <= (option_len(opt))) &&
  382: 		  (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
  383: 		for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
  384: 		  { 
  385: 		    elen = option_uint(opt, o2, 1);
  386: 		    if ((o2 + elen + 1 <= option_len(opt)) &&
  387: 			(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
  388: 		      break;
  389: 		  }
  390: 	      if (match) 
  391: 		break;
  392: 	    }	  
  393: 	}
  394:       else
  395: 	{
  396: 	  if (!(opt = option_find(mess, sz, o->opt, 1)))
  397: 	    continue;
  398: 	  
  399: 	  match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
  400: 	} 
  401: 
  402:       if (match)
  403: 	{
  404: 	  o->netid->next = netid;
  405: 	  netid = o->netid;
  406: 	}
  407:     }
  408: 	
  409:   /* user-class options are, according to RFC3004, supposed to contain
  410:      a set of counted strings. Here we check that this is so (by seeing
  411:      if the counts are consistent with the overall option length) and if
  412:      so zero the counts so that we don't get spurious matches between 
  413:      the vendor string and the counts. If the lengths don't add up, we
  414:      assume that the option is a single string and non RFC3004 compliant 
  415:      and just do the substring match. dhclient provides these broken options.
  416:      The code, later, which sends user-class data to the lease-change script
  417:      relies on the transformation done here.
  418:   */
  419: 
  420:   if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
  421:     {
  422:       unsigned char *ucp = option_ptr(opt, 0);
  423:       int tmp, j;
  424:       for (j = 0; j < option_len(opt); j += ucp[j] + 1);
  425:       if (j == option_len(opt))
  426: 	for (j = 0; j < option_len(opt); j = tmp)
  427: 	  {
  428: 	    tmp = j + ucp[j] + 1;
  429: 	    ucp[j] = 0;
  430: 	  }
  431:     }
  432:     
  433:   for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
  434:     {
  435:       int mopt;
  436:       
  437:       if (vendor->match_type == MATCH_VENDOR)
  438: 	mopt = OPTION_VENDOR_ID;
  439:       else if (vendor->match_type == MATCH_USER)
  440: 	mopt = OPTION_USER_CLASS; 
  441:       else
  442: 	continue;
  443: 
  444:       if ((opt = option_find(mess, sz, mopt, 1)))
  445: 	{
  446: 	  int i;
  447: 	  for (i = 0; i <= (option_len(opt) - vendor->len); i++)
  448: 	    if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
  449: 	      {
  450: 		vendor->netid.next = netid;
  451: 		netid = &vendor->netid;
  452: 		break;
  453: 	      }
  454: 	}
  455:     }
  456: 
  457:   /* mark vendor-encapsulated options which match the client-supplied vendor class,
  458:      save client-supplied vendor class */
  459:   if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
  460:     {
  461:       memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
  462:       vendor_class_len = option_len(opt);
  463:     }
  464:   match_vendor_opts(opt, daemon->dhcp_opts);
  465:   
  466:   if (option_bool(OPT_LOG_OPTS))
  467:     {
  468:       if (sanitise(opt, daemon->namebuff))
  469: 	my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
  470:       if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
  471: 	my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
  472:     }
  473: 
  474:   mess->op = BOOTREPLY;
  475:   
  476:   config = find_config(daemon->dhcp_conf, context, clid, clid_len, 
  477: 		       mess->chaddr, mess->hlen, mess->htype, NULL);
  478: 
  479:   /* set "known" tag for known hosts */
  480:   if (config)
  481:     {
  482:       known_id.net = "known";
  483:       known_id.next = netid;
  484:       netid = &known_id;
  485:     }
  486:   
  487:   if (mess_type == 0 && !pxe)
  488:     {
  489:       /* BOOTP request */
  490:       struct dhcp_netid id, bootp_id;
  491:       struct in_addr *logaddr = NULL;
  492: 
  493:       /* must have a MAC addr for bootp */
  494:       if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY))
  495: 	return 0;
  496:       
  497:       if (have_config(config, CONFIG_DISABLE))
  498: 	message = _("disabled");
  499: 
  500:       end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
  501:             
  502:       if (have_config(config, CONFIG_NAME))
  503: 	{
  504: 	  hostname = config->hostname;
  505: 	  domain = config->domain;
  506: 	}
  507: 
  508:       if (config)
  509: 	{
  510: 	  struct dhcp_netid_list *list;
  511: 
  512: 	  for (list = config->netid; list; list = list->next)
  513: 	    {
  514: 	      list->list->next = netid;
  515: 	      netid = list->list;
  516: 	    }
  517: 	}
  518: 
  519:       /* Match incoming filename field as a netid. */
  520:       if (mess->file[0])
  521: 	{
  522: 	  memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file));
  523: 	  daemon->dhcp_buff2[sizeof(mess->file) + 1] = 0; /* ensure zero term. */
  524: 	  id.net = (char *)daemon->dhcp_buff2;
  525: 	  id.next = netid;
  526: 	  netid = &id;
  527: 	}
  528: 
  529:       /* Add "bootp" as a tag to allow different options, address ranges etc
  530: 	 for BOOTP clients */
  531:       bootp_id.net = "bootp";
  532:       bootp_id.next = netid;
  533:       netid = &bootp_id;
  534:       
  535:       tagif_netid = run_tag_if(netid);
  536: 
  537:       for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
  538: 	if (match_netid(id_list->list, tagif_netid, 0))
  539: 	  message = _("ignored");
  540:       
  541:       if (!message)
  542: 	{
  543: 	  int nailed = 0;
  544: 
  545: 	  if (have_config(config, CONFIG_ADDR))
  546: 	    {
  547: 	      nailed = 1;
  548: 	      logaddr = &config->addr;
  549: 	      mess->yiaddr = config->addr;
  550: 	      if ((lease = lease_find_by_addr(config->addr)) &&
  551: 		  (lease->hwaddr_len != mess->hlen ||
  552: 		   lease->hwaddr_type != mess->htype ||
  553: 		   memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
  554: 		message = _("address in use");
  555: 	    }
  556: 	  else
  557: 	    {
  558: 	      if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
  559: 		  !address_available(context, lease->addr, tagif_netid))
  560: 		{
  561: 		   if (lease)
  562: 		     {
  563: 		       /* lease exists, wrong network. */
  564: 		       lease_prune(lease, now);
  565: 		       lease = NULL;
  566: 		     }
  567: 		   if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now))
  568: 		     message = _("no address available");
  569: 		}
  570: 	      else
  571: 		mess->yiaddr = lease->addr;
  572: 	    }
  573: 	  
  574: 	  if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
  575: 	    message = _("wrong network");
  576: 	  else if (context->netid.net)
  577: 	    {
  578: 	      context->netid.next = netid;
  579: 	      tagif_netid = run_tag_if(&context->netid);
  580: 	    }
  581: 
  582: 	  log_tags(tagif_netid, ntohl(mess->xid));
  583: 	    
  584: 	  if (!message && !nailed)
  585: 	    {
  586: 	      for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
  587: 		if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
  588: 		  break;
  589: 	      if (!id_list)
  590: 		message = _("no address configured");
  591: 	    }
  592: 
  593: 	  if (!message && 
  594: 	      !lease && 
  595: 	      (!(lease = lease4_allocate(mess->yiaddr))))
  596: 	    message = _("no leases left");
  597: 	  
  598: 	  if (!message)
  599: 	    {
  600: 	      logaddr = &mess->yiaddr;
  601: 		
  602: 	      lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now, 1);
  603: 	      if (hostname)
  604: 		lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain); 
  605: 	      /* infinite lease unless nailed in dhcp-host line. */
  606: 	      lease_set_expires(lease,  
  607: 				have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff, 
  608: 				now); 
  609: 	      lease_set_interface(lease, int_index, now);
  610: 	      
  611: 	      clear_packet(mess, end);
  612: 	      do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 
  613: 			 netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
  614: 	    }
  615: 	}
  616:       
  617:       log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
  618:       
  619:       return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
  620:     }
  621:       
  622:   if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
  623:     {
  624:       /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
  625:       int len = option_len(opt);
  626:       char *pq = daemon->dhcp_buff;
  627:       unsigned char *pp, *op = option_ptr(opt, 0);
  628:       
  629:       fqdn_flags = *op;
  630:       len -= 3;
  631:       op += 3;
  632:       pp = op;
  633:       
  634:       /* NB, the following always sets at least one bit */
  635:       if (option_bool(OPT_FQDN_UPDATE))
  636: 	{
  637: 	  if (fqdn_flags & 0x01)
  638: 	    {
  639: 	      fqdn_flags |= 0x02; /* set O */
  640: 	      fqdn_flags &= ~0x01; /* clear S */
  641: 	    }
  642: 	  fqdn_flags |= 0x08; /* set N */
  643: 	}
  644:       else 
  645: 	{
  646: 	  if (!(fqdn_flags & 0x01))
  647: 	    fqdn_flags |= 0x03; /* set S and O */
  648: 	  fqdn_flags &= ~0x08; /* clear N */
  649: 	}
  650:       
  651:       if (fqdn_flags & 0x04)
  652: 	while (*op != 0 && ((op + (*op)) - pp) < len)
  653: 	  {
  654: 	    memcpy(pq, op+1, *op);
  655: 	    pq += *op;
  656: 	    op += (*op)+1;
  657: 	    *(pq++) = '.';
  658: 	  }
  659:       else
  660: 	{
  661: 	  memcpy(pq, op, len);
  662: 	  if (len > 0 && op[len-1] == 0)
  663: 	    borken_opt = 1;
  664: 	  pq += len + 1;
  665: 	}
  666:       
  667:       if (pq != daemon->dhcp_buff)
  668: 	pq--;
  669:       
  670:       *pq = 0;
  671:       
  672:       if (legal_hostname(daemon->dhcp_buff))
  673: 	offer_hostname = client_hostname = daemon->dhcp_buff;
  674:     }
  675:   else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
  676:     {
  677:       int len = option_len(opt);
  678:       memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
  679:       /* Microsoft clients are broken, and need zero-terminated strings
  680: 	 in options. We detect this state here, and do the same in
  681: 	 any options we send */
  682:       if (len > 0 && daemon->dhcp_buff[len-1] == 0)
  683: 	borken_opt = 1;
  684:       else
  685: 	daemon->dhcp_buff[len] = 0;
  686:       if (legal_hostname(daemon->dhcp_buff))
  687: 	client_hostname = daemon->dhcp_buff;
  688:     }
  689: 
  690:   if (client_hostname && option_bool(OPT_LOG_OPTS))
  691:     my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
  692:   
  693:   if (have_config(config, CONFIG_NAME))
  694:     {
  695:       hostname = config->hostname;
  696:       domain = config->domain;
  697:       hostname_auth = 1;
  698:       /* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
  699:       if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
  700:         offer_hostname = hostname;
  701:     }
  702:   else if (client_hostname)
  703:     {
  704:       domain = strip_hostname(client_hostname);
  705:       
  706:       if (strlen(client_hostname) != 0)
  707: 	{
  708: 	  hostname = client_hostname;
  709: 	  if (!config)
  710: 	    {
  711: 	      /* Search again now we have a hostname. 
  712: 		 Only accept configs without CLID and HWADDR here, (they won't match)
  713: 		 to avoid impersonation by name. */
  714: 	      struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
  715: 						    mess->chaddr, mess->hlen, 
  716: 						    mess->htype, hostname);
  717: 	      if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
  718: 		{
  719: 		  config = new;
  720: 		  /* set "known" tag for known hosts */
  721: 		  known_id.net = "known";
  722: 		  known_id.next = netid;
  723: 		  netid = &known_id;
  724: 		}
  725: 	    }
  726: 	}
  727:     }
  728:   
  729:   if (config)
  730:     {
  731:       struct dhcp_netid_list *list;
  732:       
  733:       for (list = config->netid; list; list = list->next)
  734: 	{
  735: 	  list->list->next = netid;
  736: 	  netid = list->list;
  737: 	}
  738:     }
  739:   
  740:   tagif_netid = run_tag_if(netid);
  741:   
  742:   /* if all the netids in the ignore list are present, ignore this client */
  743:   for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
  744:     if (match_netid(id_list->list, tagif_netid, 0))
  745:       ignore = 1;
  746: 
  747:   /* If configured, we can override the server-id to be the address of the relay, 
  748:      so that all traffic goes via the relay and can pick up agent-id info. This can be
  749:      configured for all relays, or by address. */
  750:   if (daemon->override && mess->giaddr.s_addr != 0 && override.s_addr == 0)
  751:     {
  752:       if (!daemon->override_relays)
  753: 	override = mess->giaddr;
  754:       else
  755: 	{
  756: 	  struct addr_list *l;
  757: 	  for (l = daemon->override_relays; l; l = l->next)
  758: 	    if (l->addr.s_addr == mess->giaddr.s_addr)
  759: 	      break;
  760: 	  if (l)
  761: 	    override = mess->giaddr;
  762: 	}
  763:     }
  764: 
  765:   /* Can have setting to ignore the client ID for a particular MAC address or hostname */
  766:   if (have_config(config, CONFIG_NOCLID))
  767:     clid = NULL;
  768:           
  769:   /* Check if client is PXE client. */
  770:   if (daemon->enable_pxe && 
  771:       (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) && 
  772:       strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
  773:     {
  774:       if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
  775: 	{
  776: 	  memcpy(pxe_uuid, option_ptr(opt, 0), 17);
  777: 	  uuid = pxe_uuid;
  778: 	}
  779: 
  780:       /* Check if this is really a PXE bootserver request, and handle specially if so. */
  781:       if ((mess_type == DHCPREQUEST || mess_type == DHCPINFORM) &&
  782: 	  (opt = option_find(mess, sz, OPTION_VENDOR_CLASS_OPT, 1)) &&
  783: 	  (opt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_PXE_BOOT_ITEM, 4)))
  784: 	{
  785: 	  struct pxe_service *service;
  786: 	  int type = option_uint(opt, 0, 2);
  787: 	  int layer = option_uint(opt, 2, 2);
  788: 	  unsigned char save71[4];
  789: 	  struct dhcp_opt opt71;
  790: 
  791: 	  if (ignore)
  792: 	    return 0;
  793: 
  794: 	  if (layer & 0x8000)
  795: 	    {
  796: 	      my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
  797: 	      return 0;
  798: 	    }
  799: 
  800: 	  memcpy(save71, option_ptr(opt, 0), 4);
  801: 	  
  802: 	  for (service = daemon->pxe_services; service; service = service->next)
  803: 	    if (service->type == type)
  804: 	      break;
  805: 	  
  806: 	  if (!service || !service->basename)
  807: 	    return 0;
  808: 	  
  809: 	  clear_packet(mess, end);
  810: 	  
  811: 	  mess->yiaddr = mess->ciaddr;
  812: 	  mess->ciaddr.s_addr = 0;
  813: 	  if (service->sname)
  814: 	    mess->siaddr = a_record_from_hosts(service->sname, now);
  815: 	  else if (service->server.s_addr != 0)
  816: 	    mess->siaddr = service->server; 
  817: 	  else
  818: 	    mess->siaddr = context->local; 
  819: 	  
  820: 	  snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);
  821: 	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
  822: 	  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
  823: 	  pxe_misc(mess, end, uuid);
  824: 	  
  825: 	  prune_vendor_opts(tagif_netid);
  826: 	  opt71.val = save71;
  827: 	  opt71.opt = SUBOPT_PXE_BOOT_ITEM;
  828: 	  opt71.len = 4;
  829: 	  opt71.flags = DHOPT_VENDOR_MATCH;
  830: 	  opt71.netid = NULL;
  831: 	  opt71.next = daemon->dhcp_opts;
  832: 	  do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
  833: 	  
  834: 	  log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
  835: 	  log_tags(tagif_netid, ntohl(mess->xid));
  836: 	  return dhcp_packet_size(mess, agent_id, real_end);	  
  837: 	}
  838:       
  839:       if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
  840: 	{
  841: 	  pxearch = option_uint(opt, 0, 2);
  842: 
  843: 	  /* proxy DHCP here. */
  844: 	  if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
  845: 	    {
  846: 	      struct dhcp_context *tmp;
  847: 	      
  848: 	      for (tmp = context; tmp; tmp = tmp->current)
  849: 		if ((tmp->flags & CONTEXT_PROXY) &&
  850: 		    match_netid(tmp->filter, tagif_netid, 1))
  851: 		  break;
  852: 	      
  853: 	      if (tmp)
  854: 		{
  855: 		  struct dhcp_boot *boot;
  856: 		  
  857: 		  if (tmp->netid.net)
  858: 		    {
  859: 		      tmp->netid.next = netid;
  860: 		      tagif_netid = run_tag_if(&tmp->netid);
  861: 		    }
  862: 		  
  863: 		  boot = find_boot(tagif_netid);
  864: 		  
  865: 		  mess->yiaddr.s_addr = 0;
  866: 		  if  (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
  867: 		    {
  868: 		      mess->ciaddr.s_addr = 0;
  869: 		      mess->flags |= htons(0x8000); /* broadcast */
  870: 		    }
  871: 		  
  872: 		  clear_packet(mess, end);
  873: 		  
  874: 		  /* Provide the bootfile here, for gPXE, and in case we have no menu items
  875: 		     and set discovery_control = 8 */
  876: 		  if (boot)
  877: 		    {
  878: 		      if (boot->next_server.s_addr) 
  879: 			mess->siaddr = boot->next_server;
  880: 		      else if (boot->tftp_sname) 
  881: 			mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
  882: 		      
  883: 		      if (boot->file)
  884: 			strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
  885: 		    }
  886: 		  
  887: 		  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
  888: 			     mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
  889: 		  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
  890: 		  pxe_misc(mess, end, uuid);
  891: 		  prune_vendor_opts(tagif_netid);
  892: 		  do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
  893: 		  
  894: 		  log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
  895: 		  log_tags(tagif_netid, ntohl(mess->xid));
  896: 		  return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);	  
  897: 		}
  898: 	    }
  899: 	}
  900:     }
  901: 
  902:   /* if we're just a proxy server, go no further */
  903:   if ((context->flags & CONTEXT_PROXY) || pxe)
  904:     return 0;
  905:   
  906:   if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
  907:     {
  908:       req_options = (unsigned char *)daemon->dhcp_buff2;
  909:       memcpy(req_options, option_ptr(opt, 0), option_len(opt));
  910:       req_options[option_len(opt)] = OPTION_END;
  911:     }
  912:   
  913:   switch (mess_type)
  914:     {
  915:     case DHCPDECLINE:
  916:       if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
  917: 	  option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
  918: 	return 0;
  919:       
  920:       /* sanitise any message. Paranoid? Moi? */
  921:       sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
  922:       
  923:       if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
  924: 	return 0;
  925:       
  926:       log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
  927:       
  928:       if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
  929: 	lease_prune(lease, now);
  930:       
  931:       if (have_config(config, CONFIG_ADDR) && 
  932: 	  config->addr.s_addr == option_addr(opt).s_addr)
  933: 	{
  934: 	  prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
  935: 	  my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), 
  936: 		    inet_ntoa(config->addr), daemon->dhcp_buff);
  937: 	  config->flags |= CONFIG_DECLINED;
  938: 	  config->decline_time = now;
  939: 	}
  940:       else
  941: 	/* make sure this host gets a different address next time. */
  942: 	for (; context; context = context->current)
  943: 	  context->addr_epoch++;
  944:       
  945:       return 0;
  946: 
  947:     case DHCPRELEASE:
  948:       if (!(context = narrow_context(context, mess->ciaddr, tagif_netid)) ||
  949: 	  !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
  950: 	  option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
  951: 	return 0;
  952:       
  953:       if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
  954: 	lease_prune(lease, now);
  955:       else
  956: 	message = _("unknown lease");
  957: 
  958:       log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
  959: 	
  960:       return 0;
  961:       
  962:     case DHCPDISCOVER:
  963:       if (ignore || have_config(config, CONFIG_DISABLE))
  964: 	{
  965: 	  if (option_bool(OPT_QUIET_DHCP))
  966: 	    return 0;
  967: 	  message = _("ignored");
  968: 	  opt = NULL;
  969: 	}
  970:       else 
  971: 	{
  972: 	  struct in_addr addr, conf;
  973: 	  
  974: 	  addr.s_addr = conf.s_addr = 0;
  975: 
  976: 	  if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))	 
  977: 	    addr = option_addr(opt);
  978: 	  
  979: 	  if (have_config(config, CONFIG_ADDR))
  980: 	    {
  981: 	      char *addrs = inet_ntoa(config->addr);
  982: 	      
  983: 	      if ((ltmp = lease_find_by_addr(config->addr)) && 
  984: 		  ltmp != lease &&
  985: 		  !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
  986: 		{
  987: 		  int len;
  988: 		  unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
  989: 						       ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
  990: 		  my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
  991: 			    addrs, print_mac(daemon->namebuff, mac, len));
  992: 		}
  993: 	      else
  994: 		{
  995: 		  struct dhcp_context *tmp;
  996: 		  for (tmp = context; tmp; tmp = tmp->current)
  997: 		    if (context->router.s_addr == config->addr.s_addr)
  998: 		      break;
  999: 		  if (tmp)
 1000: 		    my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
 1001: 		  else if (have_config(config, CONFIG_DECLINED) &&
 1002: 			   difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
 1003: 		    my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
 1004: 		  else
 1005: 		    conf = config->addr;
 1006: 		}
 1007: 	    }
 1008: 	  
 1009: 	  if (conf.s_addr)
 1010: 	    mess->yiaddr = conf;
 1011: 	  else if (lease && 
 1012: 		   address_available(context, lease->addr, tagif_netid) && 
 1013: 		   !config_find_by_address(daemon->dhcp_conf, lease->addr))
 1014: 	    mess->yiaddr = lease->addr;
 1015: 	  else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) && 
 1016: 		   !config_find_by_address(daemon->dhcp_conf, addr))
 1017: 	    mess->yiaddr = addr;
 1018: 	  else if (emac_len == 0)
 1019: 	    message = _("no unique-id");
 1020: 	  else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now))
 1021: 	    message = _("no address available");      
 1022: 	}
 1023:       
 1024:       log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); 
 1025: 
 1026:       if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
 1027: 	return 0;
 1028: 
 1029:       if (context->netid.net)
 1030: 	{
 1031: 	  context->netid.next = netid;
 1032: 	  tagif_netid = run_tag_if(&context->netid);
 1033: 	}
 1034: 
 1035:       log_tags(tagif_netid, ntohl(mess->xid));
 1036:       
 1037:       log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
 1038:       
 1039:       time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
 1040:       clear_packet(mess, end);
 1041:       option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
 1042:       option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
 1043:       option_put(mess, end, OPTION_LEASE_TIME, 4, time);
 1044:       /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
 1045:       if (time != 0xffffffff)
 1046: 	{
 1047: 	  option_put(mess, end, OPTION_T1, 4, (time/2));
 1048: 	  option_put(mess, end, OPTION_T2, 4, (time*7)/8);
 1049: 	}
 1050:       do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), 
 1051: 		 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
 1052:       
 1053:       return dhcp_packet_size(mess, agent_id, real_end);
 1054:       
 1055:     case DHCPREQUEST:
 1056:       if (ignore || have_config(config, CONFIG_DISABLE))
 1057: 	return 0;
 1058:       if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
 1059: 	{
 1060: 	  /* SELECTING  or INIT_REBOOT */
 1061: 	  mess->yiaddr = option_addr(opt);
 1062: 	  
 1063: 	  /* send vendor and user class info for new or recreated lease */
 1064: 	  do_classes = 1;
 1065: 	  
 1066: 	  if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
 1067: 	    {
 1068: 	      /* SELECTING */
 1069: 	      selecting = 1;
 1070: 	      
 1071: 	      if (override.s_addr != 0)
 1072: 		{
 1073: 		  if (option_addr(opt).s_addr != override.s_addr)
 1074: 		    return 0;
 1075: 		}
 1076: 	      else 
 1077: 		{
 1078: 		  for (; context; context = context->current)
 1079: 		    if (context->local.s_addr == option_addr(opt).s_addr)
 1080: 		      break;
 1081: 		  
 1082: 		  if (!context)
 1083: 		    {
 1084: 		      /* Handle very strange configs where clients have more than one route to the server.
 1085: 			 If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
 1086: 			 Have to set override to make sure we echo back the correct server-id */
 1087: 		      struct irec *intr;
 1088: 		      
 1089: 		      enumerate_interfaces(0);
 1090: 
 1091: 		      for (intr = daemon->interfaces; intr; intr = intr->next)
 1092: 			if (intr->addr.sa.sa_family == AF_INET &&
 1093: 			    intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
 1094: 			    intr->tftp_ok)
 1095: 			  break;
 1096: 
 1097: 		      if (intr)
 1098: 			override = intr->addr.in.sin_addr;
 1099: 		      else
 1100: 			{
 1101: 			  /* In auth mode, a REQUEST sent to the wrong server
 1102: 			     should be faulted, so that the client establishes 
 1103: 			     communication with us, otherwise, silently ignore. */
 1104: 			  if (!option_bool(OPT_AUTHORITATIVE))
 1105: 			    return 0;
 1106: 			  message = _("wrong server-ID");
 1107: 			}
 1108: 		    }
 1109: 		}
 1110: 
 1111: 	      /* If a lease exists for this host and another address, squash it. */
 1112: 	      if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
 1113: 		{
 1114: 		  lease_prune(lease, now);
 1115: 		  lease = NULL;
 1116: 		}
 1117: 	    }
 1118: 	  else
 1119: 	    {
 1120: 	      /* INIT-REBOOT */
 1121: 	      if (!lease && !option_bool(OPT_AUTHORITATIVE))
 1122: 		return 0;
 1123: 	      
 1124: 	      if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
 1125: 		message = _("wrong address");
 1126: 	    }
 1127: 	}
 1128:       else
 1129: 	{
 1130: 	  /* RENEWING or REBINDING */ 
 1131: 	  /* Check existing lease for this address.
 1132: 	     We allow it to be missing if dhcp-authoritative mode
 1133: 	     as long as we can allocate the lease now - checked below.
 1134: 	     This makes for a smooth recovery from a lost lease DB */
 1135: 	  if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
 1136: 	      (!lease && !option_bool(OPT_AUTHORITATIVE)))
 1137: 	    {
 1138: 	      /* A client rebinding will broadcast the request, so we may see it even 
 1139: 		 if the lease is held by another server. Just ignore it in that case. 
 1140: 		 If the request is unicast to us, then somethings wrong, NAK */
 1141: 	      if (!unicast_dest)
 1142: 		return 0;
 1143: 	      message = _("lease not found");
 1144: 	      /* ensure we broadcast NAK */
 1145: 	      unicast_dest = 0;
 1146: 	    }
 1147: 
 1148: 	  /* desynchronise renewals */
 1149: 	  fuzz = rand16();
 1150: 	  mess->yiaddr = mess->ciaddr;
 1151: 	}
 1152:       
 1153:       log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
 1154:  
 1155:       if (!message)
 1156: 	{
 1157: 	  struct dhcp_config *addr_config;
 1158: 	  struct dhcp_context *tmp = NULL;
 1159: 	  
 1160: 	  if (have_config(config, CONFIG_ADDR))
 1161: 	    for (tmp = context; tmp; tmp = tmp->current)
 1162: 	      if (context->router.s_addr == config->addr.s_addr)
 1163: 		break;
 1164: 	  
 1165: 	  if (!(context = narrow_context(context, mess->yiaddr, tagif_netid)))
 1166: 	    {
 1167: 	      /* If a machine moves networks whilst it has a lease, we catch that here. */
 1168: 	      message = _("wrong network");
 1169: 	      /* ensure we broadcast NAK */
 1170: 	      unicast_dest = 0;
 1171: 	    }
 1172: 	  
 1173: 	  /* Check for renewal of a lease which is outside the allowed range. */
 1174: 	  else if (!address_available(context, mess->yiaddr, tagif_netid) &&
 1175: 		   (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
 1176: 	    message = _("address not available");
 1177: 	  
 1178: 	  /* Check if a new static address has been configured. Be very sure that
 1179: 	     when the client does DISCOVER, it will get the static address, otherwise
 1180: 	     an endless protocol loop will ensue. */
 1181: 	  else if (!tmp && !selecting &&
 1182: 		   have_config(config, CONFIG_ADDR) && 
 1183: 		   (!have_config(config, CONFIG_DECLINED) ||
 1184: 		    difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
 1185: 		   config->addr.s_addr != mess->yiaddr.s_addr &&
 1186: 		   (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
 1187: 	    message = _("static lease available");
 1188: 
 1189: 	  /* Check to see if the address is reserved as a static address for another host */
 1190: 	  else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
 1191: 	    message = _("address reserved");
 1192: 
 1193: 	  else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
 1194: 	    {
 1195: 	      /* If a host is configured with more than one MAC address, it's OK to 'nix 
 1196: 		 a lease from one of it's MACs to give the address to another. */
 1197: 	      if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
 1198: 		{
 1199: 		  my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
 1200: 			    print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len), 
 1201: 			    inet_ntoa(ltmp->addr));
 1202: 		  lease = ltmp;
 1203: 		}
 1204: 	      else
 1205: 		message = _("address in use");
 1206: 	    }
 1207: 
 1208: 	  if (!message)
 1209: 	    {
 1210: 	      if (emac_len == 0)
 1211: 		message = _("no unique-id");
 1212: 	      
 1213: 	      else if (!lease)
 1214: 		{	     
 1215: 		  if ((lease = lease4_allocate(mess->yiaddr)))
 1216: 		    do_classes = 1;
 1217: 		  else
 1218: 		    message = _("no leases left");
 1219: 		}
 1220: 	    }
 1221: 	}
 1222: 
 1223:       if (message)
 1224: 	{
 1225: 	  log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
 1226: 	  
 1227: 	  mess->yiaddr.s_addr = 0;
 1228: 	  clear_packet(mess, end);
 1229: 	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
 1230: 	  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
 1231: 	  option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
 1232: 	  /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on 
 1233: 	     a distant subnet which unicast a REQ to us won't work. */
 1234: 	  if (!unicast_dest || mess->giaddr.s_addr != 0 || 
 1235: 	      mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
 1236: 	    {
 1237: 	      mess->flags |= htons(0x8000); /* broadcast */
 1238: 	      mess->ciaddr.s_addr = 0;
 1239: 	    }
 1240: 	}
 1241:       else
 1242: 	{
 1243: 	  if (context->netid.net)
 1244: 	    {
 1245: 	      context->netid.next = netid;
 1246: 	      tagif_netid = run_tag_if( &context->netid);
 1247: 	    }
 1248: 
 1249: 	  log_tags(tagif_netid, ntohl(mess->xid));
 1250: 	  
 1251: 	  if (do_classes)
 1252: 	    {
 1253: 	      /* pick up INIT-REBOOT events. */
 1254: 	      lease->flags |= LEASE_CHANGED;
 1255: 
 1256: #ifdef HAVE_SCRIPT
 1257: 	      if (daemon->lease_change_command)
 1258: 		{
 1259: 		  struct dhcp_netid *n;
 1260: 		  
 1261: 		  if (mess->giaddr.s_addr)
 1262: 		    lease->giaddr = mess->giaddr;
 1263: 		  
 1264: 		  free(lease->extradata);
 1265: 		  lease->extradata = NULL;
 1266: 		  lease->extradata_size = lease->extradata_len = 0;
 1267: 		  
 1268: 		  add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
 1269: 		  add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
 1270: 		  add_extradata_opt(lease, oui);
 1271: 		  add_extradata_opt(lease, serial);
 1272: 		  add_extradata_opt(lease, class);
 1273: 
 1274: 		  if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
 1275: 		    {
 1276: 		      add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
 1277: 		      add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
 1278: 		      add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
 1279: 		    }
 1280: 		  else
 1281: 		    {
 1282: 		      add_extradata_opt(lease, NULL);
 1283: 		      add_extradata_opt(lease, NULL);
 1284: 		      add_extradata_opt(lease, NULL);
 1285: 		    }
 1286: 
 1287: 		  /* space-concat tag set */
 1288: 		  if (!tagif_netid)
 1289: 		    add_extradata_opt(lease, NULL);
 1290: 		  else
 1291: 		    for (n = tagif_netid; n; n = n->next)
 1292: 		      {
 1293: 			struct dhcp_netid *n1;
 1294: 			/* kill dupes */
 1295: 			for (n1 = n->next; n1; n1 = n1->next)
 1296: 			  if (strcmp(n->net, n1->net) == 0)
 1297: 			    break;
 1298: 			if (!n1)
 1299: 			  lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0); 
 1300: 		      }
 1301: 		  
 1302: 		  if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
 1303: 		    {
 1304: 		      int len = option_len(opt);
 1305: 		      unsigned char *ucp = option_ptr(opt, 0);
 1306: 		      /* If the user-class option started as counted strings, the first byte will be zero. */
 1307: 		      if (len != 0 && ucp[0] == 0)
 1308: 			ucp++, len--;
 1309: 		      lease_add_extradata(lease, ucp, len, 0);
 1310: 		    }
 1311: 		}
 1312: #endif
 1313: 	    }
 1314: 	  
 1315: 	  if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
 1316: 	    {
 1317: 	      domain = get_domain(mess->yiaddr);
 1318: 	      hostname = client_hostname;
 1319: 	      hostname_auth = 1;
 1320: 	    }
 1321: 	  
 1322: 	  time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
 1323: 	  lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now, do_classes);
 1324: 	  
 1325: 	  /* if all the netids in the ignore_name list are present, ignore client-supplied name */
 1326: 	  if (!hostname_auth)
 1327: 	    {
 1328: 	      for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
 1329: 		if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
 1330: 		  break;
 1331: 	      if (id_list)
 1332: 		hostname = NULL;
 1333: 	    }
 1334: 	  
 1335: 	  /* Last ditch, if configured, generate hostname from mac address */
 1336: 	  if (!hostname && emac_len != 0)
 1337: 	    {
 1338: 	      for (id_list = daemon->dhcp_gen_names; id_list; id_list = id_list->next)
 1339: 		if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
 1340: 		  break;
 1341: 	      if (id_list)
 1342: 		{
 1343: 		  int i;
 1344: 
 1345: 		  hostname = daemon->dhcp_buff;
 1346: 		  /* buffer is 256 bytes, 3 bytes per octet */
 1347: 		  for (i = 0; (i < emac_len) && (i < 80); i++)
 1348: 		    hostname += sprintf(hostname, "%.2x%s", emac[i], (i == emac_len - 1) ? "" : "-");
 1349: 		  hostname = daemon->dhcp_buff;
 1350: 		}
 1351: 	    }
 1352: 
 1353: 	  if (hostname)
 1354: 	    lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
 1355: 	  
 1356: 	  lease_set_expires(lease, time, now);
 1357: 	  lease_set_interface(lease, int_index, now);
 1358: 
 1359: 	  if (override.s_addr != 0)
 1360: 	    lease->override = override;
 1361: 	  else
 1362: 	    override = lease->override;
 1363: 
 1364: 	  log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);  
 1365: 	  
 1366: 	  clear_packet(mess, end);
 1367: 	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
 1368: 	  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
 1369: 	  option_put(mess, end, OPTION_LEASE_TIME, 4, time);
 1370: 	  if (time != 0xffffffff)
 1371: 	    {
 1372: 	      while (fuzz > (time/16))
 1373: 		fuzz = fuzz/2; 
 1374: 	      option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
 1375: 	      option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
 1376: 	    }
 1377: 	  do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), 
 1378: 		     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
 1379: 	}
 1380: 
 1381:       return dhcp_packet_size(mess, agent_id, real_end); 
 1382:       
 1383:     case DHCPINFORM:
 1384:       if (ignore || have_config(config, CONFIG_DISABLE))
 1385: 	message = _("ignored");
 1386:       
 1387:       log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
 1388:      
 1389:       if (message || mess->ciaddr.s_addr == 0)
 1390: 	return 0;
 1391: 
 1392:       /* For DHCPINFORM only, cope without a valid context */
 1393:       context = narrow_context(context, mess->ciaddr, tagif_netid);
 1394:       
 1395:       /* Find a least based on IP address if we didn't
 1396: 	 get one from MAC address/client-d */
 1397:       if (!lease &&
 1398: 	  (lease = lease_find_by_addr(mess->ciaddr)) && 
 1399: 	  lease->hostname)
 1400: 	hostname = lease->hostname;
 1401:       
 1402:       if (!hostname)
 1403: 	hostname = host_from_dns(mess->ciaddr);
 1404:       
 1405:       if (context && context->netid.net)
 1406: 	{
 1407: 	  context->netid.next = netid;
 1408: 	  tagif_netid = run_tag_if(&context->netid);
 1409: 	}
 1410: 
 1411:       log_tags(tagif_netid, ntohl(mess->xid));
 1412:       
 1413:       log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
 1414:       
 1415:       if (lease)
 1416: 	{
 1417: 	  lease_set_interface(lease, int_index, now);
 1418: 	  if (override.s_addr != 0)
 1419: 	    lease->override = override;
 1420: 	  else
 1421: 	    override = lease->override;
 1422: 	}
 1423: 
 1424:       clear_packet(mess, end);
 1425:       option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
 1426:       option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
 1427:      
 1428:       /* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but 
 1429: 	 we supply a utility which makes DHCPINFORM requests to get this information.
 1430: 	 Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
 1431: 	 which won't be true for ordinary clients, but will be true for the 
 1432: 	 dhcp_lease_time utility. */
 1433:       if (lease && in_list(req_options, OPTION_LEASE_TIME))
 1434: 	{
 1435: 	  if (lease->expires == 0)
 1436: 	    time = 0xffffffff;
 1437: 	  else
 1438: 	    time = (unsigned int)difftime(lease->expires, now);
 1439: 	  option_put(mess, end, OPTION_LEASE_TIME, 4, time);
 1440: 	}
 1441: 
 1442:       do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
 1443: 		 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
 1444:       
 1445:       *is_inform = 1; /* handle reply differently */
 1446:       return dhcp_packet_size(mess, agent_id, real_end); 
 1447:     }
 1448:   
 1449:   return 0;
 1450: }
 1451: 
 1452: /* find a good value to use as MAC address for logging and address-allocation hashing.
 1453:    This is normally just the chaddr field from the DHCP packet,
 1454:    but eg Firewire will have hlen == 0 and use the client-id instead. 
 1455:    This could be anything, but will normally be EUI64 for Firewire.
 1456:    We assume that if the first byte of the client-id equals the htype byte
 1457:    then the client-id is using the usual encoding and use the rest of the 
 1458:    client-id: if not we can use the whole client-id. This should give
 1459:    sane MAC address logs. */
 1460: unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr, 
 1461: 				      int clid_len, unsigned char *clid, int *len_out)
 1462: {
 1463:   if (hwlen == 0 && clid && clid_len > 3)
 1464:     {
 1465:       if (clid[0]  == hwtype)
 1466: 	{
 1467: 	  *len_out = clid_len - 1 ;
 1468: 	  return clid + 1;
 1469: 	}
 1470: 
 1471: #if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
 1472:       if (clid[0] ==  ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
 1473: 	{
 1474: 	  *len_out = clid_len - 1 ;
 1475: 	  return clid + 1;
 1476: 	}
 1477: #endif
 1478:       
 1479:       *len_out = clid_len;
 1480:       return clid;
 1481:     }
 1482:   
 1483:   *len_out = hwlen;
 1484:   return hwaddr;
 1485: }
 1486: 
 1487: static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
 1488: {
 1489:   unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
 1490:   
 1491:   if (opt)
 1492:     { 
 1493:       unsigned int req_time = option_uint(opt, 0, 4);
 1494:       if (req_time < 120 )
 1495: 	req_time = 120; /* sanity */
 1496:       if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
 1497: 	time = req_time;
 1498:     }
 1499: 
 1500:   return time;
 1501: }
 1502: 
 1503: static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
 1504: {
 1505:   if (override.s_addr != 0)
 1506:     return override;
 1507:   else if (context && context->local.s_addr != 0)
 1508:     return context->local;
 1509:   else
 1510:     return fallback;
 1511: }
 1512: 
 1513: static int sanitise(unsigned char *opt, char *buf)
 1514: {
 1515:   char *p;
 1516:   int i;
 1517:   
 1518:   *buf = 0;
 1519:   
 1520:   if (!opt)
 1521:     return 0;
 1522: 
 1523:   p = option_ptr(opt, 0);
 1524: 
 1525:   for (i = option_len(opt); i > 0; i--)
 1526:     {
 1527:       char c = *p++;
 1528:       if (isprint((int)c))
 1529: 	*buf++ = c;
 1530:     }
 1531:   *buf = 0; /* add terminator */
 1532:   
 1533:   return 1;
 1534: }
 1535: 
 1536: #ifdef HAVE_SCRIPT
 1537: static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
 1538: {
 1539:   if (!opt)
 1540:     lease_add_extradata(lease, NULL, 0, 0);
 1541:   else
 1542:     lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0); 
 1543: }
 1544: #endif
 1545: 
 1546: static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
 1547: 		       int mac_len, char *interface, char *string, char *err, u32 xid)
 1548: {
 1549:   struct in_addr a;
 1550:  
 1551:   if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
 1552:     return;
 1553:   
 1554:   /* addr may be misaligned */
 1555:   if (addr)
 1556:     memcpy(&a, addr, sizeof(a));
 1557:   
 1558:   print_mac(daemon->namebuff, ext_mac, mac_len);
 1559:   
 1560:   if(option_bool(OPT_LOG_OPTS))
 1561:      my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
 1562: 	       ntohl(xid), 
 1563: 	       type,
 1564: 	       interface, 
 1565: 	       addr ? inet_ntoa(a) : "",
 1566: 	       addr ? " " : "",
 1567: 	       daemon->namebuff,
 1568: 	       string ? string : "",
 1569: 	       err ? err : "");
 1570:   else
 1571:     my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
 1572: 	      type,
 1573: 	      interface, 
 1574: 	      addr ? inet_ntoa(a) : "",
 1575: 	      addr ? " " : "",
 1576: 	      daemon->namebuff,
 1577: 	      string ? string : "",
 1578: 	      err ? err : "");
 1579: }
 1580: 
 1581: static void log_options(unsigned char *start, u32 xid)
 1582: {
 1583:   while (*start != OPTION_END)
 1584:     {
 1585:       char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
 1586:       
 1587:       my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s  %s", 
 1588: 		ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
 1589:       start += start[1] + 2;
 1590:     }
 1591: }
 1592: 
 1593: static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
 1594: {
 1595:   while (1) 
 1596:     {
 1597:       if (p > end)
 1598: 	return NULL;
 1599:       else if (*p == OPTION_END)
 1600: 	return opt == OPTION_END ? p : NULL;
 1601:       else if (*p == OPTION_PAD)
 1602: 	p++;
 1603:       else 
 1604: 	{ 
 1605: 	  int opt_len;
 1606: 	  if (p > end - 2)
 1607: 	    return NULL; /* malformed packet */
 1608: 	  opt_len = option_len(p);
 1609: 	  if (p > end - (2 + opt_len))
 1610: 	    return NULL; /* malformed packet */
 1611: 	  if (*p == opt && opt_len >= minsize)
 1612: 	    return p;
 1613: 	  p += opt_len + 2;
 1614: 	}
 1615:     }
 1616: }
 1617:  
 1618: static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
 1619: {
 1620:   unsigned char *ret, *overload;
 1621:   
 1622:   /* skip over DHCP cookie; */
 1623:   if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
 1624:     return ret;
 1625: 
 1626:   /* look for overload option. */
 1627:   if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
 1628:     return NULL;
 1629:   
 1630:   /* Can we look in filename area ? */
 1631:   if ((overload[2] & 1) &&
 1632:       (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
 1633:     return ret;
 1634: 
 1635:   /* finally try sname area */
 1636:   if ((overload[2] & 2) &&
 1637:       (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
 1638:     return ret;
 1639: 
 1640:   return NULL;
 1641: }
 1642: 
 1643: static struct in_addr option_addr(unsigned char *opt)
 1644: {
 1645:    /* this worries about unaligned data in the option. */
 1646:   /* struct in_addr is network byte order */
 1647:   struct in_addr ret;
 1648: 
 1649:   memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
 1650: 
 1651:   return ret;
 1652: }
 1653: 
 1654: static unsigned int option_uint(unsigned char *opt, int offset, int size)
 1655: {
 1656:   /* this worries about unaligned data and byte order */
 1657:   unsigned int ret = 0;
 1658:   int i;
 1659:   unsigned char *p = option_ptr(opt, offset);
 1660:   
 1661:   for (i = 0; i < size; i++)
 1662:     ret = (ret << 8) | *p++;
 1663: 
 1664:   return ret;
 1665: }
 1666: 
 1667: static unsigned char *dhcp_skip_opts(unsigned char *start)
 1668: {
 1669:   while (*start != 0)
 1670:     start += start[1] + 2;
 1671:   return start;
 1672: }
 1673: 
 1674: /* only for use when building packet: doesn't check for bad data. */ 
 1675: static unsigned char *find_overload(struct dhcp_packet *mess)
 1676: {
 1677:   unsigned char *p = &mess->options[0] + sizeof(u32);
 1678:   
 1679:   while (*p != 0)
 1680:     {
 1681:       if (*p == OPTION_OVERLOAD)
 1682: 	return p;
 1683:       p += p[1] + 2;
 1684:     }
 1685:   return NULL;
 1686: }
 1687: 
 1688: static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
 1689: {
 1690:   unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
 1691:   unsigned char *overload;
 1692:   size_t ret;
 1693:   
 1694:   /* move agent_id back down to the end of the packet */
 1695:   if (agent_id)
 1696:     {
 1697:       memmove(p, agent_id, real_end - agent_id);
 1698:       p += real_end - agent_id;
 1699:       memset(p, 0, real_end - p); /* in case of overlap */
 1700:     }
 1701:   
 1702:   /* add END options to the regions. */
 1703:   overload = find_overload(mess);
 1704:   
 1705:   if (overload && (option_uint(overload, 0, 1) & 1))
 1706:     {
 1707:       *dhcp_skip_opts(mess->file) = OPTION_END;
 1708:       if (option_bool(OPT_LOG_OPTS))
 1709: 	log_options(mess->file, mess->xid);
 1710:     }
 1711:   else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
 1712:     my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
 1713:   
 1714:   if (overload && (option_uint(overload, 0, 1) & 2))
 1715:     {
 1716:       *dhcp_skip_opts(mess->sname) = OPTION_END;
 1717:       if (option_bool(OPT_LOG_OPTS))
 1718: 	log_options(mess->sname, mess->xid);
 1719:     }
 1720:   else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
 1721:     my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
 1722: 
 1723: 
 1724:   *p++ = OPTION_END;
 1725:   
 1726:   if (option_bool(OPT_LOG_OPTS))
 1727:     {
 1728:       if (mess->siaddr.s_addr != 0)
 1729: 	my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
 1730:       
 1731:       if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0)
 1732: 	my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid));
 1733:       
 1734:       log_options(&mess->options[0] + sizeof(u32), mess->xid);
 1735:     } 
 1736:   
 1737:   ret = (size_t)(p - (unsigned char *)mess);
 1738:   
 1739:   if (ret < MIN_PACKETSZ)
 1740:     ret = MIN_PACKETSZ;
 1741:   
 1742:   return ret;
 1743: }
 1744: 
 1745: static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
 1746: {
 1747:   unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
 1748:   
 1749:   if (p + len + 3 >= end)
 1750:     /* not enough space in options area, try and use overload, if poss */
 1751:     {
 1752:       unsigned char *overload;
 1753:       
 1754:       if (!(overload = find_overload(mess)) &&
 1755: 	  (mess->file[0] == 0 || mess->sname[0] == 0))
 1756: 	{
 1757: 	  /* attempt to overload fname and sname areas, we've reserved space for the
 1758: 	     overflow option previuously. */
 1759: 	  overload = p;
 1760: 	  *(p++) = OPTION_OVERLOAD;
 1761: 	  *(p++) = 1;
 1762: 	}
 1763:       
 1764:       p = NULL;
 1765:       
 1766:       /* using filename field ? */
 1767:       if (overload)
 1768: 	{
 1769: 	  if (mess->file[0] == 0)
 1770: 	    overload[2] |= 1;
 1771: 	  
 1772: 	  if (overload[2] & 1)
 1773: 	    {
 1774: 	      p = dhcp_skip_opts(mess->file);
 1775: 	      if (p + len + 3 >= mess->file + sizeof(mess->file))
 1776: 		p = NULL;
 1777: 	    }
 1778: 	  
 1779: 	  if (!p)
 1780: 	    {
 1781: 	      /* try to bring sname into play (it may be already) */
 1782: 	      if (mess->sname[0] == 0)
 1783: 		overload[2] |= 2;
 1784: 	      
 1785: 	      if (overload[2] & 2)
 1786: 		{
 1787: 		  p = dhcp_skip_opts(mess->sname);
 1788: 		  if (p + len + 3 >= mess->sname + sizeof(mess->sname))
 1789: 		    p = NULL;
 1790: 		}
 1791: 	    }
 1792: 	}
 1793:       
 1794:       if (!p)
 1795: 	my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
 1796:     }
 1797:  
 1798:   if (p)
 1799:     {
 1800:       *(p++) = opt;
 1801:       *(p++) = len;
 1802:     }
 1803: 
 1804:   return p;
 1805: }
 1806: 	      
 1807: static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
 1808: {
 1809:   int i;
 1810:   unsigned char *p = free_space(mess, end, opt, len);
 1811:   
 1812:   if (p) 
 1813:     for (i = 0; i < len; i++)
 1814:       *(p++) = val >> (8 * (len - (i + 1)));
 1815: }
 1816: 
 1817: static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt, 
 1818: 			      char *string, int null_term)
 1819: {
 1820:   unsigned char *p;
 1821:   size_t len = strlen(string);
 1822: 
 1823:   if (null_term && len != 255)
 1824:     len++;
 1825: 
 1826:   if ((p = free_space(mess, end, opt, len)))
 1827:     memcpy(p, string, len);
 1828: }
 1829: 
 1830: /* return length, note this only does the data part */
 1831: static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
 1832: {
 1833:   int len = opt->len;
 1834:   
 1835:   if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
 1836:     len++;
 1837: 
 1838:   if (p && len != 0)
 1839:     {
 1840:       if (context && (opt->flags & DHOPT_ADDR))
 1841: 	{
 1842: 	  int j;
 1843: 	  struct in_addr *a = (struct in_addr *)opt->val;
 1844: 	  for (j = 0; j < opt->len; j+=INADDRSZ, a++)
 1845: 	    {
 1846: 	      /* zero means "self" (but not in vendorclass options.) */
 1847: 	      if (a->s_addr == 0)
 1848: 		memcpy(p, &context->local, INADDRSZ);
 1849: 	      else
 1850: 		memcpy(p, a, INADDRSZ);
 1851: 	      p += INADDRSZ;
 1852: 	    }
 1853: 	}
 1854:       else
 1855: 	/* empty string may be extended to "\0" by null_term */
 1856: 	memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
 1857:     }  
 1858:   return len;
 1859: }
 1860: 
 1861: static int in_list(unsigned char *list, int opt)
 1862: {
 1863:   int i;
 1864: 
 1865:    /* If no requested options, send everything, not nothing. */
 1866:   if (!list)
 1867:     return 1;
 1868:   
 1869:   for (i = 0; list[i] != OPTION_END; i++)
 1870:     if (opt == list[i])
 1871:       return 1;
 1872: 
 1873:   return 0;
 1874: }
 1875: 
 1876: static struct dhcp_opt *option_find2(int opt)
 1877: {
 1878:   struct dhcp_opt *opts;
 1879:   
 1880:   for (opts = daemon->dhcp_opts; opts; opts = opts->next)
 1881:     if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
 1882:       return opts;
 1883:   
 1884:   return NULL;
 1885: }
 1886: 
 1887: /* mark vendor-encapsulated options which match the client-supplied  or
 1888:    config-supplied vendor class */
 1889: static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
 1890: {
 1891:   for (; dopt; dopt = dopt->next)
 1892:     {
 1893:       dopt->flags &= ~DHOPT_VENDOR_MATCH;
 1894:       if (opt && (dopt->flags & DHOPT_VENDOR))
 1895: 	{
 1896: 	  int i, len = 0;
 1897: 	  if (dopt->u.vendor_class)
 1898: 	    len = strlen((char *)dopt->u.vendor_class);
 1899: 	  for (i = 0; i <= (option_len(opt) - len); i++)
 1900: 	    if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
 1901: 	      {
 1902: 		dopt->flags |= DHOPT_VENDOR_MATCH;
 1903: 		break;
 1904: 	      }
 1905: 	}
 1906:     }
 1907: }
 1908: 
 1909: static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,  
 1910: 			 struct dhcp_packet *mess, unsigned char *end, int null_term)
 1911: {
 1912:   int len, enc_len, ret = 0;
 1913:   struct dhcp_opt *start;
 1914:   unsigned char *p;
 1915:     
 1916:   /* find size in advance */
 1917:   for (enc_len = 0, start = opt; opt; opt = opt->next)
 1918:     if (opt->flags & flag)
 1919:       {
 1920: 	int new = do_opt(opt, NULL, NULL, null_term) + 2;
 1921: 	ret  = 1;
 1922: 	if (enc_len + new <= 255)
 1923: 	  enc_len += new;
 1924: 	else
 1925: 	  {
 1926: 	    p = free_space(mess, end, encap, enc_len);
 1927: 	    for (; start && start != opt; start = start->next)
 1928: 	      if (p && (start->flags & flag))
 1929: 		{
 1930: 		  len = do_opt(start, p + 2, NULL, null_term);
 1931: 		  *(p++) = start->opt;
 1932: 		  *(p++) = len;
 1933: 		  p += len;
 1934: 		}
 1935: 	    enc_len = new;
 1936: 	    start = opt;
 1937: 	  }
 1938:       }
 1939:   
 1940:   if (enc_len != 0 &&
 1941:       (p = free_space(mess, end, encap, enc_len + 1)))
 1942:     {
 1943:       for (; start; start = start->next)
 1944: 	if (start->flags & flag)
 1945: 	  {
 1946: 	    len = do_opt(start, p + 2, NULL, null_term);
 1947: 	    *(p++) = start->opt;
 1948: 	    *(p++) = len;
 1949: 	    p += len;
 1950: 	  }
 1951:       *p = OPTION_END;
 1952:     }
 1953: 
 1954:   return ret;
 1955: }
 1956: 
 1957: static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
 1958: {
 1959:   unsigned char *p;
 1960: 
 1961:   option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
 1962:   if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
 1963:     memcpy(p, uuid, 17);
 1964: }
 1965: 
 1966: static int prune_vendor_opts(struct dhcp_netid *netid)
 1967: {
 1968:   int force = 0;
 1969:   struct dhcp_opt *opt;
 1970: 
 1971:   /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
 1972:   for (opt = daemon->dhcp_opts; opt; opt = opt->next)
 1973:     if (opt->flags & DHOPT_VENDOR_MATCH)
 1974:       {
 1975: 	if (!match_netid(opt->netid, netid, 1))
 1976: 	  opt->flags &= ~DHOPT_VENDOR_MATCH;
 1977: 	else if (opt->flags & DHOPT_FORCE)
 1978: 	  force = 1;
 1979:       }
 1980:   return force;
 1981: }
 1982: 
 1983: static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
 1984: {
 1985: #define NUM_OPTS 4  
 1986: 
 1987:   unsigned  char *p, *q;
 1988:   struct pxe_service *service;
 1989:   static struct dhcp_opt *o, *ret;
 1990:   int i, j = NUM_OPTS - 1;
 1991:   struct in_addr boot_server;
 1992:   
 1993:   /* We pass back references to these, hence they are declared static */
 1994:   static unsigned char discovery_control;
 1995:   static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' }; 
 1996:   static struct dhcp_opt *fake_opts = NULL;
 1997:   
 1998:   /* Disable multicast, since we don't support it, and broadcast
 1999:      unless we need it */
 2000:   discovery_control = 3;
 2001:   
 2002:   ret = daemon->dhcp_opts;
 2003:   
 2004:   if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
 2005:     return ret;
 2006: 
 2007:   for (i = 0; i < NUM_OPTS; i++)
 2008:     {
 2009:       fake_opts[i].flags = DHOPT_VENDOR_MATCH;
 2010:       fake_opts[i].netid = NULL;
 2011:       fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
 2012:     }
 2013:   
 2014:   /* create the data for the PXE_MENU and PXE_SERVERS options. */
 2015:   p = (unsigned char *)daemon->dhcp_buff;
 2016:   q = (unsigned char *)daemon->dhcp_buff3;
 2017: 
 2018:   for (i = 0, service = daemon->pxe_services; service; service = service->next)
 2019:     if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
 2020:       {
 2021: 	size_t len = strlen(service->menu);
 2022: 	/* opt 43 max size is 255. encapsulated option has type and length
 2023: 	   bytes, so its max size is 253. */
 2024: 	if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
 2025: 	  {
 2026: 	    *(p++) = service->type >> 8;
 2027: 	    *(p++) = service->type;
 2028: 	    *(p++) = len;
 2029: 	    memcpy(p, service->menu, len);
 2030: 	    p += len;
 2031: 	    i++;
 2032: 	  }
 2033: 	else
 2034: 	  {
 2035: 	  toobig:
 2036: 	    my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
 2037: 	    return daemon->dhcp_opts;
 2038: 	  }
 2039: 	
 2040: 	boot_server = service->basename ? local : 
 2041: 	  (service->sname ? a_record_from_hosts(service->sname, now) : service->server);
 2042: 	
 2043: 	if (boot_server.s_addr != 0)
 2044: 	  {
 2045: 	    if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
 2046: 	      goto toobig;
 2047: 	    
 2048: 	    /* Boot service with known address - give it */
 2049: 	    *(q++) = service->type >> 8;
 2050: 	    *(q++) = service->type;
 2051: 	    *(q++) = 1;
 2052: 	    /* dest misaligned */
 2053: 	    memcpy(q, &boot_server.s_addr, INADDRSZ);
 2054: 	    q += INADDRSZ;
 2055: 	  }
 2056: 	else if (service->type != 0)
 2057: 	  /* We don't know the server for a service type, so we'll
 2058: 	     allow the client to broadcast for it */
 2059: 	  discovery_control = 2;
 2060:       }
 2061: 
 2062:   /* if no prompt, wait forever if there's a choice */
 2063:   fake_prompt[0] = (i > 1) ? 255 : 0;
 2064:   
 2065:   if (i == 0)
 2066:     discovery_control = 8; /* no menu - just use use mess->filename */
 2067:   else
 2068:     {
 2069:       ret = &fake_opts[j--];
 2070:       ret->len = p - (unsigned char *)daemon->dhcp_buff;
 2071:       ret->val = (unsigned char *)daemon->dhcp_buff;
 2072:       ret->opt = SUBOPT_PXE_MENU;
 2073: 
 2074:       if (q - (unsigned char *)daemon->dhcp_buff3 != 0)
 2075: 	{
 2076: 	  ret = &fake_opts[j--]; 
 2077: 	  ret->len = q - (unsigned char *)daemon->dhcp_buff3;
 2078: 	  ret->val = (unsigned char *)daemon->dhcp_buff3;
 2079: 	  ret->opt = SUBOPT_PXE_SERVERS;
 2080: 	}
 2081:     }
 2082: 
 2083:   for (o = daemon->dhcp_opts; o; o = o->next)
 2084:     if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
 2085:       break;
 2086:   
 2087:   if (!o)
 2088:     {
 2089:       ret = &fake_opts[j--]; 
 2090:       ret->len = sizeof(fake_prompt);
 2091:       ret->val = fake_prompt;
 2092:       ret->opt = SUBOPT_PXE_MENU_PROMPT;
 2093:     }
 2094:   
 2095:   ret = &fake_opts[j--]; 
 2096:   ret->len = 1;
 2097:   ret->opt = SUBOPT_PXE_DISCOVERY;
 2098:   ret->val= &discovery_control;
 2099:  
 2100:   return ret;
 2101: }
 2102:   
 2103: static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
 2104: {
 2105:   memset(mess->sname, 0, sizeof(mess->sname));
 2106:   memset(mess->file, 0, sizeof(mess->file));
 2107:   memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
 2108:   mess->siaddr.s_addr = 0;
 2109: }
 2110: 
 2111: struct dhcp_boot *find_boot(struct dhcp_netid *netid)
 2112: {
 2113:   struct dhcp_boot *boot;
 2114: 
 2115:   /* decide which dhcp-boot option we're using */
 2116:   for (boot = daemon->boot_config; boot; boot = boot->next)
 2117:     if (match_netid(boot->netid, netid, 0))
 2118:       break;
 2119:   if (!boot)
 2120:     /* No match, look for one without a netid */
 2121:     for (boot = daemon->boot_config; boot; boot = boot->next)
 2122:       if (match_netid(boot->netid, netid, 1))
 2123: 	break;
 2124: 
 2125:   return boot;
 2126: }
 2127: 
 2128: static void do_options(struct dhcp_context *context,
 2129: 		       struct dhcp_packet *mess,
 2130: 		       unsigned char *end, 
 2131: 		       unsigned char *req_options,
 2132: 		       char *hostname, 
 2133: 		       char *domain,
 2134: 		       struct dhcp_netid *netid,
 2135: 		       struct in_addr subnet_addr,
 2136: 		       unsigned char fqdn_flags,
 2137: 		       int null_term, int pxe_arch,
 2138: 		       unsigned char *uuid,
 2139: 		       int vendor_class_len,
 2140: 		       time_t now)
 2141: {
 2142:   struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
 2143:   struct dhcp_boot *boot;
 2144:   unsigned char *p;
 2145:   int i, len, force_encap = 0;
 2146:   unsigned char f0 = 0, s0 = 0;
 2147:   int done_file = 0, done_server = 0;
 2148:   int done_vendor_class = 0;
 2149:   struct dhcp_netid *tagif;
 2150:   struct dhcp_netid_list *id_list;
 2151: 
 2152:   /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
 2153:   if (context)
 2154:     context->netid.next = NULL;
 2155:   tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
 2156: 	
 2157:   /* logging */
 2158:   if (option_bool(OPT_LOG_OPTS) && req_options)
 2159:     {
 2160:       char *q = daemon->namebuff;
 2161:       for (i = 0; req_options[i] != OPTION_END; i++)
 2162: 	{
 2163: 	  char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
 2164: 	  q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
 2165: 			"%d%s%s%s", 
 2166: 			req_options[i],
 2167: 			strlen(s) != 0 ? ":" : "",
 2168: 			s, 
 2169: 			req_options[i+1] == OPTION_END ? "" : ", ");
 2170: 	  if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
 2171: 	    {
 2172: 	      q = daemon->namebuff;
 2173: 	      my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
 2174: 	    }
 2175: 	}
 2176:     }
 2177:       
 2178:   for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
 2179:     if ((!id_list->list) || match_netid(id_list->list, netid, 0))
 2180:       break;
 2181:   if (id_list)
 2182:     mess->flags |= htons(0x8000); /* force broadcast */
 2183:   
 2184:   if (context)
 2185:     mess->siaddr = context->local;
 2186:   
 2187:   /* See if we can send the boot stuff as options.
 2188:      To do this we need a requested option list, BOOTP
 2189:      and very old DHCP clients won't have this, we also 
 2190:      provide an manual option to disable it.
 2191:      Some PXE ROMs have bugs (surprise!) and need zero-terminated 
 2192:      names, so we always send those.  */
 2193:   if ((boot = find_boot(tagif)))
 2194:     {
 2195:       if (boot->sname)
 2196: 	{	  
 2197: 	  if (!option_bool(OPT_NO_OVERRIDE) &&
 2198: 	      req_options && 
 2199: 	      in_list(req_options, OPTION_SNAME))
 2200: 	    option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
 2201: 	  else
 2202: 	    strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
 2203: 	}
 2204:       
 2205:       if (boot->file)
 2206: 	{
 2207: 	  if (!option_bool(OPT_NO_OVERRIDE) &&
 2208: 	      req_options && 
 2209: 	      in_list(req_options, OPTION_FILENAME))
 2210: 	    option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
 2211: 	  else
 2212: 	    strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
 2213: 	}
 2214:       
 2215:       if (boot->next_server.s_addr) 
 2216: 	mess->siaddr = boot->next_server;
 2217:       else if (boot->tftp_sname)
 2218: 	mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
 2219:     }
 2220:   else
 2221:     /* Use the values of the relevant options if no dhcp-boot given and
 2222:        they're not explicitly asked for as options. OPTION_END is used
 2223:        as an internal way to specify siaddr without using dhcp-boot, for use in
 2224:        dhcp-optsfile. */
 2225:     {
 2226:       if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
 2227: 	  (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
 2228: 	{
 2229: 	  strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
 2230: 	  done_file = 1;
 2231: 	}
 2232:       
 2233:       if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
 2234: 	  (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
 2235: 	{
 2236: 	  strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
 2237: 	  done_server = 1;
 2238: 	}
 2239:       
 2240:       if ((opt = option_find2(OPTION_END)))
 2241: 	mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;	
 2242:     }
 2243:         
 2244:   /* We don't want to do option-overload for BOOTP, so make the file and sname
 2245:      fields look like they are in use, even when they aren't. This gets restored
 2246:      at the end of this function. */
 2247: 
 2248:   if (!req_options || option_bool(OPT_NO_OVERRIDE))
 2249:     {
 2250:       f0 = mess->file[0];
 2251:       mess->file[0] = 1;
 2252:       s0 = mess->sname[0];
 2253:       mess->sname[0] = 1;
 2254:     }
 2255:       
 2256:   /* At this point, if mess->sname or mess->file are zeroed, they are available
 2257:      for option overload, reserve space for the overload option. */
 2258:   if (mess->file[0] == 0 || mess->sname[0] == 0)
 2259:     end -= 3;
 2260: 
 2261:   /* rfc3011 says this doesn't need to be in the requested options list. */
 2262:   if (subnet_addr.s_addr)
 2263:     option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
 2264:   
 2265:   /* replies to DHCPINFORM may not have a valid context */
 2266:   if (context)
 2267:     {
 2268:       if (!option_find2(OPTION_NETMASK))
 2269: 	option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
 2270:   
 2271:       /* May not have a "guessed" broadcast address if we got no packets via a relay
 2272: 	 from this net yet (ie just unicast renewals after a restart */
 2273:       if (context->broadcast.s_addr &&
 2274: 	  !option_find2(OPTION_BROADCAST))
 2275: 	option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
 2276:       
 2277:       /* Same comments as broadcast apply, and also may not be able to get a sensible
 2278: 	 default when using subnet select.  User must configure by steam in that case. */
 2279:       if (context->router.s_addr &&
 2280: 	  in_list(req_options, OPTION_ROUTER) &&
 2281: 	  !option_find2(OPTION_ROUTER))
 2282: 	option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
 2283:       
 2284:       if (daemon->port == NAMESERVER_PORT &&
 2285: 	  in_list(req_options, OPTION_DNSSERVER) &&
 2286: 	  !option_find2(OPTION_DNSSERVER))
 2287: 	option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
 2288:     }
 2289: 
 2290:   if (domain && in_list(req_options, OPTION_DOMAINNAME) && 
 2291:       !option_find2(OPTION_DOMAINNAME))
 2292:     option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
 2293:  
 2294:   /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
 2295:   if (hostname)
 2296:     {
 2297:       if (in_list(req_options, OPTION_HOSTNAME) &&
 2298: 	  !option_find2(OPTION_HOSTNAME))
 2299: 	option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
 2300:       
 2301:       if (fqdn_flags != 0)
 2302: 	{
 2303: 	  len = strlen(hostname) + 3;
 2304: 	  
 2305: 	  if (fqdn_flags & 0x04)
 2306: 	    len += 2;
 2307: 	  else if (null_term)
 2308: 	    len++;
 2309: 
 2310: 	  if (domain)
 2311: 	    len += strlen(domain) + 1;
 2312: 	  else if (fqdn_flags & 0x04)
 2313: 	    len--;
 2314: 
 2315: 	  if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
 2316: 	    {
 2317: 	      *(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */ 
 2318: 	      *(p++) = 255;
 2319: 	      *(p++) = 255;
 2320: 
 2321: 	      if (fqdn_flags & 0x04)
 2322: 		{
 2323: 		  p = do_rfc1035_name(p, hostname);
 2324: 		  if (domain)
 2325: 		    {
 2326: 		      p = do_rfc1035_name(p, domain);
 2327: 		      *p++ = 0;
 2328: 		    }
 2329: 		}
 2330: 	      else
 2331: 		{
 2332: 		  memcpy(p, hostname, strlen(hostname));
 2333: 		  p += strlen(hostname);
 2334: 		  if (domain)
 2335: 		    {
 2336: 		      *(p++) = '.';
 2337: 		      memcpy(p, domain, strlen(domain));
 2338: 		      p += strlen(domain);
 2339: 		    }
 2340: 		  if (null_term)
 2341: 		    *(p++) = 0;
 2342: 		}
 2343: 	    }
 2344: 	}
 2345:     }      
 2346: 
 2347:   for (opt = config_opts; opt; opt = opt->next)
 2348:     {
 2349:       int optno = opt->opt;
 2350: 
 2351:       /* netids match and not encapsulated? */
 2352:       if (!(opt->flags & DHOPT_TAGOK))
 2353: 	continue;
 2354:       
 2355:       /* was it asked for, or are we sending it anyway? */
 2356:       if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
 2357: 	continue;
 2358:       
 2359:       /* prohibit some used-internally options */
 2360:       if (optno == OPTION_CLIENT_FQDN ||
 2361: 	  optno == OPTION_MAXMESSAGE ||
 2362: 	  optno == OPTION_OVERLOAD ||
 2363: 	  optno == OPTION_PAD ||
 2364: 	  optno == OPTION_END)
 2365: 	continue;
 2366: 
 2367:       if (optno == OPTION_SNAME && done_server)
 2368: 	continue;
 2369: 
 2370:       if (optno == OPTION_FILENAME && done_file)
 2371: 	continue;
 2372:       
 2373:       /* For the options we have default values on
 2374: 	 dhc-option=<optionno> means "don't include this option"
 2375: 	 not "include a zero-length option" */
 2376:       if (opt->len == 0 && 
 2377: 	  (optno == OPTION_NETMASK ||
 2378: 	   optno == OPTION_BROADCAST ||
 2379: 	   optno == OPTION_ROUTER ||
 2380: 	   optno == OPTION_DNSSERVER || 
 2381: 	   optno == OPTION_DOMAINNAME ||
 2382: 	   optno == OPTION_HOSTNAME))
 2383: 	continue;
 2384: 
 2385:       /* vendor-class comes from elsewhere for PXE */
 2386:       if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
 2387: 	continue;
 2388:       
 2389:       /* always force null-term for filename and servername - buggy PXE again. */
 2390:       len = do_opt(opt, NULL, context, 
 2391: 		   (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
 2392: 
 2393:       if ((p = free_space(mess, end, optno, len)))
 2394: 	{
 2395: 	  do_opt(opt, p, context, 
 2396: 		 (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
 2397: 	  
 2398: 	  /* If we send a vendor-id, revisit which vendor-ops we consider 
 2399: 	     it appropriate to send. */
 2400: 	  if (optno == OPTION_VENDOR_ID)
 2401: 	    {
 2402: 	      match_vendor_opts(p - 2, config_opts);
 2403: 	      done_vendor_class = 1;
 2404: 	    }
 2405: 	}  
 2406:     }
 2407: 
 2408:   /* Now send options to be encapsulated in arbitrary options, 
 2409:      eg dhcp-option=encap:172,17,.......
 2410:      Also handle vendor-identifying vendor-encapsulated options,
 2411:      dhcp-option = vi-encap:13,17,.......
 2412:      The may be more that one "outer" to do, so group
 2413:      all the options which match each outer in turn. */
 2414:   for (opt = config_opts; opt; opt = opt->next)
 2415:     opt->flags &= ~DHOPT_ENCAP_DONE;
 2416:   
 2417:   for (opt = config_opts; opt; opt = opt->next)
 2418:     {
 2419:       int flags;
 2420:       
 2421:       if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
 2422: 	{
 2423: 	  int found = 0;
 2424: 	  struct dhcp_opt *o;
 2425: 
 2426: 	  if (opt->flags & DHOPT_ENCAP_DONE)
 2427: 	    continue;
 2428: 
 2429: 	  for (len = 0, o = config_opts; o; o = o->next)
 2430: 	    {
 2431: 	      int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
 2432: 
 2433: 	      o->flags &= ~DHOPT_ENCAP_MATCH;
 2434: 	      
 2435: 	      if (!(o->flags & flags) || opt->u.encap != o->u.encap)
 2436: 		continue;
 2437: 	      
 2438: 	      o->flags |= DHOPT_ENCAP_DONE;
 2439: 	      if (match_netid(o->netid, tagif, 1) &&
 2440: 		  ((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
 2441: 		{
 2442: 		  o->flags |= DHOPT_ENCAP_MATCH;
 2443: 		  found = 1;
 2444: 		  len += do_opt(o, NULL, NULL, 0) + 2;
 2445: 		}
 2446: 	    } 
 2447: 	  
 2448: 	  if (found)
 2449: 	    { 
 2450: 	      if (flags & DHOPT_ENCAPSULATE)
 2451: 		do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
 2452: 	      else if (len > 250)
 2453: 		my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
 2454: 	      else if ((p = free_space(mess, end,  OPTION_VENDOR_IDENT_OPT, len + 5)))
 2455: 		{
 2456: 		  int swap_ent = htonl(opt->u.encap);
 2457: 		  memcpy(p, &swap_ent, 4);
 2458: 		  p += 4;
 2459: 		  *(p++) = len;
 2460: 		  for (o = config_opts; o; o = o->next)
 2461: 		    if (o->flags & DHOPT_ENCAP_MATCH)
 2462: 		      {
 2463: 			len = do_opt(o, p + 2, NULL, 0);
 2464: 			*(p++) = o->opt;
 2465: 			*(p++) = len;
 2466: 			p += len;
 2467: 		      }     
 2468: 		}
 2469: 	    }
 2470: 	}
 2471:     }      
 2472: 
 2473:   force_encap = prune_vendor_opts(tagif);
 2474:   
 2475:   if (context && pxe_arch != -1)
 2476:     {
 2477:       pxe_misc(mess, end, uuid);
 2478:       config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
 2479:     }
 2480: 
 2481:   if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
 2482:       do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term) && 
 2483:       pxe_arch == -1 && !done_vendor_class && vendor_class_len != 0 &&
 2484:       (p = free_space(mess, end, OPTION_VENDOR_ID, vendor_class_len)))
 2485:     /* If we send vendor encapsulated options, and haven't already sent option 60,
 2486:        echo back the value we got from the client. */
 2487:     memcpy(p, daemon->dhcp_buff3, vendor_class_len);	    
 2488:    
 2489:    /* restore BOOTP anti-overload hack */
 2490:   if (!req_options || option_bool(OPT_NO_OVERRIDE))
 2491:     {
 2492:       mess->file[0] = f0;
 2493:       mess->sname[0] = s0;
 2494:     }
 2495: }
 2496: 
 2497: #endif
 2498:   
 2499: 
 2500:   
 2501:   
 2502: 
 2503: 
 2504:   

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>