12 #include <lanahelper.h>
19 void afsi_log(TCHAR *p, ...) {
24 _vstprintf(buffer,p,marker);
26 _tcscat(buffer,_T("\n"));
28 OutputDebugString(buffer);
33 static const char *szAFSConfigKeyName = "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
34 static const char *szNetbiosNameValue = "NetbiosName";
35 static const char *szIsGatewayValue = "IsGateway";
36 static const char *szLanAdapterValue = "LanAdapter";
37 static const char *szNoFindLanaByName = "NoFindLanaByName";
39 // Use the IShellFolder API to get the connection name for the given Guid.
40 static HRESULT lana_ShellGetNameFromGuidW(WCHAR *wGuid, WCHAR *wName, int NameSize)
42 // This is the GUID for the network connections folder. It is constant.
43 // {7007ACC7-3202-11D1-AAD2-00805FC1270E}
44 const GUID CLSID_NetworkConnections = {
45 0x7007ACC7, 0x3202, 0x11D1, {
46 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
50 IShellFolder *pShellFolder;
51 IMalloc *pShellMalloc;
53 // Build the display name in the form "::{GUID}".
54 if (wcslen(wGuid) >= MAX_PATH)
56 WCHAR szAdapterGuid[MAX_PATH + 2];
57 swprintf(szAdapterGuid, L"::%ls", wGuid);
62 // Get the shell allocator.
63 HRESULT hr = SHGetMalloc(&pShellMalloc);
66 // Create an instance of the network connections folder.
67 hr = CoCreateInstance(CLSID_NetworkConnections, NULL,
68 CLSCTX_INPROC_SERVER, IID_IShellFolder,
69 reinterpret_cast<LPVOID *>(&pShellFolder));
73 hr = pShellFolder->ParseDisplayName(NULL, NULL, szAdapterGuid, NULL,
77 // Get the display name; this returns the friendly name.
79 hr = pShellFolder->GetDisplayNameOf(pidl, SHGDN_NORMAL, &sName);
81 wcsncpy(wName, sName.pOleStr, NameSize);
82 pShellMalloc->Free(pidl);
89 // Get the Connection Name for the given GUID.
90 extern "C" int lana_GetNameFromGuid(char *Guid, char **Name)
92 typedef HRESULT (WINAPI *HrLanProcAddr)(GUID *, PCWSTR, PWSTR, LPDWORD);
93 HrLanProcAddr HrLanProc = NULL;
97 WCHAR wName[MAX_PATH];
98 DWORD NameSize = MAX_PATH;
102 // Convert the Guid string to Unicode. First we ask only for the size
103 // of the converted string. Then we allocate a buffer of sufficient
104 // size to hold the result of the conversion.
105 size = MultiByteToWideChar(CP_ACP, 0, Guid, -1, NULL, 0);
106 wGuid = (WCHAR *) malloc(size * sizeof(WCHAR));
107 MultiByteToWideChar(CP_ACP, 0, Guid, -1, wGuid, size);
109 // First try the IShellFolder interface, which was unimplemented
110 // for the network connections folder before XP.
112 /* XXX pbh 9/11/03 - revert to using the undocumented APIs on XP while
113 * waiting to hear back from PSS about the slow reboot issue.
114 * This is an ugly, misleading hack, but is minimally invasive
115 * and will be easy to rollback.
118 //status = getname_shellfolder(wGuid, wName, NameSize);
121 /* XXX end of pbh 9/11/03 temporary hack*/
123 if (status == E_NOTIMPL) {
124 // The IShellFolder interface is not implemented on this platform.
125 // Try the (undocumented) HrLanConnectionNameFromGuidOrPath API
126 // from the netman DLL.
128 afsi_log("IShellFolder API not implemented, trying HrLanConnectionNameFromGuidOrPath");
130 hNetMan = LoadLibrary("netman.dll");
131 if (hNetMan == NULL) {
135 /* Super Secret Microsoft Call */
136 HrLanProc = (HrLanProcAddr) GetProcAddress(hNetMan,
137 "HrLanConnectionNameFromGuidOrPath");
138 if (HrLanProc == NULL) {
139 FreeLibrary(hNetMan);
143 status = HrLanProc(NULL, wGuid, wName, &NameSize);
144 FreeLibrary(hNetMan);
147 if (FAILED(status)) {
149 afsi_log("lana_GetNameFromGuid: failed to get connection name (status %ld)",
155 // Get the required buffer size, and then convert the string.
156 size = WideCharToMultiByte(CP_ACP, 0, wName, -1, NULL, 0, NULL, NULL);
157 name = (char *) malloc(size);
160 WideCharToMultiByte(CP_ACP, 0, wName, -1, name, size, NULL, NULL);
162 afsi_log("Connection name for %s is '%s'", Guid, name);
171 // Return an array of LANAINFOs corresponding to a connection named LanaName
172 // (NULL LanaName matches all connections), and has an IPv4 binding. Returns
173 // NULL if something goes wrong.
174 // NOTE: caller must free the returned block if non NULL.
175 extern "C" LANAINFO * lana_FindLanaByName(const char *LanaName)
177 const char RegNetBiosLinkageKeyName[] =
178 "System\\CurrentControlSet\\Services\\NetBios\\Linkage";
184 } lanamap[MAX_LANA+1];
185 DWORD lanamapsize = sizeof(lanamap);
187 char *bindpaths = NULL;
198 // Open the NetBios Linkage key.
199 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegNetBiosLinkageKeyName, 0,
200 KEY_QUERY_VALUE, &hkey);
202 if (status != ERROR_SUCCESS) {
204 afsi_log("Failed to open NetBios Linkage key (status %ld)", status);
209 // Read the lana map.
210 status = RegQueryValueEx(hkey, "LanaMap", 0, &type,
211 (BYTE *) &lanamap, &lanamapsize);
212 if (status != ERROR_SUCCESS) {
214 afsi_log("Failed to read LanaMap (status %ld)", status);
219 if (lanamapsize == 0) {
221 afsi_log("No data in LanaMap");
225 nlana = lanamapsize / sizeof(lanamap[0]);
227 // Get the bind paths for NetBios so we can match them up
228 // with the lana map. First we query for the size, so we
229 // can allocate an appropriate buffer.
230 status = RegQueryValueEx(hkey, "Bind", 0, &type, NULL, &bindpathsize);
231 if (status == ERROR_SUCCESS && bindpathsize != 0) {
232 bindpaths = (char *) malloc(bindpathsize * sizeof(char));
233 if (bindpaths == NULL) {
235 afsi_log("Cannot allocate %ld bytes for bindpaths", bindpathsize);
240 status = RegQueryValueEx(hkey, "Bind", 0, &type,
241 (BYTE *) bindpaths, &bindpathsize);
244 if (status != ERROR_SUCCESS) {
246 afsi_log("Failed to read bind paths (status %ld)", status);
248 if (bindpaths != NULL)
252 if (bindpathsize == 0) {
254 afsi_log("No bindpath data");
256 if (bindpaths != NULL)
263 lanainfo = (LANAINFO *) malloc(sizeof(LANAINFO)*2);
264 if(lanainfo == NULL) {
268 memset(lanainfo, 0, sizeof(LANAINFO) * 2);
269 lanainfo[0].lana_number = LANA_INVALID;
273 lanainfo = (LANAINFO *) malloc(sizeof(LANAINFO)*(nlana+1));
274 if(lanainfo == NULL) {
278 memset(lanainfo, 0, sizeof(LANAINFO) * (nlana+1));
283 // Iterate over the lana map entries and bind paths.
284 for (i = 0, pBind = bindpaths; i < nlana;
285 i++, pBind += strlen(pBind) + 1) {
286 // Ignore an invalid map entry.
287 if ((lanamap[i].flags & 1) == 0)
290 // check for an IPv4 binding
291 if(!strstr(pBind,"_Tcpip_"))
294 // Find the beginning of the GUID.
295 guid = strchr(pBind, '{');
297 continue; // Malformed path entry?
301 // Find the end of the GUID.
302 p = strchr(guid, '}');
304 free(guid); // Malformed GUID?
307 *++p = '\0'; // Ignore anything after the GUID.
308 status = lana_GetNameFromGuid(guid, &name);
311 if (status == 0 && name != 0)
315 if (strcmp(name, LanaName) ==0)
317 lanainfo[index].lana_number = lanamap[i].number;
318 _tcscpy(lanainfo[index].lana_name, name);
326 lanainfo[index].lana_number = lanamap[i].number;
327 _tcscpy(lanainfo[index].lana_name, name);
334 lanainfo[index].lana_number = LANA_INVALID;
340 extern "C" lana_number_t lana_FindLoopback(void)
347 memset(&ncb, 0, sizeof(ncb));
348 ncb.ncb_command = NCBENUM;
349 ncb.ncb_buffer = (UCHAR *) &lana_list;
350 ncb.ncb_length = sizeof(lana_list);
351 status = Netbios(&ncb);
354 afsi_log("Netbios NCBENUM failed: status %ld", status);
358 for (i = 0; i < lana_list.length; i++) {
359 if (lana_IsLoopback(lana_list.lana[i])) {
360 // Found one, return it.
362 afsi_log("lana_FindLoopback: Found LAN adapter %d",
365 return lana_list.lana[i];
368 // Could not find a loopback adapter.
372 // Is the given lana a Windows Loopback Adapter?
373 // TODO: implement a better check for loopback
374 // TODO: also check for proper bindings (IPv4)
375 extern "C" BOOL lana_IsLoopback(lana_number_t lana)
379 ADAPTER_STATUS status;
380 NAME_BUFFER names[MAX_LANA+1];
382 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
385 // Reset the adapter: in Win32, this is required for every process, and
386 // acts as an init call, not as a real hardware reset.
387 memset(&ncb, 0, sizeof(ncb));
388 ncb.ncb_command = NCBRESET;
389 ncb.ncb_callname[0] = 100;
390 ncb.ncb_callname[2] = 100;
391 ncb.ncb_lana_num = lana;
392 status = Netbios(&ncb);
394 status = ncb.ncb_retcode;
397 afsi_log("NCBRESET failed: lana %u, status %ld", lana, status);
402 // Use the NCBASTAT command to get the adapter address.
403 memset(&ncb, 0, sizeof(ncb));
404 ncb.ncb_command = NCBASTAT;
405 ncb.ncb_lana_num = lana;
406 strcpy((char *) ncb.ncb_callname, "* ");
407 ncb.ncb_buffer = (UCHAR *) &astat;
408 ncb.ncb_length = sizeof(astat);
409 status = Netbios(&ncb);
411 status = ncb.ncb_retcode;
412 if (ncb.ncb_retcode != 0) {
414 afsi_log("NCBASTAT failed: lana %u, status %ld", lana, status);
418 return (memcmp(astat.status.adapter_address, kWLA_MAC, 6) == 0);
421 // Get the netbios named used/to-be-used by the AFS SMB server.
422 // IF <lana specified> THEN
423 // Use specified lana
425 // Look for an adapter named "AFS", failing which,
426 // look for a loopback adapter.
428 // IF lana is for a loopback && !IsGateway THEN
429 // IF netbios name is specified THEN
430 // use specified netbios name
435 // use netbios name "<hostname>-AFS"
437 // Return ERROR_SUCCESS if netbios name was successfully generated.
438 // Returns the lana number to use in *pLana (if pLana is non-NULL) and also
439 // the IsGateway setting in *pIsGateway (if pIsGateway is non-NULL).
440 // the type of name returned.
442 // buffer is assumed to hold at least MAX_NB_NAME_LENGTH bytes.
445 // LANA_NETBIOS_NAME_IN : Use the values of *pLana and *pIsGateway as [in] parameters.
446 // LANA_NETBIOS_NAME_SUFFIX : Only return the suffix of netbios name
447 // LANA_NETBIOS_NAME_FULL : Return full netbios name
448 extern "C" long lana_GetUncServerNameEx(char *buffer, lana_number_t * pLana, int * pIsGateway, int flags) {
453 int regGateway, regNoFindLanaByName;
454 TCHAR regNbName[MAX_NB_NAME_LENGTH];
455 TCHAR nbName[MAX_NB_NAME_LENGTH];
456 TCHAR hostname[MAX_COMPUTERNAME_LENGTH+1];
458 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,szAFSConfigKeyName,0,KEY_READ,&hkConfig);
459 if(rv == ERROR_SUCCESS) {
460 if(!(flags & LANA_NETBIOS_NAME_IN) || !pLana) {
461 dummyLen = sizeof(regLana);
462 rv = RegQueryValueEx(hkConfig, szLanAdapterValue, NULL, NULL, (LPBYTE) ®Lana, &dummyLen);
463 if(rv != ERROR_SUCCESS) regLana = -1;
467 if(!(flags & LANA_NETBIOS_NAME_IN) || !pIsGateway) {
468 dummyLen = sizeof(regGateway);
469 rv = RegQueryValueEx(hkConfig, szIsGatewayValue, NULL, NULL, (LPBYTE) ®Gateway, &dummyLen);
470 if(rv != ERROR_SUCCESS) regGateway = 0;
472 regGateway = *pIsGateway;
474 dummyLen = sizeof(regNoFindLanaByName);
475 rv = RegQueryValueEx(hkConfig, szNoFindLanaByName, NULL, NULL, (LPBYTE) ®NoFindLanaByName, &dummyLen);
476 if(rv != ERROR_SUCCESS) regNoFindLanaByName = 0;
478 // Do not care if the call fails for insufficient buffer size. We are not interested
479 // in netbios names over 15 chars.
480 dummyLen = sizeof(regNbName);
481 rv = RegQueryValueEx(hkConfig, szNetbiosNameValue, NULL, NULL, (LPBYTE) ®NbName, &dummyLen);
482 if(rv != ERROR_SUCCESS) regNbName[0] = 0;
483 else regNbName[15] = 0;
485 RegCloseKey(hkConfig);
487 if(flags & LANA_NETBIOS_NAME_IN) {
488 regLana = (pLana)? *pLana: -1;
489 regGateway = (pIsGateway)? *pIsGateway: 0;
494 regNoFindLanaByName = 0;
498 if(regLana < 0 || regLana > MAX_LANA)
502 LANAINFO *lanaInfo = NULL;
503 int nLana = LANA_INVALID;
505 if (!regNoFindLanaByName)
506 lanaInfo = lana_FindLanaByName("AFS");
507 if(lanaInfo != NULL) {
508 nLana = lanaInfo[0].lana_number;
511 nLana = LANA_INVALID;
513 if(nLana == LANA_INVALID && !regGateway) {
514 nLana = lana_FindLoopback();
516 if(nLana != LANA_INVALID)
521 (regLana >=0 && lana_IsLoopback((lana_number_t) regLana))) {
522 strncpy(nbName,regNbName,15);
528 if(flags & LANA_NETBIOS_NAME_SUFFIX) {
529 strcpy(nbName,"-AFS");
531 dummyLen = sizeof(hostname);
532 // assume we are not a cluster.
533 rv = GetComputerName(hostname, &dummyLen);
534 if(!SUCCEEDED(rv)) { // should not happen, but...
537 strncpy(nbName, hostname, 11);
539 if(dot = strchr(nbName,'.'))
541 strcat(nbName,"-AFS");
545 if(pLana) *pLana = regLana;
546 if(pIsGateway) *pIsGateway = regGateway;
548 strcpy(buffer, nbName);
550 return ERROR_SUCCESS;
553 extern "C" void lana_GetUncServerNameDynamic(int lanaNumber, BOOL isGateway, TCHAR *name, int type) {
554 char szName[MAX_NB_NAME_LENGTH];
555 lana_number_t lana = (lana_number_t) lanaNumber;
556 int gateway = (int) isGateway;
558 if(SUCCEEDED(lana_GetUncServerNameEx(szName, &lana, &gateway, LANA_NETBIOS_NAME_IN | type))) {
560 mbswcs(name,szName,MAX_NB_NAME_LENGTH);
562 strncpy(name,szName,MAX_NB_NAME_LENGTH);
568 extern "C" void lana_GetUncServerName(TCHAR *name, int type) {
569 char szName[MAX_NB_NAME_LENGTH];
571 if(SUCCEEDED(lana_GetUncServerNameEx(szName,NULL,NULL,type))) {
573 mbswcs(name,szName,MAX_NB_NAME_LENGTH);
575 strncpy(name,szName,MAX_NB_NAME_LENGTH);
582 extern "C" void lana_GetAfsNameString(int lanaNumber, BOOL isGateway, TCHAR* name)
584 TCHAR netbiosName[32];
585 lana_GetUncServerNameDynamic(lanaNumber, isGateway, netbiosName, LANA_NETBIOS_NAME_FULL);
586 _stprintf(name, _T("Your UNC name to reach the root of AFS is \\\\%s\\all"), netbiosName);
589 extern "C" void lana_GetNetbiosName(LPTSTR pszName, int type)
592 TCHAR name[MAX_NB_NAME_LENGTH];
595 memset(name, 0, sizeof(name));
596 if (GetVersion() >= 0x80000000) // not WindowsNT
598 if (type == LANA_NETBIOS_NAME_SUFFIX)
600 _tcscpy(pszName, TEXT("-afs"));
604 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,szAFSConfigKeyName,0,KEY_READ,&hkCfg) == ERROR_SUCCESS) {
605 dummyLen = sizeof(name);
606 if(RegQueryValueEx(hkCfg,TEXT("Gateway"),NULL,NULL,(LPBYTE) name,&dummyLen) == ERROR_SUCCESS)
611 if (_tcslen(name) == 0)
613 _tcscpy(pszName, TEXT("unknown"));
617 _tcscpy(pszName, name);
618 _tcscat(pszName, TEXT("-afs"));
622 lana_GetUncServerName(name,type);
624 _tcscpy(pszName, name);