webadmin.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /*
  2. 3APA3A simpliest proxy server
  3. (c) 2002-2008 by ZARAZA <3APA3A@security.nnov.ru>
  4. please read License Agreement
  5. */
  6. #include "proxy.h"
  7. #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
  8. #define LINESIZE 2048
  9. extern FILE *writable;
  10. FILE * confopen();
  11. extern void decodeurl(unsigned char *s, int filter);
  12. struct printparam {
  13. char buf[1024];
  14. int inbuf;
  15. struct clientparam *cp;
  16. };
  17. static void stdpr(struct printparam* pp, char *buf, int inbuf){
  18. if((pp->inbuf + inbuf > 1024) || !buf) {
  19. socksend(pp->cp->clisock, (unsigned char *)pp->buf, pp->inbuf, conf.timeouts[STRING_S]);
  20. pp->inbuf = 0;
  21. if(!buf) return;
  22. }
  23. if(inbuf >= 1000){
  24. socksend(pp->cp->clisock, (unsigned char *)buf, inbuf, conf.timeouts[STRING_S]);
  25. }
  26. else {
  27. memcpy(pp->buf + pp->inbuf, buf, inbuf);
  28. pp->inbuf += inbuf;
  29. }
  30. }
  31. static void stdcbf(void *cb, char *buf, int inbuf){
  32. int delay = 0;
  33. int i;
  34. for(i = 0; i < inbuf; i++){
  35. switch(buf[i]){
  36. case '&':
  37. if(delay){
  38. stdpr((struct printparam*)cb, buf+i-delay, delay);
  39. delay = 0;
  40. }
  41. stdpr((struct printparam*)cb, "&amp;", 5);
  42. break;
  43. case '<':
  44. if(delay){
  45. stdpr((struct printparam*)cb, buf+i-delay, delay);
  46. delay = 0;
  47. }
  48. stdpr((struct printparam*)cb, "&lt;", 4);
  49. break;
  50. case '>':
  51. if(delay){
  52. stdpr((struct printparam*)cb, buf+i-delay, delay);
  53. delay = 0;
  54. }
  55. stdpr((struct printparam*)cb, "&gt;", 4);
  56. break;
  57. default:
  58. delay++;
  59. break;
  60. }
  61. }
  62. if(delay){
  63. stdpr((struct printparam*)cb, buf+i-delay, delay);
  64. }
  65. }
  66. /*
  67. static char * templateprint(struct printparam* pp, int *level, struct dictionary *dict, char * template){
  68. char *s, *s2;
  69. for(; template && *template; ){
  70. if(!( s = strchr(template, '<'))){
  71. stdpr(pp, template, (int)strlen(template));
  72. return template + strlen(template);
  73. }
  74. if(s[1] != '%' || s[2] == '%'){
  75. stdpr(pp, template, (int)(s - template) + 1);
  76. template = s + 1;
  77. continue;
  78. }
  79. if(s[2] == '/' && (s2 = strchr(s + 2, '>')) && *(s2 - 1) == '%'){
  80. if(--*level < 0) return NULL;
  81. return s2 + 1;
  82. }
  83. }
  84. return template;
  85. }
  86. */
  87. static void printstr(struct printparam* pp, char* str){
  88. stdpr(pp, str, str?(int)strlen(str):0);
  89. }
  90. static void printval(void *value, int type, int level, struct printparam* pp){
  91. struct node pn, cn;
  92. struct property *p;
  93. int i;
  94. pn.iteration = NULL;
  95. pn.parent = NULL;
  96. pn.type = type;
  97. pn.value = value;
  98. printstr(pp, "<item>");
  99. for(p = datatypes[type].properties; p; ) {
  100. cn.iteration = NULL;
  101. cn.parent = &pn;
  102. cn.type = p->type;
  103. cn.value = (*p->e_f)(&pn);
  104. if(cn.value){
  105. for(i = 0; i < level; i++) printstr(pp, "\t");
  106. if(strcmp(p->name, "next")){
  107. printstr(pp, "<parameter>");
  108. printstr(pp, "<name>");
  109. printstr(pp, p->name);
  110. printstr(pp, "</name>");
  111. printstr(pp, "<type>");
  112. printstr(pp, datatypes[p->type].type);
  113. printstr(pp, "</type>");
  114. printstr(pp, "<description>");
  115. printstr(pp, p->description);
  116. printstr(pp, "</description>");
  117. }
  118. if(datatypes[p->type].p_f){
  119. printstr(pp, "<value><![CDATA[");
  120. (*datatypes[p->type].p_f)(&cn, stdcbf, pp);
  121. printstr(pp, "]]></value>\n");
  122. printstr(pp, "</parameter>");
  123. }
  124. else {
  125. if(!strcmp(p->name, "next")){
  126. /* printstr(pp, "<!-- -------------------- -->\n"); */
  127. printstr(pp, "</item>\n<item>");
  128. p = datatypes[type].properties;
  129. pn.value = value = cn.value;
  130. continue;
  131. }
  132. else {
  133. printstr(pp, "\n");
  134. printval(cn.value, cn.type, level+1, pp);
  135. printstr(pp, "</parameter>");
  136. }
  137. }
  138. }
  139. p=p->next;
  140. }
  141. printstr(pp, "</item>");
  142. }
  143. char * admin_stringtable[]={
  144. "HTTP/1.0 401 Authentication Required\r\n"
  145. "WWW-Authenticate: Basic realm=\"proxy\"\r\n"
  146. "Connection: close\r\n"
  147. "Content-type: text/html; charset=us-ascii\r\n"
  148. "\r\n"
  149. "<html><head><title>401 Authentication Required</title></head>\r\n"
  150. "<body><h2>401 Authentication Required</h2><h3>Access to requested resource disallowed by administrator or you need valid username/password to use this resource</h3></body></html>\r\n",
  151. "HTTP/1.0 200 OK\r\n"
  152. "Connection: close\r\n"
  153. "Expires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
  154. "Cache-Control: no-cache\r\n"
  155. "Content-type: text/html\r\n"
  156. "\r\n"
  157. "<http><head><title>%s configuration page</title></head>\r\n"
  158. "<table width=\'100%%\' border=\'0\'>\r\n"
  159. "<tr><td width=\'150\' valign=\'top\'>\r\n"
  160. "<h2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
  161. "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</h2>\r\n"
  162. "<A HREF=\'/C'>Counters</A><br>\r\n"
  163. "<A HREF=\'/R'>Reload</A><br>\r\n"
  164. "<A HREF=\'/S'>Running Services</A><br>\r\n"
  165. "<A HREF=\'/F'>Config</A>\r\n"
  166. "</td><td>"
  167. "<h2>%s %s configuration</h2>",
  168. "HTTP/1.0 200 OK\r\n"
  169. "Connection: close\r\n"
  170. "Cache-Control: no-cache\r\n"
  171. "Content-type: text/xml\r\n"
  172. "\r\n"
  173. "<?xml version=\"1.0\"?>\r\n"
  174. "<?xml-stylesheet href=\"/SX\" type=\"text/css\"?>\r\n"
  175. "<services>\r\n"
  176. "<description>Services currently running and connected clients</description>\r\n",
  177. "</services>\r\n",
  178. "HTTP/1.0 200 OK\r\n"
  179. "Connection: close\r\n"
  180. "Cache-Control: no-cache\r\n"
  181. "Content-type: text/css\r\n"
  182. "\r\n"
  183. "services {\r\n"
  184. " display: block;\r\n"
  185. " margin: 10px auto 10px auto;\r\n"
  186. " width: 80%;\r\n"
  187. " background: black;\r\n"
  188. " font-family: sans-serif;\r\n"
  189. " font-size: small;\r\n"
  190. " color: silver;\r\n"
  191. " }\r\n"
  192. "item {\r\n"
  193. " display: block;\r\n"
  194. " margin-bottom: 10px;\r\n"
  195. " border: 2px solid #CCC;\r\n"
  196. " padding: 10px;\r\n"
  197. " spacing: 2px;\r\n"
  198. " }\r\n"
  199. "parameter {\r\n"
  200. " display: block;\r\n"
  201. " padding: 2px;\r\n"
  202. " margin-top: 10px;\r\n"
  203. " border: 1px solid grey;\r\n"
  204. " background: #EEE;\r\n"
  205. " color: black;\r\n"
  206. " }\r\n"
  207. "name {\r\n"
  208. " display: inline;\r\n"
  209. " float: left;\r\n"
  210. " margin-right: 5px;\r\n"
  211. " font-weight: bold;\r\n"
  212. " }\r\n"
  213. "type {\r\n"
  214. " display: inline;\r\n"
  215. " font-size: x-small;\r\n"
  216. " margin-right: 5px;\r\n"
  217. " color: #666;\r\n"
  218. " white-space: nowrap;\r\n"
  219. " font-style: italic;\r\n"
  220. " }\r\n"
  221. "description {\r\n"
  222. " display: inline;\r\n"
  223. " margin-right: 5px;\r\n"
  224. " white-space: nowrap;\r\n"
  225. " }\r\n"
  226. "value {\r\n"
  227. " display: block;\r\n"
  228. " margin-right: 5px;\r\n"
  229. " }\r\n",
  230. "<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />\r\n"
  231. "<pre><font size=\'-2\'><b>"
  232. COPYRIGHT
  233. "</b></font>\r\n"
  234. "</td></tr></table></body></html>",
  235. "<h3>Counters</h3>\r\n"
  236. "<table border = \'1\'>\r\n"
  237. "<tr align=\'center\'><td>Description</td><td>Active</td>"
  238. "<td>Users</td><td>Source Address</td><td>Destination Address</td>"
  239. "<td>Port</td>"
  240. "<td>Limit</td><td>Units</td><td>Value</td>"
  241. "<td>Reset</td><td>Updated</td><td>Num</td></tr>\r\n",
  242. "</table>\r\n",
  243. NULL
  244. };
  245. #define authreq admin_stringtable[0]
  246. #define ok admin_stringtable[1]
  247. #define xml admin_stringtable[2]
  248. #define postxml admin_stringtable[3]
  249. #define style admin_stringtable[4]
  250. #define tail admin_stringtable[5]
  251. #define counters admin_stringtable[6]
  252. #define counterstail admin_stringtable[7]
  253. static int printportlist(char *buf, int bufsize, struct portlist* pl, char * delim){
  254. int printed = 0;
  255. for(; pl; pl = pl->next){
  256. if(printed > (bufsize - 64)) break;
  257. if(pl->startport != pl->endport)
  258. printed += sprintf(buf+printed, "%hu-%hu%s", pl->startport, pl->endport, pl->next?delim:"");
  259. else {
  260. /*
  261. struct servent *se=NULL;
  262. if(pl->startport)se = getservbyport((int)ntohs(pl->startport), NULL);
  263. printed += sprintf(buf+printed, "%hu(%s)%s", pl->startport, se?se->s_name:"unknown", pl->next?delim:"");
  264. */
  265. printed += sprintf(buf+printed, "%hu%s", pl->startport, pl->next?delim:"");
  266. }
  267. if(printed > (bufsize - 64)) {
  268. printed += sprintf(buf+printed, "...");
  269. break;
  270. }
  271. }
  272. return printed;
  273. }
  274. static int printuserlist(char *buf, int bufsize, struct userlist* ul, char * delim){
  275. int printed = 0;
  276. for(; ul; ul = ul->next){
  277. if(printed > (bufsize - 64)) break;
  278. printed += sprintf(buf+printed, "%s%s", ul->user, ul->next?delim:"");
  279. if(printed > (bufsize - 64)) {
  280. printed += sprintf(buf+printed, "...");
  281. break;
  282. }
  283. }
  284. return printed;
  285. }
  286. int printiple(char *buf, struct iplist* ipl);
  287. static int printiplist(char *buf, int bufsize, struct iplist* ipl, char * delim){
  288. int printed = 0;
  289. for(; ipl; ipl = ipl->next){
  290. if(printed > (bufsize - 128)) break;
  291. printed += printiple(buf+printed, ipl);
  292. if(printed > (bufsize - 128)) {
  293. printed += sprintf(buf+printed, "...");
  294. break;
  295. }
  296. }
  297. return printed;
  298. }
  299. void * adminchild(struct clientparam* param) {
  300. int i, res;
  301. char * buf;
  302. char username[256];
  303. char *sb;
  304. char *req = NULL;
  305. struct printparam pp;
  306. int contentlen = 0;
  307. int isform = 0;
  308. pp.inbuf = 0;
  309. pp.cp = param;
  310. buf = myalloc(LINESIZE);
  311. if(!buf) {RETURN(555);}
  312. i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S]);
  313. if(i<5 || ((buf[0]!='G' || buf[1]!='E' || buf[2]!='T' || buf[3]!=' ' || buf[4]!='/') &&
  314. (buf[0]!='P' || buf[1]!='O' || buf[2]!='S' || buf[3]!='T' || buf[4]!=' ' || buf[5]!='/')))
  315. {
  316. RETURN(701);
  317. }
  318. buf[i] = 0;
  319. sb = strchr(buf+5, ' ');
  320. if(!sb){
  321. RETURN(702);
  322. }
  323. *sb = 0;
  324. req = mystrdup(buf + ((*buf == 'P')? 6 : 5));
  325. while((i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S])) > 2){
  326. buf[i] = 0;
  327. if(i > 19 && (!strncasecmp(buf, "authorization", 13))){
  328. sb = strchr(buf, ':');
  329. if(!sb)continue;
  330. ++sb;
  331. while(isspace(*sb))sb++;
  332. if(!*sb || strncasecmp(sb, "basic", 5)){
  333. continue;
  334. }
  335. sb+=5;
  336. while(isspace(*sb))sb++;
  337. i = de64((unsigned char *)sb, (unsigned char *)username, 255);
  338. if(i<=0)continue;
  339. username[i] = 0;
  340. sb = strchr((char *)username, ':');
  341. if(sb){
  342. *sb = 0;
  343. if(param->password)myfree(param->password);
  344. param->password = (unsigned char *)mystrdup(sb+1);
  345. }
  346. if(param->username) myfree(param->username);
  347. param->username = (unsigned char *)mystrdup(username);
  348. continue;
  349. }
  350. else if(i > 15 && (!strncasecmp(buf, "content-length:", 15))){
  351. sb = buf + 15;
  352. while(isspace(*sb))sb++;
  353. contentlen = atoi(sb);
  354. }
  355. else if(i > 13 && (!strncasecmp(buf, "content-type:", 13))){
  356. sb = buf + 13;
  357. while(isspace(*sb))sb++;
  358. if(!strncasecmp(sb, "x-www-form-urlencoded", 21)) isform = 1;
  359. }
  360. }
  361. param->operation = ADMIN;
  362. if(isform && contentlen) {
  363. printstr(&pp, "HTTP/1.0 100 Continue\r\n\r\n");
  364. stdpr(&pp, NULL, 0);
  365. }
  366. res = (*param->srv->authfunc)(param);
  367. if(res && res != 10) {
  368. printstr(&pp, authreq);
  369. RETURN(res);
  370. }
  371. if(param->srv->singlepacket || param->redirected){
  372. if(*req == 'C') req[1] = 0;
  373. else *req = 0;
  374. }
  375. sprintf(buf, ok, conf.stringtable?(char *)conf.stringtable[2]:"3proxy", conf.stringtable?(char *)conf.stringtable[2]:"3[APA3A] tiny proxy", conf.stringtable?(char *)conf.stringtable[3]:"");
  376. if(*req != 'S') printstr(&pp, buf);
  377. switch(*req){
  378. case 'C':
  379. printstr(&pp, counters);
  380. {
  381. struct trafcount *cp;
  382. int num = 0;
  383. for(cp = conf.trafcounter; cp; cp = cp->next, num++){
  384. int inbuf = 0;
  385. if(cp->ace && (param->srv->singlepacket || param->redirected)){
  386. if(!ACLmatches(cp->ace, param))continue;
  387. }
  388. if(req[1] == 'S' && atoi(req+2) == num) cp->disabled=0;
  389. if(req[1] == 'D' && atoi(req+2) == num) cp->disabled=1;
  390. inbuf += sprintf(buf, "<tr>"
  391. "<td>%s</td><td><A HREF=\'/C%c%d\'>%s</A></td><td>",
  392. (cp->comment)?cp->comment:"&nbsp;",
  393. (cp->disabled)?'S':'D',
  394. num,
  395. (cp->disabled)?"NO":"YES"
  396. );
  397. if(!cp->ace || !cp->ace->users){
  398. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  399. }
  400. else {
  401. inbuf += printuserlist(buf+inbuf, LINESIZE-800, cp->ace->users, ",<br />\r\n");
  402. }
  403. inbuf += sprintf(buf+inbuf, "</td><td>");
  404. if(!cp->ace || !cp->ace->src){
  405. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  406. }
  407. else {
  408. inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->src, ",<br />\r\n");
  409. }
  410. inbuf += sprintf(buf+inbuf, "</td><td>");
  411. if(!cp->ace || !cp->ace->dst){
  412. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  413. }
  414. else {
  415. inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->dst, ",<br />\r\n");
  416. }
  417. inbuf += sprintf(buf+inbuf, "</td><td>");
  418. if(!cp->ace || !cp->ace->ports){
  419. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  420. }
  421. else {
  422. inbuf += printportlist(buf+inbuf, LINESIZE-128, cp->ace->ports, ",<br />\r\n");
  423. }
  424. if(cp->type == NONE) {
  425. inbuf += sprintf(buf+inbuf,
  426. "</td><td colspan=\'6\' align=\'center\'>exclude from limitation</td></tr>\r\n"
  427. );
  428. }
  429. else {
  430. inbuf += sprintf(buf+inbuf,
  431. "</td><td>%"PRINTF_INT64_MODIFIER"u</td>"
  432. "<td>MB%s</td>"
  433. "<td>%"PRINTF_INT64_MODIFIER"u</td>"
  434. "<td>%s</td>",
  435. cp->traflim64,
  436. rotations[cp->type],
  437. cp->traf64,
  438. cp->cleared?ctime(&cp->cleared):"never"
  439. );
  440. inbuf += sprintf(buf + inbuf,
  441. "<td>%s</td>"
  442. "<td>%i</td>"
  443. "</tr>\r\n",
  444. cp->updated?ctime(&cp->updated):"never",
  445. cp->number
  446. );
  447. }
  448. printstr(&pp, buf);
  449. }
  450. }
  451. printstr(&pp, counterstail);
  452. break;
  453. case 'R':
  454. conf.needreload = 1;
  455. printstr(&pp, "<h3>Reload scheduled</h3>");
  456. break;
  457. case 'S':
  458. {
  459. if(req[1] == 'X'){
  460. printstr(&pp, style);
  461. break;
  462. }
  463. printstr(&pp, xml);
  464. printval(conf.services, TYPE_SERVER, 0, &pp);
  465. printstr(&pp, postxml);
  466. }
  467. break;
  468. case 'F':
  469. {
  470. FILE *fp;
  471. char buf[256];
  472. fp = confopen();
  473. if(!fp){
  474. printstr(&pp, "<h3><font color=\"red\">Failed to open config file</font></h3>");
  475. break;
  476. }
  477. printstr(&pp, "<h3>Please be careful editing config file remotely</h3>");
  478. printstr(&pp, "<form method=\"POST\" action=\"/U\"><textarea cols=\"80\" rows=\"30\" name=\"conffile\">");
  479. while(fgets(buf, 256, fp)){
  480. printstr(&pp, buf);
  481. }
  482. if(!writable) fclose(fp);
  483. printstr(&pp, "</textarea><br><input type=\"Submit\"></form>");
  484. break;
  485. }
  486. case 'U':
  487. {
  488. int l=0;
  489. int error = 0;
  490. if(!writable || fseek(writable, 0, 0)){
  491. error = 1;
  492. }
  493. while((i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '+', conf.timeouts[STRING_S])) > 0){
  494. if(i > (contentlen - l)) i = (contentlen - l);
  495. buf[i] = 0;
  496. if(!l){
  497. if(strncasecmp(buf, "conffile=", 9)) error = 1;
  498. }
  499. if(!error){
  500. decodeurl((unsigned char *)buf, 1);
  501. fprintf(writable, "%s", l? buf : buf + 9);
  502. }
  503. l += i;
  504. if(l >= contentlen) break;
  505. }
  506. if(writable && !error){
  507. fflush(writable);
  508. #ifndef _WINCE
  509. ftruncate(fileno(writable), ftell(writable));
  510. #endif
  511. }
  512. printstr(&pp, error? "<h3><font color=\"red\">Config file is not writable</font></h3>Make sure you have \"writable\" command in configuration file":
  513. "<h3>Configuration updated</h3>");
  514. }
  515. break;
  516. default:
  517. printstr(&pp, (char *)conf.stringtable[WEBBANNERS]);
  518. break;
  519. }
  520. if(*req != 'S') printstr(&pp, tail);
  521. CLEANRET:
  522. printstr(&pp, NULL);
  523. if(buf) myfree(buf);
  524. (*param->srv->logfunc)(param, (unsigned char *)req);
  525. if(req)myfree(req);
  526. freeparam(param);
  527. return (NULL);
  528. }