Example #1
0
NET_API_STATUS RplCreateSecurityObject( VOID)
/*++

Routine Description:

    This function creates the remote bootr user-mode configuration
    information object which is represented by a security descriptors.

Arguments:

    None.

Return Value:

    NET_API_STATUS code

--*/
{
    NTSTATUS        status;

    //
    //  Order matters!  These ACEs are inserted into the DACL in the
    //  following order.  Security access is granted or denied based on
    //  the order of the ACEs in the DACL.
    // 
    //  LocalGroupAdmins are fow now allowed to perform all remote boot
    //  Service operations.  Everybody else is denied.
    //

    ACE_DATA    aceData[] = {
        {ACCESS_ALLOWED_ACE_TYPE, 0, 0, GENERIC_ALL, &AliasAdminsSid}
    };


    status = NetpCreateSecurityObject(
            aceData,                                //  pAceData
            sizeof(aceData) / sizeof(aceData[0]),   //  countAceData
            NULL,                                   //  OwnerSid
            NULL,                                   //  PrimaryGroupSid
            &RG_SecurityMapping,                    //  GenericToSpecificMapping
            &RG_SecurityDescriptor                  //  ppNewDescriptor
            );

    if ( ! NT_SUCCESS (status)) {
        RplDump( ++RG_Assert, ( "status = 0x%x", status));
        return NetpNtStatusToApiStatus( status);
    }

    return( NO_ERROR);
}
Example #2
0
File: tod.c Project: mingpen/OpenNT
NET_API_STATUS
NetrRemoteTOD (
    IN        LPSTR                    ServerName,
    OUT LPTIME_OF_DAY_INFO  *lpTimeOfDayInfo
    )

/*++

Routine Description:

  This is the RPC server entry point for the NetRemoteTOD API.

Arguments:

    ServerName            - Name of server on which this API is to be executed.
                      It should match this server's name - no checking is
                      done since it is assumed that RPC did the right thing.

    lpTimeOfDayInfo - On return takes a pointer to a TIME_OF_DAY_INFO
                      structure - the memory is allocated here.


Return Value:

    Returns a NET_API_STATUS code.
    Also returns a pointer to the TIME_OF_DAY_INFO data buffer that was
    allocated, if there is no error.


--*/
{
    NTSTATUS status;

    //
    // Call the worker routine to collect all the time/date information
    //
    status = timesvc_RemoteTimeOfDay(lpTimeOfDayInfo);

    //
    // Translate the NTSTATUS to a NET_API_STATUS error, and return it.
    //

    return(NetpNtStatusToApiStatus(status));

    UNREFERENCED_PARAMETER( ServerName );
}
Example #3
0
VOID
ServeAdd(
    IN PSZ TransportName
    )
/*++

Routine Description:

    This function binds a TransportName to the server

Arguments:

    TransportName - The name of the transport

Return Value:

    None.

--*/
{

    NTSTATUS status;

    start_autostart(txt_SERVICE_FILE_SRV);

    status = NetLocalAddServedNet(TransportName,NULL);
    if ( NT_SUCCESS(status) ) {
	InfoSuccess();
    }
    else {
	ErrorExit(LOWORD(NetpNtStatusToApiStatus(status)));
    }

    return;

}
Example #4
0
VOID
ServeDisplay(
    VOID
    )
