Logo Search packages:      
Sourcecode: ike version File versions  Download package

ike.exch.config.cpp

/*
 * Copyright (c) 2007
 *      Shrew Soft Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Redistributions in any form must be accompanied by information on
 *    how to obtain complete source code for the software and any
 *    accompanying software that uses the software.  The source code
 *    must either be included in the distribution or be available for no
 *    more than the cost of distribution plus a nominal fee, and must be
 *    freely redistributable under reasonable conditions.  For an
 *    executable file, complete source code means the source code for all
 *    modules it contains.  It does not include source code for modules or
 *    files that typically accompany the major components of the operating
 *    system on which the executable file runs.
 *
 * THIS SOFTWARE IS PROVIDED BY SHREW SOFT INC ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO EVENT SHALL SHREW SOFT INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * AUTHOR : Matthew Grooms
 *          mgrooms@shrew.net
 *
 */

#include "iked.h"

long _IKED::process_config_recv( IDB_PH1 * ph1, PACKET_IKE & packet, unsigned char payload )
{
      long result = LIBIKE_OK;

      //
      // log packet type
      //

      log.txt( LLOG_INFO,
            "ii : processing config packet ( %i bytes )\n",
            packet.size() );

      //
      // attempt to locate a known
      // config for this phase1
      //

      uint32_t msgid = packet.get_msgid();

      IDB_CFG * cfg = NULL;
      if( !idb_list_cfg.find( true, &cfg, ph1 ) )
      {
            //
            // create new object config object
            //

            cfg = new IDB_CFG( ph1, false );
            cfg->add( true );
      }

      //
      // if the msgid has changed, set the
      // config msgid value and the iv
      //

      if( cfg->msgid != msgid )
      {
            cfg->msgid = msgid;
            cfg->new_msgiv( ph1 );
      }

      //
      // make sure we are not dealing
      // with an sa marked for delete
      //

      if( ph1->status() == XCH_STATUS_DEAD )
      {
            log.txt( LLOG_ERROR, "!! : config packet ignored ( phase1 marked for death )\n" );
            cfg->dec( true );
            return LIBIKE_OK;
      }

      if( cfg->status() == XCH_STATUS_DEAD )
      {
            log.txt( LLOG_ERROR, "!! : config packet ignored ( config marked for death )\n" );
            cfg->dec( true );
            return LIBIKE_OK;
      }

      //
      // make sure we are not dealing
      // whith an imature phase1 sa
      //

      if( ph1->status() < XCH_STATUS_MATURE )
      {
            log.txt( LLOG_ERROR, "!! : config packet ignored ( phase1 not mature )\n" );
            cfg->dec( true );
            return LIBIKE_OK;
      }

      //
      // make sure we are not dealing
      // with a mature sa
      //

      if( cfg->status() >= XCH_STATUS_MATURE )
      {
            log.txt( LLOG_ERROR, "!! : config packet ignored, ( config already mature )\n" );
            cfg->dec( true );
            return LIBIKE_OK;
      }

      //
      // decrypt packet
      //

      if( packet_ike_decrypt( ph1, packet, &cfg->iv ) != LIBIKE_OK )
      {
            log.txt( LLOG_ERROR, "!! : config packet ignored ( packet decryption error )\n" );
            cfg->dec( true );
            return LIBIKE_OK;
      }

      //
      // if we are dumping decrypted packets,
      // we need to rebuild a full packet to
      // dump to pcap format 
      //

      if( dump_decrypt )
      {
            //
            // strip the isakmp encryption flag
            //

            packet.buff()[ ISAKMP_FLAGS_OFFSET ] &= ~ISAKMP_FLAG_ENCRYPT;

            //
            // build ip dump packet
            //

            PACKET_IP packet_ip_dump;
            packet_ike_encap(
                  packet,
                  packet_ip_dump,
                  cfg->tunnel->saddr_r,
                  cfg->tunnel->saddr_l,
                  cfg->tunnel->natt_version );

            //
            // obtain ethernet header
            //

            ETH_HEADER ethhdr;
            header( packet_ip_dump, ethhdr );

            //
            // dump the packet
            //

            pcap_decrypt.dump(
                  ethhdr,
                  packet_ip_dump );
      }

      //
      // read and process all payloads
      //

      cfg->hda.del();
      cfg->attr_reset();

      while( payload != ISAKMP_PAYLOAD_NONE )
      {
            //
            // read the payload header
            //

            uint8_t next_payload;
            if( !packet.get_payload( false, next_payload ) )
                  break;

            //
            // check the payload type
            //

            switch( payload )
            {
                  //
                  // hash payload
                  //

                  case ISAKMP_PAYLOAD_HASH:
                  {
                        result = payload_get_hash( packet, cfg->hash_r, ph1->hash_size );

                        cfg->xstate |= XSTATE_RECV_HA;

                        break;
                  }

                  //
                  // attribute payload
                  //

                  case ISAKMP_PAYLOAD_ATTRIB:
                  {
                        size_t beg = packet.oset() - 4;
                        result = payload_get_cfglist( packet, cfg );
                        size_t end = packet.oset();
                        cfg->hda.add( packet.buff() + beg, end - beg );

                        break;
                  }

                  //
                  // unhandled payload
                  //

                  default:

                        log.txt( LLOG_ERROR,
                              "!! : unhandled config payload \'%s\' ( %i )\n",
                              find_name( NAME_PAYLOAD, payload ),
                              payload );

                        result = LIBIKE_FAILED;

                        break;
            }

            //
            // was the entire payload read
            //

            if( packet.get_payload_left() )
                  log.txt( LLOG_ERROR, "!! : unprocessed payload data !!!\n" );

            //
            // check the result
            //

            if( result != LIBIKE_OK )
            {
                  //
                  // flag sa for removal
                  //

                  ph1->status( XCH_STATUS_DEAD, XCH_FAILED_MSG_FORMAT, packet.notify );
                  cfg->dec( true );

                  return result;
            }

            //
            // read next payload
            //

            payload = next_payload;
      }

      //
      // now that all payloads have been read,
      // validate any received hash values
      //

      if( config_chk_hash( ph1, cfg, msgid ) != LIBIKE_OK )
      {
            //
            // update status and release
            //

            ph1->status( XCH_STATUS_DEAD, XCH_FAILED_MSG_AUTH, ISAKMP_N_INVALID_HASH_INFORMATION );
            cfg->dec( true );

            return LIBIKE_FAILED;
      }

      //
      // hanlde server to client messages
      //

      while( ph1->initiator )
      {
            //
            // handle xauth messages
            //

            if( ph1->vendopts_l.flag.xauth )
                  if( !( cfg->xstate & CSTATE_RECV_XRSLT ) )
                        if( !config_client_xauth_recv( cfg, ph1 ) )
                              break;

            //
            // handle modecfg pull messages
            //

            if( cfg->tunnel->peer->xconf_mode == CONFIG_MODE_PULL )
                  if( !( cfg->xstate & CSTATE_RECV_XCONF ) )
                        if( !config_client_xconf_pull_recv( cfg, ph1 ) )
                              break;

            //
            // handle modecfg push messages
            //

            if( cfg->tunnel->peer->xconf_mode == CONFIG_MODE_PUSH )
                  if( !( cfg->xstate & CSTATE_RECV_XCONF ) )
                        if( !config_client_xconf_push_recv( cfg, ph1 ) )
                              break;

            //
            // unexpected message
            //

            break;
      }

      //
      // now build and send any response
      // packets that may be necessary
      //

      if( ( ph1->status() != XCH_STATUS_DEAD ) &&
            ( cfg->status() != XCH_STATUS_MATURE ) )
            process_config_send( ph1, cfg );

      //
      // cleanup
      //

      cfg->dec( true );

      return LIBIKE_OK;
}

