#include <shellapi.h>
#include <objbase.h>
#include <shlobj.h>
-#include <shlwapi.h>
#include <wtypes.h>
#include <string.h>
#include <malloc.h>
-#include "lanahelper.h"
+#include <lanahelper.h>
+#define NOLOGGING
+#ifndef NOLOGGING
+extern "C" {
+ void afsi_log(...);
+}
+#endif
-extern "C" void afsi_log(...);
+static const char *szAFSConfigKeyName = "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
+static const char *szNetbiosNameValue = "NetbiosName";
+static const char *szIsGatewayValue = "IsGateway";
+static const char *szLanAdapterValue = "LanAdapter";
+static const char *szNoFindLanaByName = "NoFindLanaByName";
-static HRESULT getname_shellfolder(WCHAR *wGuid, WCHAR *wName, int NameSize)
+// Use the IShellFolder API to get the connection name for the given Guid.
+static HRESULT lana_ShellGetNameFromGuidW(WCHAR *wGuid, WCHAR *wName, int NameSize)
{
// This is the GUID for the network connections folder. It is constant.
// {7007ACC7-3202-11D1-AAD2-00805FC1270E}
// Get the shell allocator.
HRESULT hr = SHGetMalloc(&pShellMalloc);
if (SUCCEEDED(hr))
+ {
// Create an instance of the network connections folder.
hr = CoCreateInstance(CLSID_NetworkConnections, NULL,
CLSCTX_INPROC_SERVER, IID_IShellFolder,
reinterpret_cast<LPVOID *>(&pShellFolder));
- if (SUCCEEDED(hr))
+ }
+ if (SUCCEEDED(hr))
+ {
hr = pShellFolder->ParseDisplayName(NULL, NULL, szAdapterGuid, NULL,
&pidl, NULL);
+ }
if (SUCCEEDED(hr)) {
// Get the display name; this returns the friendly name.
STRRET sName;
// The IShellFolder interface is not implemented on this platform.
// Try the (undocumented) HrLanConnectionNameFromGuidOrPath API
// from the netman DLL.
+#ifndef NOLOGGING
afsi_log("IShellFolder API not implemented, trying HrLanConnectionNameFromGuidOrPath");
+#endif
hNetMan = LoadLibrary("netman.dll");
if (hNetMan == NULL) {
free(wGuid);
return -1;
}
+ /* Super Secret Microsoft Call */
HrLanProc = (HrLanProcAddr) GetProcAddress(hNetMan,
"HrLanConnectionNameFromGuidOrPath");
if (HrLanProc == NULL) {
}
free(wGuid);
if (FAILED(status)) {
+#ifndef NOLOGGING
afsi_log("lana_GetNameFromGuid: failed to get connection name (status %ld)",
status);
+#endif
return -1;
}
if (name == NULL)
return -1;
WideCharToMultiByte(CP_ACP, 0, wName, -1, name, size, NULL, NULL);
+#ifndef NOLOGGING
afsi_log("Connection name for %s is '%s'", Guid, name);
+#endif
if (*Name)
*Name = name;
else
return 0;
}
-// Find the lana number for the given connection name.
-extern "C" lana_number_t lana_FindLanaByName(const char *LanaName)
+// Return an array of LANAINFOs corresponding to a connection named LanaName
+// (NULL LanaName matches all connections), and has an IPv4 binding. Returns
+// NULL if something goes wrong.
+// NOTE: caller must free the returned block if non NULL.
+extern "C" LANAINFO * lana_FindLanaByName(const char *LanaName)
{
const char RegNetBiosLinkageKeyName[] =
"System\\CurrentControlSet\\Services\\NetBios\\Linkage";
char *pBind;
char *p;
+ LANAINFO * lanainfo;
+
// Open the NetBios Linkage key.
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegNetBiosLinkageKeyName, 0,
KEY_QUERY_VALUE, &hkey);
- if (status != ERROR_SUCCESS) {
+ if (status != ERROR_SUCCESS) {
+#ifndef NOLOGGING
afsi_log("Failed to open NetBios Linkage key (status %ld)", status);
- return LANA_INVALID;
+#endif
+ return NULL;
}
// Read the lana map.
status = RegQueryValueEx(hkey, "LanaMap", 0, &type,
(BYTE *) &lanamap, &lanamapsize);
if (status != ERROR_SUCCESS) {
+#ifndef NOLOGGING
afsi_log("Failed to read LanaMap (status %ld)", status);
+#endif
RegCloseKey(hkey);
- return LANA_INVALID;
+ return NULL;
}
if (lanamapsize == 0) {
+#ifndef NOLOGGING
afsi_log("No data in LanaMap");
- return LANA_INVALID;
+#endif
+ return NULL;
}
nlana = lanamapsize / sizeof(lanamap[0]);
if (status == ERROR_SUCCESS && bindpathsize != 0) {
bindpaths = (char *) malloc(bindpathsize * sizeof(char));
if (bindpaths == NULL) {
+#ifndef NOLOGGING
afsi_log("Cannot allocate %ld bytes for bindpaths", bindpathsize);
+#endif
RegCloseKey(hkey);
- return LANA_INVALID;
+ return NULL;
}
status = RegQueryValueEx(hkey, "Bind", 0, &type,
(BYTE *) bindpaths, &bindpathsize);
}
RegCloseKey(hkey);
if (status != ERROR_SUCCESS) {
+#ifndef NOLOGGING
afsi_log("Failed to read bind paths (status %ld)", status);
+#endif
if (bindpaths != NULL)
free(bindpaths);
- return LANA_INVALID;
+ return NULL;
}
if (bindpathsize == 0) {
+#ifndef NOLOGGING
afsi_log("No bindpath data");
+#endif
if (bindpaths != NULL)
free(bindpaths);
- return LANA_INVALID;
+ return NULL;
+ }
+
+ if (LanaName)
+ {
+ lanainfo = (LANAINFO *) malloc(sizeof(LANAINFO)*2);
+ if(lanainfo == NULL) {
+ free(bindpaths);
+ return NULL;
+ }
+ memset(lanainfo, 0, sizeof(LANAINFO) * 2);
+ lanainfo[0].lana_number = LANA_INVALID;
+ }
+ else
+ {
+ lanainfo = (LANAINFO *) malloc(sizeof(LANAINFO)*(nlana+1));
+ if(lanainfo == NULL) {
+ free(bindpaths);
+ return NULL;
+ }
+ memset(lanainfo, 0, sizeof(LANAINFO) * (nlana+1));
}
+
+ int index = 0;
// Iterate over the lana map entries and bind paths.
for (i = 0, pBind = bindpaths; i < nlana;
if ((lanamap[i].flags & 1) == 0)
continue;
- // check for a IPv4 binding
+ // check for an IPv4 binding
if(!strstr(pBind,"_Tcpip_"))
continue;
*++p = '\0'; // Ignore anything after the GUID.
status = lana_GetNameFromGuid(guid, &name);
free(guid);
- if (status == 0 && name != 0) {
- status = strcmp(name, LanaName);
- free(name);
- if (status == 0) {
- free(bindpaths);
- afsi_log("lana_FindLanaByName: Found lana %d for %s",
- lanamap[i].number, LanaName);
- return lanamap[i].number;
- }
- }
+
+ if (status == 0 && name != 0)
+ {
+ if (LanaName)
+ {
+ if (strcmp(name, LanaName) ==0)
+ {
+ lanainfo[index].lana_number = lanamap[i].number;
+ _tcscpy(lanainfo[index].lana_name, name);
+ free(name);
+ index++;
+ break;
+ }
+ }
+ else
+ {
+ lanainfo[index].lana_number = lanamap[i].number;
+ _tcscpy(lanainfo[index].lana_name, name);
+ free(name);
+ index++;
+ }
+ }
}
+
+ lanainfo[index].lana_number = LANA_INVALID;
+
free(bindpaths);
- return LANA_INVALID;
+ return lanainfo;
}
extern "C" lana_number_t lana_FindLoopback(void)
ncb.ncb_length = sizeof(lana_list);
status = Netbios(&ncb);
if (status != 0) {
- afsi_log("Netbios NCBENUM failed: status %ld", status);
- return LANA_INVALID;
+#ifndef NOLOGGING
+ afsi_log("Netbios NCBENUM failed: status %ld", status);
+#endif
+ return LANA_INVALID;
}
for (i = 0; i < lana_list.length; i++) {
if (lana_IsLoopback(lana_list.lana[i])) {
// Found one, return it.
+#ifndef NOLOGGING
afsi_log("lana_FindLoopback: Found LAN adapter %d",
lana_list.lana[i]);
+#endif
return lana_list.lana[i];
}
}
}
// Is the given lana a Windows Loopback Adapter?
+// TODO: implement a better check for loopback
+// TODO: also check for proper bindings (IPv4)
extern "C" BOOL lana_IsLoopback(lana_number_t lana)
{
NCB ncb;
if (status == 0)
status = ncb.ncb_retcode;
if (status != 0) {
- afsi_log("NCBRESET failed: lana %u, status %ld", lana, status);
- return FALSE;
+#ifndef NOLOGGING
+ afsi_log("NCBRESET failed: lana %u, status %ld", lana, status);
+#endif
+ return FALSE;
}
// Use the NCBASTAT command to get the adapter address.
if (status == 0)
status = ncb.ncb_retcode;
if (ncb.ncb_retcode != 0) {
+#ifndef NOLOGGING
afsi_log("NCBASTAT failed: lana %u, status %ld", lana, status);
- return FALSE;
+#endif
+ return FALSE;
}
return (memcmp(astat.status.adapter_address, kWLA_MAC, 6) == 0);
}
+
+// Get the netbios named used/to-be-used by the AFS SMB server.
+// IF <lana specified> THEN
+// Use specified lana
+// ELSE
+// Look for an adapter named "AFS", failing which,
+// look for a loopback adapter.
+// ENDIF
+// IF lana is for a loopback && !IsGateway THEN
+// IF netbios name is specified THEN
+// use specified netbios name
+// ELSE
+// use "AFS"
+// ENDIF
+// ELSE
+// use netbios name "<hostname>-AFS"
+// ENDIF
+// Return ERROR_SUCCESS if netbios name was successfully generated.
+// Returns the lana number to use in *pLana (if pLana is non-NULL) and also
+// the IsGateway setting in *pIsGateway (if pIsGateway is non-NULL).
+// the type of name returned.
+//
+// buffer is assumed to hold at least MAX_NB_NAME_LENGTH bytes.
+//
+// flags :
+// LANA_NETBIOS_NAME_IN : Use the values of *pLana and *pIsGateway as [in] parameters.
+// LANA_NETBIOS_NAME_SUFFIX : Only return the suffix of netbios name
+// LANA_NETBIOS_NAME_FULL : Return full netbios name
+extern "C" long lana_GetUncServerNameEx(char *buffer, lana_number_t * pLana, int * pIsGateway, int flags) {
+ HKEY hkConfig;
+ DWORD dummyLen;
+ LONG rv;
+ int regLana;
+ int regGateway, regNoFindLanaByName;
+ char regNbName[MAX_NB_NAME_LENGTH];
+ char nbName[MAX_NB_NAME_LENGTH];
+ char hostname[MAX_COMPUTERNAME_LENGTH+1];
+
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,szAFSConfigKeyName,0,KEY_READ,&hkConfig);
+ if(rv == ERROR_SUCCESS) {
+ if(!(flags & LANA_NETBIOS_NAME_IN) || !pLana) {
+ dummyLen = sizeof(regLana);
+ rv = RegQueryValueEx(hkConfig, szLanAdapterValue, NULL, NULL, (LPBYTE) ®Lana, &dummyLen);
+ if(rv != ERROR_SUCCESS) regLana = -1;
+ } else
+ regLana = *pLana;
+
+ if(!(flags & LANA_NETBIOS_NAME_IN) || !pIsGateway) {
+ dummyLen = sizeof(regGateway);
+ rv = RegQueryValueEx(hkConfig, szIsGatewayValue, NULL, NULL, (LPBYTE) ®Gateway, &dummyLen);
+ if(rv != ERROR_SUCCESS) regGateway = 0;
+ } else
+ regGateway = *pIsGateway;
+
+ dummyLen = sizeof(regNoFindLanaByName);
+ rv = RegQueryValueEx(hkConfig, szNoFindLanaByName, NULL, NULL, (LPBYTE) ®NoFindLanaByName, &dummyLen);
+ if(rv != ERROR_SUCCESS) regNoFindLanaByName = 0;
+
+ // Do not care if the call fails for insufficient buffer size. We are not interested
+ // in netbios names over 15 chars.
+ dummyLen = sizeof(regNbName);
+ rv = RegQueryValueEx(hkConfig, szNetbiosNameValue, NULL, NULL, (LPBYTE) ®NbName, &dummyLen);
+ if(rv != ERROR_SUCCESS) regNbName[0] = 0;
+ else regNbName[15] = 0;
+
+ RegCloseKey(hkConfig);
+ } else {
+ if(flags & LANA_NETBIOS_NAME_IN) {
+ regLana = (pLana)? *pLana: -1;
+ regGateway = (pIsGateway)? *pIsGateway: 0;
+ } else {
+ regLana = -1;
+ regGateway = 0;
+ }
+ regNoFindLanaByName = 0;
+ regNbName[0] = 0;
+ }
+
+ if(regLana < 0 || regLana > MAX_LANA)
+ regLana = -1;
+
+ if(regLana == -1) {
+ LANAINFO *lanaInfo = NULL;
+ int nLana = LANA_INVALID;
+
+ if (!regNoFindLanaByName)
+ lanaInfo = lana_FindLanaByName("AFS");
+ if(lanaInfo != NULL) {
+ nLana = lanaInfo[0].lana_number;
+ free(lanaInfo);
+ } else
+ nLana = LANA_INVALID;
+
+ if(nLana == LANA_INVALID && !regGateway) {
+ nLana = lana_FindLoopback();
+ }
+ if(nLana != LANA_INVALID)
+ regLana = nLana;
+ }
+
+ if(regLana >=0 && lana_IsLoopback((lana_number_t) regLana)) {
+ if(regNbName[0]) {
+ strncpy(nbName,regNbName,15);
+ nbName[16] = 0;
+ strupr(nbName);
+ }
+ else
+ strcpy(nbName,"AFS");
+ } else {
+ char * dot;
+
+ if(flags & LANA_NETBIOS_NAME_SUFFIX) {
+ strcpy(nbName,"-AFS");
+ } else {
+ dummyLen = sizeof(hostname);
+ // assume we are not a cluster.
+ rv = GetComputerName(hostname, &dummyLen);
+ if(!SUCCEEDED(rv)) { // should not happen, but...
+ return rv;
+ }
+ strncpy(nbName, hostname, 11);
+ nbName[11] = 0;
+ if(dot = strchr(nbName,'.'))
+ *dot = 0;
+ strcat(nbName,"-AFS");
+ }
+ }
+
+ if(pLana) *pLana = regLana;
+ if(pIsGateway) *pIsGateway = regGateway;
+
+ strcpy(buffer, nbName);
+
+ return ERROR_SUCCESS;
+}
+
+extern "C" void lana_GetUncServerNameDynamic(int lanaNumber, BOOL isGateway, TCHAR *name, int type) {
+ char szName[MAX_NB_NAME_LENGTH];
+ lana_number_t lana = (lana_number_t) lanaNumber;
+ int gateway = (int) isGateway;
+
+ if(SUCCEEDED(lana_GetUncServerNameEx(szName, &lana, &gateway, LANA_NETBIOS_NAME_IN | type))) {
+#ifdef _UNICODE
+ mbswcs(name,szName,MAX_NB_NAME_LENGTH);
+#else
+ strncpy(name,szName,MAX_NB_NAME_LENGTH);
+#endif
+ } else
+ *name = _T('\0');
+}
+
+extern "C" void lana_GetUncServerName(TCHAR *name, int type) {
+ char szName[MAX_NB_NAME_LENGTH];
+
+ if(SUCCEEDED(lana_GetUncServerNameEx(szName,NULL,NULL,type))) {
+#ifdef _UNICODE
+ mbswcs(name,szName,MAX_NB_NAME_LENGTH);
+#else
+ strncpy(name,szName,MAX_NB_NAME_LENGTH);
+#endif
+ } else {
+ *name = _T('\0');
+ }
+}
+
+extern "C" void lana_GetAfsNameString(int lanaNumber, BOOL isGateway, TCHAR* name)
+{
+ lana_GetUncServerNameDynamic(lanaNumber, isGateway, name,LANA_NETBIOS_NAME_FULL);
+ _stprintf(name, _T("Your UNC name to reach the root of AFS is \\\\%s\\all"), name);
+}
+
+extern "C" void lana_GetNetbiosName(LPTSTR pszName, int type)
+{
+ HKEY hkCfg;
+ TCHAR name[MAX_NB_NAME_LENGTH];
+ DWORD dummyLen;
+
+ memset(name, 0, sizeof(name));
+ if (GetVersion() >= 0x80000000) // not WindowsNT
+ {
+ if (type == LANA_NETBIOS_NAME_SUFFIX)
+ {
+ _tcscpy(pszName, TEXT("-afs"));
+ return;
+ }
+
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,szAFSConfigKeyName,0,KEY_READ,&hkCfg) == ERROR_SUCCESS) {
+ dummyLen = sizeof(name);
+ if(RegQueryValueEx(hkCfg,TEXT("Gateway"),NULL,NULL,(LPBYTE) name,&dummyLen) == ERROR_SUCCESS)
+ name[0] = _T('\0');
+ RegCloseKey(hkCfg);
+ }
+
+ if (_tcslen(name) == 0)
+ {
+ _tcscpy(pszName, TEXT("unknown"));
+ return;
+ }
+
+ _tcscpy(pszName, name);
+ _tcscat(pszName, TEXT("-afs"));
+ return;
+ }
+
+ lana_GetUncServerName(name,type);
+ _tcslwr(name);
+ _tcscpy(pszName, name);
+ return;
+}
+