/*++

Routine Description:

    This function displays all the transports bound to the server.

Arguments:

    None.

Return Value:

    None.

--*/
{

    NTSTATUS status;

    start_autostart(txt_SERVICE_FILE_SRV);

    status = NetLocalEnumerateServedNets(NULL);
    if ( NT_SUCCESS(status) ) {
	InfoSuccess();
    }
    else {
	ErrorExit(LOWORD(NetpNtStatusToApiStatus(status)));
    }

    return;

}
Example #5
0
NET_API_STATUS
ReplDeleteFile(
    IN LPCTSTR FileName
    )
{
    NET_API_STATUS    ApiStatus;
#ifdef USE_BACKUP_APIS
    HANDLE            FileHandle = INVALID_HANDLE_VALUE;
    IO_STATUS_BLOCK   IoStatusBlock;

    const ACCESS_MASK MyAccessDesired =
                          ( DELETE
                          | FILE_READ_ATTRIBUTES
                          | FILE_READ_DATA
                          | FILE_READ_EA
                          | FILE_TRAVERSE
                          | SYNCHRONIZE
                          );

    const ULONG       MyOpenOptions =
                           FILE_SYNCHRONOUS_IO_NONALERT
                         | FILE_DELETE_ON_CLOSE
                         | FILE_OPEN_FOR_BACKUP_INTENT
                         ;

    const ULONG       MyShareAccess =
                          FILE_SHARE_READ;  // BUGBUG
//                        FILE_SHARE_DELETE;

    NTSTATUS          NtStatus;
    OBJECT_ATTRIBUTES ObjectAttributes;
    BOOL              PathAllocated = FALSE;
    UNICODE_STRING    UnicodePath;
#endif

    //
    // Check for caller errors.
    //

    if ( (FileName==NULL) || ((*FileName)==TCHAR_EOS) ) {
        ApiStatus = ERROR_INVALID_PARAMETER;
        goto Cleanup;
    }

    //
    // Tell the world what we're going to do.
    //

    IF_DEBUG( REPL ) {
        NetpKdPrint(( PREFIX_REPL
                "ReplDeleteFile: *** DELETING FILE *** '" FORMAT_LPTSTR "'.\n",
                FileName ));
    }

    //
    // return no error if the file does not exist.
    //
    if ( !ReplFileOrDirExists( FileName ) ) {
        return( NO_ERROR );
    }

#ifndef USE_BACKUP_APIS

    //
    // If the file system ACL allows us to delete, we can just
    // use the Win32 APIs for this.
    //

    if ( ! DeleteFile( (LPTSTR) FileName ) ) {
       ApiStatus = (NET_API_STATUS) GetLastError();
    } else {
       ApiStatus = NO_ERROR;
    }

#else

    //
    // It turns out that "backup semantics" is very powerful.  It allows
    // us to create files in directories which have read-only ACLs.
    // Unfortunately, there isn't a "backup semantics" flag for DeleteFile(),
    // so we need to use the NT APIs to get the same effect.
    //

    //
    // Convert file name to NT style.
    //

    RtlInitUnicodeString(
            & UnicodePath,              // output: struct
            FileName );                 // input: null terminated

    if( !RtlDosPathNameToNtPathName_U(
                            FileName,
                            &UnicodePath,
                            NULL,
                            NULL) ) {

        NetpKdPrint(( PREFIX_REPL_CLIENT
                "ReplDeleteFile: RtlDosPathNameToNtPathname_U"
                " of file '" FORMAT_LPTSTR "' failed.\n", FileName ));

        // BUGBUG: this is just our best guess for an error code this.
        ApiStatus = ERROR_INVALID_PARAMETER;
        goto Cleanup;
    }
    NetpAssert( UnicodePath.Buffer != NULL );
    PathAllocated = TRUE;

    InitializeObjectAttributes(
            &ObjectAttributes,
            (LPVOID) &UnicodePath,
            OBJ_CASE_INSENSITIVE,
            NULL,
            NULL );

    //
    // Open the file, with backup semantics and delete on close.
    //

    NtStatus = NtOpenFile(
            & FileHandle,
            MyAccessDesired,
            &ObjectAttributes,
            &IoStatusBlock,
            MyShareAccess,
            MyOpenOptions );

    if ( !NT_SUCCESS( NtStatus ) ) {

        NetpKdPrint(( PREFIX_REPL_CLIENT
                "ReplDeleteFile: NtOpenFile of file '"
                FORMAT_LPTSTR "' gave NT status " FORMAT_NTSTATUS ".\n",
                FileName, NtStatus ));

        ApiStatus = NetpNtStatusToApiStatus( NtStatus );
        NetpAssert( ApiStatus != NO_ERROR );
        goto Cleanup;
    }
    NetpAssert( NtStatus == STATUS_SUCCESS );
    NetpAssert( FileHandle != INVALID_HANDLE_VALUE );

    //
    // Close the file, which will delete it since we gave the
    // FILE_CLOSE_ON_DELETE flag.
    //

    NtStatus = NtClose( FileHandle );
    FileHandle = INVALID_HANDLE_VALUE;

    if ( !NT_SUCCESS( NtStatus ) ) {

        NetpKdPrint(( PREFIX_REPL_CLIENT
                "ReplDeleteFile: NtClose failed, "
                " NT status is " FORMAT_NTSTATUS
                ".\n", NtStatus ));

        ApiStatus = NetpNtStatusToApiStatus( NtStatus );
        NetpAssert( ApiStatus != NO_ERROR );
        goto Cleanup;
    }
    NetpAssert( NtStatus == STATUS_SUCCESS );

    (void) NtClose( FileHandle );
    FileHandle = INVALID_HANDLE_VALUE;

    (VOID) RtlFreeHeap( RtlProcessHeap(), 0, UnicodePath.Buffer );
    PathAllocated = FALSE;

    ApiStatus = NO_ERROR;

#endif


Cleanup:

    if (ApiStatus != NO_ERROR) {

        NetpKdPrint(( PREFIX_REPL
                "ReplDeleteFile: ERROR " FORMAT_API_STATUS ".\n",
                ApiStatus ));

        //
        // Log the error.
        // BUGBUG: extract master server name and log there too.
        //
        ReplErrorLog(
                NULL,             // no server name (log locally)
                NELOG_ReplSysErr, // log code
                ApiStatus,
                NULL,             // optional str1
                NULL);            // optional str2
    }

#ifdef USE_BACKUP_APIS
    if (FileHandle != INVALID_HANDLE_VALUE) {
        (VOID) NtClose( FileHandle );
    }

    if (PathAllocated) {
        (VOID) RtlFreeHeap( RtlProcessHeap(), 0, UnicodePath.Buffer );
    }
#endif

    return (ApiStatus);

}
Example #6
0
STATIC
NET_API_STATUS
AlInitializeAlerter(
    VOID
    )