long _IKED::process_config_send( IDB_PH1 * ph1, IDB_CFG * cfg )
{
      cfg->attr_reset();

      //
      // hanlde server to client messages
      //

      while( ph1->initiator )
      {
            //
            // handle xauth messages
            //

            if( ph1->vendopts_l.flag.xauth )
                  if( !( cfg->xstate & CSTATE_SENT_XRSLT ) )
                        if( !config_client_xauth_send( cfg, ph1 ) )
                              break;

            //
            // handle modecfg pull messages
            //

            if( cfg->tunnel->peer->xconf_mode == CONFIG_MODE_PULL )
                  if( !( cfg->xstate & CSTATE_SENT_ACK ) )
                        if( !config_client_xconf_pull_send( cfg, ph1 ) )
                              break;

            //
            // handle modecfg push messages
            //

            if( cfg->tunnel->peer->xconf_mode == CONFIG_MODE_PUSH )
                  if( !( cfg->xstate & CSTATE_SENT_ACK ) )
                        if( !config_client_xconf_push_send( cfg, ph1 ) )
                              break;

            //
            // handle dhcp over ipsec
            //

            if( cfg->tunnel->peer->xconf_mode == CONFIG_MODE_DHCP )
            {
                  log.txt( LLOG_INFO, "ii : configuration method is DHCP over IPsec \n" );
                  socket_dhcp_create( ph1->tunnel );
                  break;
            }

            //
            // handle manual config
            //

            if( ph1->tunnel->peer->xconf_mode == CONFIG_MODE_NONE )
            {
                  log.txt( LLOG_INFO, "ii : configuration method is manual\n" );
                  break;
            }

            //
            // unexpected message
            //

            break;
      }

      //
      // if all required operations are
      // complete, make sure the config
      // handle is flagged as mature
      //

      if( ( cfg->xstate & CSTATE_RECV_XRSLT ) &&
            ( cfg->xstate & CSTATE_SENT_XRSLT ) &&
            ( cfg->xstate & CSTATE_RECV_XCONF ) &&
            ( cfg->xstate & CSTATE_SENT_XCONF ) )
      {
            if( cfg->tunnel->peer->xconf_mode != CONFIG_MODE_DHCP )
            {
                  cfg->tunnel->tstate |= TSTATE_VNET_CONFIG;
                  cfg->tunnel->ikei->wakeup();
            }

            cfg->status( XCH_STATUS_MATURE, XCH_NORMAL, 0 );
            cfg->resend_clear( true, false );
      }

      return LIBIKE_OK;
}

bool _IKED::config_client_xauth_recv( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      //
      // expecting xauth request
      //

      if( cfg->mtype == ISAKMP_CFG_REQUEST )
      {
            //
            // if we have have previously received a
            // comlete xauth request, authentication
            // failed and the gateway is prompting
            // us for an alternate user & password
            //

            if( ( cfg->xstate & CSTATE_RECV_XUSER ) &&
                  ( cfg->xstate & CSTATE_RECV_XPASS ) )
            {
                  log.txt( LLOG_ERROR, "!! : duplicate xauth request, authentication failed\n" );
                  ph1->status( XCH_STATUS_DEAD, XCH_FAILED_USER_AUTH, 0 );

                  return false;
            }

            //
            // read the request attributes
            //

            cfg->tunnel->xauth.type = XAUTH_TYPE_GENERIC;

            BDATA message;

            long count = cfg->attr_count();
            long index = 0;

            for( ; index < count; index++ )
            {
                  IKE_ATTR * attr = cfg->attr_get( index );

                  switch( attr->atype )
                  {
                        case XAUTH_TYPE:
                        case CHKPT_TYPE:
                              if( attr->basic )
                                    cfg->tunnel->xauth.type = attr->bdata;
                              log.txt( LLOG_INFO, "ii : - xauth authentication type\n" );
                              break;

                        case XAUTH_USER_NAME:
                        case CHKPT_USER_NAME:
                              cfg->xstate |= CSTATE_RECV_XUSER;
                              log.txt( LLOG_INFO, "ii : - xauth username\n" );
                              break;

                        case XAUTH_USER_PASSWORD:
                        case CHKPT_USER_PASSWORD:
                              cfg->xstate |= CSTATE_RECV_XPASS;
                              log.txt( LLOG_INFO, "ii : - xauth password\n" );
                              break;

                        case XAUTH_PASSCODE:
                              cfg->xstate |= CSTATE_RECV_XPASS | CSTATE_USE_PASSCODE;
                              log.txt( LLOG_INFO, "ii : - xauth passcode\n" );
                              break;

                        case XAUTH_CHALLENGE:
                        case CHKPT_CHALLENGE:
                              cfg->xstate |= CSTATE_RECV_XPASS;
                              log.txt( LLOG_INFO, "ii : - xauth challenge\n" );
                              if( !attr->basic )
                                    cfg->tunnel->xauth.hash = attr->vdata;
                              break;

                        case XAUTH_MESSAGE:
                        case CHKPT_MESSAGE:
                              if( !attr->basic )
                                    message.add( attr->vdata );
                              break;

                        default:
                              log.txt( LLOG_INFO, "!! : warning, unhandled xauth attribute %i\n", attr->atype );
                              break;
                  }
            }

            message.add( 0, 1 );

            //
            // examine the xauth request
            //

            switch( cfg->tunnel->xauth.type )
            {
                  case XAUTH_TYPE_GENERIC:
                        log.txt( LLOG_INFO,
                              "ii : received basic xauth request - %s\n",
                              message.text() );
                        break;

                  case XAUTH_TYPE_RADIUS_CHAP:
                        log.txt( LLOG_INFO,
                              "ii : received chap xauth request - %s\n",
                              message.text() );
                        break;

                  default:
                        log.txt( LLOG_ERROR,
                              "!! : received unhandled xauth request type\n" );
                        ph1->status( XCH_STATUS_DEAD, XCH_FAILED_MSG_FORMAT, 0 );
                        break;
            }

            return false;
      }

      //
      // expecting xauth response
      //

      if( cfg->mtype == ISAKMP_CFG_SET )
      {
            //
            // read the result attributes
            //

            BDATA message;

            long count = cfg->attr_count();
            long index = 0;
            long status = -1;

            for( ; index < count; index++ )
            {
                  IKE_ATTR * attr = cfg->attr_get( index );

                  switch( attr->atype )
                  {
                        case XAUTH_STATUS:
                        case CHKPT_STATUS:
                              if( attr->basic )
                                    status = attr->bdata;
                                    break;

                        case XAUTH_MESSAGE:
                        case CHKPT_MESSAGE:
                              if( !attr->basic )
                                    message.add( attr->vdata );
                              break;
                  }
            }

            message.add( 0, 1 );

            //
            // make sure we received a status value
            //

            if( status == -1 )
            {
                  //
                  // some gateways will send a config push
                  // message before an xauth response. in
                  // this case, call the correct handler
                  //

                  if( cfg->tunnel->peer->xconf_mode == CONFIG_MODE_PUSH )
                        return config_client_xconf_push_recv( cfg, ph1 );

                  log.txt( LLOG_ERROR,
                        "!! : no xauth status received and config mode is not push\n" );

                  ph1->status( XCH_STATUS_DEAD, XCH_FAILED_MSG_FORMAT, 0 );

                  return false;
            }

            //
            // examine the xauth result
            //

            log.txt( LLOG_INFO, "ii : received xauth result - %s\n", message.text() );

            BDATA user;
            user = cfg->tunnel->xauth.user;
            user.add( 0, 1 );

            if( status == 1 )
            {
                  log.txt( LLOG_INFO,
                        "ii : user %s authentication succeeded\n", user.text() );
            }
            else
            {
                  log.txt( LLOG_ERROR,
                        "!! : user %s authentication failed\n", user.text() );

                  ph1->status( XCH_STATUS_DEAD, XCH_FAILED_USER_AUTH, 0 );
            }

            //
            // NOTE : we set the username and password
            // as already sent and received in case the
            // gateway bypasses xauth on rekey
            //

            cfg->xstate |= CSTATE_SENT_XUSER;
            cfg->xstate |= CSTATE_SENT_XPASS;
            cfg->xstate |= CSTATE_RECV_XUSER;
            cfg->xstate |= CSTATE_RECV_XPASS;
            cfg->xstate |= CSTATE_RECV_XRSLT;

            return false;
      }

      //
      // unhandled message type
      //

      log.txt( LLOG_ERROR, "!! : config message type is invalid for xauth\n" );
      ph1->status( XCH_STATUS_DEAD, XCH_FAILED_MSG_FORMAT, 0 );

      return false;
}

