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