/*++

Routine Description:

    This routine initializes the Alerter service.

Arguments:

    AlInitState - Returns a flag to indicate how far we got with initializing
        the Alerter service before an error occured.

Return Value:

    NET_API_STATUS - NERR_Success or reason for failure.

--*/
{
    NET_API_STATUS status;
    NTSTATUS ntstatus;
    PSECURITY_DESCRIPTOR Sd;
    SECURITY_ATTRIBUTES Sa;
    ACE_DATA AceData[1] = {
        {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
               GENERIC_READ | GENERIC_WRITE, &AlLmsvcsGlobalData->WorldSid}
        };



    AlGlobalData.MailslotHandle = (HANDLE) MAXULONG;

    //
    // Initialize Alerter to receive service requests by registering the
    // control handler.
    //
    if ((AlGlobalData.StatusHandle = RegisterServiceCtrlHandler(
                                         SERVICE_ALERTER,
                                         AlerterControlHandler
                                         )) == (SERVICE_STATUS_HANDLE) NULL) {

        status = GetLastError();
        AlHandleError(AlErrorRegisterControlHandler, status, NULL);
        return status;
    }

    //
    // Initialize all the status fields so that subsequent calls to
    // SetServiceStatus need to only update fields that changed.
    //
    AlGlobalData.Status.dwServiceType      = SERVICE_WIN32;
    AlGlobalData.Status.dwCurrentState     = SERVICE_START_PENDING;
    AlGlobalData.Status.dwControlsAccepted = 0;
    AlGlobalData.Status.dwCheckPoint       = 1;
    AlGlobalData.Status.dwWaitHint         = 10000;  // 10 secs

    SET_SERVICE_EXITCODE(
        NO_ERROR,
        AlGlobalData.Status.dwWin32ExitCode,
        AlGlobalData.Status.dwServiceSpecificExitCode
        );

    //
    // Tell the Service Controller that we are start-pending
    //
    if ((status = AlUpdateStatus()) != NERR_Success) {

        AlHandleError(AlErrorNotifyServiceController, status, NULL);
        return status;
    }

    //
    // Get the configured alert names
    //
    if ((status = AlGetAlerterConfiguration()) != NERR_Success) {

        AlHandleError(AlErrorGetComputerName, status, NULL);
        return status;
    }

    //
    // Create the security descriptor for the security attributes structure
    //
    ntstatus = NetpCreateSecurityDescriptor(
                   AceData,
                   1,
                   AlLmsvcsGlobalData->LocalSystemSid,
                   AlLmsvcsGlobalData->LocalSystemSid,
                   &Sd
                   );

    if (! NT_SUCCESS(ntstatus)) {
        status = NetpNtStatusToApiStatus(ntstatus);
        AlHandleError(AlErrorCreateMailslot, status, NULL);
        return status;
    }

    Sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    Sa.lpSecurityDescriptor = Sd;
    Sa.bInheritHandle = FALSE;

    //
    // Create mailslot to listen on alert notifications from the Server
    // service and the Spooler.
    //
    AlGlobalData.MailslotHandle = CreateMailslot(
                                      ALERTER_MAILSLOT,
                                      MAX_MAILSLOT_MESSAGE_SIZE,
                                      MAILSLOT_WAIT_FOREVER,
                                      &Sa
                                      );

    NetpMemoryFree(Sd);

    if (AlGlobalData.MailslotHandle == (HANDLE) MAXULONG) {
        status = GetLastError();
        AlHandleError(AlErrorCreateMailslot, status, NULL);
        return status;
    }
    else {
        IF_DEBUG(MAIN) {
            NetpKdPrint(("Mailslot %ws created, handle=x%08lx\n",
                         ALERTER_MAILSLOT, AlGlobalData.MailslotHandle));
        }
    }

    //
    // Tell the Service Controller that we are started.
    //
    AlGlobalData.Status.dwCurrentState     = SERVICE_RUNNING;
    AlGlobalData.Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    AlGlobalData.Status.dwCheckPoint       = 0;
    AlGlobalData.Status.dwWaitHint         = 0;

    if ((status = AlUpdateStatus()) != NERR_Success) {

        AlHandleError(AlErrorNotifyServiceController, status, NULL);
        return status;
    }

    IF_DEBUG(MAIN) {
        NetpKdPrint(("[Alerter] Successful Initialization\n"));
    }

    return NERR_Success;
}
Example #7
0
NET_API_STATUS
WINAPI
NetQueryDisplayInformation(
    _In_ LPCWSTR ServerName,
    _In_ DWORD Level,
    _In_ DWORD Index,
    _In_ DWORD EntriesRequested,
    _In_ DWORD PreferredMaximumLength,
    _Out_ LPDWORD ReturnedEntryCount,
    _Out_ PVOID *SortedBuffer)
{
    UNICODE_STRING ServerNameString;
    SAM_HANDLE ServerHandle = NULL;
    SAM_HANDLE DomainHandle = NULL;
    DOMAIN_DISPLAY_INFORMATION DisplayInformation;
    DWORD LocalTotalBytesAvailable;
    DWORD LocalTotalBytesReturned;
    DWORD LocalReturnedEntryCount;
    PVOID LocalSortedBuffer;
    NET_API_STATUS ApiStatus = NERR_Success;
    NTSTATUS Status;

    TRACE("NetQueryDisplayInformation(%s, %ld, %ld, %ld, %ld, %p, %p)\n",
          debugstr_w(ServerName), Level, Index, EntriesRequested,
          PreferredMaximumLength, ReturnedEntryCount, SortedBuffer);

    *ReturnedEntryCount = 0;
    *SortedBuffer = NULL;

    switch (Level)
    {
        case 1:
            DisplayInformation = DomainDisplayUser;
            break;

        case 2:
            DisplayInformation = DomainDisplayMachine;
            break;

        case 3:
            DisplayInformation = DomainDisplayGroup;
            break;

        default:
            return ERROR_INVALID_LEVEL;
    }

    if (ServerName != NULL)
        RtlInitUnicodeString(&ServerNameString, ServerName);

    /* Connect to the SAM Server */
    Status = SamConnect((ServerName != NULL) ? &ServerNameString : NULL,
                        &ServerHandle,
                        SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
                        NULL);
    if (!NT_SUCCESS(Status))
    {
        ERR("SamConnect failed (Status %08lx)\n", Status);
        ApiStatus = NetpNtStatusToApiStatus(Status);
        goto done;
    }

    /* Open the Account Domain */
    Status = OpenAccountDomain(ServerHandle,
                               (ServerName != NULL) ? &ServerNameString : NULL,
                               DOMAIN_LIST_ACCOUNTS,
                               &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
        ApiStatus = NetpNtStatusToApiStatus(Status);
        goto done;
    }

    /* Query the information */
    Status = SamQueryDisplayInformation(DomainHandle,
                                        DisplayInformation,
                                        Index,
                                        EntriesRequested,
                                        PreferredMaximumLength,
                                        &LocalTotalBytesAvailable,
                                        &LocalTotalBytesReturned,
                                        &LocalReturnedEntryCount,
                                        &LocalSortedBuffer);
    if (!NT_SUCCESS(Status))
    {
        ERR("SamQueryDisplayInformation failed (Status %08lx)\n", Status);
        ApiStatus = NetpNtStatusToApiStatus(Status);
        goto done;
    }

    /* FIXME */

done:
    if (DomainHandle != NULL)
        SamCloseHandle(DomainHandle);

    if (ServerHandle != NULL)
        SamCloseHandle(ServerHandle);

    return ApiStatus;
}
Example #8
0
NET_API_STATUS
WINAPI
NetGetDisplayInformationIndex(
    _In_ LPCWSTR ServerName,
    _In_ DWORD Level,
    _In_ LPCWSTR Prefix,
    _Out_ LPDWORD Index)
{
    UNICODE_STRING ServerNameString, PrefixString;
    SAM_HANDLE ServerHandle = NULL;
    SAM_HANDLE DomainHandle = NULL;
    DOMAIN_DISPLAY_INFORMATION DisplayInformation;
    NET_API_STATUS ApiStatus = NERR_Success;
    NTSTATUS Status;

    TRACE("NetGetDisplayInformationIndex(%s %ld %s %p)\n",
          debugstr_w(ServerName), Level, debugstr_w(Prefix), Index);

    switch (Level)
    {
        case 1:
            DisplayInformation = DomainDisplayUser;
            break;

        case 2:
            DisplayInformation = DomainDisplayMachine;
            break;

        case 3:
            DisplayInformation = DomainDisplayGroup;
            break;

        default:
            return ERROR_INVALID_LEVEL;
    }

    if (ServerName != NULL)
        RtlInitUnicodeString(&ServerNameString, ServerName);

    /* Connect to the SAM Server */
    Status = SamConnect((ServerName != NULL) ? &ServerNameString : NULL,
                        &ServerHandle,
                        SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
                        NULL);
    if (!NT_SUCCESS(Status))
    {
        ERR("SamConnect failed (Status %08lx)\n", Status);
        ApiStatus = NetpNtStatusToApiStatus(Status);
        goto done;
    }

    /* Open the Account Domain */
    Status = OpenAccountDomain(ServerHandle,
                               (ServerName != NULL) ? &ServerNameString : NULL,
                               DOMAIN_LIST_ACCOUNTS,
                               &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
        ApiStatus = NetpNtStatusToApiStatus(Status);
        goto done;
    }

    RtlInitUnicodeString(&PrefixString, Prefix);

    /* Get the index */
    Status = SamGetDisplayEnumerationIndex(DomainHandle,
                                           DisplayInformation,
                                           &PrefixString,
                                           Index);
    if (!NT_SUCCESS(Status))
    {
        ERR("SamGetDisplayEnumerationIndex failed (Status %08lx)\n", Status);
        ApiStatus = NetpNtStatusToApiStatus(Status);
    }

done:
    if (DomainHandle != NULL)
        SamCloseHandle(DomainHandle);

    if (ServerHandle != NULL)
        SamCloseHandle(ServerHandle);

    return ApiStatus;
}
Example #9
0
NET_API_STATUS
NetpRdrFsControlTree(
    IN LPTSTR TreeName,
    IN LPTSTR TransportName OPTIONAL,
    IN DWORD ConnectionType,
    IN DWORD FsControlCode,
    IN LPVOID SecurityDescriptor OPTIONAL,
    IN LPVOID InputBuffer OPTIONAL,
    IN DWORD InputBufferSize,
    OUT LPVOID OutputBuffer OPTIONAL,
    IN DWORD OutputBufferSize,
    IN BOOL NoPermissionRequired
    )