bool _IKED::config_client_xauth_send( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( !( cfg->xstate & CSTATE_SENT_XUSER ) ||
            !( cfg->xstate & CSTATE_SENT_XPASS ) )
      {
            cfg->mtype = ISAKMP_CFG_REPLY;

            if( !ph1->vendopts_r.flag.chkpt )
            {
                  //
                  // standard xauth processing
                  //

                  cfg->attr_add_b( XAUTH_TYPE, cfg->tunnel->xauth.type );

                  if(  ( cfg->xstate & CSTATE_RECV_XUSER ) &&
                        !( cfg->xstate & CSTATE_SENT_XUSER ) )
                  {
                        cfg->attr_add_v( XAUTH_USER_NAME,
                              cfg->tunnel->xauth.user.buff(),
                              cfg->tunnel->xauth.user.size() );

                        cfg->xstate |= CSTATE_SENT_XUSER;

                        log.txt( LLOG_INFO,
                              "ii : - standard xauth username\n" );
                  }

                  if(  ( cfg->xstate & CSTATE_RECV_XPASS ) &&
                        !( cfg->xstate & CSTATE_SENT_XPASS ) )
                  {
                        switch( cfg->tunnel->xauth.type )
                        {
                              case XAUTH_TYPE_GENERIC:

                                    if( !( cfg->xstate & CSTATE_USE_PASSCODE ) )
                                    {
                                          cfg->attr_add_v( XAUTH_USER_PASSWORD,
                                                cfg->tunnel->xauth.pass.buff(),
                                                cfg->tunnel->xauth.pass.size() );

                                          log.txt( LLOG_INFO,
                                                "ii : - standard xauth password\n" );
                                    }
                                    else
                                    {
                                          cfg->attr_add_v( XAUTH_PASSCODE,
                                                cfg->tunnel->xauth.pass.buff(),
                                                cfg->tunnel->xauth.pass.size() );

                                          log.txt( LLOG_INFO,
                                                "ii : - standard xauth passcode\n" );
                                    }

                                    break;

                              case XAUTH_TYPE_RADIUS_CHAP:
                              {
                                    if( !cfg->tunnel->xauth.hash.size() )
                                    {
                                          cfg->attr_add_v( XAUTH_USER_PASSWORD,
                                                cfg->tunnel->xauth.pass.buff(),
                                                cfg->tunnel->xauth.pass.size() );

                                          log.txt( LLOG_INFO,
                                                "ii : - standard xauth password ( no chap challenge received )\n" );
                                    }
                                    else
                                    {
                                          uint8_t id;
                                          rand_bytes( &id, 1 );

                                          BDATA rslt;
                                          rslt.add( &id, sizeof( id ) );
                                          rslt.add( 0, MD5_DIGEST_LENGTH );

                                          MD5_CTX ctx;
                                          MD5_Init( &ctx );
                                          MD5_Update( &ctx, &id, sizeof( id ) );
                                          MD5_Update( &ctx, cfg->tunnel->xauth.pass.buff(), cfg->tunnel->xauth.pass.size() );
                                          MD5_Update( &ctx, cfg->tunnel->xauth.hash.buff(), cfg->tunnel->xauth.hash.size() );
                                          MD5_Final( rslt.buff() + sizeof( id ), &ctx );

                                          cfg->attr_add_v( XAUTH_USER_PASSWORD,
                                                rslt.buff(),
                                                rslt.size() );

                                          log.txt( LLOG_INFO,
                                                "ii : - standard xauth chap password\n" );
                                    }

                                    break;
                              }
                        }

                        cfg->xstate |= CSTATE_SENT_XPASS;
                  }
            }
            else
            {
                  //
                  // checkpoint xauth processing
                  //

                  cfg->attr_add_b( XAUTH_TYPE, cfg->tunnel->xauth.type );

                  if(  ( cfg->xstate & CSTATE_RECV_XUSER ) &&
                        !( cfg->xstate & CSTATE_SENT_XUSER ) )
                  {
                        cfg->attr_add_v( CHKPT_USER_NAME,
                              cfg->tunnel->xauth.user.buff(),
                              cfg->tunnel->xauth.user.size() );

                        cfg->xstate |= CSTATE_SENT_XUSER;

                        log.txt( LLOG_INFO,
                              "ii : - checkpoint xauth username\n" );
                  }

                  if(  ( cfg->xstate & CSTATE_RECV_XPASS ) &&
                        !( cfg->xstate & CSTATE_SENT_XPASS ) )
                  {
                        switch( cfg->tunnel->xauth.type )
                        {
                              case XAUTH_TYPE_GENERIC:
                              {
                                    cfg->attr_add_v( CHKPT_USER_PASSWORD,
                                          cfg->tunnel->xauth.pass.buff(),
                                          cfg->tunnel->xauth.pass.size() );

                                    log.txt( LLOG_INFO,
                                          "ii : - checkpoint xauth password\n" );

                                    break;
                              }

                              case XAUTH_TYPE_RADIUS_CHAP:
                              {
                                    uint8_t id;
                                    rand_bytes( &id, 1 );

                                    BDATA rslt;
                                    rslt.add( &id, sizeof( id ) );
                                    rslt.add( 0, MD5_DIGEST_LENGTH );

                                    MD5_CTX ctx;
                                    MD5_Init( &ctx );
                                    MD5_Update( &ctx, &id, sizeof( id ) );
                                    MD5_Update( &ctx, cfg->tunnel->xauth.pass.buff(), cfg->tunnel->xauth.pass.size() );
                                    MD5_Update( &ctx, cfg->tunnel->xauth.hash.buff(), cfg->tunnel->xauth.hash.size() );
                                    MD5_Final( rslt.buff() + sizeof( id ), &ctx );

                                    cfg->attr_add_v( CHKPT_USER_PASSWORD,
                                          rslt.buff(),
                                          rslt.size() );

                                    log.txt( LLOG_INFO,
                                          "ii : - checkpoint xauth chap password\n" );

                                    break;
                              }
                        }

                        cfg->xstate |= CSTATE_SENT_XPASS;
                  }
            }

            //
            // send config packet
            //

            BDATA user;
            user = cfg->tunnel->xauth.user;
            user.add( 0, 1 );

            log.txt( LLOG_INFO,     "ii : sending xauth response for %s\n", user.buff() );
            config_message_send( ph1, cfg );

            return false;
      }

      if( !( cfg->xstate & CSTATE_SENT_XRSLT ) )
      {
            //
            // if we have have not yet received an
            // xauth result message, postpone this
            // ack until later

            if( !( cfg->xstate & CSTATE_RECV_XRSLT ) )
                  return true;

            cfg->mtype = ISAKMP_CFG_ACK;

            //
            // add the status attribute
            //

            if( ph1->vendopts_r.flag.chkpt ) 
                  cfg->attr_add_b( CHKPT_STATUS, 1 );

//          if( !ph1->vendopts_r.flag.chkpt ) 
//                cfg->attr_add_b( XAUTH_STATUS, 1 );
//          else
//                cfg->attr_add_b( CHKPT_STATUS, 1 );

            //
            // send config packet
            //

            log.txt( LLOG_INFO, "ii : sending xauth acknowledge\n" );
            config_message_send( ph1, cfg );

            cfg->xstate |= CSTATE_SENT_XRSLT;

            return true;
      }

      return false;
}

bool _IKED::config_client_xconf_pull_recv( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      //
      // expecting configuration pull reply
      //

      if( cfg->mtype == ISAKMP_CFG_REPLY )
      {
            //
            // get configuration attributes
            //

            log.txt( LLOG_INFO, "ii : received config pull response\n" );

            long getmask = 0;
            config_xconf_get( cfg,
                  getmask,
                  cfg->tunnel->xconf.rqst,
                  ph1->vendopts_r );

            cfg->xstate |= CSTATE_RECV_XCONF;

            return false;
      }

      //
      // unhandled message type
      //

      log.txt( LLOG_ERROR, "!! : config message type is invalid for pull config\n" );
      ph1->status( XCH_STATUS_DEAD, XCH_FAILED_MSG_FORMAT, 0 );

      return false;
}

bool _IKED::config_client_xconf_pull_send( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( !( cfg->xstate & CSTATE_SENT_XCONF ) )
      {
            //
            // set configuration attributes
            //

            log.txt( LLOG_INFO, "ii : building config attribute list\n" );

            cfg->mtype = ISAKMP_CFG_REQUEST;

            if( ph1->vendopts_r.flag.chkpt )
                  iked.rand_bytes( &cfg->ident, sizeof( cfg->ident ) );

            config_xconf_set( cfg,
                  cfg->tunnel->xconf.rqst,
                  0xffffffff,
                  ph1->vendopts_r );

            if( cfg->attr_count() )
            {
                  //
                  // create new msgid and iv
                  //

                  cfg->new_msgid();
                  cfg->new_msgiv( ph1 );

                  //
                  // send config packet
                  //

                  log.txt( LLOG_INFO, "ii : sending config pull request\n" );
                  config_message_send( ph1, cfg );

                  cfg->xstate |= CSTATE_SENT_XCONF;
            }
            else
            {
                  //
                  // config not required
                  //

                  log.txt( LLOG_INFO, "ii : config pull is not required\n" );

                  cfg->xstate |= CSTATE_SENT_XCONF;
                  cfg->xstate |= CSTATE_RECV_XCONF;
            }

            return false;
      }

      return false;
}

bool _IKED::config_client_xconf_push_recv( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      //
      // expecting configuration push request
      //

      if( cfg->mtype == ISAKMP_CFG_SET )
      {
            //
            // get xconf attributes
            //

            log.txt( LLOG_INFO, "ii : received config push request\n" );

            long getmask = 0;
            config_xconf_get( cfg,
                  getmask,
                  cfg->tunnel->xconf.rqst,
                  ph1->vendopts_r );

            //
            // config is now mature
            //

            cfg->xstate |= CSTATE_RECV_XCONF;

            return false;
      }

      //
      // unhandled message type
      //

      log.txt( LLOG_ERROR, "!! : config message type is invalid for push config\n" );
      ph1->status( XCH_STATUS_DEAD, XCH_FAILED_MSG_FORMAT, 0 );

      return false;
}

