CDSLocalAuthHelper.cpp [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include "CDSLocalAuthHelper.h"
#include "AuthHelperUtils.h"
#include "CDSLocalPlugin.h"
#include "CDSAuthDefs.h"
#include "CAuthAuthority.h"
#include "CDSLocalAuthParams.h"
#include "DirServices.h"
#include "DirServicesTypes.h"
#include "DirServicesUtils.h"
#include "DirServicesConst.h"
#include "DirServicesConstPriv.h"
#include "CFile.h"
#include "DSUtils.h"
#include "CLog.h"
#include "SMBAuth.h"
#include <CommonCrypto/CommonCryptor.h>
#include <CommonCrypto/CommonDigest.h>
#include <Security/Authorization.h>
#include <PasswordServer/CAuthFileBase.h>
#include <PasswordServer/CPolicyGlobalXML.h>
#include <PasswordServer/CPolicyXML.h>
#include <PasswordServer/KerberosInterface.h>
#include <syslog.h>
#include <sys/time.h>
#include <openssl/md5.h>
#include <openssl/evp.h>
#include <mach/mach_time.h> // for dsTimeStamp
#include "chap.h"
#include "chap_ms.h"
#include "buffer_unpackers.h"
#include "CDSPluginUtils.h"
#include "CDSLocalPluginNode.h"
#include "CRefTable.h"
#include <DirectoryServiceCore/pps.h>
#include <string> //STL string class
#define kDoNotTouchTheAuthAuthorities false
extern "C" {
extern void CvtHex(HASH Bin, HASHHEX Hex);
};
typedef struct AuthAuthorityHandler {
char* fTag;
AuthAuthorityHandlerProc fHandler;
} AuthAuthorityHandler;
tDirStatus ParseLocalCacheUserAuthData( const char *inAuthData,
char **outNodeName,
char **outRecordName,
char **outGUID );
static AuthAuthorityHandler sAuthAuthorityHandlerProcs[] =
{
{ kDSTagAuthAuthorityBasic, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoBasicAuth },
{ kDSTagAuthAuthorityLocalWindowsHash, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoShadowHashAuth },
{ kDSTagAuthAuthorityShadowHash, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoShadowHashAuth },
{ kDSTagAuthAuthorityKerberosv5, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoKerberosAuth },
{ kDSTagAuthAuthorityKerberosv5Cert, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoKerberosCertAuth },
{ kDSTagAuthAuthorityLocalCachedUser, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoLocalCachedUserAuth },
{ kDSTagAuthAuthorityPasswordServer, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoPasswordServerAuth },
{ kDSTagAuthAuthorityDisabledUser, (AuthAuthorityHandlerProc)CDSLocalAuthHelper::DoDisabledAuth },
{ NULL, NULL }
};
extern DSMutexSemaphore *gHashAuthFailedLocalMapLock;
extern dsBool gServerOS;
extern UInt32 gDaemonPID;
extern UInt32 gDaemonIPAddress;
HashAuthFailedMap gHashAuthFailedLocalMap;
static char sZeros[kHashRecoverableLength] = {0};
tDirStatus CDSLocalAuthHelper::CopyUserNameFromAuthBuffer( tDataBufferPtr inAuthData, unsigned long inUserNameIndex,
CFStringRef *outUserName )
{
tDataListPtr dataList = ::dsAuthBufferGetDataListAllocPriv(inAuthData);
if (dataList != NULL)
{
char* userNameCStr = ::dsDataListGetNodeStringPriv(dataList, inUserNameIndex);
*outUserName = CFStringCreateWithCString( NULL, userNameCStr, kCFStringEncodingUTF8 );
::free( userNameCStr );
::dsDataListDeallocatePriv(dataList);
::free(dataList);
dataList = NULL;
return eDSNoErr;
}
return eDSInvalidBuffFormat;
}
bool CDSLocalAuthHelper::AuthAuthoritiesHaveTag( CFStringRef inRecordName, CFArrayRef inAuthAuthorities, CFStringRef inTag )
{
if ( inAuthAuthorities == NULL )
return false;
if ( inTag == NULL )
return false;
if ( inRecordName == NULL )
return false;
CFIndex numAuthAuthorities = CFArrayGetCount( inAuthAuthorities );
if ( CFStringCompare( inRecordName, inTag, 0 ) == kCFCompareEqualTo )
{
char* aaVersion = NULL;
char* aaTag = NULL;
char* aaData = NULL;
char* cStr = NULL;
size_t cStrSize = 0;
char* cStr2 = NULL;
size_t cStrSize2 = 0;
bool hasTag = false;
for( CFIndex i=0; i<numAuthAuthorities; i++ )
{
const char* authAuthorityCStr = CStrFromCFString( (CFStringRef)CFArrayGetValueAtIndex(
inAuthAuthorities, i ), &cStr, &cStrSize, NULL );
tDirStatus dirStatus = ::dsParseAuthAuthority( authAuthorityCStr, &aaVersion, &aaTag, &aaData );
if ( dirStatus != eDSNoErr )
{
DbgLog( kLogPlugin, "CDSLocalPlugin::AuthAuthoritiesHaveTag(): dsParseAuthAuthority() returned an error %d",
dirStatus );
continue;
}
const char* tagCStr = CStrFromCFString( inTag, &cStr2, &cStrSize2, NULL );
if ( ::strcasecmp( tagCStr, aaTag ) == 0 )
{
hasTag = true;
break;
}
else if ( ::strcasecmp( kDSTagAuthAuthorityDisabledUser, aaTag ) == 0 &&
::strcasestr( authAuthorityCStr, tagCStr ) != NULL )
{
hasTag = true;
break;
}
}
if ( cStr != NULL )
::free( cStr );
if ( cStr2 != NULL )
::free( cStr2 );
if ( aaVersion != NULL )
::free( aaVersion );
if ( aaTag != NULL )
::free( aaTag );
if ( aaData != NULL )
::free( aaData );
return hasTag;
}
else
{
for( CFIndex i=0; i<numAuthAuthorities; i++ )
{
if ( CFStringFind( (CFStringRef)CFArrayGetValueAtIndex( inAuthAuthorities, i ), inTag, 0 ).location !=
kCFNotFound )
return true;
}
return false;
}
}
tDirStatus
CDSLocalAuthHelper::DoKerberosAuth(
tDirNodeReference inNodeRef,
CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
CAuthAuthority &inAuthAuthorityList,
const char* inGUIDString,
bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
unsigned int userLevelHashList = inHashList;
char *aaData = NULL;
if ( inAuthData == NULL )
return( eDSNullAuthStepData );
if ( inParams.mAuthMethodStr != NULL )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoKerberosAuth(): Attempting use of authentication method %s",
inParams.mAuthMethodStr );
}
siResult = inParams.LoadDSLocalParamsForAuthMethod( inParams.uiAuthMethod, userLevelHashList, inGUIDString, inAuthedUserIsAdmin,
inAuthData, outAuthData );
switch( siResult )
{
case eDSNoErr:
break;
case eDSAuthFailed:
return eDSAuthMethodNotSupported;
default:
return siResult;
}
if ( inParams.bFetchHashFiles )
{
CDSLocalAuthHelper::ReadShadowHashAndStateFiles(
inParams.pUserName,
inGUIDString,
inParams.hashes,
&inParams.modDateOfPassword,
&inParams.path,
&inParams.stateFilePath,
&inParams.state,
&inParams.hashesLengthFromFile );
}
aaData = inAuthAuthorityList.GetDataForTag( kDSTagAuthAuthorityKerberosv5, 1 );
switch( inParams.uiAuthMethod )
{
case kAuthSetPasswd:
siResult = GetUserPolicies( inMutableRecordDict, NULL, inPlugin, &inParams.policyStr );
if ( siResult == eDSNoErr )
{
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess,
&inParams.globalMoreAccess );
if ( ! inAuthedUserIsAdmin )
{
bool authFailed = false;
if ( ( inAuthedUserName == NULL ) || ( inParams.pUserName == NULL ) )
authFailed = true;
else
{
CFStringRef userNameCFStr = CFStringCreateWithCString( NULL, inParams.pUserName,
kCFStringEncodingUTF8 );
if ( CFStringCompare( userNameCFStr, inAuthedUserName, 0 ) != kCFCompareEqualTo )
authFailed = true;
CFRelease( userNameCFStr );
}
if ( authFailed )
siResult = eDSPermissionError;
else
{
siResult = CDSLocalAuthHelper::PasswordOkForPolicies( inParams.policyStr, &inParams.globalAccess,
inParams.pUserName, inParams.pNewPassword );
if ( siResult == eDSAuthPasswordTooShort &&
inParams.globalAccess.minChars == 0 &&
inParams.pNewPassword != NULL &&
*inParams.pNewPassword == '\0' &&
((inParams.policyStr == NULL) || strstr(inParams.policyStr, "minChars=0") != NULL) )
{
siResult = eDSNoErr;
}
}
}
if ( siResult == eDSNoErr )
{
char *localKDCRealmStr = GetLocalKDCRealmWithCache( kLocalKDCRealmCacheTimeout );
if ( localKDCRealmStr != NULL )
{
bool oldNewPrincEq = (aaData && inParams.pUserName && strcmp(aaData, inParams.pUserName) == 0);
pwsf_DeletePrincipalInLocalRealm( aaData, localKDCRealmStr );
if ( !oldNewPrincEq )
pwsf_DeletePrincipalInLocalRealm( inParams.pUserName, localKDCRealmStr );
if ( pwsf_AddPrincipalToLocalRealm(inParams.pUserName, inParams.pNewPassword, localKDCRealmStr) != 0 )
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoKerberosAuth(): Unable to add principal %s@%s",
inParams.pUserName, localKDCRealmStr );
if ( !oldNewPrincEq )
{
size_t princStrLen = strlen(inParams.pUserName) + strlen(localKDCRealmStr) + 2;
char *princStr = (char *)malloc( princStrLen );
if ( princStr != NULL )
{
snprintf( princStr, princStrLen, "%s@%s", inParams.pUserName, localKDCRealmStr );
inAuthAuthorityList.SetDataForTag( kDSTagAuthAuthorityKerberosv5, princStr, 1 );
SaveAuthAuthorities( inPlugin, inNodeRef, inParams.pUserName, inNativeRecType, inAuthAuthorityList );
free( princStr );
}
else
{
siResult = eMemoryError;
}
}
free( localKDCRealmStr );
}
}
}
break;
case kAuthSetPasswdAsRoot:
{
bool modifyingSelf = false;
if ( ( inAuthedUserName == NULL ) || ( inParams.pUserName == NULL ) )
modifyingSelf = true;
else
{
CFStringRef userNameCFStr = CFStringCreateWithCString( NULL, inParams.pUserName,
kCFStringEncodingUTF8 );
if ( CFStringCompare( userNameCFStr, inAuthedUserName, 0 ) == kCFCompareEqualTo )
modifyingSelf = true;
CFRelease( userNameCFStr );
}
bool notAdmin = ( ( inAuthedUserName != NULL ) && !inAuthedUserIsAdmin );
if ( inEffectiveUID != 0 )
{
if ( ( inAuthedUserName == NULL) ||
(notAdmin && (!modifyingSelf)) )
{
siResult = eDSPermissionError;
}
}
if ( siResult != eDSPermissionError )
{
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess,
&inParams.globalMoreAccess );
siResult = eDSNoErr;
if ( modifyingSelf && notAdmin )
{
siResult = CDSLocalAuthHelper::PasswordOkForPolicies( inParams.policyStr, &inParams.globalAccess,
inParams.pUserName, inParams.pNewPassword );
if ( siResult == eDSAuthPasswordTooShort &&
inParams.globalAccess.minChars == 0 &&
inParams.pNewPassword != NULL &&
*inParams.pNewPassword == '\0' &&
((inParams.policyStr == NULL) || strstr(inParams.policyStr, "minChars=0") != NULL) )
{
siResult = eDSNoErr;
}
}
if ( siResult == eDSNoErr )
{
char *localKDCRealmStr = GetLocalKDCRealmWithCache( kLocalKDCRealmCacheTimeout );
if ( localKDCRealmStr != NULL )
{
bool oldNewPrincEq = (aaData && inParams.pUserName && strcmp(aaData, inParams.pUserName) == 0);
pwsf_DeletePrincipalInLocalRealm( aaData, localKDCRealmStr );
if ( !oldNewPrincEq )
pwsf_DeletePrincipalInLocalRealm( inParams.pUserName, localKDCRealmStr );
if ( pwsf_AddPrincipalToLocalRealm(inParams.pUserName, inParams.pNewPassword, localKDCRealmStr) != 0 )
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoKerberosAuth(): Unable to add principal %s@%s",
inParams.pUserName, localKDCRealmStr );
if ( !oldNewPrincEq )
{
size_t princStrLen = strlen(inParams.pUserName) + strlen(localKDCRealmStr) + 2;
char *princStr = (char *)malloc( princStrLen );
if ( princStr != NULL )
{
snprintf( princStr, princStrLen, "%s@%s", inParams.pUserName, localKDCRealmStr );
inAuthAuthorityList.SetDataForTag( kDSTagAuthAuthorityKerberosv5, princStr, 1 );
SaveAuthAuthorities( inPlugin, inNodeRef, inParams.pUserName, inNativeRecType, inAuthAuthorityList );
free( princStr );
}
else
{
siResult = eMemoryError;
}
}
free( localKDCRealmStr );
}
}
}
}
break;
case kAuthChangePasswd:
siResult = GetUserPolicies( inMutableRecordDict, NULL, inPlugin, &inParams.policyStr );
if ( siResult == eDSNoErr )
{
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pOldPassword,
strlen(inParams.pOldPassword),
userLevelHashList,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
if ( HashesEqual( inParams.hashes, inParams.generatedHashes ) || isSecondary )
{
bool notAdmin = ( (inParams.pUserName != NULL) && !inAuthedUserIsAdmin );
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess,
&inParams.globalMoreAccess );
if ( notAdmin )
{
siResult = CDSLocalAuthHelper::PasswordOkForPolicies( inParams.policyStr, &inParams.globalAccess,
inParams.pUserName, inParams.pNewPassword );
if ( siResult == eDSAuthPasswordTooShort &&
inParams.globalAccess.minChars == 0 &&
inParams.pNewPassword != NULL &&
*inParams.pNewPassword == '\0' &&
((inParams.policyStr == NULL) || strstr(inParams.policyStr, "minChars=0") != NULL) )
{
siResult = eDSNoErr;
}
}
if ( siResult == eDSNoErr )
{
char *localKDCRealmStr = GetLocalKDCRealmWithCache( kLocalKDCRealmCacheTimeout );
if ( localKDCRealmStr != NULL ) {
pwsf_ChangePasswordInLocalRealm( inParams.pUserName, localKDCRealmStr, inParams.pNewPassword );
free( localKDCRealmStr );
}
}
}
else
{
siResult = eDSAuthFailed;
}
}
break;
case kAuthMSLMCHAP2ChangePasswd:
siResult = eDSAuthMethodNotSupported;
break;
default:
siResult = eDSAuthMethodNotSupported;
}
DSFreeString( aaData );
return siResult;
}
tDirStatus
CDSLocalAuthHelper::DoKerberosCertAuth(
tDirNodeReference inNodeRef,
CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
CAuthAuthority &inAuthAuthorityList,
const char* inGUIDString,
bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
unsigned int userLevelHashList = inHashList;
char *aaData = NULL;
if ( inAuthData == NULL )
return( eDSNullAuthStepData );
if ( inParams.mAuthMethodStr != NULL )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoKerberosCertAuth(): Attempting use of authentication method %s",
inParams.mAuthMethodStr );
}
siResult = inParams.LoadDSLocalParamsForAuthMethod(
inParams.uiAuthMethod, userLevelHashList, inGUIDString, inAuthedUserIsAdmin,
inAuthData, outAuthData );
switch( siResult )
{
case eDSNoErr:
break;
case eDSAuthFailed:
return eDSAuthMethodNotSupported;
default:
return siResult;
}
aaData = inAuthAuthorityList.GetDataForTag( kDSTagAuthAuthorityKerberosv5Cert, 1 );
switch( inParams.uiAuthMethod )
{
case kAuthSetCertificateHashAsRoot:
{
char *localKDCRealmStr = GetLocalKDCRealmWithCache( kLocalKDCRealmCacheTimeout );
if ( localKDCRealmStr != NULL )
{
char *rndPassData = GenerateRandomComputerPassword();
if ( rndPassData != NULL )
{
bool oldNewPrincEq = (aaData && inParams.pNewPassword && strcmp(aaData, inParams.pNewPassword) == 0);
pwsf_DeletePrincipalInLocalRealm( inParams.pNewPassword, localKDCRealmStr );
if ( !oldNewPrincEq && aaData != NULL )
pwsf_DeletePrincipalInLocalRealm( aaData, localKDCRealmStr );
if ( pwsf_AddPrincipalToLocalRealm(inParams.pNewPassword, rndPassData, localKDCRealmStr) == 0 )
{
pwsf_SetCertHashInLocalRealm( inParams.pNewPassword, inParams.pNewPassword, localKDCRealmStr );
}
else
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoKerberosAuth(): Unable to add principal %s@%s",
inParams.pUserName, localKDCRealmStr );
}
if ( !oldNewPrincEq )
{
size_t princStrLen = strlen(inParams.pNewPassword) + strlen(localKDCRealmStr) + 2;
char *princStr = (char *)malloc( princStrLen );
if ( princStr != NULL )
{
snprintf( princStr, princStrLen, "%s@%s", inParams.pNewPassword, localKDCRealmStr );
inAuthAuthorityList.SetDataForTag( kDSTagAuthAuthorityKerberosv5Cert, princStr, 1 );
SaveAuthAuthorities( inPlugin, inNodeRef, inParams.pUserName, inNativeRecType, inAuthAuthorityList );
free( princStr );
}
else
{
siResult = eMemoryError;
}
}
free( rndPassData );
}
free( localKDCRealmStr );
}
}
break;
default:
siResult = eDSAuthMethodNotSupported;
}
DSFreeString( aaData );
return siResult;
}
tDirStatus CDSLocalAuthHelper::DoShadowHashAuth(
tDirNodeReference inNodeRef,
CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
CAuthAuthority &inAuthAuthorityList,
const char* inGUIDString,
bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType )
{
return DoShadowHashAuth( inNodeRef, inParams, inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary,
inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList,
inPlugin, inNode, inAuthedUserName, inUID, inEffectiveUID, inNativeRecType, true );
}
tDirStatus CDSLocalAuthHelper::DoShadowHashAuth(
tDirNodeReference inNodeRef,
CDSLocalAuthParams &inParams,
CFMutableDictionaryRef *inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
CAuthAuthority &inAuthAuthorityList,
const char *inGUIDString,
bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin *inPlugin,
CDSLocalPluginNode *inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType,
bool inOKToChangeAuthAuthorities )
{
tDirStatus siResult = eDSAuthFailed;
int saslError = SASL_OK;
unsigned int userLevelHashList = inHashList;
time_t now = 0;
sHashAuthFailed *pHashAuthFailed = NULL;
UInt32 len = 0;
bool bufferUserIsAdmin = false;
CFMutableArrayRef myHashTypeArray = NULL;
bool needToChange = false;
bool bCheckDelay = true;
CFStringRef adminString = NULL;
const char *serverout = NULL;
unsigned int serveroutlen = 0;
ServerAuthDataBlockPtr ppsServerContext = NULL;
if ( inAuthData == NULL )
return( eDSNullAuthStepData );
if (inParams.mAuthMethodStr != NULL)
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoShadowHashAuth(): Attempting use of authentication method %s",
inParams.mAuthMethodStr );
}
inParams.aaData = inAuthAuthorityList.GetDataForTag( kDSTagAuthAuthorityShadowHash, 0 );
if ( inParams.aaData != NULL && inParams.aaData[0] != '\0' )
{
siResult = CDSLocalAuthHelper::GetHashSecurityLevelForUser( inParams.aaData, &userLevelHashList );
if ( siResult != eDSNoErr )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoShadowHashAuth() - encountered invalid record hash list: %s",
inParams.aaData );
userLevelHashList = inHashList;
siResult = eDSNoErr;
}
}
siResult = inParams.LoadDSLocalParamsForAuthMethod( inParams.uiAuthMethod, userLevelHashList, inGUIDString, inAuthedUserIsAdmin,
inAuthData, outAuthData );
if ( siResult != eDSNoErr )
return( siResult );
if ( inParams.bFetchHashFiles )
{
siResult = CDSLocalAuthHelper::ReadShadowHashAndStateFiles(
inParams.pUserName,
inGUIDString,
inParams.hashes,
&inParams.modDateOfPassword,
&inParams.path,
&inParams.stateFilePath,
&inParams.state,
&inParams.hashesLengthFromFile );
if ( siResult != eDSNoErr )
{
switch( inParams.uiAuthMethod )
{
case kAuthSetPasswd:
case kAuthSetPasswdAsRoot:
case kAuthWriteSecureHash:
case kAuthMSLMCHAP2ChangePasswd:
case kAuthNTSetWorkstationPasswd:
case kAuthNTSetNTHash:
case kAuthSetLMHash:
case kAuthSetPolicyAsRoot:
case kAuthSetShadowHashWindows:
case kAuthSetShadowHashSecure:
case kAuthSetComputerAcctPasswdAsRoot:
case kAuthSetCertificateHashAsRoot:
siResult = eDSNoErr;
break;
default:
break;
}
}
}
if ( (siResult != eDSNoErr) && !(isSecondary && (inParams.uiAuthMethod == kAuthChangePasswd)) )
return( siResult );
if ( inParams.pUserName != NULL )
{
CFStringRef userNameCFStr = CFStringCreateWithCString( kCFAllocatorDefault, inParams.pUserName, kCFStringEncodingUTF8 );
bufferUserIsAdmin = inPlugin->UserIsAdmin( userNameCFStr, inNode );
CFRelease( userNameCFStr );
}
switch( inParams.uiAuthMethod )
{
case kAuthGetGlobalPolicy:
siResult = CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess,
&inParams.globalMoreAccess );
if ( siResult != eDSNoErr )
return( siResult );
{
char policies[2048];
PWGlobalAccessFeaturesToStringExtra( &inParams.globalAccess, &inParams.globalMoreAccess, sizeof(policies), policies );
inParams.policyStrLen = strlen( policies );
siResult = dsFillAuthBuffer( outAuthData, 1, inParams.policyStrLen, policies );
}
if ( outAuthData->fBufferLength == 0 )
return( eDSEmptyAttribute );
break;
case kAuthSetGlobalPolicy:
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess, &inParams.globalMoreAccess );
inParams.dataList = dsAuthBufferGetDataListAllocPriv( inAuthData );
if ( inParams.dataList == NULL ) {
siResult = eDSInvalidBuffFormat;
goto finish;
}
inParams.pNewPassword = dsDataListGetNodeStringPriv(inParams.dataList, 3);
if ( inParams.pNewPassword == NULL || strlen(inParams.pNewPassword) < 1 ) {
siResult = eDSInvalidBuffFormat;
goto finish;
}
StringToPWGlobalAccessFeaturesExtra( inParams.pNewPassword, &inParams.globalAccess, &inParams.globalMoreAccess );
siResult = CDSLocalAuthHelper::SetShadowHashGlobalPolicies( inPlugin, inNode, inNodeRef,
inAuthedUserName, inUID, inEffectiveUID, &inParams.globalAccess, &inParams.globalMoreAccess );
break;
case kAuthSetPolicy:
case kAuthSetPolicyAsRoot:
siResult = CDSLocalAuthHelper::SetUserPolicies( inMutableRecordDict, inPlugin, inNode, inAuthedUserName,
inUID, inEffectiveUID, inNativeRecType, inParams.pUserName, inParams.pNewPassword, inAuthedUserIsAdmin, inNodeRef,
&inParams.targetUserState );
if ( siResult == eDSNoErr && inParams.targetUserStateFilePath != NULL )
CDSLocalAuthHelper::WriteHashStateFile( inParams.targetUserStateFilePath, &inParams.targetUserState );
break;
case kAuthGetPolicy:
siResult = GetUserPolicies( inMutableRecordDict, &inParams.state, inPlugin, &inParams.policyStr );
if ( siResult != 0 ) return( siResult );
if ( inParams.policyStr != NULL )
{
inParams.policyStrLen = strlen( inParams.policyStr );
siResult = dsFillAuthBuffer( outAuthData, 1, inParams.policyStrLen, inParams.policyStr );
}
break;
case kAuthDIGEST_MD5:
{
char *mutualDigest = NULL;
unsigned int mutualDigestLen;
unsigned long passwordLength;
siResult = CDSLocalAuthHelper::UnobfuscateRecoverablePassword( inParams.hashes + kHashOffsetToRecoverable,
(unsigned char **)&inParams.pOldPassword, &passwordLength );
if ( siResult == eDSNoErr )
{
siResult = SASLErrToDirServiceError(
digest_verify(
&inParams.digestContext, inParams.pOldPassword, passwordLength,
&mutualDigest, &mutualDigestLen ) );
}
if ( siResult == eDSNoErr && mutualDigest != NULL )
{
siResult = dsFillAuthBuffer( outAuthData, 1, mutualDigestLen, mutualDigest );
}
DSFree( mutualDigest );
}
break;
case kAuthCRAM_MD5:
siResult = CDSLocalAuthHelper::CRAM_MD5( inParams.hashes + kHashOffsetToCramMD5, inParams.challenge, inParams.pCramResponse );
break;
case kAuthAPOP:
{
unsigned long passwordLength;
siResult = CDSLocalAuthHelper::UnobfuscateRecoverablePassword( inParams.hashes + kHashOffsetToRecoverable,
(unsigned char **)&inParams.pOldPassword, &passwordLength );
if ( siResult == eDSNoErr )
siResult = CDSLocalAuthHelper::Verify_APOP( inParams.pUserName, (unsigned char *)inParams.pOldPassword,
passwordLength, inParams.challenge, inParams.apopResponse );
}
break;
case kAuthSMB_NT_Key:
memmove(inParams.P21, inParams.hashes, kHashShadowOneLength);
CalculateP24(inParams.P21, inParams.C8, inParams.P24);
siResult = (memcmp(inParams.P24, inParams.P24Input, kHashShadowResponseLength) == 0) ? eDSNoErr : eDSAuthFailed;
break;
case kAuthSMB_LM_Key:
memmove(inParams.P21, inParams.hashes + kHashOffsetToLM, kHashShadowOneLength);
CalculateP24(inParams.P21, inParams.C8, inParams.P24);
siResult = (memcmp(inParams.P24, inParams.P24Input, kHashShadowResponseLength) == 0) ? eDSNoErr : eDSAuthFailed;
break;
case kAuthNTLMv2:
if ( NTLMv2(inParams.GeneratedNTLM, inParams.hashes, inParams.pSambaName, inParams.pDomain, inParams.C8,
inParams.pNTLMDigest + kShadowHashNTLMv2Length, inParams.ntlmDigestLen - kShadowHashNTLMv2Length) == 0 )
{
if ( memcmp(inParams.GeneratedNTLM, inParams.pNTLMDigest, kShadowHashNTLMv2Length) == 0 )
{
siResult = eDSNoErr;
}
else
{
siResult = eDSAuthFailed;
}
}
break;
case kAuthMSCHAP2:
siResult = CDSLocalAuthHelper::MSCHAPv2( inParams.C16, inParams.PeerC16, inParams.pNTLMDigest, inParams.pSambaName,
inParams.hashes, inParams.MSCHAP2Response );
if ( siResult == eDSNoErr )
{
outAuthData->fBufferLength = 4 + MS_AUTH_RESPONSE_LENGTH;
inParams.ntlmDigestLen = MS_AUTH_RESPONSE_LENGTH;
memcpy( outAuthData->fBufferData, &inParams.ntlmDigestLen, 4 );
memcpy( outAuthData->fBufferData + 4, inParams.MSCHAP2Response, MS_AUTH_RESPONSE_LENGTH );
}
break;
case kAuthPPS:
if ( *inOutContinueDataDict == NULL )
{
ppsServerContext = (ServerAuthDataBlockPtr)calloc( 1, sizeof(ServerAuthDataBlock) );
server_step_0_set_hash( inParams.hashes + kHashOffsetToSaltedSHA1, ppsServerContext );
}
else
{
CFDataRef ppsContext = (CFDataRef)CFDictionaryGetValue( *inOutContinueDataDict, CFSTR("ppsContext") );
if ( ppsContext != NULL )
{
ServerAuthDataBlockPtr *ctxPtr = (ServerAuthDataBlockPtr *)CFDataGetBytePtr( ppsContext );
if ( ctxPtr != NULL )
ppsServerContext = *ctxPtr;
}
if ( ppsServerContext == NULL )
siResult = eDSAuthContinueDataBad;
}
if ( siResult == eDSNoErr )
{
saslError = pps_server_mech_step(
ppsServerContext,
inParams.challenge, strlen(inParams.challenge),
&serverout, &serveroutlen );
siResult = SASLErrToDirServiceError( saslError );
}
if ( siResult == eDSNoErr )
siResult = dsFillAuthBuffer( outAuthData, 1, serveroutlen, serverout );
if ( siResult == eDSNoErr && *inOutContinueDataDict == NULL )
{
*inOutContinueDataDict = CFDictionaryCreateMutable(
NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
if ( *inOutContinueDataDict == NULL )
throw( eMemoryError );
CFDataRef ppsContext = CFDataCreate( NULL, (UInt8 *)&ppsServerContext, sizeof(ServerAuthDataBlockPtr) );
CFDictionarySetValue( *inOutContinueDataDict, CFSTR("ppsContext"), ppsContext );
CFRelease( ppsContext );
}
if ( siResult != eDSNoErr || saslError == SASL_OK ) {
pps_server_mech_dispose( ppsServerContext );
if ( *inOutContinueDataDict != NULL ) {
CFRelease( *inOutContinueDataDict );
*inOutContinueDataDict = NULL;
}
}
break;
case kAuthVPN_PPTPMasterKeys:
if ( inEffectiveUID == 0 )
{
unsigned char sendKey[CC_SHA1_DIGEST_LENGTH];
unsigned char receiveKey[CC_SHA1_DIGEST_LENGTH];
CalculatePPTPSessionKeys( inParams.hashes, inParams.P24Input, inParams.keySize, sendKey, receiveKey );
inParams.ntlmDigestLen = inParams.keySize;
memcpy( outAuthData->fBufferData, &inParams.ntlmDigestLen, 4 );
memcpy( outAuthData->fBufferData + 4, sendKey, inParams.ntlmDigestLen );
memcpy( outAuthData->fBufferData + 4 + inParams.ntlmDigestLen, &inParams.ntlmDigestLen, 4 );
memcpy( outAuthData->fBufferData + 4 + inParams.ntlmDigestLen + 4, receiveKey, inParams.ntlmDigestLen );
outAuthData->fBufferLength = 8 + inParams.keySize*2;
}
else
{
siResult = eDSPermissionError;
}
break;
case kAuthSMBWorkstationCredentialSessionKey:
CalculateWorkstationCredentialSessKey( inParams.hashes, (char *)inParams.pNTLMDigest, (char *)inParams.pNTLMDigest + 8,
inParams.P24 );
siResult = dsFillAuthBuffer( outAuthData, 1, 8, inParams.P24 );
break;
case kAuthSecureHash:
if ( inParams.secureHashNode->fBufferLength == kHashSaltedSHA1Length )
{
siResult = (memcmp(inParams.secureHash, inParams.hashes + kHashOffsetToSaltedSHA1,
kHashSaltedSHA1Length) == 0) ? eDSNoErr : eDSAuthFailed;
}
else
{
siResult = eDSAuthFailed;
}
break;
case kAuthWriteSecureHash:
if ( inEffectiveUID != 0 )
{
siResult = eDSPermissionError;
goto finish;
}
memmove(inParams.generatedHashes + kHashOffsetToSaltedSHA1, inParams.secureHash, kHashSaltedSHA1Length);
siResult = CDSLocalAuthHelper::WriteShadowHash(inParams.pUserName, inGUIDString, inParams.generatedHashes);
break;
case kAuthReadSecureHash:
if ( inEffectiveUID != 0 )
{
siResult = eDSPermissionError;
goto finish;
}
siResult = CDSLocalAuthHelper::ReadShadowHashAndStateFiles(inParams.pUserName, inGUIDString, inParams.hashes,
&inParams.modDateOfPassword, &inParams.path, &inParams.stateFilePath, &inParams.state,
&inParams.hashesLengthFromFile);
if ( siResult == eDSNoErr )
{
UInt32 sha1hashLen = kHashSaltedSHA1Length;
unsigned char *sha1hashPtr = inParams.hashes + kHashOffsetToSaltedSHA1;
if ( inParams.hashesLengthFromFile < (kHashOffsetToSaltedSHA1 + kHashSaltedSHA1Length) ||
memcmp(sha1hashPtr, sZeros, kHashSaltedSHA1Length ) == 0 ) {
sha1hashLen = kHashSecureLength;
sha1hashPtr = inParams.hashes + kHashOffsetToSHA1;
}
siResult = dsFillAuthBuffer( outAuthData, 1, sha1hashLen, sha1hashPtr );
if ( siResult != eDSNoErr )
goto finish;
}
break;
case kAuthSetShadowHashWindows:
case kAuthSetShadowHashSecure:
case kAuthNativeClearTextOK:
case kAuthNativeNoClearText:
case kAuthSetPasswdCheckAdmin:
case kAuthNativeRetainCredential:
{
UInt32 pwdLen = 0;
siResult = GetUserPolicies( inMutableRecordDict, NULL, inPlugin, &inParams.policyStr );
if ( siResult != eDSNoErr )
goto finish;
if (inParams.pOldPassword != nil)
{
pwdLen = strlen(inParams.pOldPassword);
}
else
{
siResult = eDSAuthFailed;
goto finish;
}
if ( pwdLen >= kHashRecoverableLength ) {
siResult = eDSAuthPasswordTooLong;
goto finish;
}
if (inParams.hashesLengthFromFile == (kHashShadowBothLength + kHashSecureLength))
{
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pOldPassword,
strlen(inParams.pOldPassword),
ePluginHashSHA1 | ePluginHashNT | ePluginHashLM,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
}
else
{
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pOldPassword,
strlen(inParams.pOldPassword),
userLevelHashList,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
}
if ( HashesEqual( inParams.hashes, inParams.generatedHashes ) )
{
siResult = eDSNoErr;
if ( inParams.hashesLengthFromFile < kHashTotalLength)
{
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pOldPassword,
strlen(inParams.pOldPassword),
userLevelHashList,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
siResult = CDSLocalAuthHelper::WriteShadowHash( inParams.pUserName, inGUIDString, inParams.generatedHashes );
}
else if ( memcmp(inParams.hashes, inParams.generatedHashes, kHashTotalLength) != 0 )
{
siResult = CDSLocalAuthHelper::WriteShadowHash( inParams.pUserName, inGUIDString, inParams.generatedHashes );
}
MigrateAddKerberos( inNodeRef, inParams, inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary,
inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType, inOKToChangeAuthAuthorities );
if ( inParams.uiAuthMethod == kAuthSetShadowHashWindows ||
inParams.uiAuthMethod == kAuthSetShadowHashSecure )
{
pwsf_ShadowHashDataToArray( inParams.aaData, &myHashTypeArray );
if ( myHashTypeArray == NULL )
myHashTypeArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if (userLevelHashList & ePluginHashCRAM_MD5)
{
CFStringRef cram_md5_cfString = CFSTR( kHashNameCRAM_MD5 );
CFIndex locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), cram_md5_cfString);
if (locTag == kCFNotFound)
{
CFArrayAppendValue(myHashTypeArray, cram_md5_cfString);
needToChange = true;
}
}
if (userLevelHashList & ePluginHashRecoverable)
{
CFStringRef recoverable_cfString = CFSTR( kHashNameRecoverable );
CFIndex locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), recoverable_cfString);
if (locTag == kCFNotFound)
{
CFArrayAppendValue(myHashTypeArray, recoverable_cfString);
needToChange = true;
}
}
if (userLevelHashList & ePluginHashSecurityTeamFavorite)
{
CFStringRef team_fav_cfString = CFSTR( kHashNameSecure );
CFIndex locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), team_fav_cfString);
if (locTag == kCFNotFound)
{
CFArrayAppendValue(myHashTypeArray, team_fav_cfString);
needToChange = true;
}
}
CFStringRef salted_sha1_cfString = CFSTR( kHashNameSHA1 );
CFIndex locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), salted_sha1_cfString);
if (locTag == kCFNotFound)
{
CFArrayAppendValue(myHashTypeArray, salted_sha1_cfString);
needToChange = true;
}
if ( inParams.uiAuthMethod == kAuthSetShadowHashWindows )
{
CFStringRef smb_nt_cfString = CFSTR( kHashNameNT );
locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), smb_nt_cfString);
if (locTag == kCFNotFound)
{
CFArrayAppendValue(myHashTypeArray, smb_nt_cfString);
needToChange = true;
}
CFStringRef smb_lm_cfString = CFSTR( kHashNameLM );
locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), smb_lm_cfString);
if (locTag != kCFNotFound)
{
CFArrayRemoveValueAtIndex(myHashTypeArray, locTag);
needToChange = true;
}
}
else
if ( inParams.uiAuthMethod == kAuthSetShadowHashSecure )
{
CFStringRef smb_nt_cfString = CFSTR( kHashNameNT );
locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), smb_nt_cfString);
if (locTag != kCFNotFound)
{
CFArrayRemoveValueAtIndex(myHashTypeArray, locTag);
needToChange = true;
}
CFStringRef smb_lm_cfString = CFSTR( kHashNameLM );
locTag = CFArrayGetFirstIndexOfValue(myHashTypeArray,
CFRangeMake(0,CFArrayGetCount(myHashTypeArray)), smb_lm_cfString);
if (locTag != kCFNotFound)
{
CFArrayRemoveValueAtIndex(myHashTypeArray, locTag);
needToChange = true;
}
}
if ( needToChange )
{
long convertResult = 0;
char *newAuthAuthority = pwsf_ShadowHashArrayToData( myHashTypeArray, &convertResult );
if ( newAuthAuthority != NULL )
{
char * fullAuthAuthority = (char *) calloc(1,
1 + strlen(kDSValueAuthAuthorityShadowHash) + strlen(newAuthAuthority));
strcpy(fullAuthAuthority, kDSValueAuthAuthorityShadowHash);
strcat(fullAuthAuthority, newAuthAuthority);
if ( inOKToChangeAuthAuthorities ) {
siResult = ::SetUserAuthAuthorityAsRoot( inMutableRecordDict, inPlugin,
inNode, CFSTR( kDSStdRecordTypeUsers ), inParams.pUserName, fullAuthAuthority,
inNodeRef, false );
}
if ( siResult == eDSNoErr )
{
siResult = CDSLocalAuthHelper::GetHashSecurityLevelForUser( newAuthAuthority, &userLevelHashList );
if ( siResult != eDSNoErr )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoShadowHashAuth(): got invalid rec hash list: %s",
fullAuthAuthority );
userLevelHashList = inHashList;
siResult = eDSNoErr;
}
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pOldPassword,
strlen(inParams.pOldPassword),
userLevelHashList,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
siResult = CDSLocalAuthHelper::WriteShadowHash( inParams.pUserName, inGUIDString, inParams.generatedHashes );
}
DSFreeString( newAuthAuthority );
DSFreeString( fullAuthAuthority );
}
}
}
else
{
if ( inAuthOnly == false )
{
siResult = inPlugin->AuthOpen( inNodeRef, inParams.pUserName, inParams.pOldPassword,
inPlugin->UserIsAdmin( inMutableRecordDict, inNode ) );
}
}
}
else
{
siResult = eDSAuthFailed;
}
break;
}
case kAuthSetPasswd:
{
if ( inParams.pAdminUser == NULL && inEffectiveUID != 0 ) {
siResult = eDSPermissionError;
goto finish;
}
if ( strcmp(inParams.pUserName, "root") == 0 && strcmp(inParams.pAdminUser, "root") != 0 ) {
siResult = eDSPermissionError;
goto finish;
}
bool authenticatorIsAdmin = false;
if ( inParams.pAdminUser != NULL )
{
UInt32 pwdLen = 0;
adminString = CFStringCreateWithCString( kCFAllocatorDefault, inParams.pAdminUser, kCFStringEncodingUTF8 );
if ( adminString == NULL ) {
siResult = eMemoryError;
goto finish;
}
if ( inParams.pAdminPassword != NULL )
{
pwdLen = strlen( inParams.pAdminPassword );
}
else
{
siResult = eDSAuthFailed;
goto finish;
}
if ( pwdLen >= kHashRecoverableLength ) {
siResult = eDSAuthPasswordTooLong;
goto finish;
}
bool haveCStr = false;
char guidCStr[128];
CFStringRef guidString = inPlugin->GetUserGUID( adminString, inNode );
if ( guidString != NULL ) {
haveCStr = CFStringGetCString( guidString, guidCStr, sizeof(guidCStr), kCFStringEncodingUTF8 );
CFRelease( guidString );
}
char *adminPath = NULL;
char *adminStateFilePath = NULL;
struct timespec adminModDateOfPassword;
sHashState adminState;
unsigned char adminHashes[kHashTotalLength];
siResult = CDSLocalAuthHelper::ReadShadowHashAndStateFiles(
inParams.pAdminUser,
haveCStr ? guidCStr : NULL,
adminHashes,
&adminModDateOfPassword,
&adminPath,
&adminStateFilePath,
&adminState,
&inParams.hashesLengthFromFile );
DSFreeString( adminPath );
DSFreeString( adminStateFilePath );
if ( inParams.hashesLengthFromFile == (kHashShadowBothLength + kHashSecureLength) )
{
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pAdminPassword,
pwdLen,
ePluginHashSHA1 | ePluginHashNT | ePluginHashLM,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
}
else
{
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pAdminPassword,
pwdLen,
userLevelHashList,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
}
if ( !HashesEqual( adminHashes, inParams.generatedHashes ) ) {
siResult = eDSAuthFailed;
goto finish;
}
authenticatorIsAdmin = inPlugin->UserIsAdmin( adminString, inNode );
}
if ( !authenticatorIsAdmin )
{
siResult = GetUserPolicies( inMutableRecordDict, NULL, inPlugin, &inParams.policyStr );
if ( siResult != eDSNoErr )
goto finish;
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess, &inParams.globalMoreAccess );
bool authFailed = false;
if ( adminString == NULL || inParams.pUserName == NULL )
{
authFailed = true;
}
else
{
CFStringRef userNameCFStr = CFStringCreateWithCString( NULL, inParams.pUserName, kCFStringEncodingUTF8 );
if ( CFStringCompare( userNameCFStr, adminString, 0 ) != kCFCompareEqualTo )
authFailed = true;
CFRelease( userNameCFStr );
}
if ( authFailed )
{
siResult = eDSPermissionError;
}
else
{
siResult = CDSLocalAuthHelper::PasswordOkForPolicies( inParams.policyStr, &inParams.globalAccess,
inParams.pUserName, inParams.pNewPassword );
if ( siResult == eDSAuthPasswordTooShort &&
inParams.globalAccess.minChars == 0 &&
inParams.pNewPassword != NULL &&
*inParams.pNewPassword == '\0' &&
((inParams.policyStr == NULL) || strstr(inParams.policyStr, "minChars=0") != NULL) )
{
siResult = eDSNoErr;
}
}
}
if ( siResult == eDSNoErr )
{
AddKerberosAuthAuthority(
inNodeRef, inParams.pUserName, kDSTagAuthAuthorityKerberosv5, inAuthAuthorityList, inMutableRecordDict,
inPlugin, inNode, inNativeRecType, inOKToChangeAuthAuthorities );
bzero( inParams.generatedHashes, kHashTotalLength );
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS, inParams.pNewPassword, strlen(inParams.pNewPassword),
userLevelHashList, NULL, inParams.generatedHashes, &inParams.hashLength );
siResult = CDSLocalAuthHelper::WriteShadowHash( inParams.pUserName, inGUIDString, inParams.generatedHashes );
if ( siResult == eDSNoErr )
{
inParams.state.newPasswordRequired = 0;
time( &now );
gmtime_r( &now, &inParams.state.modDateOfPassword );
gettimeofday( &inParams.modDateAssist, NULL );
TIMEVAL_TO_TIMESPEC( &inParams.modDateAssist, &inParams.modDateOfPassword );
siResult = CDSLocalAuthHelper::DoKerberosAuth( inNodeRef, inParams, inOutContinueDataDict, inAuthData,
outAuthData, inAuthOnly, isSecondary, inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin,
inMutableRecordDict, inHashList, inPlugin, inNode, inAuthedUserName, inUID, inEffectiveUID,
inNativeRecType );
}
}
}
break;
case kAuthSetPasswdAsRoot:
{
bool modifyingSelf = false;
if ( inAuthedUserName != NULL && inParams.pUserName != NULL )
{
CFStringRef userNameCFStr = CFStringCreateWithCString( NULL, inParams.pUserName, kCFStringEncodingUTF8 );
modifyingSelf = (CFStringCompare(userNameCFStr, inAuthedUserName, 0) == kCFCompareEqualTo);
CFRelease( userNameCFStr );
}
bool notAdmin = ( inAuthedUserName == NULL || !inAuthedUserIsAdmin );
if ( inEffectiveUID != 0 )
{
if ( (inAuthedUserName == NULL) || (notAdmin && (!modifyingSelf)) ) {
siResult = eDSPermissionError;
goto finish;
}
}
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess,
&inParams.globalMoreAccess );
siResult = eDSNoErr;
if ( modifyingSelf && notAdmin )
{
siResult = CDSLocalAuthHelper::PasswordOkForPolicies( inParams.policyStr, &inParams.globalAccess,
inParams.pUserName, inParams.pNewPassword );
if ( siResult == eDSAuthPasswordTooShort &&
inParams.globalAccess.minChars == 0 &&
inParams.pNewPassword != NULL &&
*inParams.pNewPassword == '\0' &&
((inParams.policyStr == NULL) || strstr(inParams.policyStr, "minChars=0") != NULL) )
{
siResult = eDSNoErr;
}
}
if ( siResult == eDSNoErr )
{
AddKerberosAuthAuthority(
inNodeRef, inParams.pUserName, kDSTagAuthAuthorityKerberosv5, inAuthAuthorityList, inMutableRecordDict,
inPlugin, inNode, inNativeRecType, inOKToChangeAuthAuthorities );
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS, inParams.pNewPassword, strlen(inParams.pNewPassword),
userLevelHashList, NULL, inParams.generatedHashes, &inParams.hashLength );
siResult = CDSLocalAuthHelper::WriteShadowHash(inParams.pUserName, inGUIDString, inParams.generatedHashes);
if ( siResult == eDSNoErr )
{
inParams.state.newPasswordRequired = 0;
time( &now );
gmtime_r( &now, &inParams.state.modDateOfPassword );
gettimeofday( &inParams.modDateAssist, NULL );
TIMEVAL_TO_TIMESPEC( &inParams.modDateAssist, &inParams.modDateOfPassword );
siResult = CDSLocalAuthHelper::DoKerberosAuth( inNodeRef, inParams, inOutContinueDataDict, inAuthData,
outAuthData, inAuthOnly, isSecondary, inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin,
inMutableRecordDict, inHashList, inPlugin, inNode, inAuthedUserName, inUID, inEffectiveUID,
inNativeRecType );
}
}
}
break;
case kAuthChangePasswd:
siResult = GetUserPolicies( inMutableRecordDict, NULL, inPlugin, &inParams.policyStr );
if ( siResult != eDSNoErr )
goto finish;
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS,
inParams.pOldPassword,
strlen(inParams.pOldPassword),
userLevelHashList,
inParams.hashes + kHashOffsetToSaltedSHA1,
inParams.generatedHashes,
&inParams.hashLength );
if ( HashesEqual( inParams.hashes, inParams.generatedHashes ) || isSecondary )
{
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess,
&inParams.globalMoreAccess );
if ( !bufferUserIsAdmin )
{
siResult = CDSLocalAuthHelper::PasswordOkForPolicies( inParams.policyStr, &inParams.globalAccess,
inParams.pUserName, inParams.pNewPassword );
if ( siResult == eDSAuthPasswordTooShort &&
inParams.globalAccess.minChars == 0 &&
inParams.pNewPassword != NULL &&
*inParams.pNewPassword == '\0' &&
((inParams.policyStr == NULL) || strstr(inParams.policyStr, "minChars=0") != NULL) )
{
siResult = eDSNoErr;
}
}
if ( siResult == eDSNoErr )
{
bzero(inParams.generatedHashes, kHashTotalLength);
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS, inParams.pNewPassword, strlen(inParams.pNewPassword),
userLevelHashList, NULL, inParams.generatedHashes, &inParams.hashLength );
siResult = CDSLocalAuthHelper::WriteShadowHash(inParams.pUserName, inGUIDString, inParams.generatedHashes);
inParams.state.newPasswordRequired = 0;
time( &now );
gmtime_r( &now, &inParams.state.modDateOfPassword );
gettimeofday( &inParams.modDateAssist, NULL );
TIMEVAL_TO_TIMESPEC( &inParams.modDateAssist, &inParams.modDateOfPassword );
}
}
else
{
siResult = eDSAuthFailed;
}
break;
case kAuthSetLMHash:
if ( inEffectiveUID != 0 && !inAuthedUserIsAdmin ) {
siResult = eDSPermissionError;
goto finish;
}
memcpy( inParams.hashes + kHashOffsetToLM, inParams.pNTLMDigest, kHashShadowOneLength );
siResult = WriteShadowHash( inParams.pUserName, inGUIDString, inParams.hashes );
break;
case kAuthNTSetNTHash:
case kAuthNTSetWorkstationPasswd:
case kAuthSMB_NTUserSessionKey:
if ( inEffectiveUID != 0 && !inAuthedUserIsAdmin ) {
siResult = eDSPermissionError;
goto finish;
}
memcpy( inParams.hashes + kHashOffsetToNT, inParams.pNTLMDigest, kHashShadowOneLength );
siResult = WriteShadowHash( inParams.pUserName, inGUIDString, inParams.hashes );
break;
case kAuthMSLMCHAP2ChangePasswd:
bool notAdmin = ( (inParams.pUserName != NULL) && !inAuthedUserIsAdmin );
siResult = GetUserPolicies( inMutableRecordDict, NULL, inPlugin, &inParams.policyStr );
if ( siResult != eDSNoErr )
goto finish;
siResult = MSCHAPv2ChangePass( inParams.pUserName, inParams.hashes + kHashOffsetToLM, inParams.pOldPassword,
inParams.pNTLMDigest, inParams.ntlmDigestLen, (uint8_t **)&inParams.pNewPassword, &len );
if ( siResult != eDSNoErr )
goto finish;
if ( notAdmin )
{
siResult = CDSLocalAuthHelper::PasswordOkForPolicies( inParams.policyStr, &inParams.globalAccess, inParams.pUserName,
inParams.pNewPassword );
if ( siResult == eDSAuthPasswordTooShort &&
inParams.globalAccess.minChars == 0 &&
inParams.pNewPassword != NULL &&
*inParams.pNewPassword == '\0' &&
((inParams.policyStr == NULL) || strstr(inParams.policyStr, "minChars=0") != NULL) )
{
siResult = eDSNoErr;
}
if ( siResult != eDSNoErr )
goto finish;
}
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS, inParams.pNewPassword, len, userLevelHashList, NULL,
inParams.generatedHashes, &inParams.hashLength );
siResult = CDSLocalAuthHelper::WriteShadowHash(inParams.pUserName, inGUIDString, inParams.generatedHashes);
if ( siResult != eDSNoErr )
goto finish;
time( &now );
gmtime_r( &now, &inParams.state.modDateOfPassword );
gettimeofday( &inParams.modDateAssist, NULL );
TIMEVAL_TO_TIMESPEC( &inParams.modDateAssist, &inParams.modDateOfPassword );
break;
case kAuthSetCertificateHashAsRoot:
AddKerberosAuthAuthority(
inNodeRef, inParams.pUserName, kDSTagAuthAuthorityKerberosv5Cert, inAuthAuthorityList, inMutableRecordDict,
inPlugin, inNode, inNativeRecType, inOKToChangeAuthAuthorities );
siResult = CDSLocalAuthHelper::DoKerberosCertAuth(
inNodeRef, inParams, inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly,
isSecondary, inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin,
inMutableRecordDict, inHashList, inPlugin, inNode, inAuthedUserName, inUID,
inEffectiveUID, inNativeRecType );
break;
default:
siResult = eDSAuthMethodNotSupported;
break;
}
if ( !bufferUserIsAdmin )
{
if ( siResult == eDSNoErr &&
inParams.uiAuthMethod != kAuthGetPolicy && inParams.uiAuthMethod != kAuthGetGlobalPolicy &&
inParams.uiAuthMethod != kAuthSetPolicy && inParams.uiAuthMethod != kAuthSetGlobalPolicy )
{
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess, &inParams.globalMoreAccess );
siResult = CDSLocalAuthHelper::TestPolicies( inParams.policyStr, &inParams.globalAccess, &inParams.state,
&inParams.modDateOfPassword, inParams.path );
if ( siResult == eDSNoErr )
{
inParams.state.failedLoginAttempts = 0;
}
else
if ( inParams.state.disabled == 1 )
{
siResult = eDSAuthAccountDisabled;
if ( inOKToChangeAuthAuthorities )
CDSLocalAuthHelper::SetUserAAtoDisabled( inMutableRecordDict, inPlugin, inNode, inNativeRecType,
inParams.pUserName, inNodeRef, CFSTR("root"), inEffectiveUID );
}
}
else
if ( siResult == eDSAuthFailed )
{
inParams.state.failedLoginAttempts++;
CDSLocalAuthHelper::GetShadowHashGlobalPolicies( inPlugin, inNode, &inParams.globalAccess, &inParams.globalMoreAccess );
CDSLocalAuthHelper::TestPolicies( inParams.policyStr, &inParams.globalAccess, &inParams.state,
&inParams.modDateOfPassword, inParams.path );
if ( inParams.state.disabled == 1 )
{
siResult = eDSAuthAccountDisabled;
if ( inOKToChangeAuthAuthorities )
CDSLocalAuthHelper::SetUserAAtoDisabled( inMutableRecordDict, inPlugin, inNode, inNativeRecType,
inParams.pUserName, inNodeRef, CFSTR("root"), inEffectiveUID );
}
}
}
if ( siResult == eDSNoErr || siResult == eDSAuthNewPasswordRequired )
{
time( &now );
gmtime_r( &now, &(inParams.state.lastLoginDate) );
}
switch( inParams.uiAuthMethod )
{
case kAuthNativeClearTextOK:
case kAuthNativeNoClearText:
case kAuthNativeRetainCredential:
if ( (inParams.pOldPassword == nil) || ( (inParams.pOldPassword != nil) && (DSIsStringEmpty(inParams.pOldPassword) == true) ) )
bCheckDelay = false;
case kAuthSetPasswd:
case kAuthSetPasswdAsRoot:
case kAuthSMB_NT_Key:
case kAuthSMB_LM_Key:
case kAuthSecureHash:
case kAuthChangePasswd:
if ( bCheckDelay && (siResult == eDSAuthFailed) && ( inPlugin->DelayFailedLocalAuthReturnsDeltaInSeconds() != 0) )
{
gHashAuthFailedLocalMapLock->WaitLock();
string aUserName(inParams.pUserName);
HashAuthFailedMapI aHashAuthFailedMapI = gHashAuthFailedLocalMap.find(aUserName);
if (aHashAuthFailedMapI == gHashAuthFailedLocalMap.end())
{
pHashAuthFailed = (sHashAuthFailed *)calloc(1, sizeof(sHashAuthFailed));
pHashAuthFailed->nowTime = dsTimestamp();
pHashAuthFailed->lastTime = pHashAuthFailed->nowTime;
pHashAuthFailed->failCount = 1;
gHashAuthFailedLocalMap[aUserName] = pHashAuthFailed;
gHashAuthFailedLocalMapLock->SignalLock();
}
else
{
pHashAuthFailed = aHashAuthFailedMapI->second;
pHashAuthFailed->lastTime = pHashAuthFailed->nowTime;
pHashAuthFailed->nowTime = dsTimestamp();
pHashAuthFailed->failCount++;
if ( pHashAuthFailed->failCount > 5 )
{
if (pHashAuthFailed->failCount == 6)
{
syslog(LOG_ALERT, "Failed Authentication return is being delayed due to over five\
recent auth failures for username: %s.", inParams.pUserName);
}
if ( (pHashAuthFailed->nowTime - pHashAuthFailed->lastTime) > 120 * USEC_PER_SEC )
{
gHashAuthFailedLocalMap.erase(aUserName);
free(pHashAuthFailed);
pHashAuthFailed = NULL;
gHashAuthFailedLocalMapLock->SignalLock();
}
else
{
struct mach_timebase_info timeBaseInfo;
mach_timebase_info( &timeBaseInfo );
uint64_t delay = MAX(inPlugin->DelayFailedLocalAuthReturnsDeltaInSeconds(), 2) *
(((uint64_t)NSEC_PER_SEC * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer);
gHashAuthFailedLocalMapLock->SignalLock(); mach_wait_until( mach_absolute_time() + delay );
}
}
else
{
gHashAuthFailedLocalMapLock->SignalLock();
}
}
}
break;
default:
break;
}
finish:
DSCFRelease( myHashTypeArray );
DSCFRelease( adminString );
if ( inParams.stateFilePath != NULL && inParams.PolicyStateChanged() )
CDSLocalAuthHelper::WriteHashStateFile( inParams.stateFilePath, &inParams.state );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::DoBasicAuth( tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary,
CAuthAuthority &inAuthAuthorityList, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSNoErr;
UInt32 uiAuthMethod = inParams.uiAuthMethod;
try
{
if (inParams.mAuthMethodStr != NULL)
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoBasicAuth(): Attempting use of authentication method %s",
inParams.mAuthMethodStr );
}
switch( uiAuthMethod )
{
case kAuthNativeMethod:
case kAuthNativeNoClearText:
case kAuthNativeClearTextOK:
case kAuthNativeRetainCredential:
if ( outAuthData == NULL ) throw( eDSNullAuthStepData );
siResult = CDSLocalAuthHelper::DoUnixCryptAuth( inNodeRef, inParams,
inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary, NULL,
inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType );
if ( siResult == eDSNoErr )
{
if ( outAuthData->fBufferSize > sizeof(kDSStdAuthCrypt) - 1 )
{
::strcpy( outAuthData->fBufferData, kDSStdAuthCrypt );
}
}
else if ( (siResult != eDSAuthFailed) && (siResult != eDSInvalidBuffFormat) )
{
siResult = CDSLocalAuthHelper::DoNodeNativeAuth( inNodeRef, inParams,
inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary, NULL,
inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType );
if ( siResult == eDSNoErr )
{
if ( outAuthData->fBufferSize > sizeof(kDSStdAuth2WayRandom) - 1 )
{
::strcpy( outAuthData->fBufferData, kDSStdAuth2WayRandom );
}
}
}
break;
case kAuthClearText:
case kAuthCrypt:
siResult = CDSLocalAuthHelper::DoUnixCryptAuth( inNodeRef, inParams,
inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary, NULL,
inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType );
break;
case kAuthSetPasswd:
siResult = CDSLocalAuthHelper::DoSetPassword( inNodeRef, inParams,
inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary, inAuthAuthorityList, NULL,
inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType );
break;
case kAuthSetPasswdAsRoot:
siResult = CDSLocalAuthHelper::DoSetPasswordAsRoot( inNodeRef, inParams,
inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary, inAuthAuthorityList, NULL,
inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType );
break;
case kAuthChangePasswd:
siResult = CDSLocalAuthHelper::DoChangePassword( inNodeRef, inParams,
inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary, NULL,
inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType );
break;
default:
siResult = eDSAuthMethodNotSupported;
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoBasicAuth(): got error %d", err );
siResult = err;
}
return( siResult );
}
tDirStatus CDSLocalAuthHelper::DoPasswordServerAuth( tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary,
CAuthAuthority &inAuthAuthorityList, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType )
{
tDirStatus result = eDSAuthFailed;
tDirStatus error;
UInt32 authMethod;
char *serverAddr = NULL;
char *uidStr = NULL;
long uidStrLen;
tDataBufferPtr authDataBuff = NULL;
tDataBufferPtr authDataBuffTemp = NULL;
char *userName = NULL;
char *password = NULL;
CFMutableDictionaryRef continueDataDict = NULL;
tContextData passPluginContinueData = NULL;
char* cStr = NULL;
size_t cStrSize = 0;
char *aaData = NULL;
CFMutableDictionaryRef nodeDict = NULL;
try
{
aaData = inAuthAuthorityList.GetDataForTag( kDSTagAuthAuthorityPasswordServer, 0 );
if ( aaData == NULL || *aaData == '\0' )
throw( eDSAuthParameterError );
serverAddr = strchr( aaData, ':' );
if ( serverAddr )
{
uidStrLen = serverAddr - aaData;
uidStr = dsCStrFromCharacters( aaData, uidStrLen );
if ( uidStr == NULL ) throw( eMemoryError );
serverAddr++;
if (inParams.mAuthMethodStr != NULL)
{
DbgLog( kLogPlugin, "DSLocalAuthHelper::DoPasswordSerberAuth(): Attempting use of authentication method %s",
inParams.mAuthMethodStr );
}
authMethod = inParams.uiAuthMethod;
switch( authMethod )
{
case kAuth2WayRandom:
if ( inOutContinueDataDict == NULL )
throw( eDSNullParameter );
if ( *inOutContinueDataDict == NULL )
{
continueDataDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
if ( continueDataDict == NULL )
throw( eMemoryError );
inPlugin->AddContinueData( inNodeRef, continueDataDict, (void **)inOutContinueDataDict );
CFRelease( continueDataDict );
authDataBuff = ::dsDataBufferAllocatePriv( uidStrLen + 1 );
if ( authDataBuff == NULL ) throw ( eMemoryError );
strcpy( authDataBuff->fBufferData, uidStr );
authDataBuff->fBufferLength = uidStrLen;
}
else
{
continueDataDict = *inOutContinueDataDict;
authDataBuff = inAuthData;
}
break;
case kAuthSetPasswd:
case kAuthSetPolicy:
{
char* aaVersion = NULL;
char* aaTag = NULL;
char* aa2Data = NULL;
char* endPtr = NULL;
error = (tDirStatus)GetUserNameFromAuthBuffer( inAuthData, 3, &userName );
if ( error != eDSNoErr ) throw( error );
CFArrayRef authAuthorities = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrAuthenticationAuthority ) ) );
CFIndex numAuthAuthorities = 0;
if ( authAuthorities != NULL )
numAuthAuthorities = CFArrayGetCount( authAuthorities );
tDirStatus lookupResult = eDSAuthFailed;
for( CFIndex authAuthorityIndex = 0;
authAuthorityIndex < numAuthAuthorities && lookupResult == eDSAuthFailed;
authAuthorityIndex++ )
{
CFStringRef authAuthority = (CFStringRef)CFArrayGetValueAtIndex( authAuthorities,
authAuthorityIndex );
const char* authAuthorityCStr = CStrFromCFString( authAuthority, &cStr,
&cStrSize );
error = dsParseAuthAuthority( authAuthorityCStr, &aaVersion, &aaTag, &aa2Data );
if (error != eDSNoErr)
lookupResult = eParameterError;
if ( error == eDSNoErr && strcmp(aaTag, kDSTagAuthAuthorityPasswordServer) == 0 )
{
endPtr = strchr( aa2Data, ':' );
if ( endPtr == NULL )
{
lookupResult = eParameterError;
}
else
{
*endPtr = '\0';
lookupResult = eDSNoErr;
}
}
if (aaVersion != NULL) {
free(aaVersion);
aaVersion = NULL;
}
if (aaTag != NULL) {
free(aaTag);
aaTag = NULL;
}
if (lookupResult != eDSNoErr && aa2Data != NULL) {
free(aa2Data);
aa2Data = NULL;
}
}
if ( lookupResult != eDSNoErr ) throw( eDSAuthFailed );
error = (tDirStatus)RepackBufferForPWServer(inAuthData, uidStr, 1, &authDataBuffTemp );
if ( error != eDSNoErr ) throw( error );
error = (tDirStatus)RepackBufferForPWServer(authDataBuffTemp, aa2Data, 3, &authDataBuff );
DSFreeString( aa2Data );
if ( error != eDSNoErr ) throw( error );
}
break;
case kAuthClearText:
case kAuthNativeClearTextOK:
case kAuthNativeNoClearText:
case kAuthCrypt:
case kAuthNativeRetainCredential:
{
tDataListPtr dataList = dsAuthBufferGetDataListAllocPriv(inAuthData);
if (dataList != NULL)
{
userName = dsDataListGetNodeStringPriv(dataList, 1);
password = dsDataListGetNodeStringPriv(dataList, 2);
dsDataListDeallocatePriv(dataList);
free(dataList);
dataList = NULL;
}
}
default:
error = (tDirStatus)RepackBufferForPWServer(inAuthData, uidStr, 1, &authDataBuff );
if ( error != eDSNoErr ) throw( error );
}
nodeDict = inPlugin->CopyNodeDictForNodeRef( inNodeRef );
if ( nodeDict == NULL )
throw( eDSInvalidNodeRef );
tDirReference pwsDirRef = 0;
tDirNodeReference pwsNodeRef = 0;
result = OpenPasswordServerNode( inPlugin, nodeDict, serverAddr, &pwsDirRef, &pwsNodeRef );
if ( result != eDSNoErr )
throw( result );
if ( continueDataDict != NULL )
passPluginContinueData = (CFMutableDictionaryRef)CFDictionaryGetValue( continueDataDict,
CFSTR( kAuthCOntinueDataPassPluginContData ) );
tDataNodePtr authMethodNodePtr = dsDataNodeAllocateString( 0, inParams.mAuthMethodStr );
result = dsDoDirNodeAuth( pwsNodeRef, authMethodNodePtr, inAuthOnly, authDataBuff, outAuthData,
&passPluginContinueData );
if ( result == eDSAuthNoAuthServerFound || result == eDSAuthServerError )
{
result = CDSLocalAuthHelper::PWSetReplicaData( inPlugin, inNode, inNodeRef, pwsNodeRef, uidStr );
if ( result == eDSNoErr )
{
result = dsDoDirNodeAuth( pwsNodeRef, authMethodNodePtr, inAuthOnly, authDataBuff, outAuthData,
&passPluginContinueData );
}
}
dsDataBufferDeAllocate( 0, authMethodNodePtr );
authMethodNodePtr = NULL;
if ( continueDataDict != NULL )
{
if ( passPluginContinueData == NULL )
CFDictionaryRemoveValue( continueDataDict, CFSTR( kAuthCOntinueDataPassPluginContData ) );
else
{
CFDictionaryAddValue( continueDataDict, CFSTR( kAuthCOntinueDataPassPluginContData ),
passPluginContinueData );
if ( inOutContinueDataDict == NULL )
throw( eDSNullParameter );
*inOutContinueDataDict = NULL;
}
}
if ( (result == eDSNoErr) && (inAuthOnly == false) && (userName != NULL) && (password != NULL) )
{
result = inPlugin->AuthOpen( inNodeRef, userName, password, inAuthedUserIsAdmin );
}
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoPasswordServerAuth(): got error %d", err );
result = err;
}
DSCFRelease( nodeDict );
DSFreeString( aaData );
DSFree( cStr );
DSFree( uidStr );
DSFree( userName );
DSFreePassword( password );
if ( authDataBuff )
dsDataBufferDeallocatePriv( authDataBuff );
if ( authDataBuffTemp )
dsDataBufferDeallocatePriv( authDataBuffTemp );
return( result );
}
tDirStatus CDSLocalAuthHelper::DoDisabledAuth( tDirNodeReference inNodeRef,
CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
CAuthAuthority &inAuthAuthorityList,
const char* inGUIDString,
bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType )
{
tDirStatus retResult = eDSAuthAccountDisabled;
tDirStatus siResult = eDSAuthFailed;
UInt32 uiAuthMethod = 0;
bool bNetworkNodeReachable = false;
tDirReference aDSRef = 0;
tDataListPtr aNetworkNode = nil;
char *pUserName = NULL;
tDataListPtr dataList = NULL;
char *localCachedUser = NULL;
char *origAuthAuthorityTag = NULL;
try
{
origAuthAuthorityTag = inAuthAuthorityList.GetDataForTag( kDSTagAuthAuthorityDisabledUser, 1 );
if ( origAuthAuthorityTag == NULL || *origAuthAuthorityTag == '\0' )
throw( eDSAuthParameterError );
inParams.aaDataLocalCacheUser = inAuthAuthorityList.GetDataForTag( kDSTagAuthAuthorityDisabledUser, 2 );
uiAuthMethod = inParams.uiAuthMethod;
if ( strcasecmp(origAuthAuthorityTag, kDSTagAuthAuthorityLocalCachedUser) == 0 )
{
siResult = CDSLocalAuthHelper::LocalCachedUserReachable(
inNodeRef,
inOutContinueDataDict,
inAuthData,
outAuthData,
inAuthOnly,
isSecondary,
inGUIDString,
inAuthedUserIsAdmin,
inParams,
inMutableRecordDict,
inHashList,
inPlugin,
inNode,
inAuthedUserName,
inUID,
inEffectiveUID,
inNativeRecType,
&bNetworkNodeReachable,
&aDSRef,
&aNetworkNode,
&localCachedUser);
if ( siResult != eDSNoErr ) {
retResult = siResult;
throw( siResult );
}
if ( bNetworkNodeReachable )
{
inAuthAuthorityList.ToggleDisabledAuthority( true );
siResult = CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2(
inNodeRef,
inParams,
inOutContinueDataDict,
inAuthData,
outAuthData,
inAuthOnly,
isSecondary,
inAuthAuthorityList,
inGUIDString,
inAuthedUserIsAdmin,
inMutableRecordDict,
inHashList,
inPlugin,
inNode,
inAuthedUserName,
inUID,
inEffectiveUID,
inNativeRecType,
&bNetworkNodeReachable,
&aDSRef,
&aNetworkNode,
localCachedUser,
kDoNotTouchTheAuthAuthorities );
if ( bNetworkNodeReachable && siResult == eDSNoErr )
{
switch( uiAuthMethod )
{
case kAuthNativeClearTextOK:
case kAuthNativeNoClearText:
case kAuthNativeMethod:
case kAuthNativeRetainCredential:
retResult = eDSNoErr;
dataList = dsAuthBufferGetDataListAllocPriv( inAuthData );
if ( dataList == NULL )
throw( eDSInvalidBuffFormat );
if ( dsDataListGetNodeCountPriv(dataList) < 1 )
throw( eDSInvalidBuffFormat );
pUserName = dsDataListGetNodeStringPriv(dataList, 1);
if ( pUserName == NULL || DSIsStringEmpty(pUserName) )
throw( eDSInvalidBuffFormat );
siResult = CDSLocalAuthHelper::SetUserAuthAuthorityAsRoot(
inMutableRecordDict,
inPlugin,
inNode,
CFSTR( kDSStdRecordTypeUsers ),
pUserName,
inAuthAuthorityList,
inNodeRef );
break;
default:
break;
}
}
throw( retResult );
}
else
{
throw( eDSAuthAccountDisabled );
}
}
switch ( uiAuthMethod )
{
case kAuthGetPolicy:
case kAuthGetEffectivePolicy:
case kAuthSetPolicyAsRoot:
case kAuthSetPasswdAsRoot:
inAuthAuthorityList.ToggleDisabledAuthority( true );
siResult = CDSLocalAuthHelper::DoShadowHashAuth(
inNodeRef,
inParams,
inOutContinueDataDict,
inAuthData,
outAuthData,
inAuthOnly,
isSecondary,
inAuthAuthorityList,
inGUIDString,
inAuthedUserIsAdmin,
inMutableRecordDict,
inHashList,
inPlugin,
inNode,
inAuthedUserName,
inUID,
inEffectiveUID,
inNativeRecType );
inAuthAuthorityList.ToggleDisabledAuthority( false );
break;
default:
siResult = eDSAuthFailed;
}
}
catch( tDirStatus status )
{
siResult = status;
}
if ( aNetworkNode != NULL )
{
dsDataListDeallocate( aDSRef, aNetworkNode );
free( aNetworkNode );
aNetworkNode = NULL;
}
if ( dataList != NULL )
{
dsDataListDeallocatePriv( dataList );
free( dataList );
dataList = NULL;
}
DSFreeString(localCachedUser);
DSFreeString( pUserName );
DSFreeString( origAuthAuthorityTag );
return retResult;
}
tDirStatus CDSLocalAuthHelper::DoLocalCachedUserAuth( tDirNodeReference inNodeRef,
CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
CAuthAuthority &inAuthAuthorityList,
const char* inGUIDString,
bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
bool bNetworkNodeReachable = false;
tDirReference aDSRef = 0;
tDataListPtr aNetworkNode = nil;
char *localCachedUser = NULL;
try
{
if ( inParams.mAuthMethodStr != NULL )
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuth: Attempting use of authentication method %s",
inParams.mAuthMethodStr );
siResult = inParams.LoadDSLocalParamsForAuthMethod( inParams.uiAuthMethod, ePluginHashAll, inGUIDString, inAuthedUserIsAdmin,
inAuthData, outAuthData );
if ( siResult != eDSNoErr ) {
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuth: LoadDSLocalParamsForAuthMethod = %d", siResult );
throw( siResult );
}
inParams.aaDataLocalCacheUser = inAuthAuthorityList.GetDataForTag( kDSTagAuthAuthorityLocalCachedUser, 0 );
if ( inParams.aaDataLocalCacheUser == NULL ) {
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuth: GetDataForTag = NULL" );
throw( eDSAuthParameterError );
}
if ( inParams.uiAuthMethod == kAuthNativeClearTextOK || inParams.uiAuthMethod == kAuthNativeNoClearText )
MigrateAddKerberos( inNodeRef, inParams, inOutContinueDataDict, inAuthData, outAuthData, inAuthOnly, isSecondary,
inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin, inMutableRecordDict, inHashList, inPlugin, inNode,
inAuthedUserName, inUID, inEffectiveUID, inNativeRecType, true );
siResult = CDSLocalAuthHelper::LocalCachedUserReachable(
inNodeRef,
inOutContinueDataDict,
inAuthData,
outAuthData,
inAuthOnly,
isSecondary,
inGUIDString,
inAuthedUserIsAdmin,
inParams,
inMutableRecordDict,
inHashList,
inPlugin,
inNode,
inAuthedUserName,
inUID,
inEffectiveUID,
inNativeRecType,
&bNetworkNodeReachable,
&aDSRef,
&aNetworkNode,
&localCachedUser);
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuth:LocalCachedUserReachable result = %d, valid-node-on-search-path = %d",
siResult, bNetworkNodeReachable );
if ( siResult == eDSNoErr )
{
siResult = CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2(
inNodeRef,
inParams,
inOutContinueDataDict,
inAuthData,
outAuthData,
inAuthOnly,
isSecondary,
inAuthAuthorityList,
inGUIDString,
inAuthedUserIsAdmin,
inMutableRecordDict,
inHashList,
inPlugin,
inNode,
inAuthedUserName,
inUID,
inEffectiveUID,
inNativeRecType,
&bNetworkNodeReachable,
&aDSRef,
&aNetworkNode,
localCachedUser );
}
}
catch( tDirStatus status )
{
siResult = status;
}
if ( aNetworkNode != NULL )
{
dsDataListDeallocate( aDSRef, aNetworkNode );
free( aNetworkNode );
aNetworkNode = NULL;
}
DSFreeString( localCachedUser );
return( (tDirStatus)siResult );
}
tDirStatus CDSLocalAuthHelper::DoNodeNativeAuth( tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary,
const char* inAuthAuthorityData, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
return( siResult );
}
tDirStatus CDSLocalAuthHelper::DoUnixCryptAuth( tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary,
const char* inAuthAuthorityData, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
bool bResetCache = false;
const char *pwdAttrValueCStr = NULL;
char* cStr = NULL;
size_t cStrSize = 0;
char *name = NULL;
UInt32 nameLen = 0;
char *pwd = NULL;
UInt32 pwdLen = 0;
unsigned int itemCount = 0;
char salt[9];
char hashPwd[32];
try
{
if ( inAuthData == NULL )
throw( eDSNullAuthStepData );
siResult = (tDirStatus)Get2FromBuffer( inAuthData, NULL, &name, &pwd, &itemCount );
if ( siResult != eDSNoErr )
throw( siResult );
nameLen = strlen( name );
if ( itemCount != 2 || nameLen > 256 )
throw( eDSInvalidBuffFormat );
pwdLen = strlen( pwd );
if ( pwdLen >= kHashRecoverableLength )
throw ( eDSAuthPasswordTooLong );
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoUnixCryptAuth(): Attempting UNIX Crypt authentication" );
CFStringRef nameCFStr = CFStringCreateWithCString( NULL, name, kCFStringEncodingUTF8 );
CFArrayRef values = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrRecordName ) ) );
bool nameIsValid = CFArrayContainsValue( values, ::CFRangeMake( 0, CFArrayGetCount( values ) ), nameCFStr );
CFRelease( nameCFStr );
if ( !nameIsValid )
throw( eDSAuthUnknownUser );
values = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ) );
if ( values == NULL )
throw( eDSAuthBadPassword );
CFStringRef pwdAttrValue = NULL;
if ( CFArrayGetCount( values ) > 0 )
pwdAttrValue = (CFStringRef)CFArrayGetValueAtIndex( values, 0 );
else
pwdAttrValue = CFSTR( "" );
pwdAttrValueCStr = CStrFromCFString( pwdAttrValue, &cStr, &cStrSize, NULL );
if ( strcmp(pwdAttrValueCStr,"") != 0 )
{
salt[0] = pwdAttrValueCStr[0];
salt[1] = pwdAttrValueCStr[1];
salt[2] = '\0';
bzero( hashPwd, 32 );
strcpy( hashPwd, crypt(pwd, salt) );
siResult = (strcmp(hashPwd, pwdAttrValueCStr) == 0) ? eDSNoErr : eDSAuthFailed;
bzero( hashPwd, 32 );
}
else {
if ( DSIsStringEmpty(pwd) )
siResult = eDSNoErr;
}
if (siResult == eDSNoErr)
{
if ( inNode->IsLocalNode() && (pwdLen < 8) ) {
CDSLocalAuthHelper::MigrateToShadowHash( inNodeRef, inPlugin, inNode, inMutableRecordDict, name, pwd,
&bResetCache, inHashList, inNativeRecType );
}
if (inAuthOnly == false)
siResult = inPlugin->AuthOpen( inNodeRef, name, pwd, inAuthedUserIsAdmin );
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoUnixCryptAuth(): Crypt authentication error %d", err );
siResult = err;
}
DSFreeString( name );
DSFreePassword( pwd );
DSFreeString( cStr );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::DoSetPassword( tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary, CAuthAuthority &inAuthAuthorityList,
const char* inAuthAuthorityData, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
bool bResetCache = false;
char *userName = NULL;
char *userPwd = NULL;
char *rootName = NULL;
char *rootPwd = NULL;
CFMutableArrayRef recordsArray = NULL;
char* cStr = NULL;
size_t cStrSize = 0;
CFStringRef userNameCFStr = NULL;
tRecordReference recordRef = 0;
CFStringRef hashPwdCFStr = NULL;
tDataListPtr dataList = NULL;
unsigned int itemCount = 0;
try
{
if ( inAuthData == NULL )
throw( eDSNullAuthStepData );
siResult = (tDirStatus)Get2FromBuffer( inAuthData, &dataList, &userName, &userPwd, &itemCount );
if ( siResult != eDSNoErr )
throw( siResult );
if ( itemCount != 4 || userName == NULL || DSIsStringEmpty(userName) || userPwd == NULL )
throw( eDSInvalidBuffFormat );
rootName = dsDataListGetNodeStringPriv( dataList, 3 );
if ( rootName == NULL || DSIsStringEmpty(rootName) )
throw( eDSInvalidBuffFormat );
rootPwd = dsDataListGetNodeStringPriv( dataList, 4 );
if ( rootPwd == NULL )
throw( eDSInvalidBuffFormat );
char salt[3];
char hashPwd[ 32 ];
const char *pwdFromRecord = NULL;
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoSetPassword(): Attempting UNIX Crypt password change" );
recordsArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFStringRef rootNameCFStr = CFStringCreateWithCString( NULL, rootName, kCFStringEncodingUTF8 );
CFArrayRef patternsToMatch = CFArrayCreate( NULL, (const void**)&rootNameCFStr, 1, &kCFTypeArrayCallBacks );
CFRelease( rootNameCFStr );
siResult = inNode->GetRecords( inPlugin->RecordNativeTypeForStandardType( CFSTR( kDSStdRecordTypeUsers ) ),
patternsToMatch, CFSTR( kDSNAttrRecordName ), eDSExact, false, 1, recordsArray );
CFRelease( patternsToMatch );
if ( ( siResult != eDSNoErr ) || ( CFArrayGetCount( recordsArray ) == 0 ) )
#ifdef DEBUG
throw( eDSAuthUnknownUser );
#else
throw( eDSAuthFailed );
#endif
CFDictionaryRef rootDict = (CFDictionaryRef)CFArrayGetValueAtIndex( recordsArray, 0 );
CFArrayRef uidsArray = (CFArrayRef)CFDictionaryGetValue( rootDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrUniqueID ) ) );
if ( ( uidsArray == NULL ) || ( CFArrayGetCount( uidsArray ) == 0 ) )
throw( eDSAuthFailed );
siResult = eDSAuthFailed;
if ( !inPlugin->UserIsAdmin( rootDict, inNode ) )
throw( eDSPermissionError );
CFArrayRef passwordsArray = (CFArrayRef)CFDictionaryGetValue( rootDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ) );
if ( ( passwordsArray == NULL ) || ( CFArrayGetCount( passwordsArray ) == 0 ) )
pwdFromRecord = (char*)""; else
{
CFStringRef pwdFromRecordCFStr = (CFStringRef)CFArrayGetValueAtIndex( passwordsArray, 0 );
pwdFromRecord = CStrFromCFString( pwdFromRecordCFStr, &cStr, &cStrSize );
}
if (::strcmp(pwdFromRecord,"") != 0)
{
salt[ 0 ] = pwdFromRecord[0];
salt[ 1 ] = pwdFromRecord[1];
salt[ 2 ] = '\0';
bzero(hashPwd, 32);
::strcpy( hashPwd, ::crypt( rootPwd, salt ) );
siResult = eDSAuthFailed;
if ( ::strcmp( hashPwd, pwdFromRecord ) == 0 )
{
siResult = eDSNoErr;
}
bzero(hashPwd, 32);
}
else {
if (::strcmp(rootPwd,"") != 0)
{
siResult = eDSNoErr;
}
}
if (siResult == eDSNoErr)
{
if ( inNode->IsLocalNode() ) {
if ( CDSLocalAuthHelper::MigrateToShadowHash( inNodeRef, inPlugin, inNode, inMutableRecordDict,
userName, userPwd, &bResetCache, inHashList, inNativeRecType ) == eDSNoErr )
{
AddKerberosAuthAuthority(
inNodeRef, inParams.pUserName, kDSTagAuthAuthorityKerberosv5, inAuthAuthorityList, inMutableRecordDict,
inPlugin, inNode, inNativeRecType, true );
siResult = CDSLocalAuthHelper::DoKerberosAuth( inNodeRef, inParams, inOutContinueDataDict, inAuthData,
outAuthData, inAuthOnly, isSecondary, inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin,
inMutableRecordDict, inHashList, inPlugin, inNode, inAuthedUserName, inUID, inEffectiveUID,
inNativeRecType );
}
}
else
{
const char *saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
bzero(hashPwd, 32);
if ( strlen(userPwd) > 0 )
{
::srandom(getpid() + time(0));
salt[0] = saltchars[random() % 64];
salt[1] = saltchars[random() % 64];
salt[2] = '\0';
::strcpy( hashPwd, ::crypt( userPwd, salt ) );
}
CFArrayRef shortNames = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrRecordName ) ) );
userNameCFStr = CFStringCreateWithCString( NULL, userName, kCFStringEncodingUTF8 );
if ( !CFArrayContainsValue( shortNames, ::CFRangeMake( 0, CFArrayGetCount( shortNames ) ),
userNameCFStr ) )
#ifdef DEBUG
throw( eDSAuthUnknownUser );
#else
throw( eDSAuthFailed );
#endif
siResult = inPlugin->OpenRecord( inNodeRef, inPlugin->RecordStandardTypeForNativeType( inNativeRecType ),
userNameCFStr, &recordRef );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->RemoveAttribute( recordRef, CFSTR( kDS1AttrPassword ) );
hashPwdCFStr = CFStringCreateWithCString( NULL, hashPwd, kCFStringEncodingUTF8 );
siResult = inPlugin->AddAttribute( recordRef, CFSTR( kDS1AttrPassword ), hashPwdCFStr );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); recordRef = 0;
CFDictionaryRemoveValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ) );
CFMutableArrayRef mutableValuesArray = CFArrayCreateMutable( kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks );
CFArrayAppendValue( mutableValuesArray, hashPwdCFStr );
CFDictionaryAddValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ), mutableValuesArray );
CFRelease( mutableValuesArray );
bzero(hashPwd, 32);
}
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoSetPassword(): got error %d", err );
siResult = err;
}
if ( dataList != NULL )
{
dsDataListDeallocatePriv(dataList);
free(dataList);
}
if ( recordsArray != NULL )
CFRelease( recordsArray );
if ( cStr != NULL )
::free( cStr );
DSCFRelease( userNameCFStr );
DSCFRelease( hashPwdCFStr );
if ( recordRef != 0 )
{
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); }
DSFreeString( userName );
DSFreePassword( userPwd );
DSFreeString( rootName );
DSFreePassword( rootPwd );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::DoSetPasswordAsRoot( tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary, CAuthAuthority &inAuthAuthorityList,
const char* inAuthAuthorityData, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
bool bResetCache = false;
char *userName = NULL;
char *newPasswd = NULL;
CFStringRef userNameCFStr = NULL;
tRecordReference recordRef = 0;
CFStringRef hashPwdCFStr = NULL;
tDataListPtr dataList = NULL;
unsigned int itemCount = 0;
try
{
if ( inAuthData == NULL )
throw( eDSNullAuthStepData );
siResult = (tDirStatus)Get2FromBuffer( inAuthData, &dataList, &userName, &newPasswd, &itemCount );
if ( siResult != eDSNoErr )
throw( siResult );
if ( itemCount != 2 || userName == NULL || DSIsStringEmpty(userName) || newPasswd == NULL )
throw( eDSInvalidBuffFormat );
userNameCFStr = CFStringCreateWithCString( kCFAllocatorDefault, userName, kCFStringEncodingUTF8 );
if ( inEffectiveUID != 0 )
{
if ( (inAuthedUserName == NULL) ||
((CFStringCompare( inAuthedUserName, CFSTR( "root" ), 0 ) != kCFCompareEqualTo )
&& (CFStringCompare( inAuthedUserName, userNameCFStr, 0 ) != kCFCompareEqualTo )))
{
throw( eDSPermissionError );
}
}
char salt[3];
char hashPwd[ 32 ];
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoSetPasswordAsRoot():Attempting password change" );
CFArrayRef shortNames = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrRecordName ) ) );
if ( !CFArrayContainsValue(shortNames, CFRangeMake(0, CFArrayGetCount(shortNames)), userNameCFStr) )
#ifdef DEBUG
throw( eDSAuthUnknownUser );
#else
throw( eDSAuthFailed );
#endif
siResult = eDSNoErr;
if (siResult == eDSNoErr)
{
if ( inNode->IsLocalNode() ) {
siResult = CDSLocalAuthHelper::MigrateToShadowHash( inNodeRef, inPlugin, inNode, inMutableRecordDict,
userName, newPasswd, &bResetCache, inHashList, inNativeRecType );
if ( siResult == eDSNoErr )
{
inAuthAuthorityList.SetValueForTag( kDSTagAuthAuthorityShadowHash, kDSValueAuthAuthorityShadowHash );
AddKerberosAuthAuthority(
inNodeRef, inParams.pUserName, kDSTagAuthAuthorityKerberosv5, inAuthAuthorityList, inMutableRecordDict,
inPlugin, inNode, inNativeRecType, true );
siResult = CDSLocalAuthHelper::DoKerberosAuth( inNodeRef, inParams, inOutContinueDataDict, inAuthData,
outAuthData, inAuthOnly, isSecondary, inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin,
inMutableRecordDict, inHashList, inPlugin, inNode, inAuthedUserName, inUID, inEffectiveUID,
inNativeRecType );
}
}
else
{
const char *saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
bzero(hashPwd, 32);
if ( strlen(newPasswd) > 0 )
{
::srandom(getpid() + time(0));
salt[0] = saltchars[random() % 64];
salt[1] = saltchars[random() % 64];
salt[2] = '\0';
::strcpy( hashPwd, ::crypt( newPasswd, salt ) );
}
siResult = inPlugin->OpenRecord( inNodeRef, inPlugin->RecordStandardTypeForNativeType( inNativeRecType ),
userNameCFStr, &recordRef );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->RemoveAttribute( recordRef, CFSTR( kDS1AttrPassword ) );
hashPwdCFStr = CFStringCreateWithCString( NULL, hashPwd, kCFStringEncodingUTF8 );
siResult = inPlugin->AddAttribute( recordRef, CFSTR( kDS1AttrPassword ), hashPwdCFStr );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); recordRef = 0;
CFDictionaryRemoveValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ) );
CFMutableArrayRef mutableValuesArray = CFArrayCreateMutable( kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks );
CFArrayAppendValue( mutableValuesArray, hashPwdCFStr );
CFDictionaryAddValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ), mutableValuesArray );
CFRelease( mutableValuesArray );
bzero(hashPwd, 32);
}
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoSetPasswordAsRoot(): got error %d", err );
siResult = err;
}
if ( dataList != NULL )
{
dsDataListDeallocatePriv(dataList);
free(dataList);
}
if ( userNameCFStr != NULL )
CFRelease( userNameCFStr );
if ( hashPwdCFStr != NULL )
CFRelease( hashPwdCFStr );
if ( recordRef != 0 )
{
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); }
DSFreeString( userName );
DSFreePassword( newPasswd );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::DoChangePassword( tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary,
const char* inAuthAuthorityData, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
bool bResetCache = false;
char *name = NULL;
char *oldPwd = NULL;
char *newPwd = NULL;
CFStringRef userNameCFStr = NULL;
tRecordReference recordRef = 0;
CFStringRef hashPwdCFStr = NULL;
char* cStr = NULL;
size_t cStrSize = 0;
tDataListPtr dataList = NULL;
unsigned int itemCount = 0;
try
{
if ( inAuthData == NULL )
throw( eDSNullAuthStepData );
siResult = (tDirStatus)Get2FromBuffer( inAuthData, &dataList, &name, &oldPwd, &itemCount );
if ( siResult != eDSNoErr )
throw( siResult );
if ( itemCount != 3 || name == NULL || DSIsStringEmpty(name) || oldPwd == NULL )
throw( eDSInvalidBuffFormat );
newPwd = dsDataListGetNodeStringPriv( dataList, 3 );
if ( newPwd == NULL )
throw( eDSInvalidBuffFormat );
char salt[3];
char hashPwd[ 32 ];
const char *pwdFromRecord = NULL;
userNameCFStr = CFStringCreateWithCString( NULL, name, kCFStringEncodingUTF8 );
CFArrayRef userNamesFromRecord = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrRecordName ) ) );
if ( !CFArrayContainsValue(userNamesFromRecord, CFRangeMake(0, CFArrayGetCount(userNamesFromRecord)),
userNameCFStr) )
#ifdef DEBUG
throw( eDSAuthUnknownUser );
#else
throw( eDSAuthFailed );
#endif
CFArrayRef passwordValues = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ) );
if ( ( passwordValues == NULL ) || ( CFArrayGetCount( passwordValues ) == 0 ) )
pwdFromRecord = (char*)""; else
{
CFStringRef passwordAttrValue = (CFStringRef)CFArrayGetValueAtIndex( passwordValues, 0 );
pwdFromRecord = CStrFromCFString( passwordAttrValue, &cStr, &cStrSize );
}
siResult = eDSNoErr;
if ( !isSecondary )
{
siResult = eDSAuthFailed;
if (::strcmp(pwdFromRecord,"") != 0)
{
salt[ 0 ] = pwdFromRecord[0];
salt[ 1 ] = pwdFromRecord[1];
salt[ 2 ] = '\0';
bzero(hashPwd, 32);
::strcpy( hashPwd, ::crypt( oldPwd, salt ) );
if ( ::strcmp( hashPwd, pwdFromRecord ) == 0 )
{
siResult = eDSNoErr;
}
bzero(hashPwd, 32);
}
else {
if (::strcmp(oldPwd,"") == 0)
{
siResult = eDSNoErr;
}
}
}
if (siResult == eDSNoErr)
{
if ( inNode->IsLocalNode() ) {
CDSLocalAuthHelper::MigrateToShadowHash( inNodeRef, inPlugin, inNode, inMutableRecordDict, name, newPwd,
&bResetCache, inHashList, inNativeRecType );
}
else
{
const char *saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
bzero(hashPwd, 32);
if ( strlen(newPwd) > 0 )
{
::srandom(getpid() + time(0));
salt[0] = saltchars[random() % 64];
salt[1] = saltchars[random() % 64];
salt[2] = '\0';
::strcpy( hashPwd, ::crypt( newPwd, salt ) );
}
siResult = inPlugin->OpenRecord( inNodeRef, inPlugin->RecordStandardTypeForNativeType( inNativeRecType ),
userNameCFStr, &recordRef );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->RemoveAttribute( recordRef, CFSTR( kDS1AttrPassword ) );
hashPwdCFStr = CFStringCreateWithCString( NULL, hashPwd, kCFStringEncodingUTF8 );
siResult = inPlugin->AddAttribute( recordRef, CFSTR( kDS1AttrPassword ), hashPwdCFStr );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); recordRef = 0;
CFDictionaryRemoveValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ) );
CFMutableArrayRef mutableValuesArray = CFArrayCreateMutable( kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks );
CFArrayAppendValue( mutableValuesArray, hashPwdCFStr );
CFDictionaryAddValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ), mutableValuesArray );
CFRelease( mutableValuesArray );
bzero(hashPwd, 32);
}
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoChangePassword(): got error %d", err );
siResult = err;
}
if ( dataList != NULL )
{
dsDataListDeallocatePriv(dataList);
free(dataList);
}
if ( userNameCFStr != NULL )
CFRelease( userNameCFStr );
if ( hashPwdCFStr != NULL )
CFRelease( hashPwdCFStr );
if ( recordRef != 0 )
{
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); }
if ( cStr != NULL )
::free( cStr );
if ( name != NULL )
{
free( name );
name = NULL;
}
if ( newPwd != NULL )
{
bzero(newPwd, strlen(newPwd));
free( newPwd );
newPwd = NULL;
}
if ( oldPwd != NULL )
{
bzero(oldPwd, strlen(oldPwd));
free( oldPwd );
oldPwd = NULL;
}
return( siResult );
}
tDataList* CDSLocalAuthHelper::FindNodeForSearchPolicyAuthUser ( const char *userName )
{
tDirStatus siResult = eDSNoErr;
tDirStatus returnVal = (tDirStatus)-3;
unsigned long nodeCount = 0;
unsigned long recCount = 0;
tContextData context = NULL;
tDataListPtr nodeName = NULL;
tDataListPtr recName = NULL;
tDataListPtr recType = NULL;
tDataListPtr attrTypes = NULL;
tDataBufferPtr dataBuff = NULL;
tRecordEntry *pRecEntry = NULL;
tAttributeListRef attrListRef = 0;
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = NULL;
tAttributeValueEntry *pValueEntry = NULL;
tDirReference aDSRef = 0;
tDirNodeReference aSearchNodeRef = 0;
try
{
siResult = dsOpenDirService( &aDSRef );
if ( siResult != eDSNoErr ) throw( siResult );
dataBuff = dsDataBufferAllocate( aDSRef, 2048 );
if ( dataBuff == NULL ) throw( eMemoryAllocError );
siResult = dsFindDirNodes( aDSRef, dataBuff, NULL,
eDSAuthenticationSearchNodeName, &nodeCount, &context );
if ( siResult != eDSNoErr ) throw( siResult );
siResult = dsGetDirNodeName( aDSRef, dataBuff, 1, &nodeName );
if ( siResult != eDSNoErr ) throw( siResult );
siResult = dsOpenDirNode( aDSRef, nodeName, &aSearchNodeRef );
if ( siResult != eDSNoErr ) throw( siResult );
if ( nodeName != NULL )
{
dsDataListDeallocate( aDSRef, nodeName );
free( nodeName );
nodeName = NULL;
}
recName = dsBuildListFromStrings( aDSRef, userName, NULL );
recType = dsBuildListFromStrings( aDSRef, kDSStdRecordTypeUsers, NULL );
attrTypes = dsBuildListFromStrings( aDSRef, kDSNAttrMetaNodeLocation, NULL );
recCount = 1; do
{
siResult = dsGetRecordList( aSearchNodeRef, dataBuff, recName, eDSExact, recType,
attrTypes, false, &recCount, &context);
if (siResult == eDSBufferTooSmall)
{
UInt32 bufSize = dataBuff->fBufferSize;
dsDataBufferDeallocatePriv( dataBuff );
dataBuff = NULL;
dataBuff = ::dsDataBufferAllocate( aDSRef, bufSize * 2 );
}
} while ( (siResult == eDSBufferTooSmall) || ( (siResult == eDSNoErr) && (recCount == 0) && (context != NULL) ) );
if ( (siResult == eDSNoErr) && (recCount > 0) )
{
siResult = ::dsGetRecordEntry( aSearchNodeRef, dataBuff, 1, &attrListRef, &pRecEntry );
if ( (siResult == eDSNoErr) && (pRecEntry != NULL) )
{
for (unsigned int i = 1; i <= pRecEntry->fRecordAttributeCount; i++)
{
siResult = ::dsGetAttributeEntry( aSearchNodeRef, dataBuff, attrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( aSearchNodeRef, dataBuff, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
nodeName = dsBuildFromPath( aDSRef, pValueEntry->fAttributeValueData.fBufferData, "/" );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( aDSRef, pValueEntry );
pValueEntry = NULL;
}
}
dsCloseAttributeValueList(valueRef);
if (pAttrEntry != NULL)
{
dsDeallocAttributeEntry(aDSRef, pAttrEntry);
pAttrEntry = NULL;
}
} } dsCloseAttributeList(attrListRef);
if (pRecEntry != NULL)
{
dsDeallocRecordEntry(aDSRef, pRecEntry);
pRecEntry = NULL;
}
} }
catch( tDirStatus err )
{
returnVal = err;
}
if ( recName != NULL )
{
dsDataListDeallocate( aDSRef, recName );
free( recName );
recName = NULL;
}
if ( recType != NULL )
{
dsDataListDeallocate( aDSRef, recType );
free( recType );
recType = NULL;
}
if ( attrTypes != NULL )
{
dsDataListDeallocate( aDSRef, attrTypes );
free( attrTypes );
attrTypes = NULL;
}
if ( dataBuff != NULL )
{
dsDataBufferDeAllocate( aDSRef, dataBuff );
dataBuff = NULL;
}
if ( aSearchNodeRef != 0 )
{
dsCloseDirNode( aSearchNodeRef );
aSearchNodeRef = 0;
}
if ( aDSRef != 0 )
{
dsCloseDirService( aDSRef );
aDSRef = 0;
}
return nodeName;
}
bool CDSLocalAuthHelper::IsWriteAuthRequest ( UInt32 uiAuthMethod )
{
switch ( uiAuthMethod )
{
case kAuthSetPasswd:
case kAuthSetPasswdAsRoot:
case kAuthChangePasswd:
case kAuthSetGlobalPolicy:
case kAuthSetPolicy:
case kAuthSetCertificateHashAsRoot:
return true;
default:
return false;
}
}
AuthAuthorityHandlerProc CDSLocalAuthHelper::GetAuthAuthorityHandler ( const char* inTag )
{
if (inTag == NULL)
return NULL;
for (unsigned int i = 0; sAuthAuthorityHandlerProcs[i].fTag != NULL; ++i)
{
if (strcasecmp( inTag, sAuthAuthorityHandlerProcs[i].fTag) == 0)
{
return sAuthAuthorityHandlerProcs[i].fHandler;
}
}
return NULL;
}
#pragma mark -- Private methods ---
tDirStatus CDSLocalAuthHelper::SetUserPolicies( CFMutableDictionaryRef inMutableRecordDict, CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode, CFStringRef inAuthedUserName, uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType,
const char *inUsername, const char *inPolicyStr, bool inAuthedUserIsAdmin, tDirNodeReference inNodeRef,
sHashState *inOutHashState )
{
tDirStatus siResult = eDSAuthFailed;
char* currentPolicyStr = NULL;
char* newPassRequiredStr = NULL;
PWAccessFeatures access = {0};
PWMoreAccessFeatures moreAccess = {0};
CFStringRef recordName = NULL;
CFStringRef xmlDataCFStr = NULL;
tRecordReference recordRef = 0;
char *xmlDataStr = NULL;
try
{
if ( inPolicyStr == NULL || inUsername == NULL )
throw( eDSAuthFailed );
if ( (inEffectiveUID != 0) && !inAuthedUserIsAdmin )
throw( eDSPermissionError );
if ( inOutHashState != NULL && (newPassRequiredStr = strstr(inPolicyStr, kPWPolicyStr_newPasswordRequired)) != NULL )
{
newPassRequiredStr += sizeof(kPWPolicyStr_newPasswordRequired) - 1;
if ( (*newPassRequiredStr == '=') &&
(*(newPassRequiredStr + 1) == '0' || *(newPassRequiredStr + 1) == '1') )
{
inOutHashState->newPasswordRequired = *(newPassRequiredStr + 1) - '0';
}
}
GetUserPolicies( inMutableRecordDict, NULL, inPlugin, ¤tPolicyStr );
CFStringRef stdRecType = inPlugin->RecordStandardTypeForNativeType( inNativeRecType );
recordName = CFStringCreateWithCString( NULL, inUsername, kCFStringEncodingUTF8 );
if ( (inEffectiveUID != 0) || ((inAuthedUserName != NULL) && CFStringCompare(inAuthedUserName, CFSTR("root"), 0) != kCFCompareEqualTo) )
{
bool accessAllowed = inNode->WriteAccessAllowed( inAuthedUserName, inEffectiveUID, stdRecType, recordName,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPasswordPolicyOptions ) ) );
if ( !accessAllowed )
throw( eDSPermissionError );
}
{
char policyStr[2048];
::GetDefaultUserPolicies( &access );
if ( currentPolicyStr != NULL )
::StringToPWAccessFeaturesExtra( currentPolicyStr, &access, &moreAccess );
::StringToPWAccessFeaturesExtra( inPolicyStr, &access, &moreAccess );
::PWAccessFeaturesToStringWithoutStateInfoExtra( &access, &moreAccess, sizeof(policyStr), policyStr );
::pwsf_PreserveUnrepresentedPolicies( inPolicyStr, sizeof(policyStr), policyStr );
if ( ::ConvertSpaceDelimitedPolicyToXML( policyStr, &xmlDataStr ) == 0 )
{
siResult = inPlugin->OpenRecord( inNodeRef, stdRecType, recordName, &recordRef );
if ( siResult != eDSNoErr )
throw( siResult );
siResult = inPlugin->RemoveAttribute( recordRef, CFSTR( kDS1AttrPasswordPolicyOptions ) );
xmlDataCFStr = CFStringCreateWithCString( NULL, xmlDataStr, kCFStringEncodingUTF8 );
siResult = inPlugin->AddAttribute( recordRef, CFSTR( kDS1AttrPasswordPolicyOptions ), xmlDataCFStr );
if ( siResult != eDSNoErr )
throw( siResult );
CAuthAuthority aaTank;
LoadAuthAuthorities( inPlugin, recordRef, aaTank );
char *princStr = aaTank.GetDataForTag( kDSTagAuthAuthorityKerberosv5, 1 );
if ( princStr != NULL )
{
char *realmStr = princStr;
strsep( &realmStr, "@" );
if ( realmStr != NULL )
{
char *buff = NULL;
int buffLen = 0;
pwsf_ModifyPrincipalInLocalRealm( princStr, realmStr, &access, access.maxMinutesUntilChangePassword,
&buff, &buffLen );
}
free( princStr );
}
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); recordRef = 0;
CFStringRef nativeAttrType =
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPasswordPolicyOptions ) );
CFDictionaryRemoveValue( inMutableRecordDict, nativeAttrType );
CFArrayRef values = CFArrayCreate( NULL, (const void**)&xmlDataCFStr, 1, &kCFTypeArrayCallBacks );
CFDictionaryAddValue( inMutableRecordDict, nativeAttrType, values );
CFRelease( values );
}
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::SetUserPolicies(): got error %d", err );
siResult = err;
}
DSFreeString( xmlDataStr );
if ( recordRef != 0 )
{
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); }
if ( recordName != NULL )
CFRelease( recordName );
if ( xmlDataCFStr != NULL )
CFRelease( xmlDataCFStr );
if ( currentPolicyStr != NULL )
::free( currentPolicyStr );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::SetUserAAtoDisabled( CFMutableDictionaryRef inMutableRecordDict,
CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode, CFStringRef inStdRecType, const char *inUsername,
tDirNodeReference inNodeRef, CFStringRef inAuthedUserName, uid_t inEffectiveUID )
{
tDirStatus siResult = eDSAuthFailed;
CFStringRef authAuthority = NULL;
tRecordReference recordRef = 0;
CFStringRef recordName = NULL;
CAuthAuthority aaTank;
try
{
CFArrayRef values = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrAuthenticationAuthority ) ) );
if ( ( values != NULL ) && ( CFArrayGetCount( values ) > 0 ) )
authAuthority = (CFStringRef)CFArrayGetValueAtIndex( values, 0 );
if ( authAuthority != NULL && ( CFStringGetLength( authAuthority ) > 0 ) )
authAuthority = CFStringCreateWithFormat( NULL, 0, CFSTR( kDSValueAuthAuthorityDisabledUser"%@" ),
authAuthority );
else
authAuthority = CFSTR( kDSValueAuthAuthorityDisabledUser kDSValueAuthAuthorityShadowHash );
recordName = CFStringCreateWithCString( NULL, inUsername, kCFStringEncodingUTF8 );
siResult = inPlugin->OpenRecord( inNodeRef, inStdRecType, recordName, &recordRef );
if ( siResult != eDSNoErr )
throw( siResult );
LoadAuthAuthorities( inPlugin, recordRef, aaTank );
if ( aaTank.GetValueForTagAsCFDict(kDSTagAuthAuthorityLocalCachedUser) != NULL )
{
aaTank.RemoveValueForTag( kDSTagAuthAuthorityShadowHash );
aaTank.RemoveValueForTag( kDSTagAuthAuthorityDisabledUser );
aaTank.SetValueDisabledForTag( kDSTagAuthAuthorityLocalCachedUser );
}
else
{
aaTank.SetValueDisabledForTag( kDSTagAuthAuthorityShadowHash );
}
siResult = SaveAuthAuthoritiesWithRecordRef( inPlugin, inNodeRef, recordRef, aaTank );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); recordRef = 0;
}
catch( tDirStatus err )
{
if ( err != eDSNoErr )
DbgLog( kLogPlugin, "DSLocalAuthHelper::SetUserAAToDisabled(): got error %d", err );
siResult = err;
}
if ( recordRef != 0 )
{
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); }
if ( authAuthority != NULL )
CFRelease( authAuthority );
if ( recordName != NULL )
CFRelease( recordName );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::SetUserAuthAuthorityAsRoot( CFMutableDictionaryRef inMutableRecordDict,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inStdRecType,
const char *inUsername,
CAuthAuthority &inAuthAuthorityList,
tDirNodeReference inNodeRef )
{
tDirStatus siResult = eDSAuthFailed;
tRecordReference recordRef = 0;
CFStringRef authAuthorityCFStr = NULL;
UInt32 avIndex = 0;
UInt32 avCount = 0;
char *aaStr = NULL;
CFMutableArrayRef aaValueArray = NULL;
try
{
CFStringRef recordName = CFStringCreateWithCString( kCFAllocatorDefault, inUsername, kCFStringEncodingUTF8 );
siResult = inPlugin->OpenRecord( inNodeRef, inStdRecType, recordName, &recordRef );
CFRelease( recordName );
if ( siResult != eDSNoErr )
throw( siResult );
siResult = SaveAuthAuthoritiesWithRecordRef( inPlugin, inNodeRef, recordRef, inAuthAuthorityList );
if ( siResult != eDSNoErr )
throw( siResult );
aaValueArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( aaValueArray == NULL )
throw( eMemoryError );
avCount = inAuthAuthorityList.GetValueCount();
for ( avIndex = 0; avIndex < avCount; avIndex++ )
{
aaStr = inAuthAuthorityList.GetValueAtIndex( avIndex );
if ( aaStr != NULL )
{
authAuthorityCFStr = CFStringCreateWithCString( kCFAllocatorDefault, aaStr, kCFStringEncodingUTF8 );
if ( authAuthorityCFStr == NULL )
throw( eMemoryError );
CFArrayAppendValue( aaValueArray, authAuthorityCFStr );
if ( authAuthorityCFStr != NULL ) {
CFRelease( authAuthorityCFStr );
authAuthorityCFStr = NULL;
}
DSFreeString( aaStr );
}
}
CFStringRef nativeAttrType = inPlugin->AttrNativeTypeForStandardType( CFSTR(kDSNAttrAuthenticationAuthority) );
if ( nativeAttrType != NULL )
CFDictionarySetValue( inMutableRecordDict, nativeAttrType, aaValueArray );
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::SetUserAuthAuthorityAsRoot(): got error %d", err );
siResult = err;
}
if ( recordRef != 0 )
{
sFlushRecord params = { kFlushRecord, 0, recordRef };
inPlugin->FlushRecord( ¶ms );
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); }
if ( authAuthorityCFStr != NULL )
CFRelease( authAuthorityCFStr );
if ( aaValueArray != NULL )
CFRelease( aaValueArray );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::GetHashSecurityLevelForUser( const char *inHashList, unsigned int *outHashList )
{
char *hashListStr = NULL;
char *hashListPtr = NULL;
char *hashTypeStr = NULL;
char *endPtr = NULL;
if ( inHashList == NULL || outHashList == NULL )
return eParameterError;
if ( strcasecmp( inHashList, kDSTagAuthAuthorityBetterHashOnly ) == 0 )
{
*outHashList |= ePluginHashNT;
*outHashList &= (0x7FFF ^ ePluginHashLM);
return eDSNoErr;
}
else
if ( strncasecmp( inHashList, kHashNameListPrefix, sizeof(kHashNameListPrefix)-1 ) == 0 )
{
hashListPtr = hashListStr = strdup( inHashList );
hashListPtr += sizeof(kHashNameListPrefix) - 1;
if ( *hashListPtr++ != '<' )
return eParameterError;
endPtr = strchr( hashListPtr, '>' );
if ( endPtr == NULL )
return eParameterError;
*endPtr = '\0';
*outHashList = 0;
while ( (hashTypeStr = strsep( &hashListPtr, "," )) != NULL )
{
if ( CDSLocalAuthHelper::GetHashSecurityBitsForString( hashTypeStr, outHashList ) )
break;
}
if ( hashListStr != NULL )
free( hashListStr );
}
else
{
return eParameterError;
}
return eDSNoErr;
}
bool CDSLocalAuthHelper::GetHashSecurityBitsForString( const char *inHashType, unsigned int *inOutHashList )
{
bool returnVal = false;
if ( strcasecmp( inHashType, kHashNameNT ) == 0 )
*inOutHashList |= ePluginHashNT;
else if ( strcasecmp( inHashType, kHashNameLM ) == 0 )
*inOutHashList |= ePluginHashLM;
else if ( strcasecmp( inHashType, kHashNameCRAM_MD5 ) == 0 )
*inOutHashList |= ePluginHashCRAM_MD5;
else if ( strcasecmp( inHashType, kHashNameSHA1 ) == 0 )
*inOutHashList |= ePluginHashSaltedSHA1;
else if ( strcasecmp( inHashType, kHashNameRecoverable ) == 0 )
*inOutHashList |= ePluginHashRecoverable;
else if ( strcasecmp( inHashType, kHashNameSecure ) == 0 )
{
*inOutHashList = ePluginHashSecurityTeamFavorite;
returnVal = true;
}
return returnVal;
}
tDirStatus CDSLocalAuthHelper::WriteShadowHash ( const char *inUserName, const char *inGUIDString,
unsigned char inHashes[kHashTotalLength] )
{
tDirStatus result = eDSAuthFailed;
char *path = NULL;
char hexHashes[kHashTotalHexLength] = { 0 };
tDirStatus siResult = eDSNoErr;
struct stat statResult;
CFile *hashFile = NULL;
try
{
CDSLocalAuthHelper::RemoveShadowHash( inUserName, NULL, false );
if (inGUIDString != NULL)
{
path = (char*)::calloc(1, strlen(kShadowHashDirPath) + strlen(inGUIDString) + 1);
}
else
{
path = (char*)::calloc(strlen(kShadowHashDirPath) + strlen(inUserName) + 1, 1);
}
if ( path != NULL )
{
if (inGUIDString != NULL)
{
sprintf(path, "%s%s", kShadowHashDirPath, inGUIDString);
}
else
{
sprintf(path, "%s%s", kShadowHashDirPath, inUserName);
}
siResult = (tDirStatus)stat( "/var/db/shadow/hash", &statResult );
if (siResult != eDSNoErr)
{
siResult = (tDirStatus)::stat( "/var/db/shadow", &statResult );
if (siResult != eDSNoErr)
{
::mkdir( "/var/db/shadow", 0700 );
::chmod( "/var/db/shadow", 0700 );
}
siResult = (tDirStatus)::stat( "/var/db/shadow/hash", &statResult );
if (siResult != eDSNoErr)
{
::mkdir( "/var/db/shadow/hash", 0700 );
::chmod( "/var/db/shadow/hash", 0700 );
}
}
hashFile = new CFile(path, true);
if (hashFile->is_open())
{
BinaryToHexConversion( inHashes, kHashTotalLength, hexHashes );
hashFile->seekp( 0 ); hashFile->write( hexHashes, kHashTotalHexLength );
chmod( path, 0600 ); delete(hashFile);
hashFile = NULL;
result = eDSNoErr;
}
}
}
catch( ... )
{
result = eDSAuthFailed;
}
if ( path != NULL ) {
free( path );
path = NULL;
}
if (hashFile != NULL)
{
delete(hashFile);
hashFile = NULL;
}
bzero(hexHashes, kHashTotalHexLength);
return( result );
}
void CDSLocalAuthHelper::RemoveShadowHash ( const char *inUserName, const char *inGUIDString, bool bShadowToo )
{
char *path = NULL;
char hexHashes[kHashTotalHexLength] = { 0 };
bool bRemovePath = false;
CFile *hashFile = NULL;
try
{
if (bShadowToo) {
if (inGUIDString != NULL)
{
path = (char*)::calloc(1, strlen(kShadowHashDirPath) + strlen(inGUIDString) + 1);
}
else
{
path = (char*)::calloc(strlen(kShadowHashDirPath) + strlen(inUserName) + 1, 1);
}
if ( path != NULL )
{
if (inGUIDString != NULL)
{
sprintf(path, "%s%s", kShadowHashDirPath, inGUIDString);
}
else
{
sprintf(path, "%s%s", kShadowHashDirPath, inUserName);
}
try
{
hashFile = new CFile(path, false);
if (hashFile->is_open())
{
hashFile->seekp( 0 ); hashFile->write( hexHashes, kHashTotalHexLength );
delete(hashFile);
hashFile = NULL;
bRemovePath = true;
}
if (bRemovePath)
{
unlink(path);
}
}
catch( ... )
{
}
free( path );
path = NULL;
}
}
if (hashFile != NULL)
{
delete(hashFile);
hashFile = NULL;
}
bRemovePath = false;
if (inUserName != NULL)
{
path = (char*)::calloc(sizeof(kShadowHashOldDirPath) + strlen(inUserName) + 1, 1);
}
if ( path != NULL )
{
sprintf(path, "%s%s", kShadowHashOldDirPath, inUserName);
hashFile = new CFile(path, false);
if (hashFile->is_open())
{
hashFile->seekp( 0 ); hashFile->write( hexHashes, kHashShadowBothHexLength );
delete(hashFile);
hashFile = NULL;
bRemovePath = true;
}
if (bRemovePath)
{
unlink(path);
}
free( path );
path = NULL;
}
}
catch( ... )
{
}
if ( path != NULL ) {
free( path );
path = NULL;
}
if (hashFile != NULL)
{
delete(hashFile);
hashFile = NULL;
}
bzero(hexHashes, kHashTotalHexLength);
return;
}
bool CDSLocalAuthHelper::HashesEqual( const unsigned char *inUserHashes, const unsigned char *inGeneratedHashes )
{
static int sPriorityMap[ ][ 2 ] =
{
{ kHashOffsetToSaltedSHA1, kHashSaltedSHA1Length }, { kHashOffsetToSHA1, kHashSecureLength }, { kHashOffsetToNT, kHashShadowOneLength }, { kHashOffsetToLM, 16 }, { kHashOffsetToCramMD5, kHashCramLength }, { kHashOffsetToRecoverable, kHashRecoverableLength }, { 0, 0 } };
int start, len;
bool result = false;
for ( int idx = 0; ; idx++ )
{
start = sPriorityMap[idx][0];
len = sPriorityMap[idx][1];
if ( start == 0 && len == 0 )
break;
if ( memcmp( inUserHashes + start, sZeros, len ) != 0 )
{
if ( memcmp( inUserHashes + start, inGeneratedHashes + start, len ) == 0 )
result = true;
break;
}
}
return result;
}
int CDSLocalAuthHelper::WriteHashStateFile( const char *inFilePath, sHashState *inHashState )
{
CFStringRef myReplicaDataFilePathRef;
CFURLRef myReplicaDataFileRef;
CFWriteStreamRef myWriteStreamRef;
CFStringRef errorString;
int err = 0;
CFMutableDictionaryRef prefsDict;
CFDateRef aDateRef;
if ( inFilePath == NULL || inHashState == NULL )
return -1;
prefsDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
if ( prefsDict == NULL )
return -1;
do
{
if ( pwsf_ConvertBSDTimeToCFDate( &inHashState->creationDate, &aDateRef ) )
{
CFDictionaryAddValue( prefsDict, CFSTR("CreationDate"), aDateRef );
CFRelease( aDateRef );
}
if ( pwsf_ConvertBSDTimeToCFDate( &inHashState->lastLoginDate, &aDateRef ) )
{
CFDictionaryAddValue( prefsDict, CFSTR("LastLoginDate"), aDateRef );
CFRelease( aDateRef );
}
CFNumberRef failedAttemptCountRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt16Type,
&(inHashState->failedLoginAttempts) );
if ( failedAttemptCountRef != NULL )
{
CFDictionaryAddValue( prefsDict, CFSTR("FailedLoginCount"), failedAttemptCountRef );
CFRelease( failedAttemptCountRef );
}
CFNumberRef newPasswordRequiredRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt16Type,
&(inHashState->newPasswordRequired) );
if ( newPasswordRequiredRef != NULL )
{
CFDictionaryAddValue( prefsDict, CFSTR("NewPasswordRequired"), newPasswordRequiredRef );
CFRelease( newPasswordRequiredRef );
}
myReplicaDataFilePathRef = CFStringCreateWithCString( kCFAllocatorDefault, inFilePath, kCFStringEncodingUTF8 );
if ( myReplicaDataFilePathRef == NULL )
{
err = -1;
break;
}
myReplicaDataFileRef = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, myReplicaDataFilePathRef,
kCFURLPOSIXPathStyle, false );
CFRelease( myReplicaDataFilePathRef );
if ( myReplicaDataFileRef == NULL )
{
err = -1;
break;
}
myWriteStreamRef = CFWriteStreamCreateWithFile( kCFAllocatorDefault, myReplicaDataFileRef );
CFRelease( myReplicaDataFileRef );
if ( myWriteStreamRef == NULL )
{
err = -1;
break;
}
CFWriteStreamOpen( myWriteStreamRef );
chmod( inFilePath, 0600 );
errorString = NULL;
CFPropertyListWriteToStream( prefsDict, myWriteStreamRef, kCFPropertyListBinaryFormat_v1_0, NULL );
CFWriteStreamClose( myWriteStreamRef );
CFRelease( myWriteStreamRef );
} while( false );
if ( prefsDict != NULL )
CFRelease( prefsDict );
return err;
}
tDirStatus CDSLocalAuthHelper::ReadShadowHashAndStateFiles( const char *inUserName, const char *inGUIDString,
unsigned char outHashes[kHashTotalLength], struct timespec *outModTime, char **outUserHashPath, char **outStateFilePath,
sHashState *inOutHashState, SInt32 *outHashDataLen )
{
if ( outStateFilePath == NULL || outUserHashPath == NULL )
return eParameterError;
*outStateFilePath = NULL;
tDirStatus siResult = ReadShadowHash( inUserName, inGUIDString, outHashes, outModTime,
outUserHashPath, outHashDataLen, true );
if ( siResult == eDSNoErr )
siResult = GetStateFilePath( *outUserHashPath, outStateFilePath );
if ( siResult == eDSNoErr && inOutHashState != NULL )
{
siResult = (tDirStatus)ReadHashStateFile( *outStateFilePath, inOutHashState );
if (siResult != eDSNoErr)
{
siResult = eDSNoErr;
}
}
return siResult;
}
tDirStatus CDSLocalAuthHelper::GetShadowHashGlobalPolicies( CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode,
PWGlobalAccessFeatures *inOutGAccess, PWGlobalMoreAccessFeatures *inOutGMoreAccess )
{
tDirStatus error = eDSNoErr;
char* policyStr = NULL;
CFMutableArrayRef recordsArray = NULL;
char* cStr = NULL;
size_t cStrSize = 0;
if ( inOutGAccess == NULL )
return eParameterError;
bzero( inOutGAccess, sizeof(PWGlobalAccessFeatures) );
CFStringRef nativeRecType = inPlugin->RecordNativeTypeForStandardType( CFSTR( kDSStdRecordTypeConfig ) );
try
{
recordsArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFStringRef recName = CFSTR( kShadowHashRecordName );
CFArrayRef recNames = CFArrayCreate( NULL, (const void**)&recName, 1, &kCFTypeArrayCallBacks );
error = inNode->GetRecords( nativeRecType, recNames, CFSTR( kDSNAttrRecordName ), eDSExact, false, 1,
recordsArray );
CFRelease( recNames );
if ( error != eDSNoErr )
throw( error );
CFStringRef pwdPolicyOptions = NULL;
if ( CFArrayGetCount( recordsArray ) > 0 )
{
CFDictionaryRef shadowHashRecord = (CFDictionaryRef)CFArrayGetValueAtIndex( recordsArray, 0 );
CFArrayRef pwdPolicyOptionsVals = (CFArrayRef)CFDictionaryGetValue( shadowHashRecord,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPasswordPolicyOptions ) ) );
if ( ( pwdPolicyOptionsVals != NULL ) && ( CFArrayGetCount( pwdPolicyOptionsVals ) > 0 ) )
pwdPolicyOptions = (CFStringRef)CFArrayGetValueAtIndex( pwdPolicyOptionsVals, 0 );
}
if ( ( pwdPolicyOptions != NULL ) && ( CFStringGetLength( pwdPolicyOptions ) > 0 ) )
{
if ( ::ConvertGlobalXMLPolicyToSpaceDelimited(
CStrFromCFString( pwdPolicyOptions, &cStr, &cStrSize, NULL ), &policyStr ) == 0 )
::StringToPWGlobalAccessFeaturesExtra( policyStr, inOutGAccess, inOutGMoreAccess );
}
}
catch( tDirStatus catchErr )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::GetShadowHashGlobalPolicies(): got error %d", catchErr );
error = catchErr;
}
if ( recordsArray != NULL )
CFRelease( recordsArray );
if ( policyStr != NULL )
::free( policyStr );
if ( cStr != NULL )
::free( cStr );
return error;
}
tDirStatus CDSLocalAuthHelper::SetShadowHashGlobalPolicies( CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode,
tDirNodeReference inNodeRef, CFStringRef inAuthedUserName, uid_t inUID, uid_t inEffectiveUID,
PWGlobalAccessFeatures *inGAccess, PWGlobalMoreAccessFeatures *inGMoreAccess )
{
tDirStatus siResult = eDSAuthFailed;
CFMutableArrayRef recordsArray = NULL;
CFStringRef recName = NULL;
CFArrayRef recNames = NULL;
tRecordReference shadowHashRecRef = 0;
try
{
if ( inGAccess == NULL )
throw( eDSAuthFailed );
if ( inAuthedUserName == NULL )
throw( eDSPermissionError );
{ recordsArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
recNames = CFArrayCreate( NULL, (const void**)&inAuthedUserName, 1, &kCFTypeArrayCallBacks );
siResult = inNode->GetRecords( inPlugin->RecordNativeTypeForStandardType( CFSTR( kDSStdRecordTypeUsers ) ),
recNames, CFSTR( kDSNAttrRecordName ), eDSExact, false, 1, recordsArray );
CFRelease( recNames );
recNames = NULL;
if ( siResult != eDSNoErr )
throw( siResult );
if ( CFArrayGetCount( recordsArray ) == 0 )
throw( eDSPermissionError );
CFDictionaryRef authenticatedUserRec = (CFDictionaryRef)CFArrayGetValueAtIndex( recordsArray, 0 );
if ( authenticatedUserRec == NULL )
throw( eDSPermissionError );
if ( !inPlugin->UserIsAdmin( authenticatedUserRec, inNode ) )
throw( eDSPermissionError );
CFRelease( recordsArray );
recordsArray = NULL;
}
if ( recordsArray != NULL )
CFRelease( recordsArray );
recordsArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
recName = CFSTR( kShadowHashRecordName );
recNames = CFArrayCreate( NULL, (const void**)&recName, 1, &kCFTypeArrayCallBacks );
siResult = inNode->GetRecords( inPlugin->RecordNativeTypeForStandardType( CFSTR( kDSStdRecordTypeConfig ) ),
recNames, CFSTR( kDSNAttrRecordName ), eDSExact, false, 1, recordsArray );
CFRelease( recNames );
if ( siResult != eDSNoErr )
throw( siResult );
if ( CFArrayGetCount( recordsArray ) == 0 )
{
siResult = inPlugin->CreateRecord( inNodeRef, CFSTR( kDSStdRecordTypeConfig ), CFSTR( kShadowHashRecordName ),
true, &shadowHashRecRef );
if ( siResult != eDSNoErr )
throw( siResult );
}
else
{
siResult = inPlugin->OpenRecord( inNodeRef, CFSTR( kDSStdRecordTypeConfig ), CFSTR( kShadowHashRecordName ),
&shadowHashRecRef );
if ( siResult != eDSNoErr )
throw( siResult );
}
if ( ( inEffectiveUID != 0 ) || ( (inAuthedUserName != NULL) && CFStringCompare( inAuthedUserName, CFSTR( "root" ), 0 ) != kCFCompareEqualTo ) )
{
if ( !inNode->WriteAccessAllowed( inAuthedUserName, inEffectiveUID,
inPlugin->RecordNativeTypeForStandardType( CFSTR( kDSStdRecordTypeConfig ) ),
CFSTR( kShadowHashRecordName ),
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPasswordPolicyOptions ) ) ) )
throw( eDSPermissionError );
}
{
char *xmlDataStr;
char policyStr[2048];
::PWGlobalAccessFeaturesToStringExtra( inGAccess, inGMoreAccess, sizeof( policyStr ), policyStr );
if ( ::ConvertGlobalSpaceDelimitedPolicyToXML( policyStr, &xmlDataStr ) == 0 )
{
inPlugin->RemoveAttribute( shadowHashRecRef, CFSTR( kDS1AttrPasswordPolicyOptions ) );
CFStringRef xmlDataCFStr = CFStringCreateWithCString( NULL, xmlDataStr, kCFStringEncodingUTF8 );
siResult = inPlugin->AddAttribute( shadowHashRecRef, CFSTR( kDS1AttrPasswordPolicyOptions ), xmlDataCFStr );
CFRelease( xmlDataCFStr );
::free( xmlDataStr );
if ( siResult != eDSNoErr )
throw( siResult );
}
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::SetShadowHashGlobalPolicies(): got error %d", err );
siResult = err;
}
if ( shadowHashRecRef != 0 )
{
inPlugin->CloseRecord( shadowHashRecRef );
CRefTable::RemoveRecordRef( shadowHashRecRef, gDaemonPID, gDaemonIPAddress ); }
if ( recordsArray != NULL )
CFRelease( recordsArray );
return( siResult );
}
void CDSLocalAuthHelper::GenerateShadowHashes( bool inServerOS, const char *inPassword, long inPasswordLen,
int inAdditionalHashList, const unsigned char *inSHA1Salt, unsigned char *outHashes, unsigned long *outHashTotalLength )
{
CC_SHA1_CTX sha_context = {};
unsigned char digestData[kHashSecureLength] = {0};
long pos = 0;
bzero( outHashes, kHashTotalLength );
if ( (inAdditionalHashList & ePluginHashNT) )
CalculateSMBNTHash( inPassword, outHashes );
pos = kHashShadowOneLength;
if ( (inAdditionalHashList & ePluginHashLM) )
CalculateSMBLANManagerHash( inPassword, outHashes + kHashShadowOneLength );
pos = kHashShadowBothLength;
if ( (inAdditionalHashList & ePluginHashSHA1) )
{
CC_SHA1_Init( &sha_context );
CC_SHA1_Update( &sha_context, (unsigned char *)inPassword, inPasswordLen );
CC_SHA1_Final( digestData, &sha_context );
memmove( outHashes + pos, digestData, kHashSecureLength );
}
pos += kHashSecureLength;
if ( (inAdditionalHashList & ePluginHashCRAM_MD5) )
{
unsigned long cramHashLen = 0;
pwsf_getHashCramMD5( (const unsigned char *)inPassword, inPasswordLen, outHashes + pos, &cramHashLen );
}
pos += kHashCramLength;
if ( (inAdditionalHashList & ePluginHashSaltedSHA1) )
{
unsigned long salt;
if ( inSHA1Salt != NULL )
{
memcpy( &salt, inSHA1Salt, 4 );
memcpy( outHashes + pos, inSHA1Salt, 4 );
}
else
{
::srandom(getpid() + time(0));
salt = (unsigned long) random();
memcpy( outHashes + pos, &salt, 4 );
}
pos += 4;
CC_SHA1_Init( &sha_context );
CC_SHA1_Update( &sha_context, (unsigned char *)&salt, 4 );
CC_SHA1_Update( &sha_context, (unsigned char *)inPassword, inPasswordLen );
CC_SHA1_Final( digestData, &sha_context );
memmove( outHashes + pos, digestData, kHashSecureLength );
pos += kHashSecureLength;
}
else
{
pos += 4 + kHashSecureLength;
}
if ( inServerOS && (inAdditionalHashList & ePluginHashRecoverable) )
{
CCCryptorStatus status = kCCSuccess;
unsigned char iv[kCCBlockSizeAES128];
size_t dataMoved;
unsigned char passCopy[kHashRecoverableLength + kCCBlockSizeAES128];
bzero( passCopy, sizeof(passCopy) );
memcpy( passCopy, inPassword, (inPasswordLen < kHashRecoverableLength) ? inPasswordLen : (kHashRecoverableLength - 1) );
memcpy( iv, kAESVector, sizeof(iv) );
status = CCCrypt(
kCCEncrypt,
kCCAlgorithmAES128,
0,
(const unsigned char *)"key4now-key4now-key4now", kCCKeySizeAES128,
iv,
passCopy,
kHashRecoverableLength,
outHashes + pos,
kHashRecoverableLength,
&dataMoved );
}
pos += kHashRecoverableLength;
*outHashTotalLength = kHashTotalLength;
}
tDirStatus CDSLocalAuthHelper::UnobfuscateRecoverablePassword( unsigned char *inData, unsigned char **outPassword,
unsigned long *outPasswordLength )
{
CCCryptorStatus status = kCCSuccess;
unsigned char iv[kCCBlockSizeAES128];
size_t dataMoved;
unsigned char passCopy[kHashRecoverableLength + kCCBlockSizeAES128];
if ( inData == NULL || outPassword == NULL || outPasswordLength == NULL )
return eParameterError;
bzero( passCopy, sizeof(passCopy) );
memcpy( iv, kAESVector, sizeof(iv) );
status = CCCrypt(
kCCDecrypt,
kCCAlgorithmAES128,
0,
(const unsigned char *)"key4now-key4now-key4now", kCCKeySizeAES128,
iv,
inData,
kHashRecoverableLength,
passCopy,
sizeof(passCopy),
&dataMoved );
*outPasswordLength = strlen( (char *)passCopy );
*outPassword = (unsigned char *) malloc( (*outPasswordLength) + 1 );
if ( (*outPassword) == NULL )
return eMemoryError;
strlcpy( (char *)*outPassword, (char *)passCopy, (*outPasswordLength) + 1 );
return eDSNoErr;
}
tDirStatus CDSLocalAuthHelper::MSCHAPv2( const unsigned char *inC16, const unsigned char *inPeerC16,
const unsigned char *inNTLMDigest, const char *inSambaName, const unsigned char *inOurHash,
char *outMSCHAP2Response )
{
unsigned char ourP24[kHashShadowResponseLength];
unsigned char Challenge[8];
tDirStatus result = eDSAuthFailed;
ChallengeHash( inPeerC16, inC16, inSambaName, Challenge );
ChallengeResponse( Challenge, inOurHash, ourP24 );
if ( memcmp( ourP24, inNTLMDigest, kHashShadowResponseLength ) == 0 )
{
GenerateAuthenticatorResponse( inOurHash, ourP24, Challenge, outMSCHAP2Response );
result = eDSNoErr;
}
return result;
}
tDirStatus CDSLocalAuthHelper::CRAM_MD5( const unsigned char *inHash, const char *inChallenge,
const unsigned char *inResponse )
{
tDirStatus siResult = eDSAuthFailed;
HMAC_MD5_STATE md5state;
HMAC_MD5_CTX tmphmac;
unsigned char digest[MD5_DIGEST_LENGTH];
char correctAnswer[32];
memcpy(&md5state, inHash, sizeof(HMAC_MD5_STATE));
CDSLocalAuthHelper::hmac_md5_import(&tmphmac, (HMAC_MD5_STATE *) &md5state);
MD5_Update(&(tmphmac.ictx), (const unsigned char *) inChallenge, strlen(inChallenge));
CDSLocalAuthHelper::hmac_md5_final(digest, &tmphmac);
CvtHex(digest, (unsigned char *)correctAnswer);
if ( strncasecmp((char *)inResponse, correctAnswer, 32) == 0 )
siResult = eDSNoErr;
return siResult;
}
void CDSLocalAuthHelper::hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state)
{
bzero((char *)hmac, sizeof(HMAC_MD5_CTX));
hmac->ictx.A = ntohl(state->istate[0]);
hmac->ictx.B = ntohl(state->istate[1]);
hmac->ictx.C = ntohl(state->istate[2]);
hmac->ictx.D = ntohl(state->istate[3]);
hmac->octx.A = ntohl(state->ostate[0]);
hmac->octx.B = ntohl(state->ostate[1]);
hmac->octx.C = ntohl(state->ostate[2]);
hmac->octx.D = ntohl(state->ostate[3]);
hmac->ictx.Nl = hmac->octx.Nl = 0x200;
}
void CDSLocalAuthHelper::hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], HMAC_MD5_CTX *hmac)
{
MD5_Final(digest, &hmac->ictx);
MD5_Update(&hmac->octx, digest, MD5_DIGEST_LENGTH);
MD5_Final(digest, &hmac->octx);
}
tDirStatus CDSLocalAuthHelper::Verify_APOP( const char *userstr, const unsigned char *inPassword,
unsigned long inPasswordLen, const char *challenge, const char *response )
{
tDirStatus siResult = eDSAuthFailed;
unsigned char digest[16];
char digeststr[33];
CC_MD5_CTX ctx;
if ( challenge == NULL || inPassword == NULL || response == NULL )
return eParameterError;
CC_MD5_Init( &ctx );
CC_MD5_Update( &ctx, challenge, strlen(challenge) );
CC_MD5_Update( &ctx, inPassword, inPasswordLen );
CC_MD5_Final( digest, &ctx );
CvtHex(digest, (unsigned char *)digeststr);
if ( strncasecmp(digeststr, response, 32) == 0 )
{
siResult = eDSNoErr;
}
return siResult;
}
tDirStatus CDSLocalAuthHelper::PasswordOkForPolicies( const char *inSpaceDelimitedPolicies,
PWGlobalAccessFeatures *inGAccess, const char *inUsername, const char *inPassword )
{
PWAccessFeatures access;
PWMoreAccessFeatures moreAccess = {0};
tDirStatus siResult = eDSNoErr;
int result;
DbgLog( kLogPlugin, "CDSLocalAuthHelper::PasswordOkForPolicies()" );
if ( inPassword == NULL )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::PasswordOkForPolicies(): no password" );
return eDSNoErr;
}
if ( inGAccess->noModifyPasswordforSelf )
return eDSAuthFailed;
::GetDefaultUserPolicies( &access );
if ( inSpaceDelimitedPolicies != NULL )
::StringToPWAccessFeaturesExtra( inSpaceDelimitedPolicies, &access, &moreAccess );
try
{
if ( !access.canModifyPasswordforSelf )
throw( eDSAuthFailed );
result = ::pwsf_RequiredCharacterStatusExtra( &access, inGAccess, inUsername, inPassword, &moreAccess );
switch( result )
{
case kAuthOK: siResult = eDSNoErr; break;
case kAuthUserDisabled: siResult = eDSAuthAccountDisabled; break;
case kAuthPasswordExpired: siResult = eDSAuthPasswordExpired; break;
case kAuthPasswordNeedsChange: siResult = eDSAuthPasswordQualityCheckFailed; break;
case kAuthPasswordTooShort: siResult = eDSAuthPasswordTooShort; break;
case kAuthPasswordTooLong: siResult = eDSAuthPasswordTooLong; break;
case kAuthPasswordNeedsAlpha: siResult = eDSAuthPasswordNeedsLetter; break;
case kAuthPasswordNeedsDecimal: siResult = eDSAuthPasswordNeedsDigit; break;
case kAuthPasswordNeedsMixedCase: siResult = eDSAuthPasswordQualityCheckFailed; break;
default:
siResult = eDSAuthFailed;
break;
}
}
catch( tDirStatus catchErr )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::PasswordOkForPolicies(): got error: %d", catchErr );
siResult = catchErr;
}
return siResult;
}
tDirStatus CDSLocalAuthHelper::TestPolicies( const char *inSpaceDelimitedPolicies, PWGlobalAccessFeatures *inGAccess,
sHashState *inOutHashState, struct timespec *inModDateOfPassword, const char *inHashPath )
{
PWAccessFeatures access;
PWMoreAccessFeatures moreAccess = {0};
int result;
tDirStatus siResult = eDSNoErr;
if ( inHashPath == NULL )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::TestPolicies(): no path" );
return eDSNoErr;
}
GetDefaultUserPolicies( &access );
if ( inSpaceDelimitedPolicies != NULL )
StringToPWAccessFeaturesExtra( inSpaceDelimitedPolicies, &access, &moreAccess );
try
{
result = pwsf_TestDisabledStatus( &access, inGAccess, &(inOutHashState->creationDate),
&(inOutHashState->lastLoginDate), &(inOutHashState->failedLoginAttempts) );
if ( result == kAuthUserDisabled )
{
inOutHashState->disabled = 1;
throw( eDSAuthAccountDisabled );
}
if ( inOutHashState->newPasswordRequired )
throw( eDSAuthNewPasswordRequired );
gmtime_r( (const time_t *)&inModDateOfPassword->tv_sec, &(inOutHashState->modDateOfPassword) );
result = pwsf_ChangePasswordStatus( &access, inGAccess, &(inOutHashState->modDateOfPassword) );
switch( result )
{
case kAuthPasswordNeedsChange:
siResult = eDSAuthNewPasswordRequired;
break;
case kAuthPasswordExpired:
siResult = eDSAuthPasswordExpired;
break;
default:
break;
}
}
catch( tDirStatus catchErr)
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::TestPolicies(): got error %d", catchErr );
siResult = catchErr;
}
return siResult;
}
tDirStatus CDSLocalAuthHelper::MigrateToShadowHash( tDirNodeReference inNodeRef, CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode, CFMutableDictionaryRef inMutableRecordDict, const char *inUserName, const char *inPassword,
bool *outResetCache, unsigned int inHashList, CFStringRef inNativeRecType )
{
tDirStatus siResult = eDSAuthFailed;
unsigned char generatedHashes[kHashTotalLength] = {0};
unsigned long hashTotalLength = 0;
char* cStr = NULL;
size_t cStrSize = 0;
CFStringRef cfString = NULL;
tRecordReference recordRef = 0;
CFMutableDictionaryRef nodeDict = NULL;
CFStringRef preRootAuthString = NULL;
try
{
CFArrayRef values = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrGeneratedUID ) ) );
if ( ( values != NULL ) && ( CFArrayGetCount( values ) > 0 ) )
cfString = (CFStringRef)CFArrayGetValueAtIndex( values, 0 );
const char* guidCStr = NULL;
if ( ( cfString != NULL ) && ( CFStringGetLength( cfString ) > 0 ) )
guidCStr = CStrFromCFString( cfString, &cStr, &cStrSize, NULL );
values = (CFArrayRef)CFDictionaryGetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrRecordName ) ) );
if ( CFArrayGetCount( values ) > 0 )
cfString = (CFStringRef)CFArrayGetValueAtIndex( values, 0 );
else
throw( eDSRecordNotFound );
siResult = inPlugin->OpenRecord( inNodeRef, inNativeRecType, cfString, &recordRef );
if ( siResult != eDSNoErr )
throw( siResult );
if (guidCStr == NULL)
{
CFUUIDRef myUUID;
CFStringRef myUUIDString;
char genUIDValue[100];
bzero( genUIDValue, sizeof(genUIDValue) );
myUUID = CFUUIDCreate(kCFAllocatorDefault);
myUUIDString = CFUUIDCreateString(kCFAllocatorDefault, myUUID);
CFStringGetCString(myUUIDString, genUIDValue, sizeof(genUIDValue), kCFStringEncodingASCII);
CFRelease(myUUID);
CFRelease(myUUIDString);
cStr = strdup(genUIDValue);
cStrSize = strlen( cStr ) + 1;
guidCStr = cStr;
cfString = CFStringCreateWithCString( NULL, guidCStr, kCFStringEncodingUTF8 );
siResult = inPlugin->AddAttribute( recordRef, CFSTR( kDS1AttrGeneratedUID ), cfString );
if ( siResult != eDSNoErr )
throw( siResult );
CFDictionaryRemoveValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrGeneratedUID ) ) );
CFMutableArrayRef mutableArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFArrayAppendValue( mutableArray, cfString );
CFDictionaryAddValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrGeneratedUID ) ), mutableArray );
CFRelease( mutableArray );
mutableArray = NULL;
CFRelease( cfString );
cfString = NULL;
*outResetCache = true;
}
CDSLocalAuthHelper::GenerateShadowHashes( gServerOS, inPassword, strlen(inPassword), inHashList, NULL,
generatedHashes, &hashTotalLength );
siResult = CDSLocalAuthHelper::WriteShadowHash(inUserName, guidCStr, generatedHashes);
if (siResult != eDSNoErr)
throw( siResult );
{
CFDictionaryRef openRecordDict = inPlugin->RecordDictForRecordRef( recordRef );
if ( openRecordDict == NULL )
throw( eDSInvalidRecordRef );
nodeDict = (CFMutableDictionaryRef)CFDictionaryGetValue( openRecordDict, CFSTR(kOpenRecordDictNodeDict) );
if ( nodeDict == NULL )
throw( eDSInvalidNodeRef );
preRootAuthString = (CFStringRef) CFDictionaryGetValue( nodeDict, CFSTR(kNodeAuthenticatedUserName) );
if ( preRootAuthString != NULL )
CFRetain( preRootAuthString );
CFDictionarySetValue( nodeDict, CFSTR(kNodeAuthenticatedUserName), CFSTR("root") );
siResult = ::SetUserAuthAuthorityAsRoot(
inMutableRecordDict,
inPlugin,
inNode,
inPlugin->RecordStandardTypeForNativeType(inNativeRecType),
inUserName,
kDSValueAuthAuthorityShadowHash,
inNodeRef,
true );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->RemoveAttribute( recordRef, CFSTR( kDS1AttrPassword ) );
siResult = inPlugin->AddAttribute( recordRef, CFSTR( kDS1AttrPassword ),
CFSTR( kDSValueNonCryptPasswordMarker ) );
if ( siResult != eDSNoErr )
throw( siResult );
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); recordRef = 0;
CFMutableArrayRef mutableArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFArrayAppendValue( mutableArray, CFSTR( kDSValueAuthAuthorityShadowHash ) );
CFDictionarySetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrAuthenticationAuthority ) ), mutableArray );
DSCFRelease( mutableArray );
mutableArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFArrayAppendValue( mutableArray, CFSTR( kDSValueNonCryptPasswordMarker ) );
CFDictionarySetValue( inMutableRecordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPassword ) ), mutableArray );
DSCFRelease( mutableArray );
}
}
catch( tDirStatus err )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::MigrateToShadowHash(): got error %d", err );
siResult = err;
}
if ( recordRef != 0 )
{
inPlugin->CloseRecord( recordRef );
CRefTable::RemoveRecordRef( recordRef, gDaemonPID, gDaemonIPAddress ); }
if ( cStr != NULL )
free( cStr );
if ( preRootAuthString != NULL ) {
CFDictionarySetValue( nodeDict, CFSTR(kNodeAuthenticatedUserName), preRootAuthString );
CFRelease( preRootAuthString );
}
else {
CFDictionaryRemoveValue( nodeDict, CFSTR(kNodeAuthenticatedUserName) );
}
return(siResult);
}
tDirStatus CDSLocalAuthHelper::MigrateAddKerberos(
tDirNodeReference inNodeRef, CDSLocalAuthParams &inParams,
CFMutableDictionaryRef *inOutContinueDataDict, tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData, bool inAuthOnly, bool isSecondary,
CAuthAuthority &inAuthAuthorityList, const char* inGUIDString, bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict, unsigned int inHashList,
CDSLocalPlugin *inPlugin, CDSLocalPluginNode *inNode, CFStringRef inAuthedUserName,
uid_t inUID, uid_t inEffectiveUID, CFStringRef inNativeRecType,
bool inOKToChangeAuthAuthorities )
{
tDirStatus siResult = eDSNoErr;
if ( !inOKToChangeAuthAuthorities )
return siResult;
char *localKDCRealmStr = GetLocalKDCRealmWithCache( kLocalKDCRealmCacheTimeout );
if ( localKDCRealmStr != NULL )
{
if ( inAuthAuthorityList.GetValueCount() == 1 &&
(inAuthAuthorityList.GetValueForTagAsCFDict(kDSTagAuthAuthorityShadowHash) != NULL ||
inAuthAuthorityList.GetValueForTagAsCFDict(kDSTagAuthAuthorityLocalCachedUser) != NULL) )
{
AddKerberosAuthAuthority(
inNodeRef, inParams.pUserName, kDSTagAuthAuthorityKerberosv5, inAuthAuthorityList, inMutableRecordDict,
inPlugin, inNode, inNativeRecType, inOKToChangeAuthAuthorities );
if ( inParams.uiAuthMethod == kAuthNativeClearTextOK || inParams.uiAuthMethod == kAuthNativeNoClearText )
{
if ( pwsf_AddPrincipalToLocalRealm(inParams.pUserName, inParams.pOldPassword, localKDCRealmStr) != 0 )
DbgLog( kLogPlugin, "CDSLocalAuthHelper::MigrateAddKerberos(): Unable to add principal %s@%s",
inParams.pUserName, localKDCRealmStr );
}
else
{
siResult = CDSLocalAuthHelper::DoKerberosAuth( inNodeRef, inParams, inOutContinueDataDict, inAuthData,
outAuthData, inAuthOnly, isSecondary, inAuthAuthorityList, inGUIDString, inAuthedUserIsAdmin,
inMutableRecordDict, inHashList, inPlugin, inNode, inAuthedUserName, inUID, inEffectiveUID,
inNativeRecType );
}
}
free( localKDCRealmStr );
}
return siResult;
}
tDirStatus CDSLocalAuthHelper::PWSetReplicaData( CDSLocalPlugin* inPlugin, CDSLocalPluginNode* inNode,
tDirNodeReference inNodeRef, tDirNodeReference inPWSNodeRef, const char *inAuthorityData )
{
tDirStatus error = eDSNoErr;
long replicaListLen = 0;
char *rsaKeyPtr = NULL;
tDataBufferPtr replicaBuffer = NULL;
tDataBufferPtr replyBuffer = NULL;
char hashStr[34];
CFMutableArrayRef recordsArray = NULL;
char* cStr = NULL;
size_t cStrSize = 0;
try
{
CFStringRef nativeConfigRecType = inPlugin->RecordNativeTypeForStandardType( CFSTR( kDSStdRecordTypeConfig ) );
recordsArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFDictionaryRef recordDict = NULL;
rsaKeyPtr = strchr( inAuthorityData, ',' );
if ( rsaKeyPtr != NULL )
{
CC_MD5_CTX ctx;
unsigned char pubKeyHash[CC_MD5_DIGEST_LENGTH];
CC_MD5_Init( &ctx );
rsaKeyPtr++;
CC_MD5_Update( &ctx, rsaKeyPtr, strlen(rsaKeyPtr) );
CC_MD5_Final( pubKeyHash, &ctx );
BinaryToHexConversion( pubKeyHash, CC_MD5_DIGEST_LENGTH, hashStr );
CFStringRef recordName = CFStringCreateWithFormat( NULL, 0, CFSTR( "passwordserver_%s" ), hashStr );
CFArrayRef patternsToMatch = CFArrayCreate( NULL, (const void**)&recordName, 1, &kCFTypeArrayCallBacks );
error = inNode->GetRecords( nativeConfigRecType, patternsToMatch,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrRecordName ) ), eDSExact, true, 1, recordsArray );
CFRelease( recordName );
CFRelease( patternsToMatch );
if ( error != eDSNoErr )
throw( error );
if ( CFArrayGetCount( recordsArray ) > 0 )
recordDict = (CFDictionaryRef)CFArrayGetValueAtIndex( recordsArray, 0 );
}
if ( recordDict == NULL )
{
CFStringRef recordName = CFSTR( "passwordserver" );
CFArrayRef patternsToMatch = CFArrayCreate( NULL, (const void**)&recordName, 1, &kCFTypeArrayCallBacks );
error = inNode->GetRecords( nativeConfigRecType, patternsToMatch,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDSNAttrRecordName ) ), eDSExact, true, 1, recordsArray );
CFRelease( recordName );
CFRelease( patternsToMatch );
if ( error != eDSNoErr )
throw( error );
else if ( CFArrayGetCount( recordsArray ) == 0 )
throw( eDSRecordNotFound );
else
recordDict = (CFDictionaryRef)CFArrayGetValueAtIndex( recordsArray, 0 );
}
CFStringRef pwsList = NULL;
CFArrayRef pwsListAttrValues = (CFArrayRef)CFDictionaryGetValue( recordDict,
inPlugin->AttrNativeTypeForStandardType( CFSTR( kDS1AttrPasswordServerList ) ) );
if ( CFArrayGetCount( pwsListAttrValues ) > 0 )
pwsList = (CFStringRef)CFArrayGetValueAtIndex( pwsListAttrValues, 0 );
if ( ( pwsList != NULL ) && ( CFStringGetLength( pwsList ) > 0 ) )
{
const char* pwsListCStr = CStrFromCFString( pwsList, &cStr, &cStrSize );
replicaListLen = strlen( pwsListCStr );
replicaBuffer = ::dsDataBufferAllocatePriv( replicaListLen + 1 );
if ( replicaBuffer == NULL ) throw( eMemoryError );
replyBuffer = ::dsDataBufferAllocatePriv( 1 );
if ( replyBuffer == NULL ) throw( eMemoryError );
replicaBuffer->fBufferLength = replicaListLen;
memcpy( replicaBuffer->fBufferData, pwsListCStr, replicaListLen );
error = dsDoPlugInCustomCall( inPWSNodeRef, 1, replicaBuffer, replyBuffer );
::dsDataBufferDeallocatePriv( replicaBuffer );
::dsDataBufferDeallocatePriv( replyBuffer );
}
}
catch( tDirStatus catchErr )
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::PWSSetReplicaData(): got error %d", catchErr );
error = catchErr;
}
if ( recordsArray != NULL )
CFRelease( recordsArray );
if ( cStr != NULL )
::free( cStr );
return error;
}
tDirStatus
CDSLocalAuthHelper::LocalCachedUserReachable(
tDirNodeReference inNodeRef,
CFMutableDictionaryRef* inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
const char* inGUIDString,
bool inAuthedUserIsAdmin,
CDSLocalAuthParams &inPB,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType,
bool* inOutNodeReachable,
tDirReference *outDSRef,
tDataList **outDSNetworkNode,
char **localCachedUserName )
{
tDirStatus siResult = eDSAuthFailed;
char *networkNodename = nil;
char *userGUID = nil;
SInt32 result = eDSNoErr;
tDataBuffer *dataBuffer = nil;
UInt32 nodeCount = 0;
tDirNodeReference aSearchNodeRef = 0;
tDataList *pSearchNode = nil;
tDataList *pSearchNodeList = nil;
tAttributeListRef attrListRef = 0;
tAttributeValueListRef attrValueListRef = 0;
tAttributeValueEntry *pAttrValueEntry = nil;
tAttributeEntry *pAttrEntry = nil;
UInt32 aIndex = 0;
if ( inAuthData == nil ) return( eDSNullAuthStepData );
if ( inOutNodeReachable == nil ) return( eParameterError );
if ( outDSRef == nil ) return( eParameterError );
if ( outDSNetworkNode == nil ) return( eParameterError );
if ( localCachedUserName == nil ) return( eParameterError );
*inOutNodeReachable = false;
DbgLog( kLogPlugin, "LocalCachedUserReachable::checking" );
try
{
siResult = ParseLocalCacheUserAuthData( inPB.aaDataLocalCacheUser, &networkNodename, localCachedUserName, &userGUID );
result = inPlugin->GetDirServiceRef( &(*outDSRef) );
if ( result == eDSNoErr )
{
*outDSNetworkNode = dsBuildFromPathPriv( networkNodename, "/" );
if ( *outDSNetworkNode == nil ) throw( eMemoryError );
dataBuffer = ::dsDataBufferAllocate( *outDSRef, 1024 );
if ( dataBuffer == nil ) throw( eMemoryError );
if ( strncmp("/Active Directory/", networkNodename, sizeof("/Active Directory/")-1) == 0 )
{
*inOutNodeReachable = true;
siResult = eDSNoErr;
throw( siResult );
}
result = dsFindDirNodes( *outDSRef, dataBuffer, *outDSNetworkNode, eDSiExact, &nodeCount, nil );
if ( (result == eDSNoErr) && (nodeCount == 1) )
{
result = dsFindDirNodes( *outDSRef, dataBuffer, nil, eDSAuthenticationSearchNodeName, &nodeCount, nil );
if ( ( result == eDSNoErr ) && ( nodeCount == 1 ) )
{
result = dsGetDirNodeName( *outDSRef, dataBuffer, 1, &pSearchNode );
if ( result == eDSNoErr )
{
result = dsOpenDirNode( *outDSRef, pSearchNode, &aSearchNodeRef );
if ( pSearchNode != NULL )
{
dsDataListDeallocatePriv( pSearchNode );
free( pSearchNode );
pSearchNode = NULL;
}
if ( result == eDSNoErr )
{
pSearchNodeList = dsBuildFromPathPriv( kDS1AttrSearchPath, "/" );
if ( pSearchNodeList == nil ) throw( eMemoryError );
do
{
nodeCount = 0;
result = dsGetDirNodeInfo( aSearchNodeRef, pSearchNodeList, dataBuffer, false, &nodeCount, &attrListRef, nil );
if (result == eDSBufferTooSmall)
{
UInt32 bufSize = dataBuffer->fBufferSize;
dsDataBufferDeallocatePriv( dataBuffer );
dataBuffer = nil;
dataBuffer = ::dsDataBufferAllocate( *outDSRef, bufSize * 2 );
}
} while (result == eDSBufferTooSmall);
dsDataListDeallocatePriv( pSearchNodeList );
free( pSearchNodeList );
pSearchNodeList = NULL;
if ( (result == eDSNoErr) && (nodeCount > 0) )
{
result = dsGetAttributeEntry( aSearchNodeRef, dataBuffer, attrListRef, 1, &attrValueListRef, &pAttrEntry );
if ( result != eDSNoErr ) throw( result );
for (aIndex=1; aIndex < (pAttrEntry->fAttributeValueCount+1); aIndex++)
{
result = dsGetAttributeValue( aSearchNodeRef, dataBuffer, aIndex, attrValueListRef, &pAttrValueEntry );
if ( result != eDSNoErr ) throw( result );
if ( pAttrValueEntry->fAttributeValueData.fBufferData == nil )
throw( eMemoryAllocError );
if (strcmp( networkNodename, pAttrValueEntry->fAttributeValueData.fBufferData ) == 0 )
{
*inOutNodeReachable = true; dsDeallocAttributeValueEntry(*outDSRef, pAttrValueEntry);
pAttrValueEntry = nil;
break;
}
dsDeallocAttributeValueEntry(*outDSRef, pAttrValueEntry);
pAttrValueEntry = nil;
}
dsCloseAttributeList(attrListRef);
dsCloseAttributeValueList(attrValueListRef);
dsDeallocAttributeEntry(*outDSRef, pAttrEntry);
pAttrEntry = nil;
result = ::dsCloseDirNode(aSearchNodeRef);
aSearchNodeRef = 0;
if ( result != eDSNoErr ) throw( result );
}
}
}
}
}
}
}
catch( tDirStatus err )
{
siResult = err;
}
DSFreeString( networkNodename );
DSFreeString( userGUID );
if ( dataBuffer != nil )
{
dsDataBufferDeallocatePriv( dataBuffer );
dataBuffer = nil;
}
DbgLog( kLogPlugin, "LocalCachedUserReachable::result = %d, on SearchNode = %d", siResult, *inOutNodeReachable );
return( siResult );
}
tDirStatus CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2( tDirNodeReference inNodeRef,
CDSLocalAuthParams &inParams,
CFMutableDictionaryRef* inOutContinueDataDict,
tDataBufferPtr inAuthData,
tDataBufferPtr outAuthData,
bool inAuthOnly,
bool isSecondary,
CAuthAuthority &inAuthAuthorityList,
const char* inGUIDString,
bool inAuthedUserIsAdmin,
CFMutableDictionaryRef inMutableRecordDict,
unsigned int inHashList,
CDSLocalPlugin* inPlugin,
CDSLocalPluginNode* inNode,
CFStringRef inAuthedUserName,
uid_t inUID,
uid_t inEffectiveUID,
CFStringRef inNativeRecType,
bool *inOutNodeReachable,
tDirReference *inOutDSRef,
tDataList **inOutDSNetworkNode,
char *localCachedUserName,
bool inOKToModifyAuthAuthority )
{
tDirStatus siResult = eDSAuthFailed;
tDirStatus siResult2 = eDSAuthFailed;
tDirNodeReference aNodeRef = 0;
tDataBufferPtr authDataBuff = NULL;
bool nodeIsOnSearchPolicy = *inOutNodeReachable;
CFMutableDictionaryRef nodeDict = NULL;
CAuthAuthority tempAuthAuthorityList(inAuthAuthorityList);
*inOutNodeReachable = false;
if ( inAuthData == NULL )
return( eDSNullAuthStepData );
if ( localCachedUserName == NULL )
return( eDSUserUnknown );
if ( nodeIsOnSearchPolicy && (*inOutDSNetworkNode != NULL) )
{
nodeDict = inPlugin->CopyNodeDictForNodeRef( inNodeRef );
if ( nodeDict == NULL )
return( eDSInvalidNodeRef );
siResult = OpenLDAPNode( inPlugin, nodeDict, *inOutDSNetworkNode, inOutDSRef, &aNodeRef );
if ( siResult == eDSNoErr )
{
siResult = (tDirStatus)RepackBufferForPWServer( inAuthData, localCachedUserName, 1, &authDataBuff );
if ( siResult == eDSNoErr )
{
tDataNodePtr authMethodNodePtr = dsDataNodeAllocateString( 0, inParams.mAuthMethodStr );
siResult = dsDoDirNodeAuth( aNodeRef, authMethodNodePtr, inAuthOnly, authDataBuff, outAuthData, nil );
dsDataNodeDeAllocate( 0, authMethodNodePtr );
DbgLog(kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2(): dsDoDirNodeAuth = %d", siResult);
}
switch( siResult )
{
case eDSNoErr:
case eDSNotAuthorized:
case eDSAuthUnknownUser:
*inOutNodeReachable = true;
break;
case eDSInvalidNodeRef:
case eDSMaxSessionsOpen:
case eDSCannotAccessSession:
case eDSAuthNoAuthServerFound:
case eDSAuthMasterUnreachable:
break;
case eDSAuthAccountDisabled:
*inOutNodeReachable = true;
if ( inOKToModifyAuthAuthority )
{
inAuthAuthorityList.SetValueDisabledForTag( kDSTagAuthAuthorityLocalCachedUser );
SaveAuthAuthorities( inPlugin, inNodeRef, inParams.pUserName, inNativeRecType, inAuthAuthorityList );
}
goto cleanup;
default:
*inOutNodeReachable = true;
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2(): dsDoDirNodeAuth = %d", siResult );
goto cleanup;
}
}
else if ( siResult == eDSAuthMasterUnreachable || siResult == eDSOpenNodeFailed || siResult == eDSNodeNotFound ||
siResult == eDSCannotAccessSession || (siResult >= ePlugInDataError && siResult <= ePlugInCallTimedOut) )
{
siResult = eDSCannotAccessSession;
}
else
{
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2(): OpenLDAPNode = %d", siResult );
goto cleanup;
}
}
else
{
siResult = eDSCannotAccessSession;
}
if ( *inOutNodeReachable == false )
{
switch( inParams.uiAuthMethod )
{
case kAuthSetPasswd:
case kAuthSetPasswdAsRoot:
case kAuthChangePasswd:
case kAuthSetPolicy:
case kAuthSetUserName:
case kAuthSetUserData:
case kAuthSetPolicyAsRoot:
case kAuthSetShadowHashWindows:
case kAuthSetShadowHashSecure:
goto cleanup;
break;
default:
break;
}
}
tempAuthAuthorityList.SetValueForTag( kDSTagAuthAuthorityShadowHash, kDSValueAuthAuthorityShadowHash kLocalCachedUserHashList );
siResult2 = CDSLocalAuthHelper::DoShadowHashAuth(
inNodeRef,
inParams,
inOutContinueDataDict,
inAuthData,
outAuthData,
inAuthOnly,
isSecondary,
tempAuthAuthorityList,
inGUIDString,
inAuthedUserIsAdmin,
inMutableRecordDict,
inHashList,
inPlugin,
inNode,
inAuthedUserName,
inUID,
inEffectiveUID,
inNativeRecType,
kDoNotTouchTheAuthAuthorities );
DbgLog(kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2(): DoShadowHashAuth = %d", siResult2);
if ( siResult == eDSNoErr )
{
if ( siResult2 != eDSNoErr )
{
char *name = NULL;
char *pwd = NULL;
unsigned long hashTotalLength = 0;
unsigned char generatedHashes[kHashTotalLength];
siResult2 = (tDirStatus) Get2FromBuffer( inAuthData, NULL, &name, &pwd, NULL );
if ( siResult2 == eDSNoErr )
{
GenerateShadowHashes( gServerOS, pwd, strlen(pwd), inHashList, NULL, generatedHashes, &hashTotalLength );
siResult2 = CDSLocalAuthHelper::WriteShadowHash( name, inGUIDString, generatedHashes );
}
DSFreeString( name );
DSFreePassword( pwd );
}
siResult = siResult2;
}
else if ( *inOutNodeReachable == false )
{
siResult = siResult2;
}
if ( inOKToModifyAuthAuthority && siResult == eDSAuthAccountDisabled )
{
inAuthAuthorityList.SetValueDisabledForTag( kDSTagAuthAuthorityLocalCachedUser );
siResult = SaveAuthAuthorities( inPlugin, inNodeRef, inParams.pUserName, inNativeRecType, inAuthAuthorityList );
if ( siResult != eDSNoErr )
DbgLog( kLogPlugin, "CDSLocalAuthHelper::DoLocalCachedUserAuthPhase2(): SaveAuthAuthorities = %d", siResult );
}
cleanup:
DSCFRelease( nodeDict );
if ( authDataBuff != NULL )
dsDataBufferDeallocatePriv( authDataBuff );
return( siResult );
}