[KERNEL32] Check the return buffer for NULL before initializing the unicode string...
[reactos.git] / reactos / dll / win32 / kernel32 / client / compname.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS system libraries
22 * PURPOSE: Computer name functions
23 * FILE: dll/win32/kernel32/client/compname.c
24 * PROGRAMER: Eric Kohl
25 */
26
27 /* INCLUDES ******************************************************************/
28
29 #include <k32.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34
35 /* FUNCTIONS *****************************************************************/
36
37 static
38 BOOL
39 GetComputerNameFromRegistry(LPWSTR RegistryKey,
40 LPWSTR ValueNameStr,
41 LPWSTR lpBuffer,
42 LPDWORD nSize)
43 {
44 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
45 OBJECT_ATTRIBUTES ObjectAttributes;
46 UNICODE_STRING KeyName;
47 UNICODE_STRING ValueName;
48 HANDLE KeyHandle;
49 ULONG KeyInfoSize;
50 ULONG ReturnSize;
51 NTSTATUS Status;
52
53 RtlInitUnicodeString(&KeyName, RegistryKey);
54 InitializeObjectAttributes(&ObjectAttributes,
55 &KeyName,
56 OBJ_CASE_INSENSITIVE,
57 NULL,
58 NULL);
59
60 Status = NtOpenKey(&KeyHandle,
61 KEY_READ,
62 &ObjectAttributes);
63 if (!NT_SUCCESS(Status))
64 {
65 BaseSetLastNTError (Status);
66 return FALSE;
67 }
68
69 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + *nSize * sizeof(WCHAR);
70 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize);
71 if (KeyInfo == NULL)
72 {
73 NtClose(KeyHandle);
74 SetLastError(ERROR_OUTOFMEMORY);
75 return FALSE;
76 }
77
78 RtlInitUnicodeString(&ValueName, ValueNameStr);
79
80 Status = NtQueryValueKey(KeyHandle,
81 &ValueName,
82 KeyValuePartialInformation,
83 KeyInfo,
84 KeyInfoSize,
85 &ReturnSize);
86
87 NtClose(KeyHandle);
88
89 if (!NT_SUCCESS(Status))
90 {
91 *nSize = ReturnSize;
92 goto failed;
93 }
94
95 if (KeyInfo->Type != REG_SZ)
96 {
97 Status = STATUS_UNSUCCESSFUL;
98 goto failed;
99 }
100
101 if (!lpBuffer || *nSize < (KeyInfo->DataLength / sizeof(WCHAR)))
102 {
103 *nSize = ReturnSize;
104 Status = STATUS_BUFFER_OVERFLOW;
105 goto failed;
106 }
107
108 *nSize = KeyInfo->DataLength / sizeof(WCHAR) - 1;
109 RtlCopyMemory(lpBuffer, KeyInfo->Data, KeyInfo->DataLength);
110 lpBuffer[*nSize] = 0;
111
112 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
113
114 return TRUE;
115
116 failed:
117 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
118 BaseSetLastNTError(Status);
119 return FALSE;
120 }
121
122 /*
123 * @implemented
124 */
125 BOOL
126 WINAPI
127 GetComputerNameExW(COMPUTER_NAME_FORMAT NameType,
128 LPWSTR lpBuffer,
129 LPDWORD nSize)
130 {
131 UNICODE_STRING ResultString;
132 UNICODE_STRING DomainPart;
133 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
134 NTSTATUS Status;
135 BOOL ret = TRUE;
136 DWORD HostSize;
137
138 switch (NameType)
139 {
140 case ComputerNameNetBIOS:
141 return GetComputerNameFromRegistry(L"\\Registry\\Machine\\System\\CurrentControlSet"
142 L"\\Control\\ComputerName\\ComputerName",
143 L"ComputerName",
144 lpBuffer,
145 nSize);
146
147 case ComputerNameDnsDomain:
148 return GetComputerNameFromRegistry(L"\\Registry\\Machine\\System\\CurrentControlSet"
149 L"\\Services\\Tcpip\\Parameters",
150 L"Domain",
151 lpBuffer,
152 nSize);
153
154 case ComputerNameDnsFullyQualified:
155 ResultString.Length = 0;
156 ResultString.MaximumLength = (USHORT)*nSize * sizeof(WCHAR);
157 ResultString.Buffer = lpBuffer;
158
159 RtlZeroMemory(QueryTable, sizeof(QueryTable));
160 RtlInitUnicodeString(&DomainPart, NULL);
161
162 QueryTable[0].Name = L"HostName";
163 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
164 QueryTable[0].EntryContext = &DomainPart;
165
166 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
167 L"\\Registry\\Machine\\System"
168 L"\\CurrentControlSet\\Services\\Tcpip"
169 L"\\Parameters",
170 QueryTable,
171 NULL,
172 NULL);
173
174 if (NT_SUCCESS(Status))
175 {
176 Status = RtlAppendUnicodeStringToString(&ResultString, &DomainPart);
177 HostSize = DomainPart.Length;
178
179 if (!NT_SUCCESS(Status))
180 {
181 ret = FALSE;
182 }
183
184 RtlAppendUnicodeToString(&ResultString, L".");
185 RtlFreeUnicodeString(&DomainPart);
186
187 RtlInitUnicodeString(&DomainPart, NULL);
188 QueryTable[0].Name = L"Domain";
189 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
190 QueryTable[0].EntryContext = &DomainPart;
191
192 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
193 L"\\Registry\\Machine\\System"
194 L"\\CurrentControlSet\\Services\\Tcpip"
195 L"\\Parameters",
196 QueryTable,
197 NULL,
198 NULL);
199
200 if (NT_SUCCESS(Status))
201 {
202 Status = RtlAppendUnicodeStringToString(&ResultString, &DomainPart);
203 if ((!NT_SUCCESS(Status)) || (!ret))
204 {
205 *nSize = HostSize + DomainPart.Length;
206 SetLastError(ERROR_MORE_DATA);
207 RtlFreeUnicodeString(&DomainPart);
208 return FALSE;
209 }
210 RtlFreeUnicodeString(&DomainPart);
211 *nSize = ResultString.Length / sizeof(WCHAR) - 1;
212 return TRUE;
213 }
214 }
215 return FALSE;
216
217 case ComputerNameDnsHostname:
218 return GetComputerNameFromRegistry(L"\\Registry\\Machine\\System\\CurrentControlSet"
219 L"\\Services\\Tcpip\\Parameters",
220 L"Hostname",
221 lpBuffer,
222 nSize);
223
224 case ComputerNamePhysicalDnsDomain:
225 return GetComputerNameFromRegistry(L"\\Registry\\Machine\\System\\CurrentControlSet"
226 L"\\Services\\Tcpip\\Parameters",
227 L"Domain",
228 lpBuffer,
229 nSize);
230
231 /* XXX Redo these */
232 case ComputerNamePhysicalDnsFullyQualified:
233 return GetComputerNameExW(ComputerNameDnsFullyQualified,
234 lpBuffer,
235 nSize);
236
237 case ComputerNamePhysicalDnsHostname:
238 return GetComputerNameExW(ComputerNameDnsHostname,
239 lpBuffer,
240 nSize);
241
242 case ComputerNamePhysicalNetBIOS:
243 return GetComputerNameExW(ComputerNameNetBIOS,
244 lpBuffer,
245 nSize);
246
247 case ComputerNameMax:
248 return FALSE;
249 }
250
251 return FALSE;
252 }
253
254 /*
255 * @implemented
256 */
257 BOOL
258 WINAPI
259 GetComputerNameExA(COMPUTER_NAME_FORMAT NameType,
260 LPSTR lpBuffer,
261 LPDWORD nSize)
262 {
263 UNICODE_STRING UnicodeString;
264 ANSI_STRING AnsiString;
265 BOOL Result;
266 PWCHAR TempBuffer;
267
268 if (!lpBuffer)
269 {
270 SetLastError(ERROR_INVALID_PARAMETER);
271 return FALSE;
272 }
273
274 TempBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *nSize * sizeof(WCHAR));
275 if (!TempBuffer)
276 {
277 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
278 return FALSE;
279 }
280
281 AnsiString.MaximumLength = (USHORT)*nSize;
282 AnsiString.Length = 0;
283 AnsiString.Buffer = lpBuffer;
284
285 Result = GetComputerNameExW(NameType, TempBuffer, nSize);
286
287 if (Result)
288 {
289 UnicodeString.MaximumLength = (USHORT)*nSize * sizeof(WCHAR) + sizeof(WCHAR);
290 UnicodeString.Length = (USHORT)*nSize * sizeof(WCHAR) + sizeof(WCHAR);
291 UnicodeString.Buffer = TempBuffer;
292
293 RtlUnicodeStringToAnsiString(&AnsiString,
294 &UnicodeString,
295 FALSE);
296 }
297
298 RtlFreeHeap(RtlGetProcessHeap(), 0, TempBuffer);
299
300 return Result;
301 }
302
303 /*
304 * @implemented
305 */
306 BOOL
307 WINAPI
308 GetComputerNameA(LPSTR lpBuffer, LPDWORD lpnSize)
309 {
310 BOOL ret;
311
312 ret = GetComputerNameExA(ComputerNameNetBIOS, lpBuffer, lpnSize);
313 if (!ret && GetLastError() == ERROR_MORE_DATA)
314 SetLastError(ERROR_BUFFER_OVERFLOW);
315
316 return ret;
317 }
318
319
320 /*
321 * @implemented
322 */
323 BOOL
324 WINAPI
325 GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
326 {
327 BOOL ret;
328 ret=GetComputerNameExW(ComputerNameNetBIOS, lpBuffer, lpnSize);
329 if(!ret && GetLastError() == ERROR_MORE_DATA)
330 SetLastError(ERROR_BUFFER_OVERFLOW);
331 return ret;
332 }
333
334
335 /*
336 * @implemented
337 */
338 static
339 BOOL
340 IsValidComputerName(COMPUTER_NAME_FORMAT NameType,
341 LPCWSTR lpComputerName)
342 {
343 PWCHAR p;
344 ULONG Length;
345
346 /* FIXME: do verification according to NameType */
347
348 Length = 0;
349 p = (PWCHAR)lpComputerName;
350
351 while (*p != 0)
352 {
353 if (!(iswctype(*p, _ALPHA | _DIGIT) || *p == L'!' || *p == L'@' || *p == L'#' ||
354 *p == L'$' || *p == L'%' || *p == L'^' || *p == L'&' || *p == L'\'' ||
355 *p == L')' || *p == L'(' || *p == L'.' || *p == L'-' || *p == L'_' ||
356 *p == L'{' || *p == L'}' || *p == L'~'))
357 return FALSE;
358
359 Length++;
360 p++;
361 }
362
363 if (Length == 0 || Length > MAX_COMPUTERNAME_LENGTH)
364 return FALSE;
365
366 return TRUE;
367 }
368
369
370 static
371 BOOL
372 SetComputerNameToRegistry(LPCWSTR RegistryKey,
373 LPCWSTR ValueNameStr,
374 LPCWSTR lpBuffer)
375 {
376 OBJECT_ATTRIBUTES ObjectAttributes;
377 UNICODE_STRING KeyName;
378 UNICODE_STRING ValueName;
379 HANDLE KeyHandle;
380 NTSTATUS Status;
381
382 RtlInitUnicodeString(&KeyName, RegistryKey);
383 InitializeObjectAttributes(&ObjectAttributes,
384 &KeyName,
385 OBJ_CASE_INSENSITIVE,
386 NULL,
387 NULL);
388
389 Status = NtOpenKey(&KeyHandle,
390 KEY_WRITE,
391 &ObjectAttributes);
392 if (!NT_SUCCESS(Status))
393 {
394 BaseSetLastNTError(Status);
395 return FALSE;
396 }
397
398 RtlInitUnicodeString(&ValueName, ValueNameStr);
399
400 Status = NtSetValueKey(KeyHandle,
401 &ValueName,
402 0,
403 REG_SZ,
404 (PVOID)lpBuffer,
405 (wcslen (lpBuffer) + 1) * sizeof(WCHAR));
406 if (!NT_SUCCESS(Status))
407 {
408 NtClose(KeyHandle);
409 BaseSetLastNTError(Status);
410 return FALSE;
411 }
412
413 NtFlushKey(KeyHandle);
414 NtClose(KeyHandle);
415
416 return TRUE;
417 }
418
419
420 /*
421 * @implemented
422 */
423 BOOL
424 WINAPI
425 SetComputerNameA(LPCSTR lpComputerName)
426 {
427 return SetComputerNameExA(ComputerNamePhysicalNetBIOS, lpComputerName);
428 }
429
430
431 /*
432 * @implemented
433 */
434 BOOL
435 WINAPI
436 SetComputerNameW(LPCWSTR lpComputerName)
437 {
438 return SetComputerNameExW(ComputerNamePhysicalNetBIOS, lpComputerName);
439 }
440
441
442 /*
443 * @implemented
444 */
445 BOOL
446 WINAPI
447 SetComputerNameExA(COMPUTER_NAME_FORMAT NameType,
448 LPCSTR lpBuffer)
449 {
450 UNICODE_STRING Buffer;
451 BOOL bResult;
452
453 RtlCreateUnicodeStringFromAsciiz(&Buffer, (LPSTR)lpBuffer);
454
455 bResult = SetComputerNameExW(NameType, Buffer.Buffer);
456
457 RtlFreeUnicodeString(&Buffer);
458
459 return bResult;
460 }
461
462
463 /*
464 * @implemented
465 */
466 BOOL
467 WINAPI
468 SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,
469 LPCWSTR lpBuffer)
470 {
471 if (!IsValidComputerName(NameType, lpBuffer))
472 {
473 SetLastError(ERROR_INVALID_PARAMETER);
474 return FALSE;
475 }
476
477 switch( NameType )
478 {
479 case ComputerNamePhysicalDnsDomain:
480 return SetComputerNameToRegistry(L"\\Registry\\Machine\\System\\CurrentControlSet"
481 L"\\Services\\Tcpip\\Parameters",
482 L"Domain",
483 lpBuffer);
484
485 case ComputerNamePhysicalDnsHostname:
486 return SetComputerNameToRegistry(L"\\Registry\\Machine\\System\\CurrentControlSet"
487 L"\\Services\\Tcpip\\Parameters",
488 L"Hostname",
489 lpBuffer);
490
491 case ComputerNamePhysicalNetBIOS:
492 return SetComputerNameToRegistry(L"\\Registry\\Machine\\System\\CurrentControlSet"
493 L"\\Control\\ComputerName\\ComputerName",
494 L"ComputerName",
495 lpBuffer);
496
497 default:
498 SetLastError (ERROR_INVALID_PARAMETER);
499 return FALSE;
500 }
501 }
502
503
504 /*
505 * @implemented
506 */
507 BOOL
508 WINAPI
509 DnsHostnameToComputerNameA(LPCSTR Hostname,
510 LPSTR ComputerName,
511 LPDWORD nSize)
512 {
513 DWORD len;
514
515 DPRINT("(%s, %p, %p)\n", Hostname, ComputerName, nSize);
516
517 if (!Hostname || !nSize)
518 return FALSE;
519
520 len = lstrlenA(Hostname);
521
522 if (len > MAX_COMPUTERNAME_LENGTH)
523 len = MAX_COMPUTERNAME_LENGTH;
524
525 if (*nSize < len)
526 {
527 *nSize = len;
528 return FALSE;
529 }
530
531 if (!ComputerName) return FALSE;
532
533 memcpy(ComputerName, Hostname, len);
534 ComputerName[len + 1] = 0;
535 return TRUE;
536 }
537
538
539 /*
540 * @implemented
541 */
542 BOOL
543 WINAPI
544 DnsHostnameToComputerNameW(LPCWSTR hostname,
545 LPWSTR computername,
546 LPDWORD size)
547 {
548 DWORD len;
549
550 DPRINT("(%s, %p, %p): stub\n", hostname, computername, size);
551
552 if (!hostname || !size) return FALSE;
553 len = lstrlenW(hostname);
554
555 if (len > MAX_COMPUTERNAME_LENGTH)
556 len = MAX_COMPUTERNAME_LENGTH;
557
558 if (*size < len)
559 {
560 *size = len;
561 return FALSE;
562 }
563 if (!computername) return FALSE;
564
565 memcpy(computername, hostname, len * sizeof(WCHAR));
566 computername[len + 1] = 0;
567 return TRUE;
568 }
569
570 DWORD
571 WINAPI
572 AddLocalAlternateComputerNameA(LPSTR lpName, PNTSTATUS Status)
573 {
574 STUB;
575 return 0;
576 }
577
578 DWORD
579 WINAPI
580 AddLocalAlternateComputerNameW(LPWSTR lpName, PNTSTATUS Status)
581 {
582 STUB;
583 return 0;
584 }
585
586 DWORD
587 WINAPI
588 EnumerateLocalComputerNamesA(PVOID pUnknown, DWORD Size, LPSTR lpBuffer, LPDWORD lpnSize)
589 {
590 STUB;
591 return ERROR_CALL_NOT_IMPLEMENTED;
592 }
593
594 DWORD
595 WINAPI
596 EnumerateLocalComputerNamesW(PVOID pUnknown, DWORD Size, LPWSTR lpBuffer, LPDWORD lpnSize)
597 {
598 STUB;
599 return ERROR_CALL_NOT_IMPLEMENTED;
600 }
601
602 DWORD
603 WINAPI
604 RemoveLocalAlternateComputerNameA(LPSTR lpName, DWORD Unknown)
605 {
606 STUB;
607 return ERROR_CALL_NOT_IMPLEMENTED;
608 }
609
610 DWORD
611 WINAPI
612 RemoveLocalAlternateComputerNameW(LPWSTR lpName, DWORD Unknown)
613 {
614 STUB;
615 return ERROR_CALL_NOT_IMPLEMENTED;
616 }
617
618 /*
619 * @unimplemented
620 */
621 BOOL
622 WINAPI
623 SetLocalPrimaryComputerNameA(IN DWORD Unknown1,
624 IN DWORD Unknown2)
625 {
626 STUB;
627 return FALSE;
628 }
629
630 /*
631 * @unimplemented
632 */
633 BOOL
634 WINAPI
635 SetLocalPrimaryComputerNameW(IN DWORD Unknown1,
636 IN DWORD Unknown2)
637 {
638 STUB;
639 return FALSE;
640 }
641
642
643 /* EOF */