bool _IKED::config_client_xconf_push_send( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( !( cfg->xstate & CSTATE_SENT_XCONF ) )
      {
            //
            // set xconf attributes
            //

            log.txt( LLOG_INFO, "ii : building config attribute list\n" );

            cfg->mtype = ISAKMP_CFG_ACK;

            config_xconf_set( cfg,
                  cfg->tunnel->xconf.rqst,
                  0xffffffff,
                  ph1->vendopts_r );

            //
            // send config packet
            //

            log.txt( LLOG_INFO, "ii : sending config push acknowledge\n" );
            config_message_send( ph1, cfg );

            cfg->xstate |= CSTATE_SENT_XCONF;

            return false;
      }

      return false;
}

bool _IKED::config_server_xauth_recv( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( cfg->mtype == ISAKMP_CFG_REPLY )
      {
            log.txt( LLOG_INFO, "ii : received xauth response\n" );

            //
            // make sure we at least have
            // user and password attribs
            //

            long count = cfg->attr_count();
            long index = 0;

            for( ; index < count; index++ )
            {
                  IKE_ATTR * attr = cfg->attr_get( index );

                  switch( attr->atype )
                  {
                        case XAUTH_USER_NAME:
                              cfg->xstate |= CSTATE_RECV_XUSER;
                              cfg->tunnel->xauth.user.set( attr->vdata );
                              break;

                        case XAUTH_USER_PASSWORD:
                              cfg->xstate |= CSTATE_RECV_XPASS;
                              cfg->tunnel->xauth.pass.set( attr->vdata );
                              break;
                  }
            }

            if( !cfg->tunnel->xauth.user.size() )
                  log.txt( LLOG_ERROR, "!! : missing required username attribute\n" );

            if( !cfg->tunnel->xauth.pass.size() )
                  log.txt( LLOG_ERROR, "!! : missing required password attribute\n" );

            return false;
      }

      if( cfg->mtype == ISAKMP_CFG_ACK )
      {
            log.txt( LLOG_INFO, "ii : received xauth ack\n" );

            cfg->xstate |= CSTATE_RECV_XRSLT;

            if( cfg->tunnel->peer->xconf_mode != CONFIG_MODE_PUSH )
                  cfg->status( XCH_STATUS_MATURE, XCH_NORMAL, 0 );

            return false;
      }

      return false;
}

bool _IKED::config_server_xauth_send( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( !( cfg->xstate & CSTATE_SENT_XUSER ) )
      {
            //
            // set request attributes
            //

            cfg->mtype = ISAKMP_CFG_REQUEST;

            cfg->attr_add_b( XAUTH_TYPE, XAUTH_TYPE_GENERIC );
            cfg->attr_add_v( XAUTH_USER_NAME, NULL, 0 );
            cfg->attr_add_v( XAUTH_USER_PASSWORD, NULL, 0 );

            //
            // create new msgid and iv
            //

            cfg->new_msgid();
            cfg->new_msgiv( ph1 );

            //
            // send config packet
            //

            config_message_send( ph1, cfg );

            //
            // flag as sent
            //

            cfg->xstate |= CSTATE_SENT_XUSER;
            cfg->xstate |= CSTATE_SENT_XPASS;

            log.txt( LLOG_INFO, "ii : sent xauth request\n" );

            return false;
      }

      if( !( cfg->xstate & CSTATE_SENT_XRSLT ) )
      {
            bool allow = false;
            if( cfg->tunnel->xauth.user.size() &&
                  cfg->tunnel->xauth.pass.size() )
                  allow = true;

            //
            // check user password
            //

            if( allow )
            {
                  cfg->tunnel->xauth.user.add( 0, 1 );
                  cfg->tunnel->xauth.pass.add( 0, 1 );

                  allow = cfg->tunnel->peer->xauth_source->auth_pwd(
                                    cfg->tunnel->xauth );

                  if( allow )
                        iked.log.txt( LLOG_INFO,
                              "ii : xauth user %s password accepted ( %s )\n",
                              cfg->tunnel->xauth.user.text(),
                              cfg->tunnel->peer->xauth_source->name() );
                  else
                        iked.log.txt( LLOG_ERROR,
                              "!! : xauth user %s password rejected ( %s )\n",
                              cfg->tunnel->xauth.user.text(),
                              cfg->tunnel->peer->xauth_source->name() );
            }

            //
            // check user group membership
            //

            if( allow && cfg->tunnel->peer->xauth_group.size() )
            {
                  allow = cfg->tunnel->peer->xauth_source->auth_grp(
                                    cfg->tunnel->xauth,
                                    cfg->tunnel->peer->xauth_group );

                  if( allow )
                        log.txt( LLOG_INFO,
                              "ii : xauth user %s group %s membership accepted ( %s )\n",
                              cfg->tunnel->xauth.user.text(),
                              cfg->tunnel->peer->xauth_group.text(),
                              cfg->tunnel->peer->xauth_source->name() );
                  else
                        log.txt( LLOG_ERROR,
                              "!! : xauth user %s group %s membership rejected ( %s )\n",
                              cfg->tunnel->xauth.user.text(),
                              cfg->tunnel->peer->xauth_group.text(),
                              cfg->tunnel->peer->xauth_source->name() );
            }

            //
            // set result attributes
            //

            cfg->mtype = ISAKMP_CFG_SET;

            if( allow )
                  cfg->attr_add_b( XAUTH_STATUS, 1 );
            else
                  cfg->attr_add_b( XAUTH_STATUS, 0 );

            //
            // create new msgid and iv
            //

            cfg->new_msgid();
            cfg->new_msgiv( ph1 );

            //
            // send config packet
            //

            config_message_send( ph1, cfg );

            //
            // flag as sent and release
            //

            cfg->xstate |= CSTATE_SENT_XRSLT;

            log.txt( LLOG_INFO, "ii : sent xauth result\n" );

            if( !allow )
                  ph1->status( XCH_STATUS_DEAD, XCH_FAILED_USER_AUTH, 0 );

            return false;
      }

      return false;
}

bool _IKED::config_server_xconf_pull_recv( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( cfg->mtype == ISAKMP_CFG_REQUEST )
      {
            //
            // get xconf attributes
            //

            log.txt( LLOG_INFO, "ii : received config pull request\n" );

            config_xconf_get( cfg,
                  cfg->tunnel->xconf.rqst,
                  0,
                  ph1->vendopts_r );

            cfg->xstate |= CSTATE_RECV_XCONF;

            return false;
      }

      return false;
}

bool _IKED::config_server_xconf_pull_send( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( !( cfg->xstate & CSTATE_SENT_XCONF ) )
      {
            //
            // obtain the client xconf config
            //

            cfg->tunnel->peer->xconf_source->rslt(
                  cfg->tunnel );

            //
            // if we are to generate a policy
            // list during config, do this now
            //

            if( cfg->tunnel->peer->plcy_mode == POLICY_MODE_CONFIG )
                  policy_list_create( cfg->tunnel, false );

            if( cfg->tunnel->peer->plcy_mode != POLICY_MODE_DISABLE )
                  cfg->tunnel->xconf.opts |= IPSEC_OPTS_SPLITNET;

            //
            // set result attributes
            //

            cfg->mtype = ISAKMP_CFG_REPLY;

            log.txt( LLOG_INFO, "ii : building config attribute list\n" );

            config_xconf_set( cfg,
                  cfg->tunnel->xconf.opts,
                  0,
                  ph1->vendopts_r );

            //
            // send config packet
            //

            log.txt( LLOG_INFO, "ii : sending config pull response\n" );
            config_message_send( ph1, cfg );

            //
            // flag as sent
            //

            cfg->tunnel->tstate |= CSTATE_SENT_XCONF;

            return false;
      }

      return false;
}

bool _IKED::config_server_xconf_push_recv( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( cfg->mtype == ISAKMP_CFG_ACK )
      {
            //
            // get xconf attributes
            //

            log.txt( LLOG_INFO, "ii : received config push acknowledge\n" );

            long readmask = 0;

            config_xconf_get( cfg,
                  readmask,
                  0,
                  ph1->vendopts_r );

            cfg->xstate |= CSTATE_RECV_XCONF;

            return false;
      }

      return false;
}

