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