954 lines
22 KiB
C
954 lines
22 KiB
C
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
|
||
|
//
|
||
|
// FILE
|
||
|
//
|
||
|
// iasparms.cpp
|
||
|
//
|
||
|
// SYNOPSIS
|
||
|
//
|
||
|
// Defines functions for storing and retrieving (name, value) pairs from
|
||
|
// the SAM UserParameters field.
|
||
|
//
|
||
|
// MODIFICATION HISTORY
|
||
|
//
|
||
|
// 10/16/1998 Original version.
|
||
|
// 02/11/1999 Add RasUser0 functions.
|
||
|
// 02/24/1999 Treat invalid UserParameters as no dialin.
|
||
|
// 03/16/1999 Truncate callback number if too long.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#define IASSAMAPI
|
||
|
|
||
|
#include <iasapi.h>
|
||
|
#include <iasparms.h>
|
||
|
|
||
|
//////////
|
||
|
// I included the Netp function declarations here to avoid dependency on
|
||
|
// the net project.
|
||
|
//////////
|
||
|
|
||
|
DECLSPEC_IMPORT
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
NetpParmsSetUserProperty (
|
||
|
IN LPWSTR UserParms,
|
||
|
IN LPWSTR Property,
|
||
|
IN UNICODE_STRING PropertyValue,
|
||
|
IN WCHAR PropertyFlag,
|
||
|
OUT LPWSTR * pNewUserParms,
|
||
|
OUT BOOL * Update
|
||
|
);
|
||
|
|
||
|
DECLSPEC_IMPORT
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
NetpParmsQueryUserProperty (
|
||
|
IN LPWSTR UserParms,
|
||
|
IN LPWSTR Property,
|
||
|
OUT PWCHAR PropertyFlag,
|
||
|
OUT PUNICODE_STRING PropertyValue
|
||
|
);
|
||
|
|
||
|
DECLSPEC_IMPORT
|
||
|
VOID
|
||
|
NTAPI
|
||
|
NetpParmsUserPropertyFree (
|
||
|
LPWSTR NewUserParms
|
||
|
);
|
||
|
|
||
|
//////////
|
||
|
// Concatenates two BSTR's and returns the result. The caller is responsible
|
||
|
// for freeing the returned string.
|
||
|
//////////
|
||
|
BSTR
|
||
|
WINAPI
|
||
|
ConcatentateBSTRs(
|
||
|
IN CONST OLECHAR *bstr1,
|
||
|
IN CONST OLECHAR *bstr2
|
||
|
)
|
||
|
{
|
||
|
UINT len1, len2;
|
||
|
BSTR retval;
|
||
|
|
||
|
// Compute the lengths of the two strings.
|
||
|
len1 = bstr1 ? SysStringByteLen((BSTR)bstr1) : 0;
|
||
|
len2 = bstr2 ? SysStringByteLen((BSTR)bstr2) : 0;
|
||
|
|
||
|
// Allocate memory for the result.
|
||
|
retval = SysAllocStringByteLen(NULL, len1 + len2);
|
||
|
|
||
|
if (retval)
|
||
|
{
|
||
|
// Copy in the first string.
|
||
|
if (bstr1)
|
||
|
{
|
||
|
memcpy(retval, bstr1, len1 + sizeof(WCHAR));
|
||
|
}
|
||
|
|
||
|
// Copy in the second string.
|
||
|
if (bstr2)
|
||
|
{
|
||
|
memcpy((PBYTE)retval + len1, bstr2, len2 + sizeof(WCHAR));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Saves a single-valued VARIANT (i.e., not a SAFEARRAY) to a string.
|
||
|
//////////
|
||
|
HRESULT
|
||
|
WINAPI
|
||
|
SaveSingleVariantToString(
|
||
|
IN CONST VARIANT *pvarSrc,
|
||
|
OUT BSTR *pbstrDest
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
VARIANT v;
|
||
|
UINT len;
|
||
|
OLECHAR tag[18]; // 5 + 1 + 10 + 1 + 1
|
||
|
|
||
|
// Coerce the VARIANT to a BSTR.
|
||
|
VariantInit(&v);
|
||
|
hr = IASVariantChangeType(
|
||
|
&v,
|
||
|
(LPVARIANT)pvarSrc,
|
||
|
0,
|
||
|
VT_BSTR
|
||
|
);
|
||
|
if (FAILED(hr)) { return hr; }
|
||
|
|
||
|
// Compute the length of the header and the data.
|
||
|
len = SysStringLen(V_BSTR(&v));
|
||
|
len += swprintf(tag, L"%hu:%lu:", V_VT(pvarSrc), len);
|
||
|
|
||
|
// Allocate the result string.
|
||
|
*pbstrDest = SysAllocStringLen(NULL, len);
|
||
|
if (*pbstrDest != NULL)
|
||
|
{
|
||
|
// Copy in the tag and the data.
|
||
|
wcscat(wcscpy(*pbstrDest, tag), V_BSTR(&v));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
// Clear the intermediate string.
|
||
|
VariantClear(&v);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Loads a single-valued VARIANT (i.e., not a SAFEARRAY) from a string.
|
||
|
// Also returns a pointer to where the scan stopped.
|
||
|
//////////
|
||
|
HRESULT
|
||
|
WINAPI
|
||
|
LoadSingleVariantFromString(
|
||
|
IN PCWSTR pszSrc,
|
||
|
IN UINT cSrcLen,
|
||
|
OUT VARIANT *pvarDest,
|
||
|
OUT PCWSTR *ppszEnd
|
||
|
)
|
||
|
{
|
||
|
PCWSTR nptr;
|
||
|
VARTYPE vt;
|
||
|
PWSTR endptr;
|
||
|
ULONG len;
|
||
|
VARIANT v;
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Initialize the cursor.
|
||
|
nptr = pszSrc;
|
||
|
|
||
|
// Read the VARTYPE token.
|
||
|
vt = (VARTYPE)wcstoul(nptr, &endptr, 10);
|
||
|
if (endptr == nptr || *endptr != L':') { return E_INVALIDARG; }
|
||
|
nptr = endptr + 1;
|
||
|
|
||
|
// Read the length token.
|
||
|
len = wcstoul(nptr, &endptr, 10);
|
||
|
if (endptr == nptr || *endptr != L':') { return E_INVALIDARG; }
|
||
|
nptr = endptr + 1;
|
||
|
|
||
|
// Make sure there's enough characters left for the data.
|
||
|
if (nptr + len > pszSrc + cSrcLen) { return E_INVALIDARG; }
|
||
|
|
||
|
// Read the BSTR data into a VARIANT.
|
||
|
V_VT(&v) = VT_BSTR;
|
||
|
V_BSTR(&v) = SysAllocStringLen(nptr, len);
|
||
|
if (V_BSTR(&v) == NULL) { return E_OUTOFMEMORY; }
|
||
|
|
||
|
// Coerce the VARIANT to the desired type.
|
||
|
hr = IASVariantChangeType(
|
||
|
pvarDest,
|
||
|
&v,
|
||
|
0,
|
||
|
vt
|
||
|
);
|
||
|
|
||
|
// Clear the intermediate string.
|
||
|
VariantClear(&v);
|
||
|
|
||
|
// Return the position where the scan stopped.
|
||
|
*ppszEnd = nptr + len;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Saves a VARIANT to a string. The caller is responsible for freeing the
|
||
|
// returned string.
|
||
|
//////////
|
||
|
HRESULT
|
||
|
WINAPI
|
||
|
IASSaveVariantToString(
|
||
|
IN CONST VARIANT *pvarSrc,
|
||
|
OUT BSTR *pbstrDest
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
SAFEARRAY *psa;
|
||
|
LONG lowerBound, upperBound, idx;
|
||
|
VARIANT *data;
|
||
|
BSTR item, newResult;
|
||
|
|
||
|
// Check the input arguments.
|
||
|
if (pvarSrc == NULL || pbstrDest == NULL) { return E_POINTER; }
|
||
|
|
||
|
// Initialize the return parameter.
|
||
|
*pbstrDest = NULL;
|
||
|
|
||
|
// Is this an array ?
|
||
|
if (V_VT(pvarSrc) != (VT_VARIANT | VT_ARRAY))
|
||
|
{
|
||
|
// No, so we can delegate and bail.
|
||
|
return SaveSingleVariantToString(pvarSrc, pbstrDest);
|
||
|
}
|
||
|
|
||
|
// Yes, so extract the SAFEARRAY.
|
||
|
psa = V_ARRAY(pvarSrc);
|
||
|
|
||
|
// We only handle one-dimensional arrays.
|
||
|
if (SafeArrayGetDim(psa) != 1) { return DISP_E_TYPEMISMATCH; }
|
||
|
|
||
|
// Get the array bounds.
|
||
|
hr = SafeArrayGetLBound(psa, 1, &lowerBound);
|
||
|
if (FAILED(hr)) { return hr; }
|
||
|
hr = SafeArrayGetUBound(psa, 1, &upperBound);
|
||
|
if (FAILED(hr)) { return hr; }
|
||
|
|
||
|
// Get the embedded array of VARIANTs.
|
||
|
hr = SafeArrayAccessData(psa, (PVOID*)&data);
|
||
|
|
||
|
// Loop through each VARIANT in the array.
|
||
|
for (idx = lowerBound; idx <= upperBound; ++idx, ++data)
|
||
|
{
|
||
|
// Save the VARIANT into a BSTR.
|
||
|
hr = SaveSingleVariantToString(data, &item);
|
||
|
if (FAILED(hr)) { break; }
|
||
|
|
||
|
// Merge this into the result ...
|
||
|
newResult = ConcatentateBSTRs(*pbstrDest, item);
|
||
|
|
||
|
// ... and free the old strings.
|
||
|
SysFreeString(*pbstrDest);
|
||
|
SysFreeString(item);
|
||
|
|
||
|
// Store the new result.
|
||
|
*pbstrDest = newResult;
|
||
|
|
||
|
if (!newResult)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If anything went wrong, clean-up the partial result.
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
SysFreeString(*pbstrDest);
|
||
|
*pbstrDest = NULL;
|
||
|
}
|
||
|
|
||
|
// Unlock the array.
|
||
|
SafeArrayUnaccessData(psa);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Loads a VARIANT from a string. The caller is responsible for freeing the
|
||
|
// returned VARIANT.
|
||
|
//////////
|
||
|
HRESULT
|
||
|
WINAPI
|
||
|
IASLoadVariantFromString(
|
||
|
IN PCWSTR pszSrc,
|
||
|
IN UINT cSrcLen,
|
||
|
OUT VARIANT *pvarDest
|
||
|
)
|
||
|
{
|
||
|
PCWSTR end;
|
||
|
HRESULT hr;
|
||
|
SAFEARRAYBOUND bound;
|
||
|
SAFEARRAY *psa;
|
||
|
LONG index;
|
||
|
VARIANT* item;
|
||
|
|
||
|
// Check the parameters.
|
||
|
if (pszSrc == NULL || pvarDest == NULL) { return E_POINTER; }
|
||
|
|
||
|
// Initialize the out parameter.
|
||
|
VariantInit(pvarDest);
|
||
|
|
||
|
// Compute the end of the buffer.
|
||
|
end = pszSrc + cSrcLen;
|
||
|
|
||
|
// Go for the quick score on a single-valued property.
|
||
|
hr = LoadSingleVariantFromString(
|
||
|
pszSrc,
|
||
|
cSrcLen,
|
||
|
pvarDest,
|
||
|
&pszSrc
|
||
|
);
|
||
|
if (FAILED(hr) || pszSrc == end) { return hr; }
|
||
|
|
||
|
// Create a SAFEARRAY of VARIANTs to hold the array elements.
|
||
|
// We know we have at least two elements.
|
||
|
bound.cElements = 2;
|
||
|
bound.lLbound = 0;
|
||
|
psa = SafeArrayCreate(VT_VARIANT, 1, &bound);
|
||
|
if (psa == NULL)
|
||
|
{
|
||
|
VariantClear(pvarDest);
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
// Store the VARIANT we already converted.
|
||
|
index = 0;
|
||
|
SafeArrayPtrOfIndex(psa, &index, (PVOID*)&item);
|
||
|
memcpy(item, pvarDest, sizeof(VARIANT));
|
||
|
|
||
|
// Now put the SAFEARRAY into the returned VARIANT.
|
||
|
V_VT(pvarDest) = VT_ARRAY | VT_VARIANT;
|
||
|
V_ARRAY(pvarDest) = psa;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Get the next element in the array.
|
||
|
++index;
|
||
|
hr = SafeArrayPtrOfIndex(psa, &index, (PVOID*)&item);
|
||
|
if (FAILED(hr)) { break; }
|
||
|
|
||
|
// Load the next value.
|
||
|
hr = LoadSingleVariantFromString(
|
||
|
pszSrc,
|
||
|
(UINT)(end - pszSrc),
|
||
|
item,
|
||
|
&pszSrc
|
||
|
);
|
||
|
if (FAILED(hr) || pszSrc == end) { break; }
|
||
|
|
||
|
// We must have at least one more element, so grow the array.
|
||
|
++bound.cElements;
|
||
|
hr = SafeArrayRedim(psa, &bound);
|
||
|
|
||
|
} while (SUCCEEDED(hr));
|
||
|
|
||
|
// If we failed, clean-up any partial results.
|
||
|
if (FAILED(hr)) { VariantClear(pvarDest); }
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
WINAPI
|
||
|
IASParmsSetUserProperty(
|
||
|
IN PCWSTR pszUserParms,
|
||
|
IN PCWSTR pszName,
|
||
|
IN CONST VARIANT *pvarValue,
|
||
|
OUT PWSTR *ppszNewUserParms
|
||
|
)
|
||
|
{
|
||
|
BSTR bstrValue;
|
||
|
UNICODE_STRING uniValue;
|
||
|
NTSTATUS status;
|
||
|
HRESULT hr;
|
||
|
BOOL update;
|
||
|
|
||
|
// Check the parameters.
|
||
|
if (pvarValue == NULL || ppszNewUserParms == NULL) { return E_POINTER; }
|
||
|
|
||
|
// Initialize the out parameter.
|
||
|
*ppszNewUserParms = NULL;
|
||
|
|
||
|
// Is the VARIANT empty ?
|
||
|
if (V_VT(pvarValue) != VT_EMPTY)
|
||
|
{
|
||
|
// No, so save it to a string.
|
||
|
hr = IASSaveVariantToString(
|
||
|
pvarValue,
|
||
|
&bstrValue
|
||
|
);
|
||
|
if (FAILED(hr)) { return hr; }
|
||
|
|
||
|
RtlInitUnicodeString(&uniValue, bstrValue);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Yes, so we're actually going to erase the property.
|
||
|
bstrValue = NULL;
|
||
|
memset(&uniValue, 0, sizeof(UNICODE_STRING));
|
||
|
}
|
||
|
|
||
|
// Write the property to UserParms.
|
||
|
status = NetpParmsSetUserProperty(
|
||
|
(PWSTR)pszUserParms,
|
||
|
(PWSTR)pszName,
|
||
|
uniValue,
|
||
|
0,
|
||
|
ppszNewUserParms,
|
||
|
&update
|
||
|
);
|
||
|
|
||
|
if (NT_SUCCESS(status))
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = RtlNtStatusToDosError(status);
|
||
|
hr = HRESULT_FROM_WIN32(status);
|
||
|
}
|
||
|
|
||
|
// Free the BSTR value.
|
||
|
SysFreeString(bstrValue);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
WINAPI
|
||
|
IASParmsQueryUserProperty(
|
||
|
IN PCWSTR pszUserParms,
|
||
|
IN PCWSTR pszName,
|
||
|
OUT VARIANT *pvarValue
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
HRESULT hr;
|
||
|
WCHAR flag;
|
||
|
UNICODE_STRING uniValue;
|
||
|
|
||
|
// Check the parameters.
|
||
|
if (pvarValue == NULL) { return E_POINTER; }
|
||
|
|
||
|
// Initialize the out parameter.
|
||
|
VariantInit(pvarValue);
|
||
|
|
||
|
// Get the property from UserParms.
|
||
|
status = NetpParmsQueryUserProperty(
|
||
|
(PWSTR)pszUserParms,
|
||
|
(PWSTR)pszName,
|
||
|
&flag,
|
||
|
&uniValue
|
||
|
);
|
||
|
if (NT_SUCCESS(status))
|
||
|
{
|
||
|
if (uniValue.Buffer != NULL)
|
||
|
{
|
||
|
// We got a string so convert it to a VARIANT ...
|
||
|
hr = IASLoadVariantFromString(
|
||
|
uniValue.Buffer,
|
||
|
uniValue.Length / sizeof (WCHAR),
|
||
|
pvarValue
|
||
|
);
|
||
|
|
||
|
// ... and free the string.
|
||
|
LocalFree(uniValue.Buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Buffer is zero-length, so we return VT_EMPTY.
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = RtlNtStatusToDosError(status);
|
||
|
hr = HRESULT_FROM_WIN32(status);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
WINAPI
|
||
|
IASParmsFreeUserParms(
|
||
|
IN PWSTR pszNewUserParms
|
||
|
)
|
||
|
{
|
||
|
LocalFree(pszNewUserParms);
|
||
|
}
|
||
|
|
||
|
/////////
|
||
|
// Constants used for compressing/decompressing phone numbers.
|
||
|
/////////
|
||
|
|
||
|
CONST WCHAR COMPRESS_MAP[] = L"() tTpPwW,-@*#";
|
||
|
|
||
|
#define UNPACKED_DIGIT (100)
|
||
|
#define COMPRESS_MAP_BEGIN (110)
|
||
|
#define COMPRESS_MAP_END (COMPRESS_MAP_BEGIN + 14)
|
||
|
#define UNPACKED_OTHER (COMPRESS_MAP_END + 1)
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// FUNCTION
|
||
|
//
|
||
|
// CompressPhoneNumber
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// Bizarre algorithm used to compress phone numbers stored in the
|
||
|
// usr_parms field.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
VOID
|
||
|
WINAPI
|
||
|
CompressPhoneNumber(
|
||
|
IN PCWSTR uncompressed,
|
||
|
OUT PWSTR compressed
|
||
|
)
|
||
|
{
|
||
|
BOOL packed = FALSE;
|
||
|
|
||
|
for( ; *uncompressed; ++uncompressed)
|
||
|
{
|
||
|
switch (*uncompressed)
|
||
|
{
|
||
|
case L'0':
|
||
|
|
||
|
if (packed)
|
||
|
{
|
||
|
// Put zero as the second paired digit
|
||
|
if (*compressed)
|
||
|
{
|
||
|
*compressed *= 10;
|
||
|
++compressed;
|
||
|
packed = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We have a zero, we cant put a second zero or that
|
||
|
// will be a null byte. So, we store the value
|
||
|
// UNPACKED_DIGIT to fake this.
|
||
|
|
||
|
*compressed = UNPACKED_DIGIT;
|
||
|
*(++compressed) = 0;
|
||
|
packed = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*compressed = 0;
|
||
|
packed = TRUE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case L'1':
|
||
|
case L'2':
|
||
|
case L'3':
|
||
|
case L'4':
|
||
|
case L'5':
|
||
|
case L'6':
|
||
|
case L'7':
|
||
|
case L'8':
|
||
|
case L'9':
|
||
|
|
||
|
// If this is the second digit that is going to be
|
||
|
// packed into one byte
|
||
|
if (packed)
|
||
|
{
|
||
|
*compressed *= 10;
|
||
|
*compressed += *uncompressed - L'0';
|
||
|
|
||
|
// we need to special case number 32 which maps to a blank
|
||
|
if (*compressed == L' ')
|
||
|
{
|
||
|
*compressed = COMPRESS_MAP_END;
|
||
|
}
|
||
|
|
||
|
++compressed;
|
||
|
packed = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*compressed = *uncompressed - '0';
|
||
|
packed = TRUE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case L'(':
|
||
|
case L')':
|
||
|
case L' ':
|
||
|
case L't':
|
||
|
case L'T':
|
||
|
case L'p':
|
||
|
case L'P':
|
||
|
case L'w':
|
||
|
case L'W':
|
||
|
case L',':
|
||
|
case L'-':
|
||
|
case L'@':
|
||
|
case L'*':
|
||
|
case L'#':
|
||
|
|
||
|
// if the byte was packed then we unpack it
|
||
|
if (packed)
|
||
|
{
|
||
|
*compressed += UNPACKED_DIGIT;
|
||
|
++compressed;
|
||
|
packed = FALSE;
|
||
|
}
|
||
|
|
||
|
*compressed = (WCHAR)(COMPRESS_MAP_BEGIN +
|
||
|
(wcschr(COMPRESS_MAP, *uncompressed) -
|
||
|
COMPRESS_MAP));
|
||
|
++compressed;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
// if the chracter is none of the above specially recognized
|
||
|
// characters then copy the value + UNPACKED_OTHER to make it
|
||
|
// possible to decompress at the other end. [ 6/4/96 RamC ]
|
||
|
if (packed)
|
||
|
{
|
||
|
*compressed += UNPACKED_DIGIT;
|
||
|
++compressed;
|
||
|
packed = FALSE;
|
||
|
}
|
||
|
|
||
|
*compressed = *uncompressed + UNPACKED_OTHER;
|
||
|
++compressed;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we are in the middle of packing something then we unpack it.
|
||
|
if (packed)
|
||
|
{
|
||
|
*compressed += UNPACKED_DIGIT;
|
||
|
++compressed;
|
||
|
}
|
||
|
|
||
|
// Add the null terminator.
|
||
|
*compressed = L'\0';
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// FUNCTION
|
||
|
//
|
||
|
// DecompressPhoneNumber
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// The inverse of CompressPhoneNumber above.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
VOID
|
||
|
WINAPI
|
||
|
DecompressPhoneNumber(
|
||
|
IN PCWSTR compressed,
|
||
|
OUT PWSTR decompressed
|
||
|
)
|
||
|
{
|
||
|
for( ; *compressed; ++compressed, ++decompressed)
|
||
|
{
|
||
|
// If this character is packed, then we unpack it.
|
||
|
if (*compressed < UNPACKED_DIGIT)
|
||
|
{
|
||
|
*decompressed = *compressed / 10 + L'0';
|
||
|
++decompressed;
|
||
|
*decompressed = *compressed % 10 + L'0';
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// We need to special case number 32 which maps to a blank.
|
||
|
if (*compressed == COMPRESS_MAP_END)
|
||
|
{
|
||
|
*decompressed = L'3';
|
||
|
++decompressed;
|
||
|
*decompressed = L'2';
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// The character is an unpacked digit.
|
||
|
if (*compressed < COMPRESS_MAP_BEGIN)
|
||
|
{
|
||
|
*decompressed = *compressed - UNPACKED_DIGIT + L'0';
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// The character is from the compression map.
|
||
|
if (*compressed < UNPACKED_OTHER)
|
||
|
{
|
||
|
*decompressed = COMPRESS_MAP[*compressed - COMPRESS_MAP_BEGIN];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Otherwise the character is unpacked.
|
||
|
*decompressed = *compressed - UNPACKED_OTHER;
|
||
|
}
|
||
|
|
||
|
// Add a null terminator.
|
||
|
*decompressed = L'\0';
|
||
|
}
|
||
|
|
||
|
/////////
|
||
|
// Definition of the downlevel UserParameters.
|
||
|
/////////
|
||
|
|
||
|
#define UP_CLIENT_MAC (L'm')
|
||
|
#define UP_CLIENT_DIAL (L'd')
|
||
|
#define UP_LEN_MAC (LM20_UNLEN)
|
||
|
#define UP_LEN_DIAL (LM20_MAXCOMMENTSZ - 4 - UP_LEN_MAC)
|
||
|
|
||
|
typedef struct {
|
||
|
WCHAR up_MACid;
|
||
|
WCHAR up_PriGrp[UP_LEN_MAC];
|
||
|
WCHAR up_MAC_Terminator;
|
||
|
WCHAR up_DIALid;
|
||
|
WCHAR up_Privilege;
|
||
|
WCHAR up_CBNum[UP_LEN_DIAL];
|
||
|
} USER_PARMS;
|
||
|
|
||
|
#define USER_PARMS_LEN (sizeof(USER_PARMS)/sizeof(WCHAR))
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// FUNCTION
|
||
|
//
|
||
|
// InitUserParms
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// Initializes a USER_PARMS struct to a valid default state.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
VOID
|
||
|
WINAPI
|
||
|
InitUserParms(
|
||
|
IN USER_PARMS* userParms
|
||
|
)
|
||
|
{
|
||
|
WCHAR *i, *end;
|
||
|
|
||
|
// Set everything to a space ' '.
|
||
|
i = (PWCHAR)userParms;
|
||
|
end = i + USER_PARMS_LEN;
|
||
|
for ( ; i != end; ++i)
|
||
|
{
|
||
|
*i = L' ';
|
||
|
}
|
||
|
|
||
|
// Initialize the 'special' fields.
|
||
|
userParms->up_MACid = UP_CLIENT_MAC;
|
||
|
userParms->up_PriGrp[0] = L':';
|
||
|
userParms->up_DIALid = UP_CLIENT_DIAL;
|
||
|
userParms->up_Privilege = RASPRIV_NoCallback;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// FUNCTION
|
||
|
//
|
||
|
// IASParmsSetRasUser0
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// Encodes the RAS_USER_0 struct into the downlevel portion of the
|
||
|
// UserParameters string.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
IASParmsSetRasUser0(
|
||
|
IN OPTIONAL PCWSTR pszOldUserParms,
|
||
|
IN CONST RAS_USER_0* pRasUser0,
|
||
|
OUT PWSTR* ppszNewUserParms
|
||
|
)
|
||
|
{
|
||
|
size_t oldLen, newLen, compressedLen;
|
||
|
USER_PARMS userParms;
|
||
|
WCHAR compressed[MAX_PHONE_NUMBER_LEN + 1];
|
||
|
|
||
|
// Check the pointers.
|
||
|
if (pRasUser0 == NULL || ppszNewUserParms == NULL)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
// Initialize the out parameters.
|
||
|
*ppszNewUserParms = NULL;
|
||
|
|
||
|
// Determine the length of the old UserParameters.
|
||
|
oldLen = pszOldUserParms ? wcslen(pszOldUserParms) : 0;
|
||
|
|
||
|
// Initialize the USER_PARMS structure.
|
||
|
InitUserParms(&userParms);
|
||
|
|
||
|
// Preserve the MAC Primary Group if present.
|
||
|
if (oldLen > UP_LEN_MAC)
|
||
|
{
|
||
|
memcpy(
|
||
|
userParms.up_PriGrp,
|
||
|
pszOldUserParms + 1,
|
||
|
sizeof(userParms.up_PriGrp)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Validate the CallbackType and save the compressed phone number.
|
||
|
switch (pRasUser0->bfPrivilege & RASPRIV_CallbackType)
|
||
|
{
|
||
|
case RASPRIV_NoCallback:
|
||
|
case RASPRIV_AdminSetCallback:
|
||
|
case RASPRIV_CallerSetCallback:
|
||
|
{
|
||
|
|
||
|
// Compress the phone number.
|
||
|
CompressPhoneNumber(pRasUser0->wszPhoneNumber, compressed);
|
||
|
|
||
|
// Make sure it will fit in USER_PARMS.
|
||
|
compressedLen = wcslen(compressed);
|
||
|
if (compressedLen > UP_LEN_DIAL) { compressedLen = UP_LEN_DIAL; }
|
||
|
|
||
|
// Store the compressed phone number.
|
||
|
memcpy(userParms.up_CBNum, compressed, compressedLen * sizeof(WCHAR));
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
return ERROR_BAD_FORMAT;
|
||
|
}
|
||
|
|
||
|
// Store the privilege flags.
|
||
|
userParms.up_Privilege = pRasUser0->bfPrivilege;
|
||
|
|
||
|
// Allocate memory for the new UserParameters.
|
||
|
newLen = max(oldLen, USER_PARMS_LEN);
|
||
|
*ppszNewUserParms = (PWSTR)LocalAlloc(
|
||
|
LMEM_FIXED,
|
||
|
(newLen + 1) * sizeof(WCHAR)
|
||
|
);
|
||
|
if (*ppszNewUserParms == NULL) { return ERROR_NOT_ENOUGH_MEMORY; }
|
||
|
|
||
|
// Copy in the USER_PARMS struct.
|
||
|
memcpy(*ppszNewUserParms, &userParms, sizeof(USER_PARMS));
|
||
|
|
||
|
// Copy in any extra stuff.
|
||
|
if (oldLen > USER_PARMS_LEN)
|
||
|
{
|
||
|
memcpy(
|
||
|
*ppszNewUserParms + USER_PARMS_LEN,
|
||
|
pszOldUserParms + USER_PARMS_LEN,
|
||
|
(oldLen - USER_PARMS_LEN) * sizeof(WCHAR)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Add the null terminator.
|
||
|
*(*ppszNewUserParms + newLen) = L'\0';
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// FUNCTION
|
||
|
//
|
||
|
// IASParmsQueryRasUser0
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// Decodes the RAS_USER_0 struct from the UserParameters string.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
IASParmsQueryRasUser0(
|
||
|
IN OPTIONAL PCWSTR pszUserParms,
|
||
|
OUT PRAS_USER_0 pRasUser0
|
||
|
)
|
||
|
{
|
||
|
USER_PARMS* usrp;
|
||
|
WCHAR callbackNumber[UP_LEN_DIAL + 1], *p;
|
||
|
|
||
|
// Check the pointers.
|
||
|
if (pRasUser0 == NULL)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
// Cast the string buffer to a USER_PARMS struct.
|
||
|
usrp = (USER_PARMS*)pszUserParms;
|
||
|
|
||
|
// If parms is not properly initialized, default to no RAS privilege.
|
||
|
if (!pszUserParms ||
|
||
|
wcslen(pszUserParms) < USER_PARMS_LEN ||
|
||
|
usrp->up_DIALid != UP_CLIENT_DIAL)
|
||
|
{
|
||
|
pRasUser0->bfPrivilege = RASPRIV_NoCallback;
|
||
|
pRasUser0->wszPhoneNumber[0] = L'\0';
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
// Make a local copy.
|
||
|
memcpy(callbackNumber, usrp->up_CBNum, sizeof(WCHAR) * UP_LEN_DIAL);
|
||
|
|
||
|
// Add a null terminator and null out any trailing blanks.
|
||
|
p = callbackNumber + UP_LEN_DIAL;
|
||
|
*p = L'\0';
|
||
|
while (--p >= callbackNumber && *p == L' ') { *p = L'\0'; }
|
||
|
|
||
|
// Sanity check the bfPrivilege field.
|
||
|
switch(usrp->up_Privilege & RASPRIV_CallbackType)
|
||
|
{
|
||
|
case RASPRIV_NoCallback:
|
||
|
case RASPRIV_AdminSetCallback:
|
||
|
case RASPRIV_CallerSetCallback:
|
||
|
{
|
||
|
pRasUser0->bfPrivilege = (BYTE)usrp->up_Privilege;
|
||
|
DecompressPhoneNumber(callbackNumber, pRasUser0->wszPhoneNumber);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
pRasUser0->bfPrivilege = RASPRIV_NoCallback;
|
||
|
pRasUser0->wszPhoneNumber[0] = L'\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|