bool _IKED::config_server_xconf_push_send( IDB_CFG * cfg, IDB_PH1 * ph1 )
{
      if( !( cfg->xstate & CSTATE_SENT_XCONF ) )
      {
            //
            // in push mode the client doesnt
            // request its desired attributes
            //

            cfg->tunnel->xconf.rqst = cfg->tunnel->peer->xconf_source->config.opts;

            //
            // obtain the client xconf config
            //

            cfg->tunnel->peer->xconf_source->rslt(
                  cfg->tunnel );

            //
            // if we are to generate a policy
            // list during config, do this now
            //

            if( cfg->tunnel->peer->plcy_mode == POLICY_MODE_CONFIG )
                  policy_list_create( cfg->tunnel, false );

            if( cfg->tunnel->peer->plcy_mode != POLICY_MODE_DISABLE )
                  cfg->tunnel->xconf.opts |= IPSEC_OPTS_SPLITNET;

            //
            // set attributes
            //

            cfg->mtype = ISAKMP_CFG_SET;

            log.txt( LLOG_INFO, "ii : building config attribute list\n" );

            config_xconf_set( cfg,
                  cfg->tunnel->xconf.opts,
                  0,
                  ph1->vendopts_r );

            //
            // create new msgid and iv
            //

            cfg->new_msgid();
            cfg->new_msgiv( ph1 );

            //
            // send config packet
            //

            log.txt( LLOG_INFO, "ii : sending config push request\n" );

            config_message_send( ph1, cfg );

            cfg->attr_reset();

            //
            // flag as sent
            //

            cfg->xstate |= CSTATE_SENT_XCONF;

            return false;
      }

      return false;
}

long _IKED::config_xconf_set( IDB_CFG * cfg, long & setmask, long nullmask, VENDOPTS vendopts )
{
      //
      // the modecfg draft defines valid lengths
      // for most attribute values. a checkpoint
      // client always submits 4 null bytes even
      // for values that are not constrained to
      // 0 or 4 byte lengths. we mimic this odd
      // behavior for compatibility sake.
      //

      void *      null_ptr = NULL;
      char  null_len = 0;
      char  null_val[ 4 ] = { 0 };

      if( vendopts.flag.chkpt )
      {
            null_ptr = null_val;
            null_len = 4;
      }

      //
      // standard attributes
      //

      if( setmask & IPSEC_OPTS_ADDR )
      {
            if( nullmask & IPSEC_OPTS_ADDR )
            {
                  cfg->attr_add_v( INTERNAL_IP4_ADDRESS,
                        null_ptr, null_len );

                  log.txt( LLOG_DEBUG,    "ii : - IP4 Address\n" );

                  cfg->attr_add_v( INTERNAL_ADDRESS_EXPIRY,
                        null_ptr, null_len );

                  log.txt( LLOG_DEBUG,    "ii : - Address Expiry\n" );
            }
            else
            {
                  cfg->attr_add_v( INTERNAL_IP4_ADDRESS,
                        &cfg->tunnel->xconf.addr,
                        sizeof( cfg->tunnel->xconf.addr ) );

                  char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                  text_addr( txtaddr, cfg->tunnel->xconf.addr );

                  log.txt( LLOG_DEBUG,
                        "ii : - IP4 Address = %s\n",
                        txtaddr );

                  cfg->attr_add_v( INTERNAL_ADDRESS_EXPIRY,
                        &cfg->tunnel->xconf.expi,
                        sizeof( cfg->tunnel->xconf.expi ) );

                  log.txt( LLOG_DEBUG,
                        "ii : - Address Expiry = %i secs\n",
                        cfg->tunnel->xconf.expi );
            }
      }

      if( setmask & IPSEC_OPTS_MASK )
      {
            if( nullmask & IPSEC_OPTS_MASK )
            {
                  cfg->attr_add_v( INTERNAL_IP4_NETMASK,
                        null_ptr, null_len );

                  log.txt( LLOG_DEBUG,    "ii : - IP4 Netamask\n" );
            }
            else
            {
                  cfg->attr_add_v( INTERNAL_IP4_NETMASK,
                        &cfg->tunnel->xconf.mask,
                        sizeof( cfg->tunnel->xconf.mask ) );

                  char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                  text_addr( txtaddr, cfg->tunnel->xconf.mask );

                  log.txt( LLOG_DEBUG,
                        "ii : - IP4 Netamask = %s\n",
                        txtaddr );
            }
      }

      if( setmask & IPSEC_OPTS_DNSS )
      {
            if( nullmask & IPSEC_OPTS_DNSS )
            {
                  cfg->attr_add_v( INTERNAL_IP4_DNS,
                        null_ptr, null_len );

                  log.txt( LLOG_DEBUG, "ii : - IP4 DNS Server\n" );
            }
            else
            {
                  uint32_t index = 0;
                  uint32_t count = cfg->tunnel->xconf.nscfg.dnss_count;

                  for( ; index < count; index++ )
                  {
                        cfg->attr_add_v( INTERNAL_IP4_DNS,
                              &cfg->tunnel->xconf.nscfg.dnss_list[ index ], 4 );

                        char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                        text_addr( txtaddr, cfg->tunnel->xconf.nscfg.dnss_list[ index ] );

                        log.txt( LLOG_DEBUG,
                              "ii : - IP4 DNS Server = %s\n",
                              txtaddr );
                  }
            }
      }

      if( setmask & IPSEC_OPTS_NBNS )
      {
            if( nullmask & IPSEC_OPTS_NBNS )
            {
                  cfg->attr_add_v( INTERNAL_IP4_NBNS,
                        null_ptr, null_len );

                  log.txt( LLOG_DEBUG,    "ii : - IP4 WINS Server\n" );
            }
            else
            {
                  uint32_t index = 0;
                  uint32_t count = cfg->tunnel->xconf.nscfg.nbns_count;

                  for( ; index < count; index++ )
                  {
                        cfg->attr_add_v( INTERNAL_IP4_NBNS,
                              &cfg->tunnel->xconf.nscfg.nbns_list[ index ], 4 );

                        char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                        text_addr( txtaddr, cfg->tunnel->xconf.nscfg.nbns_list[ index ] );

                        log.txt( LLOG_DEBUG,
                              "ii : - IP4 WINS Server = %s\n",
                              txtaddr );
                  }
            }
      }

      //
      // non cisco unity attributes
      //

      if( !vendopts.flag.unity )
      {
            if( setmask & IPSEC_OPTS_SPLITNET )
            {
                  if( nullmask & IPSEC_OPTS_SPLITNET )
                  {
                        cfg->attr_add_v( INTERNAL_IP4_SUBNET, NULL, 0 );

                        log.txt( LLOG_DEBUG,
                              "ii : - IP4 Subnet\n" );
                  }
                  else
                  {
                        IKE_PH2ID ph2id;

                        long index = 0;

                        while( cfg->tunnel->idlist_incl.get( ph2id, index++ ) )
                        {
                              IKE_SUBNET subnet;
                              memset( &subnet, 0, sizeof( subnet ) );

                              subnet.addr = ph2id.addr1;
                              subnet.mask = ph2id.addr2;

                              char txtid[ LIBIKE_MAX_TEXTP2ID ];
                              text_ph2id( txtid, &ph2id );

                              if( subnet.addr.s_addr &&
                                    subnet.mask.s_addr )
                              {
                                    cfg->attr_add_v(
                                          INTERNAL_IP4_SUBNET,
                                          &subnet,
                                          sizeof( subnet ) );

                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 Subnet = %s\n",
                                          txtid );
                              }
                              else
                              {
                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 Subnet = %s\n ( invalid subnet ignored )",
                                          txtid );
                              }
                        }
                  }
            }
      }

      //
      // cisco unity attributes
      //

      if( vendopts.flag.unity )
      {
            if( setmask & IPSEC_OPTS_DOMAIN )
            {
                  if( nullmask & IPSEC_OPTS_DOMAIN )
                  {
                        cfg->attr_add_v( UNITY_DEF_DOMAIN, NULL, 0 );
                        log.txt( LLOG_DEBUG,
                              "ii : - DNS Suffix\n" );
                  }
                  else
                  {
                        cfg->attr_add_v( UNITY_DEF_DOMAIN,
                              &cfg->tunnel->xconf.nscfg.dnss_suffix,
                              strlen( cfg->tunnel->xconf.nscfg.dnss_suffix ) );

                        log.txt( LLOG_DEBUG,
                              "ii : - DNS Suffix = %s\n",
                              cfg->tunnel->xconf.nscfg.dnss_suffix );
                  }
            }

            if( setmask & IPSEC_OPTS_SPLITDNS )
            {
                  if( nullmask & IPSEC_OPTS_SPLITDNS )
                  {
                        cfg->attr_add_v( UNITY_SPLIT_DOMAIN, NULL, 0 );
                        log.txt( LLOG_DEBUG, "ii : - Split DNS Domain\n" );
                  }
                  else
                  {
                        BDATA domain;

                        long index = 0;

                        while( cfg->tunnel->domains.get( domain, index++ ) )
                        {
                              log.txt( LLOG_DEBUG,
                                    "ii : - Split DNS Domain = %s\n",
                                    domain.text() );

                              if( index > 1 )
                                    domain.ins( ',', 1 );

                              cfg->attr_add_v( UNITY_SPLIT_DOMAIN,
                                    domain.buff(),
                                    domain.size() );
                        }
                  }
            }

            if( setmask & IPSEC_OPTS_SPLITNET )
            {
                  if( nullmask & IPSEC_OPTS_SPLITNET )
                  {
                        cfg->attr_add_v( UNITY_SPLIT_INCLUDE, NULL, 0 );
                        cfg->attr_add_v( UNITY_SPLIT_EXCLUDE, NULL, 0 );

                        log.txt( LLOG_DEBUG,
                              "ii : - IP4 Split Network Include\n"
                              "ii : - IP4 Split Network Exclude\n" );
                  }
                  else
                  {
                        IKE_PH2ID ph2id;

                        long index = 0;

                        while( cfg->tunnel->idlist_incl.get( ph2id, index++ ) )
                        {
                              IKE_UNITY_NET unity_net;
                              memset( &unity_net, 0, sizeof( unity_net ) );

                              unity_net.prot = ph2id.prot;
                              unity_net.addr = ph2id.addr1;
                              unity_net.mask = ph2id.addr2;
                              unity_net.port_rmt = ph2id.port;

                              char txtid[ LIBIKE_MAX_TEXTP2ID ];
                              text_ph2id( txtid, &ph2id );

                              if( unity_net.addr.s_addr &&
                                    unity_net.mask.s_addr )
                              {
                                    cfg->attr_add_v( UNITY_SPLIT_INCLUDE,
                                          &unity_net,
                                          sizeof( unity_net ) );

                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 Split Network Include = %s\n",
                                          txtid );
                              }
                              else
                              {
                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 Split Network Include = %s\n ( invalid subnet ignored )",
                                          txtid );
                              }
                        }

                        index = 0;

                        while( cfg->tunnel->idlist_excl.get( ph2id, index++ ) )
                        {
                              IKE_UNITY_NET unity_net;
                              memset( &unity_net, 0, sizeof( unity_net ) );

                              unity_net.prot = ph2id.prot;
                              unity_net.addr = ph2id.addr1;
                              unity_net.mask = ph2id.addr2;
                              unity_net.port_rmt = ph2id.port;

                              char txtid[ LIBIKE_MAX_TEXTP2ID ];
                              text_ph2id( txtid, &ph2id );

                              if( unity_net.addr.s_addr &&
                                    unity_net.mask.s_addr )
                              {
                                    cfg->attr_add_v( UNITY_SPLIT_EXCLUDE,
                                          &unity_net,
                                          sizeof( unity_net ) );

                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 Split Network Exclude = %s\n",
                                          txtid );
                              }
                              else
                              {
                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 Split Network Exclude = %s\n ( invalid subnet ignored )",
                                          txtid );
                              }
                        }
                  }
            }

            if( setmask & IPSEC_OPTS_BANNER )
            {
                  if( nullmask & IPSEC_OPTS_BANNER )
                  {
                        cfg->attr_add_v( UNITY_BANNER, NULL, 0 );
                        log.txt( LLOG_DEBUG,
                              "ii : - Login Banner\n" );
                  }
                  else
                  {
                        cfg->attr_add_v( UNITY_BANNER,
                              cfg->tunnel->banner.buff(),
                              cfg->tunnel->banner.size() );

                        cfg->tunnel->banner.add( 0, 1 );

                        log.txt( LLOG_DEBUG,
                              "ii : - Login Banner ( %i bytes )\n",
                              cfg->tunnel->banner.size() );
                  }
            }

            if( setmask & IPSEC_OPTS_PFS )
            {
                  if( nullmask & IPSEC_OPTS_PFS )
                  {
                        cfg->attr_add_v( UNITY_PFS, NULL, 0 );
                        log.txt( LLOG_DEBUG,
                              "ii : - PFS Group\n" );
                  }
                  else
                  {
                        cfg->attr_add_b( UNITY_PFS,
                              cfg->tunnel->xconf.dhgr );

                        log.txt( LLOG_DEBUG,
                              "ii : - PFS Group = %i\n",
                              cfg->tunnel->xconf.dhgr );
                  }
            }

            if( setmask & IPSEC_OPTS_SAVEPW )
            {
                  if( nullmask & IPSEC_OPTS_SAVEPW )
                  {
                        cfg->attr_add_v( UNITY_SAVE_PASSWD, NULL, 0 );
                        log.txt( LLOG_DEBUG,
                              "ii : - Save Password\n" );
                  }
                  else
                  {
                        cfg->attr_add_b( UNITY_SAVE_PASSWD,
                              cfg->tunnel->xconf.svpw );

                        log.txt( LLOG_DEBUG,
                              "ii : - Save Password = %i\n",
                              cfg->tunnel->xconf.svpw );
                  }
            }

            cfg->attr_add_v( APPLICATION_VERSION,
                  UNITY_APP_VERSION_STRING,
                  strlen( UNITY_APP_VERSION_STRING ) );

            log.txt( LLOG_DEBUG,
                  "ii : - Application Version = %s\n",
                  UNITY_APP_VERSION_STRING );

            cfg->attr_add_v( UNITY_FW_TYPE,
                  unity_fwtype.buff(),
                  unity_fwtype.size() );

            log.txt( LLOG_DEBUG,
                  "ii : - Firewall Type = CISCO-UNKNOWN\n" );
      }

      //
      // checkpoint attributes
      //

      if( vendopts.flag.chkpt )
      {
            cfg->attr_add_v( CHKPT_MARCIPAN_REASON_CODE,
                        null_ptr, null_len );

            log.txt( LLOG_DEBUG,
                  "ii : - Marcipan Reason Code\n" );

            uint8_t macaddr[ 6 ];
            rand_bytes( &macaddr, 6 );
            cfg->attr_add_v( CHKPT_MAC_ADDRESS, macaddr, 6 );

            log.txt( LLOG_DEBUG,
                  "ii : - Adapter MAC Address = %02x:%02x:%02x:%02x:%02x:%02x\n",
                  macaddr[ 0 ],
                  macaddr[ 1 ],
                  macaddr[ 2 ],
                  macaddr[ 3 ],
                  macaddr[ 4 ],
                  macaddr[ 5 ] );

            if( setmask & IPSEC_OPTS_DOMAIN )
            {
                  if( nullmask & IPSEC_OPTS_DOMAIN )
                  {
                        cfg->attr_add_v( CHKPT_DEF_DOMAIN,
                              null_ptr, null_len );

                        log.txt( LLOG_DEBUG,
                              "ii : - DNS Suffix\n" );
                  }
                  else
                  {
                        cfg->attr_add_v( CHKPT_DEF_DOMAIN,
                              &cfg->tunnel->xconf.nscfg.dnss_suffix,
                              strlen( cfg->tunnel->xconf.nscfg.dnss_suffix ) );

                        log.txt( LLOG_DEBUG,
                              "ii : - DNS Suffix = %s\n",
                              cfg->tunnel->xconf.nscfg.dnss_suffix );
                  }
            }
      }

      return LIBIKE_OK;
}

