dalienv.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "platform.h"
  15. #include "jlib.hpp"
  16. #include "jio.hpp"
  17. #include "jmutex.hpp"
  18. #include "jfile.hpp"
  19. #include "jptree.hpp"
  20. #include "dasds.hpp"
  21. #include "daclient.hpp"
  22. #include "environment.hpp"
  23. #include "dalienv.hpp"
  24. #include "rmtfile.hpp"
  25. struct CIpInstance
  26. {
  27. unsigned hash;
  28. IpAddress ip;
  29. CIpInstance(const IpAddress &_ip)
  30. : ip(_ip)
  31. {
  32. hash = ip.iphash();
  33. }
  34. static unsigned getHash(const char *key)
  35. {
  36. return ((const IpAddress *)key)->iphash();
  37. }
  38. bool eq(const char *key)
  39. {
  40. return ((const IpAddress *)key)->ipequals(ip);
  41. }
  42. };
  43. struct CIpPasswordInstance: public CIpInstance
  44. {
  45. StringAttr password;
  46. StringAttr user;
  47. bool matched;
  48. CIpPasswordInstance(const IpAddress &_ip)
  49. : CIpInstance(_ip)
  50. {
  51. matched = false;
  52. }
  53. static void destroy(CIpPasswordInstance *i) { delete i; }
  54. static CIpPasswordInstance *create(const char *key) { return new CIpPasswordInstance(*(const IpAddress *)key); }
  55. };
  56. struct CIpPasswordHashTable: public CMinHashTable<CIpPasswordInstance>
  57. {
  58. };
  59. struct CIpOsInstance: public CIpInstance
  60. {
  61. EnvMachineOS os;
  62. CIpOsInstance(const IpAddress &key)
  63. : CIpInstance(key)
  64. {
  65. os=MachineOsUnknown;
  66. }
  67. static void destroy(CIpOsInstance *i) { delete i; }
  68. static CIpOsInstance *create(const char *key) { return new CIpOsInstance(*(const IpAddress *)key); }
  69. };
  70. class CIpOsHashTable: public CMinHashTable<CIpOsInstance>
  71. {
  72. };
  73. class SDSPasswordProvider : public CInterface, implements IPasswordProvider
  74. {
  75. public:
  76. SDSPasswordProvider();
  77. ~SDSPasswordProvider() { delete map; }
  78. IMPLEMENT_IINTERFACE
  79. virtual bool getPassword(const IpAddress & ip, StringBuffer & username, StringBuffer & password);
  80. void clearCache()
  81. {
  82. delete map;
  83. map = new CIpPasswordHashTable();
  84. }
  85. protected:
  86. //MORE: This cache needs to be invalidated at some point...
  87. CIpPasswordHashTable *map;
  88. Owned<IConstEnvironment> env;
  89. Mutex mutex;
  90. };
  91. SDSPasswordProvider::SDSPasswordProvider()
  92. {
  93. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  94. env.setown(factory->openEnvironment());
  95. map = new CIpPasswordHashTable();
  96. }
  97. bool SDSPasswordProvider::getPassword(const IpAddress & ip, StringBuffer & username, StringBuffer & password)
  98. {
  99. synchronized procedure(mutex);
  100. if (!env)
  101. return false;
  102. CIpPasswordInstance *match = map->find((const char *)&ip,false);
  103. if (!match)
  104. {
  105. match = new CIpPasswordInstance(ip);
  106. StringBuffer ipText;
  107. ip.getIpText(ipText);
  108. Owned<IConstMachineInfo> machine = env->getMachineByAddress(ipText.str());
  109. if (machine)
  110. {
  111. Owned<IConstDomainInfo> domain = machine->getDomain();
  112. if (domain)
  113. {
  114. SCMStringBuffer username;
  115. StringAttrAdaptor strval(match->password);
  116. domain->getAccountInfo(username, strval);
  117. SCMStringBuffer domainname;
  118. domain->getName(domainname);
  119. match->user.set(domainname.s.append('\\').append(username.str()).str());
  120. match->matched = true;
  121. }
  122. }
  123. map->add(match);
  124. }
  125. username.append(match->user);
  126. password.append(match->password);
  127. return match->matched;
  128. }
  129. static CriticalSection passwordProviderCrit;
  130. static SDSPasswordProvider * passwordProvider;
  131. MODULE_INIT(INIT_PRIORITY_ENV_ENVIRONMENT)
  132. {
  133. return true;
  134. }
  135. MODULE_EXIT()
  136. {
  137. clearPasswordsFromSDS();
  138. }
  139. void __stdcall setPasswordsFromSDS()
  140. {
  141. CriticalBlock block(passwordProviderCrit);
  142. passwordProvider = new SDSPasswordProvider();
  143. setPasswordProvider(passwordProvider);
  144. }
  145. void __stdcall resetPasswordsFromSDS()
  146. {
  147. CriticalBlock block(passwordProviderCrit);
  148. if (passwordProvider)
  149. passwordProvider->clearCache();
  150. }
  151. void __stdcall clearPasswordsFromSDS()
  152. {
  153. CriticalBlock block(passwordProviderCrit);
  154. if (passwordProvider) {
  155. setPasswordProvider(NULL);
  156. passwordProvider->Release();
  157. passwordProvider = NULL;
  158. }
  159. }
  160. //---------------------------------------------------------------------------
  161. static CriticalSection ipcachesect;
  162. static CIpOsHashTable *ipToOsCache = NULL;
  163. EnvMachineOS queryOS(const IpAddress & ip)
  164. {
  165. if (ip.isLocal()) { // we know!
  166. #ifdef _WIN32
  167. return MachineOsW2K;
  168. #else
  169. return MachineOsLinux;
  170. #endif
  171. }
  172. CriticalBlock block(ipcachesect);
  173. EnvMachineOS ret = MachineOsUnknown;
  174. if (!ipToOsCache)
  175. ipToOsCache = new CIpOsHashTable;
  176. CIpOsInstance * match = ipToOsCache->find((const char *)&ip,false);
  177. if (match)
  178. ret = match->os;
  179. else {
  180. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  181. if (factory) {
  182. Owned<IConstEnvironment> env = factory->openEnvironment();
  183. if (env) {
  184. StringBuffer ipText;
  185. ip.getIpText(ipText);
  186. Owned<IConstMachineInfo> machine = env->getMachineByAddress(ipText.str());
  187. if (machine)
  188. ret = machine->getOS();
  189. }
  190. }
  191. if (ret==MachineOsUnknown) { // lets try asking dafilesrv
  192. SocketEndpoint ep(0,ip);
  193. switch (getDaliServixOs(ep)) {
  194. case DAFS_OSwindows: ret = MachineOsW2K; break;
  195. case DAFS_OSlinux: ret = MachineOsLinux; break;
  196. case DAFS_OSsolaris: ret = MachineOsSolaris; break;
  197. }
  198. }
  199. match = new CIpOsInstance(ip);
  200. match->os = ret;
  201. ipToOsCache->add(match);
  202. }
  203. return ret;
  204. }
  205. bool canAccessFilesDirectly(const IpAddress & ip)
  206. {
  207. if (ip.isLocal()||ip.isNull()) // the isNull check is probably an error but saves time
  208. return true; // I think usually already checked, but another can't harm
  209. #ifdef _WIN32
  210. EnvMachineOS os = queryOS(ip);
  211. if (os==MachineOsW2K)
  212. return true;
  213. if ((os==MachineOsUnknown)&&!testDaliServixPresent(ip))
  214. return true; // maybe lucky if windows
  215. #endif
  216. return false;
  217. }
  218. bool canSpawnChildProcess(const IpAddress & ip)
  219. {
  220. //MORE: This isn't the correct implementation, but at least the calls now have the
  221. //correct name.
  222. return canAccessFilesDirectly(ip);
  223. }
  224. bool canAccessFilesDirectly(const char * ipText)
  225. {
  226. IpAddress ip(ipText);
  227. return canAccessFilesDirectly(ip);
  228. }
  229. bool canAccessFilesDirectly(const RemoteFilename & file)
  230. {
  231. if (file.queryEndpoint().port!=0)
  232. return false;
  233. #ifdef _WIN32
  234. if (!file.isUnixPath()) // assume any windows path can be accessed using windows share
  235. return true;
  236. #endif
  237. return canAccessFilesDirectly(file.queryIP());
  238. }
  239. void setCanAccessDirectly(RemoteFilename & file)
  240. {
  241. setCanAccessDirectly(file,canAccessFilesDirectly(file));
  242. }
  243. class CDaliEnvIntercept: public CInterface, implements IFileCreateHook
  244. {
  245. bool active;
  246. CriticalSection crit;
  247. public:
  248. IMPLEMENT_IINTERFACE;
  249. CDaliEnvIntercept() { active = false; }
  250. virtual IFile * createIFile(const RemoteFilename & filename)
  251. {
  252. CriticalBlock block(crit);
  253. if (active||!daliClientActive())
  254. return NULL;
  255. active = true;
  256. IFile * ret;
  257. if (canAccessFilesDirectly(filename))
  258. ret = NULL;
  259. else
  260. ret = createDaliServixFile(filename);
  261. active = false;
  262. return ret;
  263. }
  264. } *DaliEnvIntercept;
  265. MODULE_INIT(INIT_PRIORITY_ENV_DALIENV)
  266. {
  267. DaliEnvIntercept = new CDaliEnvIntercept;
  268. addIFileCreateHook(DaliEnvIntercept);
  269. return true;
  270. }
  271. MODULE_EXIT()
  272. {
  273. removeIFileCreateHook(DaliEnvIntercept);
  274. ::Release(DaliEnvIntercept);
  275. delete ipToOsCache;
  276. ipToOsCache = NULL;
  277. }
  278. //---------------------------------------------------------------------------
  279. const char * querySlaveExecutable(const char * keyName, const char * exeName, const char * version, const IpAddress &ip, StringBuffer &progpath, StringBuffer &workdir)
  280. {
  281. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  282. Owned<IConstEnvironment> env = factory->openEnvironment();
  283. StringBuffer addr;
  284. ip.getIpText(addr);
  285. StringBufferAdaptor spp(progpath);
  286. StringBufferAdaptor swd(workdir);
  287. if (!env || !env->getRunInfo(spp, swd, keyName, version, addr.str(), exeName)) {
  288. #ifdef _DEBUG
  289. //printf("slave path not found\n");
  290. progpath.append(exeName);
  291. #ifdef _WIN32
  292. progpath.append(".exe");
  293. #endif
  294. #else
  295. throw MakeStringException(1, "Could not find the location of the slave program %s for machine %s", keyName, addr.str());
  296. #endif
  297. }
  298. // on linux check that file exists where it is supposed to be
  299. #ifndef _WIN32
  300. if (progpath.length()) {
  301. RemoteFilename rfn;
  302. SocketEndpoint ep;
  303. ep.ipset(ip);
  304. rfn.setPath(ep,progpath.str());
  305. Owned<IFile> file = createIFile(rfn);
  306. if (!file->exists()) {
  307. WARNLOG("Could not find the the slave program %s for machine %s at %s", keyName, addr.str(), progpath.str());
  308. throw MakeStringException(1, "Could not find the slave program %s for machine %s at %s", keyName, addr.str(), progpath.str());
  309. }
  310. }
  311. #endif
  312. return progpath.str();
  313. }
  314. bool getRemoteRunInfo(const char * keyName, const char * exeName, const char * version, const IpAddress &ip, StringBuffer &progpath, StringBuffer &workdir, INode *remotedali, unsigned timeout)
  315. {
  316. // use dafilesrv to work out OS
  317. StringBuffer dalis;
  318. if (remotedali)
  319. remotedali->endpoint().getUrlStr(dalis);
  320. // first get machine by IP
  321. StringBuffer ips;
  322. ip.getIpText(ips);
  323. StringBuffer xpath;
  324. xpath.appendf("Environment/Hardware/Computer[@netAddress=\"%s\"]", ips.str());
  325. Owned<IPropertyTreeIterator> iter = querySDS().getElementsRaw(xpath,remotedali,timeout);
  326. if (!iter->first()) {
  327. ERRLOG("Unable to find machine for %s on dali %s", ips.str(),dalis.str());
  328. return false;
  329. }
  330. Owned<IPropertyTree> machine;
  331. machine.setown(&iter->get());
  332. const char *domainname = machine->queryProp("@domain");
  333. if (!domainname||!*domainname) {
  334. ERRLOG("Unable to find domain for %s on dali %s", ips.str(),dalis.str());
  335. return false;
  336. }
  337. xpath.clear().appendf("Environment/Software/%s",keyName);
  338. if (version)
  339. xpath.appendf("[@version='%s']",version);
  340. xpath.append("/Instance");
  341. iter.clear();
  342. iter.setown(querySDS().getElementsRaw(xpath,remotedali,timeout));
  343. ForEach(*iter) {
  344. IPropertyTree *inst = &iter->query();
  345. const char * comp = inst->queryProp("@computer");
  346. if (comp) {
  347. xpath.clear().appendf("Environment/Hardware/Computer[@name=\"%s\"]", comp);
  348. Owned<IPropertyTreeIterator> iter2 = querySDS().getElementsRaw(xpath,remotedali,timeout);
  349. if (iter2->first()) {
  350. Owned<IPropertyTree> machine2= &iter2->get();
  351. const char *domainname2 = machine2->queryProp("@domain");
  352. const char *ips2 = machine2->queryProp("@netAddress");
  353. if (ips2&&*ips2&&domainname2&&*domainname2&&(strcmp(domainname,domainname2)==0)) {
  354. bool appendexe;
  355. char psep;
  356. SocketEndpoint ep(ips2);
  357. if (getDaliServixOs(ep)==DAFS_OSwindows) {
  358. psep = '\\';
  359. appendexe = true;
  360. }
  361. else {
  362. psep = '/';
  363. appendexe = false;
  364. }
  365. StringBuffer tmp;
  366. const char *program = inst->queryProp("@program"); // if program specified assume absolute
  367. if (!program||!*program) {
  368. tmp.append(psep).append(psep).append(ips2).append(psep).append(inst->queryProp("@directory")).append(psep).append(exeName);
  369. size32_t l = strlen(exeName);
  370. if (appendexe&&((l<5)||(stricmp(exeName+l-4,".exe")!=0)))
  371. tmp.append(".exe");
  372. program = tmp.str();
  373. }
  374. progpath.set(program);
  375. const char *workd = inst->queryProp("@workdir"); // if program specified assume absolute
  376. workdir.set(workd?workd:"");
  377. return true;
  378. }
  379. }
  380. }
  381. }
  382. return false;
  383. }
  384. bool envGetConfigurationDirectory(const char *category, const char *component,const char *instance, StringBuffer &dirout)
  385. {
  386. SessionId sessid = myProcessSession();
  387. if (!sessid)
  388. return false;
  389. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software/Directories",sessid, 0, 10000);
  390. if (conn)
  391. return getConfigurationDirectory(conn->queryRoot(),category,component,instance,dirout);
  392. return false;
  393. }