| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- /*
- 3APA3A simpliest proxy server
- (c) 2002-2008 by ZARAZA <3APA3A@security.nnov.ru>
- please read License Agreement
- */
- #include "proxy.h"
- #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
- #define LINESIZE 2048
- extern FILE *writable;
- FILE * confopen();
- extern void decodeurl(unsigned char *s, int filter);
- struct printparam {
- char buf[1024];
- int inbuf;
- struct clientparam *cp;
- };
- static void stdpr(struct printparam* pp, char *buf, int inbuf){
- if((pp->inbuf + inbuf > 1024) || !buf) {
- socksend(pp->cp->clisock, (unsigned char *)pp->buf, pp->inbuf, conf.timeouts[STRING_S]);
- pp->inbuf = 0;
- if(!buf) return;
- }
- if(inbuf >= 1000){
- socksend(pp->cp->clisock, (unsigned char *)buf, inbuf, conf.timeouts[STRING_S]);
- }
- else {
- memcpy(pp->buf + pp->inbuf, buf, inbuf);
- pp->inbuf += inbuf;
- }
- }
- static void stdcbf(void *cb, char *buf, int inbuf){
- int delay = 0;
- int i;
- for(i = 0; i < inbuf; i++){
- switch(buf[i]){
- case '&':
- if(delay){
- stdpr((struct printparam*)cb, buf+i-delay, delay);
- delay = 0;
- }
- stdpr((struct printparam*)cb, "&", 5);
- break;
- case '<':
- if(delay){
- stdpr((struct printparam*)cb, buf+i-delay, delay);
- delay = 0;
- }
- stdpr((struct printparam*)cb, "<", 4);
- break;
- case '>':
- if(delay){
- stdpr((struct printparam*)cb, buf+i-delay, delay);
- delay = 0;
- }
- stdpr((struct printparam*)cb, ">", 4);
- break;
- default:
- delay++;
- break;
- }
- }
- if(delay){
- stdpr((struct printparam*)cb, buf+i-delay, delay);
- }
- }
- /*
- static char * templateprint(struct printparam* pp, int *level, struct dictionary *dict, char * template){
- char *s, *s2;
- for(; template && *template; ){
- if(!( s = strchr(template, '<'))){
- stdpr(pp, template, (int)strlen(template));
- return template + strlen(template);
- }
- if(s[1] != '%' || s[2] == '%'){
- stdpr(pp, template, (int)(s - template) + 1);
- template = s + 1;
- continue;
- }
- if(s[2] == '/' && (s2 = strchr(s + 2, '>')) && *(s2 - 1) == '%'){
- if(--*level < 0) return NULL;
- return s2 + 1;
- }
- }
- return template;
- }
- */
- static void printstr(struct printparam* pp, char* str){
- stdpr(pp, str, str?(int)strlen(str):0);
- }
- static void printval(void *value, int type, int level, struct printparam* pp){
- struct node pn, cn;
- struct property *p;
- int i;
- pn.iteration = NULL;
- pn.parent = NULL;
- pn.type = type;
- pn.value = value;
- printstr(pp, "<item>");
- for(p = datatypes[type].properties; p; ) {
- cn.iteration = NULL;
- cn.parent = &pn;
- cn.type = p->type;
- cn.value = (*p->e_f)(&pn);
- if(cn.value){
- for(i = 0; i < level; i++) printstr(pp, "\t");
- if(strcmp(p->name, "next")){
- printstr(pp, "<parameter>");
- printstr(pp, "<name>");
- printstr(pp, p->name);
- printstr(pp, "</name>");
- printstr(pp, "<type>");
- printstr(pp, datatypes[p->type].type);
- printstr(pp, "</type>");
- printstr(pp, "<description>");
- printstr(pp, p->description);
- printstr(pp, "</description>");
- }
- if(datatypes[p->type].p_f){
- printstr(pp, "<value><![CDATA[");
- (*datatypes[p->type].p_f)(&cn, stdcbf, pp);
- printstr(pp, "]]></value>\n");
- printstr(pp, "</parameter>");
- }
- else {
- if(!strcmp(p->name, "next")){
- /* printstr(pp, "<!-- -------------------- -->\n"); */
- printstr(pp, "</item>\n<item>");
- p = datatypes[type].properties;
- pn.value = value = cn.value;
- continue;
- }
- else {
- printstr(pp, "\n");
- printval(cn.value, cn.type, level+1, pp);
- printstr(pp, "</parameter>");
- }
- }
- }
- p=p->next;
- }
- printstr(pp, "</item>");
- }
- char * admin_stringtable[]={
- "HTTP/1.0 401 Authentication Required\r\n"
- "WWW-Authenticate: Basic realm=\"proxy\"\r\n"
- "Connection: close\r\n"
- "Content-type: text/html; charset=us-ascii\r\n"
- "\r\n"
- "<html><head><title>401 Authentication Required</title></head>\r\n"
- "<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",
- "HTTP/1.0 200 OK\r\n"
- "Connection: close\r\n"
- "Expires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
- "Cache-Control: no-cache\r\n"
- "Content-type: text/html\r\n"
- "\r\n"
- "<http><head><title>%s configuration page</title></head>\r\n"
- "<table width=\'100%%\' border=\'0\'>\r\n"
- "<tr><td width=\'150\' valign=\'top\'>\r\n"
- "<h2> "
- " </h2>\r\n"
- "<A HREF=\'/C'>Counters</A><br>\r\n"
- "<A HREF=\'/R'>Reload</A><br>\r\n"
- "<A HREF=\'/S'>Running Services</A><br>\r\n"
- "<A HREF=\'/F'>Config</A>\r\n"
- "</td><td>"
- "<h2>%s %s configuration</h2>",
- "HTTP/1.0 200 OK\r\n"
- "Connection: close\r\n"
- "Cache-Control: no-cache\r\n"
- "Content-type: text/xml\r\n"
- "\r\n"
- "<?xml version=\"1.0\"?>\r\n"
- "<?xml-stylesheet href=\"/SX\" type=\"text/css\"?>\r\n"
- "<services>\r\n"
- "<description>Services currently running and connected clients</description>\r\n",
- "</services>\r\n",
- "HTTP/1.0 200 OK\r\n"
- "Connection: close\r\n"
- "Cache-Control: no-cache\r\n"
- "Content-type: text/css\r\n"
- "\r\n"
- "services {\r\n"
- " display: block;\r\n"
- " margin: 10px auto 10px auto;\r\n"
- " width: 80%;\r\n"
- " background: black;\r\n"
- " font-family: sans-serif;\r\n"
- " font-size: small;\r\n"
- " color: silver;\r\n"
- " }\r\n"
- "item {\r\n"
- " display: block;\r\n"
- " margin-bottom: 10px;\r\n"
- " border: 2px solid #CCC;\r\n"
- " padding: 10px;\r\n"
- " spacing: 2px;\r\n"
- " }\r\n"
- "parameter {\r\n"
- " display: block;\r\n"
- " padding: 2px;\r\n"
- " margin-top: 10px;\r\n"
- " border: 1px solid grey;\r\n"
- " background: #EEE;\r\n"
- " color: black;\r\n"
- " }\r\n"
- "name {\r\n"
- " display: inline;\r\n"
- " float: left;\r\n"
- " margin-right: 5px;\r\n"
- " font-weight: bold;\r\n"
- " }\r\n"
- "type {\r\n"
- " display: inline;\r\n"
- " font-size: x-small;\r\n"
- " margin-right: 5px;\r\n"
- " color: #666;\r\n"
- " white-space: nowrap;\r\n"
- " font-style: italic;\r\n"
- " }\r\n"
- "description {\r\n"
- " display: inline;\r\n"
- " margin-right: 5px;\r\n"
- " white-space: nowrap;\r\n"
- " }\r\n"
- "value {\r\n"
- " display: block;\r\n"
- " margin-right: 5px;\r\n"
- " }\r\n",
- "<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />\r\n"
- "<pre><font size=\'-2\'><b>"
- COPYRIGHT
- "</b></font>\r\n"
- "</td></tr></table></body></html>",
- "<h3>Counters</h3>\r\n"
- "<table border = \'1\'>\r\n"
- "<tr align=\'center\'><td>Description</td><td>Active</td>"
- "<td>Users</td><td>Source Address</td><td>Destination Address</td>"
- "<td>Port</td>"
- "<td>Limit</td><td>Units</td><td>Value</td>"
- "<td>Reset</td><td>Updated</td><td>Num</td></tr>\r\n",
- "</table>\r\n",
- NULL
- };
- #define authreq admin_stringtable[0]
- #define ok admin_stringtable[1]
- #define xml admin_stringtable[2]
- #define postxml admin_stringtable[3]
- #define style admin_stringtable[4]
- #define tail admin_stringtable[5]
- #define counters admin_stringtable[6]
- #define counterstail admin_stringtable[7]
- static int printportlist(char *buf, int bufsize, struct portlist* pl, char * delim){
- int printed = 0;
- for(; pl; pl = pl->next){
- if(printed > (bufsize - 64)) break;
- if(pl->startport != pl->endport)
- printed += sprintf(buf+printed, "%hu-%hu%s", pl->startport, pl->endport, pl->next?delim:"");
- else {
- /*
- struct servent *se=NULL;
- if(pl->startport)se = getservbyport((int)ntohs(pl->startport), NULL);
- printed += sprintf(buf+printed, "%hu(%s)%s", pl->startport, se?se->s_name:"unknown", pl->next?delim:"");
- */
- printed += sprintf(buf+printed, "%hu%s", pl->startport, pl->next?delim:"");
- }
- if(printed > (bufsize - 64)) {
- printed += sprintf(buf+printed, "...");
- break;
- }
- }
- return printed;
- }
- static int printuserlist(char *buf, int bufsize, struct userlist* ul, char * delim){
- int printed = 0;
- for(; ul; ul = ul->next){
- if(printed > (bufsize - 64)) break;
- printed += sprintf(buf+printed, "%s%s", ul->user, ul->next?delim:"");
- if(printed > (bufsize - 64)) {
- printed += sprintf(buf+printed, "...");
- break;
- }
- }
- return printed;
- }
- int printiple(char *buf, struct iplist* ipl);
- static int printiplist(char *buf, int bufsize, struct iplist* ipl, char * delim){
- int printed = 0;
- for(; ipl; ipl = ipl->next){
- if(printed > (bufsize - 128)) break;
- printed += printiple(buf+printed, ipl);
- if(printed > (bufsize - 128)) {
- printed += sprintf(buf+printed, "...");
- break;
- }
- }
- return printed;
- }
- void * adminchild(struct clientparam* param) {
- int i, res;
- char * buf;
- char username[256];
- char *sb;
- char *req = NULL;
- struct printparam pp;
- int contentlen = 0;
- int isform = 0;
- pp.inbuf = 0;
- pp.cp = param;
- buf = myalloc(LINESIZE);
- if(!buf) {RETURN(555);}
- i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S]);
- if(i<5 || ((buf[0]!='G' || buf[1]!='E' || buf[2]!='T' || buf[3]!=' ' || buf[4]!='/') &&
- (buf[0]!='P' || buf[1]!='O' || buf[2]!='S' || buf[3]!='T' || buf[4]!=' ' || buf[5]!='/')))
- {
- RETURN(701);
- }
- buf[i] = 0;
- sb = strchr(buf+5, ' ');
- if(!sb){
- RETURN(702);
- }
- *sb = 0;
- req = mystrdup(buf + ((*buf == 'P')? 6 : 5));
- while((i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S])) > 2){
- buf[i] = 0;
- if(i > 19 && (!strncasecmp(buf, "authorization", 13))){
- sb = strchr(buf, ':');
- if(!sb)continue;
- ++sb;
- while(isspace(*sb))sb++;
- if(!*sb || strncasecmp(sb, "basic", 5)){
- continue;
- }
- sb+=5;
- while(isspace(*sb))sb++;
- i = de64((unsigned char *)sb, (unsigned char *)username, 255);
- if(i<=0)continue;
- username[i] = 0;
- sb = strchr((char *)username, ':');
- if(sb){
- *sb = 0;
- if(param->password)myfree(param->password);
- param->password = (unsigned char *)mystrdup(sb+1);
- }
- if(param->username) myfree(param->username);
- param->username = (unsigned char *)mystrdup(username);
- continue;
- }
- else if(i > 15 && (!strncasecmp(buf, "content-length:", 15))){
- sb = buf + 15;
- while(isspace(*sb))sb++;
- contentlen = atoi(sb);
- }
- else if(i > 13 && (!strncasecmp(buf, "content-type:", 13))){
- sb = buf + 13;
- while(isspace(*sb))sb++;
- if(!strncasecmp(sb, "x-www-form-urlencoded", 21)) isform = 1;
- }
- }
- param->operation = ADMIN;
- if(isform && contentlen) {
- printstr(&pp, "HTTP/1.0 100 Continue\r\n\r\n");
- stdpr(&pp, NULL, 0);
- }
- res = (*param->srv->authfunc)(param);
- if(res && res != 10) {
- printstr(&pp, authreq);
- RETURN(res);
- }
- if(param->srv->singlepacket || param->redirected){
- if(*req == 'C') req[1] = 0;
- else *req = 0;
- }
- 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]:"");
- if(*req != 'S') printstr(&pp, buf);
- switch(*req){
- case 'C':
- printstr(&pp, counters);
- {
- struct trafcount *cp;
- int num = 0;
- for(cp = conf.trafcounter; cp; cp = cp->next, num++){
- int inbuf = 0;
- if(cp->ace && (param->srv->singlepacket || param->redirected)){
- if(!ACLmatches(cp->ace, param))continue;
- }
- if(req[1] == 'S' && atoi(req+2) == num) cp->disabled=0;
- if(req[1] == 'D' && atoi(req+2) == num) cp->disabled=1;
- inbuf += sprintf(buf, "<tr>"
- "<td>%s</td><td><A HREF=\'/C%c%d\'>%s</A></td><td>",
- (cp->comment)?cp->comment:" ",
- (cp->disabled)?'S':'D',
- num,
- (cp->disabled)?"NO":"YES"
- );
- if(!cp->ace || !cp->ace->users){
- inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
- }
- else {
- inbuf += printuserlist(buf+inbuf, LINESIZE-800, cp->ace->users, ",<br />\r\n");
- }
- inbuf += sprintf(buf+inbuf, "</td><td>");
- if(!cp->ace || !cp->ace->src){
- inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
- }
- else {
- inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->src, ",<br />\r\n");
- }
- inbuf += sprintf(buf+inbuf, "</td><td>");
- if(!cp->ace || !cp->ace->dst){
- inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
- }
- else {
- inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->dst, ",<br />\r\n");
- }
- inbuf += sprintf(buf+inbuf, "</td><td>");
- if(!cp->ace || !cp->ace->ports){
- inbuf += sprintf(buf+inbuf, "<center>ANY</center>");
- }
- else {
- inbuf += printportlist(buf+inbuf, LINESIZE-128, cp->ace->ports, ",<br />\r\n");
- }
- if(cp->type == NONE) {
- inbuf += sprintf(buf+inbuf,
- "</td><td colspan=\'6\' align=\'center\'>exclude from limitation</td></tr>\r\n"
- );
- }
- else {
- inbuf += sprintf(buf+inbuf,
- "</td><td>%"PRINTF_INT64_MODIFIER"u</td>"
- "<td>MB%s</td>"
- "<td>%"PRINTF_INT64_MODIFIER"u</td>"
- "<td>%s</td>",
- cp->traflim64,
- rotations[cp->type],
- cp->traf64,
- cp->cleared?ctime(&cp->cleared):"never"
- );
- inbuf += sprintf(buf + inbuf,
- "<td>%s</td>"
- "<td>%i</td>"
- "</tr>\r\n",
- cp->updated?ctime(&cp->updated):"never",
- cp->number
- );
- }
- printstr(&pp, buf);
- }
- }
- printstr(&pp, counterstail);
- break;
-
- case 'R':
- conf.needreload = 1;
- printstr(&pp, "<h3>Reload scheduled</h3>");
- break;
- case 'S':
- {
- if(req[1] == 'X'){
- printstr(&pp, style);
- break;
- }
- printstr(&pp, xml);
- printval(conf.services, TYPE_SERVER, 0, &pp);
- printstr(&pp, postxml);
- }
- break;
- case 'F':
- {
- FILE *fp;
- char buf[256];
- fp = confopen();
- if(!fp){
- printstr(&pp, "<h3><font color=\"red\">Failed to open config file</font></h3>");
- break;
- }
- printstr(&pp, "<h3>Please be careful editing config file remotely</h3>");
- printstr(&pp, "<form method=\"POST\" action=\"/U\"><textarea cols=\"80\" rows=\"30\" name=\"conffile\">");
- while(fgets(buf, 256, fp)){
- printstr(&pp, buf);
- }
- if(!writable) fclose(fp);
- printstr(&pp, "</textarea><br><input type=\"Submit\"></form>");
- break;
- }
- case 'U':
- {
- int l=0;
- int error = 0;
- if(!writable || fseek(writable, 0, 0)){
- error = 1;
- }
- while((i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '+', conf.timeouts[STRING_S])) > 0){
- if(i > (contentlen - l)) i = (contentlen - l);
- buf[i] = 0;
- if(!l){
- if(strncasecmp(buf, "conffile=", 9)) error = 1;
- }
- if(!error){
- decodeurl((unsigned char *)buf, 1);
- fprintf(writable, "%s", l? buf : buf + 9);
- }
- l += i;
- if(l >= contentlen) break;
- }
- if(writable && !error){
- fflush(writable);
- #ifndef _WINCE
- ftruncate(fileno(writable), ftell(writable));
- #endif
- }
- printstr(&pp, error? "<h3><font color=\"red\">Config file is not writable</font></h3>Make sure you have \"writable\" command in configuration file":
- "<h3>Configuration updated</h3>");
- }
- break;
- default:
- printstr(&pp, (char *)conf.stringtable[WEBBANNERS]);
- break;
- }
- if(*req != 'S') printstr(&pp, tail);
- CLEANRET:
- printstr(&pp, NULL);
- if(buf) myfree(buf);
- (*param->srv->logfunc)(param, (unsigned char *)req);
- if(req)myfree(req);
- freeparam(param);
- return (NULL);
- }
|