long _IKED::config_xconf_get( IDB_CFG * cfg, long & getmask, long readmask, VENDOPTS vendopts )
{
      long count = cfg->attr_count();
      long index = 0;

      for( ; index < count; index++ )
      {
            IKE_ATTR * attr = cfg->attr_get( index );

            //
            // standard attributes
            //

            bool unhandled = false;

            switch( attr->atype )
            {
                  case INTERNAL_IP4_ADDRESS:
                  {
                        getmask |= IPSEC_OPTS_ADDR;

                        if( ( readmask & IPSEC_OPTS_ADDR ) && attr->vdata.size() )
                        {
                              if( attr->vdata.size() != 4 )
                              {
                                    log.txt( LLOG_ERROR,
                                          "!! : - IP4 Address has invalid size ( %i bytes )\n",
                                          attr->vdata.size() );

                                    break;
                              }

                              memcpy(
                                    &cfg->tunnel->xconf.addr,
                                    attr->vdata.buff(), 4 );

                              char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                              text_addr( txtaddr, cfg->tunnel->xconf.addr );

                              log.txt( LLOG_DEBUG,
                                    "ii : - IP4 Address = %s\n",
                                    txtaddr );
                        }
                        else
                              log.txt( LLOG_DEBUG,    "ii : - IP4 Address\n" );

                        break;
                  }

                  case INTERNAL_IP4_NETMASK:
                  {
                        getmask |= IPSEC_OPTS_MASK;

                        if( ( readmask & IPSEC_OPTS_MASK ) && attr->vdata.size() )
                        {
                              if( attr->vdata.size() != 4 )
                              {
                                    log.txt( LLOG_ERROR,
                                          "!! : - IP4 Netmask has invalid size ( %i bytes )\n",
                                          attr->vdata.size() );

                                    break;
                              }

                              memcpy(
                                    &cfg->tunnel->xconf.mask,
                                    attr->vdata.buff(), 4 );

                              char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                              text_addr( txtaddr, cfg->tunnel->xconf.mask );

                              log.txt( LLOG_DEBUG,
                                    "ii : - IP4 Netmask = %s\n",
                                    txtaddr );
                        }
                        else
                              log.txt( LLOG_DEBUG,    "ii : - IP4 Netmask\n" );

                        break;
                  }

                  case INTERNAL_IP4_DNS:
                  {
                        getmask |= IPSEC_OPTS_DNSS;

                        if( ( readmask & IPSEC_OPTS_DNSS ) && attr->vdata.size() )
                        {
                              if( cfg->tunnel->xconf.nscfg.dnss_count < IPSEC_DNSS_MAX )
                              {
                                    if( attr->vdata.size() != 4 )
                                    {
                                          log.txt( LLOG_ERROR,
                                                "!! : - IP4 DNS Server has invalid size ( %i bytes )\n",
                                                attr->vdata.size() );

                                          break;
                                    }

                                    memcpy(
                                          &cfg->tunnel->xconf.nscfg.dnss_list[ cfg->tunnel->xconf.nscfg.dnss_count ],
                                          attr->vdata.buff(), 4 );

                                    char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                                    text_addr( txtaddr, cfg->tunnel->xconf.nscfg.dnss_list[ cfg->tunnel->xconf.nscfg.dnss_count ] );

                                    cfg->tunnel->xconf.nscfg.dnss_count++;

                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 DNS Server = %s\n",
                                          txtaddr );
                              }
                        }
                        else
                              log.txt( LLOG_DEBUG, "ii : - IP4 DNS Server\n" );

                        break;
                  }

                  case INTERNAL_IP4_NBNS:
                  {
                        getmask |= IPSEC_OPTS_NBNS;

                        if( ( readmask & IPSEC_OPTS_NBNS ) && attr->vdata.size() )
                        {
                              if( cfg->tunnel->xconf.nscfg.nbns_count < IPSEC_NBNS_MAX )
                              {
                                    if( attr->vdata.size() != 4 )
                                    {
                                          log.txt( LLOG_ERROR,
                                                "!! : - IP4 WINS Server has invalid size ( %i bytes )\n",
                                                attr->vdata.size() );

                                          break;
                                    }

                                    memcpy(
                                          &cfg->tunnel->xconf.nscfg.nbns_list[ cfg->tunnel->xconf.nscfg.nbns_count ],
                                          attr->vdata.buff(), 4 );

                                    char txtaddr[ LIBIKE_MAX_TEXTADDR ];
                                    text_addr( txtaddr, cfg->tunnel->xconf.nscfg.nbns_list[ cfg->tunnel->xconf.nscfg.nbns_count ] );

                                    cfg->tunnel->xconf.nscfg.nbns_count++;

                                    log.txt( LLOG_DEBUG,
                                          "ii : - IP4 WINS Server = %s\n",
                                          txtaddr );
                              }
                        }
                        else
                              log.txt( LLOG_DEBUG, "ii : - IP4 WINS Server\n" );

                        break;
                  }

                  case INTERNAL_ADDRESS_EXPIRY:
                  {
                        getmask |= IPSEC_OPTS_ADDR;

                        if( ( readmask & IPSEC_OPTS_ADDR ) && attr->vdata.size() )
                        {
                              if( attr->vdata.size() != 4 )
                              {
                                    log.txt( LLOG_ERROR,
                                          "!! : - Address Expiry has invalid size ( %i bytes )\n",
                                          attr->vdata.size() );

                                    break;
                              }

                              memcpy(
                                    &cfg->tunnel->xconf.expi,
                                    attr->vdata.buff(), 4 );

                              log.txt( LLOG_DEBUG,
                                    "ii : - Address Expiry = %i\n",
                                     cfg->tunnel->xconf.expi );
                        }
                        else
                              log.txt( LLOG_DEBUG, "ii : - Address Expiry\n" );

                        break;
                  }

                  case APPLICATION_VERSION:
                  {
                        if( attr->vdata.size() )
                        {
                              BDATA appver;
                              appver = attr->vdata;
                              appver.add( "", 1 );

                              log.txt( LLOG_DEBUG,
                                    "ii : - Application Version = %s\n",
                                    appver.text() );
                        }
                        else
                              log.txt( LLOG_DEBUG, "ii : - Application Version\n" );

                        break;
                  }

                  default:
                        unhandled = true;
            }

            //
            // non cisco unity attributes
            //

            if( !vendopts.flag.unity && unhandled )
            {
                  unhandled = false;
      
                  switch( attr->atype )
                  {
                        case INTERNAL_IP4_SUBNET:
                        {
                              getmask |= IPSEC_OPTS_SPLITNET;

                              if( ( readmask & IPSEC_OPTS_SPLITNET ) && attr->vdata.size() )
                              {
                                    int net_count = int( attr->vdata.size() / sizeof( IKE_SUBNET ) );
                                    int net_index = 0;

                                    for( ; net_index < net_count; net_index++ )
                                    {
                                          long offset = sizeof( IKE_SUBNET ) * net_index;
                                          IKE_SUBNET * subnet = ( IKE_SUBNET * ) ( attr->vdata.buff() + offset );

                                          IKE_PH2ID ph2id;
                                          memset( &ph2id, 0, sizeof( ph2id ) );

                                          ph2id.type = ISAKMP_ID_IPV4_ADDR_SUBNET;
                                          ph2id.addr1 = subnet->addr;
                                          ph2id.addr2 = subnet->mask;

                                          char txtid[ LIBIKE_MAX_TEXTP2ID ];
                                          text_ph2id( txtid, &ph2id );

                                          if( subnet->addr.s_addr &&
                                                subnet->mask.s_addr )
                                          {
                                                log.txt( LLOG_DEBUG,
                                                      "ii : - IP4 Subnet = %s\n",
                                                      txtid );

                                                cfg->tunnel->idlist_incl.add( ph2id );
                                          }
                                          else
                                          {
                                                log.txt( LLOG_DEBUG,
                                                      "ii : - IP4 Subnet = %s ( invalid subnet ignored )\n",
                                                      txtid );
                                          }
                                    }
                              }
                              else
                                    log.txt( LLOG_DEBUG, "ii : - IP4 Subnet\n" );

                              break;
                        }

                        default:
                              unhandled = true;
                  }
            }

            //
            // cisco unity attributes
            //

            if( vendopts.flag.unity && unhandled )
            {
                  unhandled = false;

                  switch( attr->atype )
                  {
                        case UNITY_FW_TYPE:
                        {
                              if( attr->vdata.size() )
                              {
                                    log.txt( LLOG_DEBUG,
                                          "ii : - Firewall Type = %i bytes\n",
                                          attr->vdata.size() );
                              }
                              else
                                    log.txt( LLOG_DEBUG, "ii : - Firewall Type\n" );

                              break;
                        }

                        case UNITY_DEF_DOMAIN:
                        {
                              getmask |= IPSEC_OPTS_DOMAIN;

                              if( ( readmask & IPSEC_OPTS_DOMAIN ) && attr->vdata.size() )
                              {
                                    size_t nlen = attr->vdata.size();
                                    if( nlen > ( CONF_STRLEN - 1 ) )
                                          nlen = ( CONF_STRLEN - 1 );

                                    memcpy(
                                          cfg->tunnel->xconf.nscfg.dnss_suffix,
                                          attr->vdata.buff(), nlen );

                                    cfg->tunnel->xconf.nscfg.dnss_suffix[ nlen ] = 0;

                                    log.txt( LLOG_DEBUG,
                                          "ii : - DNS Suffix = %s\n",
                                          cfg->tunnel->xconf.nscfg.dnss_suffix );
                              }
                              else
                                    log.txt( LLOG_DEBUG, "ii : - DNS Suffix\n" );

                              break;
                        }

                        case UNITY_SPLIT_DOMAIN:
                        {
                              getmask |= IPSEC_OPTS_SPLITDNS;

                              if( ( readmask & IPSEC_OPTS_SPLITDNS ) && attr->vdata.size() )
                              {
                                    attr->vdata.add( 0, 1 );

                                    unsigned char *   dnsstr = attr->vdata.buff();
                                    size_t                  dnslen = 0;

                                    while( dnslen < ( attr->vdata.size() - 1 ) )
                                    {
                                          if( *dnsstr == ',' )
                                          {
                                                dnslen += 1;
                                                dnsstr += 1;
                                          }

                                          size_t tmplen = strlen( ( char * ) dnsstr ) + 1;

                                          BDATA domain;
                                          domain.set( dnsstr, tmplen );

                                          log.txt( LLOG_DEBUG,
                                                "ii : - Split Domain = %s\n",
                                                dnsstr );

                                          dnslen += tmplen;
                                          dnsstr += tmplen;

                                          if( readmask & IPSEC_OPTS_SPLITDNS )
                                                cfg->tunnel->domains.add( domain );
                                    }
                              }
                              else
                                    log.txt( LLOG_DEBUG, "ii : - Split Domain\n" );

                              break;
                        }

                        case UNITY_SPLIT_INCLUDE:
                        case UNITY_SPLIT_EXCLUDE:
                        {
                              getmask |= IPSEC_OPTS_SPLITNET;

                              if( ( readmask & IPSEC_OPTS_SPLITNET ) && attr->vdata.size() )
                              {
                                    int net_count = int( attr->vdata.size() / sizeof( IKE_UNITY_NET ) );
                                    int net_index = 0;

                                    for( ; net_index < net_count; net_index++ )
                                    {
                                          long offset = sizeof( IKE_UNITY_NET ) * net_index;
                                          IKE_UNITY_NET * unity_net = ( IKE_UNITY_NET * ) ( attr->vdata.buff() + offset );

                                          IKE_PH2ID ph2id;
                                          memset( &ph2id, 0, sizeof( ph2id ) );

                                          ph2id.prot = unity_net->prot;
                                          ph2id.type = ISAKMP_ID_IPV4_ADDR_SUBNET;
                                          ph2id.addr1 = unity_net->addr;
                                          ph2id.addr2 = unity_net->mask;
                                          ph2id.port = unity_net->port_rmt;

                                          //
                                          // FIXME : there is a bug in racoon
                                          // that sends bogus protocol and port
                                          // information. I have comitted a fix
                                          // to ipsec-tools head and 0.7 but we
                                          // need to wait for that to settle
                                          // before we can remove the next two
                                          // lines of code;
                                          //

                                          ph2id.prot = 0;
                                          ph2id.port = 0;

                                          char txtid[ LIBIKE_MAX_TEXTP2ID ];
                                          text_ph2id( txtid, &ph2id );

                                          if( attr->atype == UNITY_SPLIT_INCLUDE )
                                          {
                                                if( unity_net->addr.s_addr &&
                                                      unity_net->addr.s_addr )
                                                {
                                                      log.txt( LLOG_DEBUG,
                                                            "ii : - IP4 Split Network Include = %s\n",
                                                            txtid );

                                                      cfg->tunnel->idlist_incl.add( ph2id );
                                                }
                                                else
                                                {
                                                      log.txt( LLOG_DEBUG,
                                                            "ii : - IP4 Split Network Include = %s ( invalid subnet ignored )\n",
                                                            txtid );
                                                }
                                          }
                                          else
                                          {
                                                if( unity_net->addr.s_addr &&
                                                      unity_net->addr.s_addr )
                                                {
                                                      log.txt( LLOG_DEBUG,
                                                            "ii : - IP4 Split Network Exclude = %s\n",
                                                            txtid );

                                                      cfg->tunnel->idlist_excl.add( ph2id );
                                                }
                                                else
                                                {
                                                      log.txt( LLOG_DEBUG,
                                                            "ii : - IP4 Split Network Exclude = %s ( invalid subnet ignored )\n",
                                                            txtid );
                                                }
                                          }
                                    }
                              }
                              else
                              {
                                    if( attr->atype == UNITY_SPLIT_INCLUDE )
                                          log.txt( LLOG_DEBUG,    "ii : - IP4 Split Network Include\n" );

                                    if( attr->atype == UNITY_SPLIT_EXCLUDE )
                                          log.txt( LLOG_DEBUG,    "ii : - IP4 Split Network Exclude\n" );
                              }

                              break;
                        }

                        case UNITY_BANNER:
                        {
                              getmask |= IPSEC_OPTS_BANNER;

                              if( ( readmask & IPSEC_OPTS_BANNER ) && attr->vdata.size() )
                              {
                                    cfg->tunnel->banner.add( 0, 1 );

                                    size_t size = 15;
                                    char text[ 16 ] = { 0 };
                                    if( size > attr->vdata.size() )
                                          size = attr->vdata.size();

                                    memcpy( text, attr->vdata.buff(), size );

                                    log.txt( LLOG_DEBUG,
                                          "ii : - Login Banner = %s ...\n",
                                          text );

                                    cfg->tunnel->banner.set( attr->vdata );
                                    cfg->tunnel->banner.add( 0, 1 );
                              }
                              else
                                    log.txt( LLOG_DEBUG,    "ii : - Login Banner\n" );

                              break;
                        }

                        case UNITY_PFS:
                        {
                              getmask |= IPSEC_OPTS_PFS;

                              if( ( readmask & IPSEC_OPTS_PFS ) && attr->basic )
                              {
                                    log.txt( LLOG_DEBUG,
                                          "ii : - PFS Group = %d\n",
                                          attr->bdata );

                                    cfg->tunnel->xconf.dhgr = attr->bdata;
                              }
                              else
                                    log.txt( LLOG_DEBUG,    "ii : - PFS Group\n" );

                              break;
                        }

                        case UNITY_SAVE_PASSWD:
                        {
                              getmask |= IPSEC_OPTS_SAVEPW;

                              if( ( readmask & IPSEC_OPTS_SAVEPW ) && attr->basic )
                              {
                                    log.txt( LLOG_DEBUG,
                                          "ii : - Save Password = %d\n",
                                          attr->bdata );

                                    cfg->tunnel->xconf.svpw = attr->bdata;
                              }
                              else
                                    log.txt( LLOG_DEBUG,    "ii : - Save Password\n" );

                              break;
                        }

                        default:
                              unhandled = true;
                  }
            }

            //
            // unknown attribute type
            //

            if( unhandled )
            {
                  if( attr->basic )
                        log.txt( LLOG_DEBUG,
                              "ii : - Unkown BASIC %u = %u\n",
                              attr->atype,
                              attr->bdata );
                  else
                        log.txt( LLOG_DEBUG,
                              "ii : - Unkown VARIABLE %u = %u bytes\n",
                              attr->atype,
                              attr->vdata.size() );
            }
      }

      return LIBIKE_OK;
}

