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