1 /* 2 * PROJECT: ReactOS Kernel - Vista+ APIs 3 * LICENSE: GPL v2 - See COPYING in the top level directory 4 * FILE: lib/drivers/ntoskrnl_vista/fsrtl.c 5 * PURPOSE: FsRtl functions of Vista+ 6 * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org> 7 */ 8 9 #include <ntdef.h> 10 #include <ntifs.h> 11 12 NTKERNELAPI 13 NTSTATUS 14 NTAPI 15 FsRtlRemoveDotsFromPath(IN PWSTR OriginalString, 16 IN USHORT PathLength, 17 OUT USHORT *NewLength) 18 { 19 USHORT Length, ReadPos, WritePos; 20 21 Length = PathLength / sizeof(WCHAR); 22 23 if (Length == 3 && OriginalString[0] == '\\' && OriginalString[1] == '.' && OriginalString[2] == '.') 24 { 25 return STATUS_IO_REPARSE_DATA_INVALID; 26 } 27 28 if (Length == 2 && OriginalString[0] == '.' && OriginalString[1] == '.') 29 { 30 return STATUS_IO_REPARSE_DATA_INVALID; 31 } 32 33 if (Length > 2 && OriginalString[0] == '.' && OriginalString[1] == '.' && OriginalString[2] == '\\') 34 { 35 return STATUS_IO_REPARSE_DATA_INVALID; 36 } 37 38 for (ReadPos = 0, WritePos = 0; ReadPos < Length; ++WritePos) 39 { 40 for (; ReadPos > 0 && ReadPos < Length; ++ReadPos) 41 { 42 if (ReadPos < Length - 1 && OriginalString[ReadPos] == '\\' && OriginalString[ReadPos + 1] == '\\') 43 { 44 continue; 45 } 46 47 if (OriginalString[ReadPos] != '.') 48 { 49 break; 50 } 51 52 if (ReadPos == Length - 1) 53 { 54 if (OriginalString[ReadPos - 1] == '\\') 55 { 56 if (WritePos > 1) 57 { 58 --WritePos; 59 } 60 61 continue; 62 } 63 64 OriginalString[WritePos] = '.'; 65 ++WritePos; 66 continue; 67 } 68 69 if (OriginalString[ReadPos + 1] == '\\') 70 { 71 if (OriginalString[ReadPos - 1] != '\\') 72 { 73 OriginalString[WritePos] = '.'; 74 ++WritePos; 75 continue; 76 } 77 } 78 else 79 { 80 if (OriginalString[ReadPos + 1] != '.' || OriginalString[ReadPos - 1] != '\\' || 81 ((ReadPos != Length - 2) && OriginalString[ReadPos + 2] != '\\')) 82 { 83 OriginalString[WritePos] = '.'; 84 ++WritePos; 85 continue; 86 } 87 88 for (WritePos -= 2; (SHORT)WritePos > 0 && OriginalString[WritePos] != '\\'; --WritePos); 89 90 if ((SHORT)WritePos < 0 || OriginalString[WritePos] != '\\') 91 { 92 return STATUS_IO_REPARSE_DATA_INVALID; 93 } 94 95 if (WritePos == 0 && ReadPos == Length - 2) 96 { 97 WritePos = 1; 98 } 99 } 100 101 ++ReadPos; 102 } 103 104 if (ReadPos >= Length) 105 { 106 break; 107 } 108 109 OriginalString[WritePos] = OriginalString[ReadPos]; 110 ++ReadPos; 111 } 112 113 *NewLength = WritePos * sizeof(WCHAR); 114 115 while (WritePos < Length) 116 { 117 OriginalString[WritePos++] = UNICODE_NULL; 118 } 119 120 return STATUS_SUCCESS; 121 } 122 123 FORCEINLINE 124 BOOLEAN 125 IsNullGuid(IN PGUID Guid) 126 { 127 if (Guid->Data1 == 0 && Guid->Data2 == 0 && Guid->Data3 == 0 && 128 ((ULONG *)Guid->Data4)[0] == 0 && ((ULONG *)Guid->Data4)[1] == 0) 129 { 130 return TRUE; 131 } 132 133 return FALSE; 134 } 135 136 FORCEINLINE 137 BOOLEAN 138 IsEven(IN USHORT Digit) 139 { 140 return ((Digit & 1) != 1); 141 } 142 143 NTKERNELAPI 144 NTSTATUS 145 NTAPI 146 FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, 147 IN PREPARSE_DATA_BUFFER ReparseBuffer) 148 { 149 USHORT DataLength; 150 ULONG ReparseTag; 151 PREPARSE_GUID_DATA_BUFFER GuidBuffer; 152 153 /* Validate data size range */ 154 if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE || BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) 155 { 156 return STATUS_IO_REPARSE_DATA_INVALID; 157 } 158 159 GuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer; 160 DataLength = ReparseBuffer->ReparseDataLength; 161 ReparseTag = ReparseBuffer->ReparseTag; 162 163 /* Validate size consistency */ 164 if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE != BufferLength && DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE != BufferLength) 165 { 166 return STATUS_IO_REPARSE_DATA_INVALID; 167 } 168 169 /* REPARSE_DATA_BUFFER is reserved for MS tags */ 170 if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE == BufferLength && !IsReparseTagMicrosoft(ReparseTag)) 171 { 172 return STATUS_IO_REPARSE_DATA_INVALID; 173 } 174 175 /* If that a GUID data buffer, its GUID cannot be null, and it cannot contain a MS tag */ 176 if (DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE == BufferLength && ((!IsReparseTagMicrosoft(ReparseTag) 177 && IsNullGuid(&GuidBuffer->ReparseGuid)) || (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT || ReparseTag == IO_REPARSE_TAG_SYMLINK))) 178 { 179 return STATUS_IO_REPARSE_DATA_INVALID; 180 } 181 182 /* Check the data for MS non reserved tags */ 183 if (!(ReparseTag & 0xFFF0000) && ReparseTag != IO_REPARSE_TAG_RESERVED_ZERO && ReparseTag != IO_REPARSE_TAG_RESERVED_ONE) 184 { 185 /* If that's a mount point, validate the MountPointReparseBuffer branch */ 186 if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) 187 { 188 /* We need information */ 189 if (DataLength >= REPARSE_DATA_BUFFER_HEADER_SIZE) 190 { 191 /* Substitue must be the first in row */ 192 if (!ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset) 193 { 194 /* Substitude must be null-terminated */ 195 if (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset == ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL)) 196 { 197 /* There must just be the Offset/Length fields + buffer + 2 null chars */ 198 if (DataLength == ReparseBuffer->MountPointReparseBuffer.PrintNameLength + ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.SubstituteNameOffset)) + 2 * sizeof(UNICODE_NULL)) 199 { 200 return STATUS_SUCCESS; 201 } 202 } 203 } 204 } 205 } 206 else 207 { 208 #define FIELDS_SIZE (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset)) 209 210 /* If that's not a symlink, accept the MS tag as it */ 211 if (ReparseTag != IO_REPARSE_TAG_SYMLINK) 212 { 213 return STATUS_SUCCESS; 214 } 215 216 /* We need information */ 217 if (DataLength >= FIELDS_SIZE) 218 { 219 /* Validate lengths */ 220 if (ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength && ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) 221 { 222 /* Validate unicode strings */ 223 if (IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) && 224 IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset)) 225 { 226 if ((DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset + ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE) 227 && (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE)) 228 { 229 return STATUS_SUCCESS; 230 } 231 } 232 } 233 } 234 #undef FIELDS_SIZE 235 } 236 237 return STATUS_IO_REPARSE_DATA_INVALID; 238 } 239 240 return STATUS_IO_REPARSE_TAG_INVALID; 241 } 242 243