cgisimple.c 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314
  1. /*********************************************************************
  2. *
  3. * File : $Source: /cvsroot/ijbswa/current/cgisimple.c,v $
  4. *
  5. * Purpose : Simple CGIs to get information about Privoxy's
  6. * status.
  7. *
  8. * Copyright : Written by and Copyright (C) 2001-2020 the
  9. * Privoxy team. https://www.privoxy.org/
  10. *
  11. * Based on the Internet Junkbuster originally written
  12. * by and Copyright (C) 1997 Anonymous Coders and
  13. * Junkbusters Corporation. http://www.junkbusters.com
  14. *
  15. * This program is free software; you can redistribute it
  16. * and/or modify it under the terms of the GNU General
  17. * Public License as published by the Free Software
  18. * Foundation; either version 2 of the License, or (at
  19. * your option) any later version.
  20. *
  21. * This program is distributed in the hope that it will
  22. * be useful, but WITHOUT ANY WARRANTY; without even the
  23. * implied warranty of MERCHANTABILITY or FITNESS FOR A
  24. * PARTICULAR PURPOSE. See the GNU General Public
  25. * License for more details.
  26. *
  27. * The GNU General Public License should be included with
  28. * this file. If not, you can view it at
  29. * http://www.gnu.org/copyleft/gpl.html
  30. * or write to the Free Software Foundation, Inc., 59
  31. * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  32. *
  33. **********************************************************************/
  34. #include "config.h"
  35. #include <stdio.h>
  36. #include <sys/types.h>
  37. #include <stdlib.h>
  38. #include <ctype.h>
  39. #include <string.h>
  40. #include <assert.h>
  41. #if defined (HAVE_ACCESS) && defined (HAVE_UNISTD_H)
  42. #include <unistd.h>
  43. #endif /* def HAVE_ACCESS && HAVE_UNISTD_H */
  44. #include "project.h"
  45. #include "cgi.h"
  46. #include "cgisimple.h"
  47. #include "list.h"
  48. #include "encode.h"
  49. #include "jcc.h"
  50. #include "filters.h"
  51. #include "actions.h"
  52. #include "miscutil.h"
  53. #include "loadcfg.h"
  54. #include "parsers.h"
  55. #include "urlmatch.h"
  56. #include "errlog.h"
  57. #ifdef FEATURE_CLIENT_TAGS
  58. #include "client-tags.h"
  59. #endif
  60. static jb_err show_defines(struct map *exports);
  61. static jb_err cgi_show_file(struct client_state *csp,
  62. struct http_response *rsp,
  63. const struct map *parameters);
  64. static jb_err load_file(const char *filename, char **buffer, size_t *length);
  65. /*********************************************************************
  66. *
  67. * Function : cgi_default
  68. *
  69. * Description : CGI function that is called for the CGI_SITE_1_HOST
  70. * and CGI_SITE_2_HOST/CGI_SITE_2_PATH base URLs.
  71. * Boring - only exports the default exports.
  72. *
  73. * Parameters :
  74. * 1 : csp = Current client state (buffers, headers, etc...)
  75. * 2 : rsp = http_response data structure for output
  76. * 3 : parameters = map of cgi parameters
  77. *
  78. * CGI Parameters : none
  79. *
  80. * Returns : JB_ERR_OK on success
  81. * JB_ERR_MEMORY on out-of-memory
  82. *
  83. *********************************************************************/
  84. jb_err cgi_default(struct client_state *csp,
  85. struct http_response *rsp,
  86. const struct map *parameters)
  87. {
  88. struct map *exports;
  89. (void)parameters;
  90. assert(csp);
  91. assert(rsp);
  92. if (NULL == (exports = default_exports(csp, "")))
  93. {
  94. return JB_ERR_MEMORY;
  95. }
  96. return template_fill_for_cgi(csp, "default", exports, rsp);
  97. }
  98. /*********************************************************************
  99. *
  100. * Function : cgi_error_404
  101. *
  102. * Description : CGI function that is called if an unknown action was
  103. * given.
  104. *
  105. * Parameters :
  106. * 1 : csp = Current client state (buffers, headers, etc...)
  107. * 2 : rsp = http_response data structure for output
  108. * 3 : parameters = map of cgi parameters
  109. *
  110. * CGI Parameters : none
  111. *
  112. * Returns : JB_ERR_OK on success
  113. * JB_ERR_MEMORY on out-of-memory error.
  114. *
  115. *********************************************************************/
  116. jb_err cgi_error_404(struct client_state *csp,
  117. struct http_response *rsp,
  118. const struct map *parameters)
  119. {
  120. struct map *exports;
  121. assert(csp);
  122. assert(rsp);
  123. assert(parameters);
  124. if (NULL == (exports = default_exports(csp, NULL)))
  125. {
  126. return JB_ERR_MEMORY;
  127. }
  128. rsp->status = strdup_or_die("404 Privoxy configuration page not found");
  129. return template_fill_for_cgi(csp, "cgi-error-404", exports, rsp);
  130. }
  131. #ifdef FEATURE_GRACEFUL_TERMINATION
  132. /*********************************************************************
  133. *
  134. * Function : cgi_die
  135. *
  136. * Description : CGI function to shut down Privoxy.
  137. * NOTE: Turning this on in a production build
  138. * would be a BAD idea. An EXTREMELY BAD idea.
  139. * In short, don't do it.
  140. *
  141. * Parameters :
  142. * 1 : csp = Current client state (buffers, headers, etc...)
  143. * 2 : rsp = http_response data structure for output
  144. * 3 : parameters = map of cgi parameters
  145. *
  146. * CGI Parameters : none
  147. *
  148. * Returns : JB_ERR_OK on success
  149. *
  150. *********************************************************************/
  151. jb_err cgi_die (struct client_state *csp,
  152. struct http_response *rsp,
  153. const struct map *parameters)
  154. {
  155. static const char status[] = "200 OK Privoxy shutdown request received";
  156. static const char body[] =
  157. "<html>\n"
  158. "<head>\n"
  159. " <title>Privoxy shutdown request received</title>\n"
  160. " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">\n"
  161. " <link rel=\"stylesheet\" type=\"text/css\" href=\"" CGI_PREFIX "send-stylesheet\">\n"
  162. "</head>\n"
  163. "<body>\n"
  164. "<h1>Privoxy shutdown request received</h1>\n"
  165. "<p>Privoxy is going to shut down after the next request.</p>\n"
  166. "</body>\n"
  167. "</html>\n";
  168. assert(csp);
  169. assert(rsp);
  170. assert(parameters);
  171. /* quit */
  172. g_terminate = 1;
  173. csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
  174. rsp->content_length = 0;
  175. rsp->head_length = 0;
  176. rsp->is_static = 0;
  177. rsp->body = strdup_or_die(body);
  178. rsp->status = strdup_or_die(status);
  179. return JB_ERR_OK;
  180. }
  181. #endif /* def FEATURE_GRACEFUL_TERMINATION */
  182. /*********************************************************************
  183. *
  184. * Function : cgi_show_request
  185. *
  186. * Description : Show the client's request and what sed() would have
  187. * made of it.
  188. *
  189. * Parameters :
  190. * 1 : csp = Current client state (buffers, headers, etc...)
  191. * 2 : rsp = http_response data structure for output
  192. * 3 : parameters = map of cgi parameters
  193. *
  194. * CGI Parameters : none
  195. *
  196. * Returns : JB_ERR_OK on success
  197. * JB_ERR_MEMORY on out-of-memory error.
  198. *
  199. *********************************************************************/
  200. jb_err cgi_show_request(struct client_state *csp,
  201. struct http_response *rsp,
  202. const struct map *parameters)
  203. {
  204. char *p;
  205. struct map *exports;
  206. assert(csp);
  207. assert(rsp);
  208. assert(parameters);
  209. if (NULL == (exports = default_exports(csp, "show-request")))
  210. {
  211. return JB_ERR_MEMORY;
  212. }
  213. /*
  214. * Repair the damage done to the IOB by get_header()
  215. */
  216. for (p = csp->client_iob->buf; p < csp->client_iob->cur; p++)
  217. {
  218. if (*p == '\0') *p = '\n';
  219. }
  220. /*
  221. * Export the original client's request and the one we would
  222. * be sending to the server if this wasn't a CGI call
  223. */
  224. if (map(exports, "client-request", 1, html_encode(csp->client_iob->buf), 0))
  225. {
  226. free_map(exports);
  227. return JB_ERR_MEMORY;
  228. }
  229. if (map(exports, "processed-request", 1,
  230. html_encode_and_free_original(list_to_text(csp->headers)), 0))
  231. {
  232. free_map(exports);
  233. return JB_ERR_MEMORY;
  234. }
  235. return template_fill_for_cgi(csp, "show-request", exports, rsp);
  236. }
  237. #ifdef FEATURE_CLIENT_TAGS
  238. /*********************************************************************
  239. *
  240. * Function : cgi_create_client_tag_form
  241. *
  242. * Description : Creates a HTML form to enable or disable a given
  243. * client tag.
  244. * XXX: Could use a template.
  245. *
  246. * Parameters :
  247. * 1 : form = Buffer to fill with the generated form
  248. * 2 : size = Size of the form buffer
  249. * 3 : tag = Name of the tag this form should affect
  250. * 4 : toggle_state = Desired state after the button pressed 0
  251. * 5 : expires = Whether or not the tag should be enabled.
  252. * Only checked if toggle_state is 1.
  253. *
  254. * Returns : void
  255. *
  256. *********************************************************************/
  257. static void cgi_create_client_tag_form(char *form, size_t size,
  258. const char *tag, int toggle_state, int expires)
  259. {
  260. char *button_name;
  261. if (toggle_state == 1)
  262. {
  263. button_name = (expires == 1) ? "Enable" : "Enable temporarily";
  264. }
  265. else
  266. {
  267. assert(toggle_state == 0);
  268. button_name = "Disable";
  269. }
  270. snprintf(form, size,
  271. "<form method=\"GET\" action=\""CGI_PREFIX"toggle-client-tag\" style=\"display: inline\">\n"
  272. " <input type=\"hidden\" name=\"tag\" value=\"%s\">\n"
  273. " <input type=\"hidden\" name=\"toggle-state\" value=\"%i\">\n"
  274. " <input type=\"hidden\" name=\"expires\" value=\"%u\">\n"
  275. " <input type=\"submit\" value=\"%s\">\n"
  276. "</form>", tag, toggle_state, !expires, button_name);
  277. }
  278. /*********************************************************************
  279. *
  280. * Function : cgi_show_client_tags
  281. *
  282. * Description : Shows the tags that can be set based on the client
  283. * address (opt-in).
  284. *
  285. * Parameters :
  286. * 1 : csp = Current client state (buffers, headers, etc...)
  287. * 2 : rsp = http_response data structure for output
  288. * 3 : parameters = map of cgi parameters
  289. *
  290. * CGI Parameters : none
  291. *
  292. * Returns : JB_ERR_OK on success
  293. * JB_ERR_MEMORY on out-of-memory error.
  294. *
  295. *********************************************************************/
  296. jb_err cgi_show_client_tags(struct client_state *csp,
  297. struct http_response *rsp,
  298. const struct map *parameters)
  299. {
  300. struct map *exports;
  301. struct client_tag_spec *this_tag;
  302. jb_err err = JB_ERR_OK;
  303. char *client_tag_status;
  304. char buf[1000];
  305. time_t refresh_delay;
  306. assert(csp);
  307. assert(rsp);
  308. assert(parameters);
  309. if (NULL == (exports = default_exports(csp, "client-tags")))
  310. {
  311. return JB_ERR_MEMORY;
  312. }
  313. assert(csp->client_address != NULL);
  314. this_tag = csp->config->client_tags;
  315. if (this_tag->name == NULL)
  316. {
  317. client_tag_status = strdup_or_die("<p>No tags available.</p>\n");
  318. }
  319. else
  320. {
  321. client_tag_status = strdup_or_die("<table border=\"1\">\n"
  322. "<tr><th>Tag name</th>\n"
  323. "<th>Current state</th><th>Change state</th><th>Description</th></tr>\n");
  324. while ((this_tag != NULL) && (this_tag->name != NULL))
  325. {
  326. int tag_state;
  327. privoxy_mutex_lock(&client_tags_mutex);
  328. tag_state = client_has_requested_tag(csp->client_address, this_tag->name);
  329. privoxy_mutex_unlock(&client_tags_mutex);
  330. if (!err) err = string_append(&client_tag_status, "<tr><td>");
  331. if (!err) err = string_append(&client_tag_status, this_tag->name);
  332. if (!err) err = string_append(&client_tag_status, "</td><td>");
  333. if (!err) err = string_append(&client_tag_status, tag_state == 1 ? "Enabled" : "Disabled");
  334. if (!err) err = string_append(&client_tag_status, "</td><td>");
  335. cgi_create_client_tag_form(buf, sizeof(buf), this_tag->name, !tag_state, 1);
  336. if (!err) err = string_append(&client_tag_status, buf);
  337. if (tag_state == 0)
  338. {
  339. cgi_create_client_tag_form(buf, sizeof(buf), this_tag->name, !tag_state, 0);
  340. if (!err) err = string_append(&client_tag_status, buf);
  341. }
  342. if (!err) err = string_append(&client_tag_status, "</td><td>");
  343. if (!err) err = string_append(&client_tag_status, this_tag->description);
  344. if (!err) err = string_append(&client_tag_status, "</td></tr>\n");
  345. if (err)
  346. {
  347. break;
  348. }
  349. this_tag = this_tag->next;
  350. }
  351. if (!err) err = string_append(&client_tag_status, "</table>\n");
  352. if (err)
  353. {
  354. free_map(exports);
  355. return JB_ERR_MEMORY;
  356. }
  357. }
  358. refresh_delay = get_next_tag_timeout_for_client(csp->client_address);
  359. if (refresh_delay != 0)
  360. {
  361. snprintf(buf, sizeof(buf), "%u", csp->config->client_tag_lifetime);
  362. if (map(exports, "refresh-delay", 1, buf, 1))
  363. {
  364. freez(client_tag_status);
  365. free_map(exports);
  366. return JB_ERR_MEMORY;
  367. }
  368. }
  369. else
  370. {
  371. err = map_block_killer(exports, "tags-expire");
  372. if (err != JB_ERR_OK)
  373. {
  374. freez(client_tag_status);
  375. return err;
  376. }
  377. }
  378. if (map(exports, "client-tags", 1, client_tag_status, 0))
  379. {
  380. free_map(exports);
  381. return JB_ERR_MEMORY;
  382. }
  383. if (map(exports, "client-ip-addr", 1, csp->client_address, 1))
  384. {
  385. free_map(exports);
  386. return JB_ERR_MEMORY;
  387. }
  388. return template_fill_for_cgi(csp, "client-tags", exports, rsp);
  389. }
  390. /*********************************************************************
  391. *
  392. * Function : cgi_toggle_client_tag
  393. *
  394. * Description : Toggles a client tag and redirects to the show-tags
  395. * page
  396. *
  397. * Parameters :
  398. * 1 : csp = Current client state (buffers, headers, etc...)
  399. * 2 : rsp = http_response data structure for output
  400. * 3 : parameters = map of cgi parameters
  401. *
  402. * CGI Parameters : none
  403. * 1 : tag = Name of the tag to enable or disable
  404. * 2 : toggle-state = How to toggle the tag (0/1)
  405. * 3 : expires = Set to 1 if the tag should be enabled
  406. * temporarily, otherwise set to 0
  407. *
  408. * Returns : JB_ERR_OK on success
  409. * JB_ERR_MEMORY on out-of-memory error.
  410. *
  411. *********************************************************************/
  412. jb_err cgi_toggle_client_tag(struct client_state *csp,
  413. struct http_response *rsp,
  414. const struct map *parameters)
  415. {
  416. const char *toggled_tag;
  417. const char *toggle_state;
  418. const char *tag_expires;
  419. time_t time_to_live;
  420. assert(csp);
  421. assert(rsp);
  422. assert(parameters);
  423. toggled_tag = lookup(parameters, "tag");
  424. if (*toggled_tag == '\0')
  425. {
  426. log_error(LOG_LEVEL_ERROR, "Received tag toggle request without tag");
  427. }
  428. else
  429. {
  430. tag_expires = lookup(parameters, "expires");
  431. if (*tag_expires == '0')
  432. {
  433. time_to_live = 0;
  434. }
  435. else
  436. {
  437. time_to_live = csp->config->client_tag_lifetime;
  438. }
  439. toggle_state = lookup(parameters, "toggle-state");
  440. if (*toggle_state == '1')
  441. {
  442. enable_client_specific_tag(csp, toggled_tag, time_to_live);
  443. }
  444. else
  445. {
  446. disable_client_specific_tag(csp, toggled_tag);
  447. }
  448. }
  449. rsp->status = strdup_or_die("302 Done dealing with toggle request");
  450. if (enlist_unique_header(rsp->headers,
  451. "Location", CGI_PREFIX "client-tags"))
  452. {
  453. return JB_ERR_MEMORY;
  454. }
  455. return JB_ERR_OK;
  456. }
  457. #endif /* def FEATURE_CLIENT_TAGS */
  458. /*********************************************************************
  459. *
  460. * Function : cgi_send_banner
  461. *
  462. * Description : CGI function that returns a banner.
  463. *
  464. * Parameters :
  465. * 1 : csp = Current client state (buffers, headers, etc...)
  466. * 2 : rsp = http_response data structure for output
  467. * 3 : parameters = map of cgi parameters
  468. *
  469. * CGI Parameters :
  470. * type : Selects the type of banner between "trans", "logo",
  471. * and "auto". Defaults to "logo" if absent or invalid.
  472. * "auto" means to select as if we were image-blocking.
  473. * (Only the first character really counts; b and t are
  474. * equivalent).
  475. *
  476. * Returns : JB_ERR_OK on success
  477. * JB_ERR_MEMORY on out-of-memory error.
  478. *
  479. *********************************************************************/
  480. jb_err cgi_send_banner(struct client_state *csp,
  481. struct http_response *rsp,
  482. const struct map *parameters)
  483. {
  484. char imagetype = lookup(parameters, "type")[0];
  485. /*
  486. * If type is auto, then determine the right thing
  487. * to do from the set-image-blocker action
  488. */
  489. if (imagetype == 'a')
  490. {
  491. /*
  492. * Default to pattern
  493. */
  494. imagetype = 'p';
  495. #ifdef FEATURE_IMAGE_BLOCKING
  496. if ((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
  497. {
  498. static const char prefix1[] = CGI_PREFIX "send-banner?type=";
  499. static const char prefix2[] = "http://" CGI_SITE_1_HOST "/send-banner?type=";
  500. const char *p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
  501. if (p == NULL)
  502. {
  503. /* Use default - nothing to do here. */
  504. }
  505. else if (0 == strcmpic(p, "blank"))
  506. {
  507. imagetype = 'b';
  508. }
  509. else if (0 == strcmpic(p, "pattern"))
  510. {
  511. imagetype = 'p';
  512. }
  513. /*
  514. * If the action is to call this CGI, determine
  515. * the argument:
  516. */
  517. else if (0 == strncmpic(p, prefix1, sizeof(prefix1) - 1))
  518. {
  519. imagetype = p[sizeof(prefix1) - 1];
  520. }
  521. else if (0 == strncmpic(p, prefix2, sizeof(prefix2) - 1))
  522. {
  523. imagetype = p[sizeof(prefix2) - 1];
  524. }
  525. /*
  526. * Everything else must (should) be a URL to
  527. * redirect to.
  528. */
  529. else
  530. {
  531. imagetype = 'r';
  532. }
  533. }
  534. #endif /* def FEATURE_IMAGE_BLOCKING */
  535. }
  536. /*
  537. * Now imagetype is either the non-auto type we were called with,
  538. * or it was auto and has since been determined. In any case, we
  539. * can proceed to actually answering the request by sending a redirect
  540. * or an image as appropriate:
  541. */
  542. if (imagetype == 'r')
  543. {
  544. rsp->status = strdup_or_die("302 Local Redirect from Privoxy");
  545. if (enlist_unique_header(rsp->headers, "Location",
  546. csp->action->string[ACTION_STRING_IMAGE_BLOCKER]))
  547. {
  548. return JB_ERR_MEMORY;
  549. }
  550. }
  551. else
  552. {
  553. if ((imagetype == 'b') || (imagetype == 't'))
  554. {
  555. rsp->body = bindup(image_blank_data, image_blank_length);
  556. rsp->content_length = image_blank_length;
  557. }
  558. else
  559. {
  560. rsp->body = bindup(image_pattern_data, image_pattern_length);
  561. rsp->content_length = image_pattern_length;
  562. }
  563. if (rsp->body == NULL)
  564. {
  565. return JB_ERR_MEMORY;
  566. }
  567. if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
  568. {
  569. return JB_ERR_MEMORY;
  570. }
  571. rsp->is_static = 1;
  572. }
  573. return JB_ERR_OK;
  574. }
  575. /*********************************************************************
  576. *
  577. * Function : cgi_transparent_image
  578. *
  579. * Description : CGI function that sends a 1x1 transparent image.
  580. *
  581. * Parameters :
  582. * 1 : csp = Current client state (buffers, headers, etc...)
  583. * 2 : rsp = http_response data structure for output
  584. * 3 : parameters = map of cgi parameters
  585. *
  586. * CGI Parameters : None
  587. *
  588. * Returns : JB_ERR_OK on success
  589. * JB_ERR_MEMORY on out-of-memory error.
  590. *
  591. *********************************************************************/
  592. jb_err cgi_transparent_image(struct client_state *csp,
  593. struct http_response *rsp,
  594. const struct map *parameters)
  595. {
  596. (void)csp;
  597. (void)parameters;
  598. rsp->body = bindup(image_blank_data, image_blank_length);
  599. rsp->content_length = image_blank_length;
  600. if (rsp->body == NULL)
  601. {
  602. return JB_ERR_MEMORY;
  603. }
  604. if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
  605. {
  606. return JB_ERR_MEMORY;
  607. }
  608. rsp->is_static = 1;
  609. return JB_ERR_OK;
  610. }
  611. /*********************************************************************
  612. *
  613. * Function : cgi_send_default_favicon
  614. *
  615. * Description : CGI function that sends the standard favicon.
  616. *
  617. * Parameters :
  618. * 1 : csp = Current client state (buffers, headers, etc...)
  619. * 2 : rsp = http_response data structure for output
  620. * 3 : parameters = map of cgi parameters
  621. *
  622. * CGI Parameters : None
  623. *
  624. * Returns : JB_ERR_OK on success
  625. * JB_ERR_MEMORY on out-of-memory error.
  626. *
  627. *********************************************************************/
  628. jb_err cgi_send_default_favicon(struct client_state *csp,
  629. struct http_response *rsp,
  630. const struct map *parameters)
  631. {
  632. static const char default_favicon_data[] =
  633. "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
  634. "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
  635. "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
  636. "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
  637. "\000\000\377\377\377\000\377\000\052\000\017\360\000\000\077"
  638. "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
  639. "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
  640. "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
  641. "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
  642. "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
  643. "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
  644. "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
  645. "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
  646. "\017\000\000";
  647. static const size_t favicon_length = sizeof(default_favicon_data) - 1;
  648. (void)csp;
  649. (void)parameters;
  650. rsp->body = bindup(default_favicon_data, favicon_length);
  651. rsp->content_length = favicon_length;
  652. if (rsp->body == NULL)
  653. {
  654. return JB_ERR_MEMORY;
  655. }
  656. if (enlist(rsp->headers, "Content-Type: image/x-icon"))
  657. {
  658. return JB_ERR_MEMORY;
  659. }
  660. rsp->is_static = 1;
  661. return JB_ERR_OK;
  662. }
  663. /*********************************************************************
  664. *
  665. * Function : cgi_send_error_favicon
  666. *
  667. * Description : CGI function that sends the favicon for error pages.
  668. *
  669. * Parameters :
  670. * 1 : csp = Current client state (buffers, headers, etc...)
  671. * 2 : rsp = http_response data structure for output
  672. * 3 : parameters = map of cgi parameters
  673. *
  674. * CGI Parameters : None
  675. *
  676. * Returns : JB_ERR_OK on success
  677. * JB_ERR_MEMORY on out-of-memory error.
  678. *
  679. *********************************************************************/
  680. jb_err cgi_send_error_favicon(struct client_state *csp,
  681. struct http_response *rsp,
  682. const struct map *parameters)
  683. {
  684. static const char error_favicon_data[] =
  685. "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
  686. "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
  687. "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
  688. "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
  689. "\000\000\377\377\377\000\000\000\377\000\017\360\000\000\077"
  690. "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
  691. "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
  692. "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
  693. "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
  694. "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
  695. "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
  696. "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
  697. "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
  698. "\017\000\000";
  699. static const size_t favicon_length = sizeof(error_favicon_data) - 1;
  700. (void)csp;
  701. (void)parameters;
  702. rsp->body = bindup(error_favicon_data, favicon_length);
  703. rsp->content_length = favicon_length;
  704. if (rsp->body == NULL)
  705. {
  706. return JB_ERR_MEMORY;
  707. }
  708. if (enlist(rsp->headers, "Content-Type: image/x-icon"))
  709. {
  710. return JB_ERR_MEMORY;
  711. }
  712. rsp->is_static = 1;
  713. return JB_ERR_OK;
  714. }
  715. /*********************************************************************
  716. *
  717. * Function : cgi_send_stylesheet
  718. *
  719. * Description : CGI function that sends a css stylesheet found
  720. * in the cgi-style.css template
  721. *
  722. * Parameters :
  723. * 1 : csp = Current client state (buffers, headers, etc...)
  724. * 2 : rsp = http_response data structure for output
  725. * 3 : parameters = map of cgi parameters
  726. *
  727. * CGI Parameters : None
  728. *
  729. * Returns : JB_ERR_OK on success
  730. * JB_ERR_MEMORY on out-of-memory error.
  731. *
  732. *********************************************************************/
  733. jb_err cgi_send_stylesheet(struct client_state *csp,
  734. struct http_response *rsp,
  735. const struct map *parameters)
  736. {
  737. jb_err err;
  738. assert(csp);
  739. assert(rsp);
  740. (void)parameters;
  741. err = template_load(csp, &rsp->body, "cgi-style.css", 0);
  742. if (err == JB_ERR_FILE)
  743. {
  744. /*
  745. * No way to tell user; send empty stylesheet
  746. */
  747. log_error(LOG_LEVEL_ERROR, "Could not find cgi-style.css template");
  748. }
  749. else if (err)
  750. {
  751. return err; /* JB_ERR_MEMORY */
  752. }
  753. if (enlist(rsp->headers, "Content-Type: text/css"))
  754. {
  755. return JB_ERR_MEMORY;
  756. }
  757. return JB_ERR_OK;
  758. }
  759. /*********************************************************************
  760. *
  761. * Function : cgi_send_url_info_osd
  762. *
  763. * Description : CGI function that sends the OpenSearch Description
  764. * template for the show-url-info page. It allows to
  765. * access the page through "search engine plugins".
  766. *
  767. * Parameters :
  768. * 1 : csp = Current client state (buffers, headers, etc...)
  769. * 2 : rsp = http_response data structure for output
  770. * 3 : parameters = map of cgi parameters
  771. *
  772. * CGI Parameters : None
  773. *
  774. * Returns : JB_ERR_OK on success
  775. * JB_ERR_MEMORY on out-of-memory error.
  776. *
  777. *********************************************************************/
  778. jb_err cgi_send_url_info_osd(struct client_state *csp,
  779. struct http_response *rsp,
  780. const struct map *parameters)
  781. {
  782. jb_err err = JB_ERR_MEMORY;
  783. struct map *exports = default_exports(csp, NULL);
  784. (void)csp;
  785. (void)parameters;
  786. if (NULL != exports)
  787. {
  788. err = template_fill_for_cgi(csp, "url-info-osd.xml", exports, rsp);
  789. if (JB_ERR_OK == err)
  790. {
  791. err = enlist(rsp->headers,
  792. "Content-Type: application/opensearchdescription+xml");
  793. }
  794. }
  795. return err;
  796. }
  797. /*********************************************************************
  798. *
  799. * Function : get_content_type
  800. *
  801. * Description : Use the file extension to guess the content type
  802. * header we should use to serve the file.
  803. *
  804. * Parameters :
  805. * 1 : filename = Name of the file whose content type
  806. * we care about
  807. *
  808. * Returns : The guessed content type.
  809. *
  810. *********************************************************************/
  811. static const char *get_content_type(const char *filename)
  812. {
  813. int i;
  814. struct content_type
  815. {
  816. const char extension[6];
  817. const char content_type[11];
  818. };
  819. static const struct content_type content_types[] =
  820. {
  821. {".css", "text/css"},
  822. {".jpg", "image/jpeg"},
  823. {".jpeg", "image/jpeg"},
  824. {".png", "image/png"},
  825. };
  826. for (i = 0; i < SZ(content_types); i++)
  827. {
  828. if (strstr(filename, content_types[i].extension))
  829. {
  830. return content_types[i].content_type;
  831. }
  832. }
  833. /* No match by extension, default to html */
  834. return "text/html";
  835. }
  836. /*********************************************************************
  837. *
  838. * Function : cgi_send_user_manual
  839. *
  840. * Description : CGI function that sends a file in the user
  841. * manual directory.
  842. *
  843. * Parameters :
  844. * 1 : csp = Current client state (buffers, headers, etc...)
  845. * 2 : rsp = http_response data structure for output
  846. * 3 : parameters = map of cgi parameters
  847. *
  848. * CGI Parameters : file=name.html, the name of the HTML file
  849. * (relative to user-manual from config)
  850. *
  851. * Returns : JB_ERR_OK on success
  852. * JB_ERR_MEMORY on out-of-memory error.
  853. *
  854. *********************************************************************/
  855. jb_err cgi_send_user_manual(struct client_state *csp,
  856. struct http_response *rsp,
  857. const struct map *parameters)
  858. {
  859. const char *filename;
  860. char *full_path;
  861. jb_err err = JB_ERR_OK;
  862. const char *content_type;
  863. assert(csp);
  864. assert(rsp);
  865. assert(parameters);
  866. if (0 == strncmpic(csp->config->usermanual, "http://", 7))
  867. {
  868. log_error(LOG_LEVEL_CGI, "Request for local user-manual "
  869. "received while user-manual delivery is disabled.");
  870. return cgi_error_404(csp, rsp, parameters);
  871. }
  872. if (!parameters->first)
  873. {
  874. /* requested http://p.p/user-manual (without trailing slash) */
  875. return cgi_redirect(rsp, CGI_PREFIX "user-manual/");
  876. }
  877. get_string_param(parameters, "file", &filename);
  878. if (filename == NULL)
  879. {
  880. /* It's '/' so serve the index.html if there is one. */
  881. filename = "index.html";
  882. }
  883. else if (NULL != strchr(filename, '/') || NULL != strstr(filename, ".."))
  884. {
  885. /*
  886. * We currently only support a flat file
  887. * hierarchy for the documentation.
  888. */
  889. log_error(LOG_LEVEL_ERROR,
  890. "Rejecting the request to serve '%s' as it contains '/' or '..'",
  891. filename);
  892. return JB_ERR_CGI_PARAMS;
  893. }
  894. full_path = make_path(csp->config->usermanual, filename);
  895. if (full_path == NULL)
  896. {
  897. return JB_ERR_MEMORY;
  898. }
  899. err = load_file(full_path, &rsp->body, &rsp->content_length);
  900. if (JB_ERR_OK != err)
  901. {
  902. assert((JB_ERR_FILE == err) || (JB_ERR_MEMORY == err));
  903. if (JB_ERR_FILE == err)
  904. {
  905. err = cgi_error_no_template(csp, rsp, full_path);
  906. }
  907. freez(full_path);
  908. return err;
  909. }
  910. freez(full_path);
  911. content_type = get_content_type(filename);
  912. log_error(LOG_LEVEL_CGI,
  913. "Content-Type guessed for %s: %s", filename, content_type);
  914. return enlist_unique_header(rsp->headers, "Content-Type", content_type);
  915. }
  916. #ifdef FEATURE_EXTENDED_STATISTICS
  917. /*********************************************************************
  918. *
  919. * Function : get_block_reason_statistics_table
  920. *
  921. * Description : Produces the block reason statistic table content.
  922. *
  923. * Parameters :
  924. * 1 : csp = Current client state (buffers, headers, etc...)
  925. *
  926. * Returns : Pointer to the HTML statistic table content or
  927. * NULL on out of memory
  928. *
  929. *********************************************************************/
  930. static char *get_block_reason_statistics_table(const struct client_state *csp)
  931. {
  932. char buf[BUFFER_SIZE];
  933. char *statistics;
  934. int i;
  935. struct file_list *fl;
  936. jb_err err = JB_ERR_OK;
  937. statistics = strdup_or_die("");
  938. /* Run through all action files. */
  939. for (i = 0; i < MAX_AF_FILES; i++)
  940. {
  941. struct url_actions *b;
  942. struct action_spec *last_action = NULL;
  943. if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
  944. {
  945. /* Skip empty files */
  946. continue;
  947. }
  948. /* Go through all the actions. */
  949. for (b = b->next; NULL != b; b = b->next)
  950. {
  951. if (last_action == b->action)
  952. {
  953. continue;
  954. }
  955. if ((b->action->add & ACTION_BLOCK))
  956. {
  957. unsigned long long count;
  958. const char *block_reason = b->action->string[ACTION_STRING_BLOCK];
  959. const char *encoded_block_reason = html_encode(block_reason);
  960. if (encoded_block_reason == NULL)
  961. {
  962. freez(statistics);
  963. return NULL;
  964. }
  965. get_block_reason_count(block_reason, &count);
  966. snprintf(buf, sizeof(buf),
  967. "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>\n",
  968. encoded_block_reason, count);
  969. freez(encoded_block_reason);
  970. if (!err) err = string_append(&statistics, buf);
  971. }
  972. last_action = b->action;
  973. }
  974. }
  975. return statistics;
  976. }
  977. /*********************************************************************
  978. *
  979. * Function : get_filter_statistics_table
  980. *
  981. * Description : Produces the filter statistic table content.
  982. *
  983. * Parameters :
  984. * 1 : csp = Current client state (buffers, headers, etc...)
  985. *
  986. * Returns : Pointer to the HTML statistic table content or
  987. * NULL on out of memory
  988. *
  989. *********************************************************************/
  990. static char *get_filter_statistics_table(const struct client_state *csp)
  991. {
  992. char buf[BUFFER_SIZE];
  993. char *statistics;
  994. int i;
  995. struct file_list *fl;
  996. struct re_filterfile_spec *b;
  997. jb_err err = JB_ERR_OK;
  998. statistics = strdup_or_die("");
  999. for (i = 0; i < MAX_AF_FILES; i++)
  1000. {
  1001. fl = csp->rlist[i];
  1002. if ((NULL == fl) || (NULL == fl->f))
  1003. {
  1004. /*
  1005. * Either there are no filter files left or this
  1006. * filter file just contains no valid filters.
  1007. *
  1008. * Continue to be sure we don't miss valid filter
  1009. * files that are chained after empty or invalid ones.
  1010. */
  1011. continue;
  1012. }
  1013. for (b = fl->f; b != NULL; b = b->next)
  1014. {
  1015. if (b->type == FT_CONTENT_FILTER)
  1016. {
  1017. unsigned long long executions;
  1018. unsigned long long response_bodies_modified;
  1019. unsigned long long hits;
  1020. get_filter_statistics(b->name, &executions, &response_bodies_modified, &hits);
  1021. snprintf(buf, sizeof(buf),
  1022. "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
  1023. "<td style=\"text-align: right\">%llu</td>"
  1024. "<td style=\"text-align: right\">%llu</td><tr>\n",
  1025. b->name, executions, response_bodies_modified, hits);
  1026. if (!err) err = string_append(&statistics, buf);
  1027. }
  1028. }
  1029. }
  1030. return statistics;
  1031. }
  1032. #endif /* def FEATURE_EXTENDED_STATISTICS */
  1033. /*********************************************************************
  1034. *
  1035. * Function : cgi_show_status
  1036. *
  1037. * Description : CGI function that returns a web page describing the
  1038. * current status of Privoxy.
  1039. *
  1040. * Parameters :
  1041. * 1 : csp = Current client state (buffers, headers, etc...)
  1042. * 2 : rsp = http_response data structure for output
  1043. * 3 : parameters = map of cgi parameters
  1044. *
  1045. * CGI Parameters :
  1046. * file : Which file to show. Only first letter is checked,
  1047. * valid values are:
  1048. * - "a"ction file
  1049. * - "r"egex
  1050. * - "t"rust
  1051. * Default is to show menu and other information.
  1052. *
  1053. * Returns : JB_ERR_OK on success
  1054. * JB_ERR_MEMORY on out-of-memory error.
  1055. *
  1056. *********************************************************************/
  1057. jb_err cgi_show_status(struct client_state *csp,
  1058. struct http_response *rsp,
  1059. const struct map *parameters)
  1060. {
  1061. char *s = NULL;
  1062. unsigned i;
  1063. int j;
  1064. char buf[BUFFER_SIZE];
  1065. #ifdef FEATURE_STATISTICS
  1066. float perc_rej; /* Percentage of http requests rejected */
  1067. int local_urls_read;
  1068. int local_urls_rejected;
  1069. #endif /* ndef FEATURE_STATISTICS */
  1070. jb_err err = JB_ERR_OK;
  1071. struct map *exports;
  1072. assert(csp);
  1073. assert(rsp);
  1074. assert(parameters);
  1075. if ('\0' != *(lookup(parameters, "file")))
  1076. {
  1077. return cgi_show_file(csp, rsp, parameters);
  1078. }
  1079. if (NULL == (exports = default_exports(csp, "show-status")))
  1080. {
  1081. return JB_ERR_MEMORY;
  1082. }
  1083. s = strdup("");
  1084. for (j = 0; (s != NULL) && (j < Argc); j++)
  1085. {
  1086. if (!err) err = string_join (&s, html_encode(Argv[j]));
  1087. if (!err) err = string_append(&s, " ");
  1088. }
  1089. if (!err) err = map(exports, "invocation", 1, s, 0);
  1090. if (!err) err = map(exports, "options", 1, csp->config->proxy_args, 1);
  1091. if (!err) err = show_defines(exports);
  1092. if (err)
  1093. {
  1094. free_map(exports);
  1095. return JB_ERR_MEMORY;
  1096. }
  1097. #ifdef FEATURE_STATISTICS
  1098. local_urls_read = urls_read;
  1099. local_urls_rejected = urls_rejected;
  1100. /*
  1101. * Need to alter the stats not to include the fetch of this
  1102. * page.
  1103. *
  1104. * Can't do following thread safely! doh!
  1105. *
  1106. * urls_read--;
  1107. * urls_rejected--; * This will be incremented subsequently *
  1108. */
  1109. if (local_urls_read == 0)
  1110. {
  1111. if (!err) err = map_block_killer(exports, "have-stats");
  1112. }
  1113. else
  1114. {
  1115. if (!err) err = map_block_killer(exports, "have-no-stats");
  1116. perc_rej = (float)local_urls_rejected * 100.0F /
  1117. (float)local_urls_read;
  1118. snprintf(buf, sizeof(buf), "%d", local_urls_read);
  1119. if (!err) err = map(exports, "requests-received", 1, buf, 1);
  1120. snprintf(buf, sizeof(buf), "%d", local_urls_rejected);
  1121. if (!err) err = map(exports, "requests-blocked", 1, buf, 1);
  1122. snprintf(buf, sizeof(buf), "%6.2f", perc_rej);
  1123. if (!err) err = map(exports, "percent-blocked", 1, buf, 1);
  1124. }
  1125. #else /* ndef FEATURE_STATISTICS */
  1126. if (!err) err = map_block_killer(exports, "statistics");
  1127. #endif /* ndef FEATURE_STATISTICS */
  1128. #ifdef FEATURE_EXTENDED_STATISTICS
  1129. if (!err)
  1130. {
  1131. char *block_reason_statistics = get_block_reason_statistics_table(csp);
  1132. if (block_reason_statistics != NULL)
  1133. {
  1134. err = map(exports, "block-reason-statistics", 1, block_reason_statistics, 0);
  1135. }
  1136. else
  1137. {
  1138. err = map_block_killer(exports, "extended-statistics");
  1139. }
  1140. }
  1141. if (!err)
  1142. {
  1143. char *filter_statistics = get_filter_statistics_table(csp);
  1144. if (filter_statistics != NULL)
  1145. {
  1146. err = map(exports, "filter-statistics", 1, filter_statistics, 0);
  1147. }
  1148. else
  1149. {
  1150. err = map_block_killer(exports, "extended-statistics");
  1151. }
  1152. }
  1153. #else /* ndef FEATURE_EXTENDED_STATISTICS */
  1154. if (!err) err = map_block_killer(exports, "extended-statistics");
  1155. #endif /* def FEATURE_EXTENDED_STATISTICS */
  1156. /*
  1157. * List all action files in use, together with view and edit links,
  1158. * except for standard.action, which should only be viewable. (Not
  1159. * enforced in the editor itself)
  1160. * FIXME: Shouldn't include hardwired HTML here, use line template instead!
  1161. */
  1162. s = strdup("");
  1163. for (i = 0; i < MAX_AF_FILES; i++)
  1164. {
  1165. if (csp->actions_list[i] != NULL)
  1166. {
  1167. if (!err) err = string_append(&s, "<tr><td>");
  1168. if (!err) err = string_join(&s, html_encode(csp->actions_list[i]->filename));
  1169. snprintf(buf, sizeof(buf),
  1170. "</td><td class=\"buttons\"><a href=\"/show-status?file=actions&amp;index=%u\">View</a>", i);
  1171. if (!err) err = string_append(&s, buf);
  1172. #ifdef FEATURE_CGI_EDIT_ACTIONS
  1173. if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
  1174. && (NULL != csp->config->actions_file_short[i]))
  1175. {
  1176. #ifdef HAVE_ACCESS
  1177. if (access(csp->config->actions_file[i], W_OK) == 0)
  1178. {
  1179. #endif /* def HAVE_ACCESS */
  1180. snprintf(buf, sizeof(buf), "&nbsp;&nbsp;<a href=\"/edit-actions-list?f=%u\">Edit</a>", i);
  1181. if (!err) err = string_append(&s, buf);
  1182. #ifdef HAVE_ACCESS
  1183. }
  1184. else
  1185. {
  1186. if (!err) err = string_append(&s, "&nbsp;&nbsp;<strong>No write access.</strong>");
  1187. }
  1188. #endif /* def HAVE_ACCESS */
  1189. }
  1190. #endif
  1191. if (!err) err = string_append(&s, "</td></tr>\n");
  1192. }
  1193. }
  1194. if (!err && *s != '\0')
  1195. {
  1196. err = map(exports, "actions-filenames", 1, s, 0);
  1197. }
  1198. else
  1199. {
  1200. if (!err) err = map(exports, "actions-filenames", 1, "<tr><td>None specified</td></tr>", 1);
  1201. freez(s);
  1202. }
  1203. /*
  1204. * List all re_filterfiles in use, together with view options.
  1205. * FIXME: Shouldn't include hardwired HTML here, use line template instead!
  1206. */
  1207. s = strdup("");
  1208. for (i = 0; i < MAX_AF_FILES; i++)
  1209. {
  1210. if (csp->rlist[i] != NULL)
  1211. {
  1212. if (!err) err = string_append(&s, "<tr><td>");
  1213. if (!err) err = string_join(&s, html_encode(csp->rlist[i]->filename));
  1214. snprintf(buf, sizeof(buf),
  1215. "</td><td class=\"buttons\"><a href=\"/show-status?file=filter&amp;index=%u\">View</a>", i);
  1216. if (!err) err = string_append(&s, buf);
  1217. if (!err) err = string_append(&s, "</td></tr>\n");
  1218. }
  1219. }
  1220. if (!err && *s != '\0')
  1221. {
  1222. err = map(exports, "re-filter-filenames", 1, s, 0);
  1223. }
  1224. else
  1225. {
  1226. if (!err) err = map(exports, "re-filter-filenames", 1, "<tr><td>None specified</td></tr>", 1);
  1227. if (!err) err = map_block_killer(exports, "have-filterfile");
  1228. freez(s);
  1229. }
  1230. #ifdef FEATURE_TRUST
  1231. if (csp->tlist)
  1232. {
  1233. if (!err) err = map(exports, "trust-filename", 1, html_encode(csp->tlist->filename), 0);
  1234. }
  1235. else
  1236. {
  1237. if (!err) err = map(exports, "trust-filename", 1, "None specified", 1);
  1238. if (!err) err = map_block_killer(exports, "have-trustfile");
  1239. }
  1240. #else
  1241. if (!err) err = map_block_killer(exports, "trust-support");
  1242. #endif /* ndef FEATURE_TRUST */
  1243. #ifdef FEATURE_CGI_EDIT_ACTIONS
  1244. if (!err && (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
  1245. {
  1246. err = map_block_killer(exports, "cgi-editor-is-disabled");
  1247. }
  1248. #endif /* ndef CGI_EDIT_ACTIONS */
  1249. if (!err) err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1);
  1250. if (err)
  1251. {
  1252. free_map(exports);
  1253. return JB_ERR_MEMORY;
  1254. }
  1255. return template_fill_for_cgi(csp, "show-status", exports, rsp);
  1256. }
  1257. /*********************************************************************
  1258. *
  1259. * Function : cgi_show_url_info
  1260. *
  1261. * Description : CGI function that determines and shows which actions
  1262. * Privoxy will perform for a given url, and which
  1263. * matches starting from the defaults have lead to that.
  1264. *
  1265. * Parameters :
  1266. * 1 : csp = Current client state (buffers, headers, etc...)
  1267. * 2 : rsp = http_response data structure for output
  1268. * 3 : parameters = map of cgi parameters
  1269. *
  1270. * CGI Parameters :
  1271. * url : The url whose actions are to be determined.
  1272. * If url is unset, the url-given conditional will be
  1273. * set, so that all but the form can be suppressed in
  1274. * the template.
  1275. *
  1276. * Returns : JB_ERR_OK on success
  1277. * JB_ERR_MEMORY on out-of-memory error.
  1278. *
  1279. *********************************************************************/
  1280. jb_err cgi_show_url_info(struct client_state *csp,
  1281. struct http_response *rsp,
  1282. const struct map *parameters)
  1283. {
  1284. char *url_param;
  1285. struct map *exports;
  1286. char buf[150];
  1287. assert(csp);
  1288. assert(rsp);
  1289. assert(parameters);
  1290. if (NULL == (exports = default_exports(csp, "show-url-info")))
  1291. {
  1292. return JB_ERR_MEMORY;
  1293. }
  1294. /*
  1295. * Get the url= parameter (if present) and remove any leading/trailing spaces.
  1296. */
  1297. url_param = strdup_or_die(lookup(parameters, "url"));
  1298. chomp(url_param);
  1299. /*
  1300. * Handle prefixes. 4 possibilities:
  1301. * 1) "http://" or "https://" prefix present and followed by URL - OK
  1302. * 2) Only the "http://" or "https://" part is present, no URL - change
  1303. * to empty string so it will be detected later as "no URL".
  1304. * 3) Parameter specified but doesn't start with "http(s?)://" - add a
  1305. * "http://" prefix.
  1306. * 4) Parameter not specified or is empty string - let this fall through
  1307. * for now, next block of code will handle it.
  1308. */
  1309. if (0 == strncmp(url_param, "http://", 7))
  1310. {
  1311. if (url_param[7] == '\0')
  1312. {
  1313. /*
  1314. * Empty URL (just prefix).
  1315. * Make it totally empty so it's caught by the next if ()
  1316. */
  1317. url_param[0] = '\0';
  1318. }
  1319. }
  1320. else if (0 == strncmp(url_param, "https://", 8))
  1321. {
  1322. if (url_param[8] == '\0')
  1323. {
  1324. /*
  1325. * Empty URL (just prefix).
  1326. * Make it totally empty so it's caught by the next if ()
  1327. */
  1328. url_param[0] = '\0';
  1329. }
  1330. }
  1331. else if ((url_param[0] != '\0')
  1332. && ((NULL == strstr(url_param, "://")
  1333. || (strstr(url_param, "://") > strstr(url_param, "/")))))
  1334. {
  1335. /*
  1336. * No prefix or at least no prefix before
  1337. * the first slash - assume http://
  1338. */
  1339. char *url_param_prefixed = strdup_or_die("http://");
  1340. if (JB_ERR_OK != string_join(&url_param_prefixed, url_param))
  1341. {
  1342. free_map(exports);
  1343. return JB_ERR_MEMORY;
  1344. }
  1345. url_param = url_param_prefixed;
  1346. }
  1347. /*
  1348. * Hide "toggle off" warning if Privoxy is toggled on.
  1349. */
  1350. if (
  1351. #ifdef FEATURE_TOGGLE
  1352. (global_toggle_state == 1) &&
  1353. #endif /* def FEATURE_TOGGLE */
  1354. map_block_killer(exports, "privoxy-is-toggled-off")
  1355. )
  1356. {
  1357. freez(url_param);
  1358. free_map(exports);
  1359. return JB_ERR_MEMORY;
  1360. }
  1361. if (url_param[0] == '\0')
  1362. {
  1363. /* URL parameter not specified, display query form only. */
  1364. free(url_param);
  1365. if (map_block_killer(exports, "url-given")
  1366. || map(exports, "url", 1, "", 1))
  1367. {
  1368. free_map(exports);
  1369. return JB_ERR_MEMORY;
  1370. }
  1371. }
  1372. else
  1373. {
  1374. /* Given a URL, so query it. */
  1375. jb_err err;
  1376. char *matches;
  1377. char *s;
  1378. int hits = 0;
  1379. struct file_list *fl;
  1380. struct url_actions *b;
  1381. struct http_request url_to_query[1];
  1382. struct current_action_spec action[1];
  1383. int i;
  1384. if (map(exports, "url", 1, html_encode(url_param), 0))
  1385. {
  1386. free(url_param);
  1387. free_map(exports);
  1388. return JB_ERR_MEMORY;
  1389. }
  1390. init_current_action(action);
  1391. if (map(exports, "default", 1, current_action_to_html(csp, action), 0))
  1392. {
  1393. free_current_action(action);
  1394. free(url_param);
  1395. free_map(exports);
  1396. return JB_ERR_MEMORY;
  1397. }
  1398. memset(url_to_query, '\0', sizeof(url_to_query));
  1399. err = parse_http_url(url_param, url_to_query, REQUIRE_PROTOCOL);
  1400. assert((err != JB_ERR_OK) || (url_to_query->ssl == !strncmpic(url_param, "https://", 8)));
  1401. free(url_param);
  1402. if (err == JB_ERR_MEMORY)
  1403. {
  1404. free_http_request(url_to_query);
  1405. free_current_action(action);
  1406. free_map(exports);
  1407. return JB_ERR_MEMORY;
  1408. }
  1409. else if (err)
  1410. {
  1411. /* Invalid URL */
  1412. err = map(exports, "matches", 1, "<b>[Invalid URL specified!]</b>" , 1);
  1413. if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1);
  1414. if (!err) err = map_block_killer(exports, "valid-url");
  1415. free_current_action(action);
  1416. free_http_request(url_to_query);
  1417. if (err)
  1418. {
  1419. free_map(exports);
  1420. return JB_ERR_MEMORY;
  1421. }
  1422. return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
  1423. }
  1424. /*
  1425. * We have a warning about SSL paths. Hide it for unencrypted sites
  1426. * and unconditionally if https inspection is enabled.
  1427. */
  1428. #ifndef FEATURE_HTTPS_INSPECTION
  1429. if (!url_to_query->ssl)
  1430. #endif
  1431. {
  1432. if (map_block_killer(exports, "https-and-no-https-inspection"))
  1433. {
  1434. free_current_action(action);
  1435. free_map(exports);
  1436. free_http_request(url_to_query);
  1437. return JB_ERR_MEMORY;
  1438. }
  1439. }
  1440. matches = strdup_or_die("<table summary=\"\" class=\"transparent\">");
  1441. for (i = 0; i < MAX_AF_FILES; i++)
  1442. {
  1443. if (NULL == csp->config->actions_file_short[i]
  1444. || !strcmp(csp->config->actions_file_short[i], "standard.action")) continue;
  1445. b = NULL;
  1446. hits = 1;
  1447. if ((fl = csp->actions_list[i]) != NULL)
  1448. {
  1449. if ((b = fl->f) != NULL)
  1450. {
  1451. /* FIXME: Hardcoded HTML! */
  1452. string_append(&matches, "<tr><th>In file: ");
  1453. string_join (&matches, html_encode(csp->config->actions_file_short[i]));
  1454. snprintf(buf, sizeof(buf), " <a class=\"cmd\" href=\"/show-status?file=actions&amp;index=%d\">", i);
  1455. string_append(&matches, buf);
  1456. string_append(&matches, "View</a>");
  1457. #ifdef FEATURE_CGI_EDIT_ACTIONS
  1458. if (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
  1459. {
  1460. #ifdef HAVE_ACCESS
  1461. if (access(csp->config->actions_file[i], W_OK) == 0)
  1462. {
  1463. #endif /* def HAVE_ACCESS */
  1464. snprintf(buf, sizeof(buf),
  1465. " <a class=\"cmd\" href=\"/edit-actions-list?f=%d\">", i);
  1466. string_append(&matches, buf);
  1467. string_append(&matches, "Edit</a>");
  1468. #ifdef HAVE_ACCESS
  1469. }
  1470. else
  1471. {
  1472. string_append(&matches, " <strong>No write access.</strong>");
  1473. }
  1474. #endif /* def HAVE_ACCESS */
  1475. }
  1476. #endif /* FEATURE_CGI_EDIT_ACTIONS */
  1477. string_append(&matches, "</th></tr>\n");
  1478. hits = 0;
  1479. b = b->next;
  1480. }
  1481. }
  1482. for (; (b != NULL) && (matches != NULL); b = b->next)
  1483. {
  1484. if (url_match(b->url, url_to_query))
  1485. {
  1486. string_append(&matches, "<tr><td>{");
  1487. string_join (&matches, actions_to_html(csp, b->action));
  1488. string_append(&matches, " }<br>\n<code>");
  1489. string_join (&matches, html_encode(b->url->spec));
  1490. string_append(&matches, "</code></td></tr>\n");
  1491. if (merge_current_action(action, b->action))
  1492. {
  1493. freez(matches);
  1494. free_http_request(url_to_query);
  1495. free_current_action(action);
  1496. free_map(exports);
  1497. return JB_ERR_MEMORY;
  1498. }
  1499. hits++;
  1500. }
  1501. }
  1502. if (!hits)
  1503. {
  1504. string_append(&matches, "<tr><td>(no matches in this file)</td></tr>\n");
  1505. }
  1506. }
  1507. string_append(&matches, "</table>\n");
  1508. /*
  1509. * XXX: Kludge to make sure the "Forward settings" section
  1510. * shows what forward-override{} would do with the requested URL.
  1511. * No one really cares how the CGI request would be forwarded
  1512. * if it wasn't intercepted as CGI request in the first place.
  1513. *
  1514. * From here on the action bitmask will no longer reflect
  1515. * the real url (http://config.privoxy.org/show-url-info?url=.*),
  1516. * but luckily it's no longer required later on anyway.
  1517. */
  1518. free_current_action(csp->action);
  1519. get_url_actions(csp, url_to_query);
  1520. /*
  1521. * Fill in forwarding settings.
  1522. *
  1523. * The possibilities are:
  1524. * - no forwarding
  1525. * - http forwarding only
  1526. * - socks4(a) forwarding only
  1527. * - socks4(a) and http forwarding.
  1528. *
  1529. * XXX: Parts of this code could be reused for the
  1530. * "forwarding-failed" template which currently doesn't
  1531. * display the proxy port and an eventual second forwarder.
  1532. */
  1533. {
  1534. const struct forward_spec *fwd = forward_url(csp, url_to_query);
  1535. if ((fwd->gateway_host == NULL) && (fwd->forward_host == NULL))
  1536. {
  1537. if (!err) err = map_block_killer(exports, "socks-forwarder");
  1538. if (!err) err = map_block_killer(exports, "http-forwarder");
  1539. }
  1540. else
  1541. {
  1542. char port[10]; /* We save proxy ports as int but need a string here */
  1543. if (!err) err = map_block_killer(exports, "no-forwarder");
  1544. if (fwd->gateway_host != NULL)
  1545. {
  1546. char *socks_type = NULL;
  1547. switch (fwd->type)
  1548. {
  1549. case SOCKS_4:
  1550. socks_type = "socks4";
  1551. break;
  1552. case SOCKS_4A:
  1553. socks_type = "socks4a";
  1554. break;
  1555. case SOCKS_5:
  1556. socks_type = "socks5";
  1557. break;
  1558. case SOCKS_5T:
  1559. socks_type = "socks5t";
  1560. break;
  1561. default:
  1562. log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
  1563. }
  1564. if (!err) err = map(exports, "socks-type", 1, socks_type, 1);
  1565. if (!err) err = map(exports, "gateway-host", 1, fwd->gateway_host, 1);
  1566. snprintf(port, sizeof(port), "%d", fwd->gateway_port);
  1567. if (!err) err = map(exports, "gateway-port", 1, port, 1);
  1568. }
  1569. else
  1570. {
  1571. if (!err) err = map_block_killer(exports, "socks-forwarder");
  1572. }
  1573. if (fwd->forward_host != NULL)
  1574. {
  1575. if (!err) err = map(exports, "forward-host", 1, fwd->forward_host, 1);
  1576. snprintf(port, sizeof(port), "%d", fwd->forward_port);
  1577. if (!err) err = map(exports, "forward-port", 1, port, 1);
  1578. }
  1579. else
  1580. {
  1581. if (!err) err = map_block_killer(exports, "http-forwarder");
  1582. }
  1583. }
  1584. }
  1585. free_http_request(url_to_query);
  1586. if (err || matches == NULL)
  1587. {
  1588. free_current_action(action);
  1589. free_map(exports);
  1590. return JB_ERR_MEMORY;
  1591. }
  1592. #ifdef FEATURE_CGI_EDIT_ACTIONS
  1593. if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
  1594. {
  1595. err = map_block_killer(exports, "cgi-editor-is-disabled");
  1596. }
  1597. #endif /* FEATURE_CGI_EDIT_ACTIONS */
  1598. /*
  1599. * If zlib support is available, if no content filters
  1600. * are enabled or if the prevent-compression action is enabled,
  1601. * suppress the "compression could prevent filtering" warning.
  1602. */
  1603. #ifndef FEATURE_ZLIB
  1604. if (!content_filters_enabled(action) ||
  1605. (action->flags & ACTION_NO_COMPRESSION))
  1606. #endif
  1607. {
  1608. if (!err) err = map_block_killer(exports, "filters-might-be-ineffective");
  1609. }
  1610. if (err || map(exports, "matches", 1, matches , 0))
  1611. {
  1612. free_current_action(action);
  1613. free_map(exports);
  1614. return JB_ERR_MEMORY;
  1615. }
  1616. s = current_action_to_html(csp, action);
  1617. free_current_action(action);
  1618. if (map(exports, "final", 1, s, 0))
  1619. {
  1620. free_map(exports);
  1621. return JB_ERR_MEMORY;
  1622. }
  1623. }
  1624. return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
  1625. }
  1626. /*********************************************************************
  1627. *
  1628. * Function : cgi_robots_txt
  1629. *
  1630. * Description : CGI function to return "/robots.txt".
  1631. *
  1632. * Parameters :
  1633. * 1 : csp = Current client state (buffers, headers, etc...)
  1634. * 2 : rsp = http_response data structure for output
  1635. * 3 : parameters = map of cgi parameters
  1636. *
  1637. * CGI Parameters : None
  1638. *
  1639. * Returns : JB_ERR_OK on success
  1640. * JB_ERR_MEMORY on out-of-memory error.
  1641. *
  1642. *********************************************************************/
  1643. jb_err cgi_robots_txt(struct client_state *csp,
  1644. struct http_response *rsp,
  1645. const struct map *parameters)
  1646. {
  1647. char buf[100];
  1648. jb_err err;
  1649. (void)csp;
  1650. (void)parameters;
  1651. rsp->body = strdup_or_die(
  1652. "# This is the Privoxy control interface.\n"
  1653. "# It isn't very useful to index it, and you're likely to break stuff.\n"
  1654. "# So go away!\n"
  1655. "\n"
  1656. "User-agent: *\n"
  1657. "Disallow: /\n"
  1658. "\n");
  1659. err = enlist_unique(rsp->headers, "Content-Type: text/plain", 13);
  1660. rsp->is_static = 1;
  1661. get_http_time(7 * 24 * 60 * 60, buf, sizeof(buf)); /* 7 days into future */
  1662. if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
  1663. return (err ? JB_ERR_MEMORY : JB_ERR_OK);
  1664. }
  1665. /*********************************************************************
  1666. *
  1667. * Function : show_defines
  1668. *
  1669. * Description : Add to a map the state of all conditional #defines
  1670. * used when building
  1671. *
  1672. * Parameters :
  1673. * 1 : exports = map to extend
  1674. *
  1675. * Returns : JB_ERR_OK on success
  1676. * JB_ERR_MEMORY on out-of-memory error.
  1677. *
  1678. *********************************************************************/
  1679. static jb_err show_defines(struct map *exports)
  1680. {
  1681. jb_err err = JB_ERR_OK;
  1682. int i;
  1683. struct feature {
  1684. const char name[31];
  1685. const unsigned char is_available;
  1686. };
  1687. static const struct feature features[] = {
  1688. {
  1689. "FEATURE_64_BIT_TIME_T",
  1690. #if (SIZEOF_TIME_T == 8)
  1691. 1,
  1692. #else
  1693. 0,
  1694. #endif
  1695. },
  1696. {
  1697. "FEATURE_ACCEPT_FILTER",
  1698. #ifdef FEATURE_ACCEPT_FILTER
  1699. 1,
  1700. #else
  1701. 0,
  1702. #endif
  1703. },
  1704. {
  1705. "FEATURE_ACL",
  1706. #ifdef FEATURE_ACL
  1707. 1,
  1708. #else
  1709. 0,
  1710. #endif
  1711. },
  1712. {
  1713. "FEATURE_BROTLI",
  1714. #ifdef FEATURE_BROTLI
  1715. 1,
  1716. #else
  1717. 0,
  1718. #endif
  1719. },
  1720. {
  1721. "FEATURE_CGI_EDIT_ACTIONS",
  1722. #ifdef FEATURE_CGI_EDIT_ACTIONS
  1723. 1,
  1724. #else
  1725. 0,
  1726. #endif
  1727. },
  1728. {
  1729. "FEATURE_CLIENT_TAGS",
  1730. #ifdef FEATURE_CLIENT_TAGS
  1731. 1,
  1732. #else
  1733. 0,
  1734. #endif
  1735. },
  1736. {
  1737. "FEATURE_COMPRESSION",
  1738. #ifdef FEATURE_COMPRESSION
  1739. 1,
  1740. #else
  1741. 0,
  1742. #endif
  1743. },
  1744. {
  1745. "FEATURE_CONNECTION_KEEP_ALIVE",
  1746. #ifdef FEATURE_CONNECTION_KEEP_ALIVE
  1747. 1,
  1748. #else
  1749. 0,
  1750. #endif
  1751. },
  1752. {
  1753. "FEATURE_CONNECTION_SHARING",
  1754. #ifdef FEATURE_CONNECTION_SHARING
  1755. 1,
  1756. #else
  1757. 0,
  1758. #endif
  1759. },
  1760. {
  1761. "FEATURE_EXTERNAL_FILTERS",
  1762. #ifdef FEATURE_EXTERNAL_FILTERS
  1763. 1,
  1764. #else
  1765. 0,
  1766. #endif
  1767. },
  1768. {
  1769. "FEATURE_FAST_REDIRECTS",
  1770. #ifdef FEATURE_FAST_REDIRECTS
  1771. 1,
  1772. #else
  1773. 0,
  1774. #endif
  1775. },
  1776. {
  1777. "FEATURE_FORCE_LOAD",
  1778. #ifdef FEATURE_FORCE_LOAD
  1779. 1,
  1780. #else
  1781. 0,
  1782. #endif
  1783. },
  1784. {
  1785. "FEATURE_GRACEFUL_TERMINATION",
  1786. #ifdef FEATURE_GRACEFUL_TERMINATION
  1787. 1,
  1788. #else
  1789. 0,
  1790. #endif
  1791. },
  1792. {
  1793. "FEATURE_HTTPS_INSPECTION",
  1794. #ifdef FEATURE_HTTPS_INSPECTION
  1795. 1,
  1796. #else
  1797. 0,
  1798. #endif
  1799. },
  1800. {
  1801. "FEATURE_IMAGE_BLOCKING",
  1802. #ifdef FEATURE_IMAGE_BLOCKING
  1803. 1,
  1804. #else
  1805. 0,
  1806. #endif
  1807. },
  1808. {
  1809. "FEATURE_IPV6_SUPPORT",
  1810. #ifdef HAVE_RFC2553
  1811. 1,
  1812. #else
  1813. 0,
  1814. #endif
  1815. },
  1816. {
  1817. "FEATURE_NO_GIFS",
  1818. #ifdef FEATURE_NO_GIFS
  1819. 1,
  1820. #else
  1821. 0,
  1822. #endif
  1823. },
  1824. {
  1825. "FEATURE_PTHREAD",
  1826. #ifdef FEATURE_PTHREAD
  1827. 1,
  1828. #else
  1829. 0,
  1830. #endif
  1831. },
  1832. {
  1833. "FEATURE_STATISTICS",
  1834. #ifdef FEATURE_STATISTICS
  1835. 1,
  1836. #else
  1837. 0,
  1838. #endif
  1839. },
  1840. {
  1841. "FEATURE_STRPTIME_SANITY_CHECKS",
  1842. #ifdef FEATURE_STRPTIME_SANITY_CHECKS
  1843. 1,
  1844. #else
  1845. 0,
  1846. #endif
  1847. },
  1848. {
  1849. "FEATURE_TOGGLE",
  1850. #ifdef FEATURE_TOGGLE
  1851. 1,
  1852. #else
  1853. 0,
  1854. #endif
  1855. },
  1856. {
  1857. "FEATURE_TRUST",
  1858. #ifdef FEATURE_TRUST
  1859. 1,
  1860. #else
  1861. 0,
  1862. #endif
  1863. },
  1864. {
  1865. "FEATURE_ZLIB",
  1866. #ifdef FEATURE_ZLIB
  1867. 1,
  1868. #else
  1869. 0,
  1870. #endif
  1871. },
  1872. {
  1873. "FEATURE_DYNAMIC_PCRE",
  1874. #ifdef FEATURE_DYNAMIC_PCRE
  1875. 1,
  1876. #else
  1877. 0,
  1878. #endif
  1879. }
  1880. };
  1881. for (i = 0; i < SZ(features); i++)
  1882. {
  1883. err = map_conditional(exports, features[i].name, features[i].is_available);
  1884. if (err)
  1885. {
  1886. break;
  1887. }
  1888. }
  1889. return err;
  1890. }
  1891. /*********************************************************************
  1892. *
  1893. * Function : cgi_show_file
  1894. *
  1895. * Description : CGI function that shows the content of a
  1896. * configuration file.
  1897. *
  1898. * Parameters :
  1899. * 1 : csp = Current client state (buffers, headers, etc...)
  1900. * 2 : rsp = http_response data structure for output
  1901. * 3 : parameters = map of cgi parameters
  1902. *
  1903. * CGI Parameters :
  1904. * file : Which file to show. Only first letter is checked,
  1905. * valid values are:
  1906. * - "a"ction file
  1907. * - "r"egex
  1908. * - "t"rust
  1909. * Default is to show menu and other information.
  1910. *
  1911. * Returns : JB_ERR_OK on success
  1912. * JB_ERR_MEMORY on out-of-memory error.
  1913. *
  1914. *********************************************************************/
  1915. static jb_err cgi_show_file(struct client_state *csp,
  1916. struct http_response *rsp,
  1917. const struct map *parameters)
  1918. {
  1919. unsigned i;
  1920. const char * filename = NULL;
  1921. char * file_description = NULL;
  1922. assert(csp);
  1923. assert(rsp);
  1924. assert(parameters);
  1925. switch (*(lookup(parameters, "file")))
  1926. {
  1927. case 'a':
  1928. if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->actions_list[i])
  1929. {
  1930. filename = csp->actions_list[i]->filename;
  1931. file_description = "Actions File";
  1932. }
  1933. break;
  1934. case 'f':
  1935. if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->rlist[i])
  1936. {
  1937. filename = csp->rlist[i]->filename;
  1938. file_description = "Filter File";
  1939. }
  1940. break;
  1941. #ifdef FEATURE_TRUST
  1942. case 't':
  1943. if (csp->tlist)
  1944. {
  1945. filename = csp->tlist->filename;
  1946. file_description = "Trust File";
  1947. }
  1948. break;
  1949. #endif /* def FEATURE_TRUST */
  1950. }
  1951. if (NULL != filename)
  1952. {
  1953. struct map *exports;
  1954. char *s;
  1955. jb_err err;
  1956. size_t length;
  1957. exports = default_exports(csp, "show-status");
  1958. if (NULL == exports)
  1959. {
  1960. return JB_ERR_MEMORY;
  1961. }
  1962. if (map(exports, "file-description", 1, file_description, 1)
  1963. || map(exports, "filepath", 1, html_encode(filename), 0))
  1964. {
  1965. free_map(exports);
  1966. return JB_ERR_MEMORY;
  1967. }
  1968. err = load_file(filename, &s, &length);
  1969. if (JB_ERR_OK != err)
  1970. {
  1971. if (map(exports, "contents", 1, "<h1>ERROR OPENING FILE!</h1>", 1))
  1972. {
  1973. free_map(exports);
  1974. return JB_ERR_MEMORY;
  1975. }
  1976. }
  1977. else
  1978. {
  1979. s = html_encode_and_free_original(s);
  1980. if (NULL == s)
  1981. {
  1982. free_map(exports);
  1983. return JB_ERR_MEMORY;
  1984. }
  1985. if (map(exports, "contents", 1, s, 0))
  1986. {
  1987. free_map(exports);
  1988. return JB_ERR_MEMORY;
  1989. }
  1990. }
  1991. return template_fill_for_cgi(csp, "show-status-file", exports, rsp);
  1992. }
  1993. return JB_ERR_CGI_PARAMS;
  1994. }
  1995. /*********************************************************************
  1996. *
  1997. * Function : load_file
  1998. *
  1999. * Description : Loads a file into a buffer.
  2000. *
  2001. * Parameters :
  2002. * 1 : filename = Name of the file to be loaded.
  2003. * 2 : buffer = Used to return the file's content.
  2004. * 3 : length = Used to return the size of the file.
  2005. *
  2006. * Returns : JB_ERR_OK in case of success,
  2007. * JB_ERR_FILE in case of ordinary file loading errors
  2008. * (fseek() and ftell() errors are fatal)
  2009. * JB_ERR_MEMORY in case of out-of-memory.
  2010. *
  2011. *********************************************************************/
  2012. static jb_err load_file(const char *filename, char **buffer, size_t *length)
  2013. {
  2014. FILE *fp;
  2015. long ret;
  2016. jb_err err = JB_ERR_OK;
  2017. fp = fopen(filename, "rb");
  2018. if (NULL == fp)
  2019. {
  2020. log_error(LOG_LEVEL_ERROR, "Failed to open %s: %E", filename);
  2021. return JB_ERR_FILE;
  2022. }
  2023. /* Get file length */
  2024. if (fseek(fp, 0, SEEK_END))
  2025. {
  2026. log_error(LOG_LEVEL_FATAL,
  2027. "Unexpected error while fseek()ing to the end of %s: %E",
  2028. filename);
  2029. }
  2030. ret = ftell(fp);
  2031. if (-1 == ret)
  2032. {
  2033. log_error(LOG_LEVEL_FATAL,
  2034. "Unexpected ftell() error while loading %s: %E",
  2035. filename);
  2036. }
  2037. *length = (size_t)ret;
  2038. /* Go back to the beginning. */
  2039. if (fseek(fp, 0, SEEK_SET))
  2040. {
  2041. log_error(LOG_LEVEL_FATAL,
  2042. "Unexpected error while fseek()ing to the beginning of %s: %E",
  2043. filename);
  2044. }
  2045. *buffer = zalloc_or_die(*length + 1);
  2046. if (1 != fread(*buffer, *length, 1, fp))
  2047. {
  2048. /*
  2049. * May theoretically happen if the file size changes between
  2050. * fseek() and fread() because it's edited in-place. Privoxy
  2051. * and common text editors don't do that, thus we just fail.
  2052. */
  2053. log_error(LOG_LEVEL_ERROR,
  2054. "Couldn't completely read file %s.", filename);
  2055. freez(*buffer);
  2056. err = JB_ERR_FILE;
  2057. }
  2058. fclose(fp);
  2059. return err;
  2060. }
  2061. /*
  2062. Local Variables:
  2063. tab-width: 3
  2064. end:
  2065. */