⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auth.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: AUTH.CPP
Abstract: Authentication
--*/

#include "httpd.h"


const DWORD g_fAuthModule = TRUE;

//**********************************************************************
// Authentication
//**********************************************************************
#define SECURITY_DOMAIN TEXT("Domain") 	// dummy data.  
#define SEC_SUCCESS(Status) ((Status) >= 0)

BOOL SecurityServerContext(
			PSEC_WINNT_AUTH_IDENTITY pAuthIdentity,
			PAUTH_STATE pAS,BYTE *pIn, DWORD cbIn, BYTE *pOut, 
			DWORD *pcbOut, BOOL *pfDone, const TCHAR *szPackageName
	 );

BOOL SecurityClientContext(
			PSEC_WINNT_AUTH_IDENTITY pAuthIdentity,
			PAUTH_STATE pAS, BYTE *pIn, DWORD cbIn, 
			BYTE *pOut, DWORD *pcbOut
	 );


void CGlobalVariables::InitAuthentication(CReg *pReg) {
	m_fBasicAuth   =  pReg->ValueDW(RV_BASIC);

	// On root site, always load the security library whether we are using NTLM/negotiate
	// or not.  Do this in the case that one of our sub-websites is using NTLM/negotiate,
	// so we can point it back to the global function pointer table.
	if (! InitSecurityLib())
		return;

	m_fNTLMAuth      = pReg->ValueDW(RV_NTLM);
	m_fNegotiateAuth = pReg->ValueDW(RV_NEGOTIATE);
}


// Called after we've mapped the virtual root.
BOOL CHttpRequest::HandleAuthentication(void) {
	if (m_pszAuthType && m_pszRawRemoteUser) {
		if (AllowBasic() && 0==strcmpi(m_pszAuthType, cszBasic)) {
			FreePersistedAuthInfo();
			HandleBasicAuth(m_pszRawRemoteUser);
		}
		else if (AllowNTLM() && 0==strcmpi(m_pszAuthType, cszNTLM)) {
			FreePersistedAuthInfo();
			if ((m_AuthState.m_AuthType != AUTHTYPE_NONE) && (m_AuthState.m_AuthType != AUTHTYPE_NTLM))
				return FALSE;

			m_AuthState.m_AuthType = AUTHTYPE_NTLM;
			HandleNTLMNegotiateAuth(m_pszRawRemoteUser,TRUE);
		}
		else if (AllowNegotiate() && 0==strcmpi(m_pszAuthType,cszNegotiate)) {
			FreePersistedAuthInfo();

			if ((m_AuthState.m_AuthType != AUTHTYPE_NONE) && (m_AuthState.m_AuthType != AUTHTYPE_NEGOTIATE))
				return FALSE;

			m_AuthState.m_AuthType = AUTHTYPE_NEGOTIATE;
			HandleNTLMNegotiateAuth(m_pszRawRemoteUser,FALSE);
		}
		else {
			DEBUGMSG(ZONE_PARSER,(L"HTTPD: Unknown authorization type requested or requested type not enabled\r\n"));
			m_AuthLevelGranted = DeterminePermissionGranted(GetUserList(),m_AuthLevelGranted);
		}
	}
	else if (IsSecure() && m_SSLInfo.m_pClientCertContext) {
		HandleSSLClientCertCheck();
	}
	else {
		m_AuthLevelGranted = DeterminePermissionGranted(GetUserList(),m_AuthLevelGranted);
	}

	return TRUE;
}


// For calls to Basic Authentication, only called during the parsing stage.
BOOL CHttpRequest::HandleBasicAuth(PSTR pszData) {
	char szUserName[MAXUSERPASS];
	PSTR pszFinalUserName;
	DWORD dwLen = sizeof(szUserName);

	DEBUGCHK((m_pszRemoteUser == NULL) && (m_pszPassword == NULL));

	m_AuthLevelGranted = AUTH_PUBLIC;
	m_pszRemoteUser = NULL;

	if (strlen(pszData) >= MAXUSERPASS) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: Base64 data > 256 bytes on Basic Auth, failing request\r\n"));
		return FALSE;
	}

	// decode the base64
	if (! svsutil_Base64Decode(pszData,(void*)szUserName,sizeof(szUserName),NULL,TRUE)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: Base64 data is invalid, failing request\r\n"));
		return FALSE;
	}

	// find the password
	PSTR pszPassword = strchr(szUserName, ':');
	if(!pszPassword) {
		DEBUGMSG(ZONE_ERROR, (L"HTTPD: Bad Format for Basic userpass(%a)-->(%a)\r\n", pszData, szUserName));
		return FALSE;
	}
	*pszPassword++ = 0; // seperate user & pass

	// Some  clients prepend a domain name or machine name in front of user name, preceeding by a '\'.
	// Strip this out.
	if (NULL != (pszFinalUserName = strchr(szUserName,'\\'))) {
		DEBUGMSG(ZONE_AUTH,(L"HTTPD: UserName <<%s>> has \\ in it, skip preceeding data\r\n",szUserName));
		pszFinalUserName++;
	}
	else
		pszFinalUserName = szUserName;

	//  We save the data no matter what, for logging purposes and for possible
	//  GetServerVariable call.
	m_pszRemoteUser = MySzDupA(pszFinalUserName);
	m_pszPassword   = MySzDupA(pszPassword);

	if ((NULL==m_pszRemoteUser) || (NULL==m_pszPassword))
		return FALSE;

	if (! CallAuthFilterIfNeeded())
		return FALSE;

	WCHAR wszPassword[MAXUSERPASS];
	WCHAR wszRemoteUser[MAXUSERPASS];
	MyA2W(m_pszPassword, wszPassword, CCHSIZEOF(wszPassword));
	MyA2W(m_pszRemoteUser,wszRemoteUser, CCHSIZEOF(wszRemoteUser));

	// BasicToNTLM and helpers requires m_wszRemoteUser set.
	if (NULL == (m_wszRemoteUser = MySzDupW(wszRemoteUser)))
		return FALSE;

	if (BasicToNTLM(wszPassword))
		return TRUE;

	// On failure, remove m_wszRemoteUser
	ZeroAndFree(m_wszRemoteUser);
	m_AuthLevelGranted = AUTH_PUBLIC;

	DEBUGMSG(ZONE_ERROR, (L"HTTPD: Failed logon with Basic userpass(%a)-->(%a)(%a)\r\n", pszData, pszFinalUserName, pszPassword));
	return FALSE;
}

