security.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /*
  2. * security.c: Implementation of the XSLT security framework
  3. *
  4. * See Copyright for the status of this software.
  5. *
  6. * daniel@veillard.com
  7. */
  8. #define IN_LIBXSLT
  9. #include "libxslt.h"
  10. #include <string.h>
  11. #ifdef HAVE_SYS_TYPES_H
  12. #include <sys/types.h>
  13. #endif
  14. #ifdef HAVE_SYS_STAT_H
  15. #include <sys/stat.h>
  16. #endif
  17. #ifdef HAVE_MATH_H
  18. #include <math.h>
  19. #endif
  20. #ifdef HAVE_FLOAT_H
  21. #include <float.h>
  22. #endif
  23. #ifdef HAVE_IEEEFP_H
  24. #include <ieeefp.h>
  25. #endif
  26. #ifdef HAVE_NAN_H
  27. #include <nan.h>
  28. #endif
  29. #ifdef HAVE_CTYPE_H
  30. #include <ctype.h>
  31. #endif
  32. #if defined(_WIN32) && !defined(__CYGWIN__)
  33. #include <windows.h>
  34. #ifndef INVALID_FILE_ATTRIBUTES
  35. #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
  36. #endif
  37. #endif
  38. #ifndef HAVE_STAT
  39. # ifdef HAVE__STAT
  40. /* MS C library seems to define stat and _stat. The definition
  41. * is identical. Still, mapping them to each other causes a warning. */
  42. # ifndef _MSC_VER
  43. # define stat(x,y) _stat(x,y)
  44. # endif
  45. # define HAVE_STAT
  46. # endif
  47. #endif
  48. #include <libxml/xmlmemory.h>
  49. #include <libxml/tree.h>
  50. #include <libxml/uri.h>
  51. #include "xslt.h"
  52. #include "xsltInternals.h"
  53. #include "xsltutils.h"
  54. #include "extensions.h"
  55. #include "security.h"
  56. struct _xsltSecurityPrefs {
  57. xsltSecurityCheck readFile;
  58. xsltSecurityCheck createFile;
  59. xsltSecurityCheck createDir;
  60. xsltSecurityCheck readNet;
  61. xsltSecurityCheck writeNet;
  62. };
  63. static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs = NULL;
  64. /************************************************************************
  65. * *
  66. * Module interfaces *
  67. * *
  68. ************************************************************************/
  69. /**
  70. * xsltNewSecurityPrefs:
  71. *
  72. * Create a new security preference block
  73. *
  74. * Returns a pointer to the new block or NULL in case of error
  75. */
  76. xsltSecurityPrefsPtr
  77. xsltNewSecurityPrefs(void) {
  78. xsltSecurityPrefsPtr ret;
  79. xsltInitGlobals();
  80. ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs));
  81. if (ret == NULL) {
  82. xsltTransformError(NULL, NULL, NULL,
  83. "xsltNewSecurityPrefs : malloc failed\n");
  84. return(NULL);
  85. }
  86. memset(ret, 0, sizeof(xsltSecurityPrefs));
  87. return(ret);
  88. }
  89. /**
  90. * xsltFreeSecurityPrefs:
  91. * @sec: the security block to free
  92. *
  93. * Free up a security preference block
  94. */
  95. void
  96. xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) {
  97. if (sec == NULL)
  98. return;
  99. xmlFree(sec);
  100. }
  101. /**
  102. * xsltSetSecurityPrefs:
  103. * @sec: the security block to update
  104. * @option: the option to update
  105. * @func: the user callback to use for this option
  106. *
  107. * Update the security option to use the new callback checking function
  108. *
  109. * Returns -1 in case of error, 0 otherwise
  110. */
  111. int
  112. xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option,
  113. xsltSecurityCheck func) {
  114. xsltInitGlobals();
  115. if (sec == NULL)
  116. return(-1);
  117. switch (option) {
  118. case XSLT_SECPREF_READ_FILE:
  119. sec->readFile = func; return(0);
  120. case XSLT_SECPREF_WRITE_FILE:
  121. sec->createFile = func; return(0);
  122. case XSLT_SECPREF_CREATE_DIRECTORY:
  123. sec->createDir = func; return(0);
  124. case XSLT_SECPREF_READ_NETWORK:
  125. sec->readNet = func; return(0);
  126. case XSLT_SECPREF_WRITE_NETWORK:
  127. sec->writeNet = func; return(0);
  128. }
  129. return(-1);
  130. }
  131. /**
  132. * xsltGetSecurityPrefs:
  133. * @sec: the security block to update
  134. * @option: the option to lookup
  135. *
  136. * Lookup the security option to get the callback checking function
  137. *
  138. * Returns NULL if not found, the function otherwise
  139. */
  140. xsltSecurityCheck
  141. xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) {
  142. if (sec == NULL)
  143. return(NULL);
  144. switch (option) {
  145. case XSLT_SECPREF_READ_FILE:
  146. return(sec->readFile);
  147. case XSLT_SECPREF_WRITE_FILE:
  148. return(sec->createFile);
  149. case XSLT_SECPREF_CREATE_DIRECTORY:
  150. return(sec->createDir);
  151. case XSLT_SECPREF_READ_NETWORK:
  152. return(sec->readNet);
  153. case XSLT_SECPREF_WRITE_NETWORK:
  154. return(sec->writeNet);
  155. }
  156. return(NULL);
  157. }
  158. /**
  159. * xsltSetDefaultSecurityPrefs:
  160. * @sec: the security block to use
  161. *
  162. * Set the default security preference application-wide
  163. */
  164. void
  165. xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) {
  166. xsltDefaultSecurityPrefs = sec;
  167. }
  168. /**
  169. * xsltGetDefaultSecurityPrefs:
  170. *
  171. * Get the default security preference application-wide
  172. *
  173. * Returns the current xsltSecurityPrefsPtr in use or NULL if none
  174. */
  175. xsltSecurityPrefsPtr
  176. xsltGetDefaultSecurityPrefs(void) {
  177. return(xsltDefaultSecurityPrefs);
  178. }
  179. /**
  180. * xsltSetCtxtSecurityPrefs:
  181. * @sec: the security block to use
  182. * @ctxt: an XSLT transformation context
  183. *
  184. * Set the security preference for a specific transformation
  185. *
  186. * Returns -1 in case of error, 0 otherwise
  187. */
  188. int
  189. xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec,
  190. xsltTransformContextPtr ctxt) {
  191. if (ctxt == NULL)
  192. return(-1);
  193. ctxt->sec = (void *) sec;
  194. return(0);
  195. }
  196. /**
  197. * xsltSecurityAllow:
  198. * @sec: the security block to use
  199. * @ctxt: an XSLT transformation context
  200. * @value: unused
  201. *
  202. * Function used to always allow an operation
  203. *
  204. * Returns 1 always
  205. */
  206. int
  207. xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
  208. xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
  209. const char *value ATTRIBUTE_UNUSED) {
  210. return(1);
  211. }
  212. /**
  213. * xsltSecurityForbid:
  214. * @sec: the security block to use
  215. * @ctxt: an XSLT transformation context
  216. * @value: unused
  217. *
  218. * Function used to always forbid an operation
  219. *
  220. * Returns 0 always
  221. */
  222. int
  223. xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
  224. xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
  225. const char *value ATTRIBUTE_UNUSED) {
  226. return(0);
  227. }
  228. /************************************************************************
  229. * *
  230. * Internal interfaces *
  231. * *
  232. ************************************************************************/
  233. /**
  234. * xsltCheckFilename
  235. * @path: the path to check
  236. *
  237. * function checks to see if @path is a valid source
  238. * (file, socket...) for XML.
  239. *
  240. * TODO: remove at some point !!!
  241. * Local copy of xmlCheckFilename to avoid a hard dependency on
  242. * a new version of libxml2
  243. *
  244. * if stat is not available on the target machine,
  245. * returns 1. if stat fails, returns 0 (if calling
  246. * stat on the filename fails, it can't be right).
  247. * if stat succeeds and the file is a directory,
  248. * returns 2. otherwise returns 1.
  249. */
  250. static int
  251. xsltCheckFilename (const char *path)
  252. {
  253. #ifdef HAVE_STAT
  254. struct stat stat_buffer;
  255. #if defined(_WIN32) && !defined(__CYGWIN__)
  256. DWORD dwAttrs;
  257. dwAttrs = GetFileAttributesA(path);
  258. if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
  259. if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) {
  260. return 2;
  261. }
  262. }
  263. #endif
  264. if (stat(path, &stat_buffer) == -1)
  265. return 0;
  266. #ifdef S_ISDIR
  267. if (S_ISDIR(stat_buffer.st_mode)) {
  268. return 2;
  269. }
  270. #endif
  271. #endif
  272. return 1;
  273. }
  274. static int
  275. xsltCheckWritePath(xsltSecurityPrefsPtr sec,
  276. xsltTransformContextPtr ctxt,
  277. const char *path)
  278. {
  279. int ret;
  280. xsltSecurityCheck check;
  281. char *directory;
  282. check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE);
  283. if (check != NULL) {
  284. ret = check(sec, ctxt, path);
  285. if (ret == 0) {
  286. xsltTransformError(ctxt, NULL, NULL,
  287. "File write for %s refused\n", path);
  288. return(0);
  289. }
  290. }
  291. directory = xmlParserGetDirectory (path);
  292. if (directory != NULL) {
  293. ret = xsltCheckFilename(directory);
  294. if (ret == 0) {
  295. /*
  296. * The directory doesn't exist check for creation
  297. */
  298. check = xsltGetSecurityPrefs(sec,
  299. XSLT_SECPREF_CREATE_DIRECTORY);
  300. if (check != NULL) {
  301. ret = check(sec, ctxt, directory);
  302. if (ret == 0) {
  303. xsltTransformError(ctxt, NULL, NULL,
  304. "Directory creation for %s refused\n",
  305. path);
  306. xmlFree(directory);
  307. return(0);
  308. }
  309. }
  310. ret = xsltCheckWritePath(sec, ctxt, directory);
  311. if (ret == 1)
  312. ret = mkdir(directory, 0755);
  313. }
  314. xmlFree(directory);
  315. if (ret < 0)
  316. return(ret);
  317. }
  318. return(1);
  319. }
  320. /**
  321. * xsltCheckWrite:
  322. * @sec: the security options
  323. * @ctxt: an XSLT transformation context
  324. * @URL: the resource to be written
  325. *
  326. * Check if the resource is allowed to be written, if necessary makes
  327. * some preliminary work like creating directories
  328. *
  329. * Return 1 if write is allowed, 0 if not and -1 in case or error.
  330. */
  331. int
  332. xsltCheckWrite(xsltSecurityPrefsPtr sec,
  333. xsltTransformContextPtr ctxt, const xmlChar *URL) {
  334. int ret;
  335. xmlURIPtr uri;
  336. xsltSecurityCheck check;
  337. uri = xmlParseURI((const char *)URL);
  338. if (uri == NULL) {
  339. uri = xmlCreateURI();
  340. if (uri == NULL) {
  341. xsltTransformError(ctxt, NULL, NULL,
  342. "xsltCheckWrite: out of memory for %s\n", URL);
  343. return(-1);
  344. }
  345. uri->path = (char *)xmlStrdup(URL);
  346. }
  347. if ((uri->scheme == NULL) ||
  348. (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
  349. #if defined(_WIN32) && !defined(__CYGWIN__)
  350. if ((uri->path)&&(uri->path[0]=='/')&&
  351. (uri->path[1]!='\0')&&(uri->path[2]==':'))
  352. ret = xsltCheckWritePath(sec, ctxt, uri->path+1);
  353. else
  354. #endif
  355. {
  356. /*
  357. * Check if we are allowed to write this file
  358. */
  359. ret = xsltCheckWritePath(sec, ctxt, uri->path);
  360. }
  361. if (ret <= 0) {
  362. xmlFreeURI(uri);
  363. return(ret);
  364. }
  365. } else {
  366. /*
  367. * Check if we are allowed to write this network resource
  368. */
  369. check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK);
  370. if (check != NULL) {
  371. ret = check(sec, ctxt, (const char *)URL);
  372. if (ret == 0) {
  373. xsltTransformError(ctxt, NULL, NULL,
  374. "File write for %s refused\n", URL);
  375. xmlFreeURI(uri);
  376. return(0);
  377. }
  378. }
  379. }
  380. xmlFreeURI(uri);
  381. return(1);
  382. }
  383. /**
  384. * xsltCheckRead:
  385. * @sec: the security options
  386. * @ctxt: an XSLT transformation context
  387. * @URL: the resource to be read
  388. *
  389. * Check if the resource is allowed to be read
  390. *
  391. * Return 1 if read is allowed, 0 if not and -1 in case or error.
  392. */
  393. int
  394. xsltCheckRead(xsltSecurityPrefsPtr sec,
  395. xsltTransformContextPtr ctxt, const xmlChar *URL) {
  396. int ret;
  397. xmlURIPtr uri;
  398. xsltSecurityCheck check;
  399. uri = xmlParseURI((const char *)URL);
  400. if (uri == NULL) {
  401. xsltTransformError(ctxt, NULL, NULL,
  402. "xsltCheckRead: URL parsing failed for %s\n",
  403. URL);
  404. return(-1);
  405. }
  406. if ((uri->scheme == NULL) ||
  407. (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
  408. /*
  409. * Check if we are allowed to read this file
  410. */
  411. check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE);
  412. if (check != NULL) {
  413. ret = check(sec, ctxt, uri->path);
  414. if (ret == 0) {
  415. xsltTransformError(ctxt, NULL, NULL,
  416. "Local file read for %s refused\n", URL);
  417. xmlFreeURI(uri);
  418. return(0);
  419. }
  420. }
  421. } else {
  422. /*
  423. * Check if we are allowed to write this network resource
  424. */
  425. check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK);
  426. if (check != NULL) {
  427. ret = check(sec, ctxt, (const char *)URL);
  428. if (ret == 0) {
  429. xsltTransformError(ctxt, NULL, NULL,
  430. "Network file read for %s refused\n", URL);
  431. xmlFreeURI(uri);
  432. return(0);
  433. }
  434. }
  435. }
  436. xmlFreeURI(uri);
  437. return(1);
  438. }