webadmin.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /*
  2. 3APA3A simpliest proxy server
  3. (c) 2002-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
  4. please read License Agreement
  5. */
  6. #include "proxy.h"
  7. #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
  8. #define LINESIZE 65536
  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; charset=utf-8\r\n"
  172. "Content-disposition: inline; filename=running.xml\r\n"
  173. "\r\n"
  174. "<?xml version=\"1.0\"?>\r\n"
  175. "<?xml-stylesheet href=\"/SX\" type=\"text/css\"?>\r\n"
  176. "<services>\r\n"
  177. "<description>Services currently running and connected clients</description>\r\n",
  178. "</services>\r\n",
  179. "HTTP/1.0 200 OK\r\n"
  180. "Connection: close\r\n"
  181. "Cache-Control: no-cache\r\n"
  182. "Content-type: text/css\r\n"
  183. "\r\n"
  184. "services {\r\n"
  185. " display: block;\r\n"
  186. " margin: 10px auto 10px auto;\r\n"
  187. " width: 80%;\r\n"
  188. " background: black;\r\n"
  189. " font-family: sans-serif;\r\n"
  190. " font-size: small;\r\n"
  191. " color: silver;\r\n"
  192. " }\r\n"
  193. "item {\r\n"
  194. " display: block;\r\n"
  195. " margin-bottom: 10px;\r\n"
  196. " border: 2px solid #CCC;\r\n"
  197. " padding: 10px;\r\n"
  198. " spacing: 2px;\r\n"
  199. " }\r\n"
  200. "parameter {\r\n"
  201. " display: block;\r\n"
  202. " padding: 2px;\r\n"
  203. " margin-top: 10px;\r\n"
  204. " border: 1px solid grey;\r\n"
  205. " background: #EEE;\r\n"
  206. " color: black;\r\n"
  207. " }\r\n"
  208. "name {\r\n"
  209. " display: inline;\r\n"
  210. " float: left;\r\n"
  211. " margin-right: 5px;\r\n"
  212. " font-weight: bold;\r\n"
  213. " }\r\n"
  214. "type {\r\n"
  215. " display: inline;\r\n"
  216. " font-size: x-small;\r\n"
  217. " margin-right: 5px;\r\n"
  218. " color: #666;\r\n"
  219. " white-space: nowrap;\r\n"
  220. " font-style: italic;\r\n"
  221. " }\r\n"
  222. "description {\r\n"
  223. " display: inline;\r\n"
  224. " margin-right: 5px;\r\n"
  225. " white-space: nowrap;\r\n"
  226. " }\r\n"
  227. "value {\r\n"
  228. " display: block;\r\n"
  229. " margin-right: 5px;\r\n"
  230. " }\r\n",
  231. "<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />\r\n"
  232. "<pre><font size=\'-2\'><b>"
  233. COPYRIGHT
  234. "</b></font>\r\n"
  235. "</td></tr></table></body></html>",
  236. "<h3>Counters</h3>\r\n"
  237. "<table border = \'1\'>\r\n"
  238. "<tr align=\'center\'><td>Description</td><td>Active</td>"
  239. "<td>Users</td><td>Source Address</td><td>Destination Address</td>"
  240. "<td>Port</td>"
  241. "<td>Limit</td><td>Units</td><td>Value</td>"
  242. "<td>Reset</td><td>Updated</td><td>Num</td></tr>\r\n",
  243. "</table>\r\n",
  244. NULL
  245. };
  246. #define authreq admin_stringtable[0]
  247. #define ok admin_stringtable[1]
  248. #define xml admin_stringtable[2]
  249. #define postxml admin_stringtable[3]
  250. #define style admin_stringtable[4]
  251. #define tail admin_stringtable[5]
  252. #define counters admin_stringtable[6]
  253. #define counterstail admin_stringtable[7]
  254. static int printportlist(char *buf, int bufsize, struct portlist* pl, char * delim){
  255. int printed = 0;
  256. for(; pl; pl = pl->next){
  257. if(printed > (bufsize - 64)) break;
  258. if(pl->startport != pl->endport)
  259. printed += sprintf(buf+printed, "%hu-%hu%s", pl->startport, pl->endport, pl->next?delim:"");
  260. else {
  261. /*
  262. struct servent *se=NULL;
  263. if(pl->startport)se = getservbyport((int)ntohs(pl->startport), NULL);
  264. printed += sprintf(buf+printed, "%hu(%s)%s", pl->startport, se?se->s_name:"unknown", pl->next?delim:"");
  265. */
  266. printed += sprintf(buf+printed, "%hu%s", pl->startport, pl->next?delim:"");
  267. }
  268. if(printed > (bufsize - 64)) {
  269. printed += sprintf(buf+printed, "...");
  270. break;
  271. }
  272. }
  273. return printed;
  274. }
  275. static int printuserlist(char *buf, int bufsize, struct userlist* ul, char * delim){
  276. int printed = 0;
  277. for(; ul; ul = ul->next){
  278. if(printed > (bufsize - 64)) break;
  279. printed += sprintf(buf+printed, "%s%s", ul->user, ul->next?delim:"");
  280. if(printed > (bufsize - 64)) {
  281. printed += sprintf(buf+printed, "...");
  282. break;
  283. }
  284. }
  285. return printed;
  286. }
  287. int printiple(char *buf, struct iplist* ipl);
  288. static int printiplist(char *buf, int bufsize, struct iplist* ipl, char * delim){
  289. int printed = 0;
  290. for(; ipl; ipl = ipl->next){
  291. if(printed > (bufsize - 128)) break;
  292. printed += printiple(buf+printed, ipl);
  293. if(printed > (bufsize - 128)) {
  294. printed += sprintf(buf+printed, "...");
  295. break;
  296. }
  297. }
  298. return printed;
  299. }
  300. void * adminchild(struct clientparam* param) {
  301. int i, res;
  302. char * buf;
  303. char username[256];
  304. char *sb;
  305. char *req = NULL;
  306. struct printparam pp;
  307. unsigned contentlen = 0;
  308. int isform = 0;
  309. int limited = 0;
  310. limited =param->srv->singlepacket;
  311. pp.inbuf = 0;
  312. pp.cp = param;
  313. buf = myalloc(LINESIZE);
  314. if(!buf) {RETURN(555);}
  315. i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S]);
  316. if(i<5 || ((buf[0]!='G' || buf[1]!='E' || buf[2]!='T' || buf[3]!=' ' || buf[4]!='/') &&
  317. (buf[0]!='P' || buf[1]!='O' || buf[2]!='S' || buf[3]!='T' || buf[4]!=' ' || buf[5]!='/')))
  318. {
  319. RETURN(701);
  320. }
  321. buf[i] = 0;
  322. sb = strchr(buf+5, ' ');
  323. if(!sb){
  324. RETURN(702);
  325. }
  326. *sb = 0;
  327. req = mystrdup(buf + ((*buf == 'P')? 6 : 5));
  328. while((i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S])) > 2){
  329. buf[i] = 0;
  330. if(i > 19 && (!strncasecmp(buf, "authorization", 13))){
  331. sb = strchr(buf, ':');
  332. if(!sb)continue;
  333. ++sb;
  334. while(isspace(*sb))sb++;
  335. if(!*sb || strncasecmp(sb, "basic", 5)){
  336. continue;
  337. }
  338. sb+=5;
  339. while(isspace(*sb))sb++;
  340. i = de64((unsigned char *)sb, (unsigned char *)username, 255);
  341. if(i<=0)continue;
  342. username[i] = 0;
  343. sb = strchr((char *)username, ':');
  344. if(sb){
  345. *sb = 0;
  346. if(param->password)myfree(param->password);
  347. param->password = (unsigned char *)mystrdup(sb+1);
  348. }
  349. if(param->username) myfree(param->username);
  350. param->username = (unsigned char *)mystrdup(username);
  351. continue;
  352. }
  353. else if(i > 15 && (!strncasecmp(buf, "content-length:", 15))){
  354. sb = buf + 15;
  355. while(isspace(*sb))sb++;
  356. sscanf(sb, "%u", &contentlen);
  357. if(contentlen > LINESIZE*1024) contentlen = 0;
  358. }
  359. else if(i > 13 && (!strncasecmp(buf, "content-type:", 13))){
  360. sb = buf + 13;
  361. while(isspace(*sb))sb++;
  362. if(!strncasecmp(sb, "x-www-form-urlencoded", 21)) isform = 1;
  363. }
  364. }
  365. param->operation = ADMIN;
  366. if(isform && contentlen) {
  367. printstr(&pp, "HTTP/1.0 100 Continue\r\n\r\n");
  368. stdpr(&pp, NULL, 0);
  369. }
  370. res = (*param->srv->authfunc)(param);
  371. if(res && res != 10) {
  372. printstr(&pp, authreq);
  373. RETURN(res);
  374. }
  375. if(limited || param->redirected){
  376. if(*req == 'C') req[1] = 0;
  377. else *req = 0;
  378. }
  379. 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]:"");
  380. if(*req != 'S') printstr(&pp, buf);
  381. switch(*req){
  382. case 'C':
  383. printstr(&pp, counters);
  384. {
  385. struct trafcount *cp;
  386. int num = 0;
  387. for(cp = conf.trafcounter; cp; cp = cp->next, num++){
  388. int inbuf = 0;
  389. if(cp->ace && (limited || param->redirected)){
  390. if(!ACLmatches(cp->ace, param))continue;
  391. }
  392. if(req[1] == 'S' && atoi(req+2) == num) cp->disabled=0;
  393. if(req[1] == 'D' && atoi(req+2) == num) cp->disabled=1;
  394. inbuf += sprintf(buf, "<tr>"
  395. "<td>%s</td><td><A HREF=\'/C%c%d\'>%s</A></td><td>",
  396. (cp->comment)?cp->comment:"&nbsp;",
  397. (cp->disabled)?'S':'D',
  398. num,
  399. (cp->disabled)?"NO":"YES"
  400. );
  401. if(!cp->ace || !cp->ace->users){
  402. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  403. }
  404. else {
  405. inbuf += printuserlist(buf+inbuf, LINESIZE-800, cp->ace->users, ",<br />\r\n");
  406. }
  407. inbuf += sprintf(buf+inbuf, "</td><td>");
  408. if(!cp->ace || !cp->ace->src){
  409. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  410. }
  411. else {
  412. inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->src, ",<br />\r\n");
  413. }
  414. inbuf += sprintf(buf+inbuf, "</td><td>");
  415. if(!cp->ace || !cp->ace->dst){
  416. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  417. }
  418. else {
  419. inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->dst, ",<br />\r\n");
  420. }
  421. inbuf += sprintf(buf+inbuf, "</td><td>");
  422. if(!cp->ace || !cp->ace->ports){
  423. inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
  424. }
  425. else {
  426. inbuf += printportlist(buf+inbuf, LINESIZE-128, cp->ace->ports, ",<br />\r\n");
  427. }
  428. if(cp->type == NONE) {
  429. inbuf += sprintf(buf+inbuf,
  430. "</td><td colspan=\'6\' align=\'center\'>exclude from limitation</td></tr>\r\n"
  431. );
  432. }
  433. else {
  434. inbuf += sprintf(buf+inbuf,
  435. "</td><td>%"PRINTF_INT64_MODIFIER"u</td>"
  436. "<td>MB%s</td>"
  437. "<td>%"PRINTF_INT64_MODIFIER"u.%"PRINTF_INT64_MODIFIER"u</td>"
  438. "<td>%s</td>",
  439. cp->traflim64 / (1024 * 1024),
  440. rotations[cp->type],
  441. cp->traf64 / (1024 * 1024),
  442. (((cp->traf64/16) *10) / (64*1024))%10,
  443. cp->cleared?ctime(&cp->cleared):"never"
  444. );
  445. inbuf += sprintf(buf + inbuf,
  446. "<td>%s</td>"
  447. "<td>%i</td>"
  448. "</tr>\r\n",
  449. cp->updated?ctime(&cp->updated):"never",
  450. cp->number
  451. );
  452. }
  453. printstr(&pp, buf);
  454. }
  455. }
  456. printstr(&pp, counterstail);
  457. break;
  458. case 'R':
  459. conf.needreload = 1;
  460. printstr(&pp, "<h3>Reload scheduled</h3>");
  461. break;
  462. case 'S':
  463. {
  464. if(req[1] == 'X'){
  465. printstr(&pp, style);
  466. break;
  467. }
  468. printstr(&pp, xml);
  469. printval(conf.services, TYPE_SERVER, 0, &pp);
  470. printstr(&pp, postxml);
  471. }
  472. break;
  473. case 'F':
  474. {
  475. FILE *fp;
  476. char buf[256];
  477. fp = confopen();
  478. if(!fp){
  479. printstr(&pp, "<h3><font color=\"red\">Failed to open config file</font></h3>");
  480. break;
  481. }
  482. printstr(&pp, "<h3>Please be careful editing config file remotely</h3>");
  483. printstr(&pp, "<form method=\"POST\" action=\"/U\" enctype=\"application/x-www-form-urlencoded\"><textarea cols=\"80\" rows=\"30\" name=\"conffile\">");
  484. while(fgets(buf, 256, fp)){
  485. printstr(&pp, buf);
  486. }
  487. if(!writable) fclose(fp);
  488. printstr(&pp, "</textarea><br><input type=\"Submit\"></form>");
  489. break;
  490. }
  491. case 'U':
  492. {
  493. unsigned l=0;
  494. int error = 0;
  495. if(!writable || !contentlen || fseek(writable, 0, 0)){
  496. error = 1;
  497. }
  498. while(l < contentlen && (i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, (contentlen - l) > LINESIZE - 1?LINESIZE - 1:contentlen - l, '+', conf.timeouts[STRING_S])) > 0){
  499. if(i > (contentlen - l)) i = (contentlen - l);
  500. if(!l){
  501. if(i<9 || strncasecmp(buf, "conffile=", 9)) error = 1;
  502. }
  503. if(!error){
  504. buf[i] = 0;
  505. decodeurl((unsigned char *)buf, 1);
  506. fprintf(writable, "%s", l? buf : buf + 9);
  507. }
  508. l += i;
  509. }
  510. if(writable && !error){
  511. fflush(writable);
  512. #ifndef _WINCE
  513. ftruncate(fileno(writable), ftell(writable));
  514. #endif
  515. }
  516. printstr(&pp, error? "<h3><font color=\"red\">Config file is not writable</font></h3>Make sure you have \"writable\" command in configuration file":
  517. "<h3>Configuration updated</h3>");
  518. }
  519. break;
  520. default:
  521. printstr(&pp, (char *)conf.stringtable[WEBBANNERS]);
  522. break;
  523. }
  524. if(*req != 'S') printstr(&pp, tail);
  525. CLEANRET:
  526. printstr(&pp, NULL);
  527. if(buf) myfree(buf);
  528. dolog(param, (unsigned char *)req);
  529. if(req)myfree(req);
  530. freeparam(param);
  531. return (NULL);
  532. }