/*
---------------------------------------------------------------------------
 $Id: tsp_setup.c,v 1.29 2007/04/26 20:10:07 cnepveu Exp $
---------------------------------------------------------------------------
Copyright (c) 2001-2007 Hexago Inc. All rights reserved.

  LICENSE NOTICE: You may use and modify this source code only if you
  have executed a valid license agreement with Hexago Inc. granting
  you the right to do so, the said license agreement governing such
  use and modifications.   Copyright or other intellectual property
  notices are not to be removed from the source code.
---------------------------------------------------------------------------
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>

#include "platform.h"

#include "tsp_setup.h"

#include "config.h" // tConf
#include "xml_tun.h"  // tTunnel
#include "log.h"  // Display()
#include "hex_strings.h" // Strings for Display()
#include "lib.h"  // IsAll()

// Gateway6 Client Messaging Subsystem.
#include <gw6cmessaging/gw6c_c_wrapper.h>


/*  Should be defined in platform.h  */
#ifndef SCRIPT_TMP_FILE
#define SCRIPT_TMP_FILE "/tmp/gw6c-tmp.log"
#endif

/* to remove a warning. This is not right,
   it is already declared in tsp_client.h.
   */

extern void tspSetEnv(char *, char *, int);
extern int  tspSetupInterfaceLocal(tConf *c, tTunnel *t);   // Defined in tsp_local.c of each platform.


/* Execute cmd and send output to log subsystem */
int execScript(const char *cmd)
{
  char buf[16384];

  char *ptr,*ptr2;
  int retVal, fd, n,i , used;

  memset(buf, 0, sizeof(buf));
  snprintf(buf,sizeof(buf),"%s > %s", cmd, SCRIPT_TMP_FILE);
  retVal = system(buf);

  if((fd = open(SCRIPT_TMP_FILE,O_RDONLY)) == -1) {
    Display(LOG_LEVEL_3,ELError,"tspSetupInterface",HEX_STR_CANT_OPEN_TMP_FILE SCRIPT_TMP_FILE);
    return -1;
  }


  ptr2 = buf;
  used = 0;
  while( (n = read(fd, ptr2, sizeof(buf) - used ) ) > 0) {
    ptr=ptr2;
    for(i=0;i<n;i++) {
      if(ptr2[i] == '\n' ) {
        ptr2[i] = 0;
        Display(LOG_LEVEL_MAX,ELInfo,"Script","%s",ptr);
        ptr=ptr2+i+1;
      }
    }
    ptr2=ptr;
    used = buf-ptr2;
  }

  close(fd);
  unlink(SCRIPT_TMP_FILE);

  return retVal;
}