/*++

Routine Description:

    NetpRdrFsControlTree performs a given FSCTL (file system control)
    on a given tree connection name.

Arguments:

    TreeName - Remote name to do fsctl to (in \\server\share format).

    FsControlCode - function code to pass to the redirector.  These are
        defined in <ntddnfs.h>.

    SecurityDescriptor - optionally points to a security descriptor to be
        used when creating the tree connection.

    InputBuffer - optionally points to a structure to be passed to the
        redirector.

    InputBufferSize - size of InputBuffer in bytes; must be zero if
        InputBuffer is a NULL pointer.

    OutputBuffer - optionally points to a structure to be filled in by the
        redirector.

    OutputBufferSize - size of OutputBuffer in bytes; must be zero if
        OutputBuffer is a NULL pointer.

    NoPermissionRequired - TRUE if this is a no permission required API.  (I.e.
        TRUE if the null session may be used.)

Return Value:

    NET_API_STATUS

--*/

{
    NET_API_STATUS ApiStatus;
    IO_STATUS_BLOCK iosb;
    NTSTATUS ntstatus;                      // Status from NT operations.
    OBJECT_ATTRIBUTES objattrTreeConn;      // Attrs for tree conn.
    LPTSTR pszTreeConn;                      // See strTreeConn below.
#ifndef UNICODE
    STRING strTreeConn;                     // \Device\LanManRedir\server\share
#endif
    UNICODE_STRING ucTreeConn;
    HANDLE TreeConnHandle;

    PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
    PFILE_FULL_EA_INFORMATION Ea;
    USHORT TransportNameSize = 0;
    ULONG EaBufferSize = 0;
    PWSTR UnicodeTransportName = NULL;

    UCHAR EaNameDomainNameSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_DOMAIN) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    UCHAR EaNamePasswordSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_PASSWORD) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    UCHAR EaNameTransportNameSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_TRANSPORT) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    UCHAR EaNameTypeSize = (UCHAR) (ROUND_UP_COUNT(
                                        strlen(EA_NAME_TYPE) + sizeof(CHAR),
                                        ALIGN_DWORD
                                        ) - sizeof(CHAR));

    UCHAR EaNameUserNameSize = (UCHAR) (ROUND_UP_COUNT(
                                             strlen(EA_NAME_USERNAME) + sizeof(CHAR),
                                             ALIGN_WCHAR
                                             ) - sizeof(CHAR));

    USHORT TypeSize = sizeof(ULONG);




    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: entered, TreeName='"
                FORMAT_LPTSTR "', " FORMAT_LPTSTR " session.\n",
                TreeName,
                NoPermissionRequired ? TEXT("null") : TEXT("non-null") ));
    }

    if ((TreeName == NULL) || (TreeName[0] == 0)) {
        return (ERROR_INVALID_PARAMETER);
    }

    if (! NetpIsRemoteNameValid(TreeName)) {
        return (ERROR_INVALID_PARAMETER);
    }

    //
    // Build NT-style name for what we're connecting to.  Note that there is
    // NOT a pair of backslashes anywhere in this name.
    //

    {
        DWORD NameSize =

            // /Device/LanManRedirector      /    server/share     \0
#ifdef UNICODE
            ( ( STRLEN((LPTSTR)DD_NFS_DEVICE_NAME_U) + 1 + STRLEN(TreeName) + 1 ) )
#else
            ( ( STRLEN((LPTSTR)DD_NFS_DEVICE_NAME) + 1 + STRLEN(TreeName) + 1 ) )
#endif
            * sizeof(TCHAR);

        pszTreeConn = (LPTSTR)NetpMemoryAllocate( NameSize );
    }

    if (pszTreeConn == NULL) {
        return (ERROR_NOT_ENOUGH_MEMORY);
    }

    //
    // Build the tree connect name.
    //

