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