diff options
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c')
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c | 1661 |
1 files changed, 1661 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c b/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c new file mode 100644 index 0000000000..6672556174 --- /dev/null +++ b/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c @@ -0,0 +1,1661 @@ +/* + * 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" + +/* + * file: auth.c + * + * This function contains all of the routines + * necessary to authenticate Registration Requests, + * including the functions which add and validate + * the authentication extensions, the SPI lookup + * routines, etc. + */ + +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include "agent.h" +#include "mip.h" +#include "md5.h" +#include "auth.h" + +#include <sys/types.h> +#include <netinet/in.h> + + +extern char msg[]; +extern AAA_Protocol_Code aaaProtocol; +extern boolean_t faChallengeAdv; +extern boolean_t mfAuthRequired; +extern boolean_t fhAuthRequired; +extern int logVerbosity; + +/* + * Default Values... + */ +extern uint32_t defaultPool; +extern uint32_t defaultNodeSPI; + +#ifdef RADIUS_ENABLED +HaMobileNodeEntry *radiusCheckUpdate(HaMobileNodeEntry *dest, + struct hash_table *htbl, ipaddr_t mnAddr); +#endif /* RADIUS_ENABLED */ + +static boolean_t isAuthExtOk(unsigned char *, int, MipSecAssocEntry *); +extern int hexdump(char *, unsigned char *, int); +extern uint32_t getRandomValue(); + +/* ----------------- Common to all mobility agents ------------------- */ +/* + * 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; + +/* ------------------ Specific to foreign agents -------------------- */ + +/* + * Counters maintained by Foreign Agents + */ +extern ForeignAgentCounters faCounters; + +/* + * The last two challenges advertised + */ +extern char faLastChallengeIssued[2][ADV_CHALLENGE_LENGTH]; + + +/* ------------------ Specific to home agents -------------------- */ +/* + * This table has one entry for each mobile node for which a mobility + * agent offers Home Agent services. + */ +extern HashTable haMobileNodeHash; + +/* + * Counters maintained by Home Agents + */ +extern HomeAgentCounters haCounters; + +/* + * Compute authenticator for the data in buffer based on the + * Mobile IP Security Association pointed to by msaEntry. + */ + +/* + * Function: computeAuth + * + * Arguments: buffer - Pointer to buffer + * buflen - Length of data in the buffer + * authenticator - Pointer to the output buffer + * authenticationlen - length of the output buffer + * msa - Pointer to the security association entry. + * + * Description: Compute authenticator for the data in buffer based on the + * Mobile IP Security Association pointed to by msaEntry. + * + * Returns: void + */ +static void +computeAuth(unsigned char buffer[], int buflen, + unsigned char authenticator[], int *authenticatorlen, + MipSecAssocEntry *msa) +{ + MD5_CTX context; + + /* + * Initialize the length. + */ + + if (msa) { + switch (msa->mipSecAlgorithmType) { + case MD5: + if (*authenticatorlen < AUTHENTICATOR_LEN) { + syslog(LOG_ERR, + "Not enough space for MD5 authenticator."); + } else if (msa->mipSecAlgorithmMode != PREFIXSUFFIX) { + syslog(LOG_ERR, "Unknown mode specified " \ + "for MD5 algorithm."); + } else { + /* + * No longer print MD5 results. + */ + *authenticatorlen = 0; + MD5Init(&context); + MD5Update(&context, msa->mipSecKey, + (unsigned int) msa->mipSecKeyLen); + MD5Update(&context, buffer, + (unsigned int) buflen); + MD5Update(&context, msa->mipSecKey, + (unsigned int) msa->mipSecKeyLen); + MD5Final(authenticator, &context); + *authenticatorlen = AUTHENTICATOR_LEN; + } + break; + + case NONE: + /* we leave the contents of authenticator unchanged */ + *authenticatorlen = AUTHENTICATOR_LEN; + break; + + default: + /* + * Any other authentication transform, which we + * currentlydo not support. + */ + syslog(LOG_ERR, "Invalid Authentication Type " \ + "requested"); + } + } +} + + +/* + * Function: appendAuthExt + * + * Arguments: buffer - Pointer to the packet + * buflen - Offset in the packet where extension is + * to be added. + * type - Extension Id + * msa - Pointer to the Security Assocation Entry + * + * Description: Append authentication extension to a registration + * reply contained in buffer based on the Mobile IP + * Security Association pointed to by MSA. Returns + * total number of bytes in the extension. + * + * Returns: The number of bytes added to the packet. + */ +int +appendAuthExt(unsigned char *buffer, size_t buflen, uint8_t type, + MipSecAssocEntry *msa) +{ + int authlen = 0; + authExt *aep; + uint32_t SPI; + uint16_t tempShort; + + if (msa) { + /* + * TODO: + * The length of authenticator actually depends on the + * algorithm. For now, we assume AUTHENTICATOR_LEN. + */ + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + aep = (authExt *)(buffer + buflen); + aep->type = type; + + /* + * We need to set to length to the sizeof the SPI plus the + * length of the authenticator. + */ + aep->length = (sizeof (SPI) + AUTHENTICATOR_LEN); + SPI = (msa == NULL) ? 0 : msa->mipSecSPI; + tempShort = htons(SPI >> AUTHENTICATOR_LEN); + (void) memcpy(&aep->SPIhi, &tempShort, sizeof (uint16_t)); + tempShort = htons(SPI & 0xffff); + (void) memcpy(&aep->SPIlo, &tempShort, sizeof (uint16_t)); + + authlen = AUTHENTICATOR_LEN; + computeAuth(buffer, buflen + sizeof (authExt), + buffer + buflen + sizeof (authExt), &authlen, msa); + + if (authlen) { + authlen += sizeof (authExt); + } + } + + return (authlen); +} + + +/* + * Function: isAuthOk + * + * Arguments: buffer - Pointer to buffer + * buflen - Length of data in the buffer + * authenticator - Pointer to hash to compare against + * authenticationlen - length of hash buffer + * msa - Pointer to the security association entry + * + * Description: This function computes a hash using the buffer and + * compares the result with the data in the authenticator. + * If both values match, the packet is considered + * authenticated. + * + * Returns: boolean_t - _B_FALSE if packet is not authenticated. + */ +static boolean_t +isAuthOk(unsigned char buffer[], int buflen, + unsigned char authenticator[], int authenticatorlen, + MipSecAssocEntry *msa) +{ + static unsigned char newAuth[32]; + int newAuthLen = 32; + int i; + + if (msa == NULL) { + return (_B_FALSE); + } + + switch (msa->mipSecAlgorithmType) { + case MD5: + computeAuth(buffer, buflen, newAuth, &newAuthLen, msa); + mipverbose(("authenticator = %d bytes, newAuth = %d bytes\n", + authenticatorlen, newAuthLen)); + if (newAuthLen != authenticatorlen) + return (_B_FALSE); + + for (i = 0; i < newAuthLen; i++) { + if (newAuth[i] != authenticator[i]) { + syslog(LOG_ERR, + "isAuthOk: bad key at position %d (%02X <> %02X)\n", + i, authenticator[i], newAuth[i]); + return (_B_FALSE); + } + } + + break; + + case NONE: + /* No checks required */ + break; + } + + return (_B_TRUE); +} + + +/* + * Function: isAuthExtOk + * + * Arguments: buffer - Pointer to a packet + * buflen - Offset in the packet where the authentication + * extension can be found. + * msa - Pointer to a Security Assocation Entry + * + * Description: Buffer contains buflen bytes of a registration request + * and an immediately following authentication extension. + * Check if the authentication extension is correct + * according to the given msa. + * + * Returns: boolean_t - _B_TRUE if authentication extension was + * computed using the protocol security assocation. + */ +static boolean_t +isAuthExtOk(unsigned char buffer[], int buflen, MipSecAssocEntry *msa) +{ + int authLen; + boolean_t result = _B_FALSE; + authExt *aep; + genAuthExt *genAep; + uint32_t SPI; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + aep = (authExt *) (buffer + buflen); + + /* + * Support for the latest Challenge/response draft, which + * requires support for the generalized authentication header. + */ + switch (aep->type) { + case REG_MH_AUTH_EXT_TYPE: + case REG_MF_AUTH_EXT_TYPE: + case REG_FH_AUTH_EXT_TYPE: + GET_SPI(SPI, aep); + + if (SPI != msa->mipSecSPI) { + mipverbose(("Type: %d, Length %d\n", aep->type, + aep->length)); + mipverbose(("SPI mismatch got %d had %d.\n", + SPI, msa->mipSecSPI)); + result = _B_FALSE; + } else { + /* this length includes 4 bytes SPI */ + authLen = aep->length - 4; + result = isAuthOk(buffer, buflen + sizeof (authExt), + (buffer + buflen + sizeof (authExt)), + authLen, msa); + } + break; + + case REG_GEN_AUTH_EXT_TYPE: + genAep = (genAuthExt *) aep; + + GET_GEN_AUTH_SPI(SPI, genAep); + + if (SPI != msa->mipSecSPI) { + mipverbose(("Type: %d, subType: %d, Length %d\n", + genAep->type, genAep->subType, genAep->length)); + mipverbose(("SPI mismatch got %d had %d.\n", + SPI, msa->mipSecSPI)); + result = _B_FALSE; + } else { + /* This length includes 4 bytes SPI */ + authLen = ntohs(genAep->length) - 4; + result = isAuthOk(buffer, buflen + sizeof (genAuthExt), + (buffer + buflen + sizeof (genAuthExt)), + authLen, msa); + } + break; + + default: + /* + * Unknown authentication type.... reject + */ + result = _B_FALSE; + break; + } + + return (result); +} + +#ifdef TEST_AUTH +/* + * Function: main + * + * Arguments: argc - Number of command line parameters + * argv - Pointer to command line arguments + * + * Description: This function is used to validate our MD5 implementation. + * It is no longer in use, but is kept in case one needs + * to test the authentication computation in this file + * stand-alone. + * + * Returns: exits + */ +int +main(int argc, char *argv[]) +{ + int i; + unsigned char digest[AUTHENTICATOR_LEN]; + int digestlen = AUTHENTICATOR_LEN; + MipSecAssocEntry msae = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + 1, 0, MD5, PREFIXSUFFIX, 16, + { 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11 + }, + TIMESTAMPS, 0 }; + + unsigned char packet[30] = { + /* + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + */ + 0x01, 0x00, 0x00, 0x28, 0x81, 0x92, 0x7a, 0xcc, + 0x81, 0x92, 0x7a, 0xbf, 0x81, 0x92, 0xc9, 0x09, + 0x00, 0x00, 0x00, 0x00, 0xe4, 0xa8, 0x5f, 0xcb, + 0x20, 0x14, 0x00, 0x00, 0x00, 0x01 + /* + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 + */ + }; + /* + * 0x01, 0x00, 0x01, 0x2c, 0x81, 0x92, 0x7a, 0xc0, + * 0x81, 0x92, 0x7a, 0x7b, 0x81, 0x92, 0xc9, 0x09, + * 0x00, 0x00, 0x00, 0x00, 0x17, 0xe1, 0x2c, 0x23, + * 0x20, 0x14, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11 + * }; + * unsigned char packet[] = {'J', 'i', 'm'}; + */ + + printMSAE(&msae); + computeAuth(packet, 30, digest, &digestlen, &msae); + (void) printf("Authenticator for packet = "); + printBuffer(digest, digestlen); + (void) printf("\n"); + + /* Simulate data corruption or incorrect MSAE */ + msae.mipSecKeyLen = 2; + packet[2] = 0x00; + msae.mipSecKey[0] = 'A'; + printMSAE(&msae); + if (isAuthOk(packet, 3, digest, digestlen, &msae)) + (void) printf("Check succeeded.\n"); + +} +#endif /* TEST_AUTH */ + +/* + * Function: findSecAssocFromSPI + * + * Arguments: SPI - The Security Parameter Index value + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will look for a security assocation + * entry in the hash table matching on the SPI. If + * a lock type was requested, upon return the node + * will be locked. The caller will be responsible + * for unlocking the node when it no longer needs + * the security association entry. + * + * If a security association entry was found, and + * the entry is marked as dynamic and if the key + * has expired, a NULL value will be returned. + * + * Returns: If successful, a pointer to a Security Association + * Entry will be returned, otherwise NULL. + */ +MipSecAssocEntry * +findSecAssocFromSPI(uint32_t SPI, int lockType) +{ + MipSecAssocEntry *saEntry = NULL; + time_t currentTime; + + /* + * Let's see if we can find the SA using the SPI. + */ + if ((saEntry = findHashTableEntryUint(&mipSecAssocHash, + SPI, lockType, NULL, 0, 0, 0)) != NULL) { + /* + * Keys has a defined lifetime, which is set by the + * home AAA Server. We need to check whether the + * key being used is still valid. + */ + + GET_TIME(currentTime); + if (saEntry->mipSecIsEntryDynamic == TRUE && + saEntry->mipSecKeyLifetime < currentTime) { + /* + * The Security Association has expired. + * If the node was locked, we need to + * unlock it. We will be returning a NULL + * to the caller since this is no longer + * valid. + */ + if (lockType != LOCK_NONE) { + (void) rw_unlock(&saEntry->mipSecNodeLock); + } + saEntry = NULL; + } + } + + return (saEntry); +} + + +/* + * Note that upon return of a security association entry, the + * node will be locked. The caller must unlock the node once + * it is finished with the entry. + */ +/* + * Function: findSecAssocFromIp + * + * Arguments: address - Peer's IP Address + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will look for a security assocation + * entry in the hash table matching on the IP Address. + * If a lock type was requested, upon return the node + * will be locked. The caller will be responsible + * for unlocking the node when it no longer needs + * the security association entry. + * + * If a security association entry was found, and + * the entry is marked as dynamic, if the key has + * expired + * + * Returns: If successful, a pointer to a Security Association + * Entry will be returned + * If not successful, NULL is returned. + */ +MipSecAssocEntry * +findSecAssocFromIp(ipaddr_t address, int lockType) +{ + MobilityAgentEntry *maEntry; + MipSecAssocEntry *saEntry = NULL; + + /* + * First we need to find the MA structure to get + * the SPI value. + */ + if ((maEntry = findHashTableEntryUint(&mipAgentHash, + address, LOCK_READ, NULL, 0, 0, 0)) != NULL) { + /* + * Good, now let's find the SA itself. + */ + saEntry = findSecAssocFromSPI(maEntry->maSPI, lockType); + + (void) rw_unlock(&maEntry->maNodeLock); + } + + return (saEntry); +} + +/* + * Function: findMaeFromIp + * + * Arguments: address - Peer's IP Address + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will look for an IPsec Policy + * entry in the hash table matching on the IP Address. + * If a lock type was requested, upon return the node + * will be locked. The caller will be responsible + * for unlocking the node when it no longer needs + * the security association entry. + * + * Returns: If successful, a pointer to a Security Association + * Entry will be returned, otherwise NULL. + */ +MobilityAgentEntry * +findMaeFromIp(ipaddr_t address, int lockType) +{ + MobilityAgentEntry *maEntry; + + /* + * First we need to find the MA structure to get + * the SPI value. + */ + if ((maEntry = findHashTableEntryUint(&mipAgentHash, + address, lockType, NULL, 0, 0, 0)) == NULL) + return (0); + + return (maEntry); +} + + +#ifdef KEY_DISTRIBUTION +/* + * KEY_DISTRIBUTION MUST ONLY BE COMPILED FOR TESTING!!! + * + * This version of mipagent supports a AAA/DIAMETER + * interface. The DIAMETER server generates keying + * material that is sent to the Home Agent. The keys + * sent are both for the Home Agent, and for the Mobile + * Node. The keys for the Mobile Nodes are added to the + * registration reply, and the keys for the Home Agent + * cause the Home Agent to create a local SA. + * + * Since DIAMETER/AAA is not currently a product, and key + * distribution must still be tested, we have added some + * test code in mipagent. When KEY_DISTRIBUTION is enabled, + * the home agent creates and encrypts session keys for + * the Mobile Node (mimicking DIAMETER), and creates local + * SAs. Further, since the session keys MUST also be sent + * to the Foreign Agent, the session keys are sent in the + * clear to the Foreign Agent through Vendor Specific + * extensions. + * + * Again, this code is for testing purpose only and must not + * be enabled for production code, since it hasn't been + * fully tested. + */ +#define MAX_SESSION_KEY_LEN 16 +/* + * Function: createSessionKey + * + * Arguments: key - Pointer to session key buffer + * keyLen - Pointer to Length of session key + * spi - Pointer to SPI + * + * Description: This function is used to create pseudo-random + * session keys, and SPI values. Note that the + * keys created here are by no means random, and + * this function is only used for testing purposes. + * + * Returns: none + */ +static void +createSessionKey(uint8_t *key, uint32_t *keyLen, uint32_t *spi) +{ + int i; + + /* + * First we create the SPI value. + */ + *spi = htonl(getRandomValue()); + + /* + * Now we create the session key + */ + for (i = 0; i < MAX_SESSION_KEY_LEN; i++) { + key[i] = getRandomValue(); + } + + /* + * Set the length + */ + *keyLen = MAX_SESSION_KEY_LEN; + +} + +/* + * Function: createSessionKey + * + * Arguments: keyData - Pointer to Genrealized key extension + * keyLen - Length of key extension + * spi - Pointer to SPI + * + * Description: This function will create a local Security + * association, using the information found in + * a generalized key extension. Note that this + * function is only used for testing purposes. + * + * Returns: _B_TRUE if successful + */ +static boolean_t +createSecAssocFromKeyData(keyDataExt *keyData, int keyDataLen, uint32_t *SPI) +{ + uint32_t spi; + uint32_t lifetime; + + /* + * Extract the information from the generalized key ext + */ + (void) memcpy(&spi, &keyData->nodeSPI, sizeof (uint32_t)); + (void) memcpy(&lifetime, &keyData->lifetime, sizeof (uint32_t)); + + /* + * Create a new Security Association Entry + */ + if (aaaCreateKey(ntohl(spi), (uint8_t *)((char *)keyData) + + sizeof (keyDataExt), keyDataLen - sizeof (keyDataExt), + ntohl(lifetime))) { + syslog(LOG_CRIT, "Unable to create SA from keydata"); + return (_B_FALSE); + } + + /* + * Set the SPI value + */ + *SPI = ntohl(spi); + + return (_B_TRUE); +} + +#endif /* KEY_DISTRIBUTION */ + +/* + * Function: faCheckRegReqAuth + * + * Arguments: messageHdr - Pointer to Message Control Block + * mnSPI - Pointer to Mobile Node's SPI + * mnChallenge - Pointer to the FA Challenge + * mnChallengeLen - Length of the Challenge + * forwardFlag - Pointer to the forward msg flag. + * + * Description: This function is responsible for authenticating + * the Registration Request. First, the function + * will check whether the Challenge is present, which + * MUST be if the agent is configured to advertise + * challenges. Next, the Mobile-Foreign is checked + * to ensure that the message is authenticated. If + * the extension was not found, and the agent is + * configured to require this extension, authentication + * will fail. + * + * Lastly, if the Mobile-AAA authentication extension + * is present, we will send a request to the AAA + * infrastructure. If this request is successfully sent, + * the forward flag will be set to _B_FALSE to ensure that the + * caller does not forward the Registration Request to + * the Home Agent. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. The forwardFlag will be set to _B_FALSE if + * the message is being sent to the AAA infrastructure. + */ +/* ARGSUSED */ +int +faCheckRegReqAuth(MessageHdr *messageHdr, FaVisitorEntry *favePtr, + FaVisitorEntry *acceptedFave, unsigned char *mnChallenge, + uint32_t mnChallengeLen, boolean_t *forwardFlag) +{ + regRequest *reqPtr; + MipSecAssocEntry *mipSecAssocEntry; + authExt *mnAuthExt; + /* + * Support for the latest Challenge/response draft. + */ + genAuthExt *mnAAAAuthExt; + uint32_t SPI; + uint32_t aaaSPI; + size_t length; + int mnAAAAuthExtLen; + int mnAuthExtLen; + int index; + int result; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + reqPtr = (regRequest *)messageHdr->pkt; + *forwardFlag = _B_TRUE; + + /* + * We have two different authentication types that we need + * to worry about. First, and foremost, we need to be able + * to support the case where a Mobile-Foreign Security + * Association exists. In the AAA world, an authenticated + * and authorized Mobile Node would have the keys setup in + * the mnFaNodeHash, and this case would apply. + * + * The next case is when we are unaware of the Mobile Node. + * In this case, the Mobile Node should have include the + * Challenge/Response extensions which are used for AAA + * purposes. When this is found, we issue a call to the local + * AAA daemon to authenticate and authorize the MN. + */ + + if (faChallengeAdv) { + if (mnChallengeLen == 0) { + syslog(LOG_ERR, + "Missing Challenge Extention"); + faCounters.faMNAuthFailureCnt++; + /* + * Support for the latest Challenge/response draft. + * If the challenge was expected, and found present, + * return a missing challenge error. + */ + return (FA_MISSING_CHALLENGE); + } + + /* + * Obviously, we need to validate the challenge. + */ + if (memcmp(faLastChallengeIssued[0], mnChallenge, + ADV_CHALLENGE_LENGTH) != 0) { + /* + * Let's try our backup. + */ + if (memcmp(faLastChallengeIssued[1], + mnChallenge, ADV_CHALLENGE_LENGTH) != 0) { + /* + * If the visitor entry is present, then we + * can ALSO check whether a challenge was + * previously issued to the mobile node + * in a registration reply. + */ + if (acceptedFave && + acceptedFave->faVisitorChallengeAdvLen) { + if (memcmp( + acceptedFave->faVisitorChallengeAdv, + mnChallenge, + acceptedFave-> \ + faVisitorChallengeAdvLen) != 0) { + syslog(LOG_ERR, + "Invalid Challenge Extention"); + faCounters.faMNAuthFailureCnt++; + return (FA_UNKNOWN_CHALLENGE); + } + } else { + syslog(LOG_ERR, + "Invalid Challenge Extention"); + faCounters.faMNAuthFailureCnt++; + return (FA_UNKNOWN_CHALLENGE); + } + } + } + } + + + mipverbose(("Checking authext")); + + /* + * Support for the latest Challenge/Response I-D + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_GEN_AUTH_EXT(messageHdr, index, + GEN_AUTH_MN_AAA, mnAAAAuthExt, mnAAAAuthExtLen); + + /* + * If a Mobile node Foreign agent authentication extension exists + * check it. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_MF_AUTH_EXT_TYPE, + mnAuthExt, mnAuthExtLen); + + if (mnAuthExtLen) { + GET_SPI(SPI, mnAuthExt); + + /* + * Remember that the node will be locked upon return. + * We need to unlock it when we are done... + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Error: No SA for Mobile Node"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + syslog(LOG_ERR, "Failed MN-FA authentication"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + /* + * ... and now we are done, let's unlock it. + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + /* + * Support for differing extension header formats. + * + * Remove the extension by playing with the + * packet's length. + */ + messageHdr->pktLen = (messageHdr->extIdx[index-1] - + messageHdr->pkt) + messageHdr->extHdrLength[index-1] + + messageHdr->extLength[index-1]; + } else { + /* + * If we are advertising challenges, and the Mobile-AAA + * authentication extension is present, then the + * Mobile-Foreign does not need to be present. If the + * Mobile-AAA is NOT present, and we are configured to + * require Mobile-Foreign, then we will fail + * authentication. + */ + if (faChallengeAdv == _B_TRUE && mnChallengeLen && + mnAAAAuthExtLen) { + mipverbose(("Found a challenge and response\n")); + + /* + * First, it is necessary for us to have the NAI in + * order to interact with the AAA. + */ + if (messageHdr->mnNAI == NULL) { + syslog(LOG_ERR, + "MN-AAA present without an NAI"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + /* + * Is AAA Enabled? + */ + if (aaaProtocol == AAA_NONE) { + /* WORK -- why is this here? (PRC?) */ + return (0); +#if 0 + syslog(LOG_ERR, + "Not configured to interact with AAA"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); +#endif + } + + if (mnAAAAuthExtLen) { + /* + * If the MN-AAA Authentication extension was + * present, retrieve the SPI value. + */ + GET_GEN_AUTH_SPI(aaaSPI, mnAAAAuthExt); + } + + /* + * If we are using Radius only, then the SPI must be 2. + */ + if (aaaProtocol == RADIUS && aaaSPI != RADIUS_SPI) { + syslog(LOG_ERR, "Failed MN-FA authentication " + "- wrong SPI"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + /* + * Good, we've made it this far. Now let's go + * check with the AAA Infrastructure, if this + * was configured. + */ + /* + * Support for the latest Challenge response I-D + */ + length = ((char *)mnAAAAuthExt) - + ((char *)messageHdr->pkt) + sizeof (genAuthExt); + + /* + * If using Radius, we'd like to preserve messageHdr + * until we get a reply from the Radius server + */ + if (aaaProtocol == RADIUS) + messageHdr->dontDeleteNow = _B_TRUE; + + result = AAAAuthenticateRegReq(messageHdr->pkt, + messageHdr->pktLen, messageHdr->mnNAI, + messageHdr->mnNAILen, aaaSPI, + (unsigned char *)&mnAAAAuthExt[1], + mnAAAAuthExtLen - sizeof (mnAAAAuthExt), length, + reqPtr->homeAddr, reqPtr->haAddr, _B_FALSE, + messageHdr->inIfindex, + (void *)messageHdr, mnChallenge, mnChallengeLen); + + if (result) { + /* + * Now we look at the result code to determine + * what the error was. + */ + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } else { + /* + * Make sure that we notify the caller that we + * should not forward the request to the Home + * Agent since: + * - if diameter: it is being done via + * diameter server. + * - if radius: we need to wait for the auth + * answer. + */ + *forwardFlag = _B_FALSE; + } + } else if (mfAuthRequired) { + syslog(LOG_ERR, "Failed MN-FA authentication - No Ext"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + } + + return (0); +} + +/* + * Function: faCheckRegRepAuth + * + * Arguments: messageHdr - Pointer to the Message Control Block + * favePtr - Pointer to the Visitor Entry + * + * Description: This function is used to authenticate a Registration + * Reply. If the agent is configured to advertise + * challenges, we will make sure that the challenge was + * returned by the Home Agent, and that the challenge + * value is identical to the value that was used by the + * Mobile Node. + * + * Next, if the Foreign-Home Authentication extension + * is present, it is authenticated. If it is present and + * the agent is configured to require it, we will fail + * authentication. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. + */ +int +faCheckRegRepAuth(MessageHdr *messageHdr, FaVisitorEntry *favePtr) +{ + authExt *haAuthExt; + MipSecAssocEntry *mipSecAssocEntry; +#ifdef KEY_DISTRIBUTION + keyDataExt *keyData; + uint32_t keyDataLen; +#endif /* KEY_DISTRIBUTION */ + unsigned char *challenge; + uint32_t SPI; + int haAuthExtLen; + int challengeLen; + int index; + + /* + * If a Challenge was received by the Mobile Node (due to our + * advertisement, let's make sure that the same challenge is + * present in the response. + */ + if (favePtr->faVisitorChallengeToHALen) { + /* + * Retrieve the Challenge + */ + GET_EXT_DATA(messageHdr, index, REG_MF_CHALLENGE_EXT_TYPE, + challenge, challengeLen); + + if (challengeLen == 0 || challengeLen > ADV_CHALLENGE_LENGTH) { + /* + * Protect against buffer overflows... + */ + syslog(LOG_ERR, + "excessively large or missing Challenge"); + faCounters.faPoorlyFormedRepliesCnt++; + /* + * Support for the latest Challenge/response I-D. + * If the challenge was expected and not present, + * return a missing challenge error. + */ + return (FA_MISSING_CHALLENGE); + } + + if (memcmp(challenge, favePtr->faVisitorChallengeToHA, + challengeLen) != 0) { + /* + * Protect against buffer overflows... + */ + syslog(LOG_ERR, + "invalid Challenge in Registration Reply"); + faCounters.faPoorlyFormedRepliesCnt++; + /* + * Support for the latest Challenge/response I-D. + * If the challenge was invalid, return + * an unknown challenge error. + */ + return (FA_UNKNOWN_CHALLENGE); + } + } + +#ifdef KEY_DISTRIBUTION + /* + * If KEY_DISTRIBUTION is defined (testing purpose only), we will + * extract the FA session keys from the registration reply. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_VEND_KEY_EXT(messageHdr, index, VENDOR_ID_SUN, REG_MN_FA_KEY_EXT, + keyData, keyDataLen); + + if (keyDataLen) { + /* + * We have a key!!! Let's create our security assoc. + */ + if (createSecAssocFromKeyData(keyData, keyDataLen, &SPI) == + _B_FALSE) { + syslog(LOG_ERR, + "unable to create dynamic MN-FA SA"); + return (HA_FA_AUTH_FAILURE); + } + favePtr->faVisitorSPI = SPI; + } + + /* + * If KEY_DISTRIBUTION is defined (testing purpose only), we will + * extract the FA session keys from the registration reply. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_VEND_KEY_EXT(messageHdr, index, VENDOR_ID_SUN, REG_FA_HA_KEY_EXT, + keyData, keyDataLen); + + if (keyDataLen) { + /* + * We have a key!!! Let's create our security assoc. + */ + if (createSecAssocFromKeyData(keyData, keyDataLen, &SPI) == + _B_FALSE) { + syslog(LOG_ERR, + "unable to create dynamic FA-HA SA"); + return (HA_FA_AUTH_FAILURE); + } + } +#endif /* KEY_DISTRIBUTION */ + + /* + * If a Home agent Foreign agent authentication extension exists + * check it. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_FH_AUTH_EXT_TYPE, haAuthExt, + haAuthExtLen); + + if (haAuthExtLen) { + GET_SPI(SPI, haAuthExt); + + /* + * Remember that the node will be locked upon return. + * We need to unlock it when we are done... + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Error: No Home Agent SA (%d)", SPI); + faCounters.faHAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + + if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + syslog(LOG_ERR, "Failed FA-HA authentication"); + faCounters.faHAAuthFailureCnt++; + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + return (HA_FA_AUTH_FAILURE); + } + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + /* + * Remove the extension by playing with the + * packet's length. + */ + messageHdr->pktLen = (messageHdr->extIdx[index-1] - + messageHdr->pkt) + messageHdr->extHdrLength[index-1] + + messageHdr->extLength[index-1]; + + if (aaaProtocol == DIAMETER && + messageHdr->pktSource == MIP_PKT_FROM_AAA) { + /* + * We probably ended up getting a new SPI from the + * AAA Server. Update the Visitor Entry with the + * new SPI. + */ + favePtr->faVisitorSPI = messageHdr->mnFaSPI; + } + } else { + if (fhAuthRequired) { + faCounters.faHAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + } + + + return (0); +} + + +/* + * Function: haCheckRegReqAuth + * + * Arguments: messageHdr - Pointer to the Message Control Block + * hamnePtr - Pointer to a pointer to a mobile node entry + * mnSPI - Pointer to the Mobile Node SPI + * faSPI - Pointe to the Foreign Agent SPI + * + * Description: This function is used to authenticate a Registration + * request on the Home Agent. First we attempt to find + * the Mobile Node Entry using the Home Address. If the + * Home Address in the request was set to zero, we will + * attempt to find it using the Mobile Node's NAI. + * + * Next we will ensure that either the Mobile-Home or the + * Mobile-AAA autentication extension is present. If none + * is present, and the packet was marked as being received + * by the Foreign Agent (as opposed to the AAA), we will + * make sure that the unknown Mobile Node is attempting + * to authenticate using the default SPI. If the packet + * was received via the AAA infrastructure, we will + * not require any authentication from the Mobile Node. + * + * Lastly, we will check the Foreign-Home Authentication + * extension. If one was not found, and the packet was + * not received by the AAA, we will fail authentication. + * + * Note that if a Mobile Node Entry pointer is returned + * by this function, the node will be locked. The caller + * is responsible to unlock the node. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. + */ +int +haCheckRegReqAuth(MessageHdr *messageHdr, HaMobileNodeEntry **hamnePtr, + uint32_t *mnSPI, uint32_t *faSPI) +{ + regRequest *reqPtr; + int code = 0; + int result; + MipSecAssocEntry *mipSecAssocEntry; + genAuthExt *maAuthExt = NULL; + authExt *mnAuthExt = NULL; + authExt *faAuthExt = NULL; + int mnAuthExtLen; + int faAuthExtLen; + int index; + uint32_t SPI; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + reqPtr = (regRequest *)messageHdr->pkt; + *hamnePtr = NULL; + +#ifdef RADIUS_ENABLED + if (radiusEnabled) { + /* + * We always have to force a RADIUS lookup. + */ + *hamnePtr = radiusCheckUpdate(*hamnePtr, + &haMobileNodeHash, + reqPtr->homeAddr); + } +#endif /* RADIUS_ENABLED */ + + /* + * If a Foreign agent Home Agent authentication extension exists + * check it. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_FH_AUTH_EXT_TYPE, faAuthExt, + faAuthExtLen); + + if (faAuthExtLen) { + GET_SPI(SPI, faAuthExt); + *faSPI = SPI; + /* + * if an SA is returned, the node will be locked so we + * need to unlock it when we are done. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, + "Failed FA-HA authentication - SPI (%d) " + "defined", SPI); + haCounters.haFAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + + if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + syslog(LOG_ERR, "Failed FA-HA authentication"); + haCounters.haFAAuthFailureCnt++; + (void) rw_unlock( + &mipSecAssocEntry->mipSecNodeLock); + return (HA_FA_AUTH_FAILURE); + } + + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + } else if ((messageHdr->pktSource != MIP_PKT_FROM_AAA) && + (messageHdr->pktSource != MIP_PKT_FROM_RADIUS)) { + /* + * If the packet comes from the AAA, we do not need + * the FA-HA auth, otherwise we may be configured + * to require it. + */ + if (fhAuthRequired) { + haCounters.haFAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + } else { + *faSPI = messageHdr->faHaSPI; + } + + /* + * If a Mobile Node Home Agent authentication extension exists + * check it. + */ + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, mnAuthExt, + mnAuthExtLen); + + if (mnAuthExtLen) { + GET_SPI(SPI, mnAuthExt); + /* + * if an SA is returned, the node will be locked so we + * need to unlock it when we are done. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Failed MN-HA authentication - " + "No SPI defined"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) || + (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) { + if (mipSecAssocEntry->mipSecIsEntryDynamic != + TRUE) { + /* + * So the packet came from the AAA. We + * need to ensure that the key being + * used is in fact a dynamic key. + * Otherwise we are leaving a security + * hole wide open. + */ + (void) rw_unlock( + &mipSecAssocEntry->mipSecNodeLock); + syslog(LOG_WARNING, "A AAA Mobile " + "Node is attempting to use a " + "static key - security violation!"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + } else if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - + messageHdr->pkt), mipSecAssocEntry) == + _B_FALSE) { + syslog(LOG_ERR, "Failed MN-HA " + "authentication"); + haCounters.haMNAuthFailureCnt++; + (void) rw_unlock( + &mipSecAssocEntry->mipSecNodeLock); + return (HA_MN_AUTH_FAILURE); + } + + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + } + if (aaaProtocol == RADIUS) { + + /* + * Validate MN_AAA ext exists before AAA call + * This way if an error we don't need + * to call on AAA. + */ + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_GEN_AUTH_EXT(messageHdr, index, + GEN_AUTH_MN_AAA, maAuthExt, mnAuthExtLen); + + if (mnAuthExtLen == 0) { + syslog(LOG_ERR, "Missing MN AAA Ext"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + /* + * Get the MN-AAA SPI + */ + GET_GEN_AUTH_SPI(*mnSPI, maAuthExt); + + /* + * Make sure SPI used is the Radius SPI (2). + */ + if (*mnSPI != RADIUS_SPI) { + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + + /* + * If using Radius, we'd like to preserve messageHdr + * until we get a reply from the Radius server + */ + + messageHdr->dontDeleteNow = _B_TRUE; + + result = AAAAuthenticateRegReq(messageHdr->pkt, + messageHdr->pktLen, messageHdr->mnNAI, + messageHdr->mnNAILen, *mnSPI, + (unsigned char *)NULL, 0, 0, + reqPtr->homeAddr, reqPtr->haAddr, _B_TRUE, + 0, (void *)messageHdr, NULL, 0); + + if (result) { + /* + * Now we look at the result code to determine + * what the error was. + */ + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + + } + + /* + * If talking to RADIUS client, you must wait for a reponse + * back (from AAAAuthenticateRegReq() call) before + * continuing on with haCheckRegReqAuthContinue(). + * As such, wait until RADIUS responds then continue on + * with authentication process. + */ + + if (aaaProtocol != RADIUS) { + code = haCheckRegReqAuthContinue(messageHdr, hamnePtr, + mnSPI, faSPI); + return (code); + } + return (0); +} + +/* + * Function: haCheckRegReqAuthContinue + * + * Arguments: messageHdr - Pointer to the Message Control Block + * hamnePtr - Pointer to a pointer to a mobile node entry + * mnSPI - Pointer to the Mobile Node SPI + * faSPI - Pointe to the Foreign Agent SPI + * + * Description: This function is used to authenticate a Registration + * request on the Home Agent. First we attempt to find + * the Mobile Node Entry using the Home Address. If the + * Home Address in the request was set to zero, we will + * attempt to find it using the Mobile Node's NAI. + * + * if aaaProtocol is RADIUS, this funtion will be called after + * an ANSWER is received from the Radius client. + * Otherwise, the processing will continue from + * haCheckRegReqAuth() function. + * + * Next we will ensure that either the Mobile-Home or the + * Mobile-AAA autentication extension is present. If none + * is present, and the packet was marked as being received + * by the Foreign Agent (as opposed to the AAA), we will + * make sure that the unknown Mobile Node is attempting + * to authenticate using the default SPI. If the packet + * was received via the AAA infrastructure, we will + * not require any authentication from the Mobile Node. + * + * Lastly, we will check the Foreign-Home Authentication + * extension. If one was not found, and the packet was + * not received by the AAA, we will fail authentication. + * + * Note that if a Mobile Node Entry pointer is returned + * by this function, the node will be locked. The caller + * is responsible to unlock the node. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. + */ +/* ARGSUSED */ +int +haCheckRegReqAuthContinue(MessageHdr *messageHdr, HaMobileNodeEntry **hamnePtr, + uint32_t *mnSPI, uint32_t *faSPI) +{ + regRequest *reqPtr; + authExt *mnAuthExt = NULL; + genAuthExt *maAuthExt = NULL; + MipSecAssocEntry *mipSecAssocEntry; + uint32_t SPI; + int index; + int mnAuthExtLen; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + reqPtr = (regRequest *)messageHdr->pkt; + + if (reqPtr->homeAddr) { + /* + * Find the Mobile Node. Remember that this node will + * be locked upon return. As it turns out, the caller + * to this function will have to unlock the node since + * we are passing it the pointer as part of an argument. + */ + *hamnePtr = findHashTableEntryUint(&haMobileNodeHash, + reqPtr->homeAddr, LOCK_WRITE, NULL, 0, 0, 0); + } + + if (*hamnePtr == NULL) { + /* + * Search for the MobileNodeEntry based on the + * NAI. + */ + + *hamnePtr = findHashTableEntryString(&haMobileNodeHash, + messageHdr->mnNAI, messageHdr->mnNAILen, LOCK_WRITE, + NULL, 0, 0, 0); + } + + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, mnAuthExt, + mnAuthExtLen); + + /* + * If aaaProtocol != RADIUS/DIAMETER, then the home agent CAN + * accept Mobile-AAA Authentication extensions, so if we cannot + * find the Authentication Extension, find the MN-AAA. + * + * Happy Dave? + */ + if ((mnAuthExtLen == 0) && (aaaProtocol == AAA_NONE)) { + /* + * Support for the latest Challenge/Response I-D + * + * This code does not belong in the HA, this is + * really targetted to the AAA Server. We will + * include it to fully support the protocol. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_GEN_AUTH_EXT(messageHdr, index, + GEN_AUTH_MN_AAA, maAuthExt, mnAuthExtLen); + + if (mnAuthExtLen == 0) { + syslog(LOG_ERR, "Missing Challenge or Response"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + /* + * Get the MN-AAA SPI + */ + GET_GEN_AUTH_SPI(SPI, maAuthExt); +#ifdef KEY_DISTRIBUTION + /* + * If this code is compiled, the Home Agent will provide AAA + * like functionality by creating Session Keys for: + * MN-HA + * MN-FA + * FA-HA + * The last one is normally not seen by the Home Agent when + * keys are received from DIAMETER, but since we are providing + * this functionality (mostly for testing purposes) we will + * send it to the Foreign Agent as a vendor specific extension. + */ + createSessionKey(messageHdr->mnHaKey, &messageHdr->mnHaKeyLen, + &messageHdr->mnHaSPI); + + createSessionKey(messageHdr->mnFaKey, &messageHdr->mnFaKeyLen, + &messageHdr->mnFaSPI); + + createSessionKey(messageHdr->faHaKey, &messageHdr->faHaKeyLen, + &messageHdr->faHaSPI); + + messageHdr->kdcKeysPresent = _B_TRUE; + messageHdr->mnAAASPI = SPI; +#endif /* KEY_DISTRIBUTION */ + } else if (mnAuthExt) { + /* + * Get the MN-HA SPI + */ + GET_SPI(SPI, mnAuthExt); + } else { + SPI = 0; + } + + if (*hamnePtr == NULL) { + /* + * So we have a couple of options here. The first being + * where the packet is received by the AAA. In this + * case, the Mobile Node will not exist locally, and the + * key would have been installed as a dynamic key. + * The second option is where the default node is being + * used. When this occurs, it is mandatory that the + * mobile node use the default SPI. + */ + if (messageHdr->pktSource == MIP_PKT_FROM_FA) { + /* + * So, it looks like we don't know who this is. If a + * default SA is setup, we will check if we can + * create a dynamic Mobile Node Entry. + */ + if (defaultNodeSPI == 0 || defaultNodeSPI != SPI) { + syslog(LOG_ERR, + "As far as I'm concerned, this " + "mobile node doesn't exist"); + return (HA_ADM_PROHIBITED); + } + } else { + SPI = messageHdr->mnHaSPI; + } + } else { + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) || + (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) { + SPI = messageHdr->mnHaSPI; + (*hamnePtr)->haMnSPI = SPI; + } else { + /* + * Did the Mobile Node specify the correct SPI? + */ + if ((*hamnePtr)->haMnSPI != SPI) { + syslog(LOG_ERR, "Failed MN-HA authentication - " + "Invalid SPI requested %d, looking for %d", + SPI, (*hamnePtr)->haMnSPI); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + } + } + *mnSPI = SPI; + + /* + * if an SA is returned, the node will be locked so we + * need to unlock it when we are done. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Failed MN-HA authentication - " + "No SPI defined"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) || + (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) { + if (mipSecAssocEntry->mipSecIsEntryDynamic != TRUE) { + /* + * So the packet came from the AAA. We need to + * ensure that the key being used is in fact a + * dynamic key. Otherwise we are leaving a security + * hole wide open. + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + syslog(LOG_WARNING, "A AAA Mobile Node is attempting" + " to use a static key - security violation!"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + } else if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + syslog(LOG_ERR, "Failed MN-HA authentication"); + haCounters.haMNAuthFailureCnt++; + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + return (HA_MN_AUTH_FAILURE); + } + + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + return (0); +} |