Windows: engage path mtu discovery for rx
[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 #ifdef USE_VMWARE
443     unsigned char kVMWare_MAC[5] = { 0x00, 0x50, 0x56, 0xC0, 0x00 };
444 #endif
445     int status;
446     HKEY hkConfig;
447     LONG rv;
448     int regLana = -1;
449     DWORD dummyLen;
450
451     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,AFSREG_CLT_SVC_PARAM_SUBKEY,0,KEY_READ,&hkConfig);
452     if (rv == ERROR_SUCCESS) {
453         dummyLen = sizeof(regLana);
454         rv = RegQueryValueEx(hkConfig, szForceLanaLoopback, NULL, NULL, (LPBYTE) &regLana, &dummyLen);
455         RegCloseKey(hkConfig);
456
457         if (regLana == lana)
458             return TRUE;
459     }
460
461     if (reset) {
462         // Reset the adapter: in Win32, this is required for every process, and
463         // acts as an init call, not as a real hardware reset.
464         memset(&ncb, 0, sizeof(ncb));
465         ncb.ncb_command = NCBRESET;
466         ncb.ncb_callname[0] = 100;
467         ncb.ncb_callname[2] = 100;
468         ncb.ncb_lana_num = lana;
469         status = Netbios(&ncb);
470         if (status == 0)
471             status = ncb.ncb_retcode;
472         if (status != 0) {
473 #ifndef NOLOGGING
474             afsi_log("NCBRESET failed: lana %u, status %ld", lana, status);
475 #endif
476             return FALSE;
477         }
478     }
479
480     // Use the NCBASTAT command to get the adapter address.
481     memset(&ncb, 0, sizeof(ncb));
482     ncb.ncb_command = NCBASTAT;
483     ncb.ncb_lana_num = lana;
484     strcpy((char *) ncb.ncb_callname, "*               ");
485     ncb.ncb_buffer = (UCHAR *) &astat;
486     ncb.ncb_length = sizeof(astat);
487     status = Netbios(&ncb);
488     if (status == 0)
489         status = ncb.ncb_retcode;
490     if (ncb.ncb_retcode != 0) {
491 #ifndef NOLOGGING   
492         afsi_log("NCBASTAT failed: lana %u, status %ld", lana, status);
493 #endif
494         return FALSE;
495     }
496     return (memcmp(astat.status.adapter_address, kWLA_MAC, 6) == 0 ||
497             memcmp(astat.status.adapter_address, kVista_WLA_MAC, 6) == 0 
498 #ifdef USE_VMWARE
499              || memcmp(astat.status.adapter_address, kVMWare_MAC, 5) == 0
500 #endif
501              );
502 }
503
504 // Get the netbios named used/to-be-used by the AFS SMB server.
505 // IF <lana specified> THEN
506 //     Use specified lana
507 // ELSE
508 //         Look for an adapter named "AFS", failing which,
509 //     look for a loopback adapter.
510 // ENDIF
511 // IF lana is for a loopback && !IsGateway THEN
512 //    IF netbios name is specified THEN
513 //       use specified netbios name
514 //    ELSE
515 //       use "AFS"
516 //    ENDIF
517 // ELSE
518 //    use netbios name "<hostname>-AFS"
519 // ENDIF
520 // Return ERROR_SUCCESS if netbios name was successfully generated.
521 // Returns the lana number to use in *pLana (if pLana is non-NULL) and also
522 //         the IsGateway setting in *pIsGateway (if pIsGateway is non-NULL).
523 //         the type of name returned.
524 //
525 // buffer is assumed to hold at least MAX_NB_NAME_LENGTH bytes.
526 //
527 // flags :
528 //      LANA_NETBIOS_NAME_IN : Use the values of *pLana and *pIsGateway as [in] parameters.
529 //      LANA_NETBIOS_NAME_SUFFIX : Only return the suffix of netbios name
530 //      LANA_NETBIOS_NAME_FULL : Return full netbios name
531 extern "C" long lana_GetUncServerNameEx(char *buffer, lana_number_t * pLana, int * pIsGateway, int flags) {
532     HKEY hkConfig;
533     DWORD dummyLen;
534     LONG rv;
535     int regLana;
536     int regGateway;
537 #ifdef USE_FINDLANABYNAME
538     int regNoFindLanaByName;
539 #endif
540     TCHAR regNbName[MAX_NB_NAME_LENGTH] = "AFS";
541     TCHAR nbName[MAX_NB_NAME_LENGTH];
542     TCHAR hostname[MAX_COMPUTERNAME_LENGTH+1];
543
544     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,AFSREG_CLT_SVC_PARAM_SUBKEY,0,KEY_READ,&hkConfig);
545     if(rv == ERROR_SUCCESS) {
546         if(!(flags & LANA_NETBIOS_NAME_IN) || !pLana) {
547             dummyLen = sizeof(regLana);
548             rv = RegQueryValueEx(hkConfig, szLanAdapterValue, NULL, NULL, (LPBYTE) &regLana, &dummyLen);
549             if(rv != ERROR_SUCCESS) 
550                 regLana = -1;
551         } else
552             regLana = *pLana;
553
554         if(!(flags & LANA_NETBIOS_NAME_IN) || !pIsGateway) {
555             dummyLen = sizeof(regGateway);
556             rv = RegQueryValueEx(hkConfig, szIsGatewayValue, NULL, NULL, (LPBYTE) &regGateway, &dummyLen);
557             if(rv != ERROR_SUCCESS) 
558                 regGateway = 0;
559         } else
560             regGateway = *pIsGateway;
561
562 #ifdef USE_FINDLANABYNAME
563         dummyLen = sizeof(regNoFindLanaByName);
564         rv = RegQueryValueEx(hkConfig, szNoFindLanaByName, NULL, NULL, (LPBYTE) &regNoFindLanaByName, &dummyLen);
565         if(rv != ERROR_SUCCESS) 
566             regNoFindLanaByName = 0;
567 #endif
568
569         // Do not care if the call fails for insufficient buffer size.  We are not interested
570         // in netbios names over 15 chars.
571         dummyLen = sizeof(regNbName);
572         rv = RegQueryValueEx(hkConfig, szNetbiosNameValue, NULL, NULL, (LPBYTE) &regNbName, &dummyLen);
573         if(rv != ERROR_SUCCESS) 
574             strcpy(regNbName, "AFS");
575         else {
576             /* Max Suffix Length is 6 */
577             regNbName[6] = 0;
578         }
579
580         RegCloseKey(hkConfig);
581     } else {
582         if(flags & LANA_NETBIOS_NAME_IN) {
583             regLana = (pLana)? *pLana: -1;
584             regGateway = (pIsGateway)? *pIsGateway: 0;
585         } else {
586             regLana = -1;
587             regGateway = 0;
588         }
589 #ifdef USE_FINDLANABYNAME 
590         regNoFindLanaByName = 0;
591 #endif
592         strcpy(regNbName, "AFS");
593     }
594
595     if(regLana < 0 || regLana > MAX_LANA) 
596         regLana = -1;
597
598     if(regLana == -1) {
599         LANAINFO *lanaInfo = NULL;
600         int nLana = LANA_INVALID;
601
602 #ifdef USE_FINDLANABYNAME
603         if (!regNoFindLanaByName)
604             lanaInfo = lana_FindLanaByName("AFS");
605 #endif
606         if(lanaInfo != NULL) {
607             nLana = lanaInfo[0].lana_number;
608             free(lanaInfo);
609         } else
610             nLana = LANA_INVALID;
611
612         if(nLana == LANA_INVALID && !regGateway) {
613             nLana = lana_FindLoopback();
614         }
615         if(nLana != LANA_INVALID) 
616             regLana = nLana;
617         }       
618
619     if(regNbName[0] &&
620         (regLana >=0 && lana_IsLoopback((lana_number_t) regLana,FALSE)))        
621     {
622         strncpy(nbName,regNbName,14);
623         nbName[14] = 0;
624         strupr(nbName);
625     } else {
626         if(flags & LANA_NETBIOS_NAME_SUFFIX) {
627             _snprintf(nbName, MAX_NB_NAME_LENGTH, "-%s", regNbName);
628             nbName[14] = 0;
629         } else {
630             char * dot;
631
632             dummyLen = sizeof(hostname);
633             // assume we are not a cluster.
634             rv = GetComputerName(hostname, &dummyLen);
635             if(!SUCCEEDED(rv)) { // should not happen, but...
636                 return rv;
637             }
638             strncpy(nbName, hostname, MAX_NB_NAME_LENGTH);
639             nbName[MAX_NB_NAME_LENGTH-1] = 0;
640             nbName[MAX_NB_NAME_LENGTH-strlen(regNbName)-2] = 0;
641             if(dot = strchr(nbName,'.'))
642                 *dot = 0;
643             strncat(nbName, "-", MAX_NB_NAME_LENGTH);
644             strncat(nbName, regNbName, MAX_NB_NAME_LENGTH);
645             nbName[MAX_NB_NAME_LENGTH-1] = 0;
646         }
647     }
648
649     if(pLana) 
650         *pLana = regLana;
651     if(pIsGateway) 
652         *pIsGateway = regGateway;
653
654     strcpy(buffer, nbName);
655
656     return ERROR_SUCCESS;
657 }
658
659 extern "C" void lana_GetUncServerNameDynamic(int lanaNumber, BOOL isGateway, TCHAR *name, int type) {
660     char szName[MAX_NB_NAME_LENGTH];
661     lana_number_t lana = (lana_number_t) lanaNumber;
662     int gateway = (int) isGateway;
663
664     if(SUCCEEDED(lana_GetUncServerNameEx(szName, &lana, &gateway, LANA_NETBIOS_NAME_IN | type))) {
665 #ifdef _UNICODE
666         mbswcs(name,szName,MAX_NB_NAME_LENGTH);
667 #else
668         strncpy(name,szName,MAX_NB_NAME_LENGTH);
669 #endif
670     } else
671         *name = _T('\0');
672 }
673
674 extern "C" void lana_GetUncServerName(TCHAR *name, int type) {
675     char szName[MAX_NB_NAME_LENGTH];
676
677     if(SUCCEEDED(lana_GetUncServerNameEx(szName,NULL,NULL,type))) {
678 #ifdef _UNICODE
679         mbswcs(name,szName,MAX_NB_NAME_LENGTH);
680 #else   
681         strncpy(name,szName,MAX_NB_NAME_LENGTH);
682 #endif
683     } else {
684         *name = _T('\0');
685     }
686 }
687
688 extern "C" void lana_GetAfsNameString(int lanaNumber, BOOL isGateway, TCHAR* name)
689 {
690     TCHAR netbiosName[32];
691     lana_GetUncServerNameDynamic(lanaNumber, isGateway, netbiosName, LANA_NETBIOS_NAME_FULL);
692     _stprintf(name, _T("Your UNC name to reach the root of AFS is \\\\%s\\all"), netbiosName);
693 }
694
695 extern "C" void lana_GetNetbiosName(LPTSTR pszName, int type)
696 {
697     HKEY hkCfg;
698     TCHAR name[MAX_NB_NAME_LENGTH];
699     DWORD dummyLen;
700
701     memset(name, 0, sizeof(name));
702     if (GetVersion() >= 0x80000000) // not WindowsNT
703     {
704         if (type == LANA_NETBIOS_NAME_SUFFIX)
705         {
706             _tcscpy(pszName, TEXT("-afs"));
707             return;
708         }
709
710         if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,AFSREG_CLT_SVC_PARAM_SUBKEY,0,KEY_READ,&hkCfg) == ERROR_SUCCESS) {
711             dummyLen = sizeof(name);
712             if(RegQueryValueEx(hkCfg,TEXT("Gateway"),NULL,NULL,(LPBYTE) name,&dummyLen) == ERROR_SUCCESS)
713                 name[0] = _T('\0');
714             RegCloseKey(hkCfg);
715         }
716
717         if (_tcslen(name) == 0)
718         {
719             _tcscpy(pszName, TEXT("unknown"));
720             return;
721         }
722
723         _tcscpy(pszName, name);
724         _tcscat(pszName, TEXT("-afs"));
725         return;
726     }
727
728     lana_GetUncServerName(name,type);
729     _tcslwr(name);
730     _tcscpy(pszName, name);
731     return;
732 }
733