2426 lines
53 KiB
C++
2426 lines
53 KiB
C++
#include "NWCOMPAT.hxx"
|
|
#pragma hdrstop
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGetProperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGetProperty(
|
|
BSTR bstrObjectName,
|
|
LPSTR lpszPropertyName,
|
|
NWOBJ_TYPE dwOT_ID,
|
|
NWCONN_HANDLE hConn,
|
|
LPP_RPLY_SGMT_LST lppReplySegment,
|
|
LPDWORD pdwNumSegment
|
|
)
|
|
{
|
|
CHAR szObjectName[(OBJ_NAME_SIZE + 1)*2];
|
|
NWFLAGS pucMoreFlag = 0;
|
|
NWFLAGS pucPropFlag = 0;
|
|
unsigned char ucSegment = 1;
|
|
LP_RPLY_SGMT_LST lpHeadReplySegment = NULL;
|
|
LP_RPLY_SGMT_LST lpTempReplySegment = NULL;
|
|
LP_RPLY_SGMT_LST lpTemp = NULL;
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = 0;
|
|
|
|
//
|
|
// lppReplySegment is assumed to be NULL.
|
|
//
|
|
|
|
ADsAssert((*lppReplySegment) == NULL);
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
|
|
if (wcslen(bstrObjectName) > OBJ_NAME_SIZE) {
|
|
hr = E_INVALIDARG;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
bstrObjectName,
|
|
szObjectName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Initialize first node of the list and set up temp traversal pointer.
|
|
//
|
|
|
|
INIT_RPLY_SGMT(lpTempReplySegment);
|
|
lpHeadReplySegment = lpTempReplySegment;
|
|
|
|
//
|
|
// Read & dump property values into linked-list.
|
|
//
|
|
|
|
do {
|
|
|
|
usRet = NWCReadPropertyValue(
|
|
hConn,
|
|
szObjectName,
|
|
dwOT_ID,
|
|
lpszPropertyName,
|
|
ucSegment,
|
|
lpTempReplySegment->Segment,
|
|
&pucMoreFlag,
|
|
&pucPropFlag
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (pucMoreFlag) {
|
|
|
|
INIT_RPLY_SGMT(lpTempReplySegment->lpNext);
|
|
lpTempReplySegment = lpTempReplySegment->lpNext;
|
|
|
|
ucSegment++;
|
|
}
|
|
|
|
} while(pucMoreFlag);
|
|
|
|
//
|
|
// Return the resulting linked-list.
|
|
//
|
|
|
|
*lppReplySegment = lpHeadReplySegment;
|
|
*pdwNumSegment = ucSegment;
|
|
|
|
error:
|
|
if (FAILED(hr) && lpHeadReplySegment) {
|
|
|
|
DELETE_LIST(lpHeadReplySegment);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGetFileServerVersionInfo
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGetFileServerVersionInfo(
|
|
NWCONN_HANDLE hConn,
|
|
VERSION_INFO *pVersionInfo
|
|
)
|
|
{
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
HRESULT hr = S_OK;
|
|
|
|
usRet = NWCGetFileServerVersionInfo(
|
|
hConn,
|
|
pVersionInfo
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiIsObjectInSet
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiIsObjectInSet(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszObjectName,
|
|
NWOBJ_TYPE wObjType,
|
|
LPSTR lpszPropertyName,
|
|
LPSTR lpszMemberName,
|
|
NWOBJ_TYPE wMemberType
|
|
)
|
|
{
|
|
CHAR szAnsiObjectName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
|
|
if (wcslen(lpszObjectName) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
lpszObjectName,
|
|
szAnsiObjectName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Call NWCIsObjectInSet.
|
|
//
|
|
|
|
usRet = NWCIsObjectInSet(
|
|
hConn,
|
|
szAnsiObjectName,
|
|
wObjType,
|
|
lpszPropertyName,
|
|
lpszMemberName,
|
|
wMemberType
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGetObjectID
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGetObjectID(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszObjectName,
|
|
NWOBJ_TYPE wObjType,
|
|
NWOBJ_ID *pObjectID
|
|
)
|
|
{
|
|
CHAR szAnsiObjectName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(lpszObjectName) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
lpszObjectName,
|
|
szAnsiObjectName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Get Object's ID.
|
|
//
|
|
|
|
usRet = NWCGetObjectID(
|
|
hConn,
|
|
szAnsiObjectName,
|
|
wObjType,
|
|
pObjectID
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGroupGetMembers
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGroupGetMembers(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR szGroupName,
|
|
LPBYTE *lppBuffer
|
|
)
|
|
{
|
|
DWORD dwNumSegment = 0;
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
LP_RPLY_SGMT_LST lpTemp = NULL;
|
|
LP_RPLY_SGMT_LST lpReplySegment = NULL;
|
|
|
|
//
|
|
// Assert
|
|
//
|
|
|
|
ADsAssert(*lppBuffer == NULL);
|
|
|
|
//
|
|
// Get GROUP_MEMBERS.
|
|
//
|
|
|
|
hr = NWApiGetProperty(
|
|
szGroupName,
|
|
NW_PROP_GROUP_MEMBERS,
|
|
OT_USER_GROUP,
|
|
hConn,
|
|
&lpReplySegment,
|
|
&dwNumSegment
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Pack returned linked list into buffer.
|
|
//
|
|
|
|
*lppBuffer = (LPBYTE) AllocADsMem(
|
|
dwNumSegment * REPLY_VALUE_SIZE
|
|
);
|
|
if (!(*lppBuffer)) {
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
|
|
lpTemp = lpReplySegment;
|
|
|
|
for (i = 0; i < dwNumSegment; i++) {
|
|
memcpy(
|
|
*lppBuffer + i * REPLY_VALUE_SIZE,
|
|
lpTemp->Segment,
|
|
REPLY_VALUE_SIZE
|
|
);
|
|
lpTemp = lpTemp->lpNext;
|
|
}
|
|
|
|
error:
|
|
|
|
//
|
|
// Clean up.
|
|
//
|
|
|
|
lpTemp = NULL;
|
|
|
|
if (lpReplySegment) {
|
|
DELETE_LIST(lpReplySegment);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiAddGroupMember
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiAddGroupMember(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR pszGroupName,
|
|
LPWSTR pszMemberName
|
|
)
|
|
{
|
|
CHAR szGroupName[(OBJ_NAME_SIZE + 1)*2];
|
|
CHAR szMemberName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(pszGroupName) > OBJ_NAME_SIZE) {
|
|
hr = E_INVALIDARG;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if (wcslen(pszMemberName) > OBJ_NAME_SIZE) {
|
|
hr = E_INVALIDARG;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
pszGroupName,
|
|
szGroupName,
|
|
0
|
|
);
|
|
|
|
UnicodeToAnsiString(
|
|
pszMemberName,
|
|
szMemberName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Modify GROUP_MEMBERS property of the group to include the new member.
|
|
//
|
|
|
|
usRet = NWCAddObjectToSet(
|
|
hConn,
|
|
szGroupName,
|
|
OT_USER_GROUP,
|
|
"GROUP_MEMBERS",
|
|
szMemberName,
|
|
OT_USER
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Modify GROUPS_I'M_IN property of the new member to reflect its included
|
|
// in the new group.
|
|
//
|
|
|
|
usRet = NWCAddObjectToSet(
|
|
hConn,
|
|
szMemberName,
|
|
OT_USER,
|
|
"GROUPS_I'M_IN",
|
|
szGroupName,
|
|
OT_USER_GROUP
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Modify SECURITY_EQUALS property of the new member to equate its security
|
|
// to that of the new group it just joined.
|
|
//
|
|
|
|
usRet = NWCAddObjectToSet(
|
|
hConn,
|
|
szMemberName,
|
|
OT_USER,
|
|
"SECURITY_EQUALS",
|
|
szGroupName,
|
|
OT_USER_GROUP
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiRemoveGroupMember
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiRemoveGroupMember(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR pszGroupName,
|
|
LPWSTR pszMemberName
|
|
)
|
|
{
|
|
CHAR szGroupName[(OBJ_NAME_SIZE + 1)*2];
|
|
CHAR szMemberName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(pszGroupName) > OBJ_NAME_SIZE) {
|
|
hr = E_INVALIDARG;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if (wcslen(pszMemberName) > OBJ_NAME_SIZE) {
|
|
hr = E_INVALIDARG;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
pszGroupName,
|
|
szGroupName,
|
|
0
|
|
);
|
|
|
|
UnicodeToAnsiString(
|
|
pszMemberName,
|
|
szMemberName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Modify SECURITY_EQUALS property of the removed member to break its
|
|
// security tie with the group it joined.
|
|
//
|
|
|
|
usRet = NWCDeleteObjectFromSet(
|
|
hConn,
|
|
szMemberName,
|
|
OT_USER,
|
|
"SECURITY_EQUALS",
|
|
szGroupName,
|
|
OT_USER_GROUP
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Modify GROUPS_I'M_IN property of the new member to reflect it is not
|
|
// included in the group anymore.
|
|
//
|
|
|
|
usRet = NWCDeleteObjectFromSet(
|
|
hConn,
|
|
szMemberName,
|
|
OT_USER,
|
|
"GROUPS_I'M_IN",
|
|
szGroupName,
|
|
OT_USER_GROUP
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Modify GROUP_MEMBERS property of the group to remove the member.
|
|
//
|
|
|
|
usRet = NWCDeleteObjectFromSet(
|
|
hConn,
|
|
szGroupName,
|
|
OT_USER_GROUP,
|
|
"GROUP_MEMBERS",
|
|
szMemberName,
|
|
OT_USER
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGetLOGIN_CONTROL
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGetLOGIN_CONTROL(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszUserName,
|
|
LPLC_STRUCTURE lpLoginCtrlStruct
|
|
)
|
|
{
|
|
DWORD dwNumSegment = 0;
|
|
HRESULT hr = S_OK;
|
|
LP_RPLY_SGMT_LST lpReplySegment = NULL;
|
|
LP_RPLY_SGMT_LST lpTemp = NULL;
|
|
|
|
hr = NWApiGetProperty(
|
|
lpszUserName,
|
|
NW_PROP_LOGIN_CONTROL,
|
|
OT_USER,
|
|
hConn,
|
|
&lpReplySegment,
|
|
&dwNumSegment
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
*lpLoginCtrlStruct = *((LPLC_STRUCTURE) lpReplySegment->Segment);
|
|
|
|
error:
|
|
|
|
if (lpReplySegment) {
|
|
DELETE_LIST(lpReplySegment);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiSetDefaultAcctExpDate
|
|
//
|
|
// Synopsis: This function looks at the local time and returns a default value
|
|
// for an account expiration date in a variant date.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiSetDefaultAcctExpDate(
|
|
DOUBLE * pdTime,
|
|
SYSTEMTIME SysTime
|
|
)
|
|
{
|
|
DOUBLE vTime;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// According to SysCon, the default account expiration date is the first day
|
|
// of the following month.
|
|
//
|
|
|
|
if (SysTime.wMonth == 12) {
|
|
SysTime.wMonth = 1;
|
|
}
|
|
else {
|
|
SysTime.wMonth++;
|
|
}
|
|
|
|
SysTime.wDay = 1;
|
|
|
|
//
|
|
// Subtract 1980 from wYear for NWApiMakeVariantTime.
|
|
//
|
|
|
|
SysTime.wYear -= 1980;
|
|
|
|
hr = NWApiMakeVariantTime(
|
|
&vTime,
|
|
SysTime.wDay,
|
|
SysTime.wMonth,
|
|
SysTime.wYear,
|
|
0,0,0
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
*pdTime = vTime;
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiUserAsSupervisor
|
|
//
|
|
// Synopsis: This functions turns the user into one of the supervisors if TRUE
|
|
// is passed. User's supervisor privilege is removed otherwise.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiUserAsSupervisor(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszUserName,
|
|
BOOL fSupervisor
|
|
)
|
|
{
|
|
CHAR szUserName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(lpszUserName) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
lpszUserName,
|
|
szUserName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Make it a supervisor.
|
|
//
|
|
|
|
if (fSupervisor == TRUE) {
|
|
usRet = NWCAddObjectToSet(
|
|
hConn,
|
|
szUserName,
|
|
OT_USER,
|
|
"SECURITY_EQUALS",
|
|
"SUPERVISOR",
|
|
OT_USER
|
|
);
|
|
}
|
|
|
|
//
|
|
// Remove supervisor privilege.
|
|
//
|
|
|
|
else {
|
|
usRet = NWCDeleteObjectFromSet(
|
|
hConn,
|
|
szUserName,
|
|
OT_USER,
|
|
"SECURITY_EQUALS",
|
|
"SUPERVISOR",
|
|
OT_USER
|
|
);
|
|
}
|
|
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGetVolumeNumber
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGetVolumeNumber(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszVolumeName,
|
|
NWVOL_NUM *pVolumeNumber
|
|
)
|
|
{
|
|
CHAR szVolumeName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(lpszVolumeName) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
lpszVolumeName,
|
|
szVolumeName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Get Volume's number.
|
|
//
|
|
|
|
usRet = NWCGetVolumeNumber(
|
|
hConn,
|
|
szVolumeName,
|
|
pVolumeNumber
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGetVolumeName
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGetVolumeName(
|
|
NWCONN_HANDLE hConn,
|
|
NWVOL_NUM bVolNum,
|
|
LPWSTR *lppszVolName
|
|
)
|
|
{
|
|
CHAR szVolumeName[OBJ_NAME_SIZE + 1];
|
|
HRESULT hr = S_OK;
|
|
LPWSTR lpszTemp = NULL;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Get Volume's name.
|
|
//
|
|
|
|
usRet = NWCGetVolumeName(
|
|
hConn,
|
|
bVolNum,
|
|
szVolumeName
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Convert result into Unicode.
|
|
//
|
|
|
|
lpszTemp = AllocateUnicodeString(szVolumeName);
|
|
if (!lpszTemp) {
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
|
|
*lppszVolName = AllocADsStr(lpszTemp);
|
|
if (!(*lppszVolName)) {
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
|
|
FreeUnicodeString(lpszTemp);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
*lppszVolName = NULL;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiEnumJobs
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiEnumJobs(
|
|
HANDLE hPrinter,
|
|
DWORD dwFirstJob,
|
|
DWORD dwNoJobs,
|
|
DWORD dwLevel,
|
|
LPBYTE *lplpbJobs,
|
|
DWORD *pcbBuf,
|
|
LPDWORD lpdwReturned
|
|
)
|
|
{
|
|
BOOL fStatus = TRUE;
|
|
HRESULT hr = S_OK;
|
|
|
|
fStatus = WinNTEnumJobs(
|
|
hPrinter,
|
|
dwFirstJob,
|
|
dwNoJobs,
|
|
dwLevel,
|
|
lplpbJobs,
|
|
pcbBuf,
|
|
lpdwReturned
|
|
);
|
|
|
|
if (fStatus == FALSE) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiGetPrinter
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiGetPrinter(
|
|
HANDLE hPrinter,
|
|
DWORD dwLevel,
|
|
LPBYTE *lplpbPrinters
|
|
)
|
|
{
|
|
BOOL fStatus = TRUE;
|
|
HRESULT hr = S_OK;
|
|
|
|
fStatus = WinNTGetPrinter(
|
|
hPrinter,
|
|
dwLevel,
|
|
lplpbPrinters
|
|
);
|
|
|
|
if (fStatus == FALSE) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiUncFromADsPath
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiUncFromADsPath(
|
|
LPWSTR lpszADsPath,
|
|
LPWSTR lpszUncName
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
POBJECTINFO pObjectInfo = NULL;
|
|
|
|
hr = BuildObjectInfo(lpszADsPath,
|
|
&pObjectInfo );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
wsprintf(
|
|
lpszUncName,
|
|
L"\\\\%s\\%s",
|
|
pObjectInfo->ComponentArray[0],
|
|
pObjectInfo->ComponentArray[1]
|
|
);
|
|
|
|
error:
|
|
if(pObjectInfo){
|
|
FreeObjectInfo(pObjectInfo);
|
|
}
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiMakeUserInfo
|
|
//
|
|
// Synopsis: This function is very provider specific.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiMakeUserInfo(
|
|
LPWSTR lpszBinderyName,
|
|
LPWSTR lpszUserName,
|
|
LPWSTR lpszPassword,
|
|
PNW_USER_INFO pNwUserInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NW_USER_INFO NwUserInfo = {NULL, NULL, NULL, NULL};
|
|
|
|
hr = NWApiGetBinderyHandle(
|
|
&NwUserInfo.hConn,
|
|
lpszBinderyName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsAllocString(lpszBinderyName, &NwUserInfo.lpszBinderyName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsAllocString(lpszUserName, &NwUserInfo.lpszUserName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (lpszPassword) {
|
|
|
|
hr = ADsAllocString(lpszPassword, &NwUserInfo.lpszPassword);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
*pNwUserInfo = NwUserInfo;
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
if (NwUserInfo.lpszBinderyName)
|
|
ADsFreeString(NwUserInfo.lpszBinderyName);
|
|
|
|
if (NwUserInfo.lpszUserName)
|
|
ADsFreeString(NwUserInfo.lpszUserName);
|
|
|
|
if (NwUserInfo.lpszPassword)
|
|
ADsFreeString(NwUserInfo.lpszPassword);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiFreeUserInfo
|
|
//
|
|
// Synopsis: This function is very provider specific.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiFreeUserInfo(
|
|
PNW_USER_INFO pNwUserInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pNwUserInfo->lpszBinderyName) {
|
|
ADsFreeString(pNwUserInfo->lpszBinderyName);
|
|
pNwUserInfo->lpszBinderyName = NULL ;
|
|
}
|
|
|
|
if (pNwUserInfo->lpszUserName) {
|
|
ADsFreeString(pNwUserInfo->lpszUserName);
|
|
pNwUserInfo->lpszUserName = NULL;
|
|
}
|
|
|
|
if (pNwUserInfo->lpszPassword) {
|
|
ADsFreeString(pNwUserInfo->lpszPassword);
|
|
pNwUserInfo->lpszPassword = NULL;
|
|
}
|
|
|
|
if (pNwUserInfo->hConn) {
|
|
hr = NWApiReleaseBinderyHandle(
|
|
pNwUserInfo->hConn
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiCreateUser
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiCreateUser(
|
|
PNW_USER_INFO pNwUserInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrTemp = S_OK;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
NWCONN_HANDLE hConn = NULL;
|
|
NWOBJ_ID UserObjectID;
|
|
UCHAR ChallengeKey[8];
|
|
UCHAR NewKeyedPassword[17];
|
|
UCHAR ValidationKey[8];
|
|
WCHAR szTemp[MAX_PATH];
|
|
|
|
//
|
|
// "Create Bindery Object" - user object. This user object is going to be
|
|
// static, with access equals to logged read, supervisor write.
|
|
//
|
|
|
|
hr = NWApiCreateBinderyObject(
|
|
pNwUserInfo->hConn,
|
|
pNwUserInfo->lpszUserName,
|
|
OT_USER,
|
|
BF_STATIC,
|
|
BS_LOGGED_READ | BS_SUPER_WRITE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Add user password.
|
|
//
|
|
|
|
hr = NWApiSetUserPassword(
|
|
pNwUserInfo,
|
|
&UserObjectID,
|
|
NULL // no old passwd - this is a SET
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Create necessary bindery property to facilitate the addition of this user
|
|
// to the group EVERYONE.
|
|
//
|
|
|
|
hr = NWApiCreateProperty(
|
|
pNwUserInfo->hConn,
|
|
pNwUserInfo->lpszUserName,
|
|
OT_USER,
|
|
"GROUPS_I'M_IN",
|
|
BF_SET
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = NWApiCreateProperty(
|
|
pNwUserInfo->hConn,
|
|
pNwUserInfo->lpszUserName,
|
|
OT_USER,
|
|
"SECURITY_EQUALS",
|
|
BF_SET
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Add this user to the group EVERYONE.
|
|
// (okay if this fails, EVERYONE might not exist)
|
|
//
|
|
|
|
wcscpy(szTemp, L"EVERYONE");
|
|
|
|
hrTemp = NWApiAddGroupMember(
|
|
pNwUserInfo->hConn,
|
|
szTemp,
|
|
pNwUserInfo->lpszUserName
|
|
);
|
|
|
|
//
|
|
// Create mail directory and login files.
|
|
// (okay if this fails)
|
|
//
|
|
|
|
hrTemp = NWApiCreateMailDirectory(
|
|
pNwUserInfo,
|
|
UserObjectID
|
|
);
|
|
|
|
//
|
|
// Create LOGIN_CONTROL & ACCOUNT_BALANCE property for the user. Values
|
|
// from USER_DEFAULTS are used as default.
|
|
//
|
|
|
|
hr = NWApiSetLoginCtrlAndAcctBalance(
|
|
pNwUserInfo
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiDeleteUser
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiDeleteUser(
|
|
POBJECTINFO pObjectInfo
|
|
)
|
|
{
|
|
BOOL err = TRUE;
|
|
DWORD dwErr = 0;
|
|
HRESULT hr = S_OK;
|
|
NWCONN_HANDLE hConn = NULL;
|
|
NWOBJ_ID ObjectID;
|
|
WCHAR szPath[MAX_PATH];
|
|
|
|
//
|
|
// Open a handle to the bindery.
|
|
//
|
|
|
|
hr = NWApiGetBinderyHandle(
|
|
&hConn,
|
|
pObjectInfo->ComponentArray[0]
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Get the user's ObjectID which is needed to compose the path name of LOGIN
|
|
// and LOGIN.OS2.
|
|
//
|
|
|
|
hr = NWApiGetObjectID(
|
|
hConn,
|
|
pObjectInfo->ComponentArray[1],
|
|
OT_USER,
|
|
&ObjectID
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Delete SYS:MAIL\<JOBID>\LOGIN. If the file is not found, that's OK, as
|
|
// long as it is not there.
|
|
//
|
|
|
|
wsprintf(
|
|
szPath,
|
|
L"\\\\%s\\SYS\\MAIL\\%X\\LOGIN",
|
|
pObjectInfo->ComponentArray[0],
|
|
dwSWAP(ObjectID)
|
|
);
|
|
|
|
err = DeleteFile(szPath);
|
|
|
|
//
|
|
// Remove any error checking for the cleanup of
|
|
// files. If they do exist, and we do clean them up
|
|
// great. But otherwise Win95 chokes on us.
|
|
//
|
|
|
|
//
|
|
// Delete SYS:MAIL\<JOBID>\LOGIN.OS2. If the file is not found, that's OK,
|
|
// as long as it is not there.
|
|
//
|
|
|
|
wsprintf(
|
|
szPath,
|
|
L"\\\\%s\\SYS\\MAIL\\%X\\LOGIN.OS2",
|
|
pObjectInfo->ComponentArray[0],
|
|
dwSWAP(ObjectID)
|
|
);
|
|
|
|
err = DeleteFile(szPath);
|
|
|
|
//
|
|
// Remove any error checking for the cleanup of
|
|
// files. If they do exist, and we do clean them up
|
|
// great. But otherwise Win95 chokes on us.
|
|
//
|
|
|
|
//
|
|
// Delete SYS:MAIL\<JOBID>.
|
|
//
|
|
|
|
wsprintf(
|
|
szPath,
|
|
L"\\\\%s\\SYS\\MAIL\\%X",
|
|
pObjectInfo->ComponentArray[0],
|
|
dwSWAP(ObjectID)
|
|
);
|
|
|
|
err = RemoveDirectory(szPath);
|
|
|
|
//
|
|
// Remove any error checking for the cleanup of
|
|
// files. If they do exist, and we do clean them up
|
|
// great. But otherwise Win95 chokes on us.
|
|
//
|
|
|
|
|
|
//
|
|
// Delete the user object.
|
|
//
|
|
|
|
hr = NWApiDeleteBinderyObject(
|
|
hConn,
|
|
pObjectInfo->ComponentArray[1],
|
|
OT_USER
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
NWApiReleaseBinderyHandle(hConn);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiCreateBinderyObject
|
|
//
|
|
// Synopsis: This function create the specified object in the specified NetWare
|
|
// bindery. It returns S_OK if the object alread exist.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiCreateBinderyObject(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszObjectName,
|
|
NWOBJ_TYPE wObjType,
|
|
NWFLAGS ucObjectFlags,
|
|
NWFLAGS usObjSecurity
|
|
)
|
|
{
|
|
CHAR szAnsiObjectName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(lpszObjectName) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
lpszObjectName,
|
|
szAnsiObjectName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Create a Static object with LOGGED_READ & SUPERVISOR_WRITE.
|
|
//
|
|
|
|
usRet = NWCCreateObject(
|
|
hConn,
|
|
szAnsiObjectName,
|
|
wObjType,
|
|
BF_STATIC,
|
|
BS_LOGGED_READ | BS_SUPER_WRITE
|
|
);
|
|
//
|
|
// If an error occured, check if it is OBJECT_ALREADY_EXISTS. If it is,
|
|
// treat it as no error.
|
|
//
|
|
|
|
if (usRet) {
|
|
if (usRet == OBJECT_ALREADY_EXISTS) {
|
|
usRet = SUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiDeleteBinderyObject
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiDeleteBinderyObject(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszObjectName,
|
|
NWOBJ_TYPE wObjType
|
|
)
|
|
{
|
|
CHAR szAnsiObjectName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(lpszObjectName) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
lpszObjectName,
|
|
szAnsiObjectName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Delete the object from the bindery.
|
|
//
|
|
|
|
usRet = NWCDeleteObject(
|
|
hConn,
|
|
szAnsiObjectName,
|
|
wObjType
|
|
);
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
#define NW_MAX_PASSWORD_LEN 256
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiSetUserPassword
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiSetUserPassword(
|
|
PNW_USER_INFO pNwUserInfo,
|
|
DWORD *pdwUserObjID,
|
|
LPWSTR pszOldPassword
|
|
)
|
|
{
|
|
CHAR szAnsiUserName[(OBJ_NAME_SIZE + 1)*2];
|
|
CHAR szAnsiPassword[(NW_MAX_PASSWORD_LEN + 1)*2];
|
|
CHAR szAnsiOldPassword[(NW_MAX_PASSWORD_LEN + 1)*2];
|
|
CHAR Buffer[128];
|
|
DWORD err = 0;
|
|
HRESULT hr = S_OK;
|
|
LC_STRUCTURE LoginCtrl;
|
|
NTSTATUS NtStatus;
|
|
UCHAR ChallengeKey[8];
|
|
UCHAR ucMoreFlag;
|
|
UCHAR ucPropFlag;
|
|
WCHAR szOldPasswordCopy[NW_MAX_PASSWORD_LEN + 1];
|
|
|
|
if ( !pNwUserInfo ||
|
|
!(pNwUserInfo->lpszUserName) ||
|
|
!(pNwUserInfo->lpszPassword) ) {
|
|
|
|
hr = E_INVALIDARG ;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if ( (wcslen(pNwUserInfo->lpszUserName) > OBJ_NAME_SIZE) ||
|
|
(wcslen(pNwUserInfo->lpszPassword) > NW_MAX_PASSWORD_LEN) ||
|
|
( pszOldPassword && (wcslen(pszOldPassword) > NW_MAX_PASSWORD_LEN)) ) {
|
|
hr = E_INVALIDARG;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Convert UNICODE into ANSI representation required by NW APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
|
|
err = UnicodeToAnsiString(
|
|
pNwUserInfo->lpszUserName,
|
|
szAnsiUserName,
|
|
0
|
|
);
|
|
if (!err) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
_wcsupr(pNwUserInfo->lpszPassword) ;
|
|
err = UnicodeToAnsiString(
|
|
pNwUserInfo->lpszPassword,
|
|
szAnsiPassword,
|
|
0
|
|
);
|
|
if (!err) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if (pszOldPassword) {
|
|
wcscpy(szOldPasswordCopy, pszOldPassword);
|
|
_wcsupr(szOldPasswordCopy) ;
|
|
err = UnicodeToAnsiString(
|
|
szOldPasswordCopy,
|
|
szAnsiOldPassword,
|
|
0
|
|
);
|
|
if (!err) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
szAnsiOldPassword[0] = 0 ;
|
|
}
|
|
|
|
//
|
|
// Get challenge key.
|
|
//
|
|
|
|
err = NWApiMapNtStatusToDosError(
|
|
NWPGetChallengeKey(
|
|
pNwUserInfo->hConn,
|
|
ChallengeKey
|
|
));
|
|
|
|
if (!err) {
|
|
|
|
//
|
|
// For NetWare 4.x servers, this has to be done after the
|
|
// NWPGetChallengeKey so that the object id returned can be used to
|
|
// encrypt the password. 4.x bindery emulation might return different
|
|
// object ids for some users depending on whether the NWPGetChallengeKey
|
|
// is called beforehand.
|
|
//
|
|
|
|
err = NWApiMapNtStatusToDosError(
|
|
NWPGetObjectID(
|
|
pNwUserInfo->hConn,
|
|
szAnsiUserName,
|
|
OT_USER,
|
|
pdwUserObjID
|
|
));
|
|
}
|
|
|
|
|
|
if (!err) {
|
|
|
|
//
|
|
// The old password and object ID make up the 17-byte Vold. This is used
|
|
// later to form the 17-byte Vc for changing password on the server.
|
|
//
|
|
|
|
UCHAR ValidationKey[8];
|
|
UCHAR NewKeyedPassword[17];
|
|
|
|
EncryptChangePassword(
|
|
(PUCHAR) szAnsiOldPassword,
|
|
(PUCHAR) szAnsiPassword,
|
|
*pdwUserObjID,
|
|
ChallengeKey,
|
|
ValidationKey,
|
|
NewKeyedPassword
|
|
);
|
|
|
|
err = NWApiMapNtStatusToDosError(
|
|
NWPChangeObjectPasswordEncrypted(
|
|
pNwUserInfo->hConn,
|
|
szAnsiUserName,
|
|
OT_USER,
|
|
ValidationKey,
|
|
NewKeyedPassword
|
|
));
|
|
}
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
hr = HRESULT_FROM_WIN32(err);
|
|
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiCreateMailDirectory
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiCreateMailDirectory(
|
|
PNW_USER_INFO pNwUserInfo,
|
|
NWOBJ_ID UserObjID
|
|
)
|
|
{
|
|
BYTE szPath[(MAX_PATH + 1) * sizeof(WCHAR)];
|
|
CHAR szUserObjID[255];
|
|
DWORD err = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Make path.
|
|
//
|
|
|
|
_ltoa(
|
|
dwSWAP(UserObjID),
|
|
szUserObjID,
|
|
16
|
|
);
|
|
|
|
strcpy((char *) szPath, "SYS:\\MAIL\\");
|
|
strcat((char *) szPath, szUserObjID);
|
|
|
|
//
|
|
// Create a directory with Maximum rights mask.
|
|
//
|
|
|
|
err = NWApiMapNtStatusToDosError(
|
|
NWPCreateDirectory(
|
|
pNwUserInfo->hConn,
|
|
0,
|
|
(char *) szPath,
|
|
0xFF // From SysCon --- Max. access rights for directory
|
|
)); // = Full Access
|
|
|
|
if ( !err ) {
|
|
//
|
|
// Add a trustee with all rights except PARENTAL right.
|
|
//
|
|
|
|
err = NWApiMapNtStatusToDosError(
|
|
NWPAddTrustee(
|
|
pNwUserInfo->hConn,
|
|
0,
|
|
(char *) szPath,
|
|
UserObjID,
|
|
0xDF // From SysCon --- Trustee has all rights
|
|
)); // EXCEPT parental rights (right to create/
|
|
// delete subdirs, make others trustees)
|
|
//
|
|
// Create a Login file.
|
|
//
|
|
|
|
if ( !err ) {
|
|
HANDLE hFile;
|
|
|
|
wsprintfW(
|
|
(LPWSTR) szPath,
|
|
L"\\\\%ws\\SYS\\MAIL\\%X\\LOGIN",
|
|
pNwUserInfo->lpszBinderyName,
|
|
dwSWAP(UserObjID)
|
|
);
|
|
|
|
hFile = CreateFile(
|
|
(LPWSTR) szPath,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0
|
|
);
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
err = GetLastError();
|
|
}
|
|
|
|
if ( !err )
|
|
CloseHandle( hFile );
|
|
|
|
//
|
|
// Create a Login.os2 file.
|
|
//
|
|
|
|
wsprintfW(
|
|
(LPWSTR) szPath,
|
|
L"\\\\%ws\\SYS\\MAIL\\%X\\LOGIN.OS2",
|
|
pNwUserInfo->lpszBinderyName,
|
|
dwSWAP(UserObjID)
|
|
);
|
|
|
|
hFile = CreateFile(
|
|
(LPWSTR) szPath,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0
|
|
);
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
err = GetLastError();
|
|
}
|
|
|
|
if ( !err )
|
|
CloseHandle( hFile );
|
|
}
|
|
}
|
|
|
|
// err == 255 == "FAILURE"
|
|
// might be used to indicate directory already exists,
|
|
// but also used to signal generic failure
|
|
|
|
hr = HRESULT_FROM_WIN32(err);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiSetLoginCtrlAndAcctBalance
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiSetLoginCtrlAndAcctBalance(
|
|
PNW_USER_INFO pNwUserInfo
|
|
)
|
|
{
|
|
ACCT_BALANCE AccountBalance;
|
|
DWORD dwNumSegment;
|
|
HRESULT hr = S_OK;
|
|
int i = 0;
|
|
LC_STRUCTURE LoginCtrl;
|
|
LP_RPLY_SGMT_LST lpReplySegment = NULL;
|
|
LP_RPLY_SGMT_LST lpTemp = NULL;
|
|
USER_DEFAULT UserDefault;
|
|
WCHAR szTemp[MAX_PATH];
|
|
|
|
//
|
|
// Get Supervisor's USER_DEFAULTS.
|
|
//
|
|
|
|
wcscpy(szTemp, NW_PROP_SUPERVISORW);
|
|
|
|
hr = NWApiGetProperty(
|
|
szTemp,
|
|
NW_PROP_USER_DEFAULTS,
|
|
OT_USER,
|
|
pNwUserInfo->hConn,
|
|
&lpReplySegment,
|
|
&dwNumSegment
|
|
);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
UserDefault = *((LPUSER_DEFAULT) lpReplySegment->Segment);
|
|
|
|
//
|
|
// Put default values into LoginCtrl.
|
|
//
|
|
|
|
LoginCtrl.byAccountExpires[0] = UserDefault.byAccountExpiresYear;
|
|
LoginCtrl.byAccountExpires[1] = UserDefault.byAccountExpiresMonth;
|
|
LoginCtrl.byAccountExpires[2] = UserDefault.byAccountExpiresDay;
|
|
LoginCtrl.byAccountDisabled = 0;
|
|
LoginCtrl.byPasswordExpires[0] = 85;
|
|
LoginCtrl.byPasswordExpires[1] = 01;
|
|
LoginCtrl.byPasswordExpires[2] = 01;
|
|
LoginCtrl.byGraceLogins = UserDefault.byGraceLoginReset;
|
|
LoginCtrl.wPasswordInterval = UserDefault.wPasswordInterval;
|
|
LoginCtrl.byGraceLoginReset = UserDefault.byGraceLoginReset;
|
|
LoginCtrl.byMinPasswordLength = UserDefault.byMinPasswordLength;
|
|
LoginCtrl.wMaxConnections = UserDefault.wMaxConnections;
|
|
LoginCtrl.byRestrictions = UserDefault.byRestrictions;
|
|
LoginCtrl.byUnused = 0;
|
|
LoginCtrl.lMaxDiskBlocks = UserDefault.lMaxDiskBlocks;
|
|
LoginCtrl.wBadLogins = 0;
|
|
LoginCtrl.lNextResetTime = 0;
|
|
|
|
for (i = 0; i < 42; i++) {
|
|
LoginCtrl.byLoginTimes[i] = UserDefault.byLoginTimes[i];
|
|
}
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
LoginCtrl.byLastLogin[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
LoginCtrl.byBadLoginAddr[i] = 0;
|
|
}
|
|
|
|
|
|
LoginCtrl.byGraceLogins = LoginCtrl.byGraceLoginReset;
|
|
|
|
//
|
|
// Put default values into AccountBalance.
|
|
//
|
|
|
|
AccountBalance.lBalance = UserDefault.lBalance;
|
|
AccountBalance.lCreditLimit = UserDefault.lCreditLimit;
|
|
|
|
//
|
|
// Write LOGIN_CONTROL property.
|
|
//
|
|
|
|
hr = NWApiWriteProperty(
|
|
pNwUserInfo->hConn,
|
|
pNwUserInfo->lpszUserName,
|
|
OT_USER,
|
|
NW_PROP_LOGIN_CONTROL,
|
|
(LPBYTE) &LoginCtrl
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Write ACCOUNT_BALANCE property.
|
|
//
|
|
|
|
hr = NWApiWriteProperty(
|
|
pNwUserInfo->hConn,
|
|
pNwUserInfo->lpszUserName,
|
|
OT_USER,
|
|
NW_PROP_ACCOUNT_BALANCE,
|
|
(LPBYTE) &AccountBalance
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// SUPERVISOR may not exist, or may not have USER_DEFAULTS.
|
|
// This is okay.
|
|
//
|
|
hr = S_OK;
|
|
|
|
error:
|
|
|
|
if (lpReplySegment) {
|
|
DELETE_LIST(lpReplySegment);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiCreateGroup
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiCreateGroup(
|
|
POBJECTINFO pObjectInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NWCONN_HANDLE hConn = NULL;
|
|
|
|
//
|
|
// Open a handle to the bindery.
|
|
//
|
|
|
|
hr = NWApiGetBinderyHandle(
|
|
&hConn,
|
|
pObjectInfo->ComponentArray[0]
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Create a group bindery object.
|
|
//
|
|
|
|
hr = NWApiCreateBinderyObject(
|
|
hConn,
|
|
pObjectInfo->ComponentArray[1],
|
|
OT_USER_GROUP,
|
|
BF_STATIC,
|
|
BS_LOGGED_READ | BS_SUPER_WRITE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Create GROUP_MEMBERS property.
|
|
//
|
|
|
|
hr = NWApiCreateProperty(
|
|
hConn,
|
|
pObjectInfo->ComponentArray[1],
|
|
OT_USER_GROUP,
|
|
NW_PROP_GROUP_MEMBERS,
|
|
BF_SET
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
NWApiReleaseBinderyHandle(hConn);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiDeleteGroup
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiDeleteGroup(
|
|
POBJECTINFO pObjectInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NWCONN_HANDLE hConn = NULL;
|
|
|
|
//
|
|
// Open a handle to the bindery.
|
|
//
|
|
|
|
hr = NWApiGetBinderyHandle(
|
|
&hConn,
|
|
pObjectInfo->ComponentArray[0]
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Delete the group object.
|
|
//
|
|
|
|
hr = NWApiDeleteBinderyObject(
|
|
hConn,
|
|
pObjectInfo->ComponentArray[1],
|
|
OT_USER_GROUP
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
NWApiReleaseBinderyHandle(hConn);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiCreatePrinter
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiCreatePrinter(
|
|
POBJECTINFO pObjectInfo
|
|
)
|
|
{
|
|
CHAR szQueueName[(OBJ_NAME_SIZE + 1)*2];
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
NWCONN_HANDLE hConn = NULL;
|
|
WCHAR szTemp[MAX_PATH];
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(pObjectInfo->ComponentArray[1]) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
pObjectInfo->ComponentArray[1],
|
|
szQueueName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Open a handle to the bindery.
|
|
//
|
|
|
|
hr = NWApiGetBinderyHandle(
|
|
&hConn,
|
|
pObjectInfo->ComponentArray[0]
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Create a print queue object.
|
|
//
|
|
|
|
hr = NWApiCreatePrintQueue(
|
|
hConn,
|
|
pObjectInfo->ComponentArray[1]
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Change property security.
|
|
//
|
|
|
|
usRet = NWCChangePropertySecurity(
|
|
hConn,
|
|
szQueueName,
|
|
OT_PRINT_QUEUE,
|
|
NW_PROP_Q_OPERATORS,
|
|
BS_LOGGED_READ | BS_SUPER_WRITE
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Add SUPERVISOR to Q_OPERATORS.
|
|
// (okay if this fails, maybe SUPERVISOR doesn't exist)
|
|
//
|
|
|
|
usRet = NWCAddObjectToSet(
|
|
hConn,
|
|
szQueueName,
|
|
OT_PRINT_QUEUE,
|
|
NW_PROP_Q_OPERATORS,
|
|
NW_PROP_SUPERVISOR,
|
|
OT_USER
|
|
);
|
|
|
|
//
|
|
// Add EVERYONE to Q_USERS.
|
|
// (okay if this fails, maybe EVERYONE doesn't exist)
|
|
//
|
|
|
|
usRet = NWCAddObjectToSet(
|
|
hConn,
|
|
szQueueName,
|
|
OT_PRINT_QUEUE,
|
|
NW_PROP_Q_USERS,
|
|
NW_PROP_EVERYONE,
|
|
OT_USER_GROUP
|
|
);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
error:
|
|
|
|
NWApiReleaseBinderyHandle(hConn);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiDeleteGroup
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiDeletePrinter(
|
|
POBJECTINFO pObjectInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NWCONN_HANDLE hConn = NULL;
|
|
NWOBJ_ID dwQueueID = 0;
|
|
|
|
//
|
|
// Open a handle to the bindery.
|
|
//
|
|
|
|
hr = NWApiGetBinderyHandle(
|
|
&hConn,
|
|
pObjectInfo->ComponentArray[0]
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Get Queue ID.
|
|
//
|
|
|
|
hr = NWApiDestroyPrintQueue(
|
|
hConn,
|
|
pObjectInfo->ComponentArray[1]
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
NWApiReleaseBinderyHandle(hConn);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiCreatePrintQueue
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiCreatePrintQueue(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszQueueName
|
|
)
|
|
{
|
|
CHAR szQueueName[(OBJ_NAME_SIZE + 1)*2];
|
|
DWORD dwQueueID = 0;
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Convert BSTR into an ANSI representation required by NWC APIs. "0" is
|
|
// passed to UnicodeToAnsiString when the length of the string is unknown.
|
|
//
|
|
if (wcslen(lpszQueueName) > OBJ_NAME_SIZE) {
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
UnicodeToAnsiString(
|
|
lpszQueueName,
|
|
szQueueName,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Create a print queue object.
|
|
//
|
|
|
|
usRet = NWCCreateQueue(
|
|
hConn,
|
|
NULL,
|
|
szQueueName,
|
|
OT_PRINT_QUEUE,
|
|
NW_PRINTER_PATH,
|
|
&dwQueueID
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiDestroyPrintQueue
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiDestroyPrintQueue(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR lpszQueueName
|
|
)
|
|
{
|
|
DWORD dwQueueID = 0;
|
|
HRESULT hr = S_OK;
|
|
NWCCODE usRet = SUCCESSFUL;
|
|
|
|
//
|
|
// Get Queue ID.
|
|
//
|
|
|
|
hr = NWApiGetObjectID(
|
|
hConn,
|
|
lpszQueueName,
|
|
OT_PRINT_QUEUE,
|
|
&dwQueueID
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Destroy print queue.
|
|
//
|
|
|
|
usRet = NWCDestroyQueue(
|
|
hConn,
|
|
dwSWAP(dwQueueID)
|
|
);
|
|
hr = HRESULT_FROM_NWCCODE(usRet);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiMapNtStatusToDosError
|
|
//
|
|
// Synopsis: This function maps the ntstatus that was returned from the NetWare
|
|
// redirector to window errors. Similar to RtlNtStatusToDosError
|
|
// except that the special handling is done to ntstatus with netware
|
|
// facility codes.
|
|
//
|
|
// Argument: NtStatus - The ntstatus returned from NetWare rdr
|
|
//
|
|
// Return Value: WinError
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
NWApiMapNtStatusToDosError(
|
|
IN NTSTATUS NtStatus
|
|
)
|
|
{
|
|
if ( (HIWORD( NtStatus) & FACILITY_NWRDR ) == FACILITY_NWRDR )
|
|
{
|
|
if ( NtStatus == NWRDR_PASSWORD_HAS_EXPIRED )
|
|
return ERROR_PASSWORD_EXPIRED;
|
|
else
|
|
return NETWARE_GENERAL_ERROR;
|
|
}
|
|
else if ( HIWORD( NtStatus) == 0xC001 )
|
|
{
|
|
return LOWORD( NtStatus ) + NETWARE_ERROR_BASE;
|
|
}
|
|
|
|
return RtlNtStatusToDosError( NtStatus );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiConvertToAddressFormat
|
|
//
|
|
// Synopsis: Convert an IPX address obtain from NWApiGetProperty into the
|
|
// format specified in spec.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiConvertToAddressFormat(
|
|
LP_RPLY_SGMT_LST lpReplySegment,
|
|
LPWSTR *lppszAddresses
|
|
)
|
|
{
|
|
int i = 0;
|
|
LPBYTE lpBuffer = NULL;
|
|
LPWSTR lpszTemp = NULL;
|
|
WORD wSegment[NET_ADDRESS_WORD_SIZE];
|
|
|
|
//
|
|
// Put values from szReply into the wSegment array
|
|
//
|
|
|
|
lpBuffer = (LPBYTE) lpReplySegment->Segment;
|
|
|
|
for (i = 0; i < NET_ADDRESS_WORD_SIZE; i++) {
|
|
|
|
wSegment[i] = NWApiReverseWORD(*((LPWORD)lpBuffer + i));
|
|
}
|
|
|
|
//
|
|
// Put address together in the format described in spec.
|
|
//
|
|
|
|
lpszTemp = (LPWSTR) AllocADsMem((NET_ADDRESS_NUM_CHAR+1)*sizeof(WCHAR));
|
|
if (!lpszTemp) {
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
|
|
wsprintf(
|
|
lpszTemp,
|
|
L"%s:%04X%04X.%04X%04X%04X.%04X",
|
|
bstrAddressTypeString,
|
|
wSegment[0],
|
|
wSegment[1],
|
|
wSegment[2],
|
|
wSegment[3],
|
|
wSegment[4],
|
|
wSegment[5]
|
|
);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
*lppszAddresses = lpszTemp;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiMakeVariantTime
|
|
//
|
|
// Synopsis: This function creates a double precision variant time.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiMakeVariantTime(
|
|
DOUBLE * pdTime,
|
|
WORD wDay, // Day = 1..31
|
|
WORD wMonth, // Month = 1..12
|
|
WORD wYear, // Year = (19XX or 20XX) - 1980, ie. 2019 -> 39
|
|
WORD wSecond, // Second = 0..30, Second divided by 2
|
|
WORD wMinute, // Minute = 0..59
|
|
WORD wHour // Hour = 0..23
|
|
)
|
|
{
|
|
BOOL fBool = TRUE;
|
|
DOUBLE vTime = 0;
|
|
WORD wDOSDate = 0;
|
|
WORD wDOSTime = 0;
|
|
|
|
//
|
|
// Fix up parameters.
|
|
// If wDay and wMonth are 0, turn them into one.
|
|
//
|
|
|
|
if (wDay == 0) {
|
|
wDay++;
|
|
}
|
|
|
|
if (wMonth == 0) {
|
|
wMonth++;
|
|
}
|
|
|
|
//
|
|
// Shift data to correct bit as required by the DOS date & time format.
|
|
//
|
|
|
|
wMonth = wMonth << 5;
|
|
wYear = wYear << 9;
|
|
wMinute = wMinute << 5;
|
|
wHour = wHour << 11;
|
|
|
|
//
|
|
// Put them in DOS format.
|
|
//
|
|
|
|
wDOSDate = wYear | wMonth | wDay;
|
|
wDOSTime = wHour | wMinute | wSecond;
|
|
|
|
//
|
|
// Convert into VariantTime.
|
|
//
|
|
|
|
fBool = DosDateTimeToVariantTime(
|
|
wDOSDate,
|
|
wDOSTime,
|
|
&vTime
|
|
);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
if (fBool == TRUE) {
|
|
|
|
*pdTime = vTime;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
else {
|
|
RRETURN(E_FAIL);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiBreakVariantTime
|
|
//
|
|
// Synopsis: This function interprets a double precision variant time and
|
|
// returns the day, month and year individually.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiBreakVariantTime(
|
|
DOUBLE daDate,
|
|
PWORD pwDay,
|
|
PWORD pwMonth,
|
|
PWORD pwYear
|
|
)
|
|
{
|
|
BOOL fBool;
|
|
DOUBLE vTime;
|
|
WORD wDOSDate = 0;
|
|
WORD wDOSTime = 0;
|
|
WORD wDay = 0;
|
|
WORD wMonth = 0;
|
|
WORD wYear = 0;
|
|
|
|
//
|
|
// Convert variant time into DOS format.
|
|
//
|
|
|
|
fBool = VariantTimeToDosDateTime(
|
|
daDate,
|
|
&wDOSDate,
|
|
&wDOSTime
|
|
);
|
|
if (fBool == FALSE) {
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// Year: bits 9-15, add 80 to wYear because 80 was subtracted from it to
|
|
// call VariantTimeToDosDateTime.
|
|
//
|
|
|
|
wYear = wDOSDate >> 9;
|
|
wYear += 80;
|
|
|
|
//
|
|
// Month: bits 5-8.
|
|
//
|
|
|
|
wMonth = (wDOSDate >> 5) - (wYear << 4);
|
|
|
|
//
|
|
// Day: bits 0-4.
|
|
//
|
|
|
|
wDay = wDOSDate - (wMonth << 5) - (wYear << 9);
|
|
|
|
//
|
|
// Return.
|
|
//
|
|
|
|
*pwDay = wDay;
|
|
*pwMonth = wMonth;
|
|
*pwYear = wYear;
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiReverseWORD
|
|
//
|
|
// Synopsis: This function reverse a WORD.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
WORD
|
|
NWApiReverseWORD(
|
|
WORD wWORD
|
|
)
|
|
{
|
|
|
|
LPBYTE lpbTemp = (LPBYTE) &wWORD;
|
|
BYTE bTemp;
|
|
|
|
bTemp = *lpbTemp;
|
|
*lpbTemp = *(lpbTemp + 1);
|
|
*(lpbTemp + 1) = bTemp;
|
|
|
|
return(*((LPWORD) lpbTemp));
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Function: NWApiUserGetGroups
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
NWApiUserGetGroups(
|
|
NWCONN_HANDLE hConn,
|
|
LPWSTR szUserName,
|
|
LPBYTE *lppBuffer
|
|
)
|
|
{
|
|
DWORD dwNumSegment = 0;
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
LP_RPLY_SGMT_LST lpTemp = NULL;
|
|
LP_RPLY_SGMT_LST lpReplySegment = NULL;
|
|
|
|
//
|
|
// Assert
|
|
//
|
|
|
|
ADsAssert(*lppBuffer == NULL);
|
|
|
|
//
|
|
// Get GROUP_MEMBERS.
|
|
//
|
|
|
|
hr = NWApiGetProperty(
|
|
szUserName,
|
|
NW_PROP_USER_GROUPS,
|
|
OT_USER,
|
|
hConn,
|
|
&lpReplySegment,
|
|
&dwNumSegment
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Pack returned linked list into buffer.
|
|
//
|
|
|
|
*lppBuffer = (LPBYTE) AllocADsMem(
|
|
dwNumSegment * REPLY_VALUE_SIZE
|
|
);
|
|
if (!(*lppBuffer)) {
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
|
|
lpTemp = lpReplySegment;
|
|
|
|
for (i = 0; i < dwNumSegment; i++) {
|
|
memcpy(
|
|
*lppBuffer + i * REPLY_VALUE_SIZE,
|
|
lpTemp->Segment,
|
|
REPLY_VALUE_SIZE
|
|
);
|
|
lpTemp = lpTemp->lpNext;
|
|
}
|
|
|
|
error:
|
|
|
|
//
|
|
// Clean up.
|
|
//
|
|
|
|
lpTemp = NULL;
|
|
|
|
if (lpReplySegment) {
|
|
DELETE_LIST(lpReplySegment);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|