//+---------------------------------------------------------------------------- // // File: ras.cpp // // Module: CMDIAL32.DLL // // Synopsis: This module contains the functions to allow Connection Manager to // interact with RAS. // // Copyright (c) 1997-1999 Microsoft Corporation // // Author: byao created 04/29/97 // quintinb created Header 08/16/99 // //+---------------------------------------------------------------------------- #include "cmmaster.h" #include "compchck.h" #include "dial_str.h" #include "dun_str.h" #include "tunl_str.h" #include "stp_str.h" #include "ras_str.h" #include "dialogs.h" #include // located in net\inc // // CMS flags use to specify DUN settings. These entries are specific // to this code module, shared entries are stored on dun_str.h // const TCHAR* const c_pszCmSectionDunPhone = TEXT("Phone"); const TCHAR* const c_pszCmEntryDunPhoneDialAsIs = TEXT("Dial_As_Is"); const TCHAR* const c_pszCmEntryDunPhonePhoneNumber = TEXT("Phone_Number"); const TCHAR* const c_pszCmEntryDunPhoneAreaCode = TEXT("Area_Code"); const TCHAR* const c_pszCmEntryDunPhoneCountryCode = TEXT("Country_Code"); const TCHAR* const c_pszCmEntryDunPhoneCountryId = TEXT("Country_ID"); const TCHAR* const c_pszCmSectionDunDevice = TEXT("Device"); const TCHAR* const c_pszCmEntryDunDeviceType = TEXT("Type"); const TCHAR* const c_pszCmEntryDunDeviceName = TEXT("Name"); const TCHAR* const c_pszCmEntryHideTrayIcon = TEXT("HideTrayIcon"); const TCHAR* const c_pszCmEntryInternetConnection = TEXT("InternetConnection"); // // the following reg key and value control whether Dial-Up Networking on Win95 // will start the Wizard. Note that these are explicitly chars instead of TCHARs // const CHAR* const c_pszRegRemoteAccess = "RemoteAccess"; const CHAR* const c_pszRegWizard = "wizard"; #define ICM_RAS_REG_WIZARD_VALUE 0x00000080 // // .CMS flags used only by ras.cpp // const TCHAR* const c_pszCmEntryDialExtraPercent = TEXT("DialExtraPercent"); const TCHAR* const c_pszCmEntryDialExtraSampleSeconds = TEXT("DialExtraSampleSeconds"); const TCHAR* const c_pszCmEntryHangUpExtraPercent = TEXT("HangUpExtraPercent"); const TCHAR* const c_pszCmEntryHangUpExtraSampleSeconds = TEXT("HangUpExtraSampleSeconds"); // // This file includes the definitions of c_ArrayOfRasFuncsW and c_ArrayOfRasFuncsUA below // #include "raslink.cpp" //+---------------------------------------------------------------------------- // // Function: LinkToRas // // Synopsis: Establishes the RAS linkage by populating the inputted RAS Linkage structure // with function pointers from Rasapi32.dll (on NT) or from cmutoa.dll (Unicode // to ANSI wrapper functions used on win9x). Most of the actual work is done // in LinkToDll, this function just does setup work to make sure the correct // entry points are searched for and that Cmutoa.dll is initialized properly (since it // needs to link to rasapi32.dll itself to get the actual ANSI RAS API's to work with). // // Arguments: RasLinkageStruct *prlsRasLink - pointer to a RAS Linkage structure. This // structure contains storage for pointers to // the RAS dll and all of the needed RAS // function pointers. // // Returns: BOOL - FALSE if *any* entry point is still not resolved. // // History: quintinb Created Header 01/04/2000 // //+---------------------------------------------------------------------------- BOOL LinkToRas(RasLinkageStruct *prlsRasLink) { BOOL bReturn = TRUE; // // Check inputs // if (NULL == prlsRasLink) { return FALSE; } if (OS_NT) { // // On NT we get our RAS APIs from rasapi32.dll and we ask for the W version // of the API. // if (OS_NT4) { c_ArrayOfRasFuncsW[11] = NULL; //RasDeleteSubEntry c_ArrayOfRasFuncsW[12] = NULL; //RasSetCustomAuthData c_ArrayOfRasFuncsW[13] = NULL; //RasGetEapUserIdentity c_ArrayOfRasFuncsW[14] = NULL; //RasFreeEapUserIdentity c_ArrayOfRasFuncsW[15] = NULL; //RasInvokeEapUI c_ArrayOfRasFuncsW[16] = NULL; //pfnGetCredentials c_ArrayOfRasFuncsW[17] = NULL; //pfnSetCredentials } else if (OS_W2K) { // // Special-casing for APIs that changed after Windows2000 shipped // c_ArrayOfRasFuncsW[11] = "DwDeleteSubEntry"; //RasDeleteSubEntry is DwDeleteSubEntry on Win2k } bReturn = LinkToDll(&prlsRasLink->hInstRas, "RASAPI32.DLL", c_ArrayOfRasFuncsW, prlsRasLink->apvPfnRas); } else { // // On Win9x we still want the W version of the API but since it isn't available we // call the wrappers in cmutoa.dll instead. Thus we use cmutoa.dll as our RAS API dll // and call the UA APIs. We also have an extra step because we want to make sure // that cmutoa.dll can actually initialize the RAS dll's that it uses for the UA // conversion functions. Thus we call cmutoa's InitCmRasUtoA function to set up // its internal RAS linkage. If this function fails, we must fail the RAS link. typedef BOOL (WINAPI *pfnInitCmRasUtoASpec)(void); pfnInitCmRasUtoASpec InitCmRasUtoA; HMODULE hCmUtoADll = LoadLibraryExA("cmutoa.DLL", NULL, 0); // REVIEW: this should use getmodulehandle so as not to change the refcount on the dll. if (!hCmUtoADll) { return FALSE; } // Get Initialization routine from the DLL InitCmRasUtoA = (pfnInitCmRasUtoASpec) GetProcAddress(hCmUtoADll, "InitCmRasUtoA") ; if (InitCmRasUtoA) { bReturn = InitCmRasUtoA(); if (bReturn) { if (!OS_MIL) { c_ArrayOfRasFuncsUA[10] = NULL; //RasSetSubEntryProperties c_ArrayOfRasFuncsUA[11] = NULL; //RasDeleteSubEntry } bReturn = LinkToDll(&prlsRasLink->hInstRas, "CMUTOA.DLL", c_ArrayOfRasFuncsUA, prlsRasLink->apvPfnRas); } } FreeLibrary(hCmUtoADll); // we want this to stay in memory but the refcount should also be correct } return bReturn; } BOOL IsRasLoaded(const RasLinkageStruct * const prlsRasLink) { UINT uIndex = 0; // // Did we get a valid pointer passed in and does that // struct contain a pointer to a RAS dll? // BOOL bReturn = (NULL != prlsRasLink) && (NULL != prlsRasLink->hInstRas); // // The list of functions we are checking for is different on NT // and Win9x. Note that we also assume that LinkToRas has already // been called so that the list of functions we are expecting will // have been modified for the exact platform that we are one. If // LinkToRas hasn't been called then the hInstRas param should be // NULL. // if (OS_NT) { while (bReturn && (NULL != c_ArrayOfRasFuncsW[uIndex])) { // // Check for a NULL function pointer when we have // a valid function name. // if (NULL == prlsRasLink->apvPfnRas[uIndex]) { bReturn = FALSE; } uIndex++; } } else { while (bReturn && (NULL != c_ArrayOfRasFuncsUA[uIndex])) { // // Check for a NULL function pointer when we have // a valid function name. // if (NULL == prlsRasLink->apvPfnRas[uIndex]) { bReturn = FALSE; } uIndex++; } } return bReturn; } //+---------------------------------------------------------------------------- // // Function: UnlinkFromRas // // Synopsis: This function tears down the linkage with RAS by freeing RAS dll's, calling // the cmutoa unklinkage function (if necessary), and zeroing the RAS Linkage // structure passed in. // // Arguments: RasLinkageStruct *prlsRasLink - pointer to a RAS Linkage structure. This // structure contains storage for pointers to // the RAS dll and all of the needed RAS // function pointers. // // Returns: Nothing // // History: quintinb Created Header 01/04/2000 // //+---------------------------------------------------------------------------- void UnlinkFromRas(RasLinkageStruct *prlsRasLink) { if (!OS_NT) { HMODULE hCmUtoADll = LoadLibraryExA("cmutoa.dll", NULL, 0); if (!hCmUtoADll) { CMASSERTMSG(FALSE, TEXT("UnlinkFromRas -- Unable to load cmutoa.")); return; } FARPROC FreeCmRasUtoA = GetProcAddress(hCmUtoADll, "FreeCmRasUtoA"); if (FreeCmRasUtoA) { FreeCmRasUtoA(); } FreeLibrary(hCmUtoADll); } if (prlsRasLink->hInstRas) { FreeLibrary(prlsRasLink->hInstRas); } memset(prlsRasLink,0,sizeof(RasLinkageStruct)); } // // GetRasModems: get a list of modem devices from RAS // //+---------------------------------------------------------------------------- // // Function: GetRasModems // // Synopsis: Enumerates the available RAS devices. The device list is allocated and passed // back to the caller through the pprdiRasDevInfo pointer. This allocated memory // must be freed by the caller. The count of available devices is stored in the // pdwCnt input parameter. // // Arguments: RasLinkageStruct *prlsRasLink - pointer to the RAS Linkage structure // LPRASDEVINFO *pprdiRasDevInfo - pointer to hold the RAS device list // LPDWORD pdwCnt - pointer to hold the count of devices // // Returns: BOOL - FALSE if unable to return the enumerated device list. // // History: quintinb Created Header 01/04/2000 // //+---------------------------------------------------------------------------- BOOL GetRasModems(const RasLinkageStruct *prlsRasLink, LPRASDEVINFO *pprdiRasDevInfo, LPDWORD pdwCnt) { DWORD dwLen; DWORD dwRes; DWORD dwCnt; if (pprdiRasDevInfo) { *pprdiRasDevInfo = NULL; } if (pdwCnt) { *pdwCnt = 0; } if (!prlsRasLink->pfnEnumDevices) { return (FALSE); } dwLen = 0; dwRes = prlsRasLink->pfnEnumDevices(NULL,&dwLen,&dwCnt); CMTRACE3(TEXT("GetRasModems() RasEnumDevices(NULL,pdwLen,&dwCnt) returns %u, dwLen=%u, dwCnt=%u."), dwRes, dwLen, dwCnt); if (((dwRes != ERROR_SUCCESS) && (dwRes != ERROR_BUFFER_TOO_SMALL)) || (dwLen < sizeof(**pprdiRasDevInfo))) { return (FALSE); } if (!pprdiRasDevInfo) { if (pdwCnt) { *pdwCnt = dwCnt; } return (TRUE); } *pprdiRasDevInfo = (LPRASDEVINFO) CmMalloc(__max(dwLen,sizeof(**pprdiRasDevInfo))); if (*pprdiRasDevInfo) { (*pprdiRasDevInfo)->dwSize = sizeof(**pprdiRasDevInfo); dwRes = prlsRasLink->pfnEnumDevices(*pprdiRasDevInfo,&dwLen,&dwCnt); CMTRACE3(TEXT("GetRasModems() RasEnumDevices(*pprdiRasDevInfo,&dwLen,&dwCnt) returns %u, dwLen=%u, dwCnt=%u."), dwRes, dwLen, dwCnt); if (dwRes != ERROR_SUCCESS) { CmFree(*pprdiRasDevInfo); *pprdiRasDevInfo = NULL; return (FALSE); } } else { CMASSERTMSG(FALSE, TEXT("GetRasModems -- CmMalloc failed to allocate memory for *pprdiRasDevInfo.")); return (FALSE); } if (pdwCnt) { *pdwCnt = dwCnt; } return (TRUE); } //+---------------------------------------------------------------------------- // // Function: PickModem // // Synopsis: // // Arguments: const pArgs, the pArgs->pIniProfile contains the modem name // OUT pszDeviceType, the device type if not NULL // OUT pszDeviceName, the device name if not NULL // OUT pfSameModem, Whether the modem found is the same as // the one in profile // // Returns: TRUE, is modem is found // // History: fengsun Created Header 10/24/97 // //+---------------------------------------------------------------------------- BOOL PickModem(IN const ArgsStruct *pArgs, OUT LPTSTR pszDeviceType, OUT LPTSTR pszDeviceName, OUT BOOL* pfSameModem) { LPRASDEVINFO prdiModems; DWORD dwCnt; LPTSTR pszModem; DWORD dwIdx; BOOL bFound = FALSE; // // First, get a list of modems from RAS // if (!GetRasModems(&pArgs->rlsRasLink,&prdiModems,&dwCnt) || dwCnt == 0) { return (FALSE); } if (pfSameModem) { *pfSameModem = FALSE; } // // Get the name of the current modem from the service profile and // try to find a match against non-tunnel RAS devices in the list // pszModem = pArgs->piniProfile->GPPS(c_pszCmSection, c_pszCmEntryDialDevice); if (*pszModem) { CMTRACE1(TEXT("PickModem() - looking for match with %s"), pszModem); for (dwIdx=0; dwIdx < dwCnt; dwIdx++) { CMTRACE2(TEXT("PickModem() - examining device (%s) of type (%s)"), prdiModems[dwIdx].szDeviceName, prdiModems[dwIdx].szDeviceType); // // we'll take only ISDN and modem devices // if (lstrcmpiU(prdiModems[dwIdx].szDeviceType, RASDT_Isdn) && lstrcmpiU(prdiModems[dwIdx].szDeviceType, RASDT_Modem) && lstrcmpiU(prdiModems[dwIdx].szDeviceType, RASDT_Atm)) { continue; } // // If we have a match, we're done here // if (lstrcmpiU(pszModem,prdiModems[dwIdx].szDeviceName) == 0) { CMTRACE(TEXT("PickModem() - match found.")); bFound = TRUE; if (pfSameModem) { *pfSameModem = TRUE; } break; } } } if (FALSE == bFound) { // // No match, find the first non-tunnel device and use it by default. // CMTRACE(TEXT("PickModem() - enumerating devices for default match against type RASDT_Isdn, RASDT_Modem or RASDT_Atm")); for (dwIdx=0; dwIdx < dwCnt; dwIdx++) { CMTRACE2(TEXT("PickModem() - examining device (%s) of type (%s)"), prdiModems[dwIdx].szDeviceName, prdiModems[dwIdx].szDeviceType); // // we'll take only ISDN and modem devices // if (!lstrcmpiU(prdiModems[dwIdx].szDeviceType, RASDT_Isdn) || !lstrcmpiU(prdiModems[dwIdx].szDeviceType, RASDT_Modem) || !lstrcmpiU(prdiModems[dwIdx].szDeviceType, RASDT_Atm)) { CMTRACE2(TEXT("PickModem() - default device (%s) of type (%s) selected."), prdiModems[dwIdx].szDeviceName, prdiModems[dwIdx].szDeviceType); bFound = TRUE; break; } } } // // If we have a match, fill device name and device type // if (bFound) { if (pszDeviceType) { lstrcpyU(pszDeviceType,prdiModems[dwIdx].szDeviceType); } if (pszDeviceName) { lstrcpyU(pszDeviceName,prdiModems[dwIdx].szDeviceName); } } CmFree(pszModem); CmFree(prdiModems); return (bFound); } //+---------------------------------------------------------------------------- // // Function: GetDeviceType // // Synopsis: Get the deviceType for a chosen device name // // Arguments: pArgs - Pointer to ArgsStruct // pszDeviceType[OUT] - pointer to buffer where device // type will be returned // uNumCharsInDeviceType [IN] - number of chars of memory available in pszDeviceType // pszDeviceName[IN] - device name // // Returns: TRUE on success, FALSE otherwise // // History: byao Created 03/21/97 //----------------------------------------------------------------------------- BOOL GetDeviceType(ArgsStruct *pArgs, LPTSTR pszDeviceType, UINT uNumCharsInDeviceType, LPTSTR pszDeviceName) { LPRASDEVINFO prdiModems; DWORD dwCnt, dwIdx; if (!pszDeviceType) { return FALSE; } // first, get a list of modems from RAS if (!GetRasModems(&pArgs->rlsRasLink,&prdiModems,&dwCnt)) { return (FALSE); } // choose the device that has the same name as pszDeviceName for (dwIdx=0;dwIdxrlsRasLink,&prdiModems,&dwCnt)) { return (FALSE); } // then, pick up the one used for tunneling bRes = PickTunnelDevice(pszDeviceType,pszDeviceName,prdiModems,dwCnt); CmFree(prdiModems); return (bRes); } //+---------------------------------------------------------------------------- // // Function: CopyAutoDial // // Synopsis: Sets the szAutodialDll and szAutodialFunc members of the // specified RAS entry structure with our module name and // InetDialHandler repectively. Not on NT5. // // Arguments: LPRASENTRY preEntry - Ptr to the Ras entry structure. // // Returns: Nothing // // History: nickball Created Header 03/16/98 // nickball Removed from NT5 11/17/98 // //+---------------------------------------------------------------------------- void CopyAutoDial(LPRASENTRY preEntry) { MYDBGASSERT(preEntry); // // Don't set these on NT5, they are no longer used by IE and the // InetDialHandler prototype differs from that used by RAS // if (OS_NT5 || NULL == preEntry) { return; } memset(preEntry->szAutodialDll,0,sizeof(preEntry->szAutodialDll)); // // Set szAutodialDll with our Module name // GetModuleFileNameU(g_hInst, preEntry->szAutodialDll, sizeof(preEntry->szAutodialDll)/sizeof(TCHAR)); // // Set szAutodialFunc with the mangled form of InetDialHandler // memset(preEntry->szAutodialFunc,0,sizeof(preEntry->szAutodialFunc)); lstrcpyU(preEntry->szAutodialFunc, c_pszInetDialHandler); } //+---------------------------------------------------------------------------- // // Function MyRGEP // // Synopsis Call RasGetEntryProperties() // // Arguments // // Returns // // Histroy Revised to improve performance 08/7/97 fengsun //----------------------------------------------------------------------------- LPRASENTRY MyRGEP(LPCTSTR pszRasPbk, LPCTSTR pszEntryName, RasLinkageStruct *prlsRasLink) { LPRASENTRY preRasEntry; DWORD dwRes; if (!(preRasEntry = AllocateRasEntry())) { MYDBGASSERT(0); return NULL; } DWORD dwRasEntry = preRasEntry->dwSize; dwRes = prlsRasLink->pfnGetEntryProperties(pszRasPbk, pszEntryName, preRasEntry, &dwRasEntry, NULL, // lpbDeviceInfo NULL); // lpdwDeviceInfoSize CMTRACE2(TEXT("MyRGEP() - dwRasEntry = %u : sizeof(*preRasEntry) = %u"), dwRasEntry, sizeof(*preRasEntry)); if ((dwRes == ERROR_BUFFER_TOO_SMALL) && (dwRasEntry >= sizeof(*preRasEntry))) { // // If the memory if not large enough, realloc one // CmFree(preRasEntry); preRasEntry = (LPRASENTRY) CmMalloc(dwRasEntry); if (NULL != preRasEntry) { // // dwSize has to be set to sizeof(RASENTRY) // because dwRasEntry contains the additional // bytes required for this connectoid (alternative // phone numbers, etc. // preRasEntry->dwSize = sizeof(RASENTRY); // Specifies version dwRes = prlsRasLink->pfnGetEntryProperties (pszRasPbk, pszEntryName, preRasEntry, &dwRasEntry, NULL, NULL); } else { MYDBGASSERT(0); return NULL; } } if (dwRes != ERROR_SUCCESS) { CMTRACE3(TEXT("MyRGEP(*pszRasPbk=%s, *pszEntryName=%s) RasGetEntryProperties returned %u"), pszRasPbk, pszEntryName, dwRes); CmFree(preRasEntry); preRasEntry = NULL; } SetLastError(dwRes); return (preRasEntry); } //+---------------------------------------------------------------------------- // // Function IsConnectErrorFatal // // Synopsis Determine if an error is recoverable, (ie. we should re-dial). // // Arguments DWORD dwErr - The RAS error code // ArgsStruct* pArgs - Ptr to global args struct // // Returns TRUE if error is fatal // // Histroy nickball Created header 05/21/99 // //----------------------------------------------------------------------------- BOOL IsConnectErrorFatal(DWORD dwErr, ArgsStruct *pArgs) { switch (dwErr) { // // The following cases are W9x ISDN error returns that actually mean // different things on WinNT. Since we use the NT header files, we don't // have an include file that contains these errors. We have to special // case these so that we recognize them as ISDN errors, and reconnect as // appropriate. // // The 9x errors are listed below along with the NT equivalents. // case 751: // 9x.ERROR_BAD_DEST_ADDRESS == NT.ERROR_INVALID_CALLBACK_NUMBER case 752: // 9x.ERROR_UNREACHABLE_DEST == NT.ERROR_SCRIPT_SYNTAX case 753: // 9x.ERROR_INCOMPATIBLE_DEST == NT.ERROR_HANGUP_FAILED case 754: // 9x.ERROR_NETWORK_CONGESTION == NT.ERROR_BUNDLE_NOT_FOUND case 755: // 9x.ERROR_CALL_BLOCKED == NT.ERROR_CANNOT_DO_CUSTOMDIAL case 756: // 9x.ERROR_NETWORK_TEMPFAILURE == NT.ERROR_DIAL_ALREADY_IN_PROGRESS if (OS_W9X) { // // On W9x, if you have an invalid ISDN number, the error codes // returned by Millennium RAS are different from the NT ones. // We have to special-case these by number so that we reconnect // CMTRACE1(TEXT("IsConnectErrorFatal : handled Win9x ISDN error %d"), dwErr); return FALSE; } break; case ERROR_PPP_TIMEOUT: // Timed out waiting for a valid response from the remote PPP peer.%0 case ERROR_PPP_REMOTE_TERMINATED: // PPP terminated by remote machine.%0 case ERROR_PPP_INVALID_PACKET: // The PPP packet is invalid.%0 case ERROR_PPP_NO_RESPONSE: // Remote PPP peer is not responding case ERROR_SERVER_NOT_RESPONDING: case ERROR_LINE_BUSY: case ERROR_NO_CARRIER: case ERROR_REMOTE_DISCONNECTION: case ERROR_BAD_ADDRESS_SPECIFIED: case ERROR_AUTOMATIC_VPN_FAILED: // New ras error for VPN return FALSE; break; case ERROR_NO_ANSWER: { // // For ISDN (Whistler bug#384223) we want to make sure CM displays the correct ras error (same as TAPI) // thus we have to treat this error as a fatal error. // This should return TRUE for the first time we are dialing and only dual-channel mode // if (0 == lstrcmpiU(pArgs->szDeviceType, RASDT_Isdn) && (pArgs->nMaxRedials == pArgs->nRedialCnt)) { if (CM_ISDN_MODE_DUALCHANNEL_ONLY == pArgs->dwIsdnDialMode) { return TRUE; } } return FALSE; break; } default: break; } return TRUE; } //+---------------------------------------------------------------------------- // // Function IsRasError // // Synopsis Simple function to determine if an error falls in the RAS range // // Arguments DWORD dwErr - The error code // // Returns TRUE if error is within RAS range // // Histroy nickball Created header 05/21/99 // //----------------------------------------------------------------------------- inline BOOL IsRasError(DWORD dwErr) { return ((dwErr >= RASBASE) && (dwErr <= RASBASEEND)); } //+---------------------------------------------------------------------------- // // Function CheckConnectionError // // Synopsis Determine if a RAS error is recoverable. If not recoverable, // retrieves the appropriate error message for display. // // Arguments DWORD dwErr - The RAS error code // ArgsStruct* pArgs - Ptr to global args struct // BOOL fTunneling - Flag indicating whether we're tunneling // LPTSTR *ppszRasErrMsg - Pointer to pointer for message string // // Returns TRUE if error is fatal // // Histroy nickball Created header 05/21/99 // //----------------------------------------------------------------------------- BOOL CheckConnectionError(HWND hwndDlg, DWORD dwErr, ArgsStruct *pArgs, BOOL fTunneling, LPTSTR *ppszRasErrMsg) { DWORD dwIdMsg = 0; LPTSTR pszMsg = NULL; LPTSTR pszTmp = NULL; // // Examine the error more closely. Note: For W2K, we skip RAS // errors and query RAS for a displayable error string below. // if ((!OS_NT5) || (!IsRasError(dwErr))) { switch (dwErr) { case ERROR_PPP_TIMEOUT: // Timed out waiting for a valid response from the remote PPP peer.%0 case ERROR_PPP_REMOTE_TERMINATED: // PPP terminated by remote machine.%0 case ERROR_PPP_INVALID_PACKET: // The PPP packet is invalid.%0 case ERROR_PPP_NO_RESPONSE: // Remote PPP peer is not responding case ERROR_SERVER_NOT_RESPONDING: dwIdMsg = IDMSG_PPPPROBLEM; break; case ERROR_LINE_BUSY: if ((pArgs->nDialIdx+1 == MAX_PHONE_NUMBERS || !pArgs->aDialInfo[pArgs->nDialIdx+1].szDialablePhoneNumber[0]) && !pArgs->nRedialCnt) dwIdMsg = IDMSG_LINEBUSY; else dwIdMsg = IDMSG_LINEBUSYREDIAL; break; case ERROR_NO_ANSWER: case ERROR_NO_CARRIER: if ((pArgs->nDialIdx+1 == MAX_PHONE_NUMBERS || !pArgs->aDialInfo[pArgs->nDialIdx+1].szDialablePhoneNumber[0]) && !pArgs->nRedialCnt) dwIdMsg = fTunneling ? IDMSG_TUNNEL_NOANSWER : IDMSG_NOANSWER ; else dwIdMsg = fTunneling ? IDMSG_TUNNEL_NOANSWERREDIAL : IDMSG_NOANSWERREDIAL; break; case ERROR_REMOTE_DISCONNECTION: dwIdMsg = IDMSG_REMOTEDISCONNECTED; break; case ERROR_BAD_ADDRESS_SPECIFIED: dwIdMsg = IDMSG_TUNNEL_NOANSWERREDIAL; break; case ERROR_PPP_NO_PROTOCOLS_CONFIGURED: // No PPP control protocols configured.%0 dwIdMsg = IDMSG_TCPIPPROBLEM; break; case ERROR_PORT_ALREADY_OPEN: dwIdMsg = fTunneling ? IDMSG_TUNNELINUSE : IDMSG_PORTINUSE ; break; case ERROR_FROM_DEVICE: dwIdMsg = IDMSG_DEVICEERROR; break; case ERROR_HARDWARE_FAILURE: case ERROR_PORT_OR_DEVICE: //11694 case ERROR_DEVICE_NOT_READY: dwIdMsg = IDMSG_NOTRESPONDING; break; case ERROR_NO_DIALTONE: dwIdMsg = IDMSG_NODIALTONE; break; case ERROR_CANCELLED: case ERROR_USER_DISCONNECTION: dwIdMsg = IDMSG_CANCELED; break; case ERROR_AUTHENTICATION_FAILURE: case ERROR_ACCESS_DENIED: // 13795 // WINDOWS ERROR dwIdMsg = IDMSG_BADPASSWORD; break; case ERROR_VOICE_ANSWER: dwIdMsg = IDMSG_VOICEANSWER; break; case ERROR_PORT_NOT_AVAILABLE: if (IsDialingTunnel(pArgs)) { dwIdMsg = IDMSG_TUNNELNOTAVAILABLE; } else { dwIdMsg = IDMSG_PORTNOTAVAILABLE; } break; case ERROR_PORT_NOT_CONFIGURED: dwIdMsg = IDMSG_PORTNOTCONFIGURED; break; case ERROR_RESTRICTED_LOGON_HOURS: dwIdMsg = IDMSG_RESTRICTEDLOGONHOURS; break; case ERROR_ACCT_DISABLED: case ERROR_ACCT_EXPIRED: dwIdMsg = IDMSG_ACCTDISABLED; break; case ERROR_PASSWD_EXPIRED: dwIdMsg = IDMSG_PASSWDEXPIRED; break; case ERROR_NO_DIALIN_PERMISSION: dwIdMsg = IDMSG_NODIALINPERMISSION; break; case ERROR_PROTOCOL_NOT_CONFIGURED: dwIdMsg = IDMSG_PROTOCOL_NOT_CONFIGURED; break; case ERROR_INVALID_DATA: // WINDOWS ERROR // // The specific case in which we encountered DUN settings // that aren't supported on the current platform // CMTRACE(TEXT("CheckConnectionError - Unsupported DUN setting detected")); dwIdMsg = IDMSG_UNSUPPORTED_SETTING; break; case ERROR_BAD_PHONE_NUMBER: // TBD - drop through to default default: break; } } if (0 == dwIdMsg) { // // If no message ID was picked up, then try to get one from RAS // if (pArgs->rlsRasLink.pfnGetErrorString) { DWORD dwRes; DWORD dwFmtMsgId; pszTmp = (LPTSTR) CmMalloc(256 * sizeof(TCHAR)); // Docs say 256 chars is always enough. if (pszTmp) { dwRes = pArgs->rlsRasLink.pfnGetErrorString((UINT) dwErr, pszTmp, (DWORD) 256); if (ERROR_SUCCESS == dwRes) { pszMsg = CmFmtMsg(g_hInst, IDMSG_RAS_ERROR, pszTmp, dwErr); } } CmFree(pszTmp); } if (NULL == pszMsg) { // // Still no message, try to get description from system (on NT) // Note: HRESULTS are displayed in Hex, Win errors are decimal. if (OS_NT) { if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + FORMAT_MESSAGE_IGNORE_INSERTS + FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, 0, (LPTSTR) &pszTmp, 1, NULL)) { if (pszTmp) { pszMsg = CmFmtMsg(g_hInst, (dwErr > 0x7FFFFFFF) ? IDMSG_SYS_ERROR_HEX : IDMSG_SYS_ERROR_DEC, pszTmp, dwErr); LocalFree(pszTmp); } else { CMASSERTMSG(FALSE, TEXT("CheckConnectionError -- FormatMessage failed to allocate pszTmp.")); } } } if (NULL == pszMsg) { // // Still no message, go with default // pszMsg = CmFmtMsg(g_hInst, (dwErr > 0x7FFFFFFF) ? IDMSG_CM_ERROR_HEX : IDMSG_CM_ERROR_DEC, dwErr); } } } // // Special check for tunneling to verify that we have a device name // if (IsDialingTunnel(pArgs)) { // // Check whether the tunnel device name is valid // if (!PickTunnelDevice(pArgs,pArgs->szTunnelDeviceType,pArgs->szTunnelDeviceName)) { pArgs->szTunnelDeviceName[0]= TEXT('\0'); pArgs->piniProfile->WPPS(c_pszCmSection, c_pszCmEntryTunnelDevice, TEXT("")); pszMsg = CmLoadString(g_hInst, GetPPTPMsgId()); dwIdMsg = 0; } pArgs->piniProfile->WPPS(c_pszCmSection, c_pszCmEntryTunnelDevice, pArgs->szTunnelDeviceName); } // // If we have a message ID format it for display // if (dwIdMsg) { MYDBGASSERT(!pszMsg); pszMsg = CmFmtMsg(g_hInst,dwIdMsg); } if (pszMsg) { if (!ppszRasErrMsg) { AppendStatusPane(hwndDlg,pszMsg); CmFree(pszMsg); } else { // // pass the msg to the caller. the caller needs to free it. // *ppszRasErrMsg = pszMsg; } } BOOL bCancel = IsConnectErrorFatal(dwErr, pArgs); if (bCancel && dwErr != ERROR_CANCELLED && dwErr != ERROR_AUTHENTICATION_FAILURE && dwErr != ERROR_ACCESS_DENIED) { // // if we're canceling redial, then there might be something // seriously wrong. We want to recheck our configs the next // time CM is run. // ClearComponentsChecked(); } return (bCancel); } //+---------------------------------------------------------------------------- // // Function GetRasConnectoidName // // Synopsis Construct a RAS connectoid name. // // The connectoid name is "-[Primary|Backup]". // or "&Tunnel" for the case of tunnel entry. // // Arguments pArgs Pointer to ArgsStruct // piniService[IN] the service obj // fTunnelEntry[IN] TRUE: This connectoid is for tunneling // FALSE: otherwise // // Returns LPTSTR The connectoid name. // //----------------------------------------------------------------------------- LPTSTR GetRasConnectoidName( ArgsStruct *pArgs, CIni* piniService, BOOL fTunnelEntry ) { LPTSTR pszConnectoid = GetServiceName(piniService); if (pszConnectoid) { // // If tunneling 9X connectoid, append the Tunnel // Suffix - e.g. "Tunnel (for advanced use only)" // if (OS_W9X && fTunnelEntry) { LPTSTR pszSuffix = GetTunnelSuffix(); if (pszSuffix) { pszConnectoid = CmStrCatAlloc(&pszConnectoid, pszSuffix); } CmFree(pszSuffix); } } return pszConnectoid; } //+---------------------------------------------------------------------------- // // Function CreateRASEntryStruct // // Synopsis Create a connectoid with the settings specified in the cms. // If a parameter does NOT exist in the cms file, the corresponding // value is used. // // The connectoid name is "-[Primary|Backup]". // or "&Tunnel" for the case of tunnel entry. // // Arguments pArgs Pointer to ArgsStruct // pszDUN DUN name // piniService[IN] the service file obj // fTunnelEntry[IN] TRUE: This connectoid is for tunneling // FALSE: otherwise // pszRasPbk the RAS phonebook in which the connectoid is located // ppbEapData[OUT] Address of pointer to store EapData, allocated here. // pdwEapSize[OUT] Ptr to a DWORD to record the size of the data blob. // // Returns LPRASENTRY The new RAS connectoid // // History 5/12/97 henryt created // 5/23/97 byao Modified: added fSkipProfile flag // 6/9/97 byao Modified: use DUN= field when the // phone number has no DUN name associated // 7/28/97 byao Added change for #10459 // 4/13/97 nickball Renamed, return LPRASENTRY //----------------------------------------------------------------------------- LPRASENTRY CreateRASEntryStruct( ArgsStruct *pArgs, LPCTSTR pszDUN, CIni* piniService, BOOL fTunnelEntry, LPTSTR pszRasPbk, LPBYTE *ppbEapData, LPDWORD pdwEapSize ) { LPTSTR pszDunEntry = NULL; DWORD dwErr; BOOL bTmp; // // first we need to create a RAS entry in memory with default values // LPRASENTRY preBuffer = AllocateRasEntry(); if (!preBuffer) { return NULL; } MYDBGASSERT(preBuffer->dwSize >= sizeof(*preBuffer)); // // Set up the preBuffer to defaults value // preBuffer->dwFramingProtocol = RASFP_Ppp; // // Allow only TCP/IP by default // preBuffer->dwfNetProtocols |= RASNP_Ip; // // Set default RASEO settings. // if (!fTunnelEntry) { preBuffer->dwfOptions |= RASEO_UseCountryAndAreaCodes | RASEO_IpHeaderCompression | RASEO_RemoteDefaultGateway | RASEO_SwCompression; //RASEO_SecureLocalFiles; // NT 427042 //RASEO_DisableLcpExtensions; //13059 Olympus + 289461 NT // // We want to honor the HideTrayIcon flag. If it is not NT5, then // we always set this flag. If it is NT5, then we should only set // this flag if HideTrayIcon is false. // if (!OS_NT5 || !(pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryHideTrayIcon))) { preBuffer->dwfOptions |= RASEO_ModemLights; } // // In order for users to be able to specify device settings on Whistler, // they have to do it from the control panel and we have to set the // RASEO2_UseGlobalDeviceSettings flag in dwfOptions2. // if (OS_NT51) { ((LPRASENTRY_V501)preBuffer)->dwfOptions2 |= RASEO2_UseGlobalDeviceSettings; } // // We should have the devicename/devicetype by now. // (PickModem should be called) // MYDBGASSERT(pArgs->szDeviceType[0]); MYDBGASSERT(pArgs->szDeviceName[0]); lstrcpynU(preBuffer->szDeviceType, pArgs->szDeviceType, sizeof(preBuffer->szDeviceType)/sizeof(TCHAR)); lstrcpynU(preBuffer->szDeviceName, pArgs->szDeviceName, sizeof(preBuffer->szDeviceName)/sizeof(TCHAR)); } else { preBuffer->dwfOptions = RASEO_IpHeaderCompression | RASEO_RemoteDefaultGateway | RASEO_NetworkLogon | RASEO_SwCompression; //RASEO_SecureLocalFiles // NT 427042 //RASEO_DisableLcpExtensions // // Always set Modem lights on direct connection, unless HideTrayIcon // flag is explicitly set in the .CMS. #262825, #262988 // if (!(pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryHideTrayIcon))) { preBuffer->dwfOptions |= RASEO_ModemLights; } MYDBGASSERT(pArgs->szTunnelDeviceType[0]); MYDBGASSERT(pArgs->szTunnelDeviceName[0]); lstrcpynU(preBuffer->szDeviceType, pArgs->szTunnelDeviceType, sizeof(preBuffer->szDeviceType)/sizeof(TCHAR)); lstrcpynU(preBuffer->szDeviceName, pArgs->szTunnelDeviceName, sizeof(preBuffer->szDeviceName)/sizeof(TCHAR)); lstrcpyU(preBuffer->szLocalPhoneNumber, pArgs->GetTunnelAddress()); } // // Check to see if we need to tell RAS that this connection has Internet Connectivity or not // if (OS_NT51) { // // Note that we use the top level service profile on purpose here (pArgs->pIniService directly) // as this is a profile global setting. // if (pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryInternetConnection, (BOOL) ((LPRASENTRY_V501)preBuffer)->dwfOptions2 & RASEO2_Internet)) { ((LPRASENTRY_V501)preBuffer)->dwfOptions2 |= RASEO2_Internet; } else { ((LPRASENTRY_V501)preBuffer)->dwfOptions2 &= ~RASEO2_Internet; } } // // If we have a specific DUN name to use, then // use it instead of the default DUN setting in the .CMS. // if (pszDUN && *pszDUN) { pszDunEntry = CmStrCpyAlloc(pszDUN); } else { pszDunEntry = GetDefaultDunSettingName(piniService, fTunnelEntry); } // // If we have a DUN setting name, read the settings from cms // if (pszDunEntry && *pszDunEntry) { dwErr = (DWORD)ReadDUNSettings(pArgs, piniService->GetFile(), pszDunEntry, preBuffer, ppbEapData ,pdwEapSize, fTunnelEntry); if (ERROR_SUCCESS != dwErr) { CMTRACE(TEXT("UpdateRASConnectoid: ReadDUNSettings failed")); CmFree(preBuffer); preBuffer = NULL; goto exit; } } // // Get autodial information, store in preBuffer // CopyAutoDial(preBuffer); // // disable the RAS wizard on Win95 // if (OS_W9X) { DisableWin95RasWizard(); } exit: if (pszDunEntry) { CmFree(pszDunEntry); } SetLastError(dwErr); return preBuffer; } //+---------------------------------------------------------------------------- // // Function CreateRasPrivatePbk // // Synopsis Create the private RAS phone book and returns the full path. // // Arguments pArgs Pointer to global Args struct // // Returns LPTSTR The full path name of the newly created private pbk // // History ??/??/97 henryt created // // 01/15/99 Jeffspr Changed the GetTempFileName pattern, // as it was using more than the allowed/ // used 3 chars, plus made the failure // case use the same pattern (we will // filter on this in the connection // enumerator to ignore these entries). // // 05/21/99 nickball Added allocation, removed input buf // 04/10/00 quintinb Removed GetTempFileName as we no longer // want this file to be temporary. Changed // the function to create a file named _cmphone.pbk // in the profile directory. // Please see Whistler bug 15812 for details. // 07/05/00 t-urama Changed the path to the hidden pbk to point // to the RAS pbk. // //----------------------------------------------------------------------------- LPTSTR CreateRasPrivatePbk(ArgsStruct *pArgs) { // // No private PBK on win9x, everything is in the registry. // if (OS_W9X) { return NULL; } if (NULL == pArgs) { MYDBGASSERT(pArgs); return NULL; } LPTSTR pszHiddenPbkPath = NULL; LPCTSTR pszCmp = pArgs->piniProfile->GetFile(); // // This version of the function uses the function GetPathToPbk in connect.cpp to find the path // to the phone book. The hidden phone book also has to be created in the same directory. // if (pszCmp) { LPTSTR pszRasPbkDir = GetPathToPbk(pszCmp, pArgs); MYDBGASSERT(pszRasPbkDir); if (pszRasPbkDir) { pszHiddenPbkPath = (LPTSTR) CmMalloc((lstrlen(pszRasPbkDir) + lstrlen(CM_PBK_FILTER_PREFIX) + 7) * sizeof(TCHAR)); if (pszHiddenPbkPath) { wsprintfU(pszHiddenPbkPath, TEXT("%s\\%sphone"), pszRasPbkDir, CM_PBK_FILTER_PREFIX); MYDBGASSERT(pszHiddenPbkPath); HANDLE hFile = INVALID_HANDLE_VALUE; SECURITY_ATTRIBUTES sa = {0}; PSECURITY_ATTRIBUTES pSA = NULL; PSECURITY_DESCRIPTOR pSd = NULL; if (OS_NT5 && pArgs->fAllUser) { // // Be sure to create it with a security descriptor that // allows it to be read by any authenticated user. If we don't it may // prevent other users from being able to read it. We didn't want to // change the old behavior downlevel so this fix is just for Whistler+. // DWORD dwErr = AllocateSecurityDescriptorAllowAccessToWorld(&pSd); if ((ERROR_SUCCESS == dwErr) && pSd) { sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = pSd; sa.bInheritHandle = TRUE; pSA = &sa; } } hFile = CreateFileU(pszHiddenPbkPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, pSA, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); CmFree(pSd); if (hFile == INVALID_HANDLE_VALUE) { DWORD dwLastError = GetLastError(); MYDBGASSERT(hFile != INVALID_HANDLE_VALUE); CMTRACE1(TEXT("CreateRasPrivatePbk - CreateFileU failed. GetLastError = %d"), dwLastError); } CloseHandle(hFile); } else { CMASSERTMSG(FALSE, TEXT("CreateRasPrivatePbk -- CmMalloc returned NULL for pszHiddenPbkPath")); } CmFree(pszRasPbkDir); } } return pszHiddenPbkPath; } //+---------------------------------------------------------------------------- // // Function GetPathToPbk // // Synopsis This function is a helper function called by // CheckAccessToCmpAndPbk in connect.cpp and by // CreateRasPrivatePbk. It returns the path to the RAS // phonebook. // // Arguments LPTSTR pszCmp - The path to the cmp file // LPTSTR pszRasPbk - The string to store the result // ArgsStruct *pArgs - pArgs // // Returns NONE // // History 07/05/00 t-urama created //----------------------------------------------------------------------------- LPTSTR GetPathToPbk(LPCTSTR pszCmp, ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return NULL; } MYDBGASSERT(pszCmp); if (NULL == pszCmp) { return NULL; } LPTSTR pszRasPbk = NULL; // // pszRasPbk could be NULL if we are on NT4 or we are using the // all user default phonebook. // if (NULL == pArgs->pszRasPbk) { if (OS_NT4) { DWORD dwSize = (MAX_PATH + 1); DWORD dwRet; BOOL bExitLoop = TRUE; do { pszRasPbk = (LPTSTR)CmMalloc(dwSize*sizeof(TCHAR)); if (pszRasPbk) { dwRet = GetSystemDirectoryU(pszRasPbk, dwSize); if (dwRet) { if (dwRet > dwSize) { dwSize = dwRet + 1; bExitLoop = FALSE; // we didn't get all of the string, try again CmFree(pszRasPbk); } else { bExitLoop = TRUE; CmStrCatAlloc(&pszRasPbk, c_pszRasDirRas); } } else { CmFree(pszRasPbk); pszRasPbk = NULL; } } else { CMASSERTMSG(FALSE, TEXT("GetPathToPbk -- CmMalloc failed!")); return NULL; } } while (!bExitLoop); } else { pszRasPbk = CmStrCpyAlloc(pszCmp); if (pszRasPbk) { LPTSTR pszSlash = CmStrrchr(pszRasPbk, TEXT('\\')); if (pszSlash) { *pszSlash = TEXT('\0'); // remove .cmp pszSlash = CmStrrchr(pszRasPbk, TEXT('\\')); if (pszSlash) { *pszSlash = TEXT('\0'); CmStrCatAlloc(&pszRasPbk, TEXT("\\")); CmStrCatAlloc(&pszRasPbk, c_pszPbk); } else { CMASSERTMSG(FALSE, TEXT("GetPathToPbk -- unable to convert cmp path to pbk path.")); CmFree(pszRasPbk); pszRasPbk = NULL; } } else { CMASSERTMSG(FALSE, TEXT("GetPathToPbk -- unable to convert cmp path to pbk path!")); CmFree(pszRasPbk); pszRasPbk = NULL; } } } } else { pszRasPbk = CmStrCpyAlloc(pArgs->pszRasPbk); LPTSTR pszSlash = CmStrrchr(pszRasPbk, TEXT('\\')); if (pszSlash) { *pszSlash = TEXT('\0'); // remove the RAS phonebook name } else { CMASSERTMSG(FALSE, TEXT("GetPathToPbk -- unable to convert RAS pbk name to pbk path!")); CmFree(pszRasPbk); pszRasPbk = NULL; } } return pszRasPbk; } //+---------------------------------------------------------------------------- // // Function DisableWin95RasWizard // // Synopsis This function disable the Win95 Dial-up Networking wizard // by writing a dword reg value 0x00000080 in the registry. // // Arguments NONE // // Returns NONE // // History 7/1/97 henryt created //----------------------------------------------------------------------------- void DisableWin95RasWizard( void) { HKEY hkReg = NULL; LONG lRes; DWORD dwSize; DWORD dwType; DWORD dwValue; lRes = RegOpenKeyExA(HKEY_CURRENT_USER, c_pszRegRemoteAccess, 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hkReg); if (ERROR_SUCCESS != lRes) { CMTRACE1(TEXT("DisableWin95RasWizard() RegOpenKeyEx() failed, GLE=%u."), lRes); goto exit; } // // see if we already have a value there. // dwSize = sizeof(DWORD); lRes = RegQueryValueExA(hkReg, c_pszRegWizard, NULL, &dwType, (LPBYTE)&dwValue, &dwSize); if (lRes == ERROR_SUCCESS && dwSize == sizeof(DWORD) && dwType == REG_BINARY && dwValue == ICM_RAS_REG_WIZARD_VALUE) { CMTRACE(TEXT("DisableWin95RasWizard() RegQueryValueEx() - found correct value.")); goto exit; } // // well, the value is not in reg yet. we need to create the value. // dwValue = ICM_RAS_REG_WIZARD_VALUE; lRes = RegSetValueExA(hkReg, c_pszRegWizard, 0, REG_BINARY, (LPBYTE)&dwValue, sizeof(dwValue)); #ifdef DEBUG if (ERROR_SUCCESS != lRes) { CMTRACE1(TEXT("DisableWin95RasWizard() RegSetValueEx() failed, GLE=%u."), lRes); } #endif exit: if (hkReg) { lRes = RegCloseKey(hkReg); #ifdef DEBUG if (ERROR_SUCCESS != lRes) { CMTRACE1(TEXT("DisableWin95RasWizard() RegCloseKey() failed, GLE=%u."), lRes); } #endif } return; } //+---------------------------------------------------------------------------- // // Function SetIsdnDualChannelEntries // // Synopsis As what the func name says. We prepare the RASENTRY and // RASSUBENTRY properly. We don't actually make RAS calls to // save the entries. We'll leave it to the caller(so that the // can make other changes to the structs for other reasons and // commit the changes in 1 or 2 RAS calls). // // Arguments pArgs [IN] Pointer to ArgsStruct // pRasEntry [IN/OUT] rasentry to be filled // ppRasSubEntry [OUT] pointer to be filled with the subentry array // The buffer is allocated in this function. // pdwSubEntryCount Number of subentries allocated. // // Returns BOOL TRUE = success, FALSE = failure. // //----------------------------------------------------------------------------- BOOL SetIsdnDualChannelEntries(ArgsStruct *pArgs, LPRASENTRY pRasEntry, LPRASSUBENTRY *ppRasSubEntry, PDWORD pdwSubEntryCount) { // // Lets check the input parameters // MYDBGASSERT(pArgs); MYDBGASSERT(pRasEntry); MYDBGASSERT(ppRasSubEntry); MYDBGASSERT(pdwSubEntryCount); if ((NULL == pArgs) || (NULL == pRasEntry) || (NULL == ppRasSubEntry) || (NULL == pdwSubEntryCount)) { return FALSE; } // // Since we don't support BAP if they called this function they must have wanted // to do DualChannel ISDN. If the dial mode isn't set for dual channel, we will // assert an continue. Better to connect the user in dual channel mode then not // at all if they have a misconfigured profile. // MYDBGASSERT(pArgs->dwIsdnDialMode != CM_ISDN_MODE_SINGLECHANNEL); // // Check the size of the passed in RasEntry struct. If it isn't at least // a 4.01 size struct, then return. // MYDBGASSERT(pRasEntry->dwSize >= sizeof(LPRASENTRY_V401)); if (sizeof(LPRASENTRY_V401) > pRasEntry->dwSize) { return FALSE; } LPRASENTRY_V401 pRasEntry401 = (LPRASENTRY_V401)pRasEntry; // // set isdn dial mode to dial both channels // pRasEntry401->dwDialMode = RASEDM_DialAll; CMTRACE(TEXT("ISDN Dual Channel Mode On")); if (OS_NT) { *pdwSubEntryCount = 2; } else if (OS_MIL) { // 112351: 9x only requires one sub entry. We'll keep the device name the same. // In this case, Win9x will work as follows: // for the 1st channel, the device name provided works fine. // for the 2nd channel, 9x sees the device is in use and looks for the // the closest match (which is the 2nd channel). // *pdwSubEntryCount = 1; } else { CMASSERTMSG(FALSE, TEXT("SetIsdnDualChannelEntries -- Function called on a platform other than NT or Millennium.")); return FALSE; } // // Allocate the sub entries // *ppRasSubEntry = (LPRASSUBENTRY)CmMalloc((*pdwSubEntryCount)*(sizeof(RASSUBENTRY))); if (NULL == *ppRasSubEntry) { CMASSERTMSG(FALSE, TEXT("SetIsdnDualChannelEntries -- CmMalloc failed to alloc ppRasSubEntry.")); return FALSE; } // // Fill in the sub entries with the device and phonenumber information // for (DWORD dwIndex=0; dwIndex < (*pdwSubEntryCount); dwIndex++) { (*ppRasSubEntry)[dwIndex].dwSize = sizeof(RASSUBENTRY); lstrcpyU((*ppRasSubEntry)[dwIndex].szDeviceType, pArgs->szDeviceType); lstrcpyU((*ppRasSubEntry)[dwIndex].szDeviceName, pArgs->szDeviceName); lstrcpyU((*ppRasSubEntry)[dwIndex].szLocalPhoneNumber, pRasEntry401->szLocalPhoneNumber); } return TRUE; } // // Keep in case we ever want to support BAP // /* BOOL SetIsdnDualChannelEntries( ArgsStruct *pArgs, LPRASENTRY pre, LPRASSUBENTRY *prgrse, PDWORD pdwSubEntryCount ) { LPRASENTRY_V401 pre401; MYDBGASSERT(pArgs->dwIsdnDialMode != CM_ISDN_MODE_SINGLECHANNEL); MYDBGASSERT(pre->dwSize >= sizeof(LPRASENTRY_V401)); pre401 = (LPRASENTRY_V401)pre; // // set isdn dial mode // if (pArgs->dwIsdnDialMode == CM_ISDN_MODE_DIALALL) { // // dial both channels // pre401->dwDialMode = RASEDM_DialAll; CMTRACE(TEXT("ISDN Dual Channel Mode On")); } else { // // dial 2nd channel on demand // // // First get the 4 thresholds // if (!pArgs->dwDialExtraPercent) { pArgs->dwDialExtraPercent = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryDialExtraPercent, DEFAULT_DIALEXTRAPERCENT); if (pArgs->dwDialExtraPercent < 0 || pArgs->dwDialExtraPercent > 100) { pArgs->dwDialExtraPercent = DEFAULT_DIALEXTRAPERCENT; } } if (!pArgs->dwDialExtraSampleSeconds) { pArgs->dwDialExtraSampleSeconds = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryDialExtraSampleSeconds, DEFAULT_DIALEXTRASAMPLESECONDS); if (pArgs->dwDialExtraSampleSeconds < 0) { pArgs->dwDialExtraSampleSeconds = DEFAULT_DIALEXTRASAMPLESECONDS; } } if (!pArgs->dwHangUpExtraPercent) { pArgs->dwHangUpExtraPercent = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryHangUpExtraPercent, DEFAULT_HANGUPEXTRAPERCENT); if (pArgs->dwHangUpExtraPercent < 0 || pArgs->dwHangUpExtraPercent > 100) { pArgs->dwHangUpExtraPercent = DEFAULT_HANGUPEXTRAPERCENT; } } if (!pArgs->dwHangUpExtraSampleSeconds) { pArgs->dwHangUpExtraSampleSeconds = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryHangUpExtraSampleSeconds, DEFAULT_HANGUPEXTRASAMPLESECONDS); if (pArgs->dwHangUpExtraSampleSeconds < 0) { pArgs->dwHangUpExtraSampleSeconds = DEFAULT_HANGUPEXTRASAMPLESECONDS; } } // // set multilink info // pre401->dwDialMode = RASEDM_DialAsNeeded; pre401->dwDialExtraPercent = pArgs->dwDialExtraPercent; pre401->dwDialExtraSampleSeconds = pArgs->dwDialExtraSampleSeconds; pre401->dwHangUpExtraPercent = pArgs->dwHangUpExtraPercent; pre401->dwHangUpExtraSampleSeconds = pArgs->dwHangUpExtraSampleSeconds; CMTRACE2(TEXT("ISDN 2nd Channel Dial On Demand: dial extra %u%%, dial extra %u sample secs"), pre401->dwDialExtraPercent, pre401->dwDialExtraSampleSeconds); CMTRACE2(TEXT("\t\thangup extra %u%%, hangup extra %u sample secs"), pre401->dwHangUpExtraPercent, pre401->dwHangUpExtraSampleSeconds); } if (OS_NT) { if (!(*prgrse = (LPRASSUBENTRY)CmMalloc(2*sizeof(RASSUBENTRY)))) { CMTRACE(TEXT("SetIsdnDualChannelEntries failed to alloc a ras sub entry")); return FALSE; } ZeroMemory((PVOID)*prgrse, 2*sizeof(RASSUBENTRY)); // // first channel // (*prgrse)[0].dwSize = sizeof(RASSUBENTRY); lstrcpyU((*prgrse)[0].szDeviceType, pArgs->szDeviceType); lstrcpyU((*prgrse)[0].szDeviceName, pArgs->szDeviceName); lstrcpyU((*prgrse)[0].szLocalPhoneNumber, pre401->szLocalPhoneNumber); // // the 2nd channel is identical // CopyMemory((PVOID)(*prgrse + 1), (PVOID)*prgrse, sizeof(RASSUBENTRY)); *pdwSubEntryCount = 2; } else { MYDBGASSERT(OS_MIL); CMTRACE(TEXT("doing the Millennium subentry stuff")); // 112351: 9x only requires one sub entry. We'll keep the device name the same. // In this case, Win9x will work as follows: // for the 1st channel, the device name provided works fine. // for the 2nd channel, 9x sees the device is in use and looks for the // the closest match (which is the 2nd channel). // if (!(*prgrse = (LPRASSUBENTRY)CmMalloc(1*sizeof(RASSUBENTRY)))) { CMTRACE(TEXT("SetIsdnDualChannelEntries failed to alloc a ras sub entry")); return FALSE; } ZeroMemory((PVOID)*prgrse, 1*sizeof(RASSUBENTRY)); // // 2nd channel // (*prgrse)[0].dwSize = sizeof(RASSUBENTRY); lstrcpyU((*prgrse)[0].szDeviceType, pArgs->szDeviceType); lstrcpyU((*prgrse)[0].szDeviceName, pArgs->szDeviceName); lstrcpyU((*prgrse)[0].szLocalPhoneNumber, pre401->szLocalPhoneNumber); *pdwSubEntryCount = 1; } return TRUE; } */ //+---------------------------------------------------------------------------- // // Function SetNtIdleDisconnectInRasEntry // // Synopsis As what the func name says. We prepare the RASENTRY and // RASSUBENTRY properly. We don't actually make RAS calls to // save the entries. We'll leave it to the caller(so that the // can make other changes to the structs for other reasons and // commit the changes in 1 or 2 RAS calls). // // Arguments pArgs [IN] Pointer to ArgsStruct // pre [OUT] Pointer to RASENTRY with the correct size // // Returns BOOL TRUE = success, FALSE = failure. // //----------------------------------------------------------------------------- BOOL SetNtIdleDisconnectInRasEntry( ArgsStruct *pArgs, LPRASENTRY pre ) { if (!OS_NT4) { return FALSE; } if ((NULL == pArgs) || (NULL == pre) || (pre->dwSize < sizeof(LPRASENTRY_V401))) { CMASSERTMSG(FALSE, TEXT("SetNtIdleDisconnectInRasEntry -- Invalid parameter")); return FALSE; } // // If idle-disconnect is enabled, use the options value otherwise // pArgs->dwIdleTimeout is in minutes. Note that 0xFFFFFFFF means // no idle disconnect to RAS but 0 is the value we use to mean never // idle disconnect in the CMS. // DWORD dwIdle = (pArgs->dwIdleTimeout * 60); if (0 == dwIdle) { dwIdle = (DWORD)-1; } ((LPRASENTRY_V401 )pre)->dwIdleDisconnectSeconds = dwIdle; CMTRACE1(TEXT("SetNtIdleDisconnect: current idle Timeout is %u seconds."), dwIdle); return TRUE; } //+---------------------------------------------------------------------------- // // Function: DisableSystemIdleDisconnect // // Synopsis: This function sets the idle timeout value of a RAS connection to // be disabled. // // Arguments: LPRASENTRY pre - pointer to a RASENTRY to disable idle disconnect for // // Returns: BOOL TRUE = success, FALSE = failure. // //----------------------------------------------------------------------------- BOOL DisableSystemIdleDisconnect(LPRASENTRY pre) { if ((NULL == pre) || (pre->dwSize < sizeof(LPRASENTRY_V401))) { CMASSERTMSG(FALSE, TEXT("DisableSystemIdleDisconnect -- Invalid parameter")); return FALSE; } // // Set the idle time to 0xFFFFFFFF which means no idle disconnect to RAS // ((LPRASENTRY_V401 )pre)->dwIdleDisconnectSeconds = (DWORD)-1; CMTRACE(TEXT("DisableSystemIdleDisconnect -- System Idle disconnect disabled")); return TRUE; } //+---------------------------------------------------------------------------- // // Function RasDialFunc2 // // Synopsis A RAS callback type 2 for RasDial. // // Arguments // ULONG_PTR dwCallbackId,// user-defined value specified in RasDial // DWORD dwSubEntry, // subentry index in multilink connection // HRASCONN hrasconn, // handle to RAS connection // UINT unMsg, // type of event that has occurred // RASCONNSTATE rascs, // connection state about to be entered // DWORD dwError, // error that may have occurred // DWORD dwExtendedError // extended error information for some errors // // Returns LPRASENTRY - pointer to the RASENTRY structure allocated // //----------------------------------------------------------------------------- DWORD WINAPI RasDialFunc2( ULONG_PTR dwCallbackId, // user-defined value specified in RasDial DWORD dwSubEntry, // subentry index in multilink connection HRASCONN hrasconn, // handle to RAS connection UINT unMsg, // type of event that has occurred RASCONNSTATE rascs, // connection state about to be entered DWORD dwError, // error that may have occurred DWORD dwExtendedError // extended error information for some errors ) { CMTRACE2(TEXT("RasDialFunc2(): dwSubentry=%u. dwErr=0x%x"), dwSubEntry, dwError); CMTRACE2(TEXT("RasDialFunc2(): dwExtendedErr=0x%x, rascs=%u"), dwExtendedError, rascs); MYDBGASSERT(dwCallbackId); if (dwCallbackId) { ArgsStruct *pArgs = (ArgsStruct *) dwCallbackId; pArgs->dwRasSubEntry = dwSubEntry; //CMTRACE1(TEXT("RasDialFunc2(): pArgs->lInConnectOrCancel=%d"),pArgs->lInConnectOrCancel); //CMASSERTMSG((NOT_IN_CONNECT_OR_CANCEL == pArgs->lInConnectOrCancel), // TEXT("RasDialFunc2 - RasDial mutex is NOT NULL...")); SendMessage(pArgs->hwndMainDlg, pArgs->uMsgId, rascs, dwError); } return 1; } //+---------------------------------------------------------------------------- // // Function: SetRasDialExtensions // // Synopsis: Encapsulates initialization and configuration of the // RasDialExtensions that we use on NT. // // Arguments: pArgs - Ptr to global args struct // fEnablePausedStates - Use Paused states or not // fEnableCustomScripting - whether to use custom scripting or not // // Returns: DWORD - Error code // // History: nickball Created 7/22/99 // //+---------------------------------------------------------------------------- DWORD SetRasDialExtensions(ArgsStruct* pArgs, BOOL fEnablePausedStates, BOOL fEnableCustomScripting) { DWORD dwRes = ERROR_SUCCESS; MYDBGASSERT(pArgs); if (NULL == pArgs) { return ERROR_INVALID_PARAMETER; } // // If not already allocated, we need a RasDialExtensions struct // if (!pArgs->pRasDialExtensions) { pArgs->pRasDialExtensions = AllocateAndInitRasDialExtensions(); if (!pArgs->pRasDialExtensions) { dwRes = ERROR_NOT_ENOUGH_MEMORY; } } else { dwRes = InitRasDialExtensions(pArgs->pRasDialExtensions); } if (ERROR_SUCCESS != dwRes) { goto SetRasDialExtensionsExit; } // // Turn on PauseStates for NT // if (fEnablePausedStates) { pArgs->pRasDialExtensions->dwfOptions |= RDEOPT_PausedStates; } // // Turn on custom scripting if we are running on Whistler+ and the caller // asked for it. // if (fEnableCustomScripting && OS_NT51) { pArgs->pRasDialExtensions->dwfOptions |= RDEOPT_UseCustomScripting; } // // RDEOPT_NoUser is required for the WinLogon credential case, // which we identify by the presence of either lpEapLogonInfo // or lpRasNoUser. Note that the if statement below is somewhat redundant // since we should have CM_LOGON_TYPE_WINLOGON set if we get either a NoUser // struct or an EapLogonInfo struct. However, wanted to point out that on Win2k // one of the first two will always be true and on Whistler the first two may be // false but the third true (RAS now sends a flag to tell us when we are at WinLogon on // whistler as there are Ctrl-Alt-Del with SmartCard cases where it sends neither struct). // if (pArgs->lpEapLogonInfo || pArgs->lpRasNoUser || (CM_LOGON_TYPE_WINLOGON == pArgs->dwWinLogonType)) { pArgs->pRasDialExtensions->dwfOptions |= RDEOPT_NoUser; } // // If the modem speaker is turned off, makes sure that we // disable it explicitly in RAS, otherwise it will use // its default and turn the speaker on. These settings // should be ignored by RAS in the tunnel case. // if (pArgs->tlsTapiLink.bModemSpeakerOff) { pArgs->pRasDialExtensions->dwfOptions |= RDEOPT_IgnoreModemSpeaker; pArgs->pRasDialExtensions->dwfOptions &= ~RDEOPT_SetModemSpeaker; } SetRasDialExtensionsExit: return dwRes; } //+---------------------------------------------------------------------------- // // Function: InitRasDialExtensions // // Synopsis: Flushes a previously allocated RasDialExtensions buffer and sets // size, options for re-use. // // Arguments: LPRASDIALEXTENSIONS - Ptr to allocated struct with size set. // // Returns: DWORD - Error code // // History: nickball Created 5/22/99 // //+---------------------------------------------------------------------------- DWORD InitRasDialExtensions(LPRASDIALEXTENSIONS lpRasDialExtensions) { MYDBGASSERT(lpRasDialExtensions); if (NULL == lpRasDialExtensions) { return ERROR_INVALID_PARAMETER; } // // First, we determine the size // DWORD dwSize = OS_NT5 ? sizeof(RASDIALEXTENSIONS_V500) : sizeof(RASDIALEXTENSIONS); // // Flush buffer and reset size. // ZeroMemory(lpRasDialExtensions, dwSize); lpRasDialExtensions->dwSize = dwSize; // // Set customdial if needed // if (dwSize == sizeof(RASDIALEXTENSIONS_V500)) { // // Set the CustomDial flag for NT5. We don't set this on NT4 // and 9X as a precaution because the falg isn't defined. // lpRasDialExtensions->dwfOptions |= RDEOPT_CustomDial; } CMTRACE1(TEXT("InitRasDialExtensions() - dwSize is %u"), dwSize); return ERROR_SUCCESS; } //+---------------------------------------------------------------------------- // // Function: AllocateAndInitRasDialExtensions // // Synopsis: Encapsulates the allocation of a RASEXTENSION based upon the OS // // Arguments: None // // Returns: LPRASDIALEXTENSIONS - Ptr to allocated struct with size set. // // History: nickball Created 5/13/99 // //+---------------------------------------------------------------------------- LPRASDIALEXTENSIONS AllocateAndInitRasDialExtensions() { // // Allocate struct and pre-fill as appropriate // LPRASDIALEXTENSIONS prdeNew = (LPRASDIALEXTENSIONS)CmMalloc(OS_NT5 ? sizeof(RASDIALEXTENSIONS_V500) : sizeof(RASDIALEXTENSIONS)); if (!prdeNew) { CMTRACE(TEXT("AllocateAndInitRasDialExtensions: failed to alloc RasDialExtension buffer")); return NULL; } InitRasDialExtensions(prdeNew); return prdeNew; } //+---------------------------------------------------------------------------- // // Function: InitRasDialParams // // Synopsis: Flushes a previously allocated RasDialParams buffer and sets // size, options for re-use. // // Arguments: LPRASDIALPARAMS - Ptr to allocated struct with size set. // // Returns: DWORD - Error code // // History: nickball Created 5/22/99 // //+---------------------------------------------------------------------------- DWORD InitRasDialParams(LPRASDIALPARAMS lpRasDialParams) { MYDBGASSERT(lpRasDialParams); if (NULL == lpRasDialParams) { return ERROR_INVALID_PARAMETER; } // // First, we determine the size // DWORD dwSize = OS_NT ? sizeof(RASDIALPARAMS_V401) : sizeof(RASDIALPARAMS); // // Flush buffer and reset size. // ZeroMemory(lpRasDialParams, dwSize); lpRasDialParams->dwSize = dwSize; CMTRACE1(TEXT("InitRasDialParams() - dwSize is %u"), dwSize); return ERROR_SUCCESS; } //+---------------------------------------------------------------------------- // // Function: AllocateAndInitRasDialParams // // Synopsis: Encapsulates the allocation of a RASDIALPARAMS based upon the OS // // Arguments: None // // Returns: LPRASDIALPARAMS - Ptr to allocated struct with size set. // // History: nickball Created 5/22/99 // //+---------------------------------------------------------------------------- LPRASDIALPARAMS AllocateAndInitRasDialParams() { // // Allocate struct and pre-fill as appropriate // LPRASDIALPARAMS prdpNew = (LPRASDIALPARAMS)CmMalloc(OS_NT ? sizeof(RASDIALPARAMS_V401) : sizeof(RASDIALPARAMS)); if (!prdpNew) { CMTRACE(TEXT("AllocateRasDialParams: failed to alloc RasDialParams buffer")); return NULL; } InitRasDialParams(prdpNew); return prdpNew; } //+---------------------------------------------------------------------------- // // Function: AllocateRasEntry // // Synopsis: Encapsulates the allocation of a RASENTRY struct based upon the OS // // Arguments: None // // Returns: LPRASENTRY - Ptr to allocated struct with size set. // // History: nickball Created Header 5/13/99 // //+---------------------------------------------------------------------------- LPRASENTRY AllocateRasEntry() { static DWORD s_dwRasEntrySize = -1; // // first, we determine the size // if (s_dwRasEntrySize == -1) { if (OS_NT51) { // // Whistler // s_dwRasEntrySize = sizeof(RASENTRY_V501); } else if (OS_W2K) { // // nt5 // s_dwRasEntrySize = sizeof(RASENTRY_V500); } else if (OS_MIL || OS_NT4) { // // Millennium uses the NT4 structure // s_dwRasEntrySize = sizeof(RASENTRY_V401); } else { // // win9x // s_dwRasEntrySize = sizeof(RASENTRY); } } // // add 512 bytes since a rasentry can contain alternate phone #'s // See RASENTRY.dwAlternateOffset // LPRASENTRY preNew = (LPRASENTRY)CmMalloc(s_dwRasEntrySize+512); if (!preNew) { CMTRACE(TEXT("AllocateRasEntry: failed to alloc rasentry buffer")); return NULL; } preNew->dwSize = s_dwRasEntrySize; if (s_dwRasEntrySize >= sizeof(RASENTRY_V500)) { ((LPRASENTRY_V500)preNew)->dwType = RASET_Internet; // // For NT5, set szCustomDialDll with our Module name. This ensures that our // custom DialDlg, DialEntry, and Hangup routines will be called by RAS for // operations on our connectoid. We don't want to tie our path to anything // machine specific, so we'll use the %windir% environment string. // lstrcpyU(((LPRASENTRY_V500)preNew)->szCustomDialDll, c_pszCmDialPath); } CMTRACE1(TEXT("AllocateRasEntry() - s_dwRasEntrySize is %u"), s_dwRasEntrySize); return preNew; } #if 0 /* //+---------------------------------------------------------------------------- // // Function: GetRasSystemPhoneBookPath // // Synopsis: Builds the conventional path to the RAS system phonebook // // Arguments: None // // Returns: LPTSTR - The phonebook path // // History: nickball Created 8/14/98 // //+---------------------------------------------------------------------------- LPTSTR GetRasSystemPhoneBookPath() { MYDBGASSERT(OS_NT); TCHAR szTemp[MAX_PATH+1]; GetSystemDirectoryU(szTemp,sizeof(szTemp)); lstrcatU(szTemp, c_pszRasDirRas); lstrcatU(szTemp, c_pszRasPhonePbk); return CmStrCpyAlloc(szTemp); } //+--------------------------------------------------------------------------- // // Function: InitDefaultRasPhoneBook // // Synopsis: Special case Helper function ensures that there is a default // ras phonebook when running on NT. We simply attempt to create // the file which fails if the file already exists, or creates // an empty file if it does not. // // Arguments: None // // Returns: Nothing // // History: a-nichb - 4/30/97 Created // VetriV 5/21/97 Changed code to call GetOSVersion() // instead of using pArgs->dwPlatformID // for bug #4700 // nickball ??/??/98 Removed as we no longer call RasValidateEntry // which introduced the requirement of having at // least an empty phonebook for the API to work. // //---------------------------------------------------------------------------- void InitDefaultRasPhoneBook() { // // NT only. Create empty system phonebook if none exists // if (OS_NT) { LPTSTR pszSystemPbk = GetRasSystemPhoneBookPath(); if (pszSystemPbk) { // // Try to create the phonebook, fails if file already exists // HANDLE hInf = CreateFileU(pszSystemPbk, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (hInf != INVALID_HANDLE_VALUE) { CloseHandle(hInf); } } CmFree(pszSystemPbk); } } */ #endif //+---------------------------------------------------------------------------- // // Function: GetRasPbkFromNT5ProfilePath // // Synopsis: Helper function to manufacture a RAS phonebook path from // a .CMP file path on NT5 // // Arguments: LPCTSTR pszProfile - The full path to a profile .CMP file. // // Returns: LPTSTR - The new phonebook path. NULL on failure // // History: nickball Created 8/13/98 // //+---------------------------------------------------------------------------- LPTSTR GetRasPbkFromNT5ProfilePath(LPCTSTR pszProfile) { MYDBGASSERT(OS_NT5); MYDBGASSERT(pszProfile); if (NULL == pszProfile) { return NULL; } // // We will deduce the phonebook path from our current profile location. // LPTSTR pszRasPhonePath = (LPTSTR) CmMalloc(MAX_PATH + 1); MYDBGASSERT(pszRasPhonePath); if (pszRasPhonePath) { // // Strip .CMP file name and parent directory // LPTSTR pszDir = CmStripFileName(pszProfile, FALSE); MYDBGASSERT(pszDir); if (pszDir) { LPTSTR pszTmp = CmStrrchr(pszDir, TEXT('\\')); MYDBGASSERT(pszTmp); if (pszTmp) { *pszTmp = 0; // // Append \\pbk\\rasphone.pbk // lstrcpyU(pszRasPhonePath, pszDir); lstrcatU(pszRasPhonePath, TEXT("\\")); lstrcatU(pszRasPhonePath, c_pszPbk); lstrcatU(pszRasPhonePath, c_pszRasPhonePbk); } CmFree(pszDir); } else { CmFree(pszRasPhonePath); } } return pszRasPhonePath; } #define MAX_BLOB_CHARS_PER_LINE 128 //+---------------------------------------------------------------------------- // // Function: ReadDunSettingsEapData // // Synopsis: Retrieves DUN setting for EAP config (opaque blob) data. The // entry may span several lines and contain several EAP data blocks. // // Arguments: CIni *pIni - Ptr to ini object to be used. // LPBYTE* ppbEapData - Address of pointer to store EapData, allocated here. // LPDWORD pdwEapSize - Ptr to a DWORD to record the size of the data blob. // DWORD dwCustomAuthKey - The EAP type that we are interested in. // // Returns: TRUE on success // // Note: CM expects blob data to be provided in numbered entries such as: // CustomAuthData0=, CustomAuthData1=, CustomAuthData2=, etc. // // History: nickball Created 08/24/98 // nickball Handle multiple EAP data blocks in blob. 09/11/99 // //+---------------------------------------------------------------------------- BOOL ReadDunSettingsEapData(CIni *pIni, LPBYTE* ppbEapData, LPDWORD pdwEapSize, const DWORD dwCustomAuthKey) { CHAR *pchBuf = NULL; CHAR szTmp[MAX_BLOB_CHARS_PER_LINE + 2]; CHAR szEntry[128]; int nLine = -1; int nRead = -1; int nTotal = 0; LPBYTE pbEapBytes = NULL; MYDBGASSERT(pIni); MYDBGASSERT(ppbEapData); MYDBGASSERT(pdwEapSize); if (NULL == pIni || NULL == ppbEapData || NULL == pdwEapSize) { return FALSE; } // // First get the section (it should include &) then the entry. // BOOL bRet = FALSE; LPWSTR pszLoadSection = pIni->LoadSection(c_pszCmSectionDunServer); LPSTR pszSection = WzToSzWithAlloc(pszLoadSection); LPSTR pszFile = WzToSzWithAlloc(pIni->GetFile()); if (!pszLoadSection || !pszSection || !pszFile) { bRet = FALSE; goto exit; } // // Read numbered entries until there are no more. // Note: RAS blob doesn't exceed 64 chars, but can wrap over multiple lines // while (nRead) { // // Read CustomAuthDataX where X is the number of entries // nLine++; wsprintfA(szEntry, "%s%d", c_pszCmEntryDunServerCustomAuthData, nLine); nRead = GetPrivateProfileStringA(pszSection, szEntry, "", szTmp, sizeof(szTmp), pszFile); if (nRead) { // // If line exceeded 64 chars, it is considered corrupt // if (MAX_BLOB_CHARS_PER_LINE < nRead) { nTotal = 0; break; } // // Update our local master buffer with the latest fragment // if (nLine) { pchBuf = CmStrCatAllocA(&pchBuf, szTmp); } else { pchBuf = CmStrCpyAllocA(szTmp); } if (!pchBuf) { bRet = FALSE; goto exit; } nTotal += nRead; } } // // At this point we should have the entire entry in pchBuf in HEX format // Convert the buffer to byte format and store in supplied EAP buffer. // if (nTotal && !(nTotal & 1)) { nTotal /= 2; // Only need half the hex char size pbEapBytes = (BYTE *) CmMalloc(nTotal + 1); if (!pbEapBytes) { goto exit; } CHAR *pch = pchBuf; BYTE *pb = pbEapBytes; while (*pch != '\0') { *pb = HexValue( *pch++ ) * 16; *pb += HexValue( *pch++ ); ++pb; } // // Now we have the bytes, locate and extract the data block that we // are after. Note: Multiple blocks are arrayed using the following // header: // // typedef struct _EAP_CUSTOM_DATA // { // DWORD dwSignature; // DWORD dwCustomAuthKey; // DWORD dwSize; // BYTE abdata[1]; // } EAP_CUSTOM_DATA; // EAP_CUSTOM_DATA *pCustomData = (EAP_CUSTOM_DATA *) pbEapBytes; while (((LPBYTE) pCustomData - pbEapBytes) < nTotal) { if (pCustomData->dwCustomAuthKey == dwCustomAuthKey) { // // Bingo! We have a match, first make sure that the indicated // size isn't pointing out into space, then make a copy and // run for the hills. // if (((LPBYTE) pCustomData - pbEapBytes) + sizeof(EAP_CUSTOM_DATA) + pCustomData->dwSize > (DWORD) nTotal) { MYDBGASSERT(FALSE); goto exit; } *ppbEapData = (BYTE *) CmMalloc(pCustomData->dwSize); if (*ppbEapData) { CopyMemory(*ppbEapData, pCustomData->abdata, pCustomData->dwSize); *pdwEapSize = pCustomData->dwSize; bRet = TRUE; goto exit; } } // // Locate the next data block // pCustomData = (EAP_CUSTOM_DATA *) ((LPBYTE) pCustomData + sizeof(EAP_CUSTOM_DATA) + pCustomData->dwSize); } } exit: CmFree(pchBuf); CmFree(pszLoadSection); CmFree(pszSection); CmFree(pszFile); CmFree(pbEapBytes); return bRet; } //+---------------------------------------------------------------------------- // // Function: ReadDUNSettings // // Synopsis: Reads the DUN settings for the specified DUN name and .CMS file // into a RASENTRY structure. Because some settings are not supported // on downlevel platforms, this function will potentially display an // error message to the user. // // Arguments: ArgsStruct *pArgs - Ptr to global args struct. // LPCSTR pszFile - Full path to the .CMS file. // LPCTSTR pszDunName - The DUN name for the settings. // LPVOID pvBuffer - Ptr to RASENTRY buffer. // LPBYTE* ppbEapData - Address of pointer to store EapData // LPDWORD pdwEapSize - Ptr to a DWORD to record the size of the data blob. // BOOL fTunnel - are we reading tunnel settings? // // Returns: ERROR_SUCCESS on success. Use GetLastError for failure details. // // Note: This was formerly the PhoneBookReadDun API in CMPBK.DLL // // History: nickball 8/22/98 Created Header // nickball 02/03/99 Added pArgs :( in order to have access to the // the top-level service for path conversion. // //+---------------------------------------------------------------------------- LRESULT ReadDUNSettings(ArgsStruct *pArgs, LPCTSTR pszFile, LPCTSTR pszDunName, LPVOID pvBuffer, LPBYTE* ppbEapData, LPDWORD pdwEapSize, BOOL fTunnel) { MYDBGASSERT(pszFile); MYDBGASSERT(pszDunName); MYDBGASSERT(pvBuffer); if (NULL == pszFile || NULL == pszDunName || NULL == pvBuffer) { return (ERROR_INVALID_PARAMETER); } CMTRACE1(TEXT("ReadDUNSettings -- using DUN setting: %s"), pszDunName); RASENTRYW *preRas = (RASENTRYW *) pvBuffer; // // Setup INI object. Prepend pszDunName with "&" for section. // CIni iniFile(g_hInst, pszFile); LPTSTR pszSection = CmStrCpyAlloc(TEXT("&")); pszSection = CmStrCatAlloc(&pszSection, pszDunName); iniFile.SetSection(pszSection); CmFree(pszSection); // // Get and apply the Phone section entries // if (iniFile.GPPB(c_pszCmSectionDunPhone, c_pszCmEntryDunPhoneDialAsIs)) { preRas->dwfOptions &= ~RASEO_UseCountryAndAreaCodes;; } CopyGPPS(&iniFile, c_pszCmSectionDunPhone, c_pszCmEntryDunPhonePhoneNumber, preRas->szLocalPhoneNumber, sizeof(preRas->szLocalPhoneNumber)/sizeof(TCHAR)); CopyGPPS(&iniFile,c_pszCmSectionDunPhone, c_pszCmEntryDunPhoneAreaCode, preRas->szAreaCode, sizeof(preRas->szAreaCode)/sizeof(TCHAR)); preRas->dwCountryCode = iniFile.GPPI(c_pszCmSectionDunPhone, c_pszCmEntryDunPhoneCountryCode, preRas->dwCountryCode); preRas->dwCountryID = iniFile.GPPI(c_pszCmSectionDunPhone, c_pszCmEntryDunPhoneCountryId, preRas->dwCountryID); // // Get and apply the Device section entries // CopyGPPS(&iniFile,c_pszCmSectionDunDevice, c_pszCmEntryDunDeviceType, preRas->szDeviceType, sizeof(preRas->szDeviceType)/sizeof(TCHAR)); CopyGPPS(&iniFile,c_pszCmSectionDunDevice, c_pszCmEntryDunDeviceName, preRas->szDeviceName, sizeof(preRas->szDeviceName)/sizeof(TCHAR)); // // Get and apply the Server section entries // LPTSTR pszTmp = iniFile.GPPS(c_pszCmSectionDunServer, c_pszCmEntryDunServerType); if (*pszTmp) { if (0 == lstrcmpiU(pszTmp, c_pszDunPpp)) { preRas->dwFramingProtocol = RASFP_Ppp; } else if (0 == lstrcmpiU(pszTmp, c_pszDunCslip)) { preRas->dwFramingProtocol = RASFP_Slip; preRas->dwfOptions |= RASEO_IpHeaderCompression; } else if (0 == lstrcmpiU(pszTmp, c_pszDunSlip)) { preRas->dwFramingProtocol = RASFP_Slip; if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunTcpIpIpHeaderCompress, (BOOL) preRas->dwfOptions & RASEO_IpHeaderCompression)) { preRas->dwfOptions |= RASEO_IpHeaderCompression; } else { preRas->dwfOptions &= ~RASEO_IpHeaderCompression; } } } CmFree(pszTmp); if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerSwCompress, (BOOL) preRas->dwfOptions & RASEO_SwCompression)) { preRas->dwfOptions |= RASEO_SwCompression; } else { preRas->dwfOptions &= ~RASEO_SwCompression; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerDisableLcp, (BOOL) preRas->dwfOptions & RASEO_DisableLcpExtensions)) { preRas->dwfOptions |= RASEO_DisableLcpExtensions; } else { preRas->dwfOptions &= ~RASEO_DisableLcpExtensions; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerNetworkLogon, (BOOL) preRas->dwfOptions & RASEO_NetworkLogon)) { preRas->dwfOptions |= RASEO_NetworkLogon; } else { preRas->dwfOptions &= ~RASEO_NetworkLogon; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerNegotiateTcpIp, (BOOL) preRas->dwfNetProtocols & RASNP_Ip)) { preRas->dwfNetProtocols |= RASNP_Ip; } else { preRas->dwfNetProtocols &= ~RASNP_Ip; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerNegotiateIpx, (BOOL) preRas->dwfNetProtocols & RASNP_Ipx)) { preRas->dwfNetProtocols |= RASNP_Ipx; } else { preRas->dwfNetProtocols &= ~RASNP_Ipx; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerNegotiateNetBeui, preRas->dwfNetProtocols&RASNP_NetBEUI)) { preRas->dwfNetProtocols |= RASNP_NetBEUI; } else { preRas->dwfNetProtocols &= ~RASNP_NetBEUI; } // // Get the NT5 specific DUN settings. We will error out if we're running // downlevel when these settings are configured and the EnforceCustomSecurity // flag has been set. // // Note: c_pszCmEntryDunServerEnforceCustomSecurity is a DUN setting and is FALSE by default // BOOL bEnforceCustomSecurity = iniFile.GPPI(c_pszCmSectionDunServer, c_pszCmEntryDunServerEnforceCustomSecurity, FALSE); // // Is EAP required // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireEap, (BOOL) preRas->dwfOptions & RASEO_RequireEAP)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_RequireEAP; } else { preRas->dwfOptions &= ~RASEO_RequireEAP; } // // PAP required // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequirePap, (BOOL) preRas->dwfOptions & RASEO_RequirePAP)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_RequirePAP; } else { preRas->dwfOptions &= ~RASEO_RequirePAP; } // // SPAP required // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireSpap, (BOOL) preRas->dwfOptions & RASEO_RequireSPAP)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_RequireSPAP; } else { preRas->dwfOptions &= ~RASEO_RequireSPAP; } // // CHAP required // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireChap, (BOOL) preRas->dwfOptions & RASEO_RequireCHAP)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_RequireCHAP; } else { preRas->dwfOptions &= ~RASEO_RequireCHAP; } // // MSCHAP required // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireMsChap, (BOOL) preRas->dwfOptions & RASEO_RequireMsCHAP)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_RequireMsCHAP; } else { preRas->dwfOptions &= ~RASEO_RequireMsCHAP; } // // MSCHAP2 required // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireMsChap2, (BOOL) preRas->dwfOptions & RASEO_RequireMsCHAP2)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_RequireMsCHAP2; } else { preRas->dwfOptions &= ~RASEO_RequireMsCHAP2; } // // W95 MSCHAP required // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireW95MsChap, (BOOL) preRas->dwfOptions & RASEO_RequireW95MSCHAP)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_RequireW95MSCHAP; } else { preRas->dwfOptions &= ~RASEO_RequireW95MSCHAP; } // // Custom Security configuration // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerCustomSecurity, (BOOL) preRas->dwfOptions & RASEO_Custom)) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } preRas->dwfOptions |= RASEO_Custom; } else { preRas->dwfOptions &= ~RASEO_Custom; } // // Now get the legacy security settings if we don't already have // settings specificed from above. By checking for the Win2k specific // settings first we allow Admins to specify both so that legacy platforms // can have settings but Win2k can use the more granular settings. // If we didn't do this the legacy flags could water down the security on Win2k ... // const DWORD dwWin2kSecuritySettings = RASEO_RequireEAP | RASEO_RequirePAP | RASEO_RequireSPAP | RASEO_RequireCHAP | RASEO_RequireMsCHAP | RASEO_RequireMsCHAP2 | RASEO_RequireW95MSCHAP; if (0 == (preRas->dwfOptions & dwWin2kSecuritySettings) || !OS_NT5) { // // Security settings // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerPwEncrypt, (BOOL) preRas->dwfOptions & RASEO_RequireEncryptedPw)) { preRas->dwfOptions |= RASEO_RequireEncryptedPw; } else { preRas->dwfOptions &= ~RASEO_RequireEncryptedPw; } // // MS-CHAP // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerPwEncryptMs, (BOOL) preRas->dwfOptions & RASEO_RequireMsEncryptedPw)) { preRas->dwfOptions |= RASEO_RequireMsEncryptedPw; } else { preRas->dwfOptions &= ~RASEO_RequireMsEncryptedPw; } } else { CMASSERTMSG((preRas->dwfOptions & RASEO_Custom), TEXT("ReadDUNSettings -- Win2k+ security setting configured but RASEO_Custom not specified.")); } // // Encrypt Data (legacy setting, same as ET_Require from above) // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerDataEncrypt, (BOOL) preRas->dwfOptions & RASEO_RequireDataEncryption)) { preRas->dwfOptions |= RASEO_RequireDataEncryption; } else { preRas->dwfOptions &= ~RASEO_RequireDataEncryption; } // // Encryption type, just a straight int read. (win2k+ setting) // int nTmp = iniFile.GPPI(c_pszCmSectionDunServer, c_pszCmEntryDunServerEncryptionType, -1); if (OS_NT5) { // // We need to set Tunnel encryption type to ET_Require because that's what the ConnFolder does. // We also set it ET_Require if the user specified RASEO_RequireDataEncryption as a legacy setting // but didn't specify a specific win2k setting. // if (-1 == nTmp) { if (fTunnel || (preRas->dwfOptions & RASEO_RequireDataEncryption)) { nTmp = ET_Require; } else { nTmp = ET_Optional; } } ((LPRASENTRY_V500)preRas)->dwEncryptionType = (DWORD) nTmp; } else { if (-1 != nTmp && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } } // // Get the EAP type ID (CustomAuthKey) - The data is stored in the RAS // pbk via a specific API, just before dialing - SetCustomAuthData(). // nTmp = iniFile.GPPI(c_pszCmSectionDunServer, c_pszCmEntryDunServerCustomAuthKey, -1); // // If a type ID for EAP is specified, see if there is any config data // if (-1 != nTmp) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } // // We have an ID and its NT5, read the EAP config data // ((LPRASENTRY_V500)preRas)->dwCustomAuthKey = nTmp; ReadDunSettingsEapData(&iniFile, ppbEapData, pdwEapSize, nTmp); } // // Get and apply the Networking section entries. // nTmp = iniFile.GPPI(c_pszCmSectionDunNetworking, c_pszCmEntryDunNetworkingVpnStrategy, -1); if (-1 != nTmp) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } ((LPRASENTRY_V500)preRas)->dwVpnStrategy = nTmp; } // // See if the profile calls for using a Pre-Shared Key for L2TP. Note that we currently don't // provide a mechanism to set the Pre-Shared Key through RasSetCredentials but that could easily // be done through a custom action or a post install action. // if (OS_NT51) { if (iniFile.GPPB(c_pszCmSectionDunNetworking, c_pszCmEntryDunNetworkingUsePreSharedKey, (BOOL) ((LPRASENTRY_V501)preRas)->dwfOptions2 & RASEO2_UsePreSharedKey)) { ((LPRASENTRY_V501)preRas)->dwfOptions2 |= RASEO2_UsePreSharedKey; } else { ((LPRASENTRY_V501)preRas)->dwfOptions2 &= ~RASEO2_UsePreSharedKey; } } // // File and Print sharing. Note that on systems up to Win2k we only have the traditional RASEO_SecureLocalFiles. // However, Win2k gave this flag two purposes (enable/disable NetBt and enable/disable file and print sharing). // In Whistler two separate flags were developed to allow greater granularity. To give legacy profiles the behavior // they expect while disabling file and print sharing as the default the logic gets a little complicated. Basically // the new flag overrides the legacy flag and defaults to 1. If the new flag isn't specified then we use the value // of the legacy flag if it is specified. If neither is specified we set it to 1. On platforms previous to Whistler // the old flag is the only thing we have and it defaults to 0. // int nLegacySecureLocalFiles = iniFile.GPPI(c_pszCmSectionDunServer, c_pszCmEntryDunServerSecureLocalFiles, -1); int nSecureFileAndPrint = iniFile.GPPI(c_pszCmSectionDunServer, c_pszCmEntryDunNetworkingSecureFileAndPrint, -1); if (-1 == nSecureFileAndPrint) { nSecureFileAndPrint = nLegacySecureLocalFiles ? 1 : 0; } if (-1 == nLegacySecureLocalFiles) { nLegacySecureLocalFiles = 0; } if (OS_NT51) { // // Set the 501/Options2 style File and Print sharing flag // if (nSecureFileAndPrint) { if (!(OS_NT5) && bEnforceCustomSecurity) { return (ERROR_INVALID_DATA); } ((LPRASENTRY_V501)preRas)->dwfOptions2 |= RASEO2_SecureFileAndPrint; } else { ((LPRASENTRY_V501)preRas)->dwfOptions2 &= ~RASEO2_SecureFileAndPrint; } } else { if (nLegacySecureLocalFiles) { preRas->dwfOptions |= RASEO_SecureLocalFiles; } else { preRas->dwfOptions &= ~RASEO_SecureLocalFiles; } } // // Pick up Whistler specific DUN settings // if (OS_NT51) { // // Get the 501/Options2 style MSNet binding flag // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunNetworkingSecureClientForMSNet, (BOOL) ((LPRASENTRY_V501)preRas)->dwfOptions2 & RASEO2_SecureClientForMSNet)) { ((LPRASENTRY_V501)preRas)->dwfOptions2 |= RASEO2_SecureClientForMSNet; } else { ((LPRASENTRY_V501)preRas)->dwfOptions2 &= ~RASEO2_SecureClientForMSNet; } // // Get the 501/Options2 style Multilink Negotiation flag // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunNetworkingDontNegotiateMultilink, (BOOL) ((LPRASENTRY_V501)preRas)->dwfOptions2 & RASEO2_DontNegotiateMultilink)) { ((LPRASENTRY_V501)preRas)->dwfOptions2 |= RASEO2_DontNegotiateMultilink; } else { ((LPRASENTRY_V501)preRas)->dwfOptions2 &= ~RASEO2_DontNegotiateMultilink; } // // Get the 501/Options2 style DontUseRasCredentials flag // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunNetworkingDontUseRasCredentials, (BOOL) ((LPRASENTRY_V501)preRas)->dwfOptions2 & RASEO2_DontUseRasCredentials)) { ((LPRASENTRY_V501)preRas)->dwfOptions2 |= RASEO2_DontUseRasCredentials; } else { ((LPRASENTRY_V501)preRas)->dwfOptions2 &= ~RASEO2_DontUseRasCredentials; } // // Get the RASEO_CustomScript flag value. Note that this flag existed on Win2k but wasn't // available for RasDial only RasDialDlg. On Whistler+ it is available to RasDial as well. // Note that we also have to set the RDEOPT_UseCustomScripting flag in the RASDIALEXTENSIONS // for this to work. // if (iniFile.GPPB(c_pszCmSectionDunScripting, c_pszCmEntryDunScriptingUseRasCustomScriptDll, (BOOL) (preRas->dwfOptions & RASEO_CustomScript))) { preRas->dwfOptions |= RASEO_CustomScript; } else { preRas->dwfOptions &= ~RASEO_CustomScript; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerDisableNbtOverIP, (BOOL) (((LPRASENTRY_V501)preRas)->dwfOptions2 & RASEO2_DisableNbtOverIP))) { ((LPRASENTRY_V501)preRas)->dwfOptions2 |= RASEO2_DisableNbtOverIP; } else { ((LPRASENTRY_V501)preRas)->dwfOptions2 &= ~RASEO2_DisableNbtOverIP; } } // // Get and apply the TCP/IP section entries // if (iniFile.GPPB(c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpSpecifyIpAddress, (BOOL) preRas->dwfOptions & RASEO_SpecificIpAddr)) { preRas->dwfOptions |= RASEO_SpecificIpAddr; } else { preRas->dwfOptions &= ~RASEO_SpecificIpAddr; } Ip_GPPS(&iniFile, c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpIpAddress, &preRas->ipaddr); if (iniFile.GPPB(c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpSpecifyServerAddress, (BOOL) preRas->dwfOptions & RASEO_SpecificNameServers)) { preRas->dwfOptions |= RASEO_SpecificNameServers; } else { preRas->dwfOptions &= ~RASEO_SpecificNameServers; } if (iniFile.GPPB(c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpIpHeaderCompress, (BOOL) preRas->dwfOptions & RASEO_IpHeaderCompression)) { preRas->dwfOptions |= RASEO_IpHeaderCompression; } else { preRas->dwfOptions &= ~RASEO_IpHeaderCompression; } Ip_GPPS(&iniFile, c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpDnsAddress, &preRas->ipaddrDns); Ip_GPPS(&iniFile, c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpDnsAltAddress, &preRas->ipaddrDnsAlt); Ip_GPPS(&iniFile, c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpWinsAddress, &preRas->ipaddrWins); Ip_GPPS(&iniFile, c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpWinsAltAddress, &preRas->ipaddrWinsAlt); if (iniFile.GPPB(c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpGatewayOnRemote, (BOOL) preRas->dwfOptions & RASEO_RemoteDefaultGateway)) { preRas->dwfOptions |= RASEO_RemoteDefaultGateway; } else { preRas->dwfOptions &= ~RASEO_RemoteDefaultGateway; } if (OS_NT51) { // // If the caller specified a DNS suffix then lets read it and add it to the RAS entry // CopyGPPS(&iniFile, c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpDnsSuffix, ((LPRASENTRY_V501)preRas)->szDnsSuffix, sizeof(((LPRASENTRY_V501)preRas)->szDnsSuffix)/sizeof(TCHAR)); } // // Set the TCP Window size -- the NTT DoCoMo fix for Whistler. The Win2k version of this fix // must be written through a private RAS API that must be called after the phonebook entry // exists ie. after we call RasSetEntryProperties ... otherwise it won't work on the first // dial. // if (OS_NT51) { ((LPRASENTRY_V501)preRas)->dwTcpWindowSize = iniFile.GPPI(c_pszCmSectionDunTcpIp, c_pszCmEntryDunTcpIpTcpWindowSize, 0); } // // Get and apply the Scripting section entries // TCHAR szScript[MAX_PATH + 1] = TEXT(""); CopyGPPS(&iniFile,c_pszCmSectionDunScripting, c_pszCmEntryDunScriptingName, szScript, sizeof(szScript)/sizeof(TCHAR)); // // The script path from our cms file is a relative path. We need to convert // it to a full path, but make sure that we use the top-level service for // the conversion because it is used to derive the short-service name for // the directory. Note that tunnel dun settings cannot have a script. // if (szScript[0] && !fTunnel) { CMTRACE1(TEXT("ReadDunSettings() - Converting script path %s to full path"), szScript); pszTmp = CmConvertRelativePath(pArgs->piniService->GetFile(), szScript); MYDBGASSERT(pszTmp); if (pszTmp && *pszTmp) { lstrcpyU(preRas->szScript, pszTmp); CMTRACE1(TEXT("ReadDunSettings() - Script file is %s"), preRas->szScript); } CmFree(pszTmp); } else { // // The cms didn't specify a script ==> no script // preRas->szScript[0] = TEXT('\0'); } // // If this is Whistler+ then we may need to invoke a terminal window // if (OS_NT51 && !fTunnel && iniFile.GPPB(c_pszCmSectionDunScripting, c_pszCmEntryDunScriptingUseTerminalWindow, (BOOL) preRas->dwfOptions & RASEO_TerminalAfterDial)) { preRas->dwfOptions |= RASEO_TerminalAfterDial; } else { preRas->dwfOptions &= ~RASEO_TerminalAfterDial; } return (ERROR_SUCCESS); } //+---------------------------------------------------------------------------- // // Function: ValidateDialupDunSettings // // Synopsis: Verifies the DUN settings that the specified .CMS and DUN name are // supported on the current platform. If we are running on a downlevel // OS and we encounter any NT specific security settings we error out. // // Arguments: LPCTSTR pszCmsFile - The phone # specific .CMS file name. // LPCTSTR pszDunName - The DUN name, if any for the settings. // LPCTSTR pszTopLevelCms - The top-level CMS file name. // // Returns: BOOL - TRUE on success. // // History: nickball Created 8/26/98 // //+---------------------------------------------------------------------------- BOOL ValidateDialupDunSettings(LPCTSTR pszCmsFile, LPCTSTR pszDunName, LPCTSTR pszTopLevelCms) { MYDBGASSERT(pszCmsFile); MYDBGASSERT(*pszCmsFile); MYDBGASSERT(pszDunName); if (NULL == pszCmsFile || (!*pszCmsFile) || NULL == pszDunName) { return FALSE; } // // On NT5 we currently support all settings, so succeed automatically // if (OS_NT5) { return TRUE; } // // Determine the DUN name that we are looking for. In the tunnel case we // always read it from the .CMS. For dial-up, we'll use the specified DUN // name, and revert to the .CMS if blank. // CIni iniFile(g_hInst, pszCmsFile); // // Now determine the DUN name to be used when looking up settings. // LPTSTR pszEntryName; // // If we have a specific DUN name to use, and we're not tunneling // use it instead of the default DUN setting in the .CMS. // if (pszDunName && *pszDunName) { pszEntryName = CmStrCpyAlloc(pszDunName); } else { pszEntryName = GetDefaultDunSettingName(&iniFile, FALSE); // FALSE == not tunnel } // // If no DUN name is specified, then pass validation automatically // if (!pszEntryName || (!*pszEntryName)) { CmFree(pszEntryName); CMTRACE1(TEXT("ValidateDunSettings() - No DUN name found in %s"), pszCmsFile); return TRUE; } // // Include the entryname in the section headers // LPTSTR pszSection = CmStrCpyAlloc(TEXT("&")); pszSection = CmStrCatAlloc(&pszSection, pszEntryName); iniFile.SetSection(pszSection); CmFree(pszSection); CmFree(pszEntryName); // // Check to see if the admin wants us to check the custom security settings // against the platform. By default, we do not enforce this check. // // if (FALSE == iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerEnforceCustomSecurity)) { return TRUE; } // // Now check the actual settings if we're still here. // if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireEap)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequirePap)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireSpap)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireChap)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireMsChap)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireMsChap2)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerRequireW95MsChap)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerCustomSecurity)) { goto ValidateDunSettingsExit; } if (iniFile.GPPB(c_pszCmSectionDunServer, c_pszCmEntryDunServerEncryptionType)) { goto ValidateDunSettingsExit; } if (-1 != iniFile.GPPI(c_pszCmSectionDunServer, c_pszCmEntryDunServerCustomAuthKey, -1)) { goto ValidateDunSettingsExit; } if (-1 != iniFile.GPPI(c_pszCmSectionDunNetworking, c_pszCmEntryDunNetworkingVpnStrategy, -1)) { goto ValidateDunSettingsExit; } return TRUE; ValidateDunSettingsExit: // // Get the top-level service name // CIni iniTopLevelCms(g_hInst, pszTopLevelCms); LPTSTR pszTitle = GetServiceName(&iniTopLevelCms); LPTSTR pszTmp = CmFmtMsg(g_hInst,IDMSG_UNSUPPORTED_SETTING_NUM); MessageBoxEx(NULL, pszTmp, pszTitle, MB_OK|MB_ICONSTOP, LANG_USER_DEFAULT);//13309 CmFree(pszTmp); CmFree(pszTitle); CMTRACE1(TEXT("ValidateDunSettings() - Unsupported setting detected in %s"), pszCmsFile); return FALSE; } //+---------------------------------------------------------------------------- // // Function: InvokeTerminalWindow // // Synopsis: Allows CM to invoke a terminal window on Whistler or later versions // of Win2k but calling a private RAS API in RasDlg.dll. // // Arguments: LPCWSTR pszPhoneBook - full path to the phonebook file // LPCWSTR pszEntry - entry name to invoke the terminal window for // RASDIALPARAMS *pRasDialParams - RasDialParams for the connection // to invoke the terminal window for // HWND hWnd - window handle of the parent dialog // HRASCONN hRasconn - handle to the ras connection // // Returns: Windows error message // // History: quintinb Created 07/11/00 // //+---------------------------------------------------------------------------- DWORD InvokeTerminalWindow(LPCWSTR pszPhoneBook, LPCWSTR pszEntry, RASDIALPARAMS *pRasDialParams, HWND hWnd, HRASCONN hRasconn) { // // Validate the input parameters. Note that pszPhoneBook can be NULL but if it is non-NULL then we cannot have // an empty string. // MYDBGASSERT(OS_NT51); if (((NULL != pszPhoneBook) && (L'\0' == pszPhoneBook[0])) || (NULL == pszEntry) || (L'\0' == pszEntry[0]) || (NULL == pRasDialParams) || (NULL == hWnd) || (NULL == hRasconn)) { CMASSERTMSG(FALSE, TEXT("InvokeTerminalWindow - Invalid parameter passed.")); return ERROR_INVALID_PARAMETER; } DWORD dwReturn; typedef DWORD (WINAPI *pfnDwTerminalDlgSpec)(LPCWSTR, LPCWSTR, RASDIALPARAMS *, HWND, HRASCONN); // // First call loadlibrary on rasdlg.dll // HMODULE hRasDlg = LoadLibraryExU(TEXT("rasdlg.dll"), NULL, 0); if (hRasDlg) { pfnDwTerminalDlgSpec pfnDwTerminalDlg = (pfnDwTerminalDlgSpec)GetProcAddress(hRasDlg, "DwTerminalDlg"); if (pfnDwTerminalDlg) { dwReturn = pfnDwTerminalDlg(pszPhoneBook, pszEntry, pRasDialParams, hWnd, hRasconn); } else { dwReturn = ERROR_PROC_NOT_FOUND; } FreeLibrary(hRasDlg); } else { dwReturn = ERROR_MOD_NOT_FOUND; } return dwReturn; } //+---------------------------------------------------------------------------- // // Function: OnPauseRasDial // // Synopsis: Message handler for RasDial pause states. In the pause state, RAS // is suspended, waiting for us to restart it by calling RasDial after // performing the appropriate interface with the user. // // Arguments: HWND hwndDlg - Window handle of main dialog // ArgsStruct *pArgs - Ptr to global args struct // WPARAM wParam - wParam being handled // LPARAM lParam - lParam being handled // // Returns: Windows error message // // History: nickball Created 05/19/99 // //+---------------------------------------------------------------------------- DWORD OnPauseRasDial(HWND hwndDlg, ArgsStruct *pArgs, WPARAM wParam, LPARAM lParam) { CMTRACE2(TEXT("OnPauseRasDial - wParam is %u and lParam is %u."), wParam, lParam); MYDBGASSERT(pArgs); if (NULL == pArgs) { return ERROR_INVALID_PARAMETER; } // // Get connection handle and re-dial // HRASCONN hRasConn; DWORD dwRes = ERROR_SUCCESS; LPTSTR pszRasPbk = pArgs->pszRasPbk; // // Determine the appropriate connection handle and phonebook // Note: Make an explicit copy or we'll wind up re-dialing // if the connection drops while the pause UI is invoked. // if (IsDialingTunnel(pArgs)) { hRasConn = pArgs->hrcTunnelConn; } else { hRasConn = pArgs->hrcRasConn; if (pArgs->pszRasHiddenPbk) { pszRasPbk = pArgs->pszRasHiddenPbk; } } // // Handle the pause // switch (wParam) { case (RASCS_PAUSED + 4): // 4100 - RASCS_InvokeEapUI ) // // If UNATTENDED, just bail out immediately. // if (pArgs->dwFlags & FL_UNATTENDED) { dwRes = ERROR_INTERACTIVE_MODE; goto OnPauseRasDialExit; } // // If EAP triggered the pause, invoke the EAP UI // dwRes = pArgs->rlsRasLink.pfnInvokeEapUI(hRasConn, pArgs->dwRasSubEntry, pArgs->pRasDialExtensions, hwndDlg); CMTRACE1(TEXT("OnPauseRasDial() - InvokeEapUI() returns %u."), dwRes); break; case RASCS_PasswordExpired: // Domain password has expired { // // If UNATTENDED, just bail out immediately. // if (pArgs->dwFlags & FL_UNATTENDED) { dwRes = ERROR_INTERACTIVE_MODE; goto OnPauseRasDialExit; } CChangePasswordDlg NewPasswordDlg(pArgs); if (IDOK != NewPasswordDlg.DoDialogBox(g_hInst, IDD_CHANGEPASSWORD, pArgs->hwndMainDlg)) { if (pArgs->dwExitCode) { dwRes = pArgs->dwExitCode; } else { dwRes = ERROR_CANCELLED; } } CMTRACE1(TEXT("OnPauseRasDial() - Password Expired"), dwRes); break; } case RASCS_CallbackSetByCaller: // Server wants to call us back { // // Preset dial params and call dialog to retrieve number from user // LPTSTR pszTmp = pArgs->piniProfile->GPPS(c_pszCmSection, c_pszCmEntryCallbackNumber); lstrcpyU(pArgs->pRasDialParams->szCallbackNumber, pszTmp); CmFree(pszTmp); // // If we're running unattended, skip the dialog phase. The // presumption is that there is no user there to receive it. // BOOL bPromptUser = !(pArgs->dwFlags & FL_UNATTENDED); if (bPromptUser) { // // The above also applies in the case of DialAutomatically // if we have a phone number, then there is no need to prompt. // if (pArgs->fDialAutomatically && TEXT('\0') != pArgs->pRasDialParams->szCallbackNumber[0]) { bPromptUser = FALSE; } } if (bPromptUser) { CCallbackNumberDlg CallbackNumberDialog(pArgs); if (IDOK != CallbackNumberDialog.DoDialogBox(g_hInst, IDD_CALLBACK_NUMBER, pArgs->hwndMainDlg)) { // // If the user canceled, clear the number so that RAS wont attempt callback // lstrcpyU(pArgs->pRasDialParams->szCallbackNumber, TEXT("")); } } dwRes = ERROR_SUCCESS; CMTRACE1(TEXT("OnPauseRasDial() - CallbackSetByCaller returns %u"), dwRes); break; } case RASCS_RetryAuthentication: // Credentials aren't correct { // // If UNATTENDED, just bail out immediately. // if (pArgs->dwFlags & FL_UNATTENDED) { dwRes = ERROR_INTERACTIVE_MODE; goto OnPauseRasDialExit; } // // Creds didn't work, prompt user for new ones. // CRetryAuthenticationDlg RetryAuthenticationDialog(pArgs); if (IDOK != RetryAuthenticationDialog.DoDialogBox(g_hInst, RetryAuthenticationDialog.GetDlgTemplate(), pArgs->hwndMainDlg)) { // // User canceled, or the call was dropped elsewhere. Use // existing error code or designate authentication failure. // if (pArgs->dwExitCode) { dwRes = pArgs->dwExitCode; } else { dwRes = ERROR_AUTHENTICATION_FAILURE; } } CMTRACE1(TEXT("OnPauseRasDial() - RetryAuthentication"), dwRes); break; } case RASCS_Interactive: // Terminal/script pause state if (OS_NT51) { if (pArgs->dwFlags & FL_UNATTENDED) { dwRes = ERROR_INTERACTIVE_MODE; goto OnPauseRasDialExit; } dwRes = InvokeTerminalWindow(pszRasPbk, pArgs->szServiceName, pArgs->pRasDialParams, pArgs->hwndMainDlg, hRasConn); break; } // else fail through to default and error out. // // We got a pause state that we don't handle, error out. // default: dwRes = ERROR_INTERACTIVE_MODE; CMASSERTMSG(FALSE, TEXT("OnPauseRasDial() - Error, unsupported RAS pause state encountered.")); break; } // // On success, call RasDial to resume connection // if (ERROR_SUCCESS == dwRes) { // // Decode active password, re-call RasDial, then re-encode // CmDecodePassword(pArgs->pRasDialParams->szPassword); CMASSERTMSG((NOT_IN_CONNECT_OR_CANCEL == pArgs->lInConnectOrCancel), TEXT("OnPauseRasDial - RasDial mutex is NOT NULL...")); dwRes = pArgs->rlsRasLink.pfnDial(pArgs->pRasDialExtensions, pszRasPbk, pArgs->pRasDialParams, GetRasCallBackType(), GetRasCallBack(pArgs), &hRasConn); CmEncodePassword(pArgs->pRasDialParams->szPassword); CMTRACE1(TEXT("OnPauseRasDial() - RasDial() returns %u."), dwRes); // // Reset timers, the current action starts now. // pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; } OnPauseRasDialExit: if (ERROR_SUCCESS != dwRes) { OnRasErrorMessage(hwndDlg, pArgs, dwRes); } return dwRes; } //+---------------------------------------------------------------------------- // // Function: GetRasCallBackType // // Synopsis: Simple function to return the Callback type that we use for RasDial // depending upon the OS. // // Arguments: None // // Returns: DWORD - The callback type // // History: nickball Created 05/22/99 // //+---------------------------------------------------------------------------- DWORD GetRasCallBackType() { if (OS_NT5) { return 2; } else { return -1; } } //+---------------------------------------------------------------------------- // // Function: GetRasCallBack // // Synopsis: Simple function to return the Callback that we use for RasDial // depending upon the OS. // // Arguments: ArgsStruct *pArgs - Ptr to global args struct // // Returns: LPVOID - The callback // // History: nickball Created 05/22/99 // //+---------------------------------------------------------------------------- LPVOID GetRasCallBack(ArgsStruct* pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return NULL; } // // Now set return the callback func or hwnd according to OS. // if (OS_NT5) { // // Set Callback data in RasDialParams // if (pArgs->pRasDialParams->dwSize == sizeof(RASDIALPARAMS_V401)) { ((LPRASDIALPARAMS_V401)pArgs->pRasDialParams)->dwCallbackId = (ULONG_PTR) pArgs; } return (LPVOID) RasDialFunc2; } else { MYDBGASSERT(pArgs->hwndMainDlg); return (LPVOID) pArgs->hwndMainDlg; } } //+---------------------------------------------------------------------------- // // Function: AllocateSecurityDescriptorAllowAccessToWorld // // Synopsis: This function allocates a security descriptor for all users. // This function was taken directly from RAS when they create their // phonebook. This has to be before GetPhoneBookPath otherwise it // causes compile errors in other components since we don't have a // function prototype anywhere and cmcfg just includes this (getpbk.cpp) // file. This function is also in common\source\getpbk.cpp // // Arguments: PSECURITY_DESCRIPTOR *ppSd - Pointer to a pointer to the SD struct // // Returns: DWORD - returns ERROR_SUCCESS if successfull // // History: 06/27/2001 tomkel Taken from RAS ui\common\pbk\file.c // //+---------------------------------------------------------------------------- #define SIZE_ALIGNED_FOR_TYPE(_size, _type) \ (((_size) + sizeof(_type)-1) & ~(sizeof(_type)-1)) DWORD AllocateSecurityDescriptorAllowAccessToWorld(PSECURITY_DESCRIPTOR *ppSd) { PSECURITY_DESCRIPTOR pSd; PSID pSid; PACL pDacl; DWORD dwErr = ERROR_SUCCESS; DWORD dwAlignSdSize; DWORD dwAlignDaclSize; DWORD dwSidSize; PVOID pvBuffer; DWORD dwAcls = 0; // Here is the buffer we are building. // // |<- a ->|<- b ->|<- c ->| // +-------+--------+------+ // | p| p| | // | SD a| DACL a| SID | // | d| d| | // +-------+-------+-------+ // ^ ^ ^ // | | | // | | +--pSid // | | // | +--pDacl // | // +--pSd (this is returned via *ppSd) // // pad is so that pDacl and pSid are aligned properly. // // a = dwAlignSdSize // b = dwAlignDaclSize // c = dwSidSize // if (NULL == ppSd) { return ERROR_INVALID_PARAMETER; } // Initialize output parameter. // *ppSd = NULL; // Compute the size of the SID. The SID is the well-known SID for World // (S-1-1-0). // dwSidSize = GetSidLengthRequired(1); // Compute the size of the DACL. It has an inherent copy of SID within // it so add enough room for it. It also must sized properly so that // a pointer to a SID structure can come after it. Hence, we use // SIZE_ALIGNED_FOR_TYPE. // dwAlignDaclSize = SIZE_ALIGNED_FOR_TYPE( sizeof(ACCESS_ALLOWED_ACE) + sizeof(ACL) + dwSidSize, PSID); // Compute the size of the SD. It must be sized propertly so that a // pointer to a DACL structure can come after it. Hence, we use // SIZE_ALIGNED_FOR_TYPE. // dwAlignSdSize = SIZE_ALIGNED_FOR_TYPE( sizeof(SECURITY_DESCRIPTOR), PACL); // Allocate the buffer big enough for all. // dwErr = ERROR_OUTOFMEMORY; pvBuffer = CmMalloc(dwSidSize + dwAlignDaclSize + dwAlignSdSize); if (pvBuffer) { SID_IDENTIFIER_AUTHORITY SidIdentifierWorldAuth = SECURITY_WORLD_SID_AUTHORITY; PULONG pSubAuthority; dwErr = NOERROR; // Setup the pointers into the buffer. // pSd = pvBuffer; pDacl = (PACL)((PBYTE)pvBuffer + dwAlignSdSize); pSid = (PSID)((PBYTE)pDacl + dwAlignDaclSize); // Initialize pSid as S-1-1-0. // if (!InitializeSid( pSid, &SidIdentifierWorldAuth, 1)) // 1 sub-authority { dwErr = GetLastError(); goto finish; } pSubAuthority = GetSidSubAuthority(pSid, 0); *pSubAuthority = SECURITY_WORLD_RID; // Initialize pDacl. // if (!InitializeAcl( pDacl, dwAlignDaclSize, ACL_REVISION)) { dwErr = GetLastError(); goto finish; } dwAcls = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; dwAcls &= ~(WRITE_DAC | WRITE_OWNER); if(!AddAccessAllowedAce( pDacl, ACL_REVISION, dwAcls, pSid)) { dwErr = GetLastError(); goto finish; } // Initialize pSd. // if (!InitializeSecurityDescriptor( pSd, SECURITY_DESCRIPTOR_REVISION)) { dwErr = GetLastError(); goto finish; } // Set pSd to use pDacl. // if (!SetSecurityDescriptorDacl( pSd, TRUE, pDacl, FALSE)) { dwErr = GetLastError(); goto finish; } // Set the owner for pSd. // if (!SetSecurityDescriptorOwner( pSd, NULL, TRUE)) { dwErr = GetLastError(); goto finish; } // Set the group for pSd. // if (!SetSecurityDescriptorGroup( pSd, NULL, FALSE)) { dwErr = GetLastError(); goto finish; } finish: if (!dwErr) { *ppSd = pSd; } else { CmFree(pvBuffer); } } return dwErr; }