mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1092 lines
32 KiB
1092 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1991-1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
xsproc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the main processing loop for XACTSRV.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 05-Jan-1991
|
|
Shanku Niyogi (w-shanku)
|
|
|
|
Revision History:
|
|
|
|
02-Jun-1992 JohnRo
|
|
RAID 9829: Avoid SERVICE_ equate conflicts.
|
|
|
|
Chuck Lenzmeier (chuckl) 17-Jun-1992
|
|
Moved from xssvc to srvsvc\server
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes.
|
|
//
|
|
|
|
#include "srvsvcp.h"
|
|
#include "xsdata.h"
|
|
#include "ssdata.h"
|
|
|
|
#include <netevent.h>
|
|
|
|
#include <windows.h> // from sdk\inc
|
|
#include <winspool.h>
|
|
|
|
#include <xsprocs.h> // from net\inc
|
|
#include <apinums.h> // from net\inc
|
|
#include <netlib.h> // from net\inc (NetpGetComputerName)
|
|
|
|
#include <xactsrv2.h> // from private\inc
|
|
#include <smbgtpt.h>
|
|
|
|
#include <xsconst.h> // from xactsrv
|
|
#include <xsprocsp.h>
|
|
|
|
#include <lmsname.h> // from \sdk\inc
|
|
#include <lmerr.h> // from \sdk\inc
|
|
#include <lmapibuf.h> // from \sdk\inc (NetApiBufferFree)
|
|
#include <lmmsg.h> // from \sdk\inc (NetMessageBufferSend)
|
|
#include <winsvc.h> // from \sdk\inc
|
|
|
|
#include <ntlsapi.h> // from \sdk\inc (License Server APIs)
|
|
|
|
#if DBG
|
|
#include <stdio.h>
|
|
#include <lmbrowsr.h>
|
|
#endif
|
|
|
|
#undef DEBUG
|
|
#undef DEBUG_API_ERRORS
|
|
#include <xsdebug.h>
|
|
|
|
VOID
|
|
ConvertApiStatusToDosStatus(
|
|
LPXS_PARAMETER_HEADER header
|
|
);
|
|
|
|
VOID
|
|
XsProcessApis (
|
|
DWORD ThreadNum
|
|
);
|
|
|
|
//
|
|
// This is the number of Xs threads blocked waiting for an LPC request.
|
|
// When it drops to zero, all threads are active and another thread is
|
|
// created.
|
|
//
|
|
LONG XsWaitingApiThreads = 0;
|
|
|
|
|
|
VOID
|
|
XsProcessApisWrapper (
|
|
DWORD ThreadNum
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine provides multithreaded capability for main processing
|
|
routine, XsProcessApis.
|
|
|
|
Arguments:
|
|
|
|
ThreadNum - thread number for debugging purposes.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
XACTSRV_REQUEST_MESSAGE requestMessage;
|
|
|
|
//
|
|
// Increase the priority of this thread to just above foreground (the
|
|
// same as the rest of the server).
|
|
//
|
|
|
|
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
|
|
|
|
//
|
|
// Do the APIs
|
|
//
|
|
XsProcessApis( ThreadNum );
|
|
|
|
IF_DEBUG(THREADS) {
|
|
SS_PRINT(( "Thread %ld exiting, active count %ld\n", ThreadNum,
|
|
XsThreads ));
|
|
}
|
|
|
|
//
|
|
// Decrement the count of threads. If the count goes to
|
|
// zero, set the All Threads Terminated event.
|
|
//
|
|
|
|
if( InterlockedDecrement( &XsThreads ) == 0 ) {
|
|
|
|
SetEvent( XsAllThreadsTerminatedEvent );
|
|
|
|
} else if( XsTerminating ) {
|
|
|
|
//
|
|
// There are still threads left, and we are trying to terminate. Queue
|
|
// another message to the queue so the next thread will get it and
|
|
// notice that we're trying to quit.
|
|
//
|
|
RtlZeroMemory( &requestMessage, sizeof( requestMessage ));
|
|
requestMessage.PortMessage.u1.s1.DataLength =
|
|
(USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
|
|
requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
|
|
requestMessage.MessageType = XACTSRV_MESSAGE_WAKEUP;
|
|
|
|
NtRequestPort(
|
|
XsConnectionPortHandle,
|
|
(PPORT_MESSAGE)&requestMessage
|
|
);
|
|
}
|
|
|
|
|
|
ExitThread( NO_ERROR );
|
|
|
|
} // XsProcessApisWrapper
|
|
|
|
|
|
VOID
|
|
XsProcessApis (
|
|
DWORD ThreadNum
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine waits for messages to come through the LPC port to
|
|
the server. When one does, it calls the appropriate routine to
|
|
handle the API, then replies to the server indicating that the
|
|
API has completed.
|
|
|
|
Arguments:
|
|
|
|
ThreadNum - thread number for debugging purposes.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
NET_API_STATUS error;
|
|
XACTSRV_REQUEST_MESSAGE request;
|
|
XACTSRV_REPLY_MESSAGE reply;
|
|
BOOL sendReply = FALSE;
|
|
LPTRANSACTION transaction;
|
|
WORD apiNumber;
|
|
LPXS_PARAMETER_HEADER header;
|
|
LPVOID parameters;
|
|
LPDESC structureDesc;
|
|
LPDESC auxStructureDesc;
|
|
LPDESC paramStructureDesc;
|
|
DWORD newThreadCount;
|
|
#if 0
|
|
LARGE_INTEGER XactSrvStartTime;
|
|
LARGE_INTEGER XactSrvEndTime;
|
|
LARGE_INTEGER PerformanceFrequency;
|
|
#endif
|
|
|
|
//
|
|
// Loop dispatching API requests.
|
|
//
|
|
while ( XsTerminating == FALSE ) {
|
|
|
|
//
|
|
// We're waiting to handle another API...
|
|
//
|
|
InterlockedIncrement( &XsWaitingApiThreads );
|
|
|
|
//
|
|
// Send the reply to the last message and wait for the next
|
|
// message. The first time through the loop, there will be
|
|
// no last message -- reply will be NULL.
|
|
//
|
|
|
|
status = NtReplyWaitReceivePort(
|
|
XsCommunicationPortHandle,
|
|
NULL, // PortContext
|
|
sendReply ? (PPORT_MESSAGE)&reply : NULL,
|
|
(PPORT_MESSAGE)&request
|
|
);
|
|
|
|
sendReply = TRUE;
|
|
|
|
//
|
|
// Set up the response message to be sent on the next call to
|
|
// NtReplyWaitReceivePort.
|
|
//
|
|
reply.PortMessage.u1.s1.DataLength =
|
|
sizeof(reply) - sizeof(PORT_MESSAGE);
|
|
reply.PortMessage.u1.s1.TotalLength = sizeof(reply);
|
|
reply.PortMessage.u2.ZeroInit = 0;
|
|
reply.PortMessage.ClientId = request.PortMessage.ClientId;
|
|
reply.PortMessage.MessageId = request.PortMessage.MessageId;
|
|
|
|
IF_DEBUG(THREADS) {
|
|
SS_PRINT(( "XsProcessApis: Thread %d: NtReplyWaitReceivePort %X, msg %X\n",
|
|
ThreadNum, status, &request ));
|
|
}
|
|
|
|
if ( status == STATUS_INVALID_PORT_HANDLE
|
|
|| status == STATUS_PORT_DISCONNECTED
|
|
|| status == STATUS_INVALID_HANDLE
|
|
|| XsTerminating
|
|
|| request.PortMessage.u2.s2.Type == LPC_PORT_CLOSED ) {
|
|
|
|
//
|
|
// The port is no longer valid, or XACTSRV is terminating.
|
|
//
|
|
|
|
IF_DEBUG(THREADS) {
|
|
SS_PRINT(( "XsProcessApis: %s. Thread %ld quitting\n",
|
|
XsTerminating ?
|
|
"XACTSRV terminating" : "Port invalid",
|
|
ThreadNum ));
|
|
}
|
|
|
|
InterlockedDecrement( &XsWaitingApiThreads );
|
|
return;
|
|
|
|
} else if ( !NT_SUCCESS(status) ) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
SS_PRINT(( "XsProcessApis: NtReplyWaitReceivePort "
|
|
"failed: %X\n", status ));
|
|
}
|
|
InterlockedDecrement( &XsWaitingApiThreads );
|
|
return;
|
|
|
|
}
|
|
|
|
IF_DEBUG(THREADS) {
|
|
SS_PRINT(( "XsProcessApis: Thread %ld responding to request, "
|
|
" MessageType %d, XsTerminating %d",
|
|
ThreadNum, request.MessageType, XsTerminating ));
|
|
}
|
|
|
|
if( InterlockedDecrement( &XsWaitingApiThreads ) == 0 ) {
|
|
|
|
HANDLE threadHandle;
|
|
DWORD threadId;
|
|
|
|
//
|
|
// Are there other threads ready to handle new requests? If not, then
|
|
// we should spawn a new thread. Since the server synchronously sends
|
|
// requests to xactsrv, we will never end up with more than
|
|
// the maximum number of server worker threads + 1.
|
|
//
|
|
|
|
InterlockedIncrement( &XsThreads );
|
|
|
|
threadHandle = CreateThread(
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)XsProcessApisWrapper,
|
|
(LPVOID)XsThreads,
|
|
0,
|
|
&threadId
|
|
);
|
|
|
|
if ( threadHandle != 0 ) {
|
|
|
|
IF_DEBUG(THREADS) {
|
|
SS_PRINT(( "XsStartXactsrv: Created thread %ld for "
|
|
"processing APIs\n", XsThreads ));
|
|
}
|
|
|
|
CloseHandle( threadHandle );
|
|
|
|
} else {
|
|
|
|
IF_DEBUG(THREADS) {
|
|
SS_PRINT(( "XsStartXactsrv: Unable to create thread %ld for "
|
|
"processing APIs\n", XsThreads ));
|
|
}
|
|
|
|
InterlockedDecrement( &XsThreads );
|
|
}
|
|
}
|
|
|
|
switch ( request.MessageType ) {
|
|
|
|
case XACTSRV_MESSAGE_SERVER_THREAD_EXIT:
|
|
//
|
|
// If we aren't the last thread, we can go away too.
|
|
//
|
|
if( XsThreads != 1 ) {
|
|
//
|
|
// But first we need to send a response
|
|
//
|
|
NtReplyPort(
|
|
XsCommunicationPortHandle,
|
|
(PPORT_MESSAGE)&reply );
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// We are the last thread. We must not go away.
|
|
//
|
|
break;
|
|
|
|
case XACTSRV_MESSAGE_DOWN_LEVEL_API:
|
|
|
|
//
|
|
// Get a pointer to the transaction block from the message.
|
|
// It is the file server's responsibility to set up this
|
|
// pointer correctly, and since he is a trusted entity, we
|
|
// do no checking on the pointer value.
|
|
//
|
|
|
|
transaction = request.Message.DownLevelApi.Transaction;
|
|
ASSERT( transaction != NULL );
|
|
|
|
#if 0
|
|
NtQueryPerformanceCounter(&XactSrvStartTime, &PerformanceFrequency);
|
|
|
|
//
|
|
// Convert frequency from ticks/second to ticks/millisecond
|
|
//
|
|
|
|
PerformanceFrequency = LiXDiv(PerformanceFrequency, 1000);
|
|
|
|
if (LiGeq(XactSrvStartTime, transaction->XactSrvTime)) {
|
|
CHAR Buffer[200];
|
|
LARGE_INTEGER LpcTime = LiSub(XactSrvStartTime, transaction->XactSrvTime);
|
|
|
|
LpcTime = LiDiv(LpcTime, PerformanceFrequency);
|
|
|
|
sprintf(Buffer, "XactSrv: LPC Time: %ld milliseconds (%ld)\n", LpcTime.LowPart, LpcTime.HighPart);
|
|
|
|
I_BrowserDebugTrace(NULL, Buffer);
|
|
}
|
|
#endif
|
|
//
|
|
// The API number is the first word in the parameters
|
|
// section, and it is followed by the parameter descriptor
|
|
// string. After that comes the data descriptor.
|
|
//
|
|
|
|
apiNumber = SmbGetUshort( (LPWORD)transaction->InParameters );
|
|
paramStructureDesc = (LPDESC)( transaction->InParameters + 2 );
|
|
structureDesc = paramStructureDesc
|
|
+ strlen( paramStructureDesc ) + 1;
|
|
|
|
//
|
|
// Make sure the API number is in range.
|
|
//
|
|
|
|
if ( apiNumber >=
|
|
(sizeof(XsApiTable) / sizeof(XS_API_TABLE_ENTRY)) ) {
|
|
reply.Message.DownLevelApi.Status =
|
|
STATUS_INVALID_SYSTEM_SERVICE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check if the parameter descriptor is valid. If not,
|
|
// there is obviously something very wrong about this
|
|
// request.
|
|
//
|
|
|
|
if ( XsApiTable[apiNumber].Params != NULL &&
|
|
!XsCheckSmbDescriptor( paramStructureDesc,
|
|
XsApiTable[apiNumber].Params )) {
|
|
reply.Message.DownLevelApi.Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Capture the input parameters into a buffer. The API
|
|
// handler will treat this data as passed-in parameters.
|
|
//
|
|
|
|
header = XsCaptureParameters( transaction, &auxStructureDesc );
|
|
|
|
if ( header == NULL ) {
|
|
reply.Message.DownLevelApi.Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize header to default values.
|
|
//
|
|
|
|
header->Converter = 0;
|
|
header->Status = NO_ERROR;
|
|
header->ClientMachineName =
|
|
request.Message.DownLevelApi.ClientMachineName;
|
|
|
|
header->ClientTransportName = request.Message.DownLevelApi.TransportName;
|
|
|
|
header->EncryptionKey = request.Message.DownLevelApi.LanmanSessionKey;
|
|
|
|
header->Flags = request.Message.DownLevelApi.Flags;
|
|
|
|
header->ServerName = request.Message.DownLevelApi.ServerName;
|
|
|
|
parameters = header + 1;
|
|
|
|
IF_DEBUG(LPC) {
|
|
|
|
SS_PRINT(( "XsProcessApis: received message from %ws at %lx, "
|
|
"transaction %lx, API %ld on transport %ws\n",
|
|
header->ClientMachineName, &request,
|
|
transaction, apiNumber,
|
|
header->ClientTransportName ));
|
|
}
|
|
|
|
IF_DEBUG(DESC_STRINGS) {
|
|
|
|
SS_PRINT(( "XsProcessApis: API %ld, parameters %s, data %s\n",
|
|
apiNumber, paramStructureDesc, structureDesc ));
|
|
}
|
|
|
|
//
|
|
// Impersonate the client before calling the API.
|
|
//
|
|
|
|
if ( XsApiTable[apiNumber].ImpersonateClient ) {
|
|
|
|
//
|
|
// BUGBUG: Fail here if request came over a null session!
|
|
// Otherwise, forging API requests over null sessions
|
|
// would be a great way for unprivileged clients
|
|
// to execute privileged APIs.
|
|
//
|
|
|
|
status = NtImpersonateClientOfPort(
|
|
XsCommunicationPortHandle,
|
|
(PPORT_MESSAGE)&request
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
SS_PRINT(( "XsProcessApis: NtImpersonateClientOfPort "
|
|
"failed: %X\n", status ));
|
|
}
|
|
|
|
reply.Message.DownLevelApi.Status = ERROR_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call the API processing routine to perform the actual API call.
|
|
// The called routine should set up parameters, make the actual API
|
|
// call, and return the status to us.
|
|
//
|
|
|
|
reply.Message.DownLevelApi.Status =
|
|
XsApiTable[apiNumber].Handler(
|
|
header,
|
|
parameters,
|
|
structureDesc,
|
|
auxStructureDesc
|
|
);
|
|
|
|
//
|
|
// Discontinue client impersonation.
|
|
//
|
|
|
|
if ( XsApiTable[apiNumber].ImpersonateClient ) {
|
|
|
|
PVOID dummy = NULL;
|
|
|
|
status = NtSetInformationThread(
|
|
NtCurrentThread( ),
|
|
ThreadImpersonationToken,
|
|
&dummy, // discontinue impersonation
|
|
sizeof(PVOID)
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status)) {
|
|
IF_DEBUG(ERRORS) {
|
|
SS_PRINT(( "XsProcessApis: NtSetInformationThread "
|
|
"(revert) failed: %X\n", status ));
|
|
}
|
|
// *** Ignore the error.
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure we return the right error codes
|
|
//
|
|
|
|
if ( header->Status != NERR_Success ) {
|
|
ConvertApiStatusToDosStatus( header );
|
|
}
|
|
|
|
//
|
|
// Put the parameters in the transaction and free the parameter
|
|
// buffer.
|
|
//
|
|
|
|
XsSetParameters( transaction, header, parameters );
|
|
|
|
break;
|
|
|
|
case XACTSRV_MESSAGE_OPEN_PRINTER: {
|
|
|
|
UNICODE_STRING printerName;
|
|
|
|
RtlInitUnicodeString(
|
|
&printerName,
|
|
(PWCH)request.Message.OpenPrinter.PrinterName
|
|
);
|
|
|
|
if (!OpenPrinter( printerName.Buffer,
|
|
&reply.Message.OpenPrinter.hPrinter, NULL)) {
|
|
|
|
reply.Message.OpenPrinter.Error = GetLastError();
|
|
SS_PRINT(( "XsProcessApis: OpenPrinter failed: %ld\n",
|
|
reply.Message.OpenPrinter.Error ));
|
|
break;
|
|
}
|
|
|
|
|
|
reply.Message.OpenPrinter.Error = NO_ERROR;
|
|
break;
|
|
}
|
|
|
|
case XACTSRV_MESSAGE_ADD_JOB_PRINTER:
|
|
{
|
|
LPADDJOB_INFO_1 addJob;
|
|
PRINTER_DEFAULTS prtDefault;
|
|
DWORD bufferLength;
|
|
UNICODE_STRING dosName;
|
|
UNICODE_STRING ntName;
|
|
BOOL ok;
|
|
PVOID dummy = NULL;
|
|
|
|
//
|
|
// Allocate space for the add job structure. This buffer
|
|
// will get the JobId and the spool file path name.
|
|
//
|
|
|
|
bufferLength = sizeof(ADDJOB_INFO_1) +
|
|
(MAXIMUM_FILENAME_LENGTH * sizeof(TCHAR));
|
|
|
|
addJob = (LPADDJOB_INFO_1) LocalAlloc( LPTR, bufferLength );
|
|
if ( addJob == NULL ) {
|
|
reply.Message.AddPrintJob.Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Impersonate the client before calling the API.
|
|
//
|
|
|
|
status = NtImpersonateClientOfPort(
|
|
XsCommunicationPortHandle,
|
|
(PPORT_MESSAGE)&request
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
SS_PRINT(( "XsProcessApis: NtImpersonateClientOfPort "
|
|
"failed: %X\n", status ));
|
|
}
|
|
|
|
LocalFree( addJob );
|
|
reply.Message.DownLevelApi.Status = ERROR_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// call ResetJob so that we will pick up the new printer defaults
|
|
//
|
|
|
|
prtDefault.pDatatype = (LPWSTR)-1;
|
|
prtDefault.pDevMode = (LPDEVMODEW)-1;
|
|
prtDefault.DesiredAccess = 0;
|
|
|
|
ok = ResetPrinter(
|
|
request.Message.AddPrintJob.hPrinter,
|
|
&prtDefault
|
|
);
|
|
|
|
if ( !ok ) {
|
|
|
|
//
|
|
// *** Ignore the error. AddJob will use the old defaults
|
|
// in this case.
|
|
//
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
DWORD error;
|
|
error = GetLastError( );
|
|
SS_PRINT(( "XsProcessApis: ResetPrinter "
|
|
"failed: %ld\n", error ));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call AddJob to set up the print job and get a job ID
|
|
// and spool file name.
|
|
//
|
|
|
|
ok = AddJob(
|
|
request.Message.AddPrintJob.hPrinter,
|
|
1,
|
|
(LPBYTE)addJob,
|
|
bufferLength,
|
|
&bufferLength
|
|
);
|
|
|
|
if ( !ok ) {
|
|
reply.Message.AddPrintJob.Error = GetLastError( );
|
|
}
|
|
|
|
//
|
|
// Discontinue client impersonation.
|
|
//
|
|
|
|
status = NtSetInformationThread(
|
|
NtCurrentThread( ),
|
|
ThreadImpersonationToken,
|
|
&dummy, // discontinue impersonation
|
|
sizeof(PVOID)
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status)) {
|
|
IF_DEBUG(ERRORS) {
|
|
SS_PRINT(( "XsProcessApis: NtSetInformationThread "
|
|
"(revert) failed: %X\n", status ));
|
|
}
|
|
// *** Ignore the error.
|
|
}
|
|
|
|
if ( !ok ) {
|
|
SS_PRINT(( "XsProcessApis: AddJob failed, %ld\n",
|
|
reply.Message.AddPrintJob.Error ));
|
|
LocalFree( addJob );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set up the information in the return buffer.
|
|
//
|
|
|
|
reply.Message.AddPrintJob.JobId = addJob->JobId;
|
|
|
|
RtlInitUnicodeString( &dosName, addJob->Path );
|
|
|
|
status = RtlDosPathNameToNtPathName_U(
|
|
dosName.Buffer,
|
|
&ntName,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(ERRORS) {
|
|
SS_PRINT(( "XsProcessApis: Dos-to-NT path failed: %X\n",
|
|
status ));
|
|
}
|
|
ntName.Buffer = NULL;
|
|
ntName.Length = 0;
|
|
}
|
|
|
|
//
|
|
// Set up return data.
|
|
//
|
|
|
|
reply.Message.AddPrintJob.BufferLength = ntName.Length;
|
|
reply.Message.AddPrintJob.Error = NO_ERROR;
|
|
RtlCopyMemory(
|
|
request.Message.AddPrintJob.Buffer,
|
|
ntName.Buffer,
|
|
ntName.Length
|
|
);
|
|
|
|
//
|
|
// Free allocated resources.
|
|
//
|
|
|
|
LocalFree( addJob );
|
|
if ( ntName.Buffer != NULL ) {
|
|
RtlFreeHeap( RtlProcessHeap( ), 0, ntName.Buffer );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XACTSRV_MESSAGE_SCHD_JOB_PRINTER:
|
|
|
|
//
|
|
// Call ScheduleJob( ) to indicate that we're done writing to
|
|
// the spool file.
|
|
//
|
|
|
|
if ( !ScheduleJob(
|
|
request.Message.SchedulePrintJob.hPrinter,
|
|
request.Message.SchedulePrintJob.JobId ) ) {
|
|
|
|
reply.Message.SchedulePrintJob.Error = GetLastError( );
|
|
SS_PRINT(( "XsProcessApis: ScheduleJob failed, %ld\n",
|
|
reply.Message.SchedulePrintJob.Error ));
|
|
break;
|
|
}
|
|
|
|
reply.Message.SchedulePrintJob.Error = NO_ERROR;
|
|
break;
|
|
|
|
case XACTSRV_MESSAGE_CLOSE_PRINTER:
|
|
|
|
if ( !ClosePrinter( request.Message.ClosePrinter.hPrinter ) ) {
|
|
reply.Message.ClosePrinter.Error = GetLastError( );
|
|
SS_PRINT(( "XsProcessApis: ClosePrinter failed: %ld\n",
|
|
reply.Message.ClosePrinter.Error ));
|
|
break;
|
|
}
|
|
|
|
reply.Message.ClosePrinter.Error = NO_ERROR;
|
|
break;
|
|
|
|
case XACTSRV_MESSAGE_MESSAGE_SEND:
|
|
{
|
|
LPTSTR sender;
|
|
|
|
error = NetpGetComputerName( &sender );
|
|
|
|
if ( error != NO_ERROR ) {
|
|
SS_PRINT(( "XsProcessApis: NetpGetComputerName failed: %ld\n",
|
|
error ));
|
|
reply.Message.MessageBufferSend.Error = error;
|
|
break;
|
|
}
|
|
|
|
error = NetMessageBufferSend(
|
|
NULL,
|
|
|
|
//
|
|
// BUGBUG - the following LPTSTR typecast is WRONG -
|
|
// it must be fixed in ntos\srv\scavengr.c which
|
|
// should pass in a LPWSTR if built for unicode or
|
|
// convert the UNICODE_STRING to an OEM_STRING and
|
|
// pass a pointer to the buffer field, as it does
|
|
// now
|
|
//
|
|
|
|
//FIXFIX
|
|
(LPTSTR)request.Message.MessageBufferSend.Receipient,
|
|
//request.Message.MessageBufferSend.Receipient,
|
|
//ENDFIX
|
|
sender,
|
|
request.Message.MessageBufferSend.Buffer,
|
|
request.Message.MessageBufferSend.BufferLength
|
|
);
|
|
|
|
if ( error != NO_ERROR ) {
|
|
SS_PRINT(( "XsProcessApis: NetMessageBufferSend failed: %ld\n",
|
|
error ));
|
|
}
|
|
|
|
(void) NetApiBufferFree( sender );
|
|
|
|
reply.Message.MessageBufferSend.Error = error;
|
|
break;
|
|
}
|
|
|
|
case XACTSRV_MESSAGE_LSREQUEST:
|
|
SS_PRINT(( "LSREQUEST User: %ws\n", request.Message.LSRequest.UserName ));
|
|
{
|
|
NT_LS_DATA NtLSData;
|
|
|
|
NtLSData.DataType = NT_LS_USER_NAME;
|
|
NtLSData.Data = request.Message.LSRequest.UserName;
|
|
NtLSData.IsAdmin = request.Message.LSRequest.IsAdmin;
|
|
|
|
reply.Message.LSRequest.Status = NtLicenseRequest (
|
|
SsData.ServerProductName,
|
|
SsData.szVersionNumber,
|
|
(LS_HANDLE *)&reply.Message.LSRequest.hLicense,
|
|
&NtLSData
|
|
);
|
|
|
|
if( !NT_SUCCESS( reply.Message.LSRequest.Status ) ) {
|
|
//
|
|
// We need to return the 'same old' error code that clients are used to
|
|
// getting for when the server is full
|
|
//
|
|
SS_PRINT(("LSREQUEST returns status %X, mapping to %X\n",
|
|
reply.Message.LSRequest.Status, STATUS_REQUEST_NOT_ACCEPTED ));
|
|
reply.Message.LSRequest.Status = STATUS_REQUEST_NOT_ACCEPTED;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XACTSRV_MESSAGE_LSRELEASE:
|
|
|
|
SS_PRINT(( "LSRELEASE Handle: %X\n", request.Message.LSRelease.hLicense ));
|
|
NtLSFreeHandle( (LS_HANDLE)request.Message.LSRelease.hLicense );
|
|
break;
|
|
|
|
#ifdef SRV_PNP_POWER
|
|
|
|
case XACTSRV_MESSAGE_PNP:
|
|
{
|
|
|
|
UNICODE_STRING transportName;
|
|
ULONG numberOfBindings = 0;
|
|
PVOID dummy = NULL;
|
|
|
|
transportName.MaximumLength =
|
|
transportName.Length = request.Message.Pnp.TransportName.Length;
|
|
|
|
transportName.Buffer = MIDL_user_allocate( transportName.Length );
|
|
|
|
if( transportName.Buffer == NULL ) {
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory( transportName.Buffer,
|
|
request.Message.Pnp.TransportName.Buffer,
|
|
transportName.Length
|
|
);
|
|
|
|
status = NtImpersonateClientOfPort(
|
|
XsCommunicationPortHandle,
|
|
(PPORT_MESSAGE)&request
|
|
);
|
|
|
|
//
|
|
// Now process the PNP command
|
|
//
|
|
if( request.Message.Pnp.Bind == TRUE ) {
|
|
|
|
//
|
|
// Bind to the transport. First bind the primary server name, then bind all
|
|
// of the secondary names. These calls will log errors as necessary.
|
|
//
|
|
BindToTransport(
|
|
NULL, // ValueName
|
|
REG_SZ, // ValueType
|
|
transportName.Buffer, // ValueData (transport name)
|
|
transportName.Length, // ValueLength
|
|
&numberOfBindings, // Context
|
|
NULL // EntryContext
|
|
);
|
|
|
|
BindOptionalNames(
|
|
NULL, // ValueName
|
|
REG_SZ, // ValueType
|
|
transportName.Buffer, // ValueData (transport name)
|
|
transportName.Length, // ValueLength
|
|
&numberOfBindings, // Context
|
|
NULL // EntryContext
|
|
);
|
|
|
|
} else {
|
|
//
|
|
// Unbind from the transport
|
|
//
|
|
DbgPrint( "SRVSVC: PNP unbind from %wZ\n", &transportName );
|
|
}
|
|
|
|
//
|
|
// Discontinue client impersonation.
|
|
//
|
|
status = NtSetInformationThread(
|
|
NtCurrentThread( ),
|
|
ThreadImpersonationToken,
|
|
&dummy, // discontinue impersonation
|
|
sizeof(PVOID)
|
|
);
|
|
|
|
MIDL_user_free( transportName.Buffer );
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
default:
|
|
|
|
SS_ASSERT( FALSE );
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
if ( request.MessageType == XACTSRV_MESSAGE_DOWN_LEVEL_API ) {
|
|
NtQueryPerformanceCounter(&XactSrvEndTime, NULL);
|
|
|
|
if (LiGeq(XactSrvEndTime, XactSrvStartTime)) {
|
|
CHAR Buffer[200];
|
|
LARGE_INTEGER XsTime = LiSub(XactSrvEndTime, XactSrvStartTime);
|
|
|
|
XsTime = LiDiv(XsTime, PerformanceFrequency);
|
|
|
|
sprintf(Buffer, "XactSrv: Xactsrv Time: %ld milliseconds (%ld)\n", XsTime.LowPart/10000, XsTime.HighPart);
|
|
|
|
I_BrowserDebugTrace(NULL, Buffer);
|
|
}
|
|
|
|
transaction->XactSrvTime = XactSrvEndTime;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
} // XsProcessApis
|
|
|
|
|
|
|
|
VOID
|
|
ConvertApiStatusToDosStatus(
|
|
LPXS_PARAMETER_HEADER Header
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts an api return status to status expected by
|
|
downlevel.
|
|
|
|
Arguments:
|
|
|
|
Header - structure containing the status.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
WORD dosStatus;
|
|
|
|
switch ( Header->Status ) {
|
|
case ERROR_SPECIAL_ACCOUNT:
|
|
case ERROR_SPECIAL_GROUP:
|
|
case ERROR_SPECIAL_USER:
|
|
case ERROR_INVALID_LOGON_TYPE:
|
|
dosStatus = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
|
|
case ERROR_DEPENDENT_SERVICES_RUNNING:
|
|
dosStatus = NERR_ServiceCtlNotValid;
|
|
break;
|
|
|
|
case ERROR_INVALID_DOMAINNAME:
|
|
dosStatus = NERR_NotLocalDomain;
|
|
break;
|
|
|
|
case ERROR_NO_SUCH_USER:
|
|
dosStatus = NERR_UserNotFound;
|
|
break;
|
|
|
|
case ERROR_ALIAS_EXISTS:
|
|
dosStatus = NERR_GroupExists;
|
|
break;
|
|
|
|
case NERR_BadServiceName:
|
|
dosStatus = NERR_ServiceNotInstalled;
|
|
break;
|
|
|
|
case ERROR_ILL_FORMED_PASSWORD:
|
|
case NERR_PasswordTooRecent:
|
|
dosStatus = ERROR_INVALID_PASSWORD;
|
|
break;
|
|
|
|
case ERROR_PASSWORD_RESTRICTION:
|
|
dosStatus = NERR_PasswordHistConflict;
|
|
break;
|
|
|
|
case ERROR_ACCOUNT_RESTRICTION:
|
|
dosStatus = NERR_PasswordTooRecent;
|
|
break;
|
|
|
|
case ERROR_PASSWORD_EXPIRED:
|
|
case ERROR_PASSWORD_MUST_CHANGE:
|
|
dosStatus = NERR_PasswordExpired;
|
|
break;
|
|
|
|
case ERROR_INVALID_PRINTER_NAME:
|
|
dosStatus = NERR_QNotFound;
|
|
break;
|
|
|
|
case ERROR_NO_BROWSER_SERVERS_FOUND:
|
|
|
|
//
|
|
// Down level clients don't understand how to deal with
|
|
// the "No browser server" error, so we turn it into success.
|
|
//
|
|
// This seems wrong to me, but it is what WfW does in the
|
|
// same circumstance.
|
|
//
|
|
|
|
if ( !(Header->Flags & XS_FLAGS_NT_CLIENT) ) {
|
|
dosStatus = NERR_Success;
|
|
} else {
|
|
dosStatus = Header->Status;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// make sure it's a valid lm error code
|
|
//
|
|
|
|
if ( (Header->Status > ERROR_VC_DISCONNECTED) &&
|
|
((Header->Status < NERR_BASE) ||
|
|
(Header->Status > MAX_NERR)) ) {
|
|
|
|
NTSTATUS status;
|
|
LPWSTR substring[1];
|
|
WCHAR errorString[10];
|
|
UNICODE_STRING unicodeString;
|
|
|
|
substring[0] = errorString;
|
|
unicodeString.MaximumLength = 10 * sizeof(WCHAR);
|
|
unicodeString.Buffer = errorString;
|
|
|
|
status = RtlIntegerToUnicodeString(
|
|
(ULONG) Header->Status,
|
|
10,
|
|
&unicodeString
|
|
);
|
|
|
|
if ( NT_SUCCESS( status ) ) {
|
|
SsLogEvent(
|
|
EVENT_SRV_CANT_MAP_ERROR,
|
|
1,
|
|
substring,
|
|
NO_ERROR
|
|
);
|
|
}
|
|
|
|
dosStatus = ERROR_UNEXP_NET_ERR;
|
|
SS_PRINT(( "srvsvc: unmapped error %d from xactsrv.\n",
|
|
Header->Status )) ;
|
|
|
|
} else {
|
|
|
|
//
|
|
// No change
|
|
//
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
Header->Status = dosStatus;
|
|
return;
|
|
|
|
} // ConvertApiStatusToDosStatus
|
|
|