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