e0b2eca237c616e36cb864f3c3702197463e53ce
[openafs.git] / src / WINNT / afsd / lanahelper.cpp
1 /*
2
3 Copyright 2004 by the Massachusetts Institute of Technology
4
5 All rights reserved.
6
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the name of the Massachusetts
12 Institute of Technology (M.I.T.) not be used in advertising or publicity
13 pertaining to distribution of the software without specific, written
14 prior permission.
15
16 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 SOFTWARE.
23
24 */
25
26 #include <windows.h>
27 #include <winreg.h>
28 #include <nb30.h>
29 #include <tchar.h>
30 #include <shellapi.h>
31 #include <objbase.h>
32 #include <shlobj.h>
33 #include <wtypes.h>
34 #include <string.h>
35 #include <malloc.h>
36 #include <stdio.h>
37 #include <lanahelper.h>
38 #include <WINNT\afsreg.h>
39
40 #define NOLOGGING
41 #ifndef NOLOGGING
42 extern "C" {
43 #include <stdarg.h>
44
45     void afsi_log(TCHAR *p, ...) {
46         va_list marker;
47         TCHAR buffer[200];
48
49         va_start(marker,p);
50         _vstprintf(buffer,p,marker);
51         va_end(marker);
52         _tcscat(buffer,_T("\n"));
53
54         OutputDebugString(buffer);
55     }
56 }
57 #endif
58
59 static const char *szNetbiosNameValue = "NetbiosName";
60 static const char *szIsGatewayValue = "IsGateway";
61 static const char *szLanAdapterValue = "LanAdapter";
62 #ifdef USE_FINDLANABYNAME
63 static const char *szNoFindLanaByName = "NoFindLanaByName";
64 #endif
65 static const char *szForceLanaLoopback = "ForceLanaLoopback";
66
67 // Use the IShellFolder API to get the connection name for the given Guid.
68 static HRESULT lana_ShellGetNameFromGuidW(WCHAR *wGuid, WCHAR *wName, int NameSize)
69 {
70     // This is the GUID for the network connections folder. It is constant.
71     // {7007ACC7-3202-11D1-AAD2-00805FC1270E}
72     const GUID CLSID_NetworkConnections = {
73         0x7007ACC7, 0x3202, 0x11D1, {
74             0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
75         }
76     };
77     LPITEMIDLIST pidl;
78     IShellFolder *pShellFolder;
79     IMalloc *pShellMalloc;
80
81     // Build the display name in the form "::{GUID}".
82     if (wcslen(wGuid) >= MAX_PATH)
83         return E_INVALIDARG;
84     WCHAR szAdapterGuid[MAX_PATH + 2];
85     swprintf(szAdapterGuid, L"::%ls", wGuid);
86
87     // Initialize COM.
88     CoInitialize(NULL);
89
90     // Get the shell allocator.
91     HRESULT hr = SHGetMalloc(&pShellMalloc);
92     if (SUCCEEDED(hr))
93     {
94         // Create an instance of the network connections folder.
95         hr = CoCreateInstance(CLSID_NetworkConnections, NULL,
96                               CLSCTX_INPROC_SERVER, IID_IShellFolder,
97                               reinterpret_cast<LPVOID *>(&pShellFolder));
98     }
99     if (SUCCEEDED(hr)) 
100     {
101         hr = pShellFolder->ParseDisplayName(NULL, NULL, szAdapterGuid, NULL,
102                                             &pidl, NULL);
103     }
104     if (SUCCEEDED(hr)) {
105         // Get the display name; this returns the friendly name.
106         STRRET sName;
107         hr = pShellFolder->GetDisplayNameOf(pidl, SHGDN_NORMAL, &sName);
108         if (SUCCEEDED(hr))
109             wcsncpy(wName, sName.pOleStr, NameSize);
110         pShellMalloc->Free(pidl);
111     }
112
113     CoUninitialize();
114     return hr;
115 }
116
117 // Get the Connection Name for the given GUID.
118 extern "C" int lana_GetNameFromGuid(char *Guid, char **Name)
119 {
120     typedef HRESULT (WINAPI *HrLanProcAddr)(GUID *, PCWSTR, PWSTR, LPDWORD);
121     HrLanProcAddr HrLanProc = NULL;
122     HMODULE hNetMan;
123     int size;
124     WCHAR *wGuid = NULL;
125     WCHAR wName[MAX_PATH];
126     DWORD NameSize = MAX_PATH;
127     char *name = NULL;
128     HRESULT status;
129         
130     // Convert the Guid string to Unicode.  First we ask only for the size
131     // of the converted string.  Then we allocate a buffer of sufficient
132     // size to hold the result of the conversion.
133     size = MultiByteToWideChar(CP_ACP, 0, Guid, -1, NULL, 0);
134     wGuid = (WCHAR *) malloc(size * sizeof(WCHAR));
135     MultiByteToWideChar(CP_ACP, 0, Guid, -1, wGuid, size);
136
137     // First try the IShellFolder interface, which was unimplemented
138     // for the network connections folder before XP.
139
140     /* XXX pbh 9/11/03 - revert to using the undocumented APIs on XP while
141      *   waiting to hear back from PSS about the slow reboot issue.
142      *   This is an ugly, misleading hack, but is minimally invasive
143      *   and will be easy to rollback.
144      */
145
146     //status = getname_shellfolder(wGuid, wName, NameSize);
147     status = E_NOTIMPL;
148
149     /* XXX end of pbh 9/11/03 temporary hack*/  
150
151     if (status == E_NOTIMPL) {
152         // The IShellFolder interface is not implemented on this platform.
153         // Try the (undocumented) HrLanConnectionNameFromGuidOrPath API
154         // from the netman DLL.
155 #ifndef NOLOGGING
156         afsi_log("IShellFolder API not implemented, trying HrLanConnectionNameFromGuidOrPath");
157 #endif
158         hNetMan = LoadLibrary("netman.dll");
159         if (hNetMan == NULL) {
160             free(wGuid);
161             return -1;
162         }
163         /* Super Secret Microsoft Call */
164         HrLanProc = (HrLanProcAddr) GetProcAddress(hNetMan,
165                                                    "HrLanConnectionNameFromGuidOrPath");
166         if (HrLanProc == NULL) {
167             FreeLibrary(hNetMan);
168             free(wGuid);
169             return -1;
170         }
171         status = HrLanProc(NULL, wGuid, wName, &NameSize);
172         FreeLibrary(hNetMan);
173     }
174     free(wGuid);
175     if (FAILED(status)) {
176 #ifndef NOLOGGING
177         afsi_log("lana_GetNameFromGuid: failed to get connection name (status %ld)",
178                  status);
179 #endif
180         return -1;
181     }
182
183     // Get the required buffer size, and then convert the string.
184     size = WideCharToMultiByte(CP_ACP, 0, wName, -1, NULL, 0, NULL, NULL);
185     name = (char *) malloc(size);
186     if (name == NULL)
187         return -1;
188     WideCharToMultiByte(CP_ACP, 0, wName, -1, name, size, NULL, NULL);
189 #ifndef NOLOGGING
190     afsi_log("Connection name for %s is '%s'", Guid, name);
191 #endif
192     if (*Name)
193         *Name = name;
194     else
195         free(name);
196     return 0;
197 }
198
199 // Return an array of LANAINFOs corresponding to a connection named LanaName
200 // (NULL LanaName matches all connections), and has an IPv4 binding. Returns
201 // NULL if something goes wrong.
202 // NOTE: caller must free the returned block if non NULL.
203 extern "C" LANAINFO * lana_FindLanaByName(const char *LanaName)
204 {
205     const char RegNetBiosLinkageKeyName[] =
206         "System\\CurrentControlSet\\Services\\NetBios\\Linkage";
207     HKEY hkey;
208     LONG status;
209     struct {
210         BYTE flags;
211         BYTE number;
212     } lanamap[MAX_LANA+1];
213     DWORD lanamapsize = sizeof(lanamap);
214     DWORD type;
215     char *bindpaths = NULL;
216     DWORD bindpathsize;
217     int nlana;
218     int i;
219     char *guid;
220     char *name;
221     char *pBind;
222     char *p;
223
224     LANAINFO * lanainfo;
225
226     // Open the NetBios Linkage key.
227     status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegNetBiosLinkageKeyName, 0, 
228                           KEY_QUERY_VALUE, &hkey);
229         
230     if (status != ERROR_SUCCESS) {
231 #ifndef NOLOGGING
232         afsi_log("Failed to open NetBios Linkage key (status %ld)", status);
233 #endif
234         return NULL;
235     }
236
237     // Read the lana map.
238     status = RegQueryValueEx(hkey, "LanaMap", 0, &type,
239                          (BYTE *) &lanamap, &lanamapsize);
240     if (status != ERROR_SUCCESS) {
241 #ifndef NOLOGGING
242         afsi_log("Failed to read LanaMap (status %ld)", status);
243 #endif
244         RegCloseKey(hkey);
245         return NULL;
246     }
247     if (lanamapsize == 0) {
248 #ifndef NOLOGGING
249         afsi_log("No data in LanaMap");
250 #endif
251         return NULL;
252     }
253     nlana = lanamapsize / sizeof(lanamap[0]);
254
255     // Get the bind paths for NetBios so we can match them up
256     // with the lana map.  First we query for the size, so we
257     // can allocate an appropriate buffer.
258     status = RegQueryValueEx(hkey, "Bind", 0, &type, NULL, &bindpathsize);
259     if (status == ERROR_SUCCESS && bindpathsize != 0) {
260         bindpaths = (char *) malloc(bindpathsize * sizeof(char));
261         if (bindpaths == NULL) {
262 #ifndef NOLOGGING
263             afsi_log("Cannot allocate %ld bytes for bindpaths", bindpathsize);
264 #endif
265             RegCloseKey(hkey);
266             return NULL;
267         }
268         status = RegQueryValueEx(hkey, "Bind", 0, &type, 
269                                  (BYTE *) bindpaths, &bindpathsize);
270     }
271     RegCloseKey(hkey);
272     if (status != ERROR_SUCCESS) {
273 #ifndef NOLOGGING
274         afsi_log("Failed to read bind paths (status %ld)", status);
275 #endif
276         if (bindpaths != NULL)
277             free(bindpaths);
278         return NULL;
279       }
280     if (bindpathsize == 0) {
281 #ifndef NOLOGGING
282         afsi_log("No bindpath data");
283 #endif
284         if (bindpaths != NULL)
285             free(bindpaths);
286         return NULL;
287     }
288
289     if (LanaName)
290     {
291         lanainfo = (LANAINFO *) malloc(sizeof(LANAINFO)*2);
292         if(lanainfo == NULL) {
293             free(bindpaths);
294             return NULL;
295         }
296         memset(lanainfo, 0, sizeof(LANAINFO) * 2);
297         lanainfo[0].lana_number = LANA_INVALID;
298     }
299     else
300     {
301         lanainfo = (LANAINFO *) malloc(sizeof(LANAINFO)*(nlana+1));
302         if(lanainfo == NULL) {
303             free(bindpaths);
304             return NULL;
305         }
306         memset(lanainfo, 0, sizeof(LANAINFO) * (nlana+1));
307     }
308     
309     int index = 0;
310
311     // Iterate over the lana map entries and bind paths.
312     for (i = 0, pBind = bindpaths; i < nlana;
313          i++, pBind += strlen(pBind) + 1) {
314         // Ignore an invalid map entry.
315         if ((lanamap[i].flags & 1) == 0)
316             continue;
317
318         // check for an IPv4 binding
319         if(!strstr(pBind,"_Tcpip_"))
320             continue;
321
322         // Find the beginning of the GUID.
323         guid = strchr(pBind, '{');
324         if (guid == NULL)
325             continue;                   // Malformed path entry?
326         guid = strdup(guid);
327         if (guid == NULL)
328             continue;
329         // Find the end of the GUID.
330         p = strchr(guid, '}');
331         if (p == NULL) {
332             free(guid);                 // Malformed GUID?
333             continue;
334         }
335         *++p = '\0';                    // Ignore anything after the GUID.
336         status = lana_GetNameFromGuid(guid, &name);
337         free(guid);
338
339         if (status == 0 && name != 0)
340         {
341             if (LanaName)
342             {
343                 if (strcmp(name, LanaName) ==0)
344                 {
345                     lanainfo[index].lana_number = lanamap[i].number;
346                     _tcscpy(lanainfo[index].lana_name, name);
347                     free(name);
348                     index++;
349                     break;
350                 }
351             }
352             else
353             {
354                 lanainfo[index].lana_number = lanamap[i].number;
355                 _tcscpy(lanainfo[index].lana_name, name);
356                 free(name);
357                 index++;
358             }
359         }
360     }
361
362     lanainfo[index].lana_number = LANA_INVALID;
363
364     free(bindpaths);
365     return lanainfo;
366 }
367
368 extern "C" lana_number_t lana_FindLoopback(void)
369 {
370     NCB ncb;
371     LANA_ENUM lana_list;
372     int status;
373     int i;
374
375     memset(&ncb, 0, sizeof(ncb));
376     ncb.ncb_command = NCBENUM;
377     ncb.ncb_buffer = (UCHAR *) &lana_list;
378     ncb.ncb_length = sizeof(lana_list);
379     status = Netbios(&ncb);
380     if (status != 0) {
381 #ifndef NOLOGGING
382         afsi_log("Netbios NCBENUM failed: status %ld", status);
383 #endif
384         return LANA_INVALID;
385     }
386     for (i = 0; i < lana_list.length; i++) {
387         if (lana_IsLoopback(lana_list.lana[i],TRUE)) {
388             // Found one, return it.
389 #ifndef NOLOGGING
390             afsi_log("lana_FindLoopback: Found LAN adapter %d",
391                      lana_list.lana[i]);
392 #endif
393             return lana_list.lana[i];
394         }
395     }
396     // Could not find a loopback adapter.
397     return LANA_INVALID;
398 }
399
400 /* Returns TRUE if all adapters are loopback adapters */
401 extern "C" BOOL lana_OnlyLoopback(void)
402 {
403     NCB ncb;
404     LANA_ENUM lana_list;
405     int status;
406     int i;
407
408     memset(&ncb, 0, sizeof(ncb));
409     ncb.ncb_command = NCBENUM;
410     ncb.ncb_buffer = (UCHAR *) &lana_list;
411     ncb.ncb_length = sizeof(lana_list);
412     status = Netbios(&ncb);
413     if (status != 0) {
414 #ifndef NOLOGGING
415         afsi_log("Netbios NCBENUM failed: status %ld", status);
416 #endif
417         return FALSE;
418     }
419     for (i = 0; i < lana_list.length; i++) {
420         if (!lana_IsLoopback(lana_list.lana[i],FALSE)) {
421             // Found one non-Loopback adapter
422             return FALSE;
423         }
424     }
425     // All adapters are loopback
426     return TRUE;
427 }
428
429 // Is the given lana a Windows Loopback Adapter?
430 // TODO: implement a better check for loopback
431 // TODO: also check for proper bindings (IPv4)
432 // For VMWare we only check the first five octets since the last one may vary
433 extern "C" BOOL lana_IsLoopback(lana_number_t lana, BOOL reset)
434 {
435     NCB ncb;
436     struct {
437         ADAPTER_STATUS status;
438         NAME_BUFFER names[MAX_LANA+1];
439     } astat;
440     unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
441     unsigned char kVista_WLA_MAC[6] = { 0x7F, 0x00, 0x00, 0x01, 0x4f, 0x50 };
442     unsigned char kVMWare_MAC[5] = { 0x00, 0x50, 0x56, 0xC0, 0x00 };
443     int status;
444     HKEY hkConfig;
445     LONG rv;
446     int regLana = -1;
447     DWORD dummyLen;
448
449     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,AFSREG_CLT_SVC_PARAM_SUBKEY,0,KEY_READ,&hkConfig);
450     if (rv == ERROR_SUCCESS) {
451         rv = RegQueryValueEx(hkConfig, szForceLanaLoopback, NULL, NULL, (LPBYTE) &regLana, &dummyLen);
452         RegCloseKey(hkConfig);
453
454         if (regLana == lana)
455             return TRUE;
456     }
457
458     if (reset) {
459         // Reset the adapter: in Win32, this is required for every process, and
460         // acts as an init call, not as a real hardware reset.
461         memset(&ncb, 0, sizeof(ncb));
462         ncb.ncb_command = NCBRESET;
463         ncb.ncb_callname[0] = 100;
464         ncb.ncb_callname[2] = 100;
465         ncb.ncb_lana_num = lana;
466         status = Netbios(&ncb);
467         if (status == 0)
468             status = ncb.ncb_retcode;
469         if (status != 0) {
470 #ifndef NOLOGGING
471             afsi_log("NCBRESET failed: lana %u, status %ld", lana, status);
472 #endif
473             return FALSE;
474         }
475     }
476
477     // Use the NCBASTAT command to get the adapter address.
478     memset(&ncb, 0, sizeof(ncb));
479     ncb.ncb_command = NCBASTAT;
480     ncb.ncb_lana_num = lana;
481     strcpy((char *) ncb.ncb_callname, "*               ");
482     ncb.ncb_buffer = (UCHAR *) &astat;
483     ncb.ncb_length = sizeof(astat);
484     status = Netbios(&ncb);
485     if (status == 0)
486         status = ncb.ncb_retcode;
487     if (ncb.ncb_retcode != 0) {
488 #ifndef NOLOGGING   
489         afsi_log("NCBASTAT failed: lana %u, status %ld", lana, status);
490 #endif
491         return FALSE;
492     }
493     return (memcmp(astat.status.adapter_address, kWLA_MAC, 6) == 0 ||
494             memcmp(astat.status.adapter_address, kVista_WLA_MAC, 6) == 0 ||
495             memcmp(astat.status.adapter_address, kVMWare_MAC, 5) == 0);
496 }
497
498 // Get the netbios named used/to-be-used by the AFS SMB server.
499 // IF <lana specified> THEN
500 //     Use specified lana
501 // ELSE
502 //         Look for an adapter named "AFS", failing which,
503 //     look for a loopback adapter.
504 // ENDIF
505 // IF lana is for a loopback && !IsGateway THEN
506 //    IF netbios name is specified THEN
507 //       use specified netbios name
508 //    ELSE
509 //       use "AFS"
510 //    ENDIF
511 // ELSE
512 //    use netbios name "<hostname>-AFS"
513 // ENDIF
514 // Return ERROR_SUCCESS if netbios name was successfully generated.
515 // Returns the lana number to use in *pLana (if pLana is non-NULL) and also
516 //         the IsGateway setting in *pIsGateway (if pIsGateway is non-NULL).
517 //         the type of name returned.
518 //
519 // buffer is assumed to hold at least MAX_NB_NAME_LENGTH bytes.
520 //
521 // flags :
522 //      LANA_NETBIOS_NAME_IN : Use the values of *pLana and *pIsGateway as [in] parameters.
523 //      LANA_NETBIOS_NAME_SUFFIX : Only return the suffix of netbios name
524 //      LANA_NETBIOS_NAME_FULL : Return full netbios name
525 extern "C" long lana_GetUncServerNameEx(char *buffer, lana_number_t * pLana, int * pIsGateway, int flags) {
526     HKEY hkConfig;
527     DWORD dummyLen;
528     LONG rv;
529     int regLana;
530     int regGateway;
531 #ifdef USE_FINDLANABYNAME
532     int regNoFindLanaByName;
533 #endif
534     TCHAR regNbName[MAX_NB_NAME_LENGTH] = "AFS";
535     TCHAR nbName[MAX_NB_NAME_LENGTH];
536     TCHAR hostname[MAX_COMPUTERNAME_LENGTH+1];
537
538     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,AFSREG_CLT_SVC_PARAM_SUBKEY,0,KEY_READ,&hkConfig);
539     if(rv == ERROR_SUCCESS) {
540         if(!(flags & LANA_NETBIOS_NAME_IN) || !pLana) {
541             dummyLen = sizeof(regLana);
542             rv = RegQueryValueEx(hkConfig, szLanAdapterValue, NULL, NULL, (LPBYTE) &regLana, &dummyLen);
543             if(rv != ERROR_SUCCESS) 
544                 regLana = -1;
545         } else
546             regLana = *pLana;
547
548         if(!(flags & LANA_NETBIOS_NAME_IN) || !pIsGateway) {
549             dummyLen = sizeof(regGateway);
550             rv = RegQueryValueEx(hkConfig, szIsGatewayValue, NULL, NULL, (LPBYTE) &regGateway, &dummyLen);
551             if(rv != ERROR_SUCCESS) 
552                 regGateway = 0;
553         } else
554             regGateway = *pIsGateway;
555
556 #ifdef USE_FINDLANABYNAME
557         dummyLen = sizeof(regNoFindLanaByName);
558         rv = RegQueryValueEx(hkConfig, szNoFindLanaByName, NULL, NULL, (LPBYTE) &regNoFindLanaByName, &dummyLen);
559         if(rv != ERROR_SUCCESS) 
560             regNoFindLanaByName = 0;
561 #endif
562
563         // Do not care if the call fails for insufficient buffer size.  We are not interested
564         // in netbios names over 15 chars.
565         dummyLen = sizeof(regNbName);
566         rv = RegQueryValueEx(hkConfig, szNetbiosNameValue, NULL, NULL, (LPBYTE) &regNbName, &dummyLen);
567         if(rv != ERROR_SUCCESS) 
568             strcpy(regNbName, "AFS");
569         else 
570             regNbName[15] = 0;
571
572         RegCloseKey(hkConfig);
573     } else {
574         if(flags & LANA_NETBIOS_NAME_IN) {
575             regLana = (pLana)? *pLana: -1;
576             regGateway = (pIsGateway)? *pIsGateway: 0;
577         } else {
578             regLana = -1;
579             regGateway = 0;
580         }
581 #ifdef USE_FINDLANABYNAME 
582         regNoFindLanaByName = 0;
583 #endif
584         strcpy(regNbName, "AFS");
585     }
586
587     if(regLana < 0 || regLana > MAX_LANA) 
588         regLana = -1;
589
590     if(regLana == -1) {
591         LANAINFO *lanaInfo = NULL;
592         int nLana = LANA_INVALID;
593
594 #ifdef USE_FINDLANABYNAME
595         if (!regNoFindLanaByName)
596             lanaInfo = lana_FindLanaByName("AFS");
597 #endif
598         if(lanaInfo != NULL) {
599             nLana = lanaInfo[0].lana_number;
600             free(lanaInfo);
601         } else
602             nLana = LANA_INVALID;
603
604         if(nLana == LANA_INVALID && !regGateway) {
605             nLana = lana_FindLoopback();
606         }
607         if(nLana != LANA_INVALID) 
608             regLana = nLana;
609         }       
610
611     if(regNbName[0] &&
612         (regLana >=0 && lana_IsLoopback((lana_number_t) regLana,FALSE)))        
613     {
614         strncpy(nbName,regNbName,15);
615         nbName[16] = 0;
616         strupr(nbName);
617     } else {
618         char * dot;
619
620         if(flags & LANA_NETBIOS_NAME_SUFFIX) {
621             strcpy(nbName,"-AFS");
622         } else {
623             dummyLen = sizeof(hostname);
624             // assume we are not a cluster.
625             rv = GetComputerName(hostname, &dummyLen);
626             if(!SUCCEEDED(rv)) { // should not happen, but...
627                 return rv;
628             }
629             strncpy(nbName, hostname, 11);
630             nbName[11] = 0;
631             if(dot = strchr(nbName,'.'))
632                 *dot = 0;
633             strcat(nbName,"-AFS");
634         }
635     }
636
637     if(pLana) 
638         *pLana = regLana;
639     if(pIsGateway) 
640         *pIsGateway = regGateway;
641
642     strcpy(buffer, nbName);
643
644     return ERROR_SUCCESS;
645 }
646
647 extern "C" void lana_GetUncServerNameDynamic(int lanaNumber, BOOL isGateway, TCHAR *name, int type) {
648     char szName[MAX_NB_NAME_LENGTH];
649     lana_number_t lana = (lana_number_t) lanaNumber;
650     int gateway = (int) isGateway;
651
652     if(SUCCEEDED(lana_GetUncServerNameEx(szName, &lana, &gateway, LANA_NETBIOS_NAME_IN | type))) {
653 #ifdef _UNICODE
654         mbswcs(name,szName,MAX_NB_NAME_LENGTH);
655 #else
656         strncpy(name,szName,MAX_NB_NAME_LENGTH);
657 #endif
658     } else
659         *name = _T('\0');
660 }
661
662 extern "C" void lana_GetUncServerName(TCHAR *name, int type) {
663     char szName[MAX_NB_NAME_LENGTH];
664
665     if(SUCCEEDED(lana_GetUncServerNameEx(szName,NULL,NULL,type))) {
666 #ifdef _UNICODE
667         mbswcs(name,szName,MAX_NB_NAME_LENGTH);
668 #else   
669         strncpy(name,szName,MAX_NB_NAME_LENGTH);
670 #endif
671     } else {
672         *name = _T('\0');
673     }
674 }
675
676 extern "C" void lana_GetAfsNameString(int lanaNumber, BOOL isGateway, TCHAR* name)
677 {
678     TCHAR netbiosName[32];
679     lana_GetUncServerNameDynamic(lanaNumber, isGateway, netbiosName, LANA_NETBIOS_NAME_FULL);
680     _stprintf(name, _T("Your UNC name to reach the root of AFS is \\\\%s\\all"), netbiosName);
681 }
682
683 extern "C" void lana_GetNetbiosName(LPTSTR pszName, int type)
684 {
685     HKEY hkCfg;
686     TCHAR name[MAX_NB_NAME_LENGTH];
687     DWORD dummyLen;
688
689     memset(name, 0, sizeof(name));
690     if (GetVersion() >= 0x80000000) // not WindowsNT
691     {
692         if (type == LANA_NETBIOS_NAME_SUFFIX)
693         {
694             _tcscpy(pszName, TEXT("-afs"));
695             return;
696         }
697
698         if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,AFSREG_CLT_SVC_PARAM_SUBKEY,0,KEY_READ,&hkCfg) == ERROR_SUCCESS) {
699             dummyLen = sizeof(name);
700             if(RegQueryValueEx(hkCfg,TEXT("Gateway"),NULL,NULL,(LPBYTE) name,&dummyLen) == ERROR_SUCCESS)
701                 name[0] = _T('\0');
702             RegCloseKey(hkCfg);
703         }
704
705         if (_tcslen(name) == 0)
706         {
707             _tcscpy(pszName, TEXT("unknown"));
708             return;
709         }
710
711         _tcscpy(pszName, name);
712         _tcscat(pszName, TEXT("-afs"));
713         return;
714     }
715
716     lana_GetUncServerName(name,type);
717     _tcslwr(name);
718     _tcscpy(pszName, name);
719     return;
720 }
721