// --------------------------------------------------------------------------
// This function will set the required environment variables that will later
// be used when invoking the template script to actually create the tunnel.
//
int tspSetupInterface(tConf *c, tTunnel *t)
{
  char buf[1024];
  int Err = 0;
  int ret;
  FILE *template = NULL;


  // Specify the tunnel mode.
  tspSetEnv("TSP_TUNNEL_MODE", t->type, 1);

  // Specify host type {router, host}
  tspSetEnv("TSP_HOST_TYPE", c->host_type, 1);

  // Specify tunnel interface, for setup.
  if (strcasecmp(t->type, STR_XML_TUNNELMODE_V6V4) == 0 )
  {
    tspSetEnv("TSP_TUNNEL_INTERFACE", c->if_tunnel_v6v4, 1);
    gTunnelInfo.eTunnelType = TUNTYPE_V6V4;
  }
  else if (strcasecmp(t->type, STR_XML_TUNNELMODE_V6UDPV4) == 0 )
  {
    tspSetEnv("TSP_TUNNEL_INTERFACE", c->if_tunnel_v6udpv4, 1);
    gTunnelInfo.eTunnelType = TUNTYPE_V6UDPV4;
  }
#ifdef V4V6_SUPPORT
  else if (strcasecmp(t->type, STR_XML_TUNNELMODE_V4V6) == 0 )
  {
    tspSetEnv("TSP_TUNNEL_INTERFACE", c->if_tunnel_v4v6, 1);
    gTunnelInfo.eTunnelType = TUNTYPE_V4V6;
  }
#endif /* V4V6_SUPPORT */

  // Specify what interface will be used for routing advertizement,
  // if enabled.
  tspSetEnv("TSP_HOME_INTERFACE",      c->if_prefix, 1);

  // Specify local endpoint IPv4 address
  if(IsAll(IPv4Addr, t->client_address_ipv4))
  {
    tspSetEnv("TSP_CLIENT_ADDRESS_IPV4", t->client_address_ipv4, 1);
    gTunnelInfo.szIPV4AddrLocalEndpoint = t->client_address_ipv4;
  }
  else
  {
    Display(LOG_LEVEL_3, ELError, "tspSetupInterface", HEX_STR_BAD_CLIENT_IPV4_RECVD);
    Err++;
  }

  // Specify local endpoint IPv6 address
  if(IsAll(IPv6Addr, t->client_address_ipv6))
  {
    tspSetEnv("TSP_CLIENT_ADDRESS_IPV6", t->client_address_ipv6, 1);
    gTunnelInfo.szIPV6AddrLocalEndpoint = t->client_address_ipv6;
  }
  else
  {
    Display(LOG_LEVEL_3, ELError, "tspSetupInterface", HEX_STR_BAD_CLIENT_IPV6_RECVD);
    Err++;
  }

  // Specify local endpoint domain name
  if(t->client_dns_name)
  {
    tspSetEnv("TSP_CLIENT_DNS_NAME", t->client_dns_name, 1);
    gTunnelInfo.szUserDomain = t->client_dns_name;
  }

  // Specify remote endpoint IPv4 address.
  if(IsAll(IPv4Addr, t->server_address_ipv4))
  {
    tspSetEnv("TSP_SERVER_ADDRESS_IPV4", t->server_address_ipv4, 1);
    gTunnelInfo.szIPV4AddrRemoteEndpoint = t->server_address_ipv4;
  }
  else {
    Display(LOG_LEVEL_3, ELError, "tspSetupInterface", HEX_STR_BAD_SERVER_IPV4_RECVD);
    Err++;
  }

  // Specify remote endpoint IPv6 address.
  if(IsAll(IPv6Addr, t->server_address_ipv6))
  {
    tspSetEnv("TSP_SERVER_ADDRESS_IPV6", t->server_address_ipv6, 1);
    gTunnelInfo.szIPV6AddrRemoteEndpoint = t->server_address_ipv6;
  }
  else {
    Display(LOG_LEVEL_3, ELError, "tspSetupInterface", HEX_STR_BAD_SERVER_IPV6_RECVD);
    Err++;
  }

  // Specify prefix for tunnel endpoint.
  if ((strcasecmp(t->type, STR_XML_TUNNELMODE_V6V4) == 0) ||
      (strcasecmp(t->type, STR_XML_TUNNELMODE_V6UDPV4) == 0))
    tspSetEnv("TSP_TUNNEL_PREFIXLEN", "128", 1);
#ifdef V4V6_SUPPORT
  else
    tspSetEnv("TSP_TUNNEL_PREFIXLEN", "32", 1);
#endif /* V4V6_SUPPORT */


  // Free and clear delegated prefix from tunnel info.
  if( gTunnelInfo.szDelegatedPrefix != NULL )
  {
    free( gTunnelInfo.szDelegatedPrefix );
    gTunnelInfo.szDelegatedPrefix = NULL;
  }

  // Have we been allocated a prefix for routing advertizement..?
  if(t->prefix)
  {
    if(IsAll(IPAddrAny, t->prefix))
    {
      char chPrefix[128];
      int len, sep;

      /* Compute the number of characters that are significant out of the prefix. */
      /* This is meaningful only for IPv6 prefixes; no contraction is possible for IPv4. */
      if ((strcasecmp(t->type, STR_XML_TUNNELMODE_V6V4) == 0) ||
          (strcasecmp(t->type, STR_XML_TUNNELMODE_V6UDPV4) == 0))
      {
        len = (atoi(t->prefix_length) % 16) ? (atoi(t->prefix_length) / 16 + 1) * 4 : atoi(t->prefix_length) / 16 * 4;
        sep = (atoi(t->prefix_length) % 16) ? (atoi(t->prefix_length) / 16) : (atoi(t->prefix_length) / 16) -1;
      }
      else
      {
        len = strlen( t->prefix );
        sep = 0;
      }

      memset(chPrefix, 0, 128);
      memcpy(chPrefix, t->prefix, len+sep);

      // Specify delegated prefix for routing advertizement, if enabled.
      tspSetEnv("TSP_PREFIX", chPrefix, 1);
      gTunnelInfo.szDelegatedPrefix = (char*) malloc( strlen(chPrefix) + 10/*To append prefix_length*/ );
      strcpy( gTunnelInfo.szDelegatedPrefix, chPrefix );
    }
    else
    {
      Display(LOG_LEVEL_3, ELError, "tspSetupInterface", HEX_STR_BAD_SERVER_PREFIX_RECVD);
      Err++;
    }

    // Specify prefix length for routing advertizement, if enabled.
    if(IsAll(Numeric, t->prefix_length))
    {
      tspSetEnv("TSP_PREFIXLEN", t->prefix_length, 1);
      strcat( gTunnelInfo.szDelegatedPrefix, "/" );
      strcat( gTunnelInfo.szDelegatedPrefix, t->prefix_length );
    }
    else
    {
      Display(LOG_LEVEL_3, ELError, "tspSetupInterface", HEX_STR_BAD_PREFIX_LEN_RECVD);
      Err++;
    }
  }


  // Do some platform-specific stuff before tunnel setup script is launched.
  //
  if( Err == 0 )
  {
    // Do additionnal configuration. The "tspSetupInterfaceLocal" is defined in
    //   tsp_local.c in every platform.
    Err += tspSetupInterfaceLocal( c, t );
  }


  if(Err)
  {
    // Errors occured during verification of tunnel parameters.
    Display(LOG_LEVEL_2,ELError, "tspSetupInterface", HEX_STR_ERRS_IN_SERVER_RESP);
    return 1;
  }

  snprintf(buf, sizeof buf, "%d", LOG_LEVEL_MAX);

  tspSetEnv("TSP_VERBOSE",           buf, 1);
  tspSetEnv("TSP_HOME_DIR",          TspHomeDir, 1);

  snprintf(buf, sizeof buf, "%s%c%s.%s", ScriptDir, DirSeparator, c->template, ScriptExtension);
  if ((template = fopen(buf, "r")) == NULL) {
    Display(LOG_LEVEL_1, ELError, "tspSetupInterface", HEX_STR_TEMPLATE_NOT_FOUND, buf);
    return 1;
  }
  else {
    fclose(template);
    memset(buf, 0, sizeof buf);
  }

  if (ScriptInterpretor != NULL)
    snprintf(buf, sizeof buf, "%s \"%s%c%s.%s\"", ScriptInterpretor, ScriptDir, DirSeparator, c->template, ScriptExtension);
  else
    snprintf(buf, sizeof buf, "\"%s%c%s.%s\"", ScriptDir, DirSeparator, c->template, ScriptExtension);

  Display(LOG_LEVEL_2, ELInfo, "tspSetupInterface", HEX_STR_EXEC_CFG_SCRIPT, buf);


  // ------------------------------------------------
  // Run the template script to bring the tunnel up.
  // ------------------------------------------------
  if( (ret = execScript(buf)) == 0 )
  {
    Display(LOG_LEVEL_2, ELInfo, "tspSetupInterface", HEX_STR_SCRIPT_COMPLETED_OK);

    if ((strcasecmp(t->type, STR_XML_TUNNELMODE_V6V4) == 0) ||
          (strcasecmp(t->type, STR_XML_TUNNELMODE_V6UDPV4) == 0))
      Display(LOG_LEVEL_1, ELInfo, "tspSetupInterface", HEX_STR_YOUR_IPV6_IP_IS, t->client_address_ipv6);
#ifdef V4V6_SUPPORT
    else
      Display(LOG_LEVEL_1, ELInfo, "tspSetupInterface", HEX_STR_YOUR_IPV4_IP_IS, t->client_address_ipv4);
#endif /* V4V6_SUPPORT */

    if ((t->prefix != NULL) && (t->prefix_length != NULL))
    {
      if ((strcasecmp(t->type, STR_XML_TUNNELMODE_V6V4) == 0) ||
        (strcasecmp(t->type, STR_XML_TUNNELMODE_V6UDPV4) == 0))
        Display(LOG_LEVEL_1, ELInfo, "tspSetupInterface", HEX_STR_YOUR_IPV6_PREFIX_IS, t->prefix, t->prefix_length);
#ifdef V4V6_SUPPORT
      else
        Display(LOG_LEVEL_1, ELInfo, "tspSetupInterface", HEX_STR_YOUR_IPV4_PREFIX_IS, t->prefix, t->prefix_length);
#endif /* V4V6_SUPPORT */
    }

    if (t->type != NULL)
    {
      Display(LOG_LEVEL_2, ELInfo, "tspSetupInterface", HEX_STR_SETUP_TUNNEL_TYPE, t->type);
    }

    Display(LOG_LEVEL_3, ELInfo, "tspSetupInterface", HEX_STR_SETUP_PROXY, c->proxy_client == TRUE ? HEX_STR_ENABLED : HEX_STR_DISABLED);

    if (c->host_type != NULL)
    {
      Display(LOG_LEVEL_3, ELInfo, "tspSetupInterface", HEX_STR_SETUP_HOST_TYPE, c->host_type);
    }

    // Set the broker used for connection.
    gTunnelInfo.szBrokerName = c->server;

    // Set the current time(now) for tunnel start.
    gTunnelInfo.tunnelUpTime = time(NULL);

    // Send the tunnel info through the messaging subsystem.
    send_tunnel_info();
  }

  return ret;
}




syntax highlighted by Code2HTML, v. 0.9.1