summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c')
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c1079
1 files changed, 1079 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c b/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c
new file mode 100644
index 0000000000..2580ab2150
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c
@@ -0,0 +1,1079 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Functions used to save and read the binding table for persistence across
+ * mipagent reboots.
+ * Saving should be invoked by sending mipagent the proper signal.
+ * After the signal is trapped, the functions here are invoked and save
+ * the state into the binary file:
+ * "/var/inet/mipagent_state"
+ * The file
+ * "/var/inet/mipagent_state.lock"
+ * is used as a mutex.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <thread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+
+#include "impl.h"
+
+#include "agent.h"
+#include "setup.h"
+#include "hash.h"
+#include "conflib.h"
+
+#define MAXLINELENGTH 200
+/* file to save all mobility bindings to capture state across reboots */
+#define SAVE_BINDINGS_FILE "/var/inet/mipagent_state"
+#ifdef LOCKFILE
+#define SAVE_BINDINGS_LOCK_FILE "/var/inet/mipagent_state.lock"
+#endif /* LOCKFILE */
+#define ENVVAR "MIPAGENT_SAVE_STATE"
+
+/* Controls verbosity of debug messages when compiled w/ "-D MIP_DEBUG" */
+extern int logVerbosity;
+
+/*
+ * Counters maintained by Home Agents
+ */
+extern HomeAgentCounters haCounters;
+
+/* Home Agent specific data structures. */
+extern HashTable haMobileNodeHash;
+extern HashTable mipSecAssocHash;
+extern HashTable mipAgentHash;
+
+extern int installIPsecPolicy(char *);
+extern MobilityAgentEntry *findMaeFromIp(ipaddr_t, int);
+
+static FILE *agentStateFile; /* file ptr for the state file */
+#ifdef LOCKFILE
+static int lockFile; /* lock file file descriptor */
+#endif /* LOCKFILE */
+
+static int preFileAccess(boolean_t forReading);
+static int postFileAccess(void);
+static void removeStateFile(void);
+static size_t saveOneEntry(void *ptr, size_t size);
+static size_t readOneEntry(void *ptr, size_t size);
+int restoreIPsecPolicies(MobilityAgentEntry *, MobilityAgentEntry *);
+
+extern char *validIPsecAction[];
+extern char *ntoa(uint32_t, char *);
+
+/*
+ * Function: saveAgentState
+ *
+ * Arguments: None.
+ *
+ * Description: Save mobile node binding entries. ret 1 if ok, 0 otherwise.
+ *
+ * Note: This routine must be called only when everything
+ * is quiescent. Otherwise inconsistent state may result
+ * if new security associations, mobile node entries
+ * or binding entries are being created as the state
+ * is being saved.
+ *
+ * Returns: 1 if ok, 0 otherwise.
+ */
+
+int
+saveAgentState(void)
+{
+ HashEntry *hashEntry;
+ HaMobileNodeEntry *hamne;
+ HaBindingEntry *habe;
+ MipSecAssocEntry *sae;
+ MobilityAgentEntry *mae;
+ int EntriesSaved, numBindings;
+ int i;
+
+ /* Prepare for security association file access. */
+ if (preFileAccess(_B_FALSE) == -1) {
+ mipverbose(("Could not prepare state file for writing.\n"));
+ return (0);
+ }
+
+ /*
+ * Only save the *dynamic* security associations.
+ * First: count them, and write that number.
+ * Then: do the actual saves.
+ */
+ EntriesSaved = 0;
+ for (i = 0; i < HASH_TBL_SIZE; i++) {
+ if (mipSecAssocHash.buckets[i]) {
+ for (hashEntry = mipSecAssocHash.buckets[i];
+ hashEntry != NULL;
+ hashEntry = hashEntry->next) {
+ sae = hashEntry->data;
+ if (sae == NULL)
+ continue;
+ if (! sae->mipSecIsEntryDynamic)
+ continue;
+ ++EntriesSaved;
+ }
+ }
+ }
+
+ /*
+ * First item to write out: the number of dynamic security
+ * associations which follow.
+ */
+ if (saveOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved)) != 1) {
+ mipverbose(("Problem saving the number of dynamic of"
+ "security associations.\n"));
+ (void) postFileAccess();
+ (void) rw_unlock(&sae->mipSecNodeLock);
+ (void) rw_unlock(&mipSecAssocHash.bucketLock[i]);
+ return (0);
+ }
+
+ /*
+ * Now: write out the actual dynamic security
+ * associations.
+ */
+ for (i = 0; (EntriesSaved > 0) && (i < HASH_TBL_SIZE); i++) {
+ if (mipSecAssocHash.buckets[i]) {
+ for (hashEntry = mipSecAssocHash.buckets[i];
+ hashEntry != NULL;
+ hashEntry = hashEntry->next) {
+
+ sae = hashEntry->data;
+ if (sae == NULL)
+ continue;
+
+ /*
+ * If the entry is static there is
+ * no need to save it, as it will
+ * get restored out of the configuration
+ * file.
+ */
+ if (! sae->mipSecIsEntryDynamic)
+ continue;
+ /*
+ * Now it's safe to write out the sec
+ * association entry.
+ */
+ if (saveOneEntry((void *) sae,
+ sizeof (MipSecAssocEntry)) != 1) {
+ mipverbose(("Problem saving a mobile "
+ "node entry.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ --EntriesSaved;
+ }
+ }
+ }
+
+ /*
+ * Now we'll save the agent-peer entries.
+ * First: count them, and write that number.
+ * Then: do the actual saves.
+ */
+ EntriesSaved = 0;
+ for (i = 0; i < HASH_TBL_SIZE; i++) {
+ if (mipAgentHash.buckets[i]) {
+ for (hashEntry = mipAgentHash.buckets[i];
+ hashEntry != NULL;
+ hashEntry = hashEntry->next) {
+ mae = hashEntry->data;
+ if (mae == NULL)
+ continue;
+ ++EntriesSaved;
+ }
+ }
+ }
+
+ /*
+ * Now write out the number of agent-peer entries which follow
+ */
+ if (saveOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved)) != 1) {
+ mipverbose(("Problem saving the number of "
+ "agent-peer entries.\n"));
+ (void) postFileAccess();
+ (void) rw_unlock(&mipAgentHash.bucketLock[i]);
+ return (0);
+ }
+
+ /*
+ * Now: write out the actual agent-peer entries.
+ */
+ for (i = 0; (EntriesSaved > 0) && (i < HASH_TBL_SIZE); i++) {
+ if (mipAgentHash.buckets[i]) {
+ for (hashEntry = mipAgentHash.buckets[i];
+ hashEntry != NULL;
+ hashEntry = hashEntry->next) {
+
+ mae = hashEntry->data;
+
+ if (mae == NULL)
+ continue;
+
+ /*
+ * Write out the agent-peer entry
+ */
+ if (saveOneEntry((void *) mae,
+ sizeof (MobilityAgentEntry)) != 1) {
+ mipverbose(("Problem saving an agent-"
+ "peer entry.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ --EntriesSaved;
+ }
+ }
+ }
+
+
+ /*
+ * Now save each mobile node entry.
+ */
+ for (i = 0; i < HASH_TBL_SIZE; i++) {
+ if (haMobileNodeHash.buckets[i]) {
+
+ for (hashEntry = haMobileNodeHash.buckets[i];
+ hashEntry != NULL;
+ hashEntry = hashEntry->next) {
+
+ hamne = hashEntry->data;
+ /*
+ * This should have been != NULL, instead
+ * of == NULL. The issue is that we would
+ * never properly reload existing registrations
+ * if the agent was re-started.
+ */
+ if (hamne != NULL)
+ /*
+ * Instead of trusting it to really
+ * know how many bindings it has, i'll
+ * go ahead and count them just to really
+ * make sure. Otherwise we could end up with
+ * null pointers, core dumps, etc... it's
+ * one more traversal, but most of the time
+ * there's zero or one binding, and the max
+ * is small anyway... Little extra price to pay
+ * to be able to sleep at night...
+ * This way, when we read the mn entry we
+ * know we can trust the number of bindings to
+ * know how many binding entries to read after
+ * that.
+ */
+ for (numBindings = 0,
+ habe = hamne->bindingEntries;
+ habe != NULL &&
+ (numBindings <
+ MAX_SIMULTANEOUS_BINDINGS);
+ ++numBindings, habe = habe->next);
+
+ /*
+ * finished counting the number of
+ * bindings...
+ */
+ if (numBindings != hamne->haMnBindingCnt) {
+ mipverbose(("Miscounted number of "
+ "bindings! (fixing...)\n"));
+ hamne->haMnBindingCnt = numBindings;
+ }
+
+ if (numBindings != 0) {
+ /*
+ * Now it's safe to write out the
+ * mobile node entry.
+ */
+ if (saveOneEntry((void *) hamne,
+ sizeof (HaMobileNodeEntry)) != 1) {
+ mipverbose(("Problem saving "
+ "a mobile node entry.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+
+#ifdef RADIUS_ENABLED
+ /*
+ * Save any haRadiusState as
+ * len:radiusState
+ */
+
+ if (MobileNodeEntry->haRadiusState !=
+ NULL) {
+ size_t len = strlen(
+ hamne->haRadiusState);
+ if (1 != fwrite((void *) &len,
+ sizeof (size_t), 1,
+ agentStateFile)) {
+ mipverbose((
+ "Problem saving "
+ "length %d of "
+ "radius state"
+ "%s.\n", len,
+ hamne->
+ haRadiusState));
+ (void) postFileAccess();
+ return (0);
+ }
+ if (len != fwrite((void *)
+ hamne->haRadiusState,
+ sizeof (char),
+ len, agentStateFile)) {
+ mipverbose((
+ "Problem saving "
+ "radius state %s."
+ "\n",
+ hamne->
+ haRadiusState));
+ (void) postFileAccess();
+ return (0);
+ }
+ }
+#endif /* RADIUS_ENABLED */
+
+ /*
+ * 2nd traversal of the bindings chain:
+ * save each binding
+ */
+ for (habe = hamne->bindingEntries;
+ habe != NULL;
+ habe = habe->next) {
+
+ if (saveOneEntry((void *) habe,
+ sizeof (HaBindingEntry))
+ != 1) {
+ mipverbose(("Problem "
+ "saving a binding"
+ "entry.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ }
+ }
+ }
+ }
+}
+
+if (postFileAccess() == -1)
+ return (0);
+ return (1);
+ } /* saveAgentState(void) */
+
+/* returns 1 if ok, 0 otherwise. */
+static int
+restoreAllMobilityBindings(void)
+{
+ HaMobileNodeEntry hamne, *mnEntry = NULL;
+ HaBindingEntry habe;
+ MipSecAssocEntry sa, *sap;
+ MobilityAgentEntry ma, *map;
+ time_t currentTime;
+ time_t timeout;
+ boolean_t existing;
+ uint32_t sessionLifetime;
+ int EntriesSaved = 0;
+ int i;
+
+ if (preFileAccess(_B_TRUE) == -1) {
+ mipverbose(("Could not prepare state file for reading.\n"));
+ return (0);
+ }
+
+ /*
+ * First: how many dynamic security assoc's are there?
+ */
+
+ if ((int)readOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved))
+ != 1) {
+ mipverbose(("Problem reading the number of dynamic sa's.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+
+ for (i = 0; i < EntriesSaved; i++) {
+ if ((int)readOneEntry((void *) &sa,
+ sizeof (MipSecAssocEntry)) != 1) {
+ mipverbose(("Problem reading a security assoc.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+
+ /*
+ * Create the relevant security association
+ * (locked upon return).
+ * NOTE: Must rewrite the key lifetime as
+ * the create routing clobbers the previous
+ * value.
+ */
+ sap = CreateSecAssocEntry(sa.mipSecIsEntryDynamic,
+ sa.mipSecSPI,
+ sa.mipSecReplayMethod,
+ sa.mipSecAlgorithmType,
+ sa.mipSecAlgorithmMode,
+ sa.mipSecKeyLen,
+ (char *)&sa.mipSecKey[0],
+ sa.mipSecKeyLifetime);
+
+ if (sap == NULL) {
+ mipverbose(("Unable to create dynamic SA Entry\n"));
+ haCounters.haInsufficientResourceCnt++;
+ (void) postFileAccess();
+ return (0);
+ }
+
+ sap->mipSecKeyLifetime = sa.mipSecKeyLifetime;
+ mipverbose(("Created a dynamic Mobile Node Entry\n"));
+
+ /*
+ * The Create function ends up locking the sa, so
+ * we need to free it.
+ */
+ (void) rw_unlock(&sap->mipSecNodeLock);
+ }
+
+ /*
+ * the next entry should indicate the number of agent-peer entries.
+ */
+ if ((int)readOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved))
+ != 1) {
+ mipverbose(("Problem reading the number of agent-peers.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+
+ /* now restore that many agent-peer entries */
+ for (i = 0; i < EntriesSaved; i++) {
+ if ((int)readOneEntry((void *) &ma,
+ sizeof (MobilityAgentEntry)) != 1) {
+ mipverbose(("Problem reading an agent-peer entry.\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+
+ /*
+ * Agent entries are read from the config file BEFORE this
+ * function is called. Therefore, any we find here that
+ * aren't in the config file must have been deleted, and
+ * hence we don't have a SA with them any longer. Conversely
+ * if there are new agent's configured, any SA that's
+ * configued with them is obviously not currently active.
+ */
+ if ((map = findMaeFromIp(ma.maAddr, LOCK_READ)) == NULL) {
+ /*
+ * This is the former case - we saved this agent,
+ * but it hasn't been read from the config file,
+ * and so was delted. We no longer have to worry
+ * about this agent-peer, but let the user know
+ * in case the deletion was accidental.
+ */
+ char peerAddr[IPv4_ADDR_LEN];
+
+ (void) ntoa(ma.maAddr, peerAddr);
+ mipverbose(("agent-peer entry for %s "
+ "no longer configured\n", peerAddr));
+ continue;
+ }
+
+ /* Restore the active IPsec Policies */
+ (void) restoreIPsecPolicies(map, &ma);
+
+ /*
+ * The Create function ends up locking the map, so
+ * we need to free it.
+ */
+ (void) rw_unlock(&map->maNodeLock);
+ }
+
+ /*
+ * Read the mobile node entries till eof.
+ */
+ /* CONSTCOND */
+ while (_B_TRUE) {
+ rwlock_t nl;
+
+ if ((int)readOneEntry((void *) &hamne,
+ sizeof (HaMobileNodeEntry)) != 1) {
+ if (ferror(agentStateFile)) {
+ mipverbose((
+ "Problem reading a mobile node entry.\n"));
+ (void) postFileAccess();
+ return (0);
+ } else if (feof(agentStateFile)) {
+ mipverbose(("Done restoring agent state.\n"));
+ clearerr(agentStateFile);
+ }
+ return ((postFileAccess() == -1) ? 0 : 1);
+ }
+
+ /*
+ * if its a dynamic type, we must explicitly create it here
+ * Otherwise, it was created upon initialization.
+ * Note: creation produces a *locked* node.
+ */
+
+ if (hamne.haMnIsEntryDynamic) {
+ /* First, create the mobile node. */
+
+ mnEntry = CreateMobileNodeEntry(_B_TRUE,
+ hamne.haMnAddr,
+ (char *)&hamne.haMnNAI[0],
+ MAX_NAI_LENGTH,
+ hamne.haBindingIfaceAddr,
+ hamne.haMnSPI,
+ NULL,
+ hamne.haPoolIdentifier);
+
+ if (mnEntry == NULL) {
+ mipverbose((
+ "Unable to create dynamic MN Entry\n"));
+ haCounters.haInsufficientResourceCnt++;
+ (void) postFileAccess();
+ return (0);
+ }
+ mipverbose(("Created a dynamic Mobile Node Entry\n"));
+ } else {
+ mnEntry = findHashTableEntryUint(&haMobileNodeHash,
+ hamne.haMnAddr, LOCK_WRITE, NULL, 0, 0, 0);
+
+ if (mnEntry == NULL) {
+ /*
+ * Search for the MobileNodeEntry based on the
+ * NAI.
+ */
+ mnEntry = findHashTableEntryString(
+ &haMobileNodeHash,
+ (unsigned char *)&hamne.haMnNAI,
+ strlen((char *)&hamne.haMnNAI),
+ LOCK_WRITE,
+ NULL, 0, 0, 0);
+
+ if (mnEntry == NULL) {
+ mipverbose(("Unable to find a "
+ "static MN Entry\n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ }
+ mipverbose(("Found a static Mobile Node Entry\n"));
+ }
+
+ /*
+ * Copy all the fields to the (locked) mobile node entry.
+ * Must make sure the lock info does not get clobbered.
+ * Also, make sure we explicitly clobber the bindingEntries
+ * pointer, as it has no significance until we restore those
+ * entries one by one.
+ * Must also clobber the haMnBindingCnt and let restoreHABE
+ * increment that upon successful restoration of each binding
+ * entry.
+ */
+
+ nl = mnEntry->haMnNodeLock;
+ (void) memcpy((void *)mnEntry, (void *)&hamne,
+ sizeof (HaMobileNodeEntry));
+ mnEntry->haMnNodeLock = nl;
+ mnEntry->bindingEntries = NULL;
+ mnEntry->haMnBindingCnt = 0;
+
+#if 0
+ /* This is not persistent friendly yet. */
+ /* read the radiusState string if needed. */
+ if (mnEntry->haRadiusState != NULL) {
+ size_t len;
+ if (1 != fread((void *) &len, sizeof (size_t), 1,
+ agentStateFile)) {
+ mipverbose((
+ "Problem reading radius state length.\n"));
+ (void) postFileAccess();
+ (void) rw_unlock(&mnEntry->haMnNodeLock);
+ return (0);
+ }
+
+ /* allocate some space for the radius state */
+ if (len != fread((void *) mnEntry->haRadiusState,
+ sizeof (char), len, agentStateFile)) {
+ mipverbose((
+ "Problem reading radius state.\n"));
+ (void) postFileAccess();
+ (void) rw_unlock(&mnEntry->haMnNodeLock);
+ return (0);
+ }
+ }
+ mnEntry->haRadiusState = NULL;
+#endif
+
+ /*
+ * Read all binding entries for this
+ * mn entry.
+ */
+ for (i = 0; i < (int)hamne.haMnBindingCnt; i++) {
+ if ((int)readOneEntry((void *) &habe,
+ sizeof (HaBindingEntry)) != 1) {
+ mipverbose(("Problem reading a "
+ "binding entry.\n"));
+ (void) postFileAccess();
+ (void) rw_unlock(&mnEntry->haMnNodeLock);
+ return (0);
+ }
+
+ /*
+ * Figure out when the entry should expire.
+ */
+ GET_TIME(currentTime);
+
+ if (habe.haBindingTimeExpires > currentTime) {
+ timeout = habe.haBindingTimeExpires -
+ currentTime;
+ /* create the relevant binding entry */
+ (void) addHABE(mnEntry, habe.haBindingSrcAddr,
+ habe.haBindingSrcPort, NULL,
+ habe.haBindingRegFlags,
+ habe.haBindingMN,
+ habe.haBindingCOA,
+ mnEntry->haBindingIfaceAddr, timeout,
+ &existing, &sessionLifetime);
+ }
+ }
+
+ /*
+ * Done with this mn entry, but before
+ * moving on to the next, let's unlock it.
+ */
+ (void) rw_unlock(&mnEntry->haMnNodeLock);
+ }
+
+ return (0);
+} /* restoreAllMobilityBindings(void) */
+
+int
+restoreAgentState(void)
+{
+ (void) restoreAllMobilityBindings();
+ removeStateFile();
+ return (0);
+}
+
+/* ------------------------------------------------------------ */
+/* FILE FUNCTIONS */
+/* ------------------------------------------------------------ */
+
+/*
+ * Prepares the file to write out the state.
+ */
+
+static char host_file[MAXLINELENGTH] = "";
+#ifdef LOCKFILE
+static char lock_file[MAXLINELENGTH] = "";
+#endif /* LOCKFILE */
+
+/* returns -1 if error, 0 if ok */
+
+static int
+preFileAccess(boolean_t forReading)
+{
+ char *envres;
+ mode_t mask;
+
+ /* find out which files we should be using */
+
+ if ((envres = getenv(ENVVAR)) == NULL) {
+ (void) strcpy(host_file, SAVE_BINDINGS_FILE);
+#ifdef LOCKFILE
+ (void) strcpy(lock_file, SAVE_BINDINGS_LOCK_FILE);
+#endif /* LOCKFILE */
+ } else {
+ (void) strcpy(host_file, envres);
+#ifdef LOCKFILE
+ (void) strcpy(lock_file, envres);
+ (void) strcat(lock_file, ".lock");
+#endif /* LOCKFILE */
+ }
+
+#ifdef LOCKFILE
+ /* open the lock file */
+
+ if ((lockFile = open(lock_file, O_RDWR | O_CREAT)) == -1) {
+ mipverbose(("preFileAccess: cannot open lock file\n"));
+ return (-1);
+ }
+
+ /* lock it; block if already locked */
+
+ if ((lockf(lockFile, F_LOCK, 0L)) == -1) {
+ mipverbose(("preFileAccess: cannot lock %s\n",
+ lock_file));
+ return (-1);
+ }
+#endif /* LOCKFILE */
+
+ /*
+ * Must first set umask so as not to allow anybody else
+ * to read these files. They may have keyeing material.
+ */
+ mask = umask(~(S_IRUSR|S_IWUSR));
+
+ /* open for reading/writing the file */
+ if ((agentStateFile = fopen(host_file, (forReading ? "r" : "w")))
+ == NULL) {
+ mipverbose(("preFileAccess: can't open %s for %s\n",
+ host_file, (forReading ? "reading" : "writing")));
+#ifdef LOCKFILE
+ if ((lockf(lockFile, F_ULOCK, 0L)) == -1) {
+ mipverbose(("preFileAccess: can't unlock %s\n",
+ lock_file));
+ }
+ (void) close(lockFile);
+#endif /* LOCKFILE */
+ (void) umask(mask);
+ return (-1);
+ }
+ (void) umask(mask);
+ return (0);
+} /* preFileAccess() */
+
+/*
+ * Called after file access.
+ * Returns 0 if ok, -1 if error.
+ */
+static int
+postFileAccess(void)
+{
+ int ret = 0;
+
+ (void) fclose(agentStateFile);
+
+#ifdef LOCKFILE
+ /* unlock the lock file */
+
+ if ((lockf(lockFile, F_ULOCK, 0L)) == -1) {
+ mipverbose(("postFileAccess can't unlock %s\n",
+ lock_file));
+ ret = -1;
+ }
+ (void) close(lockFile);
+#endif /* LOCKFILE */
+ return (ret);
+} /* postFileAccess() */
+
+/*
+ * Delete the state and lock file after restoring.
+ */
+static void
+removeStateFile(void)
+{
+ (void) unlink(host_file);
+#ifdef LOCKFILE
+ (void) unlink(lock_file);
+#endif /* LOCKFILE */
+} /* removeStateFile() */
+
+/* returns 0 if error, otherwise 1 (nitems) */
+static size_t
+saveOneEntry(void *ptr, size_t size)
+{
+ size_t nitems = fwrite(ptr, size, 1, agentStateFile);
+
+ if (nitems != 1) {
+ if (feof(agentStateFile)) {
+ mipverbose(("saveOneEntry: eof! \n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ if (ferror(agentStateFile)) {
+ mipverbose(("saveOneEntry: error! \n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ }
+ return (nitems);
+}
+
+/* returns 0 if error, otherwise 1 (nitems) */
+static size_t
+readOneEntry(void *ptr, size_t size)
+{
+ size_t nitems = fread(ptr, size, 1, agentStateFile);
+
+ if (nitems != 1) {
+ if (feof(agentStateFile)) {
+ mipverbose(("readOneEntry: eof! \n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ if (ferror(agentStateFile)) {
+ mipverbose(("readOneEntry: error! \n"));
+ (void) postFileAccess();
+ return (0);
+ }
+ }
+ return (nitems);
+}
+
+/*
+ * Function: restoreIPsecPolicies()
+ *
+ * Arguments: new - Pointer to the new MobilityAgentEntry info.
+ * This is what we've just read from the config file.
+ * saved - Pointer to what we read as our exit config.
+ * This is how we were configured, and what IPsec
+ * policies were in place when we were told to shutdown.
+ *
+ * Description: Compares what was parsed from the config file with how we were
+ * configured when we exited. Config file settings, and hence
+ * IPsec policies can change between executions. We want to
+ * restore those that were installed with the new settings,
+ * informing the user when policies have changed, and which have
+ * been restored - especially when those that were in place have
+ * been removed.
+ *
+ * Returns: 1 if OK, 0 if not (like the others called from
+ * restoreAllMobilityBindings()).
+ */
+int
+restoreIPsecPolicies(MobilityAgentEntry *new, MobilityAgentEntry *saved)
+{
+ /*
+ * Check the new policies, and restore any that were installed. We're
+ * really just doing this as a convenience for the user. Those that
+ * were installed because of bound mobile nodes will again be installed
+ * even if the policies are changed (we do NOT second-guess that sort
+ * of thing). However, since this sort of thing can be confusing
+ * when it fails, we'll log the new policies so the user has a place
+ * to start if there are problems.
+ */
+ int action;
+ char peerAddr[IPv4_ADDR_LEN];
+
+ (void) ntoa(new->maAddr, peerAddr);
+
+ /*
+ * maPeerFlags will be restored when we restore the MN entries.
+ *
+ * We don't copy maIPsecFlags because the tunnel flags will be restored
+ * when the MN entries are restored, and the registration flags will
+ * be set as we [re]install each one.
+ *
+ * The maIPsecSAFlags[] aren't overwritten since they've been parsed
+ * based on the potentially new settings in conf-land!
+ *
+ * For readability, we first run through the policies, and see what's
+ * changed, then restore whatever was installed.
+ */
+ for (action = FIRST_IPSEC_ACTION;
+ action < LAST_IPSEC_ACTION;
+ action++) {
+ /* check all for IPSEC_APPLY, then IPSEC_PERMIT */
+ if (memcmp(&new->maIPsecRequestIPSR[action],
+ &saved->maIPsecRequestIPSR[action],
+ sizeof (ipsec_req_t)) != 0) {
+ /* SA has changed, tell the user. */
+ mipverbose(("IPsecRequest %s policy for %s changed.\n",
+ validIPsecAction[action], peerAddr));
+
+ /* was the policy active? */
+ if (saved->maIPsecFlags & REQUEST(action)) {
+ /* A problem if the user *unconfigured* it! */
+ if (*new->maIPsecRequest[action] != 0)
+ /* tell the user we know */
+ mipverbose(("new IPsecRequest %s policy"
+ " will be installed.\n",
+ validIPsecAction[action]));
+ }
+ }
+
+ if (memcmp(&new->maIPsecReplyIPSR[action],
+ &saved->maIPsecReplyIPSR[action],
+ sizeof (ipsec_req_t)) != 0) {
+ /* SA has changed, tell the user. */
+ mipverbose(("IPsecReply %s policy for %s changed.\n",
+ validIPsecAction[action], peerAddr));
+
+ /* was the policy active? */
+ if (saved->maIPsecFlags & REPLY(action)) {
+ /* A problem if the user *unconfigured* it! */
+ if (*new->maIPsecReply[action] != 0)
+ /* tell the user we know */
+ mipverbose(("new IPsecReply %s policy "
+ "will be installed.\n",
+ validIPsecAction[action]));
+ }
+ }
+
+ if (memcmp(&new->maIPsecTunnelIPSR[action],
+ &saved->maIPsecTunnelIPSR[action],
+ sizeof (ipsec_req_t)) != 0) {
+ /* SA has changed, tell the user. */
+ mipverbose(("IPsecTunnel %s policy for %s changed.\n",
+ validIPsecAction[action], peerAddr));
+
+ /* was the policy active? */
+ if (saved->maIPsecFlags & TUNNEL(action)) {
+ /* A problem if the user *unconfigured* it! */
+ if (!IPSEC_TUNNEL_ANY(
+ new->maIPsecSAFlags[action])) {
+ /* tell the user we know */
+ mipverbose(("new IPsecTunnel %s policy "
+ "will be installed.\n",
+ validIPsecAction[action]));
+ }
+ }
+ }
+
+ if (memcmp(&new->maIPsecReverseTunnelIPSR[action],
+ &saved->maIPsecReverseTunnelIPSR[action],
+ sizeof (ipsec_req_t)) != 0) {
+ /* SA has changed, tell the user. */
+ mipverbose((
+ "IPsecReverseTunnel %s policy for %s changed.\n",
+ validIPsecAction[action], peerAddr));
+
+ /* was the policy active? */
+ if (saved->maIPsecFlags & REVERSE_TUNNEL(action)) {
+ /* A problem if the user *unconfigured* it! */
+ if (!IPSEC_REVERSE_TUNNEL_ANY(
+ new->maIPsecSAFlags[action]))
+ /* tell the user we know. */
+ mipverbose((
+ "new IPsecReverseTunnel %s policy "
+ "will be installed.\n",
+ validIPsecAction[action]));
+ }
+ }
+ }
+
+ /*
+ * Restore those that were installed. Warn the user if any of these
+ * went away!
+ */
+ for (action = FIRST_IPSEC_ACTION;
+ action < LAST_IPSEC_ACTION;
+ action++) {
+ /* restore for IPSEC_APPLY, then IPSEC_PERMIT */
+
+ /*
+ * note: there is a potential problem with restoring REQUESTs.
+ * Before we restore, we parse the config file, which is when
+ * IPSEC_REQUEST_PERMIT policies need to be installed. That
+ * means if this is what we're restoring, it's been done (and
+ * it's the new = correct policy).
+ */
+ if ((action != IPSEC_PERMIT) &&
+ (saved->maIPsecFlags & REQUEST(action))) {
+ /* restore, IFF still configured */
+ if (*new->maIPsecRequest[action] != 0) {
+ if (installIPsecPolicy(
+ new->maIPsecRequest[action]) < 0) {
+ /* we wont be able to communicate */
+ mipverbose((
+ "Can't restore %s's ipsec %s"
+ "registration request policy.\n",
+ validIPsecAction[action],
+ peerAddr));
+ return (0);
+ }
+
+ /* set the installed flag */
+ new->maIPsecFlags |= REQUEST(action);
+
+ } else {
+ /* one WAS installed, but isn't configured */
+ mipverbose(("WARNING: IPsecRequest %s policy "
+ "for %s was installed but is no longer "
+ "configured! Registration request will be "
+ "in the clear!", validIPsecAction[action],
+ peerAddr));
+ return (0);
+ }
+ }
+
+ if (saved->maIPsecFlags & REPLY(action)) {
+ /* restore, IFF still configured */
+ if (*new->maIPsecReply[action] != 0) {
+ if (installIPsecPolicy(
+ new->maIPsecReply[action]) < 0) {
+ /* we wont be able to communicate */
+ mipverbose((
+ "Can't restore %s's ipsec %s"
+ "registration reply policy.\n",
+ validIPsecAction[action],
+ peerAddr));
+ return (0);
+ }
+
+ /* set the installed flag */
+ new->maIPsecFlags |= REPLY(action);
+
+ } else {
+ /* one WAS installed, but isn't configured */
+ mipverbose(("WARNING: IPsecReply %s policy "
+ "for %s was installed but is no longer "
+ "configured! Registration reply will be "
+ "in the clear!", validIPsecAction[action],
+ peerAddr));
+ return (0);
+ }
+ }
+
+ /*
+ * Note:
+ * tunnel entries are added when we restore the MNs still
+ * registered with us. An existing MN causes addHABE() to be
+ * called, which calls encapadd() where the correct ipsec_req_t
+ * is passed to ioctl() via settaddr() - exactly as if the MN
+ * registered. At this time, warn the user if any policies
+ * went away, yet we're likely to restore the policy with a MN!
+ */
+ if (saved->maIPsecFlags & TUNNEL(action)) {
+ if (!IPSEC_TUNNEL_ANY(new->maIPsecSAFlags[action]))
+ /* tell the user the config's gone */
+ mipverbose((
+ "WARNING: IPsecTunnel %s policy for "
+ " %s was installed, but is no longer "
+ "configured. Restoring with no policy!",
+ validIPsecAction[action], peerAddr));
+ }
+
+ if (saved->maIPsecFlags & REVERSE_TUNNEL(action)) {
+ if (!IPSEC_REVERSE_TUNNEL_ANY(
+ new->maIPsecSAFlags[action]))
+ /* tell the user the config's gone */
+ mipverbose((
+ "WARNING: IPsecReverseTunnel %s policy for "
+ " %s was installed, but is no longer "
+ "configured. Restoring with no policy!",
+ validIPsecAction[action], peerAddr));
+ }
+ }
+
+ return (1);
+}