Sync with trunk rev.61910 to get latest improvements and bugfixes.
[reactos.git] / dll / win32 / netapi32 / wksta.c
1 /* Copyright 2002 Andriy Palamarchuk
2 * Copyright (c) 2003 Juan Lang
3 *
4 * netapi32 user functions
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "netapi32.h"
22
23 #include <lmwksta.h>
24 #include <lmjoin.h>
25
26 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
27
28 /************************************************************
29 * NETAPI_IsLocalComputer
30 *
31 * Checks whether the server name indicates local machine.
32 */
33 BOOL NETAPI_IsLocalComputer(LMCSTR ServerName)
34 {
35 if (!ServerName)
36 {
37 return TRUE;
38 }
39 else if (ServerName[0] == '\0')
40 return TRUE;
41 else
42 {
43 DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
44 BOOL Result;
45 LPWSTR buf;
46
47 NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) &buf);
48 Result = GetComputerNameW(buf, &dwSize);
49 if (Result && (ServerName[0] == '\\') && (ServerName[1] == '\\'))
50 ServerName += 2;
51 Result = Result && !lstrcmpW(ServerName, buf);
52 NetApiBufferFree(buf);
53
54 return Result;
55 }
56 }
57
58 static void wprint_mac(WCHAR* buffer, int len, const MIB_IFROW *ifRow)
59 {
60 int i;
61 unsigned char val;
62
63 if (!buffer)
64 return;
65 if (len < 1)
66 return;
67 if (!ifRow)
68 {
69 *buffer = '\0';
70 return;
71 }
72
73 for (i = 0; i < ifRow->dwPhysAddrLen && 2 * i < len; i++)
74 {
75 val = ifRow->bPhysAddr[i];
76 if ((val >>4) >9)
77 buffer[2*i] = (WCHAR)((val >>4) + 'A' - 10);
78 else
79 buffer[2*i] = (WCHAR)((val >>4) + '0');
80 if ((val & 0xf ) >9)
81 buffer[2*i+1] = (WCHAR)((val & 0xf) + 'A' - 10);
82 else
83 buffer[2*i+1] = (WCHAR)((val & 0xf) + '0');
84 }
85 buffer[2*i]=0;
86 }
87
88 /* Theoretically this could be too short, except that MS defines
89 * MAX_ADAPTER_NAME as 128, and MAX_INTERFACE_NAME_LEN as 256, and both
90 * represent a count of WCHARs, so even with an extraordinarily long header
91 * this will be plenty
92 */
93 #define MAX_TRANSPORT_NAME MAX_INTERFACE_NAME_LEN
94 #define MAX_TRANSPORT_ADDR 13
95
96 #define NBT_TRANSPORT_NAME_HEADER "\\Device\\NetBT_Tcpip_"
97 #define UNKNOWN_TRANSPORT_NAME_HEADER "\\Device\\UnknownTransport_"
98
99 static void wprint_name(WCHAR *buffer, int len, ULONG transport,
100 PMIB_IFROW ifRow)
101 {
102 WCHAR *ptr1, *ptr2;
103 const char *name;
104
105 if (!buffer)
106 return;
107 if (!ifRow)
108 {
109 *buffer = '\0';
110 return;
111 }
112
113 if (!memcmp(&transport, TRANSPORT_NBT, sizeof(ULONG)))
114 name = NBT_TRANSPORT_NAME_HEADER;
115 else
116 name = UNKNOWN_TRANSPORT_NAME_HEADER;
117
118 for (ptr1 = buffer; *name && ptr1 < buffer + len; ptr1++, name++)
119 *ptr1 = *name;
120 for (ptr2 = ifRow->wszName; *ptr2 && ptr1 < buffer + len; ptr1++, ptr2++)
121 *ptr1 = *ptr2;
122 *ptr1 = '\0';
123 }
124
125 /***********************************************************************
126 * NetWkstaTransportEnum (NETAPI32.@)
127 */
128
129 struct WkstaTransportEnumData
130 {
131 UCHAR n_adapt;
132 UCHAR n_read;
133 DWORD prefmaxlen;
134 LPBYTE *pbuf;
135 NET_API_STATUS ret;
136 };
137
138 /**********************************************************************/
139
140 static BOOL WkstaEnumAdaptersCallback(UCHAR totalLANAs, UCHAR lanaIndex,
141 ULONG transport, const NetBIOSAdapterImpl *data, void *closure)
142 {
143 BOOL ret;
144 struct WkstaTransportEnumData *enumData = closure;
145
146 if (enumData && enumData->pbuf)
147 {
148 if (lanaIndex == 0)
149 {
150 DWORD toAllocate;
151
152 enumData->n_adapt = totalLANAs;
153 enumData->n_read = 0;
154
155 toAllocate = totalLANAs * (sizeof(WKSTA_TRANSPORT_INFO_0)
156 + MAX_TRANSPORT_NAME * sizeof(WCHAR) +
157 MAX_TRANSPORT_ADDR * sizeof(WCHAR));
158 if (enumData->prefmaxlen != MAX_PREFERRED_LENGTH)
159 toAllocate = enumData->prefmaxlen;
160 NetApiBufferAllocate(toAllocate, (LPVOID *)enumData->pbuf);
161 }
162 if (*(enumData->pbuf))
163 {
164 UCHAR spaceFor;
165
166 if (enumData->prefmaxlen == MAX_PREFERRED_LENGTH)
167 spaceFor = totalLANAs;
168 else
169 spaceFor = enumData->prefmaxlen /
170 (sizeof(WKSTA_TRANSPORT_INFO_0) + (MAX_TRANSPORT_NAME +
171 MAX_TRANSPORT_ADDR) * sizeof(WCHAR));
172 if (enumData->n_read < spaceFor)
173 {
174 PWKSTA_TRANSPORT_INFO_0 ti;
175 LMSTR transport_name, transport_addr;
176 MIB_IFROW ifRow;
177
178 ti = (PWKSTA_TRANSPORT_INFO_0)(*(enumData->pbuf) +
179 enumData->n_read * sizeof(WKSTA_TRANSPORT_INFO_0));
180 transport_name = (LMSTR)(*(enumData->pbuf) +
181 totalLANAs * sizeof(WKSTA_TRANSPORT_INFO_0) +
182 enumData->n_read * MAX_TRANSPORT_NAME * sizeof(WCHAR));
183 transport_addr = (LMSTR)(*(enumData->pbuf) +
184 totalLANAs * (sizeof(WKSTA_TRANSPORT_INFO_0) +
185 MAX_TRANSPORT_NAME * sizeof(WCHAR)) +
186 enumData->n_read * MAX_TRANSPORT_ADDR * sizeof(WCHAR));
187
188 ifRow.dwIndex = data->ifIndex;
189 GetIfEntry(&ifRow);
190 ti->wkti0_quality_of_service = 0;
191 ti->wkti0_number_of_vcs = 0;
192 ti->wkti0_transport_name = transport_name;
193 wprint_name(ti->wkti0_transport_name, MAX_TRANSPORT_NAME,
194 transport, &ifRow);
195 ti->wkti0_transport_address = transport_addr;
196 wprint_mac(ti->wkti0_transport_address, MAX_TRANSPORT_ADDR,
197 &ifRow);
198 if (!memcmp(&transport, TRANSPORT_NBT, sizeof(ULONG)))
199 ti->wkti0_wan_ish = TRUE;
200 else
201 ti->wkti0_wan_ish = FALSE;
202 TRACE("%d of %d:ti at %p\n", lanaIndex, totalLANAs, ti);
203 TRACE("transport_name at %p %s\n",
204 ti->wkti0_transport_name,
205 debugstr_w(ti->wkti0_transport_name));
206 TRACE("transport_address at %p %s\n",
207 ti->wkti0_transport_address,
208 debugstr_w(ti->wkti0_transport_address));
209 enumData->n_read++;
210 enumData->ret = NERR_Success;
211 ret = TRUE;
212 }
213 else
214 {
215 enumData->ret = ERROR_MORE_DATA;
216 ret = FALSE;
217 }
218 }
219 else
220 {
221 enumData->ret = ERROR_OUTOFMEMORY;
222 ret = FALSE;
223 }
224 }
225 else
226 ret = FALSE;
227 return ret;
228 }
229
230 /**********************************************************************/
231
232 NET_API_STATUS WINAPI
233 NetWkstaTransportEnum(LMSTR ServerName, DWORD level, PBYTE* pbuf,
234 DWORD prefmaxlen, LPDWORD read_entries,
235 PDWORD total_entries, PDWORD hresume)
236 {
237 NET_API_STATUS ret;
238
239 TRACE(":%s, 0x%08x, %p, 0x%08x, %p, %p, %p\n", debugstr_w(ServerName),
240 level, pbuf, prefmaxlen, read_entries, total_entries,hresume);
241 if (!NETAPI_IsLocalComputer(ServerName))
242 {
243 FIXME(":not implemented for non-local computers\n");
244 ret = ERROR_INVALID_LEVEL;
245 }
246 else
247 {
248 if (hresume && *hresume)
249 {
250 FIXME(":resume handle not implemented\n");
251 return ERROR_INVALID_LEVEL;
252 }
253
254 switch (level)
255 {
256 case 0: /* transport info */
257 {
258 ULONG allTransports;
259 struct WkstaTransportEnumData enumData;
260
261 if (NetBIOSNumAdapters() == 0)
262 return ERROR_NETWORK_UNREACHABLE;
263 if (!read_entries)
264 return STATUS_ACCESS_VIOLATION;
265 if (!total_entries || !pbuf)
266 return RPC_X_NULL_REF_POINTER;
267
268 enumData.prefmaxlen = prefmaxlen;
269 enumData.pbuf = pbuf;
270 memcpy(&allTransports, ALL_TRANSPORTS, sizeof(ULONG));
271 NetBIOSEnumAdapters(allTransports, WkstaEnumAdaptersCallback,
272 &enumData);
273 *read_entries = enumData.n_read;
274 *total_entries = enumData.n_adapt;
275 if (hresume) *hresume= 0;
276 ret = enumData.ret;
277 break;
278 }
279 default:
280 TRACE("Invalid level %d is specified\n", level);
281 ret = ERROR_INVALID_LEVEL;
282 }
283 }
284 return ret;
285 }
286
287
288 /************************************************************
289 * NetWkstaUserGetInfo (NETAPI32.@)
290 */
291 NET_API_STATUS WINAPI NetWkstaUserGetInfo(LMSTR reserved, DWORD level,
292 PBYTE* bufptr)
293 {
294 NET_API_STATUS nastatus;
295
296 TRACE("(%s, %d, %p)\n", debugstr_w(reserved), level, bufptr);
297 switch (level)
298 {
299 case 0:
300 {
301 PWKSTA_USER_INFO_0 ui;
302 DWORD dwSize = UNLEN + 1;
303
304 /* set up buffer */
305 nastatus = NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_0) + dwSize * sizeof(WCHAR),
306 (LPVOID *) bufptr);
307 if (nastatus != NERR_Success)
308 return ERROR_NOT_ENOUGH_MEMORY;
309
310 ui = (PWKSTA_USER_INFO_0) *bufptr;
311 ui->wkui0_username = (LMSTR) (*bufptr + sizeof(WKSTA_USER_INFO_0));
312
313 /* get data */
314 if (!GetUserNameW(ui->wkui0_username, &dwSize))
315 {
316 NetApiBufferFree(ui);
317 return ERROR_NOT_ENOUGH_MEMORY;
318 }
319 else {
320 nastatus = NetApiBufferReallocate(
321 *bufptr, sizeof(WKSTA_USER_INFO_0) +
322 (lstrlenW(ui->wkui0_username) + 1) * sizeof(WCHAR),
323 (LPVOID *) bufptr);
324 if (nastatus != NERR_Success)
325 return nastatus;
326 }
327 break;
328 }
329
330 case 1:
331 {
332 PWKSTA_USER_INFO_1 ui;
333 PWKSTA_USER_INFO_0 ui0;
334 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
335 LSA_HANDLE PolicyHandle;
336 PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo;
337 NTSTATUS NtStatus;
338
339 /* sizes of the field buffers in WCHARS */
340 int username_sz, logon_domain_sz, oth_domains_sz, logon_server_sz;
341
342 FIXME("Level 1 processing is partially implemented\n");
343 oth_domains_sz = 1;
344 logon_server_sz = 1;
345
346 /* get some information first to estimate size of the buffer */
347 ui0 = NULL;
348 nastatus = NetWkstaUserGetInfo(NULL, 0, (PBYTE *) &ui0);
349 if (nastatus != NERR_Success)
350 return nastatus;
351 username_sz = lstrlenW(ui0->wkui0_username) + 1;
352
353 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
354 NtStatus = LsaOpenPolicy(NULL, &ObjectAttributes,
355 POLICY_VIEW_LOCAL_INFORMATION,
356 &PolicyHandle);
357 if (NtStatus != STATUS_SUCCESS)
358 {
359 TRACE("LsaOpenPolicyFailed with NT status %x\n",
360 LsaNtStatusToWinError(NtStatus));
361 NetApiBufferFree(ui0);
362 return ERROR_NOT_ENOUGH_MEMORY;
363 }
364 LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation,
365 (PVOID*) &DomainInfo);
366 logon_domain_sz = lstrlenW(DomainInfo->DomainName.Buffer) + 1;
367 LsaClose(PolicyHandle);
368
369 /* set up buffer */
370 nastatus = NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_1) +
371 (username_sz + logon_domain_sz +
372 oth_domains_sz + logon_server_sz) * sizeof(WCHAR),
373 (LPVOID *) bufptr);
374 if (nastatus != NERR_Success) {
375 NetApiBufferFree(ui0);
376 return nastatus;
377 }
378 ui = (WKSTA_USER_INFO_1 *) *bufptr;
379 ui->wkui1_username = (LMSTR) (*bufptr + sizeof(WKSTA_USER_INFO_1));
380 ui->wkui1_logon_domain = (LMSTR) (
381 ((PBYTE) ui->wkui1_username) + username_sz * sizeof(WCHAR));
382 ui->wkui1_oth_domains = (LMSTR) (
383 ((PBYTE) ui->wkui1_logon_domain) +
384 logon_domain_sz * sizeof(WCHAR));
385 ui->wkui1_logon_server = (LMSTR) (
386 ((PBYTE) ui->wkui1_oth_domains) +
387 oth_domains_sz * sizeof(WCHAR));
388
389 /* get data */
390 lstrcpyW(ui->wkui1_username, ui0->wkui0_username);
391 NetApiBufferFree(ui0);
392
393 lstrcpynW(ui->wkui1_logon_domain, DomainInfo->DomainName.Buffer,
394 logon_domain_sz);
395 LsaFreeMemory(DomainInfo);
396
397 /* FIXME. Not implemented. Populated with empty strings */
398 ui->wkui1_oth_domains[0] = 0;
399 ui->wkui1_logon_server[0] = 0;
400 break;
401 }
402 case 1101:
403 {
404 PWKSTA_USER_INFO_1101 ui;
405 DWORD dwSize = 1;
406
407 FIXME("Stub. Level 1101 processing is not implemented\n");
408 /* FIXME see also wkui1_oth_domains for level 1 */
409
410 /* set up buffer */
411 nastatus = NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_1101) + dwSize * sizeof(WCHAR),
412 (LPVOID *) bufptr);
413 if (nastatus != NERR_Success)
414 return nastatus;
415 ui = (PWKSTA_USER_INFO_1101) *bufptr;
416 ui->wkui1101_oth_domains = (LMSTR)(ui + 1);
417
418 /* get data */
419 ui->wkui1101_oth_domains[0] = 0;
420 break;
421 }
422 default:
423 TRACE("Invalid level %d is specified\n", level);
424 return ERROR_INVALID_LEVEL;
425 }
426 return NERR_Success;
427 }
428
429 /************************************************************
430 * NetWkstaUserEnum (NETAPI32.@)
431 */
432 NET_API_STATUS WINAPI
433 NetWkstaUserEnum(LMSTR servername, DWORD level, LPBYTE* bufptr,
434 DWORD prefmaxlen, LPDWORD entriesread,
435 LPDWORD totalentries, LPDWORD resumehandle)
436 {
437 FIXME("(%s, %d, %p, %d, %p, %p, %p): stub!\n", debugstr_w(servername),
438 level, bufptr, prefmaxlen, entriesread, totalentries, resumehandle);
439 return ERROR_INVALID_PARAMETER;
440 }
441
442 /************************************************************
443 * NetpGetComputerName (NETAPI32.@)
444 */
445 NET_API_STATUS WINAPI NetpGetComputerName(LPWSTR *Buffer)
446 {
447 DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
448
449 TRACE("(%p)\n", Buffer);
450 NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) Buffer);
451 if (GetComputerNameW(*Buffer, &dwSize))
452 {
453 return NetApiBufferReallocate(
454 *Buffer, (dwSize + 1) * sizeof(WCHAR),
455 (LPVOID *) Buffer);
456 }
457 else
458 {
459 NetApiBufferFree(*Buffer);
460 return ERROR_NOT_ENOUGH_MEMORY;
461 }
462 }
463
464 NET_API_STATUS WINAPI I_NetNameCompare(LPVOID p1, LPWSTR wkgrp, LPWSTR comp,
465 LPVOID p4, LPVOID p5)
466 {
467 FIXME("(%p %s %s %p %p): stub\n", p1, debugstr_w(wkgrp), debugstr_w(comp),
468 p4, p5);
469 return ERROR_INVALID_PARAMETER;
470 }
471
472 NET_API_STATUS WINAPI I_NetNameValidate(LPVOID p1, LPWSTR wkgrp, LPVOID p3,
473 LPVOID p4)
474 {
475 FIXME("(%p %s %p %p): stub\n", p1, debugstr_w(wkgrp), p3, p4);
476 return ERROR_INVALID_PARAMETER;
477 }
478
479 NET_API_STATUS WINAPI NetWkstaGetInfo( LMSTR servername, DWORD level,
480 LPBYTE* bufptr)
481 {
482 NET_API_STATUS ret;
483
484 TRACE("%s %d %p\n", debugstr_w( servername ), level, bufptr );
485 if (servername)
486 {
487 if (!NETAPI_IsLocalComputer(servername))
488 {
489 FIXME("remote computers not supported\n");
490 return ERROR_INVALID_LEVEL;
491 }
492 }
493 if (!bufptr) return ERROR_INVALID_PARAMETER;
494
495 switch (level)
496 {
497 case 100:
498 case 101:
499 case 102:
500 {
501 static const WCHAR lanroot[] = {'c',':','\\','l','a','n','m','a','n',0}; /* FIXME */
502 DWORD computerNameLen, domainNameLen, size;
503 WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1];
504 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
505 LSA_HANDLE PolicyHandle;
506 NTSTATUS NtStatus;
507
508 computerNameLen = MAX_COMPUTERNAME_LENGTH + 1;
509 GetComputerNameW(computerName, &computerNameLen);
510 computerNameLen++; /* include NULL terminator */
511
512 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
513 NtStatus = LsaOpenPolicy(NULL, &ObjectAttributes,
514 POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
515 if (NtStatus != STATUS_SUCCESS)
516 ret = LsaNtStatusToWinError(NtStatus);
517 else
518 {
519 PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo;
520
521 LsaQueryInformationPolicy(PolicyHandle,
522 PolicyAccountDomainInformation, (PVOID*)&DomainInfo);
523 domainNameLen = lstrlenW(DomainInfo->DomainName.Buffer) + 1;
524 size = sizeof(WKSTA_INFO_102) + computerNameLen * sizeof(WCHAR)
525 + domainNameLen * sizeof(WCHAR) + sizeof(lanroot);
526 ret = NetApiBufferAllocate(size, (LPVOID *)bufptr);
527 if (ret == NERR_Success)
528 {
529 /* INFO_100 and INFO_101 structures are subsets of INFO_102 */
530 PWKSTA_INFO_102 info = (PWKSTA_INFO_102)*bufptr;
531 OSVERSIONINFOW verInfo;
532
533 info->wki102_platform_id = PLATFORM_ID_NT;
534 info->wki102_computername = (LMSTR)(*bufptr +
535 sizeof(WKSTA_INFO_102));
536 memcpy(info->wki102_computername, computerName,
537 computerNameLen * sizeof(WCHAR));
538 info->wki102_langroup = info->wki102_computername + computerNameLen;
539 memcpy(info->wki102_langroup, DomainInfo->DomainName.Buffer,
540 domainNameLen * sizeof(WCHAR));
541 info->wki102_lanroot = info->wki102_langroup + domainNameLen;
542 memcpy(info->wki102_lanroot, lanroot, sizeof(lanroot));
543 memset(&verInfo, 0, sizeof(verInfo));
544 verInfo.dwOSVersionInfoSize = sizeof(verInfo);
545 GetVersionExW(&verInfo);
546 info->wki102_ver_major = verInfo.dwMajorVersion;
547 info->wki102_ver_minor = verInfo.dwMinorVersion;
548 info->wki102_logged_on_users = 1;
549 }
550 LsaFreeMemory(DomainInfo);
551 LsaClose(PolicyHandle);
552 }
553 break;
554 }
555
556 default:
557 FIXME("level %d unimplemented\n", level);
558 ret = ERROR_INVALID_LEVEL;
559 }
560 return ret;
561 }
562
563 /************************************************************
564 * NetGetJoinInformation (NETAPI32.@)
565 */
566 NET_API_STATUS NET_API_FUNCTION NetGetJoinInformation(
567 LPCWSTR Server,
568 LPWSTR *Name,
569 PNETSETUP_JOIN_STATUS type)
570 {
571 FIXME("Stub %s %p %p\n", wine_dbgstr_w(Server), Name, type);
572
573 *Name = NULL;
574 *type = NetSetupUnknownStatus;
575
576 return NERR_Success;
577 }
578