Merge from amd64-branch:
[reactos.git] / reactos / subsystems / win32 / csrss / win32csr / alias.c
1 /* $Id: init.c 31400 2007-12-22 17:18:32Z fireball $
2 * PROJECT: ReactOS CSRSS
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/csrss/api/alias.c
5 * PURPOSE: CSRSS alias support functions
6 * COPYRIGHT: Christoph Wittich
7 * Johannes Anderwald
8 *
9 */
10
11
12 /* INCLUDES ******************************************************************/
13
14 #define NDEBUG
15 #include "w32csr.h"
16 #include <debug.h>
17
18 typedef struct tagALIAS_ENTRY
19 {
20 LPCWSTR lpSource;
21 LPCWSTR lpTarget;
22 struct tagALIAS_ENTRY * Next;
23 }ALIAS_ENTRY, *PALIAS_ENTRY;
24
25
26 typedef struct tagALIAS_HEADER
27 {
28 LPCWSTR lpExeName;
29 PALIAS_ENTRY Data;
30 struct tagALIAS_HEADER * Next;
31
32 }ALIAS_HEADER, *PALIAS_HEADER;
33
34 /* Ensure that a buffer is contained within the process's shared memory section. */
35 static BOOL
36 ValidateBuffer(PCSRSS_PROCESS_DATA ProcessData, PVOID Buffer, ULONG Size)
37 {
38 ULONG Offset = (BYTE *)Buffer - (BYTE *)ProcessData->CsrSectionViewBase;
39 if (Offset >= ProcessData->CsrSectionViewSize
40 || Size > (ProcessData->CsrSectionViewSize - Offset))
41 {
42 DPRINT1("Invalid buffer %p %d; not within %p %d\n",
43 Buffer, Size, ProcessData->CsrSectionViewBase, ProcessData->CsrSectionViewSize);
44 return FALSE;
45 }
46 return TRUE;
47 }
48
49 static
50 PALIAS_HEADER
51 IntFindAliasHeader(PALIAS_HEADER RootHeader, LPCWSTR lpExeName)
52 {
53 while(RootHeader)
54 {
55 INT diff = _wcsicmp(RootHeader->lpExeName, lpExeName);
56 if (!diff)
57 return RootHeader;
58
59 if (diff > 0)
60 break;
61
62 RootHeader = RootHeader->Next;
63 }
64 return NULL;
65 }
66
67 PALIAS_HEADER
68 IntCreateAliasHeader(LPCWSTR lpExeName)
69 {
70 PALIAS_HEADER Entry;
71 UINT dwLength = wcslen(lpExeName) + 1;
72
73 Entry = RtlAllocateHeap(Win32CsrApiHeap, 0, sizeof(ALIAS_HEADER) + sizeof(WCHAR) * dwLength);
74 if (!Entry)
75 return Entry;
76
77 Entry->lpExeName = (LPCWSTR)(Entry + 1);
78 wcscpy((WCHAR*)Entry->lpExeName, lpExeName);
79 Entry->Data = NULL;
80 Entry->Next = NULL;
81 return Entry;
82 }
83
84 VOID
85 IntInsertAliasHeader(PALIAS_HEADER * RootHeader, PALIAS_HEADER NewHeader)
86 {
87 PALIAS_HEADER CurrentHeader;
88 PALIAS_HEADER *LastLink = RootHeader;
89
90 while ((CurrentHeader = *LastLink) != NULL)
91 {
92 INT Diff = _wcsicmp(NewHeader->lpExeName, CurrentHeader->lpExeName);
93 if (Diff < 0)
94 {
95 break;
96 }
97 LastLink = &CurrentHeader->Next;
98 }
99
100 *LastLink = NewHeader;
101 NewHeader->Next = CurrentHeader;
102 }
103
104 PALIAS_ENTRY
105 IntGetAliasEntry(PALIAS_HEADER Header, LPCWSTR lpSrcName)
106 {
107 if (Header == NULL)
108 return NULL;
109
110 PALIAS_ENTRY RootHeader = Header->Data;
111 while(RootHeader)
112 {
113 DPRINT("IntGetAliasEntry>lpSource %S\n", RootHeader->lpSource);
114 INT diff = _wcsicmp(RootHeader->lpSource, lpSrcName);
115 if (!diff)
116 return RootHeader;
117
118 if (diff > 0)
119 break;
120
121 RootHeader = RootHeader->Next;
122 }
123 return NULL;
124 }
125
126
127 VOID
128 IntInsertAliasEntry(PALIAS_HEADER Header, PALIAS_ENTRY NewEntry)
129 {
130 PALIAS_ENTRY CurrentEntry;
131 PALIAS_ENTRY *LastLink = &Header->Data;
132
133 while ((CurrentEntry = *LastLink) != NULL)
134 {
135 INT Diff = _wcsicmp(NewEntry->lpSource, CurrentEntry->lpSource);
136 if (Diff < 0)
137 {
138 break;
139 }
140 LastLink = &CurrentEntry->Next;
141 }
142
143 *LastLink = NewEntry;
144 NewEntry->Next = CurrentEntry;
145 }
146
147 PALIAS_ENTRY
148 IntCreateAliasEntry(LPCWSTR lpSource, LPCWSTR lpTarget)
149 {
150 UINT dwSource;
151 UINT dwTarget;
152 PALIAS_ENTRY Entry;
153
154 dwSource = wcslen(lpSource) + 1;
155 dwTarget = wcslen(lpTarget) + 1;
156
157 Entry = RtlAllocateHeap(Win32CsrApiHeap, 0, sizeof(ALIAS_ENTRY) + sizeof(WCHAR) * (dwSource + dwTarget));
158 if (!Entry)
159 return Entry;
160
161 Entry->lpSource = (LPCWSTR)(Entry + 1);
162 wcscpy((LPWSTR)Entry->lpSource, lpSource);
163 Entry->lpTarget = Entry->lpSource + dwSource;
164 wcscpy((LPWSTR)Entry->lpTarget, lpTarget);
165 Entry->Next = NULL;
166
167 return Entry;
168 }
169
170 UINT
171 IntGetConsoleAliasesExesLength(PALIAS_HEADER RootHeader)
172 {
173 UINT length = 0;
174
175 while(RootHeader)
176 {
177 length += (wcslen(RootHeader->lpExeName) + 1) * sizeof(WCHAR);
178 RootHeader = RootHeader->Next;
179 }
180 if (length)
181 length += sizeof(WCHAR); // last entry entry is terminated with 2 zero bytes
182
183 return length;
184 }
185
186 UINT
187 IntGetConsoleAliasesExes(PALIAS_HEADER RootHeader, LPWSTR TargetBuffer, UINT TargetBufferSize)
188 {
189 UINT Offset = 0;
190 UINT Length;
191
192 TargetBufferSize /= sizeof(WCHAR);
193 while(RootHeader)
194 {
195 Length = wcslen(RootHeader->lpExeName) + 1;
196 if (TargetBufferSize > Offset + Length)
197 {
198 wcscpy(&TargetBuffer[Offset], RootHeader->lpExeName);
199 Offset += Length;
200 }
201 else
202 {
203 break;
204 }
205 RootHeader = RootHeader->Next;
206 }
207 Length = min(Offset+1, TargetBufferSize);
208 TargetBuffer[Length] = L'\0';
209 return Length * sizeof(WCHAR);
210 }
211
212 UINT
213 IntGetAllConsoleAliasesLength(PALIAS_HEADER Header)
214 {
215 UINT Length = 0;
216 PALIAS_ENTRY CurEntry = Header->Data;
217
218 while(CurEntry)
219 {
220 Length += wcslen(CurEntry->lpSource);
221 Length += wcslen(CurEntry->lpTarget);
222 Length += 2; // zero byte and '='
223 CurEntry = CurEntry->Next;
224 }
225
226 if (Length)
227 {
228 return (Length+1) * sizeof(WCHAR);
229 }
230 return 0;
231 }
232 UINT
233 IntGetAllConsoleAliases(PALIAS_HEADER Header, LPWSTR TargetBuffer, UINT TargetBufferLength)
234 {
235 PALIAS_ENTRY CurEntry = Header->Data;
236 UINT Offset = 0;
237 UINT SrcLength, TargetLength;
238
239 TargetBufferLength /= sizeof(WCHAR);
240 while(CurEntry)
241 {
242 SrcLength = wcslen(CurEntry->lpSource) + 1;
243 TargetLength = wcslen(CurEntry->lpTarget) + 1;
244 if (Offset + TargetLength + SrcLength >= TargetBufferLength)
245 break;
246
247 wcscpy(&TargetBuffer[Offset], CurEntry->lpSource);
248 Offset += SrcLength;
249 TargetBuffer[Offset] = L'=';
250 wcscpy(&TargetBuffer[Offset], CurEntry->lpTarget);
251 Offset += TargetLength;
252
253 CurEntry = CurEntry->Next;
254 }
255 TargetBuffer[Offset] = L'\0';
256 return Offset * sizeof(WCHAR);
257 }
258 VOID
259 IntDeleteAliasEntry(PALIAS_HEADER Header, PALIAS_ENTRY Entry)
260 {
261 PALIAS_ENTRY *LastLink = &Header->Data;
262 PALIAS_ENTRY CurEntry;
263
264 while ((CurEntry = *LastLink) != NULL)
265 {
266 if (CurEntry == Entry)
267 {
268 *LastLink = Entry->Next;
269 RtlFreeHeap(Win32CsrApiHeap, 0, Entry);
270 return;
271 }
272 LastLink = &CurEntry->Next;
273 }
274 }
275 VOID
276 IntDeleteAllAliases(PALIAS_HEADER RootHeader)
277 {
278 PALIAS_HEADER Header, NextHeader;
279 PALIAS_ENTRY Entry, NextEntry;
280 for (Header = RootHeader; Header; Header = NextHeader)
281 {
282 NextHeader = Header->Next;
283 for (Entry = Header->Data; Entry; Entry = NextEntry)
284 {
285 NextEntry = Entry->Next;
286 RtlFreeHeap(Win32CsrApiHeap, 0, Entry);
287 }
288 RtlFreeHeap(Win32CsrApiHeap, 0, Header);
289 }
290 }
291
292 CSR_API(CsrAddConsoleAlias)
293 {
294 PCSRSS_CONSOLE Console;
295 PALIAS_HEADER Header;
296 PALIAS_ENTRY Entry;
297 WCHAR * lpExeName;
298 WCHAR * lpSource;
299 WCHAR * lpTarget;
300 ULONG TotalLength;
301 WCHAR * Ptr;
302
303 TotalLength = Request->Data.AddConsoleAlias.SourceLength + Request->Data.AddConsoleAlias.ExeLength + Request->Data.AddConsoleAlias.TargetLength;
304 Ptr = (WCHAR*)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE));
305
306 lpSource = (WCHAR*)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE));
307 lpExeName = (WCHAR*)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE) + Request->Data.AddConsoleAlias.SourceLength * sizeof(WCHAR));
308 lpTarget = (Request->Data.AddConsoleAlias.TargetLength != 0 ? lpExeName + Request->Data.AddConsoleAlias.ExeLength : NULL);
309
310 DPRINT("CsrAddConsoleAlias entered Request %p lpSource %p lpExeName %p lpTarget %p\n", Request, lpSource, lpExeName, lpTarget);
311
312 if (lpExeName == NULL || lpSource == NULL)
313 {
314 return STATUS_INVALID_PARAMETER;
315 }
316
317 Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
318 if (!NT_SUCCESS(Request->Status))
319 {
320 return Request->Status;
321 }
322
323 Header = IntFindAliasHeader(Console->Aliases, lpExeName);
324 if (!Header && lpTarget != NULL)
325 {
326 Header = IntCreateAliasHeader(lpExeName);
327 if (!Header)
328 {
329 ConioUnlockConsole(Console);
330 return STATUS_INSUFFICIENT_RESOURCES;
331 }
332 IntInsertAliasHeader(&Console->Aliases, Header);
333 }
334
335 if (lpTarget == NULL) // delete the entry
336 {
337 Entry = IntGetAliasEntry(Header, lpSource);
338 if (Entry)
339 {
340 IntDeleteAliasEntry(Header, Entry);
341 Request->Status = STATUS_SUCCESS;
342 }
343 else
344 {
345 Request->Status = STATUS_INVALID_PARAMETER;
346 }
347 ConioUnlockConsole(Console);
348 return Request->Status;
349 }
350
351 Entry = IntCreateAliasEntry(lpSource, lpTarget);
352
353 if (!Entry)
354 {
355 ConioUnlockConsole(Console);
356 return STATUS_INSUFFICIENT_RESOURCES;
357 }
358
359 IntInsertAliasEntry(Header, Entry);
360 ConioUnlockConsole(Console);
361 return STATUS_SUCCESS;
362 }
363
364 CSR_API(CsrGetConsoleAlias)
365 {
366 PCSRSS_CONSOLE Console;
367 PALIAS_HEADER Header;
368 PALIAS_ENTRY Entry;
369 UINT Length;
370 WCHAR * lpExeName;
371 WCHAR * lpSource;
372 WCHAR * lpTarget;
373
374 lpSource = (LPWSTR)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE));
375 lpExeName = lpSource + Request->Data.GetConsoleAlias.SourceLength;
376 lpTarget = Request->Data.GetConsoleAlias.TargetBuffer;
377
378
379 DPRINT("CsrGetConsoleAlias entered lpExeName %p lpSource %p TargetBuffer %p TargetBufferLength %u\n",
380 lpExeName, lpSource, lpTarget, Request->Data.GetConsoleAlias.TargetBufferLength);
381
382 if (Request->Data.GetConsoleAlias.ExeLength == 0 || lpTarget == NULL ||
383 Request->Data.GetConsoleAlias.TargetBufferLength == 0 || Request->Data.GetConsoleAlias.SourceLength == 0)
384 {
385 return STATUS_INVALID_PARAMETER;
386 }
387
388 Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
389 if (!NT_SUCCESS(Request->Status))
390 {
391 return Request->Status;
392 }
393
394 Header = IntFindAliasHeader(Console->Aliases, lpExeName);
395 if (!Header)
396 {
397 ConioUnlockConsole(Console);
398 return STATUS_INVALID_PARAMETER;
399 }
400
401 Entry = IntGetAliasEntry(Header, lpSource);
402 if (!Entry)
403 {
404 ConioUnlockConsole(Console);
405 return STATUS_INVALID_PARAMETER;
406 }
407
408 Length = (wcslen(Entry->lpTarget)+1) * sizeof(WCHAR);
409 if (Length > Request->Data.GetConsoleAlias.TargetBufferLength)
410 {
411 ConioUnlockConsole(Console);
412 return STATUS_BUFFER_TOO_SMALL;
413 }
414
415 if (!ValidateBuffer(ProcessData, lpTarget, Request->Data.GetConsoleAlias.TargetBufferLength))
416 {
417 ConioUnlockConsole(Console);
418 return STATUS_ACCESS_VIOLATION;
419 }
420
421 wcscpy(lpTarget, Entry->lpTarget);
422 Request->Data.GetConsoleAlias.BytesWritten = Length;
423 ConioUnlockConsole(Console);
424 return STATUS_SUCCESS;
425 }
426
427 CSR_API(CsrGetAllConsoleAliases)
428 {
429 PCSRSS_CONSOLE Console;
430 ULONG BytesWritten;
431 PALIAS_HEADER Header;
432
433 if (Request->Data.GetAllConsoleAlias.lpExeName == NULL)
434 {
435 return STATUS_INVALID_PARAMETER;
436 }
437
438 Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
439 if (!NT_SUCCESS(Request->Status))
440 {
441 return Request->Status;
442 }
443
444 Header = IntFindAliasHeader(Console->Aliases, Request->Data.GetAllConsoleAlias.lpExeName);
445 if (!Header)
446 {
447 ConioUnlockConsole(Console);
448 return STATUS_INVALID_PARAMETER;
449 }
450
451 if (IntGetAllConsoleAliasesLength(Header) > Request->Data.GetAllConsoleAlias.AliasBufferLength)
452 {
453 ConioUnlockConsole(Console);
454 return STATUS_BUFFER_OVERFLOW;
455 }
456
457 if (!ValidateBuffer(ProcessData,
458 Request->Data.GetAllConsoleAlias.AliasBuffer,
459 Request->Data.GetAllConsoleAlias.AliasBufferLength))
460 {
461 ConioUnlockConsole(Console);
462 return STATUS_ACCESS_VIOLATION;
463 }
464
465 BytesWritten = IntGetAllConsoleAliases(Header,
466 Request->Data.GetAllConsoleAlias.AliasBuffer,
467 Request->Data.GetAllConsoleAlias.AliasBufferLength);
468
469 Request->Data.GetAllConsoleAlias.BytesWritten = BytesWritten;
470 ConioUnlockConsole(Console);
471 return STATUS_SUCCESS;
472 }
473
474 CSR_API(CsrGetAllConsoleAliasesLength)
475 {
476 PCSRSS_CONSOLE Console;
477 PALIAS_HEADER Header;
478 UINT Length;
479
480 if (Request->Data.GetAllConsoleAliasesLength.lpExeName == NULL)
481 {
482 return STATUS_INVALID_PARAMETER;
483 }
484
485 Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
486 if (!NT_SUCCESS(Request->Status))
487 {
488 return Request->Status;
489 }
490
491 Header = IntFindAliasHeader(Console->Aliases, Request->Data.GetAllConsoleAliasesLength.lpExeName);
492 if (!Header)
493 {
494 ConioUnlockConsole(Console);
495 return STATUS_INVALID_PARAMETER;
496 }
497
498 Length = IntGetAllConsoleAliasesLength(Header);
499 Request->Data.GetAllConsoleAliasesLength.Length = Length;
500 ConioUnlockConsole(Console);
501 return STATUS_SUCCESS;
502 }
503
504 CSR_API(CsrGetConsoleAliasesExes)
505 {
506 PCSRSS_CONSOLE Console;
507 UINT BytesWritten;
508 UINT ExesLength;
509
510 DPRINT("CsrGetConsoleAliasesExes entered\n");
511
512 Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
513 if (!NT_SUCCESS(Request->Status))
514 {
515 return Request->Status;
516 }
517
518 ExesLength = IntGetConsoleAliasesExesLength(Console->Aliases);
519
520 if (ExesLength > Request->Data.GetConsoleAliasesExes.Length)
521 {
522 ConioUnlockConsole(Console);
523 return STATUS_BUFFER_OVERFLOW;
524 }
525
526 if (Request->Data.GetConsoleAliasesExes.ExeNames == NULL)
527 {
528 ConioUnlockConsole(Console);
529 return STATUS_INVALID_PARAMETER;
530 }
531
532 if (!ValidateBuffer(ProcessData,
533 Request->Data.GetConsoleAliasesExes.ExeNames,
534 Request->Data.GetConsoleAliasesExes.Length))
535 {
536 ConioUnlockConsole(Console);
537 return STATUS_ACCESS_VIOLATION;
538 }
539
540 BytesWritten = IntGetConsoleAliasesExes(Console->Aliases,
541 Request->Data.GetConsoleAliasesExes.ExeNames,
542 Request->Data.GetConsoleAliasesExes.Length);
543
544 Request->Data.GetConsoleAliasesExes.BytesWritten = BytesWritten;
545 ConioUnlockConsole(Console);
546 return STATUS_SUCCESS;
547 }
548
549 CSR_API(CsrGetConsoleAliasesExesLength)
550 {
551 PCSRSS_CONSOLE Console;
552 DPRINT("CsrGetConsoleAliasesExesLength entered\n");
553
554 Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
555 if (NT_SUCCESS(Request->Status))
556 {
557 Request->Data.GetConsoleAliasesExesLength.Length = IntGetConsoleAliasesExesLength(Console->Aliases);
558 ConioUnlockConsole(Console);
559 }
560 return Request->Status;
561 }