forbidden.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. /*
  2. Copyright (c) 2003-2010 by Juliusz Chroboczek
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include "polipo.h"
  20. #ifndef NO_FORBIDDEN
  21. #include <regex.h>
  22. #include <assert.h>
  23. typedef struct _Domain {
  24. int length;
  25. char domain[1];
  26. } DomainRec, *DomainPtr;
  27. AtomPtr forbiddenFile = NULL;
  28. AtomPtr forbiddenUrl = NULL;
  29. int forbiddenRedirectCode = 302;
  30. AtomPtr redirector = NULL;
  31. int redirectorRedirectCode = 302;
  32. DomainPtr *forbiddenDomains = NULL;
  33. regex_t *forbiddenRegex = NULL;
  34. AtomPtr uncachableFile = NULL;
  35. DomainPtr *uncachableDomains = NULL;
  36. regex_t *uncachableRegex = NULL;
  37. AtomPtr forbiddenTunnelsFile = NULL;
  38. DomainPtr *forbiddenTunnelsDomains = NULL;
  39. regex_t *forbiddenTunnelsRegex = NULL;
  40. /* these three are only used internally by {parse,read}DomainFile */
  41. /* to avoid having to pass it all as parameters */
  42. static DomainPtr *domains;
  43. static char *regexbuf;
  44. static int rlen, rsize, dlen, dsize;
  45. #ifndef NO_REDIRECTOR
  46. static pid_t redirector_pid = 0;
  47. static int redirector_read_fd = -1, redirector_write_fd = -1;
  48. #define REDIRECTOR_BUFFER_SIZE 1024
  49. static char *redirector_buffer = NULL;
  50. RedirectRequestPtr redirector_request_first = NULL,
  51. redirector_request_last = NULL;
  52. #endif
  53. static int atomSetterForbidden(ConfigVariablePtr, void*);
  54. void
  55. preinitForbidden(void)
  56. {
  57. CONFIG_VARIABLE_SETTABLE(forbiddenUrl, CONFIG_ATOM, configAtomSetter,
  58. "URL to which forbidden requests "
  59. "should be redirected.");
  60. CONFIG_VARIABLE_SETTABLE(forbiddenRedirectCode, CONFIG_INT,
  61. configIntSetter,
  62. "Redirect code, 301 or 302.");
  63. CONFIG_VARIABLE_SETTABLE(forbiddenFile, CONFIG_ATOM, atomSetterForbidden,
  64. "File specifying forbidden URLs.");
  65. #ifndef NO_REDIRECTOR
  66. CONFIG_VARIABLE_SETTABLE(redirector, CONFIG_ATOM, atomSetterForbidden,
  67. "Squid-style redirector.");
  68. CONFIG_VARIABLE_SETTABLE(redirectorRedirectCode, CONFIG_INT,
  69. configIntSetter,
  70. "Redirect code to use with redirector.");
  71. #endif
  72. CONFIG_VARIABLE_SETTABLE(uncachableFile, CONFIG_ATOM, atomSetterForbidden,
  73. "File specifying uncachable URLs.");
  74. CONFIG_VARIABLE_SETTABLE(forbiddenTunnelsFile, CONFIG_ATOM, atomSetterForbidden,
  75. "File specifying forbidden tunnels.");
  76. }
  77. static int
  78. atomSetterForbidden(ConfigVariablePtr var, void *value)
  79. {
  80. initForbidden();
  81. return configAtomSetter(var, value);
  82. }
  83. int
  84. readDomainFile(char *filename)
  85. {
  86. FILE *in;
  87. char buf[512];
  88. char *rs;
  89. int i, j, is_regex, start;
  90. in = fopen(filename, "r");
  91. if(in == NULL) {
  92. if(errno != ENOENT)
  93. do_log_error(L_ERROR, errno, "Couldn't open file %s", filename);
  94. return -1;
  95. }
  96. while(1) {
  97. rs = fgets(buf, 512, in);
  98. if(rs == NULL)
  99. break;
  100. for(i = 0; i < 512; i++) {
  101. if(buf[i] != ' ' && buf[i] != '\t')
  102. break;
  103. }
  104. start = i;
  105. for(i = start; i < 512; i++) {
  106. if(buf[i] == '#' || buf[i] == '\r' || buf[i] == '\n')
  107. break;
  108. }
  109. while(i > start) {
  110. if(buf[i - 1] != ' ' && buf[i - 1] != '\t')
  111. break;
  112. i--;
  113. }
  114. if(i <= start)
  115. continue;
  116. /* The significant part of the line is now between start and i */
  117. is_regex = 0;
  118. for(j = start; j < i; j++) {
  119. if(buf[j] == '\\' || buf[j] == '*' || buf[j] == '/') {
  120. is_regex = 1;
  121. break;
  122. }
  123. }
  124. if(is_regex) {
  125. while(rlen + i - start + 8 >= rsize) {
  126. char *new_regexbuf;
  127. new_regexbuf = realloc(regexbuf, rsize * 2 + 1);
  128. if(new_regexbuf == NULL) {
  129. do_log(L_ERROR, "Couldn't reallocate regex.\n");
  130. fclose(in);
  131. return -1;
  132. }
  133. regexbuf = new_regexbuf;
  134. rsize = rsize * 2 + 1;
  135. }
  136. if(rlen != 0)
  137. rlen = snnprintf(regexbuf, rlen, rsize, "|");
  138. rlen = snnprintf(regexbuf, rlen, rsize, "(");
  139. rlen = snnprint_n(regexbuf, rlen, rsize, buf + start, i - start);
  140. rlen = snnprintf(regexbuf, rlen, rsize, ")");
  141. } else {
  142. DomainPtr new_domain;
  143. if(dlen >= dsize - 1) {
  144. DomainPtr *new_domains;
  145. new_domains = realloc(domains, (dsize * 2 + 1) *
  146. sizeof(DomainPtr));
  147. if(new_domains == NULL) {
  148. do_log(L_ERROR,
  149. "Couldn't reallocate domain list.\n");
  150. fclose(in);
  151. return -1;
  152. }
  153. domains = new_domains;
  154. dsize = dsize * 2 + 1;
  155. }
  156. new_domain = malloc(sizeof(DomainRec) - 1 + i - start);
  157. if(new_domain == NULL) {
  158. do_log(L_ERROR, "Couldn't allocate domain.\n");
  159. fclose(in);
  160. return -1;
  161. }
  162. new_domain->length = i - start;
  163. memcpy(new_domain->domain, buf + start, i - start);
  164. domains[dlen++] = new_domain;
  165. }
  166. }
  167. fclose(in);
  168. return 1;
  169. }
  170. void
  171. parseDomainFile(AtomPtr file,
  172. DomainPtr **domains_return, regex_t **regex_return)
  173. {
  174. struct stat ss;
  175. regex_t *regex;
  176. int rc;
  177. if(*domains_return) {
  178. DomainPtr *domain = *domains_return;
  179. while(*domain) {
  180. free(*domain);
  181. domain++;
  182. }
  183. free(*domains_return);
  184. *domains_return = NULL;
  185. }
  186. if(*regex_return) {
  187. regfree(*regex_return);
  188. *regex_return = NULL;
  189. }
  190. if(!file || file->length == 0)
  191. return;
  192. domains = malloc(64 * sizeof(DomainPtr));
  193. if(domains == NULL) {
  194. do_log(L_ERROR, "Couldn't allocate domain list.\n");
  195. return;
  196. }
  197. dlen = 0;
  198. dsize = 64;
  199. regexbuf = malloc(512);
  200. if(regexbuf == NULL) {
  201. do_log(L_ERROR, "Couldn't allocate regex.\n");
  202. free(domains);
  203. return;
  204. }
  205. rlen = 0;
  206. rsize = 512;
  207. rc = stat(file->string, &ss);
  208. if(rc < 0) {
  209. if(errno != ENOENT)
  210. do_log_error(L_WARN, errno, "Couldn't stat file %s", file->string);
  211. } else {
  212. if(!S_ISDIR(ss.st_mode))
  213. readDomainFile(file->string);
  214. else {
  215. char *fts_argv[2];
  216. FTS *fts;
  217. FTSENT *fe;
  218. fts_argv[0] = file->string;
  219. fts_argv[1] = NULL;
  220. fts = fts_open(fts_argv, FTS_LOGICAL, NULL);
  221. if(fts) {
  222. while(1) {
  223. fe = fts_read(fts);
  224. if(!fe) break;
  225. if(fe->fts_info != FTS_D && fe->fts_info != FTS_DP &&
  226. fe->fts_info != FTS_DC && fe->fts_info != FTS_DNR)
  227. readDomainFile(fe->fts_accpath);
  228. }
  229. fts_close(fts);
  230. } else {
  231. do_log_error(L_ERROR, errno,
  232. "Couldn't scan directory %s", file->string);
  233. }
  234. }
  235. }
  236. if(dlen > 0) {
  237. domains[dlen] = NULL;
  238. } else {
  239. free(domains);
  240. domains = NULL;
  241. }
  242. if(rlen > 0) {
  243. regex = malloc(sizeof(regex_t));
  244. rc = regcomp(regex, regexbuf, REG_EXTENDED | REG_NOSUB);
  245. if(rc != 0) {
  246. char errbuf[100];
  247. regerror(rc, regex, errbuf, 100);
  248. do_log(L_ERROR, "Couldn't compile regex: %s.\n", errbuf);
  249. free(regex);
  250. regex = NULL;
  251. }
  252. } else {
  253. regex = NULL;
  254. }
  255. free(regexbuf);
  256. *domains_return = domains;
  257. *regex_return = regex;
  258. return;
  259. }
  260. void
  261. initForbidden(void)
  262. {
  263. redirectorKill();
  264. if(forbiddenFile)
  265. forbiddenFile = expandTilde(forbiddenFile);
  266. if(forbiddenFile == NULL) {
  267. forbiddenFile = expandTilde(internAtom("~/.polipo-forbidden"));
  268. if(forbiddenFile) {
  269. if(access(forbiddenFile->string, F_OK) < 0) {
  270. releaseAtom(forbiddenFile);
  271. forbiddenFile = NULL;
  272. }
  273. }
  274. }
  275. if(forbiddenFile == NULL) {
  276. if(access("/etc/polipo/forbidden", F_OK) >= 0)
  277. forbiddenFile = internAtom("/etc/polipo/forbidden");
  278. }
  279. parseDomainFile(forbiddenFile, &forbiddenDomains, &forbiddenRegex);
  280. if(uncachableFile)
  281. uncachableFile = expandTilde(uncachableFile);
  282. if(uncachableFile == NULL) {
  283. uncachableFile = expandTilde(internAtom("~/.polipo-uncachable"));
  284. if(uncachableFile) {
  285. if(access(uncachableFile->string, F_OK) < 0) {
  286. releaseAtom(uncachableFile);
  287. uncachableFile = NULL;
  288. }
  289. }
  290. }
  291. if(uncachableFile == NULL) {
  292. if(access("/etc/polipo/uncachable", F_OK) >= 0)
  293. uncachableFile = internAtom("/etc/polipo/uncachable");
  294. }
  295. parseDomainFile(uncachableFile, &uncachableDomains, &uncachableRegex);
  296. if(forbiddenTunnelsFile)
  297. forbiddenTunnelsFile = expandTilde(forbiddenTunnelsFile);
  298. if(forbiddenTunnelsFile == NULL) {
  299. forbiddenTunnelsFile = expandTilde(internAtom("~/.polipo-forbiddenTunnels"));
  300. if(forbiddenTunnelsFile) {
  301. if(access(forbiddenTunnelsFile->string, F_OK) < 0) {
  302. releaseAtom(forbiddenTunnelsFile);
  303. forbiddenTunnelsFile = NULL;
  304. }
  305. }
  306. }
  307. if(forbiddenTunnelsFile == NULL) {
  308. if(access("/etc/polipo/forbiddenTunnels", F_OK) >= 0)
  309. forbiddenTunnelsFile = internAtom("/etc/polipo/forbiddenTunnels");
  310. }
  311. parseDomainFile(forbiddenTunnelsFile, &forbiddenTunnelsDomains, &forbiddenTunnelsRegex);
  312. return;
  313. }
  314. int
  315. tunnelIsMatched(char *url, int lurl, char *hostname, int lhost)
  316. {
  317. DomainPtr *domain, *domains;
  318. domains=forbiddenTunnelsDomains;
  319. if (domains) {
  320. domain = domains;
  321. while(*domain) {
  322. if (lhost == (*domain)->length &&
  323. memcmp(hostname, (*domain)->domain, lhost)==0)
  324. return 1;
  325. domain++;
  326. }
  327. }
  328. if(forbiddenTunnelsRegex) {
  329. if(!regexec(forbiddenTunnelsRegex, url, 0, NULL, 0))
  330. return 1;
  331. }
  332. return 0;
  333. }
  334. int
  335. urlIsMatched(char *url, int length, DomainPtr *domains, regex_t *regex)
  336. {
  337. /* This requires url to be NUL-terminated. */
  338. assert(url[length] == '\0');
  339. if(length < 8)
  340. return 0;
  341. if(lwrcmp(url, "http://", 7) != 0)
  342. return 0;
  343. if(domains) {
  344. int i;
  345. DomainPtr *domain;
  346. for(i = 8; i < length; i++) {
  347. if(url[i] == '/')
  348. break;
  349. }
  350. domain = domains;
  351. while(*domain) {
  352. if((*domain)->length <= (i - 7) &&
  353. (url[i - (*domain)->length - 1] == '.' ||
  354. url[i - (*domain)->length - 1] == '/') &&
  355. memcmp(url + i - (*domain)->length,
  356. (*domain)->domain,
  357. (*domain)->length) == 0)
  358. return 1;
  359. domain++;
  360. }
  361. }
  362. if(regex)
  363. return !regexec(regex, url, 0, NULL, 0);
  364. return 0;
  365. }
  366. int
  367. urlIsUncachable(char *url, int length)
  368. {
  369. return urlIsMatched(url, length, uncachableDomains, uncachableRegex);
  370. }
  371. int
  372. urlForbidden(AtomPtr url,
  373. int (*handler)(int, AtomPtr, AtomPtr, AtomPtr, void*),
  374. void *closure)
  375. {
  376. int forbidden = urlIsMatched(url->string, url->length,
  377. forbiddenDomains, forbiddenRegex);
  378. int code = 0;
  379. AtomPtr message = NULL, headers = NULL;
  380. if(forbidden) {
  381. message = internAtomF("Forbidden URL %s", url->string);
  382. if(forbiddenUrl) {
  383. code = forbiddenRedirectCode;
  384. headers = internAtomF("\r\nLocation: %s", forbiddenUrl->string);
  385. } else {
  386. code = 403;
  387. }
  388. }
  389. #ifndef NO_REDIRECTOR
  390. if(code == 0 && redirector) {
  391. RedirectRequestPtr request;
  392. request = malloc(sizeof(RedirectRequestRec));
  393. if(request == NULL) {
  394. do_log(L_ERROR, "Couldn't allocate redirect request.\n");
  395. goto done;
  396. }
  397. request->url = url;
  398. request->handler = handler;
  399. request->data = closure;
  400. if(redirector_request_first == NULL)
  401. redirector_request_first = request;
  402. else
  403. redirector_request_last->next = request;
  404. redirector_request_last = request;
  405. request->next = NULL;
  406. if(request == redirector_request_first)
  407. redirectorTrigger();
  408. return 1;
  409. }
  410. #endif
  411. done:
  412. handler(code, url, message, headers, closure);
  413. return 1;
  414. }
  415. #ifndef NO_REDIRECTOR
  416. static void
  417. logExitStatus(int status)
  418. {
  419. if(WIFEXITED(status) && WEXITSTATUS(status) == 142)
  420. /* See child code in runRedirector */
  421. do_log(L_ERROR, "Couldn't start redirector.\n");
  422. else {
  423. char *reason =
  424. WIFEXITED(status) ? "with status" :
  425. WIFSIGNALED(status) ? "on signal" :
  426. "with unknown status";
  427. int value =
  428. WIFEXITED(status) ? WEXITSTATUS(status) :
  429. WIFSIGNALED(status) ? WTERMSIG(status) :
  430. status;
  431. do_log(L_ERROR,
  432. "Redirector exited %s %d.\n", reason, value);
  433. }
  434. }
  435. void
  436. redirectorKill(void)
  437. {
  438. int rc, status, dead;
  439. if(redirector_read_fd >= 0) {
  440. rc = waitpid(redirector_pid, &status, WNOHANG);
  441. dead = (rc > 0);
  442. close(redirector_read_fd);
  443. redirector_read_fd = -1;
  444. close(redirector_write_fd);
  445. redirector_write_fd = -1;
  446. if(!dead) {
  447. rc = kill(redirector_pid, SIGTERM);
  448. if(rc < 0 && errno != ESRCH) {
  449. do_log_error(L_ERROR, errno, "Couldn't kill redirector");
  450. redirector_pid = -1;
  451. return;
  452. }
  453. do {
  454. rc = waitpid(redirector_pid, &status, 0);
  455. } while(rc < 0 && errno == EINTR);
  456. if(rc < 0)
  457. do_log_error(L_ERROR, errno,
  458. "Couldn't wait for redirector's death");
  459. } else
  460. logExitStatus(status);
  461. redirector_pid = -1;
  462. }
  463. }
  464. static void
  465. redirectorDestroyRequest(RedirectRequestPtr request)
  466. {
  467. assert(redirector_request_first == request);
  468. redirector_request_first = request->next;
  469. if(redirector_request_first == NULL)
  470. redirector_request_last = NULL;
  471. free(request);
  472. }
  473. void
  474. redirectorTrigger(void)
  475. {
  476. RedirectRequestPtr request = redirector_request_first;
  477. int rc;
  478. if(!request)
  479. return;
  480. if(redirector_read_fd < 0) {
  481. rc = runRedirector(&redirector_pid,
  482. &redirector_read_fd, &redirector_write_fd);
  483. if(rc < 0) {
  484. request->handler(rc, request->url, NULL, NULL, request->data);
  485. redirectorDestroyRequest(request);
  486. return;
  487. }
  488. }
  489. do_stream_2(IO_WRITE, redirector_write_fd, 0,
  490. request->url->string, request->url->length,
  491. "\n", 1,
  492. redirectorStreamHandler1, request);
  493. }
  494. int
  495. redirectorStreamHandler1(int status,
  496. FdEventHandlerPtr event,
  497. StreamRequestPtr srequest)
  498. {
  499. RedirectRequestPtr request = (RedirectRequestPtr)srequest->data;
  500. if(status) {
  501. if(status >= 0)
  502. status = -EPIPE;
  503. do_log_error(L_ERROR, -status, "Write to redirector failed");
  504. goto fail;
  505. }
  506. if(!streamRequestDone(srequest))
  507. return 0;
  508. do_stream(IO_READ, redirector_read_fd, 0,
  509. redirector_buffer, REDIRECTOR_BUFFER_SIZE,
  510. redirectorStreamHandler2, request);
  511. return 1;
  512. fail:
  513. request->handler(status < 0 ? status : -EPIPE,
  514. request->url, NULL, NULL, request->data);
  515. redirectorDestroyRequest(request);
  516. redirectorKill();
  517. return 1;
  518. }
  519. int
  520. redirectorStreamHandler2(int status,
  521. FdEventHandlerPtr event,
  522. StreamRequestPtr srequest)
  523. {
  524. RedirectRequestPtr request = (RedirectRequestPtr)srequest->data;
  525. char *c;
  526. AtomPtr message;
  527. AtomPtr headers;
  528. int code;
  529. if(status < 0) {
  530. do_log_error(L_ERROR, -status, "Read from redirector failed");
  531. request->handler(status, request->url, NULL, NULL, request->data);
  532. goto kill;
  533. }
  534. c = memchr(redirector_buffer, '\n', srequest->offset);
  535. if(!c) {
  536. if(!status && srequest->offset < REDIRECTOR_BUFFER_SIZE)
  537. return 0;
  538. do_log(L_ERROR, "Redirector returned incomplete reply.\n");
  539. request->handler(-EREDIRECTOR, request->url, NULL, NULL, request->data);
  540. goto kill;
  541. }
  542. *c = '\0';
  543. if(srequest->offset > c + 1 - redirector_buffer)
  544. do_log(L_WARN, "Stray bytes in redirector output.\n");
  545. if(c > redirector_buffer + 1 &&
  546. (c - redirector_buffer != request->url->length ||
  547. memcmp(redirector_buffer, request->url->string,
  548. request->url->length) != 0)) {
  549. code = redirectorRedirectCode;
  550. message = internAtom("Redirected by external redirector");
  551. if(message == NULL) {
  552. request->handler(-ENOMEM, request->url, NULL, NULL, request->data);
  553. goto kill;
  554. }
  555. headers = internAtomF("\r\nLocation: %s", redirector_buffer);
  556. if(headers == NULL) {
  557. releaseAtom(message);
  558. request->handler(-ENOMEM, request->url, NULL, NULL, request->data);
  559. goto kill;
  560. }
  561. } else {
  562. code = 0;
  563. message = NULL;
  564. headers = NULL;
  565. }
  566. request->handler(code, request->url,
  567. message, headers, request->data);
  568. goto cont;
  569. cont:
  570. redirectorDestroyRequest(request);
  571. redirectorTrigger();
  572. return 1;
  573. kill:
  574. redirectorKill();
  575. goto cont;
  576. }
  577. int
  578. runRedirector(pid_t *pid_return, int *read_fd_return, int *write_fd_return)
  579. {
  580. int rc, rc2, status;
  581. pid_t pid;
  582. int filedes1[2], filedes2[2];
  583. sigset_t ss, old_mask;
  584. assert(redirector);
  585. if(redirector_buffer == NULL) {
  586. redirector_buffer = malloc(REDIRECTOR_BUFFER_SIZE);
  587. if(redirector_buffer == NULL)
  588. return -errno;
  589. }
  590. rc = pipe(filedes1);
  591. if(rc < 0) {
  592. rc = -errno;
  593. goto fail1;
  594. }
  595. rc = pipe(filedes2);
  596. if(rc < 0) {
  597. rc = -errno;
  598. goto fail2;
  599. }
  600. fflush(stdout);
  601. fflush(stderr);
  602. flushLog();
  603. interestingSignals(&ss);
  604. do {
  605. rc = sigprocmask(SIG_BLOCK, &ss, &old_mask);
  606. } while (rc < 0 && errno == EINTR);
  607. if(rc < 0) {
  608. rc = -errno;
  609. goto fail3;
  610. }
  611. pid = fork();
  612. if(pid < 0) {
  613. rc = -errno;
  614. goto fail4;
  615. }
  616. if(pid > 0) {
  617. do {
  618. rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
  619. } while(rc < 0 && errno == EINTR);
  620. if(rc < 0) {
  621. rc = -errno;
  622. goto fail4;
  623. }
  624. rc = setNonblocking(filedes1[1], 1);
  625. if(rc >= 0)
  626. rc = setNonblocking(filedes2[0], 1);
  627. if(rc < 0) {
  628. rc = -errno;
  629. goto fail4;
  630. }
  631. /* This is completely unnecesary -- if the redirector cannot be
  632. started, redirectorStreamHandler1 will get EPIPE straight away --,
  633. but it improves error messages somewhat. */
  634. rc = waitpid(pid, &status, WNOHANG);
  635. if(rc > 0) {
  636. logExitStatus(status);
  637. rc = -EREDIRECTOR;
  638. goto fail4;
  639. } else if(rc < 0) {
  640. rc = -errno;
  641. goto fail4;
  642. }
  643. *read_fd_return = filedes2[0];
  644. *write_fd_return = filedes1[1];
  645. *pid_return = pid;
  646. /* This comes at the end so that the fail* labels can work */
  647. close(filedes1[0]);
  648. close(filedes2[1]);
  649. } else {
  650. close(filedes1[1]);
  651. close(filedes2[0]);
  652. uninitEvents();
  653. do {
  654. rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
  655. } while (rc < 0 && errno == EINTR);
  656. if(rc < 0)
  657. exit(142);
  658. if(filedes1[0] != 0)
  659. dup2(filedes1[0], 0);
  660. if(filedes2[1] != 1)
  661. dup2(filedes2[1], 1);
  662. execlp(redirector->string, redirector->string, (char*)NULL);
  663. exit(142);
  664. /* NOTREACHED */
  665. }
  666. return 1;
  667. fail4:
  668. do {
  669. rc2 = sigprocmask(SIG_SETMASK, &old_mask, NULL);
  670. } while(rc2 < 0 && errno == EINTR);
  671. fail3:
  672. close(filedes2[0]);
  673. close(filedes2[1]);
  674. fail2:
  675. close(filedes1[0]);
  676. close(filedes1[1]);
  677. fail1:
  678. free(redirector_buffer);
  679. redirector_buffer = NULL;
  680. return rc;
  681. }
  682. #else
  683. void
  684. redirectorKill(void)
  685. {
  686. return;
  687. }
  688. #endif
  689. #else
  690. void
  691. preinitForbidden()
  692. {
  693. return;
  694. }
  695. void
  696. initForbidden()
  697. {
  698. return;
  699. }
  700. int
  701. tunnelIsMatched(char *url, int lurl, char *hostname, int lhost)
  702. {
  703. return 0;
  704. }
  705. int
  706. urlIsUncachable(char *url, int length)
  707. {
  708. return 0;
  709. }
  710. int
  711. urlForbidden(AtomPtr url,
  712. int (*handler)(int, AtomPtr, AtomPtr, AtomPtr, void*),
  713. void *closure)
  714. {
  715. handler(0, url, NULL, NULL, closure);
  716. return 1;
  717. }
  718. #endif