windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/srvsvc/server/srvinfo.c

676 lines
16 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991-1992 Microsoft Corporation
Module Name:
SrvInfo.c
Abstract:
This module contains support for the server get and set info APIs
in the server service.
Author:
David Treadwell (davidtr) 7-Mar-1991
Revision History:
--*/
#include "srvsvcp.h"
#include "ssreg.h"
#include <netlibnt.h>
#include <tstr.h>
#include <lmerr.h>
NET_API_STATUS NET_API_FUNCTION
NetrServerGetInfo (
IN LPWSTR ServerName,
IN DWORD Level,
OUT LPSERVER_INFO InfoStruct
)
/*++
Routine Description:
This routine uses the server parameters stored in the server service
to return the server information.
Arguments:
None.
Return Value:
NET_API_STATUS - NO_ERROR or reason for failure.
--*/
{
ULONG outputBufferLength;
NET_API_STATUS error;
ACCESS_MASK desiredAccess;
LPWSTR DomainName;
PNAME_LIST_ENTRY service;
PTRANSPORT_LIST_ENTRY transport;
UCHAR serverNameBuf[ MAX_PATH ];
UNICODE_STRING ServerNameUnicode;
NTSTATUS status;
ULONG namelen;
//
// Determine the access required for the requested level of
// information.
//
switch ( Level ) {
case 100:
case 101:
desiredAccess = SRVSVC_CONFIG_USER_INFO_GET;
break;
case 102:
case 502:
desiredAccess = SRVSVC_CONFIG_POWER_INFO_GET;
break;
case 503:
desiredAccess = SRVSVC_CONFIG_ADMIN_INFO_GET;
break;
default:
return ERROR_INVALID_LEVEL;
}
//
// Make sure that the caller has that level of access.
//
error = SsCheckAccess(
&SsConfigInfoSecurityObject,
desiredAccess
);
if ( error != NO_ERROR ) {
return ERROR_ACCESS_DENIED;
}
//
// Acquire the resource that protects server information. Since
// we'll only read the information, get shared access to the
// resource.
//
(VOID)RtlAcquireResourceShared( &SsData.SsServerInfoResource, TRUE );
if( ServerName == NULL ) {
ServerName = SsData.ServerNameBuffer;
}
//
// Convert the server name
//
if( ServerName[0] == L'\\' && ServerName[1] == L'\\' ) {
ServerName += 2;
}
RtlInitUnicodeString( &ServerNameUnicode, ServerName );
error = ConvertStringToTransportAddress( &ServerNameUnicode, serverNameBuf, &namelen );
if( error != NERR_Success ) {
RtlReleaseResource( &SsData.SsServerInfoResource );
return error;
}
//
// Look for the NAME_LIST_ENTRY entry that represents the name of the server
// the client referred to.
//
DomainName = SsData.DomainNameBuffer;
for( service = SsData.SsServerNameList; service != NULL; service = service->Next ) {
if( service->TransportAddressLength != namelen ) {
continue;
}
if( RtlEqualMemory( serverNameBuf, service->TransportAddress, namelen ) ) {
DomainName = service->DomainName;
break;
}
}
//
// If we didn't find an entry, find and use the primary entry
//
if( service == NULL ) {
for( service = SsData.SsServerNameList; service != NULL; service = service->Next ) {
if( service->PrimaryName ) {
DomainName = service->DomainName;
break;
}
}
}
//
// Use the level parameter to determine how much space to allocate
// and how to fill it in.
//
switch ( Level ) {
case 100: {
PSERVER_INFO_100 sv100;
//
// All we copy is the server name.
//
outputBufferLength = sizeof(SERVER_INFO_100) +
STRSIZE( ServerName);
sv100 = MIDL_user_allocate( outputBufferLength );
if ( sv100 == NULL ) {
RtlReleaseResource( &SsData.SsServerInfoResource );
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Copy over the fixed portion of the buffer.
//
RtlCopyMemory( sv100, &SsData.ServerInfo102, sizeof(SERVER_INFO_100) );
//
// Set up the name string.
//
sv100->sv100_name = (LPWSTR)( sv100 + 1 );
STRCPY( sv100->sv100_name, ServerName );
//
// Set up the output buffer pointer.
//
InfoStruct->ServerInfo100 = sv100;
break;
}
case 101: {
PSERVER_INFO_101 sv101;
//
// All we copy is the server name.
//
outputBufferLength = sizeof(SERVER_INFO_101) +
STRSIZE( ServerName ) +
STRSIZE( SsData.ServerCommentBuffer ) ;
sv101 = MIDL_user_allocate( outputBufferLength );
if ( sv101 == NULL ) {
RtlReleaseResource( &SsData.SsServerInfoResource );
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Copy over the fixed portion of the buffer.
//
RtlCopyMemory( sv101, &SsData.ServerInfo102, sizeof(SERVER_INFO_101) );
if( service != NULL ) {
sv101->sv101_type = service->ServiceBits;
for( transport = service->Transports; transport; transport = transport->Next ) {
sv101->sv101_type |= transport->ServiceBits;
}
} else {
//
// If there are no transports,
// return the global information.
//
sv101->sv101_type = SsGetServerType();
}
//
// Set up the variable portion of the buffer.
//
sv101->sv101_name = (LPWSTR)( sv101 + 1 );
STRCPY( sv101->sv101_name, ServerName );
sv101->sv101_comment = (LPWSTR)( (PCHAR)sv101->sv101_name +
STRSIZE( ServerName ));
STRCPY( sv101->sv101_comment, SsData.ServerCommentBuffer );
//
// Set up the output buffer pointer.
//
InfoStruct->ServerInfo101 = sv101;
break;
}
case 102: {
PSERVER_INFO_102 sv102;
//
// We copy the server name, server comment, and user path
// buffer.
//
outputBufferLength = sizeof(SERVER_INFO_102) +
STRSIZE( ServerName ) +
STRSIZE( SsData.ServerCommentBuffer ) +
STRSIZE( SsData.UserPathBuffer ) ;
sv102 = MIDL_user_allocate( outputBufferLength );
if ( sv102 == NULL ) {
RtlReleaseResource( &SsData.SsServerInfoResource );
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Copy over the fixed portion of the buffer.
//
RtlCopyMemory( sv102, &SsData.ServerInfo102, sizeof(SERVER_INFO_102) );
if( service != NULL ) {
sv102->sv102_type = service->ServiceBits;
for( transport = service->Transports; transport; transport = transport->Next ) {
sv102->sv102_type |= transport->ServiceBits;
}
} else {
//
// If there are no transports,
// return the global information.
//
sv102->sv102_type = SsGetServerType();
}
//
// Set up the server name.
//
sv102->sv102_name = (LPWSTR)( sv102 + 1 );
STRCPY( sv102->sv102_name, ServerName );
//
// Set up the server comment.
//
sv102->sv102_comment = (LPWSTR)( (PCHAR)sv102->sv102_name + STRSIZE( ServerName ));
STRCPY( sv102->sv102_comment, SsData.ServerCommentBuffer );
//
// Set up the user path.
//
sv102->sv102_userpath = (LPWSTR)( (PCHAR)sv102->sv102_comment +
STRSIZE( sv102->sv102_comment ) );
STRCPY( sv102->sv102_userpath, SsData.UserPathBuffer );
//
// Set up the output buffer pointer.
//
InfoStruct->ServerInfo102 = sv102;
break;
}
case 502:
//
// Allocate enough space to hold the fixed structure. This level has
// no variable structure.
//
InfoStruct->ServerInfo502 = MIDL_user_allocate( sizeof(SERVER_INFO_502) );
if ( InfoStruct->ServerInfo502 == NULL ) {
RtlReleaseResource( &SsData.SsServerInfoResource );
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Copy the data from the server service buffer to the user buffer.
//
RtlCopyMemory(
InfoStruct->ServerInfo502,
&SsData.ServerInfo599,
sizeof(SERVER_INFO_502)
);
break;
case 503: {
PSERVER_INFO_503 sv503;
outputBufferLength = sizeof( *sv503 ) + STRSIZE( DomainName );
sv503 = MIDL_user_allocate( outputBufferLength );
if ( sv503 == NULL ) {
RtlReleaseResource( &SsData.SsServerInfoResource );
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Copy the data from the server service buffer to the user buffer.
//
RtlCopyMemory( sv503, &SsData.ServerInfo599, sizeof( *sv503 ) );
//
// Copy the domain name
//
sv503->sv503_domain = (LPWSTR)( sv503 + 1 );
STRCPY( sv503->sv503_domain, DomainName );
InfoStruct->ServerInfo503 = sv503;
break;
}
default:
RtlReleaseResource( &SsData.SsServerInfoResource );
return ERROR_INVALID_LEVEL;
}
RtlReleaseResource( &SsData.SsServerInfoResource );
return NO_ERROR;
} // NetrServerGetInfo
NET_API_STATUS NET_API_FUNCTION
NetrServerSetInfo (
IN LPWSTR ServerName,
IN DWORD Level,
IN LPSERVER_INFO InfoStruct,
OUT LPDWORD ErrorParameter OPTIONAL
)
/*++
Routine Description:
This routine sets information in the server service and server.
Arguments:
None.
Return Value:
NET_API_STATUS - NO_ERROR or reason for failure.
--*/
{
NET_API_STATUS error;
ULONG i;
LONG parmnum;
BOOLEAN validLevel = FALSE;
PSERVER_REQUEST_PACKET srp;
LPBYTE buffer = (LPBYTE)InfoStruct->ServerInfo100;
BOOLEAN announcementInformationChanged = FALSE;
ServerName;
//
// Check that user input buffer is not NULL
//
if (buffer == NULL) {
if ( ARGUMENT_PRESENT( ErrorParameter ) ) {
*ErrorParameter = PARM_ERROR_UNKNOWN;
}
return ERROR_INVALID_PARAMETER;
}
parmnum = (LONG)(Level - PARMNUM_BASE_INFOLEVEL);
if ( ARGUMENT_PRESENT( ErrorParameter ) ) {
*ErrorParameter = parmnum;
}
//
// Make sure that the caller is allowed to set information in the
// server.
//
error = SsCheckAccess(
&SsConfigInfoSecurityObject,
SRVSVC_CONFIG_INFO_SET
);
if ( error != NO_ERROR ) {
return ERROR_ACCESS_DENIED;
}
//
// Acquire the resource that protects server information. Since
// we're going to be writing to the information, we need exclusive
// access to the reqource.
//
//
// If a parameter number was specified, set that one field.
//
if ( parmnum >= 0 ) {
//
// Walk through the field descriptors looking for an
// equivalent parameter number.
//
for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
if ( (ULONG)parmnum == SsServerInfoFields[i].ParameterNumber ) {
//
// Verify that the field is settable.
//
// !!! We should also reject levels above 502?
//
if ( SsServerInfoFields[i].Settable != ALWAYS_SETTABLE ) {
return ERROR_INVALID_LEVEL;
}
(VOID)RtlAcquireResourceExclusive( &SsData.SsServerInfoResource, TRUE );
//
// Set the field.
//
error = SsSetField(
&SsServerInfoFields[i],
buffer,
TRUE,
&announcementInformationChanged
);
RtlReleaseResource( &SsData.SsServerInfoResource );
//
// If a relevant parameter changed, call
// SsSetExportedServerType. This will cause an
// announcement to be sent.
//
if ( announcementInformationChanged ) {
SsSetExportedServerType( NULL, TRUE, TRUE );
}
return error;
}
}
//
// If a match had been found we would have returned by now.
// Indicate that the parameter number was illegal.
//
return ERROR_INVALID_LEVEL;
}
//
// A full input structure was specified. Walk through all the
// server data field descriptors, looking for fields that should be
// set.
//
for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
ULONG fieldLevel;
//
// We need to set this field if:
//
// o the level specified on input is the same order as the
// level of the field. They have the same order if
// they are in the same century (e.g. 101 and 102 are
// in the same order); AND
//
// o the specified level is greater than or equal to the
// level of the field. For example, if the input
// level is 101 and the field level is 102, don't set
// the field. If the input level is 102 and the field
// level is 101, set it; AND
//
// o the field is settable. If the field is not settable
// by NetServerSetInfo, just ignore the value in the
// input structure.
//
// Note that level 598 doesn't follow the first rule above. It
// is NOT a superset of 50x, and it is NOT a subset of 599.
//
fieldLevel = SsServerInfoFields[i].Level;
if ( Level / 100 == fieldLevel / 100 &&
((fieldLevel != 598) && (Level >= fieldLevel) ||
(fieldLevel == 598) && (Level == 598)) &&
SsServerInfoFields[i].Settable == ALWAYS_SETTABLE ) {
//
// We found a match, so the specified level number must have
// been valid.
//
// !!! Reject levels above 502?
validLevel = TRUE;
//
// Set this field.
//
(VOID)RtlAcquireResourceExclusive( &SsData.SsServerInfoResource, TRUE );
error = SsSetField(
&SsServerInfoFields[i],
buffer + SsServerInfoFields[i].FieldOffset,
TRUE,
&announcementInformationChanged
);
RtlReleaseResource( &SsData.SsServerInfoResource );
if ( error != NO_ERROR ) {
//
// Set the parameter in error if we need to.
//
if ( ARGUMENT_PRESENT(ErrorParameter) ) {
*ErrorParameter = SsServerInfoFields[i].ParameterNumber;
}
return error;
}
}
}
//
// If no match was ever found, then an invalid level was passed in.
//
if ( !validLevel ) {
return ERROR_INVALID_LEVEL;
}
//
// Get an SRP and set it up with the appropriate level.
//
srp = SsAllocateSrp( );
if ( srp == NULL ) {
return ERROR_NOT_ENOUGH_MEMORY;
}
srp->Level = 0xFFFFFFFF;
(VOID)RtlAcquireResourceShared( &SsData.SsServerInfoResource, TRUE );
//
// Send the request on to the server.
//
error = SsServerFsControl(
FSCTL_SRV_NET_SERVER_SET_INFO,
srp,
&SsData.ServerInfo102,
sizeof(SERVER_INFO_102) + sizeof(SERVER_INFO_599) +
sizeof(SERVER_INFO_598)
);
//
// Release the resource and free the SRP.
//
RtlReleaseResource( &SsData.SsServerInfoResource );
SsFreeSrp( srp );
//
// If a relevant parameter changed, call SsSetExportedServerType.
// This will cause an announcement to be sent.
//
if ( announcementInformationChanged ) {
SsSetExportedServerType( NULL, TRUE, TRUE );
}
return error;
} // NetrServerSetInfo