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