windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/wkssvc/client/wksstub.c
2020-09-26 16:20:57 +08:00

3020 lines
73 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991-1993 Microsoft Corporation
Module Name:
wksstub.c
Abstract:
Client stubs of the Workstation service APIs.
Author:
Rita Wong (ritaw) 10-May-1991
Environment:
User Mode - Win32
Revision History:
18-Jun-1991 JohnRo
Remote NetUse APIs to downlevel servers.
24-Jul-1991 JohnRo
Use NET_REMOTE_TRY_RPC etc macros for NetUse APIs.
Moved NetpIsServiceStarted() into NetLib.
25-Jul-1991 JohnRo
Quiet DLL stub debug output.
19-Aug-1991 JohnRo
Implement downlevel NetWksta APIs. Use NetRpc.h for NetWksta APIs.
07-Nov-1991 JohnRo
RAID 4186: assert in RxNetShareAdd and other DLL stub problems.
19-Nov-1991 JohnRo
Make sure status is correct for APIs not supported on downlevel.
Implement remote NetWkstaUserEnum().
21-Jan-1991 rfirth
Added NetWkstaStatisticsGet wrapper
19-Apr-1993 JohnRo
Fix NET_API_FUNCTION references.
--*/
#include "wsclient.h"
#undef IF_DEBUG // avoid wsclient.h vs. debuglib.h conflicts.
#include <debuglib.h> // IF_DEBUG() (needed by netrpc.h).
#include <lmapibuf.h>
#include <lmserver.h>
#include <lmsvc.h>
#include <rxuse.h> // RxNetUse APIs.
#include <rxwksta.h> // RxNetWksta and RxNetWkstaUser APIs.
#include <rap.h> // Needed by rxserver.h
#include <rxserver.h> // RxNetServerEnum API.
#include <netlib.h> // NetpServiceIsStarted() (needed by netrpc.h).
#include <netrpc.h> // NET_REMOTE macros.
#include <lmstats.h>
#include <netstats.h> // NetWkstaStatisticsGet prototype
#include <rxstats.h>
#include <netsetup.h>
#include <crypt.h>
#include <rc4.h>
#include <md5.h>
#include <rpcasync.h>
#if(_WIN32_WINNT >= 0x0500)
#include "cscp.h"
#endif
STATIC
DWORD
WsMapRpcError(
IN DWORD RpcError
);
//-------------------------------------------------------------------//
// //
// Global variables //
// //
//-------------------------------------------------------------------//
#if DBG
DWORD WorkstationClientTrace = 0;
#endif // DBG
NET_API_STATUS NET_API_FUNCTION
NetWkstaGetInfo(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
OUT LPBYTE *bufptr
)
{
NET_API_STATUS status;
if (bufptr == NULL) {
return ERROR_INVALID_PARAMETER;
}
*bufptr = NULL; // Must be NULL so RPC knows to fill it in.
NET_REMOTE_TRY_RPC
//
// Try RPC (local or remote) version of API.
//
status = NetrWkstaGetInfo(
servername,
level,
(LPWKSTA_INFO) bufptr
);
NET_REMOTE_RPC_FAILED("NetWkstaGetInfo",
servername,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// Call downlevel version of the API.
//
status = RxNetWkstaGetInfo(
servername,
level,
bufptr
);
NET_REMOTE_END
#if(_WIN32_WINNT >= 0x0500)
if( *bufptr == NULL && servername != NULL &&
CSCNetWkstaGetInfo( servername, level, bufptr ) == NO_ERROR ) {
status = NO_ERROR;
}
#endif
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetWkstaSetInfo(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
IN LPBYTE buf,
OUT LPDWORD parm_err OPTIONAL
)
/*++
Routine Description:
This is the DLL entrypoint for NetWkstaSetInfo.
Arguments:
servername - Supplies the name of server to execute this function
level - Supplies the level of information.
buf - Supplies a buffer which contains the information structure of fields
to set. The level denotes the structure in this buffer.
parm_err - Returns the identifier to the invalid parameter in buf if this
function returns ERROR_INVALID_PARAMETER.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
NET_REMOTE_TRY_RPC
//
// Try RPC (local or remote) version of API.
//
status = NetrWkstaSetInfo(
servername,
level,
(LPWKSTA_INFO) &buf,
parm_err
);
NET_REMOTE_RPC_FAILED("NetWkstaSetInfo",
servername,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// Call downlevel version of the API.
//
status = RxNetWkstaSetInfo(
servername,
level,
buf,
parm_err
);
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetWkstaUserEnum(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
OUT LPBYTE *bufptr,
IN DWORD prefmaxlen,
OUT LPDWORD entriesread,
OUT LPDWORD totalentries,
IN OUT LPDWORD resume_handle OPTIONAL
)
/*++
Routine Description:
This is the DLL entrypoint for NetWkstaUserEnum.
Arguments:
servername - Supplies the name of server to execute this function
level - Supplies the requested level of information.
bufptr - Returns a pointer to the buffer which contains a sequence of
information structure of the specified information level. This
pointer is set to NULL if return code is not NERR_Success or
ERROR_MORE_DATA, or if EntriesRead returned is 0.
prefmaxlen - Supplies the number of bytes of information to return in the
buffer. If this value is MAXULONG, all available information will
be returned.
entriesread - Returns the number of entries read into the buffer. This
value is only valid if the return code is NERR_Success or
ERROR_MORE_DATA.
totalentries - Returns the total number of entries available. This value
is only valid if the return code is NERR_Success or ERROR_MORE_DATA.
resume_handle - Supplies a handle to resume the enumeration from where it
left off the last time through. Returns the resume handle if return
code is ERROR_MORE_DATA.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
GENERIC_INFO_CONTAINER GenericInfoContainer;
GENERIC_ENUM_STRUCT InfoStruct;
if (bufptr == NULL || entriesread == NULL) {
return ERROR_INVALID_PARAMETER;
}
try {
*entriesread = 0;
} except( EXCEPTION_EXECUTE_HANDLER ) {
return ERROR_INVALID_PARAMETER;
}
GenericInfoContainer.Buffer = NULL;
GenericInfoContainer.EntriesRead = 0;
InfoStruct.Container = &GenericInfoContainer;
InfoStruct.Level = level;
NET_REMOTE_TRY_RPC
//
// Try RPC (local or remote) version of API.
//
status = NetrWkstaUserEnum(
servername,
(LPWKSTA_USER_ENUM_STRUCT) &InfoStruct,
prefmaxlen,
totalentries,
resume_handle
);
if (status == NERR_Success || status == ERROR_MORE_DATA) {
*bufptr = (LPBYTE) GenericInfoContainer.Buffer;
*entriesread = GenericInfoContainer.EntriesRead;
}
NET_REMOTE_RPC_FAILED("NetWkstaUserEnum",
servername,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// Call downlevel version.
//
status = RxNetWkstaUserEnum(
servername,
level,
bufptr,
prefmaxlen,
entriesread,
totalentries,
resume_handle);
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetWkstaUserGetInfo(
IN LPTSTR reserved,
IN DWORD level,
OUT LPBYTE *bufptr
)
/*++
Routine Description:
This is the DLL entrypoint for NetWkstaUserGetInfo.
Arguments:
reserved - Must be NULL.
level - Supplies the requested level of information.
bufptr - Returns a pointer to a buffer which contains the requested
user information.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
if (reserved != NULL || bufptr == NULL) {
return ERROR_INVALID_PARAMETER;
}
*bufptr = NULL; // Must be NULL so RPC knows to fill it in.
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
status = NetrWkstaUserGetInfo(
NULL,
level,
(LPWKSTA_USER_INFO) bufptr
);
NET_REMOTE_RPC_FAILED("NetWkstaUserGetInfo",
NULL,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// No downlevel version to call
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetWkstaUserSetInfo(
IN LPTSTR reserved,
IN DWORD level,
OUT LPBYTE buf,
OUT LPDWORD parm_err OPTIONAL
)
/*++
Routine Description:
This is the DLL entrypoint for NetWkstaUserSetInfo.
Arguments:
reserved - Must be NULL.
level - Supplies the level of information.
buf - Supplies a buffer which contains the information structure of fields
to set. The level denotes the structure in this buffer.
parm_err - Returns the identifier to the invalid parameter in buf if this
function returns ERROR_INVALID_PARAMETER.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
if (reserved != NULL) {
return ERROR_INVALID_PARAMETER;
}
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
status = NetrWkstaUserSetInfo(
NULL,
level,
(LPWKSTA_USER_INFO) &buf,
parm_err
);
NET_REMOTE_RPC_FAILED("NetWkstaUserSetInfo",
NULL,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// No downlevel version to call
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetWkstaTransportEnum(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
OUT LPBYTE *bufptr,
IN DWORD prefmaxlen,
OUT LPDWORD entriesread,
OUT LPDWORD totalentries,
IN OUT LPDWORD resume_handle OPTIONAL
)
/*++
Routine Description:
This is the DLL entrypoint for NetWkstaTransportEnum.
Arguments:
servername - Supplies the name of server to execute this function
level - Supplies the requested level of information.
bufptr - Returns a pointer to the buffer which contains a sequence of
information structure of the specified information level. This
pointer is set to NULL if return code is not NERR_Success or
ERROR_MORE_DATA, or if EntriesRead returned is 0.
prefmaxlen - Supplies the number of bytes of information to return in the
buffer. If this value is MAXULONG, all available information will
be returned.
entriesread - Returns the number of entries read into the buffer. This
value is only valid if the return code is NERR_Success or
ERROR_MORE_DATA.
totalentries - Returns the total number of entries available. This value
is only valid if the return code is NERR_Success or ERROR_MORE_DATA.
resume_handle - Supplies a handle to resume the enumeration from where it
left off the last time through. Returns the resume handle if return
code is ERROR_MORE_DATA.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
GENERIC_INFO_CONTAINER GenericInfoContainer;
GENERIC_ENUM_STRUCT InfoStruct;
if (bufptr == NULL || entriesread == NULL) {
return ERROR_INVALID_PARAMETER;
}
try {
*entriesread = 0;
} except( EXCEPTION_EXECUTE_HANDLER ) {
return ERROR_INVALID_PARAMETER;
}
GenericInfoContainer.Buffer = NULL;
GenericInfoContainer.EntriesRead = 0;
InfoStruct.Container = &GenericInfoContainer;
InfoStruct.Level = level;
NET_REMOTE_TRY_RPC
//
// Try RPC (local or remote) version of API.
//
status = NetrWkstaTransportEnum(
servername,
(LPWKSTA_TRANSPORT_ENUM_STRUCT) &InfoStruct,
prefmaxlen,
totalentries,
resume_handle
);
if (status == NERR_Success || status == ERROR_MORE_DATA) {
*bufptr = (LPBYTE) GenericInfoContainer.Buffer;
*entriesread = GenericInfoContainer.EntriesRead;
}
NET_REMOTE_RPC_FAILED("NetWkstaTransportEnum",
servername,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// No downlevel version to call
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetWkstaTransportAdd(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
IN LPBYTE buf,
OUT LPDWORD parm_err OPTIONAL
)
/*++
Routine Description:
This is the DLL entrypoint for NetWkstaTransportAdd.
Arguments:
servername - Supplies the name of server to execute this function
level - Supplies the level of information.
buf - Supplies a buffer which contains the information of transport to add.
parm_err - Returns the identifier to the invalid parameter in buf if this
function returns ERROR_INVALID_PARAMETER.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
NET_REMOTE_TRY_RPC
//
// Try RPC (local or remote) version of API.
//
status = NetrWkstaTransportAdd(
servername,
level,
(LPWKSTA_TRANSPORT_INFO_0) buf,
parm_err
);
NET_REMOTE_RPC_FAILED("NetWkstaTransportAdd",
servername,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// No downlevel version to call
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetWkstaTransportDel(
IN LPTSTR servername OPTIONAL,
IN LPTSTR transportname,
IN DWORD ucond
)
/*++
Routine Description:
This is the DLL entrypoint for NetWkstaTransportDel.
Arguments:
servername - Supplies the name of server to execute this function
transportname - Supplies the name of the transport to delete.
ucond - Supplies a value which specifies the force level of disconnection
for existing use on the transport.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
NET_REMOTE_TRY_RPC
//
// Try RPC (local or remote) version of API.
//
status = NetrWkstaTransportDel(
servername,
transportname,
ucond
);
NET_REMOTE_RPC_FAILED("NetWkstaTransportDel",
servername,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// No downlevel version to try
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetUseAdd(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
IN LPBYTE buf,
OUT LPDWORD parm_err OPTIONAL
)
/*++
Routine Description:
This is the DLL entrypoint for NetUseAdd.
Arguments:
servername - Supplies the name of server to execute this function
level - Supplies the requested level of information.
buf - Supplies a buffer which contains the information of use to add.
parm_err - Returns the identifier to the invalid parameter in buf if this
function returns ERROR_INVALID_PARAMETER.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
LPWSTR lpwTempPassword = NULL;
UNICODE_STRING EncodedPassword;
#define NETR_USE_ADD_PASSWORD_SEED 0x56 // Pick a non-zero seed.
DWORD OptionsSupported;
status = NetRemoteComputerSupports(
servername,
SUPPORTS_RPC | SUPPORTS_LOCAL, // options wanted
&OptionsSupported
);
if (status != NERR_Success) {
//
// This is where machine not found gets handled.
//
return status;
}
if (OptionsSupported & SUPPORTS_LOCAL) {
//
// Local case
//
RtlInitUnicodeString( &EncodedPassword, NULL );
RpcTryExcept {
//
// Obfuscate the password so it won't end up in the pagefile
//
if ( level >= 1 ) {
if ( ((PUSE_INFO_1)buf)->ui1_password != NULL ) {
UCHAR Seed = NETR_USE_ADD_PASSWORD_SEED;
// create a local copy of the password
lpwTempPassword = ((PUSE_INFO_1)buf)->ui1_password;
((PUSE_INFO_1)buf)->ui1_password = (LPWSTR)LocalAlloc(LMEM_FIXED,(wcslen(lpwTempPassword)+1) * sizeof(WCHAR));
if (((PUSE_INFO_1)buf)->ui1_password == NULL) {
((PUSE_INFO_1)buf)->ui1_password = lpwTempPassword;
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(((PUSE_INFO_1)buf)->ui1_password,lpwTempPassword);
RtlInitUnicodeString( &EncodedPassword,
((PUSE_INFO_1)buf)->ui1_password );
RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
}
}
status = NetrUseAdd(
NULL,
level,
(LPUSE_INFO) &buf,
parm_err
);
}
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
status = WsMapRpcError(RpcExceptionCode());
}
RpcEndExcept
//
// Put the password back the way we found it.
//
if(lpwTempPassword != NULL) {
LocalFree(((PUSE_INFO_1)buf)->ui1_password);
((PUSE_INFO_1)buf)->ui1_password = lpwTempPassword;
}
}
else {
//
// Remote servername specified. Only allow remoting to downlevel.
//
if (OptionsSupported & SUPPORTS_RPC) {
status = ERROR_NOT_SUPPORTED;
}
else {
//
// Call downlevel version of the API.
//
status = RxNetUseAdd(
servername,
level,
buf,
parm_err
);
}
}
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetUseDel(
IN LPTSTR servername OPTIONAL,
IN LPTSTR usename,
IN DWORD ucond
)
/*++
Routine Description:
This is the DLL entrypoint for NetUseDel.
Arguments:
servername - Supplies the name of server to execute this function
transportname - Supplies the name of the transport to delete.
ucond - Supplies a value which specifies the force level of disconnection
for the use.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
DWORD OptionsSupported;
status = NetRemoteComputerSupports(
servername,
SUPPORTS_RPC | SUPPORTS_LOCAL, // options wanted
&OptionsSupported
);
if (status != NERR_Success) {
//
// This is where machine not found gets handled.
//
return status;
}
if (OptionsSupported & SUPPORTS_LOCAL) {
//
// Local case
//
RpcTryExcept {
status = NetrUseDel(
NULL,
usename,
ucond
);
}
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
status = WsMapRpcError(RpcExceptionCode());
}
RpcEndExcept
}
else {
//
// Remote servername specified. Only allow remoting to downlevel.
//
if (OptionsSupported & SUPPORTS_RPC) {
status = ERROR_NOT_SUPPORTED;
}
else {
//
// Call downlevel version of the API.
//
status = RxNetUseDel(
servername,
usename,
ucond
);
}
}
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetUseGetInfo(
IN LPTSTR servername OPTIONAL,
IN LPTSTR usename,
IN DWORD level,
OUT LPBYTE *bufptr
)
/*++
Routine Description:
This is the DLL entrypoint for NetUseGetInfo.
Arguments:
servername - Supplies the name of server to execute this function
level - Supplies the requested level of information.
bufptr - Returns a pointer to a buffer which contains the requested
use information.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
DWORD OptionsSupported;
if (bufptr == NULL) {
return ERROR_INVALID_PARAMETER;
}
*bufptr = NULL; // Must be NULL so RPC knows to fill it in.
status = NetRemoteComputerSupports(
servername,
SUPPORTS_RPC | SUPPORTS_LOCAL, // options wanted
&OptionsSupported
);
if (status != NERR_Success) {
//
// This is where machine not found gets handled.
//
return status;
}
if (OptionsSupported & SUPPORTS_LOCAL) {
//
// Local case
//
RpcTryExcept {
status = NetrUseGetInfo(
NULL,
usename,
level,
(LPUSE_INFO) bufptr
);
}
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
status = WsMapRpcError(RpcExceptionCode());
}
RpcEndExcept
}
else {
//
// Remote servername specified. Only allow remoting to downlevel.
//
if (OptionsSupported & SUPPORTS_RPC) {
status = ERROR_NOT_SUPPORTED;
}
else {
//
// Call downlevel version of the API.
//
status = RxNetUseGetInfo(
servername,
usename,
level,
bufptr
);
}
}
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetUseEnum(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
OUT LPBYTE *bufptr,
IN DWORD prefmaxlen,
OUT LPDWORD entriesread,
OUT LPDWORD totalentries,
IN OUT LPDWORD resume_handle OPTIONAL
)
/*++
Routine Description:
This is the DLL entrypoint for NetUseEnum.
Arguments:
servername - Supplies the name of server to execute this function
level - Supplies the requested level of information.
bufptr - Returns a pointer to the buffer which contains a sequence of
information structure of the specified information level. This
pointer is set to NULL if return code is not NERR_Success or
ERROR_MORE_DATA, or if EntriesRead returned is 0.
prefmaxlen - Supplies the number of bytes of information to return in the
buffer. If this value is MAXULONG, all available information will
be returned.
entriesread - Returns the number of entries read into the buffer. This
value is only valid if the return code is NERR_Success or
ERROR_MORE_DATA.
totalentries - Returns the total number of entries available. This value
is only valid if the return code is NERR_Success or ERROR_MORE_DATA.
resume_handle - Supplies a handle to resume the enumeration from where it
left off the last time through. Returns the resume handle if return
code is ERROR_MORE_DATA.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
GENERIC_INFO_CONTAINER GenericInfoContainer;
GENERIC_ENUM_STRUCT InfoStruct;
DWORD OptionsSupported;
if (bufptr == NULL || entriesread == NULL) {
return ERROR_INVALID_PARAMETER;
}
try {
*entriesread = 0;
} except( EXCEPTION_EXECUTE_HANDLER ) {
return ERROR_INVALID_PARAMETER;
}
GenericInfoContainer.Buffer = NULL;
GenericInfoContainer.EntriesRead = 0;
InfoStruct.Container = &GenericInfoContainer;
InfoStruct.Level = level;
status = NetRemoteComputerSupports(
servername,
SUPPORTS_RPC | SUPPORTS_LOCAL, // options wanted
&OptionsSupported
);
if (status != NERR_Success) {
//
// This is where machine not found gets handled.
//
return status;
}
if (OptionsSupported & SUPPORTS_LOCAL) {
//
// Local case
//
RpcTryExcept {
status = NetrUseEnum(
NULL,
(LPUSE_ENUM_STRUCT) &InfoStruct,
prefmaxlen,
totalentries,
resume_handle
);
if (status == NERR_Success || status == ERROR_MORE_DATA) {
*bufptr = (LPBYTE) GenericInfoContainer.Buffer;
*entriesread = GenericInfoContainer.EntriesRead;
}
}
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
status = WsMapRpcError(RpcExceptionCode());
}
RpcEndExcept
}
else {
//
// Remote servername specified. Only allow remoting to downlevel.
//
if (OptionsSupported & SUPPORTS_RPC) {
status = ERROR_NOT_SUPPORTED;
}
else {
//
// Call downlevel version of the API.
//
status = RxNetUseEnum(
servername,
level,
bufptr,
prefmaxlen,
entriesread,
totalentries,
resume_handle
);
}
}
return status;
}
NET_API_STATUS NET_API_FUNCTION
NetMessageBufferSend (
IN LPCWSTR servername OPTIONAL,
IN LPCWSTR msgname,
IN LPCWSTR fromname,
IN LPBYTE buf,
IN DWORD buflen
)
/*++
Routine Description:
This is the DLL entrypoint for NetMessageBufferSend.
Arguments:
servername - Supplies the name of server to execute this function
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
#define MAX_MESSAGE_SIZE 1792
NET_API_STATUS status;
//
// Truncate messages greater than (2K - 1/8th) = 1792 due to the 2K LPC
// port data size max. The messenger server receiving this message uses
// the MessageBox() api with the MB_SERVICE_NOTIFICATION flag to display
// this message. The MB_SERVICE_NOTIFICATION flag instructs MessageBox()
// to piggyback the hard error mechanism to get the UI on the console;
// otherwise the UI would never be seen. This is where the LPC port data
// size limitation comes into play.
//
// Why subtract an 1/8th from 2K? The messenger server prepends a string
// to the message (e.g., "Message from Joe to Linda on 3/7/96 12:04PM").
// In English, this string is 67 characters max (max user/computer name
// is 15 chars).
// 67 * 1.5 (other languages) * 2 (sizeof(WCHAR)) = 201 bytes.
// An 1/8th of 2K is 256.
//
if (buflen > MAX_MESSAGE_SIZE) {
buf[MAX_MESSAGE_SIZE - 2] = '\0';
buf[MAX_MESSAGE_SIZE - 1] = '\0';
buflen = MAX_MESSAGE_SIZE;
}
NET_REMOTE_TRY_RPC
//
// Try RPC (local or remote) version of API.
//
status = NetrMessageBufferSend(
(LPWSTR)servername,
(LPWSTR)msgname,
(LPWSTR)fromname,
buf,
buflen
);
NET_REMOTE_RPC_FAILED("NetMessageBufferSend",
(LPWSTR)servername,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION )
//
// Call downlevel version of the API.
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
I_NetLogonDomainNameAdd(
IN LPTSTR logondomain
)
/*++
Routine Description:
This is the DLL entrypoint for the internal API I_NetLogonDomainNameAdd.
Arguments:
logondomain - Supplies the name of the logon domain to add to the Browser.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
status = I_NetrLogonDomainNameAdd(
logondomain
);
NET_REMOTE_RPC_FAILED(
"I_NetLogonDomainNameAdd",
NULL,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS NET_API_FUNCTION
I_NetLogonDomainNameDel(
IN LPTSTR logondomain
)
/*++
Routine Description:
This is the DLL entrypoint for the internal API I_NetLogonDomainNameDel.
Arguments:
logondomain - Supplies the name of the logon domain to delete from the
Browser.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
status = I_NetrLogonDomainNameDel(
logondomain
);
NET_REMOTE_RPC_FAILED(
"I_NetLogonDomainNameDel",
NULL,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
return status;
}
NET_API_STATUS
NetWkstaStatisticsGet(
IN LPTSTR ServerName,
IN DWORD Level,
IN DWORD Options,
OUT LPBYTE* Buffer
)
/*++
Routine Description:
Wrapper for workstation statistics retrieval routine - either calls the
client-side RPC function or calls RxNetStatisticsGet to retrieve the
statistics from a down-level workstation service
Arguments:
ServerName - where to remote this function
Level - of information required (MBZ)
Options - flags. Currently MBZ
Buffer - pointer to pointer to returned buffer
Return Value:
NET_API_STATUS
Success - NERR_Success
Failure - ERROR_INVALID_LEVEL
Level not 0
ERROR_INVALID_PARAMETER
Unsupported options requested
ERROR_NOT_SUPPORTED
Service is not SERVER or WORKSTATION
ERROR_ACCESS_DENIED
Caller doesn't have necessary access rights for request
--*/
{
NET_API_STATUS status;
if (Buffer == NULL) {
return ERROR_INVALID_PARAMETER;
}
//
// set the caller's buffer pointer to known value. This will kill the
// calling app if it gave us a bad pointer and didn't use try...except
//
*Buffer = NULL;
//
// validate parms
//
if (Level) {
return ERROR_INVALID_LEVEL;
}
//
// we don't even allow clearing of stats any more
//
if (Options) {
return ERROR_INVALID_PARAMETER;
}
//
// NTRAID-70679-2/6/2000 davey remove redundant service name parameter
//
NET_REMOTE_TRY_RPC
status = NetrWorkstationStatisticsGet(ServerName,
SERVICE_WORKSTATION,
Level,
Options,
(LPSTAT_WORKSTATION_0*)Buffer
);
NET_REMOTE_RPC_FAILED("NetrWorkstationStatisticsGet",
ServerName,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
status = RxNetStatisticsGet(ServerName,
SERVICE_LM20_WORKSTATION,
Level,
Options,
Buffer
);
NET_REMOTE_END
return status;
}
STATIC
DWORD
WsMapRpcError(
IN DWORD RpcError
)
/*++
Routine Description:
This routine maps the RPC error into a more meaningful net
error for the caller.
Arguments:
RpcError - Supplies the exception error raised by RPC
Return Value:
Returns the mapped error.
--*/
{
switch (RpcError) {
case RPC_S_SERVER_UNAVAILABLE:
return NERR_WkstaNotStarted;
case RPC_X_NULL_REF_POINTER:
return ERROR_INVALID_PARAMETER;
case EXCEPTION_ACCESS_VIOLATION:
return ERROR_INVALID_ADDRESS;
default:
return RpcError;
}
}
NET_API_STATUS
NetpEncodeJoinPassword(
IN LPWSTR lpPassword,
OUT LPWSTR *EncodedPassword
)
{
NET_API_STATUS status = NERR_Success;
UNICODE_STRING EncodedPasswordU;
PWSTR PasswordPart;
ULONG PwdLen;
UCHAR Seed;
*EncodedPassword = NULL;
if ( lpPassword ) {
PwdLen = wcslen( ( LPWSTR )lpPassword ) * sizeof( WCHAR );
PwdLen += sizeof( WCHAR ) + sizeof( WCHAR );
status = NetApiBufferAllocate( PwdLen,
( PVOID * )EncodedPassword );
if ( status == NERR_Success ) {
//
// We'll put the encode byte as the first character in the string
//
PasswordPart = ( *EncodedPassword ) + 1;
wcscpy( PasswordPart, ( LPWSTR )lpPassword );
RtlInitUnicodeString( &EncodedPasswordU, PasswordPart );
Seed = 0;
RtlRunEncodeUnicodeString( &Seed, &EncodedPasswordU );
*( PWCHAR )( *EncodedPassword ) = ( WCHAR )Seed;
}
}
return( status );
}
NTSTATUS
JoinpRandomFill(
IN ULONG BufferSize,
IN OUT PUCHAR Buffer
)
/*++
Routine Description:
This routine fills a buffer with random data.
Parameters:
BufferSize - Length of the input buffer, in bytes.
Buffer - Input buffer to be filled with random data.
Return Values:
Errors from NtQuerySystemTime()
--*/
{
ULONG Index;
LARGE_INTEGER Time;
ULONG Seed;
NTSTATUS NtStatus;
NtStatus = NtQuerySystemTime(&Time);
if (!NT_SUCCESS(NtStatus)) {
return(NtStatus);
}
Seed = Time.LowPart ^ Time.HighPart;
for (Index = 0 ; Index < BufferSize ; Index++ )
{
*Buffer++ = (UCHAR) (RtlRandom(&Seed) % 256);
}
return(STATUS_SUCCESS);
}
NET_API_STATUS
NetpEncryptJoinPasswordStart(
IN LPCWSTR ServerName OPTIONAL,
IN LPCWSTR lpPassword OPTIONAL,
OUT RPC_BINDING_HANDLE *RpcBindingHandle,
OUT HANDLE *RedirHandle,
OUT PJOINPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPassword,
OUT LPWSTR *EncodedPassword
)
/*++
Routine Description:
This routine takes a cleartext unicode NT password from the user,
and encrypts it with the session key.
Parameters:
ServerName - UNC server name of the server to remote the API to
lpPassword - the cleartext unicode NT password.
RpcBindingHandle - RPC handle used for acquiring a session key.
RedirHandle - Returns a handle to the redir. Since RpcBindingHandles don't represent
and open connection to the server, we have to ensure the connection stays open
until the server side has a chance to get this same UserSessionKey. The only
way to do that is to keep the connect open.
Returns NULL if no handle is needed.
EncryptedUserPassword - receives the encrypted cleartext password.
If lpPassword is NULL, a NULL is returned.
EncodedPassword - receives an encode form of lpPassowrd.
This form can be passed around locally with impunity.
Return Values:
If this routine returns NO_ERROR, the returned data must be freed using
NetpEncryptJoinPasswordEnd.
--*/
{
NET_API_STATUS NetStatus;
NTSTATUS NtStatus;
USER_SESSION_KEY UserSessionKey;
RC4_KEYSTRUCT Rc4Key;
MD5_CTX Md5Context;
PJOINPR_USER_PASSWORD UserPassword = NULL;
ULONG PasswordSize;
//
// Initialization
//
*RpcBindingHandle = NULL;
*EncryptedUserPassword = NULL;
*RedirHandle = NULL;
*EncodedPassword = NULL;
//
// Get an RPC handle to the server.
//
NetStatus = NetpBindRpc (
(LPWSTR) ServerName,
WORKSTATION_INTERFACE_NAME,
TEXT("Security=Impersonation Dynamic False"),
RpcBindingHandle );
if ( NetStatus != NO_ERROR ) {
goto Cleanup;
}
//
// If no password was specified,
// just return.
//
if ( lpPassword == NULL ) {
NetStatus = NO_ERROR;
goto Cleanup;
}
//
// Sanity check the password length
//
try {
PasswordSize = wcslen( lpPassword ) * sizeof(WCHAR);
} except( EXCEPTION_EXECUTE_HANDLER ) {
NetStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
if ( PasswordSize > JOIN_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) {
NetStatus = ERROR_PASSWORD_RESTRICTION;
goto Cleanup;
}
//
// Encode the password
//
NetStatus = NetpEncodeJoinPassword( (LPWSTR) lpPassword, EncodedPassword );
if ( NetStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Allocate a buffer to encrypt and fill it in.
//
UserPassword = LocalAlloc( 0, sizeof(*UserPassword) );
if ( UserPassword == NULL ) {
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// Copy the password into the tail end of the buffer.
//
RtlCopyMemory(
((PCHAR) UserPassword->Buffer) +
(JOIN_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
PasswordSize,
lpPassword,
PasswordSize );
UserPassword->Length = PasswordSize;
//
// Fill the front of the buffer with random data
//
NtStatus = JoinpRandomFill(
(JOIN_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
PasswordSize,
(PUCHAR) UserPassword->Buffer );
if ( !NT_SUCCESS(NtStatus) ) {
NetStatus = NetpNtStatusToApiStatus( NtStatus );
goto Cleanup;
}
NtStatus = JoinpRandomFill(
JOIN_OBFUSCATOR_LENGTH,
(PUCHAR) UserPassword->Obfuscator );
if ( !NT_SUCCESS(NtStatus) ) {
NetStatus = NetpNtStatusToApiStatus( NtStatus );
goto Cleanup;
}
//
// Get the session key.
//
NtStatus = RtlGetUserSessionKeyClientBinding(
*RpcBindingHandle,
RedirHandle,
&UserSessionKey );
if ( !NT_SUCCESS(NtStatus) ) {
NetStatus = NetpNtStatusToApiStatus( NtStatus );
goto Cleanup;
}
//
// The UserSessionKey is the same for the life of the session. RC4'ing multiple
// strings with a single key is weak (if you crack one you've cracked them all).
// So compute a key that's unique for this particular encryption.
//
//
MD5Init(&Md5Context);
MD5Update( &Md5Context, (LPBYTE)&UserSessionKey, sizeof(UserSessionKey) );
MD5Update( &Md5Context, UserPassword->Obfuscator, sizeof(UserPassword->Obfuscator) );
MD5Final( &Md5Context );
rc4_key( &Rc4Key, MD5DIGESTLEN, Md5Context.digest );
//
// Encrypt it.
// Don't encrypt the obfuscator. The server needs that to compute the key.
//
rc4( &Rc4Key, sizeof(UserPassword->Buffer)+sizeof(UserPassword->Length), (LPBYTE) UserPassword->Buffer );
NetStatus = NO_ERROR;
Cleanup:
if ( NetStatus == NO_ERROR ) {
*EncryptedUserPassword = (PJOINPR_ENCRYPTED_USER_PASSWORD) UserPassword;
} else {
if ( UserPassword != NULL ) {
LocalFree( UserPassword );
}
if ( *RpcBindingHandle != NULL ) {
NetpUnbindRpc( *RpcBindingHandle );
*RpcBindingHandle = NULL;
}
if ( *RedirHandle != NULL ) {
NtClose( *RedirHandle );
*RedirHandle = NULL;
}
if ( *EncodedPassword != NULL ) {
NetApiBufferFree( *EncodedPassword );
*EncodedPassword = NULL;
}
}
return NetStatus;
}
VOID
NetpEncryptJoinPasswordEnd(
IN RPC_BINDING_HANDLE RpcBindingHandle,
IN HANDLE RedirHandle OPTIONAL,
IN PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword OPTIONAL,
IN LPWSTR EncodedPassword OPTIONAL
)
/*++
Routine Description:
This routine takes the variables returned by NetpEncryptJoinPasswordStart and
frees them.
Parameters:
RpcBindingHandle - RPC handle used for acquiring a session key.
RedirHandle - Handle to the redirector
EncryptedUserPassword - the encrypted cleartext password.
EncodedPassword - the encoded form of lpPassowrd.
Return Values:
--*/
{
NET_API_STATUS NetStatus;
NTSTATUS NtStatus;
USER_SESSION_KEY UserSessionKey;
RC4_KEYSTRUCT Rc4Key;
PJOINPR_USER_PASSWORD UserPassword = NULL;
ULONG PasswordSize;
//
// Free the RPC binding handle.
//
if ( RpcBindingHandle != NULL ) {
(VOID) NetpUnbindRpc ( RpcBindingHandle );
}
//
// Close the redir handle.
//
if ( RedirHandle != NULL ) {
NtClose( RedirHandle );
}
//
// Free the encrypted password.
//
if ( EncryptedUserPassword != NULL ) {
LocalFree( EncryptedUserPassword );
}
//
// Free the encoded password
//
if ( EncodedPassword != NULL ) {
NetApiBufferFree( EncodedPassword );
}
}
NET_API_STATUS
NET_API_FUNCTION
NetJoinDomain(
IN LPCWSTR lpServer OPTIONAL,
IN LPCWSTR lpDomain,
IN LPCWSTR lpMachineAccountOU OPTIONAL,
IN LPCWSTR lpAccount OPTIONAL,
IN LPCWSTR lpPassword OPTIONAL,
IN DWORD fJoinOptions
)
/*++
Routine Description:
Joins the machine to the domain.
Arguments:
lpServer -- Name of server on which to execute this function
lpDomain -- Domain to join
lpMachineAccountOU -- Optional name of the OU under which to create the machine account
lpAccount -- Account to use for join
lpPassword -- Password matching the account
fOptions -- Options to use when joining the domain
Returns:
NERR_Success -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this interface
--*/
{
NET_API_STATUS NetStatus, OldStatus;
PWSTR ComputerName = NULL;
BOOLEAN CallLocal = FALSE;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( lpServer,
lpPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC version of API.
//
NetStatus = NetrJoinDomain2( RpcBindingHandle,
( LPWSTR )lpServer,
( LPWSTR )lpDomain,
( LPWSTR )lpMachineAccountOU,
( LPWSTR )lpAccount,
EncryptedUserPassword,
fJoinOptions );
NET_REMOTE_RPC_FAILED(
"NetJoinDomain",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
if ( NetStatus == NERR_WkstaNotStarted || NetStatus == ERROR_ACCESS_DENIED ) {
OldStatus = NetStatus;
if ( lpServer ) {
NetStatus = NetpGetComputerName( &ComputerName );
if ( NetStatus == NERR_Success ) {
if ( !_wcsicmp( lpServer, ComputerName ) ) {
CallLocal = TRUE;
}
NetApiBufferFree( ComputerName );
}
} else {
CallLocal = TRUE;
}
//
// Only call locally if we are joining a workgroup
//
if ( CallLocal && !FLAG_ON( fJoinOptions, NETSETUP_JOIN_DOMAIN ) ) {
NetStatus = NetpDoDomainJoin( ( LPWSTR )lpServer,
( LPWSTR )lpDomain,
NULL,
( LPWSTR )lpAccount,
( LPWSTR )EncodedPassword,
fJoinOptions );
} else {
NetStatus = OldStatus;
}
}
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetUnjoinDomain(
IN LPCWSTR lpServer OPTIONAL,
IN LPCWSTR lpAccount OPTIONAL,
IN LPCWSTR lpPassword OPTIONAL,
IN DWORD fUnjoinOptions
)
/*++
Routine Description:
Unjoins from the joined domain
Arguments:
lpServer -- Name of server on which to execute this function
lpAccount -- Account to use for unjoining
lpPassword -- Password matching the account
fOptions -- Options to use when unjoining the domain
Returns:
NERR_Success -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this interface
--*/
{
NET_API_STATUS NetStatus;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( lpServer,
lpPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC version of API.
//
NetStatus = NetrUnjoinDomain2(
RpcBindingHandle,
( LPWSTR )lpServer,
( LPWSTR )lpAccount,
EncryptedUserPassword,
fUnjoinOptions );
NET_REMOTE_RPC_FAILED(
"NetUnjoinDomain",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetRenameMachineInDomain(
IN LPCWSTR lpServer OPTIONAL,
IN LPCWSTR lpNewMachineName OPTIONAL,
IN LPCWSTR lpAccount OPTIONAL,
IN LPCWSTR lpPassword OPTIONAL,
IN DWORD fRenameOptions
)
/*++
Routine Description:
Renames a machine currently joined to a domain.
Arguments:
lpServer -- Name of server on which to execute this function
lpNewMachineName -- New name for this machine. If the name is specified, it is used
for the new machine name. If it is not specified, it is assumed that SetComputerName
has already been invoked, and that name will be used.
lpAccount -- Account to use for the rename
lpPassword -- Password matching the account
fOptions -- Options to use for the rename
Returns:
NERR_Success -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this interface
--*/
{
NET_API_STATUS NetStatus;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( lpServer,
lpPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
NetStatus = NetrRenameMachineInDomain2(
RpcBindingHandle,
( LPWSTR )lpServer,
( LPWSTR )lpNewMachineName,
( LPWSTR )lpAccount,
EncryptedUserPassword,
fRenameOptions );
NET_REMOTE_RPC_FAILED(
"NetRenameMachineInDomain",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetValidateName(
IN LPCWSTR lpServer OPTIONAL,
IN LPCWSTR lpName,
IN LPCWSTR lpAccount OPTIONAL,
IN LPCWSTR lpPassword OPTIONAL,
IN NETSETUP_NAME_TYPE NameType
)
/*++
Routine Description:
Ensures that the given name is valid for a name of that type
Arguments:
lpServer -- Name of server on which to execute this function
lpName -- Name to validate
lpAccount -- Account to use for validation
lpPassword -- Password matching the account
NameType -- Type of the name to validate
Returns:
NERR_Success -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this interface
--*/
{
NET_API_STATUS NetStatus, OldStatus;
PWSTR ComputerName = NULL;
BOOLEAN CallLocal = FALSE;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( lpServer,
lpPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
NetStatus = NetrValidateName2( RpcBindingHandle,
( LPWSTR )lpServer,
( LPWSTR )lpName,
( LPWSTR )lpAccount,
EncryptedUserPassword,
NameType );
NET_REMOTE_RPC_FAILED(
"NetValidateName",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
if ( NetStatus == NERR_WkstaNotStarted ) {
OldStatus = NetStatus;
if ( lpServer ) {
NetStatus = NetpGetComputerName( &ComputerName );
if ( NetStatus == NERR_Success ) {
if ( !_wcsicmp( lpServer, ComputerName ) ) {
CallLocal = TRUE;
}
NetApiBufferFree( ComputerName );
}
} else {
CallLocal = TRUE;
}
if ( CallLocal ) {
NetStatus = NetpValidateName( ( LPWSTR )lpServer,
( LPWSTR )lpName,
( LPWSTR )lpAccount,
EncodedPassword,
NameType );
} else {
NetStatus = OldStatus;
}
}
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetGetJoinInformation(
IN LPCWSTR lpServer OPTIONAL,
OUT LPWSTR *lpNameBuffer,
OUT PNETSETUP_JOIN_STATUS BufferType
)
/*++
Routine Description:
Gets information on the state of the workstation. The information
obtainable is whether the machine is joined to a workgroup or a domain,
and optionally, the name of that workgroup/domain.
Arguments:
lpServer -- Name of server on which to execute this function
lpNameBuffer -- Where the domain/workgroup name is returned.
BufferType -- Whether the machine is joined to a workgroup or a domain
Returns:
NERR_Success -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this interface
ERROR_INVALID_PARAMETER -- An invalid buffer pointer was given
--*/
{
NET_API_STATUS status, OldStatus;
LPWSTR Name = NULL, ComputerName = NULL;
BOOLEAN CallLocal = FALSE;
if ( lpNameBuffer == NULL ) {
return( ERROR_INVALID_PARAMETER );
}
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
status = NetrGetJoinInformation( ( LPWSTR )lpServer,
&Name,
BufferType );
NET_REMOTE_RPC_FAILED(
"NetGetJoinInformation",
NULL,
status,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
status = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
if ( status != NERR_Success ) {
OldStatus = status;
if ( lpServer ) {
if ( status == NERR_Success ) {
if ( !_wcsicmp( lpServer, ComputerName ) ) {
CallLocal = TRUE;
}
NetApiBufferFree( ComputerName );
}
} else {
CallLocal = TRUE;
}
if ( CallLocal ) {
status = NetpGetJoinInformation( ( LPWSTR )lpServer,
&Name,
BufferType );
} else {
status = OldStatus;
}
}
if ( status == NERR_Success ) {
*lpNameBuffer = Name;
}
return status;
}
NET_API_STATUS
NET_API_FUNCTION
NetGetJoinableOUs(
IN LPCWSTR lpServer OPTIONAL,
IN LPCWSTR lpDomain,
IN LPCWSTR lpAccount OPTIONAL,
IN LPCWSTR lpPassword OPTIONAL,
OUT DWORD *OUCount,
OUT LPWSTR **OUs
)
/*++
Routine Description:
This API is used to determine the list of OUs in which a machine account
can be created. This function is only valid against an NT5 or greater Dc.
Arguments:
lpServer -- Name of server on which to execute this function
lpDomain -- Domain to join
lpAccount -- Account to use for join
lpPassword -- Password matching the account
OUCount -- Where the number of joinable OU strings is returned
OUs -- Where the list of OU under which machine accounts can be created is returned
Returns:
NERR_Success -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this interface
ERROR_INVALID_PARAMETER -- An invalid buffer pointer was given
--*/
{
NET_API_STATUS NetStatus = NERR_Success;
ULONG Count = 0;
LPWSTR *OUList = NULL;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
if ( OUCount == NULL || OUs == NULL ) {
return( ERROR_INVALID_PARAMETER );
}
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( lpServer,
lpPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC (local only) version of API.
//
NetStatus = NetrGetJoinableOUs2(
RpcBindingHandle,
( LPWSTR )lpServer,
( LPWSTR )lpDomain,
( LPWSTR )lpAccount,
EncryptedUserPassword,
&Count,
&OUList );
NET_REMOTE_RPC_FAILED(
"NetrGetJoinableOUs",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
if ( NetStatus == NERR_Success ) {
*OUCount = Count;
*OUs = OUList;
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetAddAlternateComputerName(
IN LPCWSTR Server OPTIONAL,
IN LPCWSTR AlternateName,
IN LPCWSTR DomainAccount OPTIONAL,
IN LPCWSTR DomainAccountPassword OPTIONAL,
IN ULONG Reserved
)
/*++
Routine Description:
Adds an alternate name for the specified server.
Arguments:
Server -- Name of server on which to execute this function.
AlternateName -- The name to add.
DomainAccount -- Domain account to use for accessing the
machine account object for the specified server in the AD.
Not used if the server is not joined to a domain. May be
NULL in which case the credentials of the user executing
this routine are used.
DomainAccountPassword -- Password matching the domain account.
Not used if the server is not joined to a domain. May be
NULL in which case the credentials of the user executing
this routine are used.
Reserved -- Reserved for future use. If some flags are specified
that are not supported, they will be ignored if
NET_IGNORE_UNSUPPORTED_FLAGS is set, otherwise this routine
will fail with ERROR_INVALID_FLAGS.
Note:
The process that calls this routine must have administrator
privileges on the server computer.
Returns:
NO_ERROR -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this
functionality.
ERROR_INVALID_FLAGS - The Flags parameter is incorrect.
--*/
{
NET_API_STATUS NetStatus;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( Server,
DomainAccountPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC version of API.
//
NetStatus = NetrAddAlternateComputerName(
RpcBindingHandle,
(LPWSTR) Server,
(LPWSTR) AlternateName,
(LPWSTR) DomainAccount,
EncryptedUserPassword,
Reserved );
NET_REMOTE_RPC_FAILED(
"NetRenameMachineInDomain",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetRemoveAlternateComputerName(
IN LPCWSTR Server OPTIONAL,
IN LPCWSTR AlternateName,
IN LPCWSTR DomainAccount OPTIONAL,
IN LPCWSTR DomainAccountPassword OPTIONAL,
IN ULONG Reserved
)
/*++
Routine Description:
Deletes an alternate name for the specified server.
Arguments:
Server -- Name of server on which to execute this function.
AlternateName -- The name to delete.
DomainAccount -- Domain account to use for accessing the
machine account object for the specified server in the AD.
Not used if the server is not joined to a domain. May be
NULL in which case the credentials of the user executing
this routine are used.
DomainAccountPassword -- Password matching the domain account.
Not used if the server is not joined to a domain. May be
NULL in which case the credentials of the user executing
this routine are used.
Reserved -- Reserved for future use. If some flags are specified
that are not supported, they will be ignored if
NET_IGNORE_UNSUPPORTED_FLAGS is set, otherwise this routine
will fail with ERROR_INVALID_FLAGS.
Note:
The process that calls this routine must have administrator
privileges on the server computer.
Returns:
NO_ERROR -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this
functionality.
ERROR_INVALID_FLAGS - The Flags parameter is incorrect.
--*/
{
NET_API_STATUS NetStatus;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( Server,
DomainAccountPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC version of API.
//
NetStatus = NetrRemoveAlternateComputerName(
RpcBindingHandle,
(LPWSTR) Server,
(LPWSTR) AlternateName,
(LPWSTR) DomainAccount,
EncryptedUserPassword,
Reserved );
NET_REMOTE_RPC_FAILED(
"NetRenameMachineInDomain",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetSetPrimaryComputerName(
IN LPCWSTR Server OPTIONAL,
IN LPCWSTR PrimaryName,
IN LPCWSTR DomainAccount OPTIONAL,
IN LPCWSTR DomainAccountPassword OPTIONAL,
IN ULONG Reserved
)
/*++
Routine Description:
Sets the primary computer name for the specified server.
Arguments:
Server -- Name of server on which to execute this function.
PrimaryName -- The primary computer name to set.
DomainAccount -- Domain account to use for accessing the
machine account object for the specified server in the AD.
Not used if the server is not joined to a domain. May be
NULL in which case the credentials of the user executing
this routine are used.
DomainAccountPassword -- Password matching the domain account.
Not used if the server is not joined to a domain. May be
NULL in which case the credentials of the user executing
this routine are used.
Reserved -- Reserved for future use. If some flags are specified
that are not supported, they will be ignored if
NET_IGNORE_UNSUPPORTED_FLAGS is set, otherwise this routine
will fail with ERROR_INVALID_FLAGS.
Note:
The process that calls this routine must have administrator
privileges on the server computer.
Returns:
NO_ERROR -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this
functionality.
ERROR_INVALID_FLAGS - The Flags parameter is incorrect.
--*/
{
NET_API_STATUS NetStatus;
RPC_BINDING_HANDLE RpcBindingHandle;
HANDLE RedirHandle;
PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedUserPassword;
LPWSTR EncodedPassword;
//
// Encrypt the password.
//
NetStatus = NetpEncryptJoinPasswordStart( Server,
DomainAccountPassword,
&RpcBindingHandle,
&RedirHandle,
&EncryptedUserPassword,
&EncodedPassword );
if ( NetStatus == NERR_Success ) {
NET_REMOTE_TRY_RPC
//
// Try RPC version of API.
//
NetStatus = NetrSetPrimaryComputerName(
RpcBindingHandle,
(LPWSTR) Server,
(LPWSTR) PrimaryName,
(LPWSTR) DomainAccount,
EncryptedUserPassword,
Reserved );
NET_REMOTE_RPC_FAILED(
"NetRenameMachineInDomain",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
NetpEncryptJoinPasswordEnd( RpcBindingHandle,
RedirHandle,
EncryptedUserPassword,
EncodedPassword );
}
return NetStatus;
}
NET_API_STATUS
NET_API_FUNCTION
NetEnumerateComputerNames(
IN LPCWSTR Server OPTIONAL,
IN NET_COMPUTER_NAME_TYPE NameType,
IN ULONG Reserved,
OUT PDWORD EntryCount,
OUT LPWSTR **ComputerNames
)
/*++
Routine Description:
Enumerates computer names for the specified server.
Arguments:
Server -- Name of server on which to execute this function.
NameType -- The type of the name queried.
Reserved -- Reserved for future use. If some flags are specified
that are not supported, they will be ignored if
NET_IGNORE_UNSUPPORTED_FLAGS is set, otherwise this routine
will fail with ERROR_INVALID_FLAGS.
EntryCount -- Returns the number of names returned
ComputerNames -- An array of pointers to names. Must be freed by
calling NetApiBufferFree.
Returns:
NO_ERROR -- Success
ERROR_NOT_SUPPORTED -- The specified server does not support this
functionality.
ERROR_INVALID_FLAGS - The Flags parameter is incorrect.
--*/
{
NET_API_STATUS NetStatus = NO_ERROR;
PNET_COMPUTER_NAME_ARRAY ComputerNameArray = NULL;
NET_REMOTE_TRY_RPC
//
// Try RPC version of API.
//
NetStatus = NetrEnumerateComputerNames(
(LPWSTR) Server,
NameType,
Reserved,
&ComputerNameArray );
NET_REMOTE_RPC_FAILED(
"NetRenameMachineInDomain",
NULL,
NetStatus,
NET_REMOTE_FLAG_NORMAL,
SERVICE_WORKSTATION
)
//
// No downlevel version to try
//
NetStatus = ERROR_NOT_SUPPORTED;
NET_REMOTE_END
//
// Convert the computer names to what the caller expects
//
if ( NetStatus == NO_ERROR && ComputerNameArray != NULL ) {
//
// If there are no names returned,
// set the entry count to zero
//
if ( ComputerNameArray->EntryCount == 0 ) {
*ComputerNames = NULL;
*EntryCount = 0;
//
// Otherwise, allocate a buffer to return to the caller
//
} else {
ULONG Size;
ULONG i;
LPBYTE Where;
Size = sizeof(LPWSTR) * ComputerNameArray->EntryCount;
for ( i = 0; i < ComputerNameArray->EntryCount; i++ ) {
Size += ComputerNameArray->ComputerNames[i].Length + sizeof(WCHAR);
}
NetStatus = NetApiBufferAllocate( Size, (PVOID) ComputerNames );
if ( NetStatus == NO_ERROR ) {
//
// Set the size of the array
//
*EntryCount = ComputerNameArray->EntryCount;
//
// Loop copying names to the caller.
//
Where = ((LPBYTE)(*ComputerNames)) + sizeof(LPWSTR) * ComputerNameArray->EntryCount;
for ( i = 0; i < ComputerNameArray->EntryCount; i++ ) {
//
// Copy the site name into the return buffer.
//
(*ComputerNames)[i] = (LPWSTR) Where;
RtlCopyMemory( Where,
ComputerNameArray->ComputerNames[i].Buffer,
ComputerNameArray->ComputerNames[i].Length );
Where += ComputerNameArray->ComputerNames[i].Length;
*((LPWSTR)Where) = L'\0';
Where += sizeof(WCHAR);
}
}
}
NetApiBufferFree( ComputerNameArray );
}
return NetStatus;
}