1 /*
2  * PROJECT:     ReactOS API Tests
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Test for RtlpApplyLengthFunction
5  * COPYRIGHT:   Copyright 2021 Mark Jansen <mark.jansen@reactos.org>
6  */
7 
8 #include "precomp.h"
9 #include <ntstrsafe.h>
10 
11 
12 NTSTATUS
13 NTAPI
14 RtlpApplyLengthFunction(IN ULONG Flags,
15     IN ULONG Type,
16     IN PVOID UnicodeStringOrUnicodeStringBuffer,
17     IN NTSTATUS(NTAPI*LengthFunction)(ULONG, PUNICODE_STRING, PULONG));
18 
19 
LengthFunctionFail(ULONG Unknown,PUNICODE_STRING String,PULONG Length)20 NTSTATUS NTAPI LengthFunctionFail(ULONG Unknown, PUNICODE_STRING String, PULONG Length)
21 {
22     ok_int(*Length, 0);
23     /* Show that this is ignored when an error is returned */
24     *Length = 3;
25     return STATUS_INVALID_ACCOUNT_NAME;
26 }
27 
LengthFunctionOk(ULONG Unknown,PUNICODE_STRING String,PULONG Length)28 NTSTATUS NTAPI LengthFunctionOk(ULONG Unknown, PUNICODE_STRING String, PULONG Length)
29 {
30     ok_int(*Length, 0);
31     *Length = 4;
32     return STATUS_SUCCESS;
33 }
34 
LengthFunctionReturn1(ULONG Unknown,PUNICODE_STRING String,PULONG Length)35 NTSTATUS NTAPI LengthFunctionReturn1(ULONG Unknown, PUNICODE_STRING String, PULONG Length)
36 {
37     ok_int(*Length, 0);
38     *Length = 4;
39     return (NTSTATUS)1;
40 }
41 
LengthFunctionCopyLen(ULONG Unknown,PUNICODE_STRING String,PULONG Length)42 NTSTATUS NTAPI LengthFunctionCopyLen(ULONG Unknown, PUNICODE_STRING String, PULONG Length)
43 {
44     /* Use Buffer as length, to show that the function does not interpret the contents at all */
45     *Length = (ULONG)(ULONG_PTR)String->Buffer;
46     return STATUS_SUCCESS;
47 }
48 
49 
START_TEST(RtlpApplyLengthFunction)50 START_TEST(RtlpApplyLengthFunction)
51 {
52     NTSTATUS Status;
53     /* Show that RtlpApplyLengthFunction does not interpret anything in the UNICODE_STRING */
54     UNICODE_STRING String = { 1, 2, (PWSTR)3 };
55     RTL_UNICODE_STRING_BUFFER Buffer;
56     WCHAR StaticBuffer[10] = { 0 };
57     ULONG n;
58 
59     Status = RtlpApplyLengthFunction(0, 0, NULL, LengthFunctionFail);
60     ok_int(String.Length, 1);
61     ok_hex(Status, STATUS_INVALID_PARAMETER);
62 
63     Status = RtlpApplyLengthFunction(0, 0, &String, LengthFunctionFail);
64     ok_int(String.Length, 1);
65     ok_hex(Status, STATUS_INVALID_PARAMETER);
66 
67     /* Show that no flag is accepted */
68     for (n = 0; n < 32; ++n)
69     {
70         Status = RtlpApplyLengthFunction((1 << n), sizeof(String), &String, LengthFunctionFail);
71         ok_int(String.Length, 1);
72         ok_hex(Status, STATUS_INVALID_PARAMETER);
73     }
74 
75     Status = RtlpApplyLengthFunction(0, sizeof(String), &String, NULL);
76     ok_int(String.Length, 1);
77     ok_hex(Status, STATUS_INVALID_PARAMETER);
78 
79     /* Still Length 1 when the function returns an error */
80     Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionFail);
81     ok_int(String.Length, 1);
82     ok_hex(Status, STATUS_INVALID_ACCOUNT_NAME);
83 
84     Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionOk);
85     ok_int(String.Length, 8);   /* Value returned from LengthFunction is multiplied by sizeof(WCHAR) */
86     ok_hex(Status, STATUS_SUCCESS);
87 
88     String.Length = 1;
89     Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionReturn1);
90     ok_int(String.Length, 8);
91     ok_hex(Status, STATUS_SUCCESS); /* Returns STATUS_SUCCESS regardless of success code from the function */
92 
93     /* Show max length */
94     String.Buffer = (PWCHAR)UNICODE_STRING_MAX_CHARS;
95     String.Length = 2;
96     Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionCopyLen);
97     ok_int(String.Length, UNICODE_STRING_MAX_CHARS * sizeof(WCHAR));
98     ok_hex(Status, STATUS_SUCCESS);
99 
100     String.Buffer = (PWCHAR)(UNICODE_STRING_MAX_CHARS + 1);
101     String.Length = 2;
102     Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionCopyLen);
103     ok_int(String.Length, 2);       /* Unchanged */
104     ok_hex(Status, STATUS_NAME_TOO_LONG);
105 
106     /* Now try it with the RTL_UNICODE_STRING_BUFFER, this works fine on 2k3 but not on Win10!! */
107     RtlInitBuffer(&Buffer.ByteBuffer, (PUCHAR)StaticBuffer, sizeof(StaticBuffer));
108     /* In this case the Buffer is modified, so we should have a valid UNICODE_STRING! */
109     Buffer.String.Length = 5;
110     Buffer.String.MaximumLength = Buffer.ByteBuffer.StaticSize;
111     Buffer.String.Buffer = (PWSTR)Buffer.ByteBuffer.Buffer;
112     wcscpy(StaticBuffer, L"123456789");
113 
114     /* Show that no flag is accepted */
115     for (n = 0; n < 32; ++n)
116     {
117         Status = RtlpApplyLengthFunction((1 << n), sizeof(Buffer), &Buffer, LengthFunctionFail);
118         ok_int(Buffer.String.Length, 5);
119         ok_hex(Status, STATUS_INVALID_PARAMETER);
120         ok_wstr(StaticBuffer, L"123456789");
121     }
122 
123     /* Still Length 1 when the function returns an error */
124     Status = RtlpApplyLengthFunction(0, sizeof(Buffer), &Buffer, LengthFunctionFail);
125     ok_int(Buffer.String.Length, 5);
126     ok_hex(Status, STATUS_INVALID_ACCOUNT_NAME);
127     ok_wstr(StaticBuffer, L"123456789");
128 
129     Status = RtlpApplyLengthFunction(0, sizeof(Buffer), &Buffer, LengthFunctionOk);
130     ok_int(Buffer.String.Length, 8);   /* Value returned from LengthFunction is multiplied by sizeof(WCHAR) */
131     ok_hex(Status, STATUS_SUCCESS);
132     ok_wstr(StaticBuffer, L"1234");     /* Buffer is truncated */
133     ok_wstr(StaticBuffer + 5, L"6789"); /* Rest is not overwritten*/
134 
135     Buffer.String.Length = 1;
136     wcscpy(StaticBuffer, L"123456789");
137     Status = RtlpApplyLengthFunction(0, sizeof(Buffer), &Buffer, LengthFunctionReturn1);
138     ok_int(Buffer.String.Length, 8);
139     ok_hex(Status, STATUS_SUCCESS); /* Returns STATUS_SUCCESS regardless of success code from the function */
140     ok_wstr(StaticBuffer, L"1234");     /* Buffer is truncated */
141     ok_wstr(StaticBuffer + 5, L"6789"); /* Rest is not overwritten*/
142 }
143 
144