#ifdef UNICODE
    (void) STRCPY(pszTreeConn, (LPTSTR) DD_NFS_DEVICE_NAME_U);
#else
    (void) STRCPY(pszTreeConn, (LPTSTR) DD_NFS_DEVICE_NAME);
#endif

    //
    // NOTE: We add 1, (not sizeof(TCHAR)) because pointer arithmetic is done
    // in terms of multiples of sizeof(*pointer), not bytes
    //

    (void) STRCAT(pszTreeConn, TreeName+1); // \server\share

#ifdef UNICODE
    RtlInitUnicodeString(&ucTreeConn, pszTreeConn);
#else
    RtlInitString( & strTreeConn, pszTreeConn);
    (void) RtlOemStringToUnicodeString(&ucTreeConn, &strTreeConn, TRUE);
#endif

    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: UNICODE name is " FORMAT_LPWSTR
                ".\n", ucTreeConn.Buffer ));
    }



    //
    // Calculate the number of bytes needed for the EA buffer.
    // This may have the transport name.  For regular sessions, the user
    // name, password, and domain name are implicit.  For null sessions, we
    // must give 0-len user name, 0-len password, and 0-len domain name.
    //

    if (ARGUMENT_PRESENT(TransportName)) {
        ASSERT(ConnectionType == USE_IPC);

#ifdef UNICODE
        UnicodeTransportName = TransportName;
#else
        UnicodeTransportName = NetpAllocWStrFromStr(TransportName);

        if (UnicodeTransportName == NULL) {

            NetpMemoryFree(pszTreeConn);

            return ERROR_NOT_ENOUGH_MEMORY;
        }
#endif
        TransportNameSize = (USHORT) (wcslen(UnicodeTransportName) * sizeof(WCHAR));

        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNameTransportNameSize + sizeof(CHAR) +
                            TransportNameSize,
                            ALIGN_DWORD
                            );
    }

    if (NoPermissionRequired) {

        // Domain name (0-len).
        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNameDomainNameSize + sizeof(CHAR),
                            ALIGN_DWORD
                            );

        // Password (0-len).
        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNamePasswordSize + sizeof(CHAR),
                            ALIGN_DWORD
                            );

        // User name (0-len).
        EaBufferSize += ROUND_UP_COUNT(
                            FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
                            EaNameUserNameSize + sizeof(CHAR),
                            ALIGN_DWORD
                            );
    }

    EaBufferSize += ((ULONG)FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]))+
                    EaNameTypeSize + sizeof(CHAR) +
                    TypeSize;


    //
    // Allocate the EA buffer
    //

    if ((EaBuffer = NetpMemoryAllocate( EaBufferSize )) == NULL) {

        NetpMemoryFree(pszTreeConn);

#ifndef UNICODE
        if (UnicodeTransportName != NULL) {
            NetpMemoryFree(UnicodeTransportName);
        }
#endif

        return ERROR_NOT_ENOUGH_MEMORY;
    }

    //
    // Fill-in the EA buffer.
    //

    RtlZeroMemory(EaBuffer, EaBufferSize);

    Ea = EaBuffer;

    if (ARGUMENT_PRESENT(TransportName)) {

        //
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        strcpy(Ea->EaName, EA_NAME_TRANSPORT);
        Ea->EaNameLength = EaNameTransportNameSize;

        //
        // Copy the EA value into EA buffer.  EA value length does not
        // include the zero terminator.
        //
        (VOID) wcscpy(
            (LPWSTR) &(Ea->EaName[EaNameTransportNameSize + sizeof(CHAR)]),
            UnicodeTransportName
            );

        Ea->EaValueLength = TransportNameSize;

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNameTransportNameSize + sizeof(CHAR) +
                                  TransportNameSize,
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;
    }

    if (NoPermissionRequired) {

        //
        // *** DOMAIN NAME ***
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        (VOID) strcpy(Ea->EaName, EA_NAME_DOMAIN);
        Ea->EaNameLength = EaNameDomainNameSize;

        Ea->EaValueLength = 0;  // There is no EA value for this.

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNameDomainNameSize + sizeof(CHAR),
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;

        //
        // *** PASSWORD ***
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        (VOID) strcpy(Ea->EaName, EA_NAME_PASSWORD);
        Ea->EaNameLength = EaNamePasswordSize;

        Ea->EaValueLength = 0;  // There is no EA value for this.

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNamePasswordSize + sizeof(CHAR),
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;

        //
        // *** USER NAME ***
        // Copy the EA name into EA buffer.  EA name length does not
        // include the zero terminator.
        //
        (VOID) strcpy(Ea->EaName, EA_NAME_USERNAME);
        Ea->EaNameLength = EaNameUserNameSize;

        Ea->EaValueLength = 0;  // There is no EA value for this.

        Ea->NextEntryOffset = ROUND_UP_COUNT(
                                  FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
                                  EaNameUserNameSize + sizeof(CHAR),
                                  ALIGN_DWORD
                                  );
        Ea->Flags = 0;

        (ULONG) Ea += Ea->NextEntryOffset;
    }

    //
    // Copy the EA for the connection type name into EA buffer.  EA name length
    // does not include the zero terminator.
    //
    strcpy(Ea->EaName, EA_NAME_TYPE);
    Ea->EaNameLength = EaNameTypeSize;

    *((PULONG) &(Ea->EaName[EaNameTypeSize + sizeof(CHAR)])) = ConnectionType;

    Ea->EaValueLength = TypeSize;

    Ea->NextEntryOffset = 0;
    Ea->Flags = 0;

    // Set object attributes for the tree conn.
    InitializeObjectAttributes(
                & objattrTreeConn,                       // obj attr to init
                (LPVOID) & ucTreeConn,                   // string to use
                OBJ_CASE_INSENSITIVE,                    // Attributes
                NULL,                                    // Root directory
                SecurityDescriptor);                     // Security Descriptor

    //
    // Open a tree connection to the remote server.
    //

    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: opening " FORMAT_LPTSTR ".\n",
                pszTreeConn ));
    }
    ntstatus = NtCreateFile(
                & TreeConnHandle,                        // ptr to handle
                SYNCHRONIZE                              // desired...
                | GENERIC_READ | GENERIC_WRITE,          // ...access
                & objattrTreeConn,                       // name & attributes
                & iosb,                                  // I/O status block.
                NULL,                                    // alloc size.
                FILE_ATTRIBUTE_NORMAL,                   // (ignored)
                FILE_SHARE_READ | FILE_SHARE_WRITE,      // ...access
                FILE_OPEN_IF,                            // create disposition
                FILE_CREATE_TREE_CONNECTION              // create...
                | FILE_SYNCHRONOUS_IO_NONALERT,          // ...options
                EaBuffer,                                // EA buffer
                EaBufferSize );                          // Ea buffer size

