dalienv.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jlib.hpp"
  15. #include "jio.hpp"
  16. #include "jmutex.hpp"
  17. #include "jfile.hpp"
  18. #include "jptree.hpp"
  19. #include "dasds.hpp"
  20. #include "daclient.hpp"
  21. #include "environment.hpp"
  22. #include "dalienv.hpp"
  23. #include "rmtfile.hpp"
  24. struct CIpInstance
  25. {
  26. unsigned hash;
  27. IpAddress ip;
  28. CIpInstance(const IpAddress &_ip)
  29. : ip(_ip)
  30. {
  31. hash = ip.iphash();
  32. }
  33. static unsigned getHash(const char *key)
  34. {
  35. return ((const IpAddress *)key)->iphash();
  36. }
  37. bool eq(const char *key)
  38. {
  39. return ((const IpAddress *)key)->ipequals(ip);
  40. }
  41. };
  42. struct CIpPasswordInstance: public CIpInstance
  43. {
  44. StringAttr password;
  45. StringAttr user;
  46. bool matched;
  47. CIpPasswordInstance(const IpAddress &_ip)
  48. : CIpInstance(_ip)
  49. {
  50. matched = false;
  51. }
  52. static void destroy(CIpPasswordInstance *i) { delete i; }
  53. static CIpPasswordInstance *create(const char *key) { return new CIpPasswordInstance(*(const IpAddress *)key); }
  54. };
  55. struct CIpPasswordHashTable: public CMinHashTable<CIpPasswordInstance>
  56. {
  57. };
  58. struct CIpOsInstance: public CIpInstance
  59. {
  60. EnvMachineOS os;
  61. CIpOsInstance(const IpAddress &key)
  62. : CIpInstance(key)
  63. {
  64. os=MachineOsUnknown;
  65. }
  66. static void destroy(CIpOsInstance *i) { delete i; }
  67. static CIpOsInstance *create(const char *key) { return new CIpOsInstance(*(const IpAddress *)key); }
  68. };
  69. class CIpOsHashTable: public CMinHashTable<CIpOsInstance>
  70. {
  71. };
  72. class SDSPasswordProvider : public CInterface, implements IPasswordProvider
  73. {
  74. public:
  75. SDSPasswordProvider();
  76. ~SDSPasswordProvider() { delete map; }
  77. IMPLEMENT_IINTERFACE
  78. virtual bool getPassword(const IpAddress & ip, StringBuffer & username, StringBuffer & password);
  79. void clearCache()
  80. {
  81. delete map;
  82. map = new CIpPasswordHashTable();
  83. }
  84. protected:
  85. //MORE: This cache needs to be invalidated at some point...
  86. CIpPasswordHashTable *map;
  87. Owned<IConstEnvironment> env;
  88. Mutex mutex;
  89. };
  90. SDSPasswordProvider::SDSPasswordProvider()
  91. {
  92. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  93. env.setown(factory->openEnvironment());
  94. map = new CIpPasswordHashTable();
  95. }
  96. bool SDSPasswordProvider::getPassword(const IpAddress & ip, StringBuffer & username, StringBuffer & password)
  97. {
  98. synchronized procedure(mutex);
  99. if (!env)
  100. return false;
  101. CIpPasswordInstance *match = map->find((const char *)&ip,false);
  102. if (!match)
  103. {
  104. match = new CIpPasswordInstance(ip);
  105. StringBuffer ipText;
  106. ip.getIpText(ipText);
  107. Owned<IConstMachineInfo> machine = env->getMachineByAddress(ipText.str());
  108. if (machine)
  109. {
  110. Owned<IConstDomainInfo> domain = machine->getDomain();
  111. if (domain)
  112. {
  113. SCMStringBuffer username;
  114. StringAttrAdaptor strval(match->password);
  115. domain->getAccountInfo(username, strval);
  116. SCMStringBuffer domainname;
  117. domain->getName(domainname);
  118. match->user.set(domainname.s.append('\\').append(username.str()).str());
  119. match->matched = true;
  120. }
  121. }
  122. map->add(match);
  123. }
  124. username.append(match->user);
  125. password.append(match->password);
  126. return match->matched;
  127. }
  128. static CriticalSection passwordProviderCrit;
  129. static SDSPasswordProvider * passwordProvider = NULL;
  130. MODULE_INIT(INIT_PRIORITY_ENV_ENVIRONMENT)
  131. {
  132. return true;
  133. }
  134. MODULE_EXIT()
  135. {
  136. clearPasswordsFromSDS();
  137. }
  138. void __stdcall setPasswordsFromSDS()
  139. {
  140. CriticalBlock block(passwordProviderCrit);
  141. if (passwordProvider == NULL)
  142. {
  143. passwordProvider = new SDSPasswordProvider();
  144. setPasswordProvider(passwordProvider);
  145. }
  146. }
  147. void __stdcall resetPasswordsFromSDS()
  148. {
  149. CriticalBlock block(passwordProviderCrit);
  150. if (passwordProvider)
  151. passwordProvider->clearCache();
  152. }
  153. void __stdcall clearPasswordsFromSDS()
  154. {
  155. CriticalBlock block(passwordProviderCrit);
  156. if (passwordProvider) {
  157. setPasswordProvider(NULL);
  158. passwordProvider->Release();
  159. passwordProvider = NULL;
  160. }
  161. }
  162. //---------------------------------------------------------------------------
  163. static CriticalSection ipcachesect;
  164. static CIpOsHashTable *ipToOsCache = NULL;
  165. EnvMachineOS queryOS(const IpAddress & ip)
  166. {
  167. if (ip.isLocal()) { // we know!
  168. #ifdef _WIN32
  169. return MachineOsW2K;
  170. #else
  171. return MachineOsLinux;
  172. #endif
  173. }
  174. CriticalBlock block(ipcachesect);
  175. EnvMachineOS ret = MachineOsUnknown;
  176. if (!ipToOsCache)
  177. ipToOsCache = new CIpOsHashTable;
  178. CIpOsInstance * match = ipToOsCache->find((const char *)&ip,false);
  179. if (match)
  180. ret = match->os;
  181. else {
  182. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  183. if (factory) {
  184. Owned<IConstEnvironment> env = factory->openEnvironment();
  185. if (env) {
  186. StringBuffer ipText;
  187. ip.getIpText(ipText);
  188. Owned<IConstMachineInfo> machine = env->getMachineByAddress(ipText.str());
  189. if (machine)
  190. ret = machine->getOS();
  191. }
  192. }
  193. if (ret==MachineOsUnknown) { // lets try asking dafilesrv
  194. SocketEndpoint ep(0,ip);
  195. switch (getDaliServixOs(ep)) {
  196. case DAFS_OSwindows: ret = MachineOsW2K; break;
  197. case DAFS_OSlinux: ret = MachineOsLinux; break;
  198. case DAFS_OSsolaris: ret = MachineOsSolaris; break;
  199. }
  200. }
  201. match = new CIpOsInstance(ip);
  202. match->os = ret;
  203. ipToOsCache->add(match);
  204. }
  205. return ret;
  206. }
  207. bool canAccessFilesDirectly(const IpAddress & ip)
  208. {
  209. if (ip.isLocal()||ip.isNull()) // the isNull check is probably an error but saves time
  210. return true; // I think usually already checked, but another can't harm
  211. #ifdef _WIN32
  212. EnvMachineOS os = queryOS(ip);
  213. if (os==MachineOsW2K)
  214. return true;
  215. if ((os==MachineOsUnknown)&&!testDaliServixPresent(ip))
  216. return true; // maybe lucky if windows
  217. #endif
  218. return false;
  219. }
  220. bool canSpawnChildProcess(const IpAddress & ip)
  221. {
  222. //MORE: This isn't the correct implementation, but at least the calls now have the
  223. //correct name.
  224. return canAccessFilesDirectly(ip);
  225. }
  226. bool canAccessFilesDirectly(const char * ipText)
  227. {
  228. IpAddress ip(ipText);
  229. return canAccessFilesDirectly(ip);
  230. }
  231. bool canAccessFilesDirectly(const RemoteFilename & file)
  232. {
  233. if (file.queryEndpoint().port!=0)
  234. return false;
  235. #ifdef _WIN32
  236. if (!file.isUnixPath()) // assume any windows path can be accessed using windows share
  237. return true;
  238. #endif
  239. return canAccessFilesDirectly(file.queryIP());
  240. }
  241. void setCanAccessDirectly(RemoteFilename & file)
  242. {
  243. setCanAccessDirectly(file,canAccessFilesDirectly(file));
  244. }
  245. class CDaliEnvIntercept: public CInterface, implements IRemoteFileCreateHook
  246. {
  247. bool active;
  248. CriticalSection crit;
  249. public:
  250. IMPLEMENT_IINTERFACE;
  251. CDaliEnvIntercept() { active = false; }
  252. virtual IFile * createIFile(const RemoteFilename & filename)
  253. {
  254. CriticalBlock block(crit);
  255. if (active||!daliClientActive())
  256. return NULL;
  257. active = true;
  258. IFile * ret;
  259. if (canAccessFilesDirectly(filename))
  260. ret = NULL;
  261. else
  262. ret = createDaliServixFile(filename);
  263. active = false;
  264. return ret;
  265. }
  266. } *DaliEnvIntercept;
  267. MODULE_INIT(INIT_PRIORITY_ENV_DALIENV)
  268. {
  269. DaliEnvIntercept = new CDaliEnvIntercept;
  270. addIFileCreateHook(DaliEnvIntercept);
  271. return true;
  272. }
  273. MODULE_EXIT()
  274. {
  275. removeIFileCreateHook(DaliEnvIntercept);
  276. ::Release(DaliEnvIntercept);
  277. delete ipToOsCache;
  278. ipToOsCache = NULL;
  279. }
  280. //---------------------------------------------------------------------------
  281. const char * querySlaveExecutable(const char * keyName, const char * exeName, const char * version, const IpAddress &ip, StringBuffer &progpath, StringBuffer &workdir)
  282. {
  283. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  284. Owned<IConstEnvironment> env = factory->openEnvironment();
  285. StringBuffer addr;
  286. ip.getIpText(addr);
  287. StringBufferAdaptor spp(progpath);
  288. StringBufferAdaptor swd(workdir);
  289. if (!env || !env->getRunInfo(spp, swd, keyName, version, addr.str(), exeName)) {
  290. #ifdef _DEBUG
  291. //printf("slave path not found\n");
  292. progpath.append(exeName);
  293. #ifdef _WIN32
  294. progpath.append(".exe");
  295. #endif
  296. #else
  297. throw MakeStringException(1, "Could not find the location of the slave program %s for machine %s", keyName, addr.str());
  298. #endif
  299. }
  300. // on linux check that file exists where it is supposed to be
  301. #ifndef _WIN32
  302. if (progpath.length()) {
  303. RemoteFilename rfn;
  304. SocketEndpoint ep;
  305. ep.ipset(ip);
  306. rfn.setPath(ep,progpath.str());
  307. Owned<IFile> file = createIFile(rfn);
  308. if (!file->exists()) {
  309. WARNLOG("Could not find the the slave program %s for machine %s at %s", keyName, addr.str(), progpath.str());
  310. throw MakeStringException(1, "Could not find the slave program %s for machine %s at %s", keyName, addr.str(), progpath.str());
  311. }
  312. }
  313. #endif
  314. return progpath.str();
  315. }
  316. bool getRemoteRunInfo(const char * keyName, const char * exeName, const char * version, const IpAddress &ip, StringBuffer &progpath, StringBuffer &workdir, INode *remotedali, unsigned timeout)
  317. {
  318. // use dafilesrv to work out OS
  319. StringBuffer dalis;
  320. if (remotedali)
  321. remotedali->endpoint().getUrlStr(dalis);
  322. // first get machine by IP
  323. StringBuffer ips;
  324. ip.getIpText(ips);
  325. //Cannot use getEnvironmentFactory() since it is using a remotedali
  326. StringBuffer xpath;
  327. xpath.appendf("Environment/Hardware/Computer[@netAddress=\"%s\"]", ips.str());
  328. Owned<IPropertyTreeIterator> iter = querySDS().getElementsRaw(xpath,remotedali,timeout);
  329. if (!iter->first()) {
  330. ERRLOG("Unable to find machine for %s on dali %s", ips.str(),dalis.str());
  331. return false;
  332. }
  333. Owned<IPropertyTree> machine;
  334. machine.setown(&iter->get());
  335. const char *domainname = machine->queryProp("@domain");
  336. if (!domainname||!*domainname) {
  337. ERRLOG("Unable to find domain for %s on dali %s", ips.str(),dalis.str());
  338. return false;
  339. }
  340. xpath.clear().appendf("Environment/Software/%s",keyName);
  341. if (version)
  342. xpath.appendf("[@version='%s']",version);
  343. xpath.append("/Instance");
  344. iter.clear();
  345. iter.setown(querySDS().getElementsRaw(xpath,remotedali,timeout));
  346. ForEach(*iter) {
  347. IPropertyTree *inst = &iter->query();
  348. const char * comp = inst->queryProp("@computer");
  349. if (comp) {
  350. xpath.clear().appendf("Environment/Hardware/Computer[@name=\"%s\"]", comp);
  351. Owned<IPropertyTreeIterator> iter2 = querySDS().getElementsRaw(xpath,remotedali,timeout);
  352. if (iter2->first()) {
  353. Owned<IPropertyTree> machine2= &iter2->get();
  354. const char *domainname2 = machine2->queryProp("@domain");
  355. const char *ips2 = machine2->queryProp("@netAddress");
  356. if (ips2&&*ips2&&domainname2&&*domainname2&&(strcmp(domainname,domainname2)==0)) {
  357. bool appendexe;
  358. char psep;
  359. SocketEndpoint ep(ips2);
  360. if (getDaliServixOs(ep)==DAFS_OSwindows) {
  361. psep = '\\';
  362. appendexe = true;
  363. }
  364. else {
  365. psep = '/';
  366. appendexe = false;
  367. }
  368. StringBuffer tmp;
  369. const char *program = inst->queryProp("@program"); // if program specified assume absolute
  370. if (!program||!*program) {
  371. tmp.append(psep).append(psep).append(ips2).append(psep).append(inst->queryProp("@directory")).append(psep).append(exeName);
  372. size32_t l = strlen(exeName);
  373. if (appendexe&&((l<5)||(stricmp(exeName+l-4,".exe")!=0)))
  374. tmp.append(".exe");
  375. program = tmp.str();
  376. }
  377. progpath.set(program);
  378. const char *workd = inst->queryProp("@workdir"); // if program specified assume absolute
  379. workdir.set(workd?workd:"");
  380. return true;
  381. }
  382. }
  383. }
  384. }
  385. return false;
  386. }
  387. bool envGetConfigurationDirectory(const char *category, const char *component,const char *instance, StringBuffer &dirout)
  388. {
  389. SessionId sessid = myProcessSession();
  390. if (!sessid)
  391. return false;
  392. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  393. Owned<IConstEnvironment> env = factory->openEnvironment();
  394. if (env)
  395. {
  396. Owned<IPropertyTree> root = &env->getPTree();
  397. IPropertyTree * child = root->queryPropTree("Software/Directories");
  398. if (child)
  399. return getConfigurationDirectory(child,category,component,instance,dirout);
  400. }
  401. return false;
  402. }
  403. IPropertyTree *envGetNASConfiguration(IPropertyTree *source)
  404. {
  405. if ((NULL==source) || !source->hasProp("NAS"))
  406. return NULL;
  407. // check for NAS node : <Hardware><NAS><Filter ....><Filter ....>..</NAS></Hardware>
  408. if (source->hasProp("NAS/Filter"))
  409. return createPTreeFromIPT(source->queryPropTree("NAS"));
  410. else
  411. {
  412. // check for 'flat' format : <Hardware><NAS ...../><NAS ..../>....</Hardware>
  413. Owned<IPropertyTreeIterator> nasIter = source->getElements("NAS");
  414. if (!nasIter->first())
  415. return NULL;
  416. Owned<IPropertyTree> nas = createPTree("NAS");
  417. do
  418. {
  419. IPropertyTree *filter = &nasIter->query();
  420. nas->addPropTree("Filter", LINK(filter));
  421. }
  422. while (nasIter->next());
  423. return nas.getClear();
  424. }
  425. }
  426. IPropertyTree *envGetNASConfiguration()
  427. {
  428. SessionId sessid = myProcessSession();
  429. if (!sessid)
  430. return NULL;
  431. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  432. Owned<IConstEnvironment> env = factory->openEnvironment();
  433. if (env)
  434. {
  435. Owned<IPropertyTree> root = &env->getPTree();
  436. IPropertyTree * hardware = root->queryPropTree("Hardware");
  437. if (hardware)
  438. return envGetNASConfiguration(hardware);
  439. }
  440. return NULL;
  441. }
  442. IPropertyTree *envGetInstallNASHooks(SocketEndpoint *myEp)
  443. {
  444. Owned<IPropertyTree> nasPTree = envGetNASConfiguration();
  445. return envGetInstallNASHooks(nasPTree, myEp);
  446. }
  447. IPropertyTree *envGetInstallNASHooks(IPropertyTree *nasPTree, SocketEndpoint *myEp)
  448. {
  449. IDaFileSrvHook *daFileSrvHook = queryDaFileSrvHook();
  450. if (!daFileSrvHook) // probably always installed
  451. return NULL;
  452. daFileSrvHook->clearFilters();
  453. if (!nasPTree)
  454. return NULL;
  455. return daFileSrvHook->addMyFilters(nasPTree, myEp);
  456. }
  457. void envInstallNASHooks(SocketEndpoint *myEp)
  458. {
  459. Owned<IPropertyTree> installedFilters = envGetInstallNASHooks(myEp);
  460. }
  461. void envInstallNASHooks(IPropertyTree *nasPTree, SocketEndpoint *myEp)
  462. {
  463. Owned<IPropertyTree> installedFilters = envGetInstallNASHooks(nasPTree, myEp);
  464. }