Commit message: Fix: out-of-bounds write and few more bugs in 'admin' configuration upload
CVE: CVE-2019-14495
CWE: CWE-787
Vulnerability description: webadmin.c in 3proxy before 0.8.13 has an out-of-bounds write in the admin interface.

Project: 3proxy
File: webadmin.c

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;
}

Project: 3proxy
File: webadmin.c

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;
}

Project: 3proxy
File: webadmin.c

static void printstr(struct printparam* pp, char* str){
	stdpr(pp, str, str?(int)strlen(str):0);
}

Project: 3proxy
File: webadmin.c

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;
}

Project: 3proxy
File: webadmin.c

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>");
}

Project: 3proxy
File: webadmin.c

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, "&amp;", 5);
				break;
			case '<':
				if(delay){
					stdpr((struct printparam*)cb, buf+i-delay, delay);
					delay = 0;
				}
				stdpr((struct printparam*)cb, "&lt;", 4);
				break;
			case '>':
				if(delay){
					stdpr((struct printparam*)cb, buf+i-delay, delay);
					delay = 0;
				}
				stdpr((struct printparam*)cb, "&gt;", 4);
				break;
			default:
				delay++;
				break;
		}
	}
	if(delay){
		stdpr((struct printparam*)cb, buf+i-delay, delay);
	}
}

Project: 3proxy
File: webadmin.c

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;
	}
}