#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) { SecureZeroMemory(NwUserInfo.lpszPassword, wcslen(NwUserInfo.lpszPassword) * sizeof(WCHAR)); 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) { SecureZeroMemory(pNwUserInfo->lpszPassword, wcslen(pNwUserInfo->lpszPassword) * sizeof(WCHAR)); 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\\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\\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\. // 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: SecureZeroMemory(szAnsiPassword, sizeof(szAnsiPassword)); SecureZeroMemory(szAnsiOldPassword, sizeof(szAnsiOldPassword)); SecureZeroMemory(szOldPasswordCopy, sizeof(szOldPasswordCopy)); 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 ); if (!err) { // // 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); }