long _IKED::config_chk_hash( IDB_PH1 * ph1, IDB_CFG * cfg, unsigned long msgid )
{
      BDATA hash_c;
      hash_c.size( ph1->hash_size );

      HMAC_CTX ctx_prf;
      HMAC_Init( &ctx_prf, ph1->skeyid_a.buff(), ( int ) ph1->skeyid_a.size(), ph1->evp_hash );
      HMAC_Update( &ctx_prf, ( unsigned char * ) &msgid, 4 );
      HMAC_Update( &ctx_prf, cfg->hda.buff(), cfg->hda.size() );
      HMAC_Final( &ctx_prf, hash_c.buff(), NULL );
      HMAC_cleanup( &ctx_prf );

      log.bin(
            LLOG_DEBUG,
            LLOG_DECODE,
            cfg->hash_r.buff(),
            cfg->hash_r.size(),
            "== : configure hash_i ( computed )" );

      log.bin(
            LLOG_DEBUG,
            LLOG_DECODE,
            hash_c.buff(),
            hash_c.size(),
            "== : configure hash_c ( computed )" );

      if( memcmp( cfg->hash_r.buff(), hash_c.buff(), hash_c.size() ) )
      {
            log.txt( LLOG_ERROR,    "!! : configure hash verification failed\n" );
            return LIBIKE_FAILED;
      }

      log.txt( LLOG_DEBUG,    "ii : configure hash verified\n" );
      return LIBIKE_OK;
}

