SHGetFileInfo should tolerate null pointers.
[wine] / dlls / netapi32 / wksta.c
1 /*
2  * Copyright 2002 Andriy Palamarchuk
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdlib.h>
22 #include "winbase.h"
23 #include "nb30.h"
24 #include "lmcons.h"
25 #include "lmapibuf.h"
26 #include "lmerr.h"
27 #include "lmwksta.h"
28 #include "iphlpapi.h"
29 #include "winerror.h"
30 #include "winternl.h"
31 #include "ntsecapi.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
35
36 /************************************************************
37  *                NETAPI_IsLocalComputer
38  *
39  * Checks whether the server name indicates local machine.
40  */
41 BOOL NETAPI_IsLocalComputer(LPCWSTR ServerName)
42 {
43     if (!ServerName)
44     {
45         return TRUE;
46     }
47     else
48     {
49         DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
50         BOOL Result;
51         LPWSTR buf;
52
53         NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) &buf);
54         Result = GetComputerNameW(buf,  &dwSize);
55         if (Result && (ServerName[0] == '\\') && (ServerName[1] == '\\'))
56             ServerName += 2;
57         Result = Result && !lstrcmpW(ServerName, buf);
58         NetApiBufferFree(buf);
59
60         return Result;
61     }
62 }
63
64 static void wprint_mac(WCHAR* buffer, PIP_ADAPTER_INFO adapter)
65 {
66   if (adapter != NULL)
67     {
68       int i;
69       unsigned char  val;
70
71       for (i = 0; i<max(adapter->AddressLength, 6); i++)
72         {
73           val = adapter->Address[i];
74           if ((val >>4) >9)
75             buffer[2*i] = (WCHAR)((val >>4) + 'A' - 10);
76           else
77             buffer[2*i] = (WCHAR)((val >>4) + '0');
78           if ((val & 0xf ) >9)
79             buffer[2*i+1] = (WCHAR)((val & 0xf) + 'A' - 10);
80           else
81             buffer[2*i+1] = (WCHAR)((val & 0xf) + '0');
82         }
83       buffer[12]=(WCHAR)0;
84     }
85   else
86     buffer[0] = 0;
87 }
88
89 #define TRANSPORT_NAME_HEADER "\\Device\\NetBT_Tcpip_"
90 #define TRANSPORT_NAME_LEN \
91  (sizeof(TRANSPORT_NAME_HEADER) + MAX_ADAPTER_NAME_LENGTH)
92
93 static void wprint_name(WCHAR *buffer, int len, PIP_ADAPTER_INFO adapter)
94 {
95   WCHAR *ptr;
96   const char *name;
97
98   if (!buffer)
99     return;
100   if (!adapter)
101     return;
102
103   for (ptr = buffer, name = TRANSPORT_NAME_HEADER; *name && ptr < buffer + len;
104    ptr++, name++)
105     *ptr = *name;
106   for (name = adapter->AdapterName; name && *name && ptr < buffer + len;
107    ptr++, name++)
108     *ptr = *name;
109   *ptr = '\0';
110 }
111
112 NET_API_STATUS WINAPI 
113 NetWkstaTransportEnum(LPCWSTR ServerName, DWORD level, LPBYTE* pbuf,
114                       DWORD prefmaxlen, LPDWORD read_entries,
115                       LPDWORD total_entries, LPDWORD hresume)
116 {
117   FIXME(":%s, 0x%08lx, %p, 0x%08lx, %p, %p, %p\n", debugstr_w(ServerName), 
118         level, pbuf, prefmaxlen, read_entries, total_entries,hresume);
119   if (!NETAPI_IsLocalComputer(ServerName))
120     {
121       FIXME(":not implemented for non-local computers\n");
122       return ERROR_INVALID_LEVEL;
123     }
124   else
125     {
126       if (hresume && *hresume)
127         {
128           FIXME(":resume handle not implemented\n");
129           return ERROR_INVALID_LEVEL;
130         }
131         
132       switch (level)
133         {
134         case 0: /* transport info */
135           {
136             PWKSTA_TRANSPORT_INFO_0 ti;
137             int i,size_needed,n_adapt;
138             DWORD apiReturn, adaptInfoSize = 0;
139             PIP_ADAPTER_INFO info, ptr;
140             
141             apiReturn = GetAdaptersInfo(NULL, &adaptInfoSize);
142             if (apiReturn == ERROR_NO_DATA)
143               return ERROR_NETWORK_UNREACHABLE;
144             if (!read_entries)
145               return STATUS_ACCESS_VIOLATION;
146             if (!total_entries || !pbuf)
147               return RPC_X_NULL_REF_POINTER;
148
149             info = (PIP_ADAPTER_INFO)malloc(adaptInfoSize);
150             apiReturn = GetAdaptersInfo(info, &adaptInfoSize);
151             if (apiReturn != NO_ERROR)
152               {
153                 free(info);
154                 return apiReturn;
155               }
156
157             for (n_adapt = 0, ptr = info; ptr; ptr = ptr->Next)
158               n_adapt++;
159             size_needed = n_adapt * (sizeof(WKSTA_TRANSPORT_INFO_0) 
160              + n_adapt * TRANSPORT_NAME_LEN * sizeof (WCHAR)
161              + n_adapt * 13 * sizeof (WCHAR));
162             if (prefmaxlen == MAX_PREFERRED_LENGTH)
163               NetApiBufferAllocate( size_needed, (LPVOID *) pbuf);
164             else
165               {
166                 if (size_needed > prefmaxlen)
167                   {
168                     free(info);
169                     return ERROR_MORE_DATA;
170                   }
171                 NetApiBufferAllocate(prefmaxlen,
172                                      (LPVOID *) pbuf);
173               }
174             for (i = 0, ptr = info; ptr; ptr = ptr->Next, i++)
175               {
176                 ti = (PWKSTA_TRANSPORT_INFO_0) 
177                   ((PBYTE) *pbuf + i * sizeof(WKSTA_TRANSPORT_INFO_0));
178                 ti->wkti0_quality_of_service=0;
179                 ti->wkti0_number_of_vcs=0;
180                 ti->wkti0_transport_name= (LPWSTR)
181                   ((PBYTE )*pbuf +
182                    n_adapt * sizeof(WKSTA_TRANSPORT_INFO_0)
183                    + i * TRANSPORT_NAME_LEN * sizeof (WCHAR));
184                 wprint_name(ti->wkti0_transport_name,TRANSPORT_NAME_LEN, ptr);
185                 ti->wkti0_transport_address= (LPWSTR)
186                   ((PBYTE )*pbuf +
187                    n_adapt * sizeof(WKSTA_TRANSPORT_INFO_0) +
188                    n_adapt * TRANSPORT_NAME_LEN * sizeof (WCHAR)
189                    + i * 13 * sizeof (WCHAR));
190                 ti->wkti0_wan_ish=TRUE; /*TCPIP/NETBIOS Protocoll*/
191                 wprint_mac(ti->wkti0_transport_address, ptr);
192                 TRACE("%d of %d:ti at %p transport_address at %p %s\n",i,n_adapt,
193                       ti, ti->wkti0_transport_address, debugstr_w(ti->wkti0_transport_address));
194               }
195             *read_entries = n_adapt;
196             *total_entries = n_adapt;
197             free(info);
198             if(hresume) *hresume= 0;
199             break;
200           }
201         default:
202           ERR("Invalid level %ld is specified\n", level);
203           return ERROR_INVALID_LEVEL;
204         }
205       return NERR_Success;
206     }
207 }
208                                             
209
210 /************************************************************
211  *                NetWkstaUserGetInfo  (NETAPI32.@)
212  */
213 NET_API_STATUS WINAPI NetWkstaUserGetInfo(LPWSTR reserved, DWORD level,
214                                           PBYTE* bufptr)
215 {
216     TRACE("(%s, %ld, %p)\n", debugstr_w(reserved), level, bufptr);
217     switch (level)
218     {
219     case 0:
220     {
221         PWKSTA_USER_INFO_0 ui;
222         DWORD dwSize = UNLEN + 1;
223
224         /* set up buffer */
225         NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_0) + dwSize * sizeof(WCHAR),
226                              (LPVOID *) bufptr);
227
228         ui = (PWKSTA_USER_INFO_0) *bufptr;
229         ui->wkui0_username = (LPWSTR) (*bufptr + sizeof(WKSTA_USER_INFO_0));
230
231         /* get data */
232         if (!GetUserNameW(ui->wkui0_username, &dwSize))
233         {
234             NetApiBufferFree(ui);
235             return ERROR_NOT_ENOUGH_MEMORY;
236         }
237         else
238             NetApiBufferReallocate(
239                 *bufptr, sizeof(WKSTA_USER_INFO_0) +
240                 (lstrlenW(ui->wkui0_username) + 1) * sizeof(WCHAR),
241                 (LPVOID *) bufptr);
242         break;
243     }
244
245     case 1:
246     {
247         PWKSTA_USER_INFO_1 ui;
248         PWKSTA_USER_INFO_0 ui0;
249         DWORD dwSize;
250         LSA_OBJECT_ATTRIBUTES ObjectAttributes;
251         LSA_HANDLE PolicyHandle;
252         PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo;
253         NTSTATUS NtStatus;
254
255         /* sizes of the field buffers in WCHARS */
256         int username_sz, logon_domain_sz, oth_domains_sz, logon_server_sz;
257
258         FIXME("Level 1 processing is partially implemented\n");
259         oth_domains_sz = 1;
260         logon_server_sz = 1;
261
262         /* get some information first to estimate size of the buffer */
263         ui0 = NULL;
264         NetWkstaUserGetInfo(NULL, 0, (PBYTE *) &ui0);
265         username_sz = lstrlenW(ui0->wkui0_username) + 1;
266
267         ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
268         NtStatus = LsaOpenPolicy(NULL, &ObjectAttributes,
269                                  POLICY_VIEW_LOCAL_INFORMATION,
270                                  &PolicyHandle);
271         if (NtStatus != STATUS_SUCCESS)
272         {
273             ERR("LsaOpenPolicyFailed with NT status %lx\n",
274                 LsaNtStatusToWinError(NtStatus));
275             NetApiBufferFree(ui0);
276             return ERROR_NOT_ENOUGH_MEMORY;
277         }
278         LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation,
279                                   (PVOID*) &DomainInfo);
280         logon_domain_sz = lstrlenW(DomainInfo->DomainName.Buffer) + 1;
281         LsaClose(PolicyHandle);
282
283         /* set up buffer */
284         NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_1) +
285                              (username_sz + logon_domain_sz +
286                               oth_domains_sz + logon_server_sz) * sizeof(WCHAR),
287                              (LPVOID *) bufptr);
288         ui = (WKSTA_USER_INFO_1 *) *bufptr;
289         ui->wkui1_username = (LPWSTR) (*bufptr + sizeof(WKSTA_USER_INFO_1));
290         ui->wkui1_logon_domain = (LPWSTR) (
291             ((PBYTE) ui->wkui1_username) + username_sz * sizeof(WCHAR));
292         ui->wkui1_oth_domains = (LPWSTR) (
293             ((PBYTE) ui->wkui1_logon_domain) +
294             logon_domain_sz * sizeof(WCHAR));
295         ui->wkui1_logon_server = (LPWSTR) (
296             ((PBYTE) ui->wkui1_oth_domains) +
297             oth_domains_sz * sizeof(WCHAR));
298
299         /* get data */
300         dwSize = username_sz;
301         lstrcpyW(ui->wkui1_username, ui0->wkui0_username);
302         NetApiBufferFree(ui0);
303
304         lstrcpynW(ui->wkui1_logon_domain, DomainInfo->DomainName.Buffer,
305                 logon_domain_sz);
306         LsaFreeMemory(DomainInfo);
307
308         /* FIXME. Not implemented. Populated with empty strings */
309         ui->wkui1_oth_domains[0] = 0;
310         ui->wkui1_logon_server[0] = 0;
311         break;
312     }
313     case 1101:
314     {
315         PWKSTA_USER_INFO_1101 ui;
316         DWORD dwSize = 1;
317
318         FIXME("Stub. Level 1101 processing is not implemented\n");
319         /* FIXME see also wkui1_oth_domains for level 1 */
320
321         /* set up buffer */
322         NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_1101) + dwSize * sizeof(WCHAR),
323                              (LPVOID *) bufptr);
324
325         ui = (PWKSTA_USER_INFO_1101) *bufptr;
326         ui->wkui1101_oth_domains = (LPWSTR)(ui + 1);
327
328         /* get data */
329         ui->wkui1101_oth_domains[0] = 0;
330         break;
331     }
332     default:
333         ERR("Invalid level %ld is specified\n", level);
334         return ERROR_INVALID_LEVEL;
335     }
336     return NERR_Success;
337 }
338
339 /************************************************************
340  *                NetpGetComputerName  (NETAPI32.@)
341  */
342 NET_API_STATUS WINAPI NetpGetComputerName(LPWSTR *Buffer)
343 {
344     DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
345
346     TRACE("(%p)\n", Buffer);
347     NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) Buffer);
348     if (GetComputerNameW(*Buffer,  &dwSize))
349     {
350         NetApiBufferReallocate(
351             *Buffer, dwSize * sizeof(WCHAR),
352             (LPVOID *) Buffer);
353         return NERR_Success;
354     }
355     else
356     {
357         NetApiBufferFree(*Buffer);
358         return ERROR_NOT_ENOUGH_MEMORY;
359     }
360 }