xref: /reactos/dll/win32/mpr/wnet.c (revision 7930bed0)
1 /*
2  * MPR WNet functions
3  *
4  * Copyright 1999 Ulrich Weigand
5  * Copyright 2004 Juan Lang
6  * Copyright 2007 Maarten Lankhorst
7  * Copyright 2016-2018 Pierre Schweitzer
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winioctl.h"
29 #include "winnetwk.h"
30 #include "npapi.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #ifndef __REACTOS__
34 #define WINE_MOUNTMGR_EXTENSIONS
35 #include "ddk/mountmgr.h"
36 #endif
37 #include "wine/debug.h"
38 #include "mprres.h"
39 #include "wnetpriv.h"
40 #ifdef __REACTOS__
41 #include <wine/unicode.h>
42 #endif
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
45 
46 /* Data structures representing network service providers.  Assumes only one
47  * thread creates them, and that they are constant for the life of the process
48  * (and therefore doesn't synchronize access).
49  * FIXME: only basic provider data and enumeration-related data are implemented
50  * so far, need to implement the rest too.
51  */
52 typedef struct _WNetProvider
53 {
54     HMODULE           hLib;
55     PWSTR             name;
56     PF_NPGetCaps      getCaps;
57     DWORD             dwSpecVersion;
58     DWORD             dwNetType;
59     DWORD             dwEnumScopes;
60     PF_NPOpenEnum     openEnum;
61     PF_NPEnumResource enumResource;
62     PF_NPCloseEnum    closeEnum;
63     PF_NPGetResourceInformation getResourceInformation;
64     PF_NPAddConnection addConnection;
65     PF_NPAddConnection3 addConnection3;
66     PF_NPCancelConnection cancelConnection;
67 #ifdef __REACTOS__
68     PF_NPGetConnection getConnection;
69 #endif
70 } WNetProvider, *PWNetProvider;
71 
72 typedef struct _WNetProviderTable
73 {
74     LPWSTR           entireNetwork;
75     DWORD            numAllocated;
76     DWORD            numProviders;
77     WNetProvider     table[1];
78 } WNetProviderTable, *PWNetProviderTable;
79 
80 #define WNET_ENUMERATOR_TYPE_GLOBAL     0
81 #define WNET_ENUMERATOR_TYPE_PROVIDER   1
82 #define WNET_ENUMERATOR_TYPE_CONTEXT    2
83 #define WNET_ENUMERATOR_TYPE_CONNECTED  3
84 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
85 
86 /* An WNet enumerator.  Note that the type doesn't correspond to the scope of
87  * the enumeration; it represents one of the following types:
88  * - a global enumeration, one that's executed across all providers
89  * - a provider-specific enumeration, one that's only executed by a single
90  *   provider
91  * - a context enumeration.  I know this contradicts what I just said about
92  *   there being no correspondence between the scope and the type, but it's
93  *   necessary for the special case that a "Entire Network" entry needs to
94  *   be enumerated in an enumeration of the context scope.  Thus an enumeration
95  *   of the context scope results in a context type enumerator, which morphs
96  *   into a global enumeration (so the enumeration continues across all
97  *   providers).
98  * - a remembered enumeration, not related to providers themselves, but it
99  *   is a registry enumeration for saved connections
100  */
101 typedef struct _WNetEnumerator
102 {
103     DWORD          enumType;
104     DWORD          providerIndex;
105     HANDLE         handle;
106     BOOL           providerDone;
107     DWORD          dwScope;
108     DWORD          dwType;
109     DWORD          dwUsage;
110     union
111     {
112         NETRESOURCEW* net;
113         HANDLE* handles;
114         struct
115         {
116             HKEY registry;
117             DWORD index;
118         } remembered;
119     } specific;
120 } WNetEnumerator, *PWNetEnumerator;
121 
122 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
123 
124 /* Returns an index (into the global WNetProviderTable) of the provider with
125  * the given name, or BAD_PROVIDER_INDEX if not found.
126  */
127 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
128 
129 static PWNetProviderTable providerTable;
130 
131 /*
132  * Global provider table functions
133  */
134 
_tryLoadProvider(PCWSTR provider)135 static void _tryLoadProvider(PCWSTR provider)
136 {
137     static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
138      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
139      'S','e','r','v','i','c','e','s','\\',0 };
140     static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
141      'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
142     WCHAR serviceName[MAX_PATH];
143     HKEY hKey;
144 
145     TRACE("%s\n", debugstr_w(provider));
146     swprintf(serviceName, serviceFmt, servicePrefix, provider);
147     serviceName[ARRAY_SIZE(serviceName) - 1] = '\0';
148     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
149      ERROR_SUCCESS)
150     {
151         static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
152          'P','a','t','h',0 };
153         WCHAR providerPath[MAX_PATH];
154         DWORD type, size = sizeof(providerPath);
155 
156         if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
157          (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
158         {
159             static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
160             PWSTR name = NULL;
161 
162             if (type == REG_EXPAND_SZ)
163             {
164                 WCHAR path[MAX_PATH];
165                 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
166             }
167 
168             size = 0;
169             RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
170             if (size)
171             {
172                 name = HeapAlloc(GetProcessHeap(), 0, size);
173                 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
174                  (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
175                 {
176                     HeapFree(GetProcessHeap(), 0, name);
177                     name = NULL;
178                 }
179             }
180             if (name)
181             {
182                 HMODULE hLib = LoadLibraryW(providerPath);
183 
184                 if (hLib)
185                 {
186 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
187 
188                     PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
189 
190                     TRACE("loaded lib %p\n", hLib);
191                     if (getCaps)
192                     {
193                         DWORD connectCap;
194                         PWNetProvider provider =
195                          &providerTable->table[providerTable->numProviders];
196 
197                         provider->hLib = hLib;
198                         provider->name = name;
199                         TRACE("name is %s\n", debugstr_w(name));
200                         provider->getCaps = getCaps;
201                         provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
202                         provider->dwNetType = getCaps(WNNC_NET_TYPE);
203                         TRACE("net type is 0x%08x\n", provider->dwNetType);
204                         provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
205                         if (provider->dwEnumScopes)
206                         {
207                             TRACE("supports enumeration\n");
208                             provider->openEnum = MPR_GETPROC(NPOpenEnum);
209                             TRACE("NPOpenEnum %p\n", provider->openEnum);
210                             provider->enumResource = MPR_GETPROC(NPEnumResource);
211                             TRACE("NPEnumResource %p\n", provider->enumResource);
212                             provider->closeEnum = MPR_GETPROC(NPCloseEnum);
213                             TRACE("NPCloseEnum %p\n", provider->closeEnum);
214                             provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
215                             TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
216                             if (!provider->openEnum ||
217                                 !provider->enumResource ||
218                                 !provider->closeEnum)
219                             {
220                                 provider->openEnum = NULL;
221                                 provider->enumResource = NULL;
222                                 provider->closeEnum = NULL;
223                                 provider->dwEnumScopes = 0;
224                                 WARN("Couldn't load enumeration functions\n");
225                             }
226                         }
227                         connectCap = getCaps(WNNC_CONNECTION);
228                         if (connectCap & WNNC_CON_ADDCONNECTION)
229                             provider->addConnection = MPR_GETPROC(NPAddConnection);
230                         if (connectCap & WNNC_CON_ADDCONNECTION3)
231                             provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
232                         if (connectCap & WNNC_CON_CANCELCONNECTION)
233                             provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
234 #ifdef __REACTOS__
235                         if (connectCap & WNNC_CON_GETCONNECTIONS)
236                             provider->getConnection = MPR_GETPROC(NPGetConnection);
237 #endif
238                         TRACE("NPAddConnection %p\n", provider->addConnection);
239                         TRACE("NPAddConnection3 %p\n", provider->addConnection3);
240                         TRACE("NPCancelConnection %p\n", provider->cancelConnection);
241                         providerTable->numProviders++;
242                     }
243                     else
244                     {
245                         WARN("Provider %s didn't export NPGetCaps\n",
246                          debugstr_w(provider));
247                         HeapFree(GetProcessHeap(), 0, name);
248                         FreeLibrary(hLib);
249                     }
250 
251 #undef MPR_GETPROC
252                 }
253                 else
254                 {
255                     WARN("Couldn't load library %s for provider %s\n",
256                      debugstr_w(providerPath), debugstr_w(provider));
257                     HeapFree(GetProcessHeap(), 0, name);
258                 }
259             }
260             else
261             {
262                 WARN("Couldn't get provider name for provider %s\n",
263                  debugstr_w(provider));
264             }
265         }
266         else
267             WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
268         RegCloseKey(hKey);
269     }
270     else
271         WARN("Couldn't open service key for provider %s\n",
272          debugstr_w(provider));
273 }
274 
275 #ifdef __REACTOS__
_restoreSavedConnection(HKEY connection,WCHAR * local)276 static void _restoreSavedConnection(HKEY connection, WCHAR * local)
277 {
278     NETRESOURCEW net;
279     DWORD type, prov, index, size;
280 
281     net.lpProvider = NULL;
282     net.lpRemoteName = NULL;
283     net.lpLocalName = NULL;
284 
285     TRACE("Restoring: %S\n", local);
286 
287     size = sizeof(DWORD);
288     if (RegQueryValueExW(connection, L"ConnectionType", NULL, &type, (BYTE *)&net.dwType, &size) != ERROR_SUCCESS)
289        return;
290 
291     if (type != REG_DWORD || size != sizeof(DWORD))
292         return;
293 
294     if (RegQueryValueExW(connection, L"ProviderName", NULL, &type, NULL, &size) != ERROR_SUCCESS)
295         return;
296 
297     if (type != REG_SZ)
298         return;
299 
300     net.lpProvider = HeapAlloc(GetProcessHeap(), 0, size);
301     if (!net.lpProvider)
302         return;
303 
304     if (RegQueryValueExW(connection, L"ProviderName", NULL, NULL, (BYTE *)net.lpProvider, &size) != ERROR_SUCCESS)
305         goto cleanup;
306 
307     size = sizeof(DWORD);
308     if (RegQueryValueExW(connection, L"ProviderType", NULL, &type, (BYTE *)&prov, &size) != ERROR_SUCCESS)
309         goto cleanup;
310 
311     if (type != REG_DWORD || size != sizeof(DWORD))
312         goto cleanup;
313 
314     index = _findProviderIndexW(net.lpProvider);
315     if (index == BAD_PROVIDER_INDEX)
316         goto cleanup;
317 
318     if (providerTable->table[index].dwNetType != prov)
319         goto cleanup;
320 
321     if (RegQueryValueExW(connection, L"RemotePath", NULL, &type, NULL, &size) != ERROR_SUCCESS)
322         goto cleanup;
323 
324     if (type != REG_SZ)
325         goto cleanup;
326 
327     net.lpRemoteName = HeapAlloc(GetProcessHeap(), 0, size);
328     if (!net.lpRemoteName)
329         goto cleanup;
330 
331     if (RegQueryValueExW(connection, L"RemotePath", NULL, NULL, (BYTE *)net.lpRemoteName, &size) != ERROR_SUCCESS)
332         goto cleanup;
333 
334     size = strlenW(local);
335     net.lpLocalName = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR) + 2 * sizeof(WCHAR));
336     if (!net.lpLocalName)
337         goto cleanup;
338 
339     strcpyW(net.lpLocalName, local);
340     net.lpLocalName[size] = ':';
341     net.lpLocalName[size + 1] = 0;
342 
343     TRACE("Attempting connection\n");
344 
345     WNetAddConnection2W(&net, NULL, NULL, 0);
346 
347 cleanup:
348     HeapFree(GetProcessHeap(), 0, net.lpProvider);
349     HeapFree(GetProcessHeap(), 0, net.lpRemoteName);
350     HeapFree(GetProcessHeap(), 0, net.lpLocalName);
351 }
352 #endif
353 
wnetInit(HINSTANCE hInstDll)354 void wnetInit(HINSTANCE hInstDll)
355 {
356     static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
357      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
358      'C','o','n','t','r','o','l','\\',
359      'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
360      'O','r','d','e','r',0 };
361      static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
362       'O','r','d','e','r',0 };
363     HKEY hKey;
364 
365     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
366      == ERROR_SUCCESS)
367     {
368         DWORD size = 0;
369 
370         RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
371         if (size)
372         {
373             PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
374 
375             if (providers)
376             {
377                 DWORD type;
378 
379                 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
380                  (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
381                 {
382                     PWSTR ptr;
383                     DWORD numToAllocate;
384 
385                     TRACE("provider order is %s\n", debugstr_w(providers));
386                     /* first count commas as a heuristic for how many to
387                      * allocate space for */
388                     for (ptr = providers, numToAllocate = 1; ptr; )
389                     {
390                         ptr = wcschr(ptr, ',');
391                         if (ptr) {
392                             numToAllocate++;
393                             ptr++;
394                         }
395                     }
396                     providerTable =
397                      HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
398                      sizeof(WNetProviderTable)
399                      + (numToAllocate - 1) * sizeof(WNetProvider));
400                     if (providerTable)
401                     {
402                         PWSTR ptrPrev;
403                         int entireNetworkLen;
404                         LPCWSTR stringresource;
405 
406                         entireNetworkLen = LoadStringW(hInstDll,
407                          IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
408                         providerTable->entireNetwork = HeapAlloc(
409                          GetProcessHeap(), 0, (entireNetworkLen + 1) *
410                          sizeof(WCHAR));
411                         if (providerTable->entireNetwork)
412                         {
413                             memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
414                             providerTable->entireNetwork[entireNetworkLen] = 0;
415                         }
416                         providerTable->numAllocated = numToAllocate;
417                         for (ptr = providers; ptr; )
418                         {
419                             ptrPrev = ptr;
420                             ptr = wcschr(ptr, ',');
421                             if (ptr)
422                                 *ptr++ = '\0';
423                             _tryLoadProvider(ptrPrev);
424                         }
425                     }
426                 }
427                 HeapFree(GetProcessHeap(), 0, providers);
428             }
429         }
430         RegCloseKey(hKey);
431     }
432 
433 #ifdef __REACTOS__
434     if (providerTable)
435     {
436         HKEY user_profile;
437 
438         if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
439         {
440             HKEY network;
441             WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
442 
443             if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &network) == ERROR_SUCCESS)
444             {
445                 DWORD size, max;
446 
447                 TRACE("Enumerating remembered connections\n");
448 
449                 if (RegQueryInfoKey(network, NULL, NULL, NULL, &max, &size, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
450                 {
451                     WCHAR *local;
452 
453                     TRACE("There are %lu connections\n", max);
454 
455                     local = HeapAlloc(GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR));
456                     if (local)
457                     {
458                         DWORD index;
459 
460                         for (index = 0; index < max; ++index)
461                         {
462                             DWORD len = size + 1;
463                             HKEY connection;
464 
465                             TRACE("Trying connection %lu\n", index);
466 
467                             if (RegEnumKeyExW(network, index, local, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
468                                 continue;
469 
470                             TRACE("It is %S\n", local);
471 
472                             if (RegOpenKeyExW(network, local, 0, KEY_READ, &connection) != ERROR_SUCCESS)
473                                 continue;
474 
475                             _restoreSavedConnection(connection, local);
476                             RegCloseKey(connection);
477                         }
478 
479                         HeapFree(GetProcessHeap(), 0, local);
480                     }
481                 }
482 
483                 RegCloseKey(network);
484             }
485 
486             RegCloseKey(user_profile);
487         }
488     }
489 #endif
490 }
491 
wnetFree(void)492 void wnetFree(void)
493 {
494     if (providerTable)
495     {
496         DWORD i;
497 
498         for (i = 0; i < providerTable->numProviders; i++)
499         {
500             HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
501             FreeModule(providerTable->table[i].hLib);
502         }
503         HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
504         HeapFree(GetProcessHeap(), 0, providerTable);
505         providerTable = NULL;
506     }
507 }
508 
_findProviderIndexW(LPCWSTR lpProvider)509 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
510 {
511     DWORD ret = BAD_PROVIDER_INDEX;
512 
513     if (providerTable && providerTable->numProviders)
514     {
515         DWORD i;
516 
517         for (i = 0; i < providerTable->numProviders &&
518          ret == BAD_PROVIDER_INDEX; i++)
519             if (!lstrcmpW(lpProvider, providerTable->table[i].name))
520                 ret = i;
521     }
522     return ret;
523 }
524 
525 /*
526  * Browsing Functions
527  */
528 
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet)529 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
530 {
531     LPNETRESOURCEW ret;
532 
533     if (lpNet)
534     {
535         ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
536         if (ret)
537         {
538             size_t len;
539 
540             *ret = *lpNet;
541             ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
542             if (lpNet->lpRemoteName)
543             {
544                 len = lstrlenW(lpNet->lpRemoteName) + 1;
545                 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
546                 if (ret->lpRemoteName)
547                     lstrcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
548             }
549         }
550     }
551     else
552         ret = NULL;
553     return ret;
554 }
555 
_freeEnumNetResource(LPNETRESOURCEW lpNet)556 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
557 {
558     if (lpNet)
559     {
560         HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
561         HeapFree(GetProcessHeap(), 0, lpNet);
562     }
563 }
564 
_createGlobalEnumeratorW(DWORD dwScope,DWORD dwType,DWORD dwUsage,LPNETRESOURCEW lpNet)565 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
566  DWORD dwUsage, LPNETRESOURCEW lpNet)
567 {
568     PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
569      HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
570 
571     if (ret)
572     {
573         ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
574         ret->dwScope = dwScope;
575         ret->dwType  = dwType;
576         ret->dwUsage = dwUsage;
577         ret->specific.net = _copyNetResourceForEnumW(lpNet);
578     }
579     return ret;
580 }
581 
_createProviderEnumerator(DWORD dwScope,DWORD dwType,DWORD dwUsage,DWORD index,HANDLE handle)582 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
583  DWORD dwUsage, DWORD index, HANDLE handle)
584 {
585     PWNetEnumerator ret;
586 
587     if (!providerTable || index >= providerTable->numProviders)
588         ret = NULL;
589     else
590     {
591         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
592         if (ret)
593         {
594             ret->enumType      = WNET_ENUMERATOR_TYPE_PROVIDER;
595             ret->providerIndex = index;
596             ret->dwScope       = dwScope;
597             ret->dwType        = dwType;
598             ret->dwUsage       = dwUsage;
599             ret->handle        = handle;
600         }
601     }
602     return ret;
603 }
604 
_createContextEnumerator(DWORD dwScope,DWORD dwType,DWORD dwUsage)605 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
606  DWORD dwUsage)
607 {
608     PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
609      HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
610 
611     if (ret)
612     {
613         ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
614         ret->dwScope = dwScope;
615         ret->dwType  = dwType;
616         ret->dwUsage = dwUsage;
617     }
618     return ret;
619 }
620 
_createConnectedEnumerator(DWORD dwScope,DWORD dwType,DWORD dwUsage)621 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
622  DWORD dwUsage)
623 {
624     PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
625     if (ret)
626     {
627         ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
628         ret->dwScope = dwScope;
629         ret->dwType  = dwType;
630         ret->dwUsage = dwUsage;
631         ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
632         if (!ret->specific.handles)
633         {
634             HeapFree(GetProcessHeap(), 0, ret);
635             ret = NULL;
636         }
637     }
638     return ret;
639 }
640 
_createRememberedEnumerator(DWORD dwScope,DWORD dwType,HKEY remembered)641 static PWNetEnumerator _createRememberedEnumerator(DWORD dwScope, DWORD dwType,
642  HKEY remembered)
643 {
644     PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
645     if (ret)
646     {
647         ret->enumType = WNET_ENUMERATOR_TYPE_REMEMBERED;
648         ret->dwScope = dwScope;
649         ret->dwType = dwType;
650         ret->specific.remembered.registry = remembered;
651     }
652     return ret;
653 }
654 
655 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
656  * lpBuffer, with size *lpBufferSize.  lpNetArrayIn contains *lpcCount entries
657  * to start.  On return, *lpcCount reflects the number thunked into lpBuffer.
658  * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
659  * if not all members of the array could be thunked, and something else on
660  * failure.
661  */
_thunkNetResourceArrayWToA(const NETRESOURCEW * lpNetArrayIn,const DWORD * lpcCount,LPVOID lpBuffer,const DWORD * lpBufferSize)662 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
663  const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
664 {
665     DWORD i, numToThunk, totalBytes, ret;
666     LPSTR strNext;
667 
668     if (!lpNetArrayIn)
669         return WN_BAD_POINTER;
670     if (!lpcCount)
671         return WN_BAD_POINTER;
672     if (*lpcCount == -1)
673         return WN_BAD_VALUE;
674     if (!lpBuffer)
675         return WN_BAD_POINTER;
676     if (!lpBufferSize)
677         return WN_BAD_POINTER;
678 
679     for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
680     {
681         const NETRESOURCEW *lpNet = lpNetArrayIn + i;
682 
683         totalBytes += sizeof(NETRESOURCEA);
684         if (lpNet->lpLocalName)
685             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
686              -1, NULL, 0, NULL, NULL);
687         if (lpNet->lpRemoteName)
688             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
689              -1, NULL, 0, NULL, NULL);
690         if (lpNet->lpComment)
691             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
692              -1, NULL, 0, NULL, NULL);
693         if (lpNet->lpProvider)
694             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
695              -1, NULL, 0, NULL, NULL);
696         if (totalBytes < *lpBufferSize)
697             numToThunk = i + 1;
698     }
699     strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
700     for (i = 0; i < numToThunk; i++)
701     {
702         LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
703         const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
704 
705         memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
706         /* lie about string lengths, we already verified how many
707          * we have space for above
708          */
709         if (lpNetIn->lpLocalName)
710         {
711             lpNetOut->lpLocalName = strNext;
712             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
713              lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
714         }
715         if (lpNetIn->lpRemoteName)
716         {
717             lpNetOut->lpRemoteName = strNext;
718             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
719              lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
720         }
721         if (lpNetIn->lpComment)
722         {
723             lpNetOut->lpComment = strNext;
724             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
725              lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
726         }
727         if (lpNetIn->lpProvider)
728         {
729             lpNetOut->lpProvider = strNext;
730             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
731              lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
732         }
733     }
734     ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
735     TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
736      *lpcCount, ret);
737     return ret;
738 }
739 
740 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
741  * lpBuffer, with size *lpBufferSize.  lpNetArrayIn contains *lpcCount entries
742  * to start.  On return, *lpcCount reflects the number thunked into lpBuffer.
743  * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
744  * if not all members of the array could be thunked, and something else on
745  * failure.
746  */
_thunkNetResourceArrayAToW(const NETRESOURCEA * lpNetArrayIn,const DWORD * lpcCount,LPVOID lpBuffer,const DWORD * lpBufferSize)747 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
748  const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
749 {
750     DWORD i, numToThunk, totalBytes, ret;
751     LPWSTR strNext;
752 
753     if (!lpNetArrayIn)
754         return WN_BAD_POINTER;
755     if (!lpcCount)
756         return WN_BAD_POINTER;
757     if (*lpcCount == -1)
758         return WN_BAD_VALUE;
759     if (!lpBuffer)
760         return WN_BAD_POINTER;
761     if (!lpBufferSize)
762         return WN_BAD_POINTER;
763 
764     for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
765     {
766         const NETRESOURCEA *lpNet = lpNetArrayIn + i;
767 
768         totalBytes += sizeof(NETRESOURCEW);
769         if (lpNet->lpLocalName)
770             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
771              -1, NULL, 0) * sizeof(WCHAR);
772         if (lpNet->lpRemoteName)
773             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
774              -1, NULL, 0) * sizeof(WCHAR);
775         if (lpNet->lpComment)
776             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
777              -1, NULL, 0) * sizeof(WCHAR);
778         if (lpNet->lpProvider)
779             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
780              -1, NULL, 0) * sizeof(WCHAR);
781         if (totalBytes < *lpBufferSize)
782             numToThunk = i + 1;
783     }
784     strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
785     for (i = 0; i < numToThunk; i++)
786     {
787         LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
788         const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
789 
790         memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
791         /* lie about string lengths, we already verified how many
792          * we have space for above
793          */
794         if (lpNetIn->lpLocalName)
795         {
796             lpNetOut->lpLocalName = strNext;
797             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
798              -1, lpNetOut->lpLocalName, *lpBufferSize);
799         }
800         if (lpNetIn->lpRemoteName)
801         {
802             lpNetOut->lpRemoteName = strNext;
803             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
804              -1, lpNetOut->lpRemoteName, *lpBufferSize);
805         }
806         if (lpNetIn->lpComment)
807         {
808             lpNetOut->lpComment = strNext;
809             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
810              -1, lpNetOut->lpComment, *lpBufferSize);
811         }
812         if (lpNetIn->lpProvider)
813         {
814             lpNetOut->lpProvider = strNext;
815             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
816              -1, lpNetOut->lpProvider, *lpBufferSize);
817         }
818     }
819     ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
820     TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
821      *lpcCount, ret);
822     return ret;
823 }
824 
825 /*********************************************************************
826  * WNetOpenEnumA [MPR.@]
827  *
828  * See comments for WNetOpenEnumW.
829  */
WNetOpenEnumA(DWORD dwScope,DWORD dwType,DWORD dwUsage,LPNETRESOURCEA lpNet,LPHANDLE lphEnum)830 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
831                             LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
832 {
833     DWORD ret;
834 
835     TRACE( "(%08X, %08X, %08X, %p, %p)\n",
836 	    dwScope, dwType, dwUsage, lpNet, lphEnum );
837 
838     if (!lphEnum)
839         ret = WN_BAD_POINTER;
840     else if (!providerTable || providerTable->numProviders == 0)
841     {
842         *lphEnum = NULL;
843         ret = WN_NO_NETWORK;
844     }
845     else
846     {
847         if (lpNet)
848         {
849             LPNETRESOURCEW lpNetWide = NULL;
850             BYTE buf[1024];
851             DWORD size = sizeof(buf), count = 1;
852             BOOL allocated = FALSE;
853 
854             ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
855             if (ret == WN_MORE_DATA)
856             {
857                 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
858                  size);
859                 if (lpNetWide)
860                 {
861                     ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
862                      &size);
863                     allocated = TRUE;
864                 }
865                 else
866                     ret = WN_OUT_OF_MEMORY;
867             }
868             else if (ret == WN_SUCCESS)
869                 lpNetWide = (LPNETRESOURCEW)buf;
870             if (ret == WN_SUCCESS)
871                 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
872                  lphEnum);
873             if (allocated)
874                 HeapFree(GetProcessHeap(), 0, lpNetWide);
875         }
876         else
877             ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
878     }
879     if (ret)
880         SetLastError(ret);
881     TRACE("Returning %d\n", ret);
882     return ret;
883 }
884 
885 /*********************************************************************
886  * WNetOpenEnumW [MPR.@]
887  *
888  * Network enumeration has way too many parameters, so I'm not positive I got
889  * them right.  What I've got so far:
890  *
891  * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
892  *   all the network providers should be enumerated.
893  *
894  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
895  *   and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
896  *   lpProvider is set, all the network providers should be enumerated.
897  *   (This means the enumeration is a list of network providers, not that the
898  *   enumeration is passed on to the providers.)
899  *
900  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
901  *   resource matches the "Entire Network" resource (no remote name, no
902  *   provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
903  *   enumeration is done on every network provider.
904  *
905  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
906  *   the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
907  *   only to the given network provider.
908  *
909  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
910  *   no lpProvider is set, enumeration will be tried on every network provider,
911  *   in the order in which they're loaded.
912  *
913  * - The LPNETRESOURCE should be disregarded for scopes besides
914  *   RESOURCE_GLOBALNET.  MSDN states that lpNet must be NULL if dwScope is not
915  *   RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
916  *
917  * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
918  *   resource in the enumerated list, as well as any machines in your
919  *   workgroup.  The machines in your workgroup come from doing a
920  *   RESOURCE_CONTEXT enumeration of every Network Provider.
921  */
WNetOpenEnumW(DWORD dwScope,DWORD dwType,DWORD dwUsage,LPNETRESOURCEW lpNet,LPHANDLE lphEnum)922 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
923                             LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
924 {
925     DWORD ret;
926 
927     TRACE( "(%08X, %08X, %08X, %p, %p)\n",
928           dwScope, dwType, dwUsage, lpNet, lphEnum );
929 
930     if (!lphEnum)
931         ret = WN_BAD_POINTER;
932     else if (!providerTable || providerTable->numProviders == 0)
933     {
934         *lphEnum = NULL;
935         ret = WN_NO_NETWORK;
936     }
937     else
938     {
939         switch (dwScope)
940         {
941             case RESOURCE_GLOBALNET:
942                 if (lpNet)
943                 {
944                     if (lpNet->lpProvider)
945                     {
946                         DWORD index = _findProviderIndexW(lpNet->lpProvider);
947 
948                         if (index != BAD_PROVIDER_INDEX)
949                         {
950                             if (providerTable->table[index].openEnum &&
951                              providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
952                             {
953                                 HANDLE handle;
954                                 PWSTR RemoteName = lpNet->lpRemoteName;
955 
956                                 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
957                                     RemoteName && !lstrcmpW(RemoteName, lpNet->lpProvider))
958                                     lpNet->lpRemoteName = NULL;
959 
960                                 ret = providerTable->table[index].openEnum(
961                                  dwScope, dwType, dwUsage, lpNet, &handle);
962                                 if (ret == WN_SUCCESS)
963                                 {
964                                     *lphEnum = _createProviderEnumerator(
965                                      dwScope, dwType, dwUsage, index, handle);
966                                     ret = *lphEnum ? WN_SUCCESS :
967                                      WN_OUT_OF_MEMORY;
968                                 }
969 
970                                 lpNet->lpRemoteName = RemoteName;
971                             }
972                             else
973                                 ret = WN_NOT_SUPPORTED;
974                         }
975                         else
976                             ret = WN_BAD_PROVIDER;
977                     }
978                     else if (lpNet->lpRemoteName)
979                     {
980                         *lphEnum = _createGlobalEnumeratorW(dwScope,
981                          dwType, dwUsage, lpNet);
982                         ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
983                     }
984                     else
985                     {
986                         if (lpNet->lpComment && !lstrcmpW(lpNet->lpComment,
987                          providerTable->entireNetwork))
988                         {
989                             /* comment matches the "Entire Network", enumerate
990                              * global scope of every provider
991                              */
992                             *lphEnum = _createGlobalEnumeratorW(dwScope,
993                              dwType, dwUsage, lpNet);
994                         }
995                         else
996                         {
997                             /* this is the same as not having passed lpNet */
998                             *lphEnum = _createGlobalEnumeratorW(dwScope,
999                              dwType, dwUsage, NULL);
1000                         }
1001                         ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1002                     }
1003                 }
1004                 else
1005                 {
1006                     *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
1007                      dwUsage, lpNet);
1008                     ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1009                 }
1010                 break;
1011             case RESOURCE_CONTEXT:
1012                 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
1013                 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1014                 break;
1015             case RESOURCE_CONNECTED:
1016                 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
1017                 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1018                 break;
1019             case RESOURCE_REMEMBERED:
1020                 {
1021                     HKEY remembered, user_profile;
1022 
1023                     ret = WN_OUT_OF_MEMORY;
1024                     if (RegOpenCurrentUser(KEY_READ, &user_profile) == ERROR_SUCCESS)
1025                     {
1026                         WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
1027 
1028                         if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &remembered) == ERROR_SUCCESS)
1029                         {
1030                             *lphEnum = _createRememberedEnumerator(dwScope, dwType, remembered);
1031                             ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1032                         }
1033 
1034                         RegCloseKey(user_profile);
1035                     }
1036                 }
1037                 break;
1038             default:
1039                 WARN("unknown scope 0x%08x\n", dwScope);
1040                 ret = WN_BAD_VALUE;
1041         }
1042     }
1043     if (ret)
1044         SetLastError(ret);
1045     TRACE("Returning %d\n", ret);
1046     return ret;
1047 }
1048 
1049 /*********************************************************************
1050  * WNetEnumResourceA [MPR.@]
1051  */
WNetEnumResourceA(HANDLE hEnum,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize)1052 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
1053                                 LPVOID lpBuffer, LPDWORD lpBufferSize )
1054 {
1055     DWORD ret;
1056 
1057     TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1058 
1059     if (!hEnum)
1060         ret = WN_BAD_POINTER;
1061     else if (!lpcCount)
1062         ret = WN_BAD_POINTER;
1063     else if (!lpBuffer)
1064         ret = WN_BAD_POINTER;
1065     else if (!lpBufferSize)
1066         ret = WN_BAD_POINTER;
1067     else if (*lpBufferSize < sizeof(NETRESOURCEA))
1068     {
1069         *lpBufferSize = sizeof(NETRESOURCEA);
1070         ret = WN_MORE_DATA;
1071     }
1072     else
1073     {
1074         DWORD localCount = *lpcCount, localSize = *lpBufferSize;
1075         LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
1076 
1077         if (localBuffer)
1078         {
1079             ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
1080              &localSize);
1081             if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
1082             {
1083                 /* FIXME: this isn't necessarily going to work in the case of
1084                  * WN_MORE_DATA, because our enumerator may have moved on to
1085                  * the next provider.  MSDN states that a large (16KB) buffer
1086                  * size is the appropriate usage of this function, so
1087                  * hopefully it won't be an issue.
1088                  */
1089                 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
1090                  lpBuffer, lpBufferSize);
1091                 *lpcCount = localCount;
1092             }
1093             HeapFree(GetProcessHeap(), 0, localBuffer);
1094         }
1095         else
1096             ret = WN_OUT_OF_MEMORY;
1097     }
1098     if (ret)
1099         SetLastError(ret);
1100     TRACE("Returning %d\n", ret);
1101     return ret;
1102 }
1103 
_countProviderBytesW(PWNetProvider provider)1104 static DWORD _countProviderBytesW(PWNetProvider provider)
1105 {
1106     DWORD ret;
1107 
1108     if (provider)
1109     {
1110         ret = sizeof(NETRESOURCEW);
1111         ret += 2 * (lstrlenW(provider->name) + 1) * sizeof(WCHAR);
1112     }
1113     else
1114         ret = 0;
1115     return ret;
1116 }
1117 
_enumerateProvidersW(PWNetEnumerator enumerator,LPDWORD lpcCount,LPVOID lpBuffer,const DWORD * lpBufferSize)1118 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1119  LPVOID lpBuffer, const DWORD *lpBufferSize)
1120 {
1121     DWORD ret;
1122 
1123     if (!enumerator)
1124         return WN_BAD_POINTER;
1125     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1126         return WN_BAD_VALUE;
1127     if (!lpcCount)
1128         return WN_BAD_POINTER;
1129     if (!lpBuffer)
1130         return WN_BAD_POINTER;
1131     if (!lpBufferSize)
1132         return WN_BAD_POINTER;
1133     if (*lpBufferSize < sizeof(NETRESOURCEA))
1134         return WN_MORE_DATA;
1135 
1136     if (!providerTable || enumerator->providerIndex >=
1137      providerTable->numProviders)
1138         ret = WN_NO_MORE_ENTRIES;
1139     else
1140     {
1141         DWORD bytes = 0, count = 0, countLimit, i;
1142         LPNETRESOURCEW resource;
1143         LPWSTR strNext;
1144 
1145         countLimit = *lpcCount == -1 ?
1146          providerTable->numProviders - enumerator->providerIndex : *lpcCount;
1147         while (count < countLimit && bytes < *lpBufferSize)
1148         {
1149             DWORD bytesNext = _countProviderBytesW(
1150              &providerTable->table[count + enumerator->providerIndex]);
1151 
1152             if (bytes + bytesNext < *lpBufferSize)
1153             {
1154                 bytes += bytesNext;
1155                 count++;
1156             }
1157         }
1158         strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
1159         for (i = 0, resource = lpBuffer; i < count; i++, resource++)
1160         {
1161             resource->dwScope = RESOURCE_GLOBALNET;
1162             resource->dwType = RESOURCETYPE_ANY;
1163             resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
1164             resource->dwUsage = RESOURCEUSAGE_CONTAINER |
1165              RESOURCEUSAGE_RESERVED;
1166             resource->lpLocalName = NULL;
1167             resource->lpRemoteName = strNext;
1168             lstrcpyW(resource->lpRemoteName,
1169              providerTable->table[i + enumerator->providerIndex].name);
1170             strNext += lstrlenW(resource->lpRemoteName) + 1;
1171             resource->lpComment = NULL;
1172             resource->lpProvider = strNext;
1173             lstrcpyW(resource->lpProvider,
1174              providerTable->table[i + enumerator->providerIndex].name);
1175             strNext += lstrlenW(resource->lpProvider) + 1;
1176         }
1177         enumerator->providerIndex += count;
1178         *lpcCount = count;
1179         ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1180     }
1181     TRACE("Returning %d\n", ret);
1182     return ret;
1183 }
1184 
1185 /* Advances the enumerator (assumed to be a global enumerator) to the next
1186  * provider that supports the enumeration scope passed to WNetOpenEnum.  Does
1187  * not open a handle with the next provider.
1188  * If the existing handle is NULL, may leave the enumerator unchanged, since
1189  * the current provider may support the desired scope.
1190  * If the existing handle is not NULL, closes it before moving on.
1191  * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1192  * provider, and another error on failure.
1193  */
_globalEnumeratorAdvance(PWNetEnumerator enumerator)1194 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1195 {
1196     if (!enumerator)
1197         return WN_BAD_POINTER;
1198     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1199         return WN_BAD_VALUE;
1200     if (!providerTable || enumerator->providerIndex >=
1201      providerTable->numProviders)
1202         return WN_NO_MORE_ENTRIES;
1203 
1204     if (enumerator->providerDone)
1205     {
1206         DWORD dwEnum = 0;
1207         enumerator->providerDone = FALSE;
1208         if (enumerator->handle)
1209         {
1210             providerTable->table[enumerator->providerIndex].closeEnum(
1211              enumerator->handle);
1212             enumerator->handle = NULL;
1213             enumerator->providerIndex++;
1214         }
1215         if (enumerator->dwScope == RESOURCE_CONNECTED)
1216             dwEnum = WNNC_ENUM_LOCAL;
1217         else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1218             dwEnum = WNNC_ENUM_GLOBAL;
1219         else if (enumerator->dwScope == RESOURCE_CONTEXT)
1220             dwEnum = WNNC_ENUM_CONTEXT;
1221         for (; enumerator->providerIndex < providerTable->numProviders &&
1222          !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1223          & dwEnum); enumerator->providerIndex++)
1224             ;
1225     }
1226     return enumerator->providerIndex < providerTable->numProviders ?
1227      WN_SUCCESS : WN_NO_MORE_ENTRIES;
1228 }
1229 
1230 /* "Passes through" call to the next provider that supports the enumeration
1231  * type.
1232  * FIXME: if one call to a provider's enumerator succeeds while there's still
1233  * space in lpBuffer, I don't call to the next provider.  The caller may not
1234  * expect that it should call EnumResourceW again with a return value of
1235  * WN_SUCCESS (depending what *lpcCount was to begin with).  That means strings
1236  * may have to be moved around a bit, ick.
1237  */
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize)1238 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1239  LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1240 {
1241     DWORD ret;
1242 
1243     if (!enumerator)
1244         return WN_BAD_POINTER;
1245     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1246         return WN_BAD_VALUE;
1247     if (!lpcCount)
1248         return WN_BAD_POINTER;
1249     if (!lpBuffer)
1250         return WN_BAD_POINTER;
1251     if (!lpBufferSize)
1252         return WN_BAD_POINTER;
1253     if (*lpBufferSize < sizeof(NETRESOURCEW))
1254         return WN_MORE_DATA;
1255 
1256     ret = _globalEnumeratorAdvance(enumerator);
1257     if (ret == WN_SUCCESS)
1258     {
1259         ret = providerTable->table[enumerator->providerIndex].
1260          openEnum(enumerator->dwScope, enumerator->dwType,
1261          enumerator->dwUsage, enumerator->specific.net,
1262          &enumerator->handle);
1263         if (ret == WN_SUCCESS)
1264         {
1265             ret = providerTable->table[enumerator->providerIndex].
1266              enumResource(enumerator->handle, lpcCount, lpBuffer,
1267              lpBufferSize);
1268             if (ret != WN_MORE_DATA)
1269                 enumerator->providerDone = TRUE;
1270         }
1271     }
1272     TRACE("Returning %d\n", ret);
1273     return ret;
1274 }
1275 
_enumerateGlobalW(PWNetEnumerator enumerator,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize)1276 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1277  LPVOID lpBuffer, LPDWORD lpBufferSize)
1278 {
1279     DWORD ret;
1280 
1281     if (!enumerator)
1282         return WN_BAD_POINTER;
1283     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1284         return WN_BAD_VALUE;
1285     if (!lpcCount)
1286         return WN_BAD_POINTER;
1287     if (!lpBuffer)
1288         return WN_BAD_POINTER;
1289     if (!lpBufferSize)
1290         return WN_BAD_POINTER;
1291     if (*lpBufferSize < sizeof(NETRESOURCEW))
1292         return WN_MORE_DATA;
1293     if (!providerTable)
1294         return WN_NO_NETWORK;
1295 
1296     switch (enumerator->dwScope)
1297     {
1298         case RESOURCE_GLOBALNET:
1299             if (enumerator->specific.net)
1300                 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1301                  lpBuffer, lpBufferSize);
1302             else
1303                 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1304                  lpBufferSize);
1305             break;
1306         case RESOURCE_CONTEXT:
1307             ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1308              lpBufferSize);
1309             break;
1310         default:
1311             WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1312             ret = WN_NO_MORE_ENTRIES;
1313     }
1314     TRACE("Returning %d\n", ret);
1315     return ret;
1316 }
1317 
_enumerateProviderW(PWNetEnumerator enumerator,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize)1318 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1319  LPVOID lpBuffer, LPDWORD lpBufferSize)
1320 {
1321     if (!enumerator)
1322         return WN_BAD_POINTER;
1323     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1324         return WN_BAD_VALUE;
1325     if (!enumerator->handle)
1326         return WN_BAD_VALUE;
1327     if (!lpcCount)
1328         return WN_BAD_POINTER;
1329     if (!lpBuffer)
1330         return WN_BAD_POINTER;
1331     if (!lpBufferSize)
1332         return WN_BAD_POINTER;
1333     if (!providerTable)
1334         return WN_NO_NETWORK;
1335     if (enumerator->providerIndex >= providerTable->numProviders)
1336         return WN_NO_MORE_ENTRIES;
1337     if (!providerTable->table[enumerator->providerIndex].enumResource)
1338         return WN_BAD_VALUE;
1339     return providerTable->table[enumerator->providerIndex].enumResource(
1340      enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1341 }
1342 
_enumerateContextW(PWNetEnumerator enumerator,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize)1343 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1344  LPVOID lpBuffer, LPDWORD lpBufferSize)
1345 {
1346     DWORD ret;
1347     size_t cchEntireNetworkLen, bytesNeeded;
1348 
1349     if (!enumerator)
1350         return WN_BAD_POINTER;
1351     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1352         return WN_BAD_VALUE;
1353     if (!lpcCount)
1354         return WN_BAD_POINTER;
1355     if (!lpBuffer)
1356         return WN_BAD_POINTER;
1357     if (!lpBufferSize)
1358         return WN_BAD_POINTER;
1359     if (!providerTable)
1360         return WN_NO_NETWORK;
1361 
1362     cchEntireNetworkLen = lstrlenW(providerTable->entireNetwork) + 1;
1363     bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1364     if (*lpBufferSize < bytesNeeded)
1365     {
1366         *lpBufferSize = bytesNeeded;
1367         ret = WN_MORE_DATA;
1368     }
1369     else
1370     {
1371         LPNETRESOURCEW lpNet = lpBuffer;
1372 
1373         lpNet->dwScope = RESOURCE_GLOBALNET;
1374         lpNet->dwType = enumerator->dwType;
1375         lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1376         lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1377         lpNet->lpLocalName = NULL;
1378         lpNet->lpRemoteName = NULL;
1379         lpNet->lpProvider = NULL;
1380         /* odd, but correct: put comment at end of buffer, so it won't get
1381          * overwritten by subsequent calls to a provider's enumResource
1382          */
1383         lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1384          (cchEntireNetworkLen * sizeof(WCHAR)));
1385         lstrcpyW(lpNet->lpComment, providerTable->entireNetwork);
1386         ret = WN_SUCCESS;
1387     }
1388     if (ret == WN_SUCCESS)
1389     {
1390         DWORD bufferSize = *lpBufferSize - bytesNeeded;
1391 
1392         /* "Entire Network" entry enumerated--morph this into a global
1393          * enumerator.  enumerator->lpNet continues to be NULL, since it has
1394          * no meaning when the scope isn't RESOURCE_GLOBALNET.
1395          */
1396         enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1397         ret = _enumerateGlobalW(enumerator, lpcCount,
1398          (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1399         if (ret == WN_SUCCESS)
1400         {
1401             /* reflect the fact that we already enumerated "Entire Network" */
1402             (*lpcCount)++;
1403             *lpBufferSize = bufferSize + bytesNeeded;
1404         }
1405         else
1406         {
1407             /* the provider enumeration failed, but we already succeeded in
1408              * enumerating "Entire Network"--leave type as global to allow a
1409              * retry, but indicate success with a count of one.
1410              */
1411             ret = WN_SUCCESS;
1412             *lpcCount = 1;
1413             *lpBufferSize = bytesNeeded;
1414         }
1415     }
1416     TRACE("Returning %d\n", ret);
1417     return ret;
1418 }
1419 
_copyStringToEnumW(const WCHAR * source,DWORD * left,void ** end)1420 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1421 {
1422     DWORD len;
1423     WCHAR* local = *end;
1424 
1425     len = lstrlenW(source) + 1;
1426     len *= sizeof(WCHAR);
1427     if (*left < len)
1428         return WN_MORE_DATA;
1429 
1430     local -= (len / sizeof(WCHAR));
1431     memcpy(local, source, len);
1432     *left -= len;
1433     *end = local;
1434 
1435     return WN_SUCCESS;
1436 }
1437 
_enumerateConnectedW(PWNetEnumerator enumerator,DWORD * user_count,void * user_buffer,DWORD * user_size)1438 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1439                                   void* user_buffer, DWORD* user_size)
1440 {
1441     DWORD ret, index, count, total_count, size, i, left;
1442     void* end;
1443     NETRESOURCEW* curr, * buffer;
1444     HANDLE* handles;
1445 
1446     if (!enumerator)
1447         return WN_BAD_POINTER;
1448     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1449         return WN_BAD_VALUE;
1450     if (!user_count || !user_buffer || !user_size)
1451         return WN_BAD_POINTER;
1452     if (!providerTable)
1453         return WN_NO_NETWORK;
1454 
1455     handles = enumerator->specific.handles;
1456     left = *user_size;
1457     size = *user_size;
1458     buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1459     if (!buffer)
1460         return WN_NO_NETWORK;
1461 
1462     curr = user_buffer;
1463     end = (char *)user_buffer + size;
1464     count = *user_count;
1465     total_count = 0;
1466 
1467     ret = WN_NO_MORE_ENTRIES;
1468     for (index = 0; index < providerTable->numProviders; index++)
1469     {
1470         if (providerTable->table[index].dwEnumScopes)
1471         {
1472             if (handles[index] == 0)
1473             {
1474                 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1475                                                            enumerator->dwType,
1476                                                            enumerator->dwUsage,
1477                                                            NULL, &handles[index]);
1478                 if (ret != WN_SUCCESS)
1479                     continue;
1480             }
1481 
1482             ret = providerTable->table[index].enumResource(handles[index],
1483                                                            &count, buffer,
1484                                                            &size);
1485             total_count += count;
1486             if (ret == WN_MORE_DATA)
1487                 break;
1488 
1489             if (ret == WN_SUCCESS)
1490             {
1491                 for (i = 0; i < count; ++i)
1492                 {
1493                     if (left < sizeof(NETRESOURCEW))
1494                     {
1495                         ret = WN_MORE_DATA;
1496                         break;
1497                     }
1498 
1499                     memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1500                     left -= sizeof(NETRESOURCEW);
1501 
1502                     ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1503                     if (ret == WN_MORE_DATA)
1504                         break;
1505                     curr->lpLocalName = end;
1506 
1507                     ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1508                     if (ret == WN_MORE_DATA)
1509                         break;
1510                     curr->lpRemoteName = end;
1511 
1512                     ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1513                     if (ret == WN_MORE_DATA)
1514                         break;
1515                     curr->lpProvider = end;
1516 
1517                     ++curr;
1518                 }
1519 
1520                 size = left;
1521             }
1522 
1523             if (*user_count != -1)
1524                 count = *user_count - total_count;
1525             else
1526                 count = *user_count;
1527         }
1528     }
1529 
1530     if (total_count == 0)
1531         ret = WN_NO_MORE_ENTRIES;
1532 
1533     *user_count = total_count;
1534     if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1535         ret = WN_SUCCESS;
1536 
1537     HeapFree(GetProcessHeap(), 0, buffer);
1538 
1539     TRACE("Returning %d\n", ret);
1540     return ret;
1541 }
1542 
1543 static const WCHAR connectionType[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
1544 static const WCHAR providerName[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
1545 static const WCHAR remotePath[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
1546 
get_reg_str(HKEY hkey,const WCHAR * value,DWORD * len)1547 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value, DWORD *len)
1548 {
1549     DWORD type;
1550     WCHAR *ret = NULL;
1551 
1552     if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, len) && type == REG_SZ)
1553     {
1554         if (!(ret = HeapAlloc(GetProcessHeap(), 0, *len))) return NULL;
1555         RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, len);
1556     }
1557 
1558     return ret;
1559 }
1560 
_enumeratorRememberedW(PWNetEnumerator enumerator,DWORD * user_count,void * user_buffer,DWORD * user_size)1561 static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count,
1562                                     void* user_buffer, DWORD* user_size)
1563 {
1564     HKEY registry, connection;
1565     WCHAR buffer[255];
1566     LONG size_left;
1567     DWORD index, ret, type, len, size, registry_size, full_size = 0, total_count;
1568     NETRESOURCEW * net_buffer = user_buffer;
1569     WCHAR * str, * registry_string;
1570 
1571     /* we will do the work in a single loop, so here is some things:
1572      * we write netresource at the begin of the user buffer
1573      * we write strings at the end of the user buffer
1574      */
1575     size_left = *user_size;
1576     total_count = 0;
1577     type = enumerator->dwType;
1578     registry = enumerator->specific.remembered.registry;
1579     str = (WCHAR *)((ULONG_PTR)user_buffer + *user_size - sizeof(WCHAR));
1580     for (index = enumerator->specific.remembered.index; ; ++index)
1581     {
1582         enumerator->specific.remembered.index = index;
1583 
1584         if (*user_count != -1 && total_count == *user_count)
1585         {
1586             ret = WN_SUCCESS;
1587             break;
1588         }
1589 
1590         len = ARRAY_SIZE(buffer);
1591         ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL);
1592         if (ret != ERROR_SUCCESS)
1593         {
1594             if (ret == ERROR_NO_MORE_ITEMS) ret = WN_SUCCESS;
1595             break;
1596         }
1597 
1598         if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS)
1599         {
1600             continue;
1601         }
1602 
1603         full_size = sizeof(NETRESOURCEW);
1604         size_left -= sizeof(NETRESOURCEW);
1605 
1606         if (size_left > 0)
1607         {
1608             size = sizeof(DWORD);
1609             RegQueryValueExW(connection, connectionType, NULL, NULL, (BYTE *)&net_buffer->dwType, &size);
1610             if (type != RESOURCETYPE_ANY && net_buffer->dwType != type)
1611             {
1612                 size_left += sizeof(NETRESOURCEW);
1613                 RegCloseKey(connection);
1614                 continue;
1615             }
1616 
1617             net_buffer->dwScope = RESOURCE_REMEMBERED;
1618             net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
1619             net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE;
1620         }
1621         else
1622             ret = WN_MORE_DATA;
1623 
1624         /* FIXME: this only supports drive letters */
1625         full_size += 3 * sizeof(WCHAR);
1626         size_left -= 3 * sizeof(WCHAR);
1627         if (size_left > 0)
1628         {
1629             str -= 3;
1630             str[0] = buffer[0];
1631             str[1] = ':';
1632             str[2] = 0;
1633             net_buffer->lpLocalName = str;
1634         }
1635 
1636         registry_size = 0;
1637         registry_string = get_reg_str(connection, providerName, &registry_size);
1638         if (registry_string)
1639         {
1640             full_size += registry_size;
1641             size_left -= registry_size;
1642 
1643             if (size_left > 0)
1644             {
1645                 str -= (registry_size / sizeof(WCHAR));
1646                 lstrcpyW(str, registry_string);
1647                 net_buffer->lpProvider = str;
1648             }
1649             else
1650                 ret = WN_MORE_DATA;
1651 
1652             HeapFree(GetProcessHeap(), 0, registry_string);
1653         }
1654 
1655         registry_size = 0;
1656         registry_string = get_reg_str(connection, remotePath, &registry_size);
1657         if (registry_string)
1658         {
1659             full_size += registry_size;
1660             size_left -= registry_size;
1661 
1662             if (size_left > 0)
1663             {
1664                 str -= (registry_size / sizeof(WCHAR));
1665                 lstrcpyW(str, registry_string);
1666                 net_buffer->lpRemoteName = str;
1667             }
1668             else
1669                 ret = WN_MORE_DATA;
1670 
1671             HeapFree(GetProcessHeap(), 0, registry_string);
1672         }
1673 
1674         RegCloseKey(connection);
1675 
1676         net_buffer->lpComment = NULL;
1677 
1678         if (size_left < 0)
1679             break;
1680 
1681         ++total_count;
1682         ++net_buffer;
1683     }
1684 
1685     if (total_count == 0)
1686         ret = WN_NO_MORE_ENTRIES;
1687 
1688     *user_count = total_count;
1689 
1690     if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1691         ret = WN_SUCCESS;
1692 
1693     if (ret == WN_MORE_DATA)
1694         *user_size = *user_size + full_size;
1695 
1696     return ret;
1697 }
1698 
1699 /*********************************************************************
1700  * WNetEnumResourceW [MPR.@]
1701  */
WNetEnumResourceW(HANDLE hEnum,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize)1702 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1703                                 LPVOID lpBuffer, LPDWORD lpBufferSize )
1704 {
1705     DWORD ret;
1706 
1707     TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1708 
1709     if (!hEnum)
1710         ret = WN_BAD_POINTER;
1711     else if (!lpcCount)
1712         ret = WN_BAD_POINTER;
1713     else if (!lpBuffer)
1714         ret = WN_BAD_POINTER;
1715     else if (!lpBufferSize)
1716         ret = WN_BAD_POINTER;
1717     else if (*lpBufferSize < sizeof(NETRESOURCEW))
1718     {
1719         *lpBufferSize = sizeof(NETRESOURCEW);
1720         ret = WN_MORE_DATA;
1721     }
1722     else
1723     {
1724         PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1725 
1726         switch (enumerator->enumType)
1727         {
1728             case WNET_ENUMERATOR_TYPE_GLOBAL:
1729                 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1730                  lpBufferSize);
1731                 break;
1732             case WNET_ENUMERATOR_TYPE_PROVIDER:
1733                 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1734                  lpBufferSize);
1735                 break;
1736             case WNET_ENUMERATOR_TYPE_CONTEXT:
1737                 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1738                  lpBufferSize);
1739                 break;
1740             case WNET_ENUMERATOR_TYPE_CONNECTED:
1741                 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1742                  lpBufferSize);
1743                 break;
1744             case WNET_ENUMERATOR_TYPE_REMEMBERED:
1745                 ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer,
1746                  lpBufferSize);
1747                 break;
1748             default:
1749                 WARN("bogus enumerator type!\n");
1750                 ret = WN_NO_NETWORK;
1751         }
1752     }
1753     if (ret)
1754         SetLastError(ret);
1755     TRACE("Returning %d\n", ret);
1756     return ret;
1757 }
1758 
1759 /*********************************************************************
1760  * WNetCloseEnum [MPR.@]
1761  */
WNetCloseEnum(HANDLE hEnum)1762 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1763 {
1764     DWORD ret, index;
1765     HANDLE *handles;
1766 
1767     TRACE( "(%p)\n", hEnum );
1768 
1769     if (hEnum)
1770     {
1771         PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1772 
1773         switch (enumerator->enumType)
1774         {
1775             case WNET_ENUMERATOR_TYPE_GLOBAL:
1776                 if (enumerator->specific.net)
1777                     _freeEnumNetResource(enumerator->specific.net);
1778                 if (enumerator->handle)
1779                     providerTable->table[enumerator->providerIndex].
1780                      closeEnum(enumerator->handle);
1781                 ret = WN_SUCCESS;
1782                 break;
1783             case WNET_ENUMERATOR_TYPE_PROVIDER:
1784                 if (enumerator->handle)
1785                     providerTable->table[enumerator->providerIndex].
1786                      closeEnum(enumerator->handle);
1787                 ret = WN_SUCCESS;
1788                 break;
1789             case WNET_ENUMERATOR_TYPE_CONNECTED:
1790                 handles = enumerator->specific.handles;
1791                 for (index = 0; index < providerTable->numProviders; index++)
1792                 {
1793                     if (providerTable->table[index].dwEnumScopes && handles[index])
1794                         providerTable->table[index].closeEnum(handles[index]);
1795                 }
1796                 HeapFree(GetProcessHeap(), 0, handles);
1797                 ret = WN_SUCCESS;
1798                 break;
1799             case WNET_ENUMERATOR_TYPE_REMEMBERED:
1800                 RegCloseKey(enumerator->specific.remembered.registry);
1801                 ret = WN_SUCCESS;
1802                 break;
1803             default:
1804                 WARN("bogus enumerator type!\n");
1805                 ret = WN_BAD_HANDLE;
1806         }
1807         HeapFree(GetProcessHeap(), 0, hEnum);
1808     }
1809     else
1810         ret = WN_BAD_HANDLE;
1811     if (ret)
1812         SetLastError(ret);
1813     TRACE("Returning %d\n", ret);
1814     return ret;
1815 }
1816 
1817 /*********************************************************************
1818  * WNetGetResourceInformationA [MPR.@]
1819  *
1820  * See WNetGetResourceInformationW
1821  */
WNetGetResourceInformationA(LPNETRESOURCEA lpNetResource,LPVOID lpBuffer,LPDWORD cbBuffer,LPSTR * lplpSystem)1822 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1823                                           LPVOID lpBuffer, LPDWORD cbBuffer,
1824                                           LPSTR *lplpSystem )
1825 {
1826     DWORD ret;
1827 
1828     TRACE( "(%p, %p, %p, %p)\n",
1829            lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1830 
1831     if (!providerTable || providerTable->numProviders == 0)
1832         ret = WN_NO_NETWORK;
1833     else if (lpNetResource)
1834     {
1835         LPNETRESOURCEW lpNetResourceW = NULL;
1836         DWORD size = 1024, count = 1;
1837         DWORD len;
1838 
1839         lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1840         ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1841         if (ret == WN_MORE_DATA)
1842         {
1843             HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1844             lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1845             if (lpNetResourceW)
1846                 ret = _thunkNetResourceArrayAToW(lpNetResource,
1847                         &count, lpNetResourceW, &size);
1848             else
1849                 ret = WN_OUT_OF_MEMORY;
1850         }
1851         if (ret == WN_SUCCESS)
1852         {
1853             LPWSTR lpSystemW = NULL;
1854             LPVOID lpBufferW;
1855             size = 1024;
1856             lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1857             if (lpBufferW)
1858             {
1859                 ret = WNetGetResourceInformationW(lpNetResourceW,
1860                         lpBufferW, &size, &lpSystemW);
1861                 if (ret == WN_MORE_DATA)
1862                 {
1863                     HeapFree(GetProcessHeap(), 0, lpBufferW);
1864                     lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1865                     if (lpBufferW)
1866                         ret = WNetGetResourceInformationW(lpNetResourceW,
1867                             lpBufferW, &size, &lpSystemW);
1868                     else
1869                         ret = WN_OUT_OF_MEMORY;
1870                 }
1871                 if (ret == WN_SUCCESS)
1872                 {
1873                     ret = _thunkNetResourceArrayWToA(lpBufferW,
1874                             &count, lpBuffer, cbBuffer);
1875                     HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1876                     lpNetResourceW = lpBufferW;
1877                     size = sizeof(NETRESOURCEA);
1878                     size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1879                             -1, NULL, 0, NULL, NULL);
1880                     size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1881                             -1, NULL, 0, NULL, NULL);
1882 
1883                     len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1884                                       -1, NULL, 0, NULL, NULL);
1885                     if ((len) && ( size + len < *cbBuffer))
1886                     {
1887                         *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1888                         WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1889                              *lplpSystem, len, NULL, NULL);
1890                          ret = WN_SUCCESS;
1891                     }
1892                     else
1893                         ret = WN_MORE_DATA;
1894                 }
1895                 else
1896                     ret = WN_OUT_OF_MEMORY;
1897                 HeapFree(GetProcessHeap(), 0, lpBufferW);
1898             }
1899             else
1900                 ret = WN_OUT_OF_MEMORY;
1901             HeapFree(GetProcessHeap(), 0, lpSystemW);
1902         }
1903         HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1904     }
1905     else
1906         ret = WN_NO_NETWORK;
1907 
1908     if (ret)
1909         SetLastError(ret);
1910     TRACE("Returning %d\n", ret);
1911     return ret;
1912 }
1913 
1914 /*********************************************************************
1915  * WNetGetResourceInformationW [MPR.@]
1916  *
1917  * WNetGetResourceInformationW function identifies the network provider
1918  * that owns the resource and gets information about the type of the resource.
1919  *
1920  * PARAMS:
1921  *  lpNetResource    [ I]    the pointer to NETRESOURCEW structure, that
1922  *                          defines a network resource.
1923  *  lpBuffer         [ O]   the pointer to buffer, containing result. It
1924  *                          contains NETRESOURCEW structure and strings to
1925  *                          which the members of the NETRESOURCEW structure
1926  *                          point.
1927  *  cbBuffer         [I/O] the pointer to DWORD number - size of buffer
1928  *                          in bytes.
1929  *  lplpSystem       [ O]   the pointer to string in the output buffer,
1930  *                          containing the part of the resource name without
1931  *                          names of the server and share.
1932  *
1933  * RETURNS:
1934  *  NO_ERROR if the function succeeds. System error code if the function fails.
1935  */
1936 
WNetGetResourceInformationW(LPNETRESOURCEW lpNetResource,LPVOID lpBuffer,LPDWORD cbBuffer,LPWSTR * lplpSystem)1937 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1938                                           LPVOID lpBuffer, LPDWORD cbBuffer,
1939                                           LPWSTR *lplpSystem )
1940 {
1941     DWORD ret = WN_NO_NETWORK;
1942     DWORD index;
1943 
1944     TRACE( "(%p, %p, %p, %p)\n",
1945            lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1946 
1947     if (!(lpBuffer))
1948         ret = WN_OUT_OF_MEMORY;
1949     else if (providerTable != NULL)
1950     {
1951         /* FIXME: For function value of a variable is indifferent, it does
1952          * search of all providers in a network.
1953          */
1954         for (index = 0; index < providerTable->numProviders; index++)
1955         {
1956             if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1957                 WNNC_DLG_GETRESOURCEINFORMATION)
1958             {
1959                 if (providerTable->table[index].getResourceInformation)
1960                     ret = providerTable->table[index].getResourceInformation(
1961                         lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1962                 else
1963                     ret = WN_NO_NETWORK;
1964                 if (ret == WN_SUCCESS)
1965                     break;
1966             }
1967         }
1968     }
1969     if (ret)
1970         SetLastError(ret);
1971     return ret;
1972 }
1973 
1974 /*********************************************************************
1975  * WNetGetResourceParentA [MPR.@]
1976  */
WNetGetResourceParentA(LPNETRESOURCEA lpNetResource,LPVOID lpBuffer,LPDWORD lpBufferSize)1977 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1978                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
1979 {
1980     FIXME( "(%p, %p, %p): stub\n",
1981            lpNetResource, lpBuffer, lpBufferSize );
1982 
1983     SetLastError(WN_NO_NETWORK);
1984     return WN_NO_NETWORK;
1985 }
1986 
1987 /*********************************************************************
1988  * WNetGetResourceParentW [MPR.@]
1989  */
WNetGetResourceParentW(LPNETRESOURCEW lpNetResource,LPVOID lpBuffer,LPDWORD lpBufferSize)1990 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1991                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
1992 {
1993     FIXME( "(%p, %p, %p): stub\n",
1994            lpNetResource, lpBuffer, lpBufferSize );
1995 
1996     SetLastError(WN_NO_NETWORK);
1997     return WN_NO_NETWORK;
1998 }
1999 
2000 
2001 
2002 /*
2003  * Connection Functions
2004  */
2005 
2006 /*********************************************************************
2007  *  WNetAddConnectionA [MPR.@]
2008  */
WNetAddConnectionA(LPCSTR lpRemoteName,LPCSTR lpPassword,LPCSTR lpLocalName)2009 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
2010                                  LPCSTR lpLocalName )
2011 {
2012     NETRESOURCEA resourcesA;
2013 
2014     memset(&resourcesA, 0, sizeof(resourcesA));
2015     resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
2016     resourcesA.lpLocalName = (LPSTR)lpLocalName;
2017     return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
2018 }
2019 
2020 /*********************************************************************
2021  *  WNetAddConnectionW [MPR.@]
2022  */
WNetAddConnectionW(LPCWSTR lpRemoteName,LPCWSTR lpPassword,LPCWSTR lpLocalName)2023 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
2024                                  LPCWSTR lpLocalName )
2025 {
2026     NETRESOURCEW resourcesW;
2027 
2028     memset(&resourcesW, 0, sizeof(resourcesW));
2029     resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
2030     resourcesW.lpLocalName = (LPWSTR)lpLocalName;
2031     return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
2032 }
2033 
2034 /*********************************************************************
2035  *  WNetAddConnection2A [MPR.@]
2036  */
WNetAddConnection2A(LPNETRESOURCEA lpNetResource,LPCSTR lpPassword,LPCSTR lpUserID,DWORD dwFlags)2037 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
2038                                   LPCSTR lpPassword, LPCSTR lpUserID,
2039                                   DWORD dwFlags )
2040 {
2041     return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
2042                               NULL, 0, NULL);
2043 }
2044 
2045 /*********************************************************************
2046  * WNetAddConnection2W [MPR.@]
2047  */
WNetAddConnection2W(LPNETRESOURCEW lpNetResource,LPCWSTR lpPassword,LPCWSTR lpUserID,DWORD dwFlags)2048 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
2049                                   LPCWSTR lpPassword, LPCWSTR lpUserID,
2050                                   DWORD dwFlags )
2051 {
2052     return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
2053                               NULL, 0, NULL);
2054 }
2055 
2056 /*********************************************************************
2057  * WNetAddConnection3A [MPR.@]
2058  */
WNetAddConnection3A(HWND hwndOwner,LPNETRESOURCEA lpNetResource,LPCSTR lpPassword,LPCSTR lpUserID,DWORD dwFlags)2059 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
2060                                   LPCSTR lpPassword, LPCSTR lpUserID,
2061                                   DWORD dwFlags )
2062 {
2063     return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
2064                               dwFlags, NULL, 0, NULL);
2065 }
2066 
2067 /*********************************************************************
2068  * WNetAddConnection3W [MPR.@]
2069  */
WNetAddConnection3W(HWND hwndOwner,LPNETRESOURCEW lpNetResource,LPCWSTR lpPassword,LPCWSTR lpUserID,DWORD dwFlags)2070 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
2071                                   LPCWSTR lpPassword, LPCWSTR lpUserID,
2072                                   DWORD dwFlags )
2073 {
2074     return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
2075                               dwFlags, NULL, 0, NULL);
2076 }
2077 
2078 struct use_connection_context
2079 {
2080     HWND hwndOwner;
2081     NETRESOURCEW *resource;
2082     NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
2083     WCHAR *password;
2084     WCHAR *userid;
2085     DWORD flags;
2086     void *accessname;
2087     DWORD *buffer_size;
2088     DWORD *result;
2089     DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
2090     void  (*set_accessname)(struct use_connection_context*, WCHAR *);
2091 };
2092 
use_connection_pre_set_accessnameW(struct use_connection_context * ctxt,WCHAR * local_name)2093 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
2094 {
2095     if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
2096     {
2097         DWORD len;
2098 
2099         if (local_name)
2100             len = lstrlenW(local_name);
2101         else
2102             len = lstrlenW(ctxt->resource->lpRemoteName);
2103 
2104         if (++len > *ctxt->buffer_size)
2105         {
2106             *ctxt->buffer_size = len;
2107             return ERROR_MORE_DATA;
2108         }
2109     }
2110     else
2111         ctxt->accessname = NULL;
2112 
2113     return ERROR_SUCCESS;
2114 }
2115 
use_connection_set_accessnameW(struct use_connection_context * ctxt,WCHAR * local_name)2116 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
2117 {
2118     WCHAR *accessname = ctxt->accessname;
2119     if (local_name)
2120     {
2121         lstrcpyW(accessname, local_name);
2122         if (ctxt->result)
2123             *ctxt->result = CONNECT_LOCALDRIVE;
2124     }
2125     else
2126         lstrcpyW(accessname, ctxt->resource->lpRemoteName);
2127 }
2128 
wnet_use_provider(struct use_connection_context * ctxt,NETRESOURCEW * netres,WNetProvider * provider,BOOLEAN redirect)2129 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
2130 {
2131     DWORD caps, ret;
2132 
2133     caps = provider->getCaps(WNNC_CONNECTION);
2134     if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
2135         return ERROR_BAD_PROVIDER;
2136 
2137     ret = WN_ACCESS_DENIED;
2138     do
2139     {
2140         if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
2141             ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
2142         else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
2143             ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
2144 
2145         if (ret == WN_ALREADY_CONNECTED && redirect)
2146             netres->lpLocalName[0] -= 1;
2147     } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
2148 
2149     if (ret == WN_SUCCESS && ctxt->accessname)
2150         ctxt->set_accessname(ctxt, netres->lpLocalName);
2151 
2152     return ret;
2153 }
2154 
2155 static const WCHAR providerType[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 };
2156 static const WCHAR userName[] = { 'U','s','e','r','N','a','m','e',0 };
2157 
wnet_use_connection(struct use_connection_context * ctxt)2158 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
2159 {
2160     WNetProvider *provider = NULL;
2161     DWORD index, ret = WN_NO_NETWORK;
2162     BOOL redirect = FALSE;
2163     WCHAR letter[3] = {'Z', ':', 0};
2164     NETRESOURCEW netres;
2165 
2166     if (!providerTable || providerTable->numProviders == 0)
2167         return WN_NO_NETWORK;
2168 
2169     if (!ctxt->resource)
2170         return ERROR_INVALID_PARAMETER;
2171     netres = *ctxt->resource;
2172 
2173     if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
2174     {
2175         if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
2176             return ERROR_BAD_DEV_TYPE;
2177 
2178         if (netres.dwType == RESOURCETYPE_PRINT)
2179         {
2180             FIXME("Local device selection is not implemented for printers.\n");
2181             return WN_NO_NETWORK;
2182         }
2183 
2184         redirect = TRUE;
2185         netres.lpLocalName = letter;
2186     }
2187 
2188     if (ctxt->flags & CONNECT_INTERACTIVE)
2189         return ERROR_BAD_NET_NAME;
2190 
2191     if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
2192         return ret;
2193 
2194     if (netres.lpProvider)
2195     {
2196         index = _findProviderIndexW(netres.lpProvider);
2197         if (index == BAD_PROVIDER_INDEX)
2198             return ERROR_BAD_PROVIDER;
2199 
2200         provider = &providerTable->table[index];
2201         ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2202     }
2203     else
2204     {
2205         for (index = 0; index < providerTable->numProviders; index++)
2206         {
2207             provider = &providerTable->table[index];
2208             ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2209             if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
2210                 break;
2211         }
2212     }
2213 
2214     if (ret == WN_SUCCESS && ctxt->flags & CONNECT_UPDATE_PROFILE)
2215     {
2216         HKEY user_profile;
2217 
2218         if (netres.dwType == RESOURCETYPE_PRINT)
2219         {
2220             FIXME("Persistent connection are not supported for printers\n");
2221             return ret;
2222         }
2223 
2224         if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2225         {
2226             HKEY network;
2227             WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres.lpLocalName[0], 0};
2228 
2229             if (RegCreateKeyExW(user_profile, subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
2230                                 KEY_ALL_ACCESS, NULL, &network, NULL) == ERROR_SUCCESS)
2231             {
2232                 DWORD dword_arg = RESOURCETYPE_DISK;
2233                 DWORD len = (lstrlenW(provider->name) + 1) * sizeof(WCHAR);
2234                 static const WCHAR empty[1] = {0};
2235 
2236                 RegSetValueExW(network, connectionType, 0, REG_DWORD, (const BYTE *)&dword_arg, sizeof(DWORD));
2237                 RegSetValueExW(network, providerName, 0, REG_SZ, (const BYTE *)provider->name, len);
2238                 RegSetValueExW(network, providerType, 0, REG_DWORD, (const BYTE *)&provider->dwNetType, sizeof(DWORD));
2239                 len = (lstrlenW(netres.lpRemoteName) + 1) * sizeof(WCHAR);
2240                 RegSetValueExW(network, remotePath, 0, REG_SZ, (const BYTE *)netres.lpRemoteName, len);
2241                 len = sizeof(empty);
2242                 RegSetValueExW(network, userName, 0, REG_SZ, (const BYTE *)empty, len);
2243                 RegCloseKey(network);
2244             }
2245 
2246             RegCloseKey(user_profile);
2247         }
2248     }
2249 
2250     return ret;
2251 }
2252 
2253 /*****************************************************************
2254  *  WNetUseConnectionW [MPR.@]
2255  */
WNetUseConnectionW(HWND hwndOwner,NETRESOURCEW * resource,LPCWSTR password,LPCWSTR userid,DWORD flags,LPWSTR accessname,DWORD * buffer_size,DWORD * result)2256 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
2257     LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
2258 {
2259     struct use_connection_context ctxt;
2260 
2261     TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2262            hwndOwner, resource, password, debugstr_w(userid), flags,
2263            accessname, buffer_size, result );
2264 
2265     ctxt.hwndOwner = hwndOwner;
2266     ctxt.resource = resource;
2267     ctxt.resourceA = NULL;
2268     ctxt.password = (WCHAR*)password;
2269     ctxt.userid = (WCHAR*)userid;
2270     ctxt.flags = flags;
2271     ctxt.accessname = accessname;
2272     ctxt.buffer_size = buffer_size;
2273     ctxt.result = result;
2274     ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
2275     ctxt.set_accessname = use_connection_set_accessnameW;
2276 
2277     return wnet_use_connection(&ctxt);
2278 }
2279 
use_connection_pre_set_accessnameA(struct use_connection_context * ctxt,WCHAR * local_name)2280 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2281 {
2282     if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
2283     {
2284         DWORD len;
2285 
2286         if (local_name)
2287             len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
2288         else
2289             len = strlen(ctxt->resourceA->lpRemoteName);
2290 
2291         if (++len > *ctxt->buffer_size)
2292         {
2293             *ctxt->buffer_size = len;
2294             return ERROR_MORE_DATA;
2295         }
2296     }
2297     else
2298         ctxt->accessname = NULL;
2299 
2300     return ERROR_SUCCESS;
2301 }
2302 
use_connection_set_accessnameA(struct use_connection_context * ctxt,WCHAR * local_name)2303 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2304 {
2305     char *accessname = ctxt->accessname;
2306     if (local_name)
2307     {
2308         WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
2309         if (ctxt->result)
2310             *ctxt->result = CONNECT_LOCALDRIVE;
2311     }
2312     else
2313         strcpy(accessname, ctxt->resourceA->lpRemoteName);
2314 }
2315 
strdupAtoW(LPCSTR str)2316 static LPWSTR strdupAtoW( LPCSTR str )
2317 {
2318     LPWSTR ret;
2319     INT len;
2320 
2321     if (!str) return NULL;
2322     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2323     ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2324     if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
2325     return ret;
2326 }
2327 
netresource_a_to_w(NETRESOURCEA * resourceA,NETRESOURCEW * resourceW)2328 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
2329 {
2330     resourceW->dwScope = resourceA->dwScope;
2331     resourceW->dwType = resourceA->dwType;
2332     resourceW->dwDisplayType = resourceA->dwDisplayType;
2333     resourceW->dwUsage = resourceA->dwUsage;
2334     resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
2335     resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
2336     resourceW->lpComment = strdupAtoW(resourceA->lpComment);
2337     resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
2338 }
2339 
free_netresourceW(NETRESOURCEW * resource)2340 static void free_netresourceW( NETRESOURCEW *resource )
2341 {
2342     HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
2343     HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
2344     HeapFree(GetProcessHeap(), 0, resource->lpComment);
2345     HeapFree(GetProcessHeap(), 0, resource->lpProvider);
2346 }
2347 
2348 /*****************************************************************
2349  *  WNetUseConnectionA [MPR.@]
2350  */
WNetUseConnectionA(HWND hwndOwner,NETRESOURCEA * resource,LPCSTR password,LPCSTR userid,DWORD flags,LPSTR accessname,DWORD * buffer_size,DWORD * result)2351 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
2352     LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
2353     DWORD *buffer_size, DWORD *result )
2354 {
2355     struct use_connection_context ctxt;
2356     NETRESOURCEW resourceW;
2357     DWORD ret;
2358 
2359     TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
2360         accessname, buffer_size, result );
2361 
2362     netresource_a_to_w(resource, &resourceW);
2363 
2364     ctxt.hwndOwner = hwndOwner;
2365     ctxt.resource = &resourceW;
2366     ctxt.resourceA = resource;
2367     ctxt.password = strdupAtoW(password);
2368     ctxt.userid = strdupAtoW(userid);
2369     ctxt.flags = flags;
2370     ctxt.accessname = accessname;
2371     ctxt.buffer_size = buffer_size;
2372     ctxt.result = result;
2373     ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2374     ctxt.set_accessname = use_connection_set_accessnameA;
2375 
2376     ret = wnet_use_connection(&ctxt);
2377 
2378     free_netresourceW(&resourceW);
2379     HeapFree(GetProcessHeap(), 0, ctxt.password);
2380     HeapFree(GetProcessHeap(), 0, ctxt.userid);
2381 
2382     return ret;
2383 }
2384 
2385 /*********************************************************************
2386  *  WNetCancelConnectionA [MPR.@]
2387  */
WNetCancelConnectionA(LPCSTR lpName,BOOL fForce)2388 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2389 {
2390     return WNetCancelConnection2A(lpName, 0, fForce);
2391 }
2392 
2393 /*********************************************************************
2394  *  WNetCancelConnectionW [MPR.@]
2395  */
WNetCancelConnectionW(LPCWSTR lpName,BOOL fForce)2396 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2397 {
2398     return WNetCancelConnection2W(lpName, 0, fForce);
2399 }
2400 
2401 /*********************************************************************
2402  *  WNetCancelConnection2A [MPR.@]
2403  */
WNetCancelConnection2A(LPCSTR lpName,DWORD dwFlags,BOOL fForce)2404 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2405 {
2406     DWORD ret;
2407     WCHAR * name = strdupAtoW(lpName);
2408     if (!name)
2409         return ERROR_NOT_CONNECTED;
2410 
2411     ret = WNetCancelConnection2W(name, dwFlags, fForce);
2412     HeapFree(GetProcessHeap(), 0, name);
2413 
2414     return ret;
2415 }
2416 
2417 /*********************************************************************
2418  *  WNetCancelConnection2W [MPR.@]
2419  */
WNetCancelConnection2W(LPCWSTR lpName,DWORD dwFlags,BOOL fForce)2420 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2421 {
2422     DWORD ret = WN_NO_NETWORK;
2423     DWORD index;
2424 
2425     if (providerTable != NULL)
2426     {
2427         for (index = 0; index < providerTable->numProviders; index++)
2428         {
2429             if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2430                 WNNC_CON_CANCELCONNECTION)
2431             {
2432                 if (providerTable->table[index].cancelConnection)
2433                     ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2434                 else
2435                     ret = WN_NO_NETWORK;
2436                 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2437                     break;
2438             }
2439         }
2440     }
2441 
2442     if (ret == WN_SUCCESS && dwFlags & CONNECT_UPDATE_PROFILE)
2443     {
2444         HKEY user_profile;
2445 
2446         /* FIXME: Only remove it if that's a drive letter */
2447         if (iswalpha(lpName[0]) && lpName[1] == ':' &&
2448             RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2449         {
2450             WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName[0], 0};
2451 
2452             RegDeleteKeyW(user_profile, subkey);
2453 
2454             RegCloseKey(user_profile);
2455         }
2456     }
2457 
2458     return ret;
2459 }
2460 
2461 /*****************************************************************
2462  *  WNetRestoreConnectionA [MPR.@]
2463  */
WNetRestoreConnectionA(HWND hwndOwner,LPCSTR lpszDevice)2464 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2465 {
2466     FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2467 
2468     SetLastError(WN_NO_NETWORK);
2469     return WN_NO_NETWORK;
2470 }
2471 
2472 /*****************************************************************
2473  *  WNetRestoreConnectionW [MPR.@]
2474  */
WNetRestoreConnectionW(HWND hwndOwner,LPCWSTR lpszDevice)2475 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2476 {
2477     FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2478 
2479     SetLastError(WN_NO_NETWORK);
2480     return WN_NO_NETWORK;
2481 }
2482 
2483 /**************************************************************************
2484  * WNetGetConnectionA [MPR.@]
2485  *
2486  * RETURNS
2487  * - WN_BAD_LOCALNAME     lpLocalName makes no sense
2488  * - WN_NOT_CONNECTED     drive is a local drive
2489  * - WN_MORE_DATA         buffer isn't big enough
2490  * - WN_SUCCESS           success (net path in buffer)
2491  *
2492  * FIXME: need to test return values under different errors
2493  */
WNetGetConnectionA(LPCSTR lpLocalName,LPSTR lpRemoteName,LPDWORD lpBufferSize)2494 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2495                                  LPSTR lpRemoteName, LPDWORD lpBufferSize )
2496 {
2497     DWORD ret;
2498 
2499     if (!lpLocalName)
2500         ret = WN_BAD_POINTER;
2501     else if (!lpBufferSize)
2502         ret = WN_BAD_POINTER;
2503     else if (!lpRemoteName && *lpBufferSize)
2504         ret = WN_BAD_POINTER;
2505     else
2506     {
2507         int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2508 
2509         if (len)
2510         {
2511             PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2512 
2513             if (wideLocalName)
2514             {
2515                 WCHAR wideRemoteStatic[MAX_PATH];
2516                 DWORD wideRemoteSize = ARRAY_SIZE(wideRemoteStatic);
2517 
2518                 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2519 
2520                 /* try once without memory allocation */
2521                 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2522                  &wideRemoteSize);
2523                 if (ret == WN_SUCCESS)
2524                 {
2525                     int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2526                      -1, NULL, 0, NULL, NULL);
2527 
2528                     if (len <= *lpBufferSize)
2529                     {
2530                         WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2531                          lpRemoteName, *lpBufferSize, NULL, NULL);
2532                         ret = WN_SUCCESS;
2533                     }
2534                     else
2535                     {
2536                         *lpBufferSize = len;
2537                         ret = WN_MORE_DATA;
2538                     }
2539                 }
2540                 else if (ret == WN_MORE_DATA)
2541                 {
2542                     PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2543                      wideRemoteSize * sizeof(WCHAR));
2544 
2545                     if (wideRemote)
2546                     {
2547                         ret = WNetGetConnectionW(wideLocalName, wideRemote,
2548                          &wideRemoteSize);
2549                         if (ret == WN_SUCCESS)
2550                         {
2551                             if (len <= *lpBufferSize)
2552                             {
2553                                 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2554                                  -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2555                                 ret = WN_SUCCESS;
2556                             }
2557                             else
2558                             {
2559                                 *lpBufferSize = len;
2560                                 ret = WN_MORE_DATA;
2561                             }
2562                         }
2563                         HeapFree(GetProcessHeap(), 0, wideRemote);
2564                     }
2565                     else
2566                         ret = WN_OUT_OF_MEMORY;
2567                 }
2568                 HeapFree(GetProcessHeap(), 0, wideLocalName);
2569             }
2570             else
2571                 ret = WN_OUT_OF_MEMORY;
2572         }
2573         else
2574             ret = WN_BAD_LOCALNAME;
2575     }
2576     if (ret)
2577         SetLastError(ret);
2578     TRACE("Returning %d\n", ret);
2579     return ret;
2580 }
2581 
2582 /* find the network connection for a given drive; helper for WNetGetConnection */
get_drive_connection(WCHAR letter,LPWSTR remote,LPDWORD size)2583 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2584 {
2585 #ifndef __REACTOS__
2586     char buffer[1024];
2587     struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2588     HANDLE mgr;
2589     DWORD ret = WN_NOT_CONNECTED;
2590     DWORD bytes_returned;
2591 
2592     if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2593                             FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2594                             0, 0 )) == INVALID_HANDLE_VALUE)
2595     {
2596         ERR( "failed to open mount manager err %u\n", GetLastError() );
2597         return ret;
2598     }
2599     memset( data, 0, sizeof(*data) );
2600     data->letter = letter;
2601     if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2602                          data, sizeof(buffer), &bytes_returned, NULL ))
2603     {
2604         char *p, *mount_point = buffer + data->mount_point_offset;
2605         DWORD len;
2606 
2607         if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2608         {
2609             mount_point += 2;
2610             mount_point[0] = '\\';
2611             for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2612 
2613             len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2614             if (len > *size)
2615             {
2616                 *size = len;
2617                 ret = WN_MORE_DATA;
2618             }
2619             else
2620             {
2621                 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2622                 ret = WN_SUCCESS;
2623             }
2624         }
2625     }
2626     CloseHandle( mgr );
2627     return ret;
2628 #else
2629     DWORD ret = WN_NO_NETWORK;
2630     DWORD index;
2631     WCHAR local[3] = {letter, ':', 0};
2632 
2633     if (providerTable != NULL)
2634     {
2635         for (index = 0; index < providerTable->numProviders; index++)
2636         {
2637             if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2638                 WNNC_CON_GETCONNECTIONS)
2639             {
2640                 if (providerTable->table[index].getConnection)
2641                     ret = providerTable->table[index].getConnection(
2642                         local, remote, size);
2643                 else
2644                     ret = WN_NO_NETWORK;
2645                 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2646                     break;
2647             }
2648         }
2649     }
2650     if (ret)
2651         SetLastError(ret);
2652     return ret;
2653 #endif
2654 }
2655 
2656 /**************************************************************************
2657  * WNetGetConnectionW [MPR.@]
2658  *
2659  * FIXME: need to test return values under different errors
2660  */
WNetGetConnectionW(LPCWSTR lpLocalName,LPWSTR lpRemoteName,LPDWORD lpBufferSize)2661 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2662                                  LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2663 {
2664     DWORD ret;
2665 
2666     TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2667      lpBufferSize);
2668 
2669     if (!lpLocalName)
2670         ret = WN_BAD_POINTER;
2671     else if (!lpBufferSize)
2672         ret = WN_BAD_POINTER;
2673     else if (!lpRemoteName && *lpBufferSize)
2674         ret = WN_BAD_POINTER;
2675     else if (!lpLocalName[0])
2676         ret = WN_BAD_LOCALNAME;
2677     else
2678     {
2679         if (lpLocalName[1] == ':')
2680         {
2681             switch(GetDriveTypeW(lpLocalName))
2682             {
2683             case DRIVE_REMOTE:
2684                 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2685                 break;
2686             case DRIVE_REMOVABLE:
2687             case DRIVE_FIXED:
2688             case DRIVE_CDROM:
2689                 TRACE("file is local\n");
2690                 ret = WN_NOT_CONNECTED;
2691                 break;
2692             default:
2693                 ret = WN_BAD_LOCALNAME;
2694             }
2695         }
2696         else
2697             ret = WN_BAD_LOCALNAME;
2698     }
2699     if (ret)
2700         SetLastError(ret);
2701     TRACE("Returning %d\n", ret);
2702     return ret;
2703 }
2704 
2705 /**************************************************************************
2706  * WNetSetConnectionA [MPR.@]
2707  */
WNetSetConnectionA(LPCSTR lpName,DWORD dwProperty,LPVOID pvValue)2708 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2709                                  LPVOID pvValue )
2710 {
2711     FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2712 
2713     SetLastError(WN_NO_NETWORK);
2714     return WN_NO_NETWORK;
2715 }
2716 
2717 /**************************************************************************
2718  * WNetSetConnectionW [MPR.@]
2719  */
WNetSetConnectionW(LPCWSTR lpName,DWORD dwProperty,LPVOID pvValue)2720 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2721                                  LPVOID pvValue )
2722 {
2723     FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2724 
2725     SetLastError(WN_NO_NETWORK);
2726     return WN_NO_NETWORK;
2727 }
2728 
2729 /*****************************************************************
2730  * WNetGetUniversalNameA [MPR.@]
2731  */
WNetGetUniversalNameA(LPCSTR lpLocalPath,DWORD dwInfoLevel,LPVOID lpBuffer,LPDWORD lpBufferSize)2732 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2733                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
2734 {
2735     DWORD err, size;
2736 
2737     FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2738            debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2739 
2740     switch (dwInfoLevel)
2741     {
2742     case UNIVERSAL_NAME_INFO_LEVEL:
2743     {
2744         LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2745 
2746         if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2747         {
2748             err = ERROR_NOT_CONNECTED;
2749             break;
2750         }
2751 
2752         size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2753         if (*lpBufferSize < size)
2754         {
2755             err = WN_MORE_DATA;
2756             break;
2757         }
2758         info->lpUniversalName = (char *)info + sizeof(*info);
2759         lstrcpyA(info->lpUniversalName, lpLocalPath);
2760         err = WN_NO_ERROR;
2761         break;
2762     }
2763     case REMOTE_NAME_INFO_LEVEL:
2764         err = WN_NOT_CONNECTED;
2765         break;
2766 
2767     default:
2768         err = WN_BAD_VALUE;
2769         break;
2770     }
2771 
2772     SetLastError(err);
2773     return err;
2774 }
2775 
2776 /*****************************************************************
2777  * WNetGetUniversalNameW [MPR.@]
2778  */
WNetGetUniversalNameW(LPCWSTR lpLocalPath,DWORD dwInfoLevel,LPVOID lpBuffer,LPDWORD lpBufferSize)2779 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2780                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
2781 {
2782     DWORD err, size;
2783 
2784     FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2785            debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2786 
2787     switch (dwInfoLevel)
2788     {
2789     case UNIVERSAL_NAME_INFO_LEVEL:
2790     {
2791         LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2792 
2793         if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2794         {
2795             err = ERROR_NOT_CONNECTED;
2796             break;
2797         }
2798 
2799         size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2800         if (*lpBufferSize < size)
2801         {
2802             *lpBufferSize = size;
2803             err = WN_MORE_DATA;
2804             break;
2805         }
2806         info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2807         lstrcpyW(info->lpUniversalName, lpLocalPath);
2808         err = WN_NO_ERROR;
2809         break;
2810     }
2811     case REMOTE_NAME_INFO_LEVEL:
2812         err = WN_NO_NETWORK;
2813         break;
2814 
2815     default:
2816         err = WN_BAD_VALUE;
2817         break;
2818     }
2819 
2820     if (err != WN_NO_ERROR) SetLastError(err);
2821     return err;
2822 }
2823 
2824 /*****************************************************************
2825  * WNetClearConnections [MPR.@]
2826  */
WNetClearConnections(HWND owner)2827 DWORD WINAPI WNetClearConnections ( HWND owner )
2828 {
2829     HANDLE connected;
2830     PWSTR connection;
2831     DWORD ret, size, count;
2832     NETRESOURCEW * resources, * iter;
2833 
2834     ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
2835     if (ret != WN_SUCCESS)
2836     {
2837         if (ret != WN_NO_NETWORK)
2838         {
2839             return ret;
2840         }
2841 
2842         /* Means no provider, then, clearing is OK */
2843         return WN_SUCCESS;
2844     }
2845 
2846     size = 0x1000;
2847     resources = HeapAlloc(GetProcessHeap(), 0, size);
2848     if (!resources)
2849     {
2850         WNetCloseEnum(connected);
2851         return WN_OUT_OF_MEMORY;
2852     }
2853 
2854     for (;;)
2855     {
2856         size = 0x1000;
2857         count = -1;
2858 
2859         memset(resources, 0, size);
2860         ret = WNetEnumResourceW(connected, &count, resources, &size);
2861         if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2862         {
2863             for (iter = resources; count; count--, iter++)
2864             {
2865                 if (iter->lpLocalName && iter->lpLocalName[0])
2866                     connection = iter->lpLocalName;
2867                 else
2868                     connection = iter->lpRemoteName;
2869 
2870                 WNetCancelConnection2W(connection, 0, TRUE);
2871             }
2872         }
2873         else
2874             break;
2875     }
2876 
2877     HeapFree(GetProcessHeap(), 0, resources);
2878     WNetCloseEnum(connected);
2879 
2880     return ret;
2881 }
2882 
2883 
2884 /*
2885  * Other Functions
2886  */
2887 
2888 /**************************************************************************
2889  * WNetGetUserA [MPR.@]
2890  *
2891  * FIXME: we should not return ourselves, but the owner of the drive lpName
2892  */
WNetGetUserA(LPCSTR lpName,LPSTR lpUserID,LPDWORD lpBufferSize)2893 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2894 {
2895     if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2896     return GetLastError();
2897 }
2898 
2899 /*****************************************************************
2900  * WNetGetUserW [MPR.@]
2901  *
2902  * FIXME: we should not return ourselves, but the owner of the drive lpName
2903  */
WNetGetUserW(LPCWSTR lpName,LPWSTR lpUserID,LPDWORD lpBufferSize)2904 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2905 {
2906     if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2907     return GetLastError();
2908 }
2909 
2910 /*********************************************************************
2911  * WNetConnectionDialog [MPR.@]
2912  */
WNetConnectionDialog(HWND hwnd,DWORD dwType)2913 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2914 {
2915     CONNECTDLGSTRUCTW conn_dlg;
2916     NETRESOURCEW net_res;
2917 
2918     ZeroMemory(&conn_dlg, sizeof(conn_dlg));
2919     ZeroMemory(&net_res, sizeof(net_res));
2920 
2921     conn_dlg.cbStructure = sizeof(conn_dlg);
2922     conn_dlg.lpConnRes = &net_res;
2923     conn_dlg.hwndOwner = hwnd;
2924     net_res.dwType = dwType;
2925 
2926     return WNetConnectionDialog1W(&conn_dlg);
2927 }
2928 
2929 /*********************************************************************
2930  * WNetConnectionDialog1A [MPR.@]
2931  */
WNetConnectionDialog1A(LPCONNECTDLGSTRUCTA lpConnDlgStruct)2932 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2933 {
2934     FIXME( "(%p): stub\n", lpConnDlgStruct );
2935 
2936     SetLastError(WN_NO_NETWORK);
2937     return WN_NO_NETWORK;
2938 }
2939 
2940 /*********************************************************************
2941  * WNetConnectionDialog1W [MPR.@]
2942  */
WNetConnectionDialog1W(LPCONNECTDLGSTRUCTW lpConnDlgStruct)2943 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2944 {
2945     FIXME( "(%p): stub\n", lpConnDlgStruct );
2946 
2947     SetLastError(WN_NO_NETWORK);
2948     return WN_NO_NETWORK;
2949 }
2950 
2951 /*********************************************************************
2952  * WNetDisconnectDialog [MPR.@]
2953  */
WNetDisconnectDialog(HWND hwnd,DWORD dwType)2954 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2955 {
2956 #ifdef __REACTOS__
2957     DWORD dwRet;
2958     HMODULE hDll = LoadLibraryW(L"netplwiz.dll");
2959     static BOOL (WINAPI *pSHDisconnectNetDrives)(PVOID);
2960     pSHDisconnectNetDrives = (VOID *) GetProcAddress(hDll, "SHDisconnectNetDrives");
2961 
2962     dwRet = pSHDisconnectNetDrives(NULL);
2963 
2964     FreeLibrary(hDll);
2965     return dwRet;
2966 #else
2967     FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2968 
2969     SetLastError(WN_NO_NETWORK);
2970     return WN_NO_NETWORK;
2971 #endif
2972 }
2973 
2974 /*********************************************************************
2975  * WNetDisconnectDialog1A [MPR.@]
2976  */
WNetDisconnectDialog1A(LPDISCDLGSTRUCTA lpConnDlgStruct)2977 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2978 {
2979     FIXME( "(%p): stub\n", lpConnDlgStruct );
2980 
2981     SetLastError(WN_NO_NETWORK);
2982     return WN_NO_NETWORK;
2983 }
2984 
2985 /*********************************************************************
2986  * WNetDisconnectDialog1W [MPR.@]
2987  */
WNetDisconnectDialog1W(LPDISCDLGSTRUCTW lpConnDlgStruct)2988 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2989 {
2990     FIXME( "(%p): stub\n", lpConnDlgStruct );
2991 
2992     SetLastError(WN_NO_NETWORK);
2993     return WN_NO_NETWORK;
2994 }
2995 
2996 /*********************************************************************
2997  * WNetGetLastErrorA [MPR.@]
2998  */
WNetGetLastErrorA(LPDWORD lpError,LPSTR lpErrorBuf,DWORD nErrorBufSize,LPSTR lpNameBuf,DWORD nNameBufSize)2999 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
3000                                 LPSTR lpErrorBuf, DWORD nErrorBufSize,
3001                                 LPSTR lpNameBuf, DWORD nNameBufSize )
3002 {
3003     FIXME( "(%p, %p, %d, %p, %d): stub\n",
3004            lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
3005 
3006     SetLastError(WN_NO_NETWORK);
3007     return WN_NO_NETWORK;
3008 }
3009 
3010 /*********************************************************************
3011  * WNetGetLastErrorW [MPR.@]
3012  */
WNetGetLastErrorW(LPDWORD lpError,LPWSTR lpErrorBuf,DWORD nErrorBufSize,LPWSTR lpNameBuf,DWORD nNameBufSize)3013 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
3014                                 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
3015                          LPWSTR lpNameBuf, DWORD nNameBufSize )
3016 {
3017     FIXME( "(%p, %p, %d, %p, %d): stub\n",
3018            lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
3019 
3020     SetLastError(WN_NO_NETWORK);
3021     return WN_NO_NETWORK;
3022 }
3023 
3024 /*********************************************************************
3025  * WNetGetNetworkInformationA [MPR.@]
3026  */
WNetGetNetworkInformationA(LPCSTR lpProvider,LPNETINFOSTRUCT lpNetInfoStruct)3027 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
3028                                          LPNETINFOSTRUCT lpNetInfoStruct )
3029 {
3030     DWORD ret;
3031 
3032     TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
3033 
3034     if (!lpProvider)
3035         ret = WN_BAD_POINTER;
3036     else
3037     {
3038         int len;
3039 
3040         len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
3041         if (len)
3042         {
3043             LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3044 
3045             if (wideProvider)
3046             {
3047                 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
3048                  len);
3049                 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
3050                 HeapFree(GetProcessHeap(), 0, wideProvider);
3051             }
3052             else
3053                 ret = WN_OUT_OF_MEMORY;
3054         }
3055         else
3056             ret = GetLastError();
3057     }
3058     if (ret)
3059         SetLastError(ret);
3060     TRACE("Returning %d\n", ret);
3061     return ret;
3062 }
3063 
3064 /*********************************************************************
3065  * WNetGetNetworkInformationW [MPR.@]
3066  */
WNetGetNetworkInformationW(LPCWSTR lpProvider,LPNETINFOSTRUCT lpNetInfoStruct)3067 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
3068                                          LPNETINFOSTRUCT lpNetInfoStruct )
3069 {
3070     DWORD ret;
3071 
3072     TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
3073 
3074     if (!lpProvider)
3075         ret = WN_BAD_POINTER;
3076     else if (!lpNetInfoStruct)
3077         ret = WN_BAD_POINTER;
3078     else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
3079         ret = WN_BAD_VALUE;
3080     else
3081     {
3082         if (providerTable && providerTable->numProviders)
3083         {
3084             DWORD providerIndex = _findProviderIndexW(lpProvider);
3085 
3086             if (providerIndex != BAD_PROVIDER_INDEX)
3087             {
3088                 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
3089                 lpNetInfoStruct->dwProviderVersion =
3090                  providerTable->table[providerIndex].dwSpecVersion;
3091                 lpNetInfoStruct->dwStatus = NO_ERROR;
3092                 lpNetInfoStruct->dwCharacteristics = 0;
3093                 lpNetInfoStruct->dwHandle = 0;
3094                 lpNetInfoStruct->wNetType =
3095                  HIWORD(providerTable->table[providerIndex].dwNetType);
3096                 lpNetInfoStruct->dwPrinters = -1;
3097                 lpNetInfoStruct->dwDrives = -1;
3098                 ret = WN_SUCCESS;
3099             }
3100             else
3101                 ret = WN_BAD_PROVIDER;
3102         }
3103         else
3104             ret = WN_NO_NETWORK;
3105     }
3106     if (ret)
3107         SetLastError(ret);
3108     TRACE("Returning %d\n", ret);
3109     return ret;
3110 }
3111 
3112 /*****************************************************************
3113  *  WNetGetProviderNameA [MPR.@]
3114  */
WNetGetProviderNameA(DWORD dwNetType,LPSTR lpProvider,LPDWORD lpBufferSize)3115 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
3116                                    LPSTR lpProvider, LPDWORD lpBufferSize )
3117 {
3118     DWORD ret;
3119 
3120     TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
3121      lpBufferSize);
3122 
3123     if (!lpProvider)
3124         ret = WN_BAD_POINTER;
3125     else if (!lpBufferSize)
3126         ret = WN_BAD_POINTER;
3127     else
3128     {
3129         if (providerTable)
3130         {
3131             DWORD i;
3132 
3133             ret = WN_NO_NETWORK;
3134             for (i = 0; i < providerTable->numProviders &&
3135              HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
3136              i++)
3137                 ;
3138             if (i < providerTable->numProviders)
3139             {
3140                 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
3141                  providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
3142 
3143                 if (*lpBufferSize < sizeNeeded)
3144                 {
3145                     *lpBufferSize = sizeNeeded;
3146                     ret = WN_MORE_DATA;
3147                 }
3148                 else
3149                 {
3150                     WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
3151                      -1, lpProvider, *lpBufferSize, NULL, NULL);
3152                     ret = WN_SUCCESS;
3153                     /* FIXME: is *lpBufferSize set to the number of characters
3154                      * copied? */
3155                 }
3156             }
3157         }
3158         else
3159             ret = WN_NO_NETWORK;
3160     }
3161     if (ret)
3162         SetLastError(ret);
3163     TRACE("Returning %d\n", ret);
3164     return ret;
3165 }
3166 
3167 /*****************************************************************
3168  *  WNetGetProviderNameW [MPR.@]
3169  */
WNetGetProviderNameW(DWORD dwNetType,LPWSTR lpProvider,LPDWORD lpBufferSize)3170 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
3171                                    LPWSTR lpProvider, LPDWORD lpBufferSize )
3172 {
3173     DWORD ret;
3174 
3175     TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
3176      lpBufferSize);
3177 
3178     if (!lpProvider)
3179         ret = WN_BAD_POINTER;
3180     else if (!lpBufferSize)
3181         ret = WN_BAD_POINTER;
3182     else
3183     {
3184         if (providerTable)
3185         {
3186             DWORD i;
3187 
3188             ret = WN_NO_NETWORK;
3189             for (i = 0; i < providerTable->numProviders &&
3190              HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
3191              i++)
3192                 ;
3193             if (i < providerTable->numProviders)
3194             {
3195                 DWORD sizeNeeded = lstrlenW(providerTable->table[i].name) + 1;
3196 
3197                 if (*lpBufferSize < sizeNeeded)
3198                 {
3199                     *lpBufferSize = sizeNeeded;
3200                     ret = WN_MORE_DATA;
3201                 }
3202                 else
3203                 {
3204                     lstrcpyW(lpProvider, providerTable->table[i].name);
3205                     ret = WN_SUCCESS;
3206                     /* FIXME: is *lpBufferSize set to the number of characters
3207                      * copied? */
3208                 }
3209             }
3210         }
3211         else
3212             ret = WN_NO_NETWORK;
3213     }
3214     if (ret)
3215         SetLastError(ret);
3216     TRACE("Returning %d\n", ret);
3217     return ret;
3218 }
3219