long _IKED::config_message_send( IDB_PH1 * ph1, IDB_CFG * cfg )
{
      //
      // create config exchange packet
      //

      BDATA hash;
      hash.size( ph1->hash_size );

      PACKET_IKE packet;
      packet.set_msgid( cfg->msgid );

      packet.write( ph1->cookies, ISAKMP_PAYLOAD_HASH, ISAKMP_EXCH_CONFIG, ISAKMP_FLAG_ENCRYPT );

      size_t off = packet.size();

      payload_add_hash( packet, hash, ISAKMP_PAYLOAD_ATTRIB );

      size_t beg = packet.size();
      payload_add_cfglist( packet, cfg, ISAKMP_PAYLOAD_NONE );
      size_t end = packet.size();

      packet.done();

      //
      // create message authentication hash
      //

      HMAC_CTX ctx_prf;
      HMAC_Init( &ctx_prf, ph1->skeyid_a.buff(), ( int ) ph1->skeyid_a.size(), ph1->evp_hash );
      HMAC_Update( &ctx_prf, ( unsigned char * ) &cfg->msgid, sizeof( cfg->msgid ) );
      HMAC_Update( &ctx_prf, packet.buff() + beg, end - beg );
      HMAC_Final( &ctx_prf, hash.buff(), 0 );
      HMAC_cleanup( &ctx_prf );

      memcpy( packet.buff() + off + 4, hash.buff(), hash.size() );

      log.bin(
            LLOG_DEBUG,
            LLOG_DECODE,
            hash.buff(),
            hash.size(),
            "== : new configure hash" );

      packet_ike_send( ph1, cfg, packet, true );

      return LIBIKE_OK;
}

Generated by  Doxygen 1.6.0   Back to index