#ifndef UNICODE
    RtlFreeUnicodeString( &ucTreeConn );
#endif

    if (! NT_SUCCESS(ntstatus)) {

#ifndef UNICODE
        if (UnicodeTransportName != NULL) {
            NetpMemoryFree(UnicodeTransportName);

        }
#endif

        if (EaBuffer != NULL) {
            NetpMemoryFree(EaBuffer);
        }

        NetpMemoryFree(pszTreeConn);
        ApiStatus = NetpNtStatusToApiStatus(ntstatus);
        if (ApiStatus == ERROR_BAD_NET_NAME) {
            ApiStatus = NERR_BadTransactConfig;  // Special meaning if no IPC$
        }

        if (ApiStatus != ERROR_BAD_NETPATH) {
            NetpKdPrint(( PREFIX_NETLIB
                    "NetpRdrFsControlTree: unexpected create error,\n"
                    "  tree name='" FORMAT_LPTSTR "', "
                    "ntstatus=" FORMAT_NTSTATUS ",\n"
                    "  iosb.Status=" FORMAT_NTSTATUS ", "
                    "iosb.Info=" FORMAT_HEX_ULONG ", "
                    "  returning " FORMAT_API_STATUS ".\n",
                    TreeName, ntstatus,
                    iosb.Status, iosb.Information, ApiStatus ));
        }

        return (ApiStatus);
    }

    // Do the FSCTL.
    IF_DEBUG(RDRFSCTL) {
        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: doing fsctl...\n" ));
    }
    ntstatus = NtFsControlFile(
                        TreeConnHandle,                  // handle
                        NULL,                            // no event
                        NULL,                            // no APC routine
                        NULL,                            // no APC context
                        & iosb,                          // I/O stat blk (set)
                        FsControlCode,                   // func code
                        InputBuffer,
                        InputBufferSize,
                        OutputBuffer,
                        OutputBufferSize);

    if (! NT_SUCCESS(ntstatus)) {
       NTSTATUS Status;

       Status = NtClose(TreeConnHandle);
#if DBG
       if (!NT_SUCCESS(Status)) {
           NetpKdPrint(( PREFIX_NETLIB
                   "NetpRdrFsControlTree: "
                   "Unexpected error closing tree connect handle: "
                   FORMAT_NTSTATUS "\n",
                   Status ));
       }
#endif

       NetpMemoryFree(pszTreeConn);

#ifndef UNICODE
        if (UnicodeTransportName != NULL) {
            NetpMemoryFree(UnicodeTransportName);

        }
#endif

        if (EaBuffer != NULL) {
            NetpMemoryFree(EaBuffer);
        }
        ApiStatus = NetpNtStatusToApiStatus(ntstatus);

        NetpKdPrint(( PREFIX_NETLIB
                "NetpRdrFsControlTree: unexpected FSCTL error,\n"
                "  tree name='" FORMAT_LPTSTR "', "
                "ntstatus=" FORMAT_NTSTATUS ".\n"
                "  ApiStatus=" FORMAT_API_STATUS ", "
                "iosb.Status=" FORMAT_NTSTATUS ", "
                "iosb.Info=" FORMAT_HEX_ULONG ".\n",
                TreeName, ntstatus, ApiStatus, iosb.Status, iosb.Information ));

        return (ApiStatus);
    }

    // Clean up.
    ntstatus = NtClose(TreeConnHandle);
#if DBG
       if (!NT_SUCCESS(ntstatus)) {
           NetpKdPrint(( PREFIX_NETLIB
                   "NetpRdrFsControlTree: "
                   "Unexpected error closing tree connect handle: "
                   FORMAT_NTSTATUS "\n", ntstatus ));
       }
#endif

    NetpMemoryFree(pszTreeConn);

#ifndef UNICODE
    if (UnicodeTransportName != NULL) {
        NetpMemoryFree(UnicodeTransportName);

    }
#endif

    if (EaBuffer != NULL) {
        NetpMemoryFree(EaBuffer);
    }

    return (NERR_Success);

} // NetpRdrFsControlTree