BOOL CGlobalVariables::InitSecurityLib(void) {
	DEBUG_CODE_INIT;
	FARPROC pInit;
	SECURITY_STATUS ss = 0;
	BOOL ret = FALSE;
	PSecurityFunctionTable pSecFun;

	if (!m_fRootSite)  {
		// No need to reload DLL and get new interface ptrs for each website.
		if (g_pVars->m_hSecurityLib) {
			memcpy(&m_SecurityInterface,&g_pVars->m_SecurityInterface,sizeof(m_SecurityInterface));
			m_cbMaxToken = g_pVars->m_cbMaxToken;
			return TRUE;
		}
		return FALSE;
	}
	DEBUGCHK(!m_hSecurityLib);

	m_hSecurityLib = LoadLibrary (SECURITY_DLL_NAME);
	if (NULL == m_hSecurityLib)  {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: Unable to load %s, GLE=0x%08x\r\n",SECURITY_DLL_NAME,GetLastError()));
		myleave(700);
	}

	pInit = (FARPROC) GetProcAddress (m_hSecurityLib, SECURITY_ENTRYPOINT_CE);
	if (NULL == pInit)  {
		DEBUGCHK(0);
		myleave(701);
	}

	pSecFun = (PSecurityFunctionTable) pInit ();
	if (NULL == pSecFun) {
		DEBUGCHK(0);
		myleave(702);
	}

	memcpy(&m_SecurityInterface,pSecFun,sizeof(SecurityFunctionTable));

	PSecPkgInfo pkgInfo;
	ss = m_SecurityInterface.QuerySecurityPackageInfo (NTLM_PACKAGE_NAME, &pkgInfo);
	if (!SEC_SUCCESS(ss))  {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: QuerySecurityPackageInfo failed, GLE=0x%08x\r\n",GetLastError()));
		myleave(703);
	}

	m_cbMaxToken = pkgInfo->cbMaxToken;
	m_SecurityInterface.FreeContextBuffer (pkgInfo);

	m_SecurityInterface.EncryptMessage = (ENCRYPT_MESSAGE_FN) m_SecurityInterface.Reserved3;
	m_SecurityInterface.DecryptMessage = (DECRYPT_MESSAGE_FN) m_SecurityInterface.Reserved4;

	DEBUGMSG(ZONE_AUTH,(L"HTTPD: Security Library successfully initialized\r\n"));

	ret = TRUE;
done:
	if (FALSE == ret) {
		CReg reg(HKEY_LOCAL_MACHINE,RK_HTTPD);
		MyFreeLib (m_hSecurityLib);
		m_hSecurityLib = 0;

		// only complain if the user requested NTLM.
		if (reg.ValueDW(RV_NTLM) || reg.ValueDW(RV_NEGOTIATE)) {
			if (ss == 0) // if unset above, then API that failed uses SetLastError().
				ss = GetLastError();

			m_pLog->WriteEvent(IDS_HTTPD_AUTH_INIT_ERROR,ss);
		}
	}

	return ret;
}


// This function is called 2 times during an NTLM auth session.  The first
// time it has the Client user name, domain,... which it forwards to DC or
// looks in registry for (this NTLM detail is transparent to httpd)
// On 2nd time it has the client's response, which either is or is not 
// enough to grant access to page.  On 2nd pass, free up all NTLM context data.

// FILTER NOTES:  On IIS no user name or password info is given to the filter
// on NTLM calls, so neither do we.  (WinCE does give BASIC data, though).

BOOL CHttpRequest::HandleNTLMNegotiateAuth(PSTR pszSecurityToken, BOOL fUseNTLM) {
	DEBUG_CODE_INIT;
	BOOL ret = FALSE;
	DWORD dwIn;
	DWORD dwOut;
	DWORD dwSecurityOutBufLen;
	BOOL fDone = FALSE;
	PBYTE pOutBuf = NULL;
	PBYTE pInBuf = NULL;   // Base64 decoded data from pszSecurityToken
	const TCHAR *szPackageName = fUseNTLM ? NTLM_PACKAGE_NAME : NEGOTIATE_PACKAGE_NAME ;

	DEBUGCHK((fUseNTLM && AllowNTLM()) || (!fUseNTLM && AllowNegotiate()));
	
	if (!g_pVars->m_hSecurityLib)
		myretleave(FALSE,94);

	dwOut = g_pVars->m_cbMaxToken;
	dwSecurityOutBufLen = 1 + (dwOut + 2) / 3 * 4;
	if (NULL == (pOutBuf = MyRgAllocNZ(BYTE,dwOut)))
		myleave(360);

	if (NULL == m_pszSecurityOutBuf) {
		// We will later Base64Encode pOutBuf, encoding writes 4 outbut bytes
		// for every 3 input bytes
		if (NULL == (m_pszSecurityOutBuf = MyRgAllocNZ(CHAR,dwSecurityOutBufLen)))
			myleave(361);
	}

	dwIn = strlen(pszSecurityToken) + 1;
	if (NULL == (pInBuf = MyRgAllocNZ(BYTE,dwIn)))
		myleave(363);

	if (! svsutil_Base64Decode(pszSecurityToken,pInBuf,dwIn,&dwIn,FALSE))
		myleave(365);

	//  On the 1st pass this gets a data blob to be sent back to the client
	//  broweser in pOutBuf, which is encoded to m_pszSecurityOutBuf.  On the 2nd
	//  pass it either authenticates or fails.


	if (! SecurityServerContext(NULL, &m_AuthState, pInBuf,
							dwIn,pOutBuf,&dwOut,&fDone,szPackageName))
	{
		// Note:  We MUST free the m_pszNTMLOutBuf on 2nd pass failure.  If the 
		// client receives the blob on a failure
		// it will consider the web server to be malfunctioning and will not send
		// another set of data, and will not prompt the user for a password.
		MyFree(m_pszSecurityOutBuf);


		// Setting to DONE will cause the local structs to be freed; they must
		// be fresh in case browser attempts to do NTLM again with new user name/
		// password on same session.  Don't bother unloading the lib.
		m_AuthState.m_Stage = SEC_STATE_DONE;
		myleave(362);
	}
	
	if (fDone) {
		DEBUGMSG(ZONE_AUTH,(L"HTTPD: Successfully authenticated user\r\n"));
		GetUserAndGroupInfo(&m_AuthState);
		m_AuthLevelGranted = DeterminePermissionGranted(GetUserList(),AUTH_USER);
		
		m_dwAuthFlags |= m_AuthLevelGranted;
		m_AuthState.m_Stage = SEC_STATE_DONE;
		MyFree(m_pszSecurityOutBuf);
		
		myretleave(TRUE,0);
	}

	ret = svsutil_Base64Encode(pOutBuf, dwOut, m_pszSecurityOutBuf, dwSecurityOutBufLen, NULL);
done:
	DEBUGMSG_ERR(ZONE_ERROR,(L"HTTPD: HandleNTLMNegotiateAuth died, err = %d, gle = %d\r\n",err,GetLastError()));
	
	MyFree(pOutBuf);
	MyFree(pInBuf);
	return ret;
}



//  Unload the contexts.  The library is NOT freed in this call, only freed
//  in CHttpRequest destructor.
void FreeSecContextHandles(PAUTH_STATE pAuthState) {
	if (NULL == pAuthState || NULL == g_pVars->m_hSecurityLib)
		return;
		
	if (pAuthState->m_fHaveCtxtHandle)
		g_pVars->m_SecurityInterface.DeleteSecurityContext (&pAuthState->m_hctxt);

	if (pAuthState->m_fHaveCredHandle)
		g_pVars->m_SecurityInterface.FreeCredentialHandle (&pAuthState->m_hcred);

	pAuthState->m_fHaveCredHandle = FALSE;
	pAuthState->m_fHaveCtxtHandle = FALSE;
	pAuthState->m_AuthType        = AUTHTYPE_NONE;
}




//  Given Basic authentication data, we try to "forge" and NTLM request
//  This fcn simulates a client+server talking to each other, though it's in the
//  same proc.  The client is "virtual," doesn't refer to the http client

//  pAuthState is CHttpRequest::m_AuthState
BOOL CHttpRequest::BasicToNTLM(WCHAR * wszPassword) {
	DEBUG_CODE_INIT;

	AUTH_STATE  ClientState;			// forges the client role
	AUTH_STATE  ServerState;			// forges the server role
	BOOL fDone = FALSE;
	PBYTE pClientOutBuf = NULL;
	PBYTE pServerOutBuf = NULL;
	DWORD cbServerBuf;
	DWORD cbClientBuf;
	
	DEBUGCHK(wszPassword != NULL && m_wszRemoteUser != NULL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -