agentInit.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* file: agentInit.c
*
* This file contains the functions necessary to read
* and parse the /etc/inet/mipagent.conf configuration
* file.
*/
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <alloca.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/resource.h>
#include "mip.h"
#include "agent.h"
#include "conflib.h"
#include "pool.h"
#include "setup.h"
#include "mipagentstat_door.h"
/* Common to all mobility agents */
extern struct hash_table maAdvConfigHash;
extern char maNai[MAX_NAI_LENGTH];
/* Foreign Agent specific data structures. */
extern struct hash_table faVisitorHash;
/* Home Agent specific data structures. */
extern struct hash_table haMobileNodeHash;
/* This table stores all of the Security Violations */
extern struct hash_table mipSecViolationHash;
/* Home Agent specific data structures. */
#ifdef FIREWALL_SUPPORT
extern DomainInfo domainInfo;
#endif /* FIREWALL_SUPPORT */
extern uint32_t subagent_addr;
/*
* This table stores all of the Security Assocations
*/
extern HashTable mipSecAssocHash;
/*
* This table has one entry for each known Mobility Agent
*/
extern HashTable mipAgentHash;
/*
* This table has one entry for each pool defined in the config file
*/
extern HashTable mipPoolHash;
/*
* This table has one entry for each active tunnel number
*/
extern HashTable mipTunlHash;
/* Other external declarations */
extern int logVerbosity;
#ifdef RADIUS_ENABLED
extern int radiusEnabled;
extern char radiusSharedLibrary[];
#endif /* RADIUS_ENABLED */
extern int visitorEntryHighWaterMark;
extern int visitorEntryLowWaterMark;
extern int IDfreshnessSlack;
extern int advLifetime;
extern int periodicInterval;
extern boolean_t faChallengeAdv;
extern boolean_t mfAuthRequired;
extern boolean_t fhAuthRequired;
extern boolean_t shutdown_flag;
extern int performanceInterval;
extern boolean_t disableSNMP;
extern char *ipsec_policy_string[];
extern char *validIPsecAction[];
/* AAA Globals */
extern unsigned short gbl_aaaPort;
extern char gbl_aaaHost[];
extern AAA_Protocol_Code aaaProtocol;
/*
* Default Values...
*/
extern uint32_t defaultPool;
extern uint32_t defaultNodeSPI;
extern char *sprintTime(char *, int);
extern char *sprintRelativeTime(char *, int);
extern int hexConvert(char *, int, char *);
#ifdef FIREWALL_SUPPORT
extern void printProtectedDomainInfo(DomainInfo);
#endif /* FIREWALL_SUPPORT */
/* OS-specific initialization for Mobile IP */
extern void OScleanup();
/* Called when SIGUSR1 is received to save state. */
extern int saveAgentState(void);
extern int killDispatcherTaskThread();
extern int killPeriodicTaskThread();
extern int killSNMPTaskThread();
extern int killAAATaskThread();
extern int killStatServer();
extern void printMaAdvConfigHash(struct hash_table *);
extern void randomInit();
extern int InitNet();
extern void printHaMobileNodeHash(struct hash_table *);
extern int getdomainname(char *, int);
extern int installIPsecPolicy(char *);
extern int removeIPsecPolicy(char *);
extern int formIPsecBits(int, char *, char *, char *, size_t);
typedef struct {
char *string;
} Str2Int;
/* YES(x) simply checks to see if the string begins with a y. */
/*
* FA(x) needs to check if the FA is included in the setting. This happens
* if the setting is "yes", "both" or "fa" [and NOT when the setting is
* "no", "none", or "ha").
*/
(tolower(x) == 'b') || \
/*
* Macros to produce a quoted string containing the value of a
* preprocessor macro. For example, if SIZE is defined to be 256,
* VAL2STR(SIZE) is "256". This is used to construct format
* strings for scanf-family functions below.
*/
#define QUOTE(x) #x
/* The analogous HA(x) is not needed [yet] */
#define MAX_BUFFER_SIZE 1024
#define MAX_KEY_STRING_LEN 256
#define MAX_TAG_SIZE 30
/*
* Function: daemonInit
*
* Arguments:
*
* Description: This function will deamonize the agent
*
* Returns: int, -1 if the deamon could not be started.
*/
static int
{
switch (fork()) {
case -1:
perror("mipagent: can not fork");
return (-1);
case 0:
break;
default:
exit(0);
}
/*
* standard input, output, and error, and detach from
* controlling terminal.
*/
closefrom(0);
(void) dup(1);
(void) setsid();
(void) umask(0); /* clear file mode creation mask */
return (0);
}
/*
* Function: get_ipsec_support
*
* Parameters: s the PF_KEY socket
* struct sadb_msg *msg pointer to message buffer
* uint8_t satype which SA type (ah, or esp)
*
* Description: Builds, and writes an sadb_message to s, then reads until it
* gets the appropriate message, and returns the length so the caller
* knows how many bytes to parse.
*
* Returns: -1 on error.
* The length of what was put in msg on success.
*/
int
{
/* Note: parsing the <base, supported> msg requires an ipsec_req_t */
int len; /* what we'll return */
return (-1);
}
/* don't let stale data in msg confuse our read! */
/* send a <base> message to the kernel, get back <base, supported> */
do {
}
/*
* Function: IsIPsecLoaded()
*
* the globals ipsec_ah_loaded, and ipsec_esp_loaded are set directly for
* reference during init.
*/
{
int s;
/* Curious. We're root, or mipagent would've stopped by now */
return (_B_FALSE);
}
/* AH support? */
/* we got something back, so ah is supported */
/* ESP support? */
/* we got something back, so esp is supported */
(void) close(s);
return (_B_TRUE);
}
/*
* Funcition: setIPsecSAFlags
*
* Arguments: ipsr_p - pointer to an ipsec_req_t containing the ipsec policy.
* type - the type of service this policy is for (request, ...).
*
* Description: setIPsecSAFlags looks at the details of the ipsec policy, and
* returns a bit-field of what the policy is requiring in terms of
* AH and ESP support.
*
* Returns: The bit field indicating what of AH and ESP type is requiring.
*/
{
/* type defines how we set our bits. For now use low-order bits */
if (ipsr_p->ipsr_auth_alg)
/* Shift depending on the actual type */
switch (type) {
case IPSEC_REQUEST:
return (bitfield);
case IPSEC_REPLY:
return (bitfield << 2);
case IPSEC_TUNNEL:
return (bitfield << 4);
case IPSEC_REVERSE_TUNNEL:
return (bitfield << 6);
default:
"configuration type %d\n", type);
break;
}
return (0);
}
/*
* ParseAgentIPsecPolicy
*
* Arguments: mae - A pointer to a MobilityAgentEntry struct containing
* information about an agent-peer with which we may have
* to add IPsec security associations.
* ipsType - Identifies the type of IPsec Policy we're parsing.
* ipsp - The string that may contain one or two IPsec Policies.
* Keywords to look for are 'apply' and 'permit', and if
* both appear, the policies MUST be separated by a ':'.
*
* Description: We need to sanity check the policies pointed to by ipsp, and
* put them into the correct placeholder in the MobilityAgentEntry
* structure. We return the relavent bits in mpIPsecFlags so the
* caller knows which policies were found.
*
* Note: there can never be more than two bits set at once, one
* for the permit, and one for the apply of this ipsType,
* so a return of -1 is quite revealing!
*/
int
{
int i;
int policies_found = 0;
/* Oh, sanity... */
return (-1);
return (-1);
freeP = p; /* strtok_r() is destructive! */
/* lets just deal with lower case */
/*
* ipsec policies can only be passed one-at-a-time, so thunk if needed.
*
* Note: we don't know which order the user's put his actions in,
* so we have to always start at the begining of validIPsecAction[]s.
*/
if (++policies_found > IPSEC_ORDER) {
char peerAddr[IPv4_ADDR_LEN];
/* Tell the user they have too many */
return (-1);
}
for (i = 0; validIPsecAction[i] != NULL; i++) {
/*
* Fill a corresponding empty array with a policy
* containing this validIPsecAction[].
*/
!= NULL)) {
/* something new to parse */
char peerAddr[IPv4_ADDR_LEN];
switch (ipsType) {
case IPSEC_REQUEST:
if (isIPsecPolicyValid(ipsPolicy[i],
&(mae->maIPsecRequestIPSR[i]))
!= _B_TRUE) {
return (-1);
}
/* policy is OK (and parsed)! */
if (formIPsecBits(REQUEST(i),
&mae->maIPsecRequest[i][0],
sizeof (mae->maIPsecRequest[i]))
< 0) {
return (-1);
}
/* set SA flags */
mae->maIPsecSAFlags[i] |=
&mae->maIPsecRequestIPSR[i],
ipsType);
/* Remember we did this */
break;
case IPSEC_REPLY:
if (isIPsecPolicyValid(ipsPolicy[i],
&(mae->maIPsecReplyIPSR[i]))
!= _B_TRUE) {
return (-1);
}
/* policy is OK (and parsed)! */
if (formIPsecBits(REPLY(i),
&mae->maIPsecReply[i][0],
sizeof (mae->maIPsecReply[i]))
< 0) {
return (-1);
}
/* set SA flags */
mae->maIPsecSAFlags[i] |=
&mae->maIPsecReplyIPSR[i],
ipsType);
/* Remember we did this */
break;
/*
* For the tunnel policies, we pass the
* IPSR bits into the ioctl(), so we
* don't need to form the ASCII policy.
*/
case IPSEC_TUNNEL:
if (isIPsecPolicyValid(ipsPolicy[i],
&(mae->maIPsecTunnelIPSR[i]))
!= _B_TRUE) {
return (-1);
}
/* policy is OK (and parsed)! */
/* set SA flags */
mae->maIPsecSAFlags[i] |=
&mae->maIPsecTunnelIPSR[i],
ipsType);
/* Remember we did this */
break;
case IPSEC_REVERSE_TUNNEL:
if (isIPsecPolicyValid(ipsPolicy[i],
&(mae->maIPsecReverseTunnelIPSR[i]))
!= _B_TRUE) {
return (-1);
}
/* policy is OK (and parsed)! */
/* set SA flags */
mae->maIPsecSAFlags[i] |=
&mae->maIPsecReverseTunnelIPSR[i],
ipsType);
/* Remember we did this */
ipsFlags |= REVERSE_TUNNEL(i);
break;
}
}
}
/* setup for the next policy */
p = NULL;
}
/* we're out of policies */
/* reveal what we found */
return (ipsFlags);
}
/*
* Function: setupSPI
*
* Arguments: configFile - Pointer to config file
* SPIstr - Pointer to the section
*
* Description: This function will process an [SPI x] section.
* If the section is valid, we will create the
* static security assocation entry.
*
* Returns: int - 0 if successful.
*/
static int
{
int rc;
int i;
/* Agent Node */
char Key[MAX_KEY_STRING_LEN];
char mipSecKey[MAX_KEY_LEN];
Str2Int replayMethods[] = {
{ "none", NONE },
{ "timestamps", TIMESTAMPS },
/* SPI Definition */
if (rc != 2) {
return (-1);
}
/*
* GetPrivateProfileString() returns "-2" for all
* configuration file loading and parsing errors.
* Hence, to catch those errors, there is a check
* for rc == -2 here.
*/
if (rc == -2) {
return (-1);
}
if (*buffer == '\0') {
return (-1);
}
/* Check the replay method */
for (i = 0; replayMethods[i].string; i++) {
break;
}
}
"Possible values are (none or timestamps)", SPIstr);
return (-1);
}
if (rc == -2) {
return (-1);
}
if (Key[0] == 0) {
return (-1);
}
if (hexConvert((char *)mipSecKey,
return (-2);
}
/*
* Now we create the Security Assocation
*/
return (-2);
}
/*
* The Create function ends up locking the node, so
* we need to free it.
*/
return (0);
} /* setupSPI */
/*
* Function: setupAddress
*
* Arguments: configFile - Pointer to config file
* Address - Pointer to the section
*
* Description: This function will process an [Address x] section.
* If the section is valid, we will create the
* static Mobile Node or Mobility Agent entry.
*
* This function supports three different types
* of addresses:
* x.x.x.x - Normal IP Address format
* xxx@yyy - Network Access Identifier (up to 256 characters)
* Default-Node - Default Mobile Node Config
*
* Returns: int - 0 if successful.
*/
static int
{
/* Check what we were passed!!! */
"Error: Invalid Address passed to setupAddress.");
return (-1);
}
/*
* Mobile Node Definition -
*/
if (rc != 2) {
return (-1);
}
"Error: NAI too long in [%s...] section of config file.\n",
Address);
return (-1);
}
if (rc == -2) {
return (-1);
}
if (!*buffer) {
"Error in section [%s]", Address);
return (-1);
}
/* Figure out what type of address this is */
/*
* This is a default entry.... Fun and Joy!!
*/
if (SPI == -1) {
"Problem reading MobileNode <%s>. No SPI", Address);
return (-1);
}
/*
* The default SPI MUST be present, however the Pool is
* optional.
*/
if (Pool != -1) {
defaultPool = Pool;
}
/* Figure out what type of address this is */
if (SPI == -1) {
"Problem reading MobileNode <%s>. No SPI",
Address);
return (-1);
}
/*
* We don't need a pool every time we have an NAI (FA-only
* config, for example; NAIs are used for more than obtaining
* an address these days). If we end up being this node's HA
* and it needs an address, but there's none to give it (that
* is, we have a broken config, read: user error), then we'll
* reply with 130 "insufficient resources", and (hopefully)
* log the appropriate error in the user-feedback nicities.
*/
if (Pool != -1) {
/*
* If the MN will need a pool, it implies we'll need
* an NAI for identification!
*/
"Problem reading MobileNode <%s>. "
"Pool invalid for non-NAI addresses", Address);
return (-1);
}
} else {
Pool = 0; /* don't pass -1 into Create...(). */
}
/*
* And we create the Mobile Node
*/
} else {
}
"Unable to create MN-HA for %s", nodeID);
return (-2);
}
/*
* A successful Create...() function ends up locking the node,
* so we need to unlock it.
*/
/* Agent Node */
if (NAI) {
"Error: NAIs invalid for Agent Addresses");
return (-1);
}
/*
* The assumption, then, is nodeID is a dotted-decimal
* address. Even if not, we can use it to identify to
* the user which [Address *] section we're flagging.
*
* The SPI is for identifying the usual MD5 agent-agent
* SA/authentication, and has nothing to do with the SPI
* used by ipsec!
*/
if (SPI == -1) {
"Problem reading FA-HA-auth Node <%s>. No SPI",
nodeID);
return (-1);
}
"Unable to create HA-FA for %s", nodeID);
return (-2);
}
/* Check to see if there are any IPsec policies to apply */
"Catastrophic failure while trying to get "
"IPsecRequest configuration in the %s section "
"of %s. Please verify file integrity.",
return (-1);
}
if (*IPSPolicy) {
/*
* The first time we could have found an IPSec policy
* as restoring our state is done after we init. Note:
* we don't support NAIs, or MA-MA authenticators.
*/
IPSPolicy) < 0) {
/* syslog the error, and fail */
"IPsecRequest in [%s] section of %s.",
/* mipagent fails in these cases. */
return (-1);
}
}
"Catastrophic failure while trying to get "
"IPsecReply configuration in the %s section "
"of %s. Please verify file integrity.",
return (-1);
}
if (*IPSPolicy) {
/* parse it into it's individual properties */
IPSPolicy) < 0) {
/* syslog the error, and fail. */
" policy in [%s] section of %s",
/* mipagent fails in these cases. */
return (-1);
}
}
"Catastrophic failure while trying to get "
"IPsecTunnel configuration in the %s section of %s."
" Please verify file integrity.",
return (-1);
}
if (*IPSPolicy) {
/* parse it into it's individual properties */
IPSPolicy) < 0) {
/* syslog the error, and fail. */
" policy in [%s] section of %s",
/* mipagent fails in these cases. */
return (-1);
}
}
/*
* ipsec only supports symmetric tunnel policies, so we can't
* support asymmetric tunnel policies yet. When ipsec supports
* multiple per-socket policies, that will (likely) change.
* Note that if this GetPrivateProfileString() returns -2, we
* don't care.
*/
if (*IPSPolicy)
/*
* If the user tried the obvious tag, then at least
* warn them asymmetric tunnel policies are not
* supported at this time.
*/
"IPSecReverseTunnel. Asymmetric IPsec tunnel "
"policies are not supported at this time. Setting"
" reverse tunnel policies to conform to forward"
" tunnel settings.", Address);
/* Make the tunnel policies symmetric (for mipagentstat) */
/* tunnel apply = HA, so we set reverse tunnel permit */
/* tunnel apply = HA, so we set reverse tunnel permit */
/* tunnel permit = FA, so we set reverse tunnel apply */
/* tunnel permit = FA, so we set reverse tunnel apply */
/* if the user wants to use ipsec, see if we can */
if ((ipsec_loaded == _B_FALSE) &&
/* load, if not loaded */
if (IsIPsecLoaded() == _B_FALSE)
"Can't determine ipsec state. Configured "
"[%s] IPsec policies may fail to install!",
Address);
else
}
/* Is AH or ESP protection requested, but not offered? */
if ((!ipsec_ah_loaded) &&
/* --><-- user wants, not available (now) */
"IPsec AH protections, but AH is not "
if ((!ipsec_esp_loaded) &&
/* --><-- user wants, not available (now) */
"IPsec ESP protection, but ESP is not"
/*
* "IPsecRequest permit {properties}" are for HAs receiving
* registration requests from FAs, and so we need to be
* ready to receive these (they'll be unannounced).
* Pass down any of these policies now. Note: we don't check
* to see if it's been installed because we just read the
* policy, and we haven't called AgentRestoreState() yet!
*/
/*
* We found an IPsecRequest permit. Do whatever
* we do to install the ipsec policy.
*/
if (installIPsecPolicy(
"Could not install %s for [Address %s]: %s",
/* we're exiting, but unlock anyway */
/* mipagent fails to load at these times */
return (-1);
} else
/*
* success, set the flag. Note: this is NOT
* technically an agent-peer until we have
* a mobile node registered with it!
*/
}
/* done processing type = agent, UNLOCK! */
return (0);
} else {
"Error: invalid type in section [%s]", Address);
return (-1);
}
return (0);
} /* setupAddress */
/*
* Function: setupInterface
*
* Arguments: configFile - Pointer to config file
* Interface - Pointer to the interface section
*
* Description: This function will process an [Interface x] section.
* If the section is valid, we will create the
* static Interface entry.
*
* Returns: int - 0 if successful.
*/
static int
{
char buffer[MAX_BUFFER_SIZE];
/* Interface definition */
int advInterval;
int i;
/*
* We need a local regLifetime variable
*/
int regLifetime;
{ "homeAgent", ADV_IS_HOME_AGENT},
{ "foreignAgent", ADV_IS_FOREIGN_AGENT},
{ "registrationRequired", ADV_REGISTRATION_REQUIRED},
#ifdef ENABLE_ALL_FLAGS
{ "minEncap", ADV_MIN_ENCAP},
{ "greEncap", ADV_GRE_ENCAP},
{ "vjCompression", ADV_VJ_COMPRESSION},
#endif
{ "reverseTunnel", ADV_REVERSE_TUNNEL},
{ NULL, 0 }};
/* Search the file for Advertisements tags */
if (rc == -2) {
return (-1);
}
if (*buffer) {
/*
* If we're talking "reverseTunnel", then we only
* advertise what the setting for the FA is. This is
* because the only MNs that care about what's in these
* becons are those that are visiting this subnet, so
* if the setting for HA is no, but the setting for FA
* is yes, advertise them.
*/
} else {
}
continue;
}
} else {
}
}
}
/* regLifetime */
if (rc != -1)
regLifetime = rc;
/* advLifetime */
if (rc != -1)
advLifetime = rc;
/* periodicInterval */
advInterval = rc;
if (advInterval < DEFAULT_MIN_INTERVAL)
"advFrequency value exceeds recommended value: "
"less than or equal to %d",
(int)(advLifetime/3));
}
/* AdvInitCount */
/* AdvLimitUnsolicited */
if (rc == -2) {
return (-1);
}
}
if (advLimitUnsolicited == _B_FALSE)
advInitCount = 1;
/* Is Reverse Tunneling allowed on this interface? */
if (rc == -2) {
return (-1);
}
/* We support differenct HA and FA reverseTunnelAllowed settings. */
}
}
}
}
}
}
/* Is Reverse Tunneling required on this interface? */
if (rc == -2) {
return (-1);
}
/* We support differenct HA and FA reverseTunnelRequired settings */
}
}
}
}
}
}
if (rc != 2) {
return (-1);
}
if (rc == -2) {
return (-1);
}
if (*buffer) {
} else {
}
}
/* advertiseOnBcast */
if (rc == -2) {
return (-1);
}
if (*buffer) {
} else {
}
}
/*
* Note that the CreateInterfaceEntry does NOT lock the node
* and simply returns an int. Last argument is B_FALSE for static
* entries
*/
advInterval, _B_FALSE)) {
return (-2);
}
return (0);
} /* setupInterface */
/*
* Function: setupPool
*
* Arguments: configFile - Pointer to config file
* Poolstr - Pointer to the section
*
* Description: This function will process an [Pool x] section.
* If the section is valid, we will create the
* static Pool entry.
*
* Returns: int - 0 if successful.
*/
static int
{
/* SPI Definition */
if (rc != 2) {
return (-1);
}
if (rc == -2) {
return (-1);
}
if (*buffer == '\0') {
"Problem reading Pool <%d>. No BaseAddress", poolId);
return (-1);
}
if (poolSize == -1) {
return (-1);
}
/*
* Now we create the Security Assocation
*/
return (-2);
}
/*
* The Create function ends up locking the node, so
* we need to free it.
*/
return (0);
} /* setupPool */
/*
* Function: readGSPs
*
* Arguments: configFile - Pointer to config file
*
* Description: This function will parse the
* [GlobalSecurityParameters] section in the
* config file.
*
* Returns: void
*/
static void
readGSPs(char *configFile)
{
char buffer[MAX_BUFFER_SIZE];
char *GSP = "GlobalSecurityParameters";
/* IDfreshnessSlack */
if (rc != -1)
/*
* Is inter-Mobility-Agent Authentication Required?
*/
if (rc == -2) {
exit(1);
}
if (*buffer) {
else
}
/*
* Is Authentication between the Mobile Node and the Foreign
* agent required?
*/
if (rc == -2) {
exit(1);
}
if (*buffer) {
else
}
/*
* Should we be advertising the challenge?
*/
if (rc == -2) {
exit(1);
}
if (*buffer) {
else
}
/*
* What is our key distribution strategy?
*/
if (rc == -2) {
exit(1);
}
}
#ifdef RADIUS_ENABLED
/* Radius Library */
if (rc == -2) {
return (-1);
}
if (*radiusSharedLibrary) {
radiusEnabled = 0;
}
#endif /* RADIUS_ENABLED */
return;
} /* readGSPs */
/*
* Function: readAAASettings
*
* Arguments: configFile - Pointer to config file
*
* Description: This function will parse the
* [AAASettings] section in the config file.
*
* Returns: void
*/
/* ARGSUSED */
static void
readAAASettings(char *configFile)
{
#ifdef TEST_DIAMETER
char buffer[MAX_BUFFER_SIZE];
char *AAASettings = "AAASettings";
int rc;
#endif
/* First, set the defaults */
/*
* The only time we would ever want these configurable is during
* testing. So, only enable them when TEST_DIAMETER is defined.
*/
#ifdef TEST_DIAMETER
/* Server */
if (rc == -2) {
return (-1);
}
if (*buffer) {
}
/* Port */
if (rc != -1)
gbl_aaaPort = (short)rc;
mipverbose(("WARNING: Changing DIAMETER host/port to"
" %s:%d for testing!\n",
#endif
return;
} /* readGSPs */
/*
* Function: readGeneral
*
* Arguments: configFile - Pointer to config file
*
* Description: This function will parse the
* [General] section in the config file.
*
* Returns: int - 0 if successful.
*/
static int
readGeneral(char *configFile)
{
char buffer[MAX_BUFFER_SIZE];
char *General = "General";
int i;
Str2Int debugLevels[] = {
{ "quiet", 0 },
{ "low", 1 },
{ "norm", 2 },
{ "all", 3 },
/* Debug Level */
if (rc == -2) {
return (-1);
}
if (*buffer) {
for (i = 0; debugLevels[i].string; i++) {
break;
}
}
if (!debugLevels[i].string) {
/* Broke out of loop! */
" one of (quiet, low, norm, or all)");
return (-1);
}
}
/*
* Should we be advertising our NAI?
*/
if (rc == -2) {
return (-1);
}
if (*buffer) {
else
}
/* Visitor Entry High Water Mark */
if (rc != -1)
/* Visitor Entry Low Water Mark */
if (rc != -1)
/* periodicInterval - This one is undocumented. */
-1, configFile);
if (rc != -1) {
/*
* Magic numbers. Given that this is a faily dangerous
* feature, we need to restrict the values one can
* configure.
*/
if (rc < MIN_GARBAGE_COLLECTION_INTERVAL) {
} else if (rc > MAX_GARBAGE_COLLECTION_INTERVAL) {
}
}
/* performance checking interval - This one is undocumented. */
-1, configFile);
if (rc != -1) {
}
/*
* Should we be advertising our NAI?
*/
if (rc == -2) {
return (-1);
}
if (*buffer) {
else
}
/*
* Should SNMP be disabled?
*/
if (rc == -2) {
return (-1);
}
if (*buffer) {
else
}
return (0);
} /* readGeneral */
/*
* Function: memswp
*
* Arguments: A - Pointer to buffer
* B - Pointer to buffer
* length - length
*
* Description: This function will swap the contents
* of A and B.
*
* Returns: int - 0 if successful.
*/
static void
{
char *temp;
if (!temp) {
return;
}
}
/*
* Function: sortSections
*
* Arguments: Sections - Pointer to sections
* numSections - Number of sections
* sectionSize - Size of section
*
* Description: Since we have to have the Pools and SPIs defined
* before we add an address, move all of the addresses to the end
* of the sections. Use a single pass, starting at the end, and
* doing a direct swap.
*
* Returns:
*/
static void
{
int i;
int j = -1;
for (i = numSections-1; i >= 0; i--) {
/* Ok, we're stuck at a non-address, find one */
/* to exchange with us */
if (j < 0)
j = i-1;
for (; j >= 0; j--) {
"Address", 7)) {
/* Found one! Swap it */
&Sections[j*sectionSize],
/* break out of inner for loop */
break;
}
}
/* Check to see if we're finished */
if (j < 0)
return;
}
}
} /* sortSections */
/*
* Function: readConfigInfo
*
* Arguments: configFile - Pointer to filename
*
* Description: Read configuration information for the mobility
* agent from file
*
* Returns: int - 0 if successful
*/
static int
readConfigInfo(char *configFile)
{
char *Sections;
int numSections, sectionSize;
#ifdef FIREWALL_SUPPORT
domainInfo.firewallCnt = 0;
#endif /* FIREWALL_SUPPORT */
if (readGeneral(configFile)) {
return (-1);
}
/*
* Ok, now is when it gets a little complex. Read in all the
* section names, then add Interfaces and Mobile nodes as they
* come up.
*/
/*
* We need to check for NULL return from iniListSections,
* otherwise we would be accessing a NULL pointer.
*/
int i;
for (i = 0; i < numSections; i++) {
"Advertisements", 14)) {
if (setupInterface(configFile,
&Sections[i*sectionSize]))
return (-1);
"Address", 7)) {
if (setupAddress(configFile,
&Sections[i*sectionSize]))
return (-1);
"SPI", 3)) {
if (setupSPI(configFile,
&Sections[i*sectionSize]))
return (-1);
"Pool", 4)) {
if (setupPool(configFile,
&Sections[i*sectionSize]))
return (-1);
}
#ifdef FIREWALL_SUPPORT
/*
* XXX: Does this section need some enhancement ?.
*/
"Firewall", 8)) {
Firewall);
} /* end If */
#endif /* FIREWALL_SUPPORT */
} /* End for() each section */
}
}
return (0);
} /* readConfigInfo */
/*
* Function: InitSockets
*
* Arguments: pointer to MaAdvConfigEntry
*
* Description: This function will open the ICMP, BCAST and
* the multicast socket, and will bind on all
* interfaces configured. A specific Join must
* be done for multicast on each interface.
*
* Returns: int, 0 if successful
*/
int
{
int sid;
int enable = 1;
unsigned int ifceno;
char addrstr1[40];
struct sockaddr_in sa;
mipverbose(("Creating ICMP socket.\n"));
/*
* First off, let's get the interface number.
*/
if (ifceno == 0) {
"Unable to get interface number for %s",
entry->maIfaceName);
return (-1);
}
/* Get a socket to receive ICMPs on. */
"socket()Error: Couldn't create ICMP socket " \
"in InitSockets.");
return (-1);
}
/*
* Just in case we advertise on 255.255.255.255, enable
* bcast
*/
enable = 1;
(char *)&enable, sizeof (int)) < 0) {
return (-1);
}
sizeof (char *))) {
"Unable to bind socket to interface %d", ifceno);
return (-1);
}
/*
* Enable IP_XMIT_IF here so that we don't need to
* turn it on sendICMPmessage everytime we send
* multicast adv. IP_XMIT_IF will have to be set
* for all PPP interfaces, because there may be
* cases when PPP local and remote end both have
* non-unique addresses ( ex: private address)
*/
/*
* set IP_XMIT_IF
*/
"setsockopt() couldn't set IP_XMIT_IF"
"on Adv socket for interface id %d",
ifceno);
return (-1);
}
} else {
/*
* For non-pointtopoint interfaces we are still
* setting IP_MULTICAST_IF, as we expect to have
* unique ifaddr in this case.
* We can take advantage of cached routing entry
* too.
*/
"setsockopt() Couldn't set multicast"
"on socket");
return (-1);
}
}
/*
* Create and bind the socket to monitor the
* unicast interface addr
*/
"socket()Error: Couldn't create unicast UDP " \
"socket - to monitor unicast interface addr");
return (-1);
}
(char *)&enable, sizeof (int)) < 0) {
"socket - to monitor unicast interface addr");
}
mipverbose(("Binding UDP socket to %s port %d.\n",
"bind() Error: Could not bind unicast socket." \
"(maIfaceaddr): %m");
return (-1);
}
/*
* ToDO: Verify whether IP_RECV[IF|SLLA|TTL] socket
* options to be set here. This socket is used for
* broadcasting advertisements.
*/
sizeof (int)) < 0) {
"(maIfaceAddr):%m");
return (-1);
}
sizeof (int)) < 0) {
"(maIfaceAddr): %m");
return (-1);
}
sizeof (int)) < 0) {
"(maIfaceAddr): %m");
return (-1);
}
sizeof (char *))) {
"Unable to bind socket to interface %d", ifceno);
return (-1);
}
/*
* PPP interfaces would not receive any broadcast packets.
* Therefore we don't need to bind to broadcast addresses.
*/
/*
* Create and bind the socket to monitor
* the bcast interface addr
*/
"socket()Error:Couldn't create broadcast "
"UDP socket");
return (-1);
}
(char *)&enable, sizeof (int)) < 0) {
"on the broadcast UDP socket");
}
mipverbose(("Binding UDP socket to %s port %d.\n",
sizeof (sa)) < 0) {
"bind Error: Could not bind broadcast "
"socket - to monitor the bcast interface "
"addr");
return (-1);
}
/*
* TODO: Verify whether IP_RECV* sockets are useful
* in this socket which binds itself to link_broadcast
* address.
*/
sizeof (int)) < 0) {
"(LINK_BCAST_ADDR): %m");
return (-1);
}
sizeof (int)) < 0) {
"setsockopt IP_RECVSLLA failed "
"(LINK_BCAST_ADDR): %m");
return (-1);
}
sizeof (int)) < 0) {
"setsockopt IP_RECVTTL failed "
"(LINK_BCAST_ADDR): %m");
return (-1);
}
(char *)&ifceno, sizeof (char *))) {
"Unable to bind socket to interface %d",
ifceno);
return (-1);
}
/*
* Create and bind the socket to monitor
* the directed bcast interface addr
*/
"socket()Error:Couldn't create broadcast UDP "
"socket");
return (-1);
}
(char *)&enable, sizeof (int)) < 0) {
"on broadcast UDP socket");
}
mipverbose(("Binding UDP socket to %s port %d.\n",
sizeof (sa)) < 0) {
"bind Error: Could not bind broadcast "
"socket.");
return (-1);
}
/*
* Setting option on socket bound to NET_BROADCAST_ADDR
*/
sizeof (int)) < 0) {
"(NET_BROADCAST_ADDR): %m");
return (-1);
}
sizeof (int)) < 0) {
"(NET_BROADCAST_ADDR): %m");
return (-1);
}
sizeof (int)) < 0) {
"(NET_BROADCAST_ADDR): %m");
return (-1);
}
(char *)&ifceno, sizeof (char *))) {
"Unable to bind socket to interface %d",
ifceno);
return (-1);
}
enable = 1;
(char *)&enable, sizeof (int)) < 0) {
"(NET_BROADCAST_ADDR): %m");
}
} else {
/* Set fd to -1 */
}
/*
* Create and bind the socket to monitor
* the multicast advertisement traffic (224.0.0.1
* and 224.0.0.2)
*/
"socket() Error: Couldn't create ICMP socket " \
"in InitSockets to monitor mcast advertisement.");
return (-1);
}
sizeof (int)) < 0) {
return (-1);
}
sizeof (char *))) {
"Unable to bind socket to interface %d", ifceno);
return (-1);
}
/*
* Join multicast groups so we can receive ICMP messages
* on this interface sent to 224.0.0.1
*/
"Could not join multicast group 224.0.0.1");
} else {
mipverbose(("Joined %s on interface %s.\n",
}
/*
* Join multicast groups so we can receive ICMP messages
* on this interface sent to 224.0.0.2.
*/
"Could not join multicast group 224.0.0.2");
} else {
mipverbose(("Joined %s on interface %s.\n",
}
/*
* Create and bind the socket to monitor
* the multicast registration traffic (224.0.0.11)
*/
"socket()Error:Couldn't create broadcast UDP socket " \
"to monitor multicast registration traffic.");
return (-1);
}
(char *)&enable, sizeof (int)) < 0) {
"UDP socket to monitor mcast registration traffic.");
}
mipverbose(("Binding UDP socket to %s port %d.\n",
"bind Error: Could not bind broadcast socket.");
return (-1);
}
/* Set socket option for socket bound to 224.0.0.11 */
sizeof (int)) < 0) {
"(LINK_MCAST_REG_ADDR): %m");
return (-1);
}
sizeof (int)) < 0) {
"(LINK_MCAST_REG_ADDR): %m");
return (-1);
}
sizeof (int)) < 0) {
"(LINK_MCAST_REG_ADDR): %m");
return (-1);
}
sizeof (char *))) {
"Unable to bind socket to interface %d", ifceno);
return (-1);
}
/*
* Join 224.0.0.11 so we can receive Registration Requests
* from the multicast address.
*/
"Could not join multicast group 224.0.0.11");
} else {
mipverbose(("Joined %s on interface %s.\n",
}
return (0);
}
/*
* Function: deleteMobileNodeEntryHashHelper
*
* Arguments: entry - Pointer to Mobile Node Entry
* p1 - First parameter to match (current time)
*
* Description: This function is used as the Hash Table Helper routine
* for Finalize() when we need to delete all
* mobile node entries, and will be called by
* getAllHashTableEntries().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
/* ARGSUSED */
static boolean_t
{
while (bindingEntry) {
}
return (_B_FALSE);
}
/*
* Function: deleteVisitorEntryHashHelper
*
* Arguments: entry - Pointer to Mobile Node Entry
* p1 - First parameter to match (current time)
*
* Description: This function is used as the Hash Table Helper routine
* for Finalize() when we need to delete all
* visitor entries, and will be called by
* getAllHashTableEntries().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
/* ARGSUSED */
static boolean_t
{
return (_B_FALSE);
}
/*
* This funciton cleans up whatever registration policy is
* flagged as remaining. We don't clean up tunnels policy
* because that is done when the tunnel in encaprem() or
* decaprem(). We return _B_FALSE since we want the entry
* to be freed.
*/
/* ARGSUSED */
static boolean_t
{
int i;
for (i = FIRST_IPSEC_ACTION; i < LAST_IPSEC_ACTION; i++) {
}
return (_B_FALSE);
}
/*
* Function: Finalize
*
* Arguments: signo - signal
*
* Description: This function is the signal handler and is
* called when the agent is terminating. This
* function will destroy all of the threads,
* and free all of the binding and visitor entries
* which will clean up the Tunnel interfaces and the
* routing entries.
*
* Returns:
*/
/* ARGSUSED */
void
{
char relativeTime[MAX_TIME_STRING_SIZE];
char currentTime[MAX_TIME_STRING_SIZE];
/*
* First we need to kill all of the threads to ensure that no one
* will try to step on our toes. This will ensure that no other
* threads try to access any of the HashTables that we will need
* next.
*/
mipverbose(("<<< Shutting down threads >>>\n"));
if (DynamicInterface)
(void) killDynamicInterfaceThread();
(void) killDispatcherTaskThread();
(void) killPeriodicTaskThread();
(void) killSNMPTaskThread();
(void) killAAATaskThread();
(void) killStatServer();
/*
* Save the state of the entire agent (mobile node entries,
* (dynamic) security associations, IPsec SAs, and binding
* entries. This allows subsequent restoration of the state.
*/
(void) saveAgentState();
/*
* Let's delete all of the Mobile Node binding entries
* so we end up cleaning up our tunnel interfaces. Note that
* since we are coming down, we will not request any locks,
* since that could get the signal handler in a deadlock
* situation.
*/
/*
* Let's delete all of the Mobile Node binding entries
* so we end up cleaning up our routes. Note that
* since we are coming down, we will not request any locks,
* since that could get the signal handler in a deadlock
* situation.
*/
/*
* Finally clean up any IPsec policies we have installed! We don't
* do this above, because cleaning out the FA removed those
* specific to the FA, now we'll clean up the rest.
*/
OScleanup();
exit(1);
}
/*
* Function: docleanup
*
* Arguments:
*
* Description: This function is called when the AAA connection
* to mipagent is down. The function will
* free all of the binding and visitor entries
* which will clean up the Tunnel interfaces and the
* routing entries.
* Returns:
*/
void
docleanup(void)
{
char relativeTime[MAX_TIME_STRING_SIZE];
char currentTime[MAX_TIME_STRING_SIZE];
mipverbose(("mipagent-AAA connection is down\n"));
/*
* Let's delete all of the Mobile Node binding entries
* so we end up cleaning up our tunnel interfaces.
*/
/*
* Let's delete all of the Mobile Node binding entries
* so we end up cleaning up our routes.
*/
}
/*
* Function: SetSigHandlers
*
* Arguments: Set up handlers for various signals
*
* Description:
*
* Returns:
*/
static void
{
"signal() Error: failed to set handler for SIGINT.");
}
"signal() Error: failed to set handler for SIGTERM.");
}
}
/*
* Function: showConfigInfo
*
* Arguments:
*
* Description: This function will print out the current
* configuration of the agent.
*
* Returns:
*/
static void
{
#ifdef RADIUS_ENABLED
if (radiusEnabled)
mipverbose((" RadiusSharedLibrary : %s\n",
#endif /* RADIUS_ENABLED */
/*
* No longer used
* mipverbose(("AdvLifetime : %d\n", advLifetime));
* mipverbose(("RegLifetime : %d\n", regLifetime));
*/
mipverbose(("\n"));
mipverbose(("\n"));
mipverbose(("\n"));
#ifdef FIREWALL_SUPPORT
#endif /* FIREWALL_SUPPORT */
mipverbose(("\n"));
}
/*
* Function: Initialize
*
* Arguments: configFile - Pointer to the config file name
*
* Description: This is the main initialization function. This
* function will initialize the hash tables, retrieve
* our NAI, read the config file and initialize the
* network interfaces.
*
* Returns: int, 0 if successful
*/
int
Initialize(char *configFile)
{
char domainname[MAX_NAI_LENGTH];
char currentTime[MAX_TIME_STRING_SIZE];
char relativeTime[MAX_TIME_STRING_SIZE];
struct hash_table *htbl;
struct hash_entry *pentry;
int i;
/* Make sure we are running as root. */
if (getuid()) {
"mipagent: Error: must be run by root\n");
return (-1);
}
/* Initiate global DynamicInterface variables here */
/* Can we find, and read our config file? */
/*
* config file non existent, or can't be read...
* keel over verbosely (is there an other way?)
*/
"access() error %m.");
/* Spit a critical startup error to the user, too */
"or not readable, cannot initialize.\n");
/* tell the calling function it can keel over now. */
return (-1);
}
/* Initialize random number generator */
randomInit();
/* Get the hosts' Network Access Identifier */
return (-1);
}
errno = 0;
if (errno != 0) {
return (-1);
}
/*
* Initialize the hash tables
*/
if (InitHash(&faVisitorHash)) {
return (-1);
}
if (InitHash(&maAdvConfigHash)) {
return (-1);
}
if (InitHash(&haMobileNodeHash)) {
return (-1);
}
if (InitHash(&mipSecAssocHash)) {
"Unable to initialize security associations hash table");
return (-1);
}
if (InitHash(&mipAgentHash)) {
return (-1);
}
if (InitHash(&mipSecViolationHash)) {
"Unable to initialize security violation hash table");
return (-1);
}
if (InitHash(&mipPoolHash)) {
return (-1);
}
if (InitHash(&mipTunlHash)) {
return (-1);
}
/* Initialize maAdvConfigTable and haMobileNodeTable from file */
if (readConfigInfo(configFile) < 0) {
return (-1);
}
/*
* Initialize itself as a daemon
*/
if (daemonInit() == -1)
exit(1);
}
/* OS-specific initialization of tunneling module etc */
if (InitNet() == -1) {
return (-1);
}
/* OS-neutral, socket initialization */
htbl = &maAdvConfigHash;
return (-1);
}
}
}
/* Set up periodic house keeping and other chores */
return (0);
}