2014-04-08 17:03:21 +08:00
|
|
|
/*
|
2021-07-02 16:50:33 +08:00
|
|
|
(c) 2002-2021 by Vladimir Dubrovin <3proxy@3proxy.org>
|
2016-12-20 20:47:02 +08:00
|
|
|
|
|
|
|
please read License Agreement
|
|
|
|
|
2014-04-08 17:03:21 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "proxy.h"
|
|
|
|
|
|
|
|
|
|
|
|
int ftplogin(struct clientparam *param, char *nbuf, int *innbuf) {
|
2016-03-10 22:05:56 +08:00
|
|
|
char tbuf[256];
|
2014-04-08 17:03:21 +08:00
|
|
|
int i;
|
|
|
|
char *buf;
|
|
|
|
int len;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
buf = nbuf?nbuf:tbuf;
|
2016-03-10 22:05:56 +08:00
|
|
|
len = nbuf?*innbuf:sizeof(tbuf);
|
2014-04-08 17:03:21 +08:00
|
|
|
|
|
|
|
if(innbuf)*innbuf = 0;
|
2016-03-10 22:05:56 +08:00
|
|
|
if(len < 140) return 707;
|
2014-04-08 17:03:21 +08:00
|
|
|
while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
if(i < 3) return 706;
|
|
|
|
buf[i] = 0;
|
|
|
|
if(atoi(buf)/100 != 2) {
|
|
|
|
*innbuf = i;
|
|
|
|
return 702;
|
|
|
|
}
|
2016-03-10 22:05:56 +08:00
|
|
|
sprintf(buf, "USER %.128s\r\n", param->extusername?param->extusername:(unsigned char *)"anonymous");
|
2024-02-17 22:31:25 +08:00
|
|
|
if((int)socksend(param, param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){
|
2014-04-08 17:03:21 +08:00
|
|
|
return 703;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += (int)strlen(buf);
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
if(i < 3) return 704;
|
|
|
|
buf[i] = 0;
|
|
|
|
res = atoi(buf)/100;
|
|
|
|
if(res == 3){
|
2016-03-10 22:05:56 +08:00
|
|
|
sprintf(buf, "PASS %.128s\r\n",
|
2014-04-08 17:03:21 +08:00
|
|
|
param->extusername?
|
|
|
|
(param->extpassword?
|
|
|
|
param->extpassword:(unsigned char *)"")
|
|
|
|
:(unsigned char *)"3proxy@");
|
|
|
|
res = (int)strlen(buf);
|
2024-02-17 22:31:25 +08:00
|
|
|
if((int)socksend(param, param->remsock, (unsigned char *)buf, res, conf.timeouts[STRING_S]) != (int)strlen(buf)){
|
2014-04-08 17:03:21 +08:00
|
|
|
return 705;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += res;
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0){
|
|
|
|
buf[i] = 0;
|
|
|
|
res = (i>3 && buf[3] != '-')? atoi(buf)/100 : 0;
|
|
|
|
if(res || (nbuf && (len-i) > 256 && i > 3)) {
|
|
|
|
buf += i;
|
|
|
|
len -= i;
|
|
|
|
if(innbuf)*innbuf += i;
|
|
|
|
}
|
|
|
|
if(res) break;
|
|
|
|
}
|
|
|
|
if(i < 3) {
|
|
|
|
return 701;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(res != 2) {
|
|
|
|
return 700;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ftpcd(struct clientparam *param, unsigned char* path, char *nbuf, int *innbuf){
|
|
|
|
char buf[1024];
|
|
|
|
int i;
|
|
|
|
int inbuf = 0;
|
|
|
|
|
|
|
|
sprintf(buf, "CWD %.512s\r\n", path);
|
2024-02-17 22:31:25 +08:00
|
|
|
if((int)socksend(param, param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){
|
2014-04-08 17:03:21 +08:00
|
|
|
return 711;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += (int)strlen(buf);
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
if(nbuf && innbuf && inbuf + i < *innbuf && i > 6) {
|
|
|
|
memcpy(nbuf + inbuf, buf, i);
|
|
|
|
inbuf += i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(innbuf)*innbuf = inbuf;
|
|
|
|
if(i < 3) return 712;
|
|
|
|
buf[3] = 0;
|
|
|
|
if(buf[0] != '2') return 710;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ftpres(struct clientparam *param, unsigned char * buf, int l){
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (l < 16) return 755;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, buf, l - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
buf[i] = 0;
|
|
|
|
if(i < 3) return 751;
|
|
|
|
if(buf[0] != '2' && buf[0] != '1') return 750;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ftpsyst(struct clientparam *param, unsigned char *buf, unsigned len){
|
|
|
|
int i;
|
|
|
|
|
2024-02-17 22:31:25 +08:00
|
|
|
if(socksend(param, param->remsock, (unsigned char *)"SYST\r\n", 6, conf.timeouts[STRING_S]) != 6){
|
2014-04-08 17:03:21 +08:00
|
|
|
return 721;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += 6;
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
if(i < 7) return 722;
|
|
|
|
buf[3] = 0;
|
|
|
|
if(atoi((char *)buf)/100 != 2) return 723;
|
|
|
|
buf[i-2] = 0;
|
|
|
|
strcpy((char *)buf, (char *)buf+4);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ftppwd(struct clientparam *param, unsigned char *buf, unsigned len){
|
|
|
|
int i;
|
|
|
|
char *b, *e;
|
|
|
|
|
2024-02-17 22:31:25 +08:00
|
|
|
if(socksend(param, param->remsock, (unsigned char *)"PWD\r\n", 5, conf.timeouts[STRING_S]) != 5){
|
2014-04-08 17:03:21 +08:00
|
|
|
return 731;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += 5;
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
if(i < 7) return 732;
|
|
|
|
buf[3] = 0;
|
|
|
|
if(atoi((char *)buf)/100 != 2) return 733;
|
|
|
|
buf[i-2] = 0;
|
|
|
|
b = (char *)buf+4;
|
|
|
|
if(*b == '\"' && (e = strchr(b+1, '\"'))){
|
|
|
|
b++;
|
|
|
|
*e = 0;
|
|
|
|
}
|
|
|
|
strcpy((char *)buf, b);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ftptype(struct clientparam *param, unsigned char* f_type){
|
|
|
|
char buf[1024];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
sprintf(buf, "TYPE %.512s\r\n", f_type);
|
2024-02-17 22:31:25 +08:00
|
|
|
if((int)socksend(param, param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){
|
2014-04-08 17:03:21 +08:00
|
|
|
return 741;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += (int)strlen(buf);
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
if(i < 3) return 742;
|
|
|
|
if(buf[0] != '2') return 740;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SOCKET ftpdata(struct clientparam *param){
|
|
|
|
char buf[1024];
|
|
|
|
int i;
|
|
|
|
char *sb, *se;
|
|
|
|
SOCKET s = INVALID_SOCKET, rem;
|
|
|
|
unsigned long b1, b2, b3, b4;
|
|
|
|
unsigned short b5, b6;
|
2016-05-14 05:09:51 +08:00
|
|
|
SASIZETYPE sasize;
|
2014-04-08 17:03:21 +08:00
|
|
|
|
2024-02-17 22:31:25 +08:00
|
|
|
if(socksend(param, param->remsock, (unsigned char *)"PASV\r\n", 6, conf.timeouts[STRING_S]) != 6){
|
2014-04-08 17:03:21 +08:00
|
|
|
return INVALID_SOCKET;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += 6;
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
if(i < 7) return INVALID_SOCKET;
|
|
|
|
if(buf[0] != '2') return INVALID_SOCKET;
|
|
|
|
buf[i-2] = 0;
|
|
|
|
if(!(sb = strchr(buf+4, '(')) || !(se= strchr(sb, ')'))) return INVALID_SOCKET;
|
|
|
|
if(sscanf(sb+1, "%lu,%lu,%lu,%lu,%hu,%hu", &b1, &b2, &b3, &b4, &b5, &b6)!=6) return INVALID_SOCKET;
|
2016-05-14 05:09:51 +08:00
|
|
|
sasize = sizeof(param->sinsl);
|
2024-02-17 22:31:25 +08:00
|
|
|
if(so._getsockname(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsl, &sasize)){return INVALID_SOCKET;}
|
2016-05-14 05:09:51 +08:00
|
|
|
sasize = sizeof(param->sinsr);
|
2024-02-17 22:31:25 +08:00
|
|
|
if(so._getpeername(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsr, &sasize)){return INVALID_SOCKET;}
|
2014-04-08 17:03:21 +08:00
|
|
|
rem = param->remsock;
|
|
|
|
param->remsock = INVALID_SOCKET;
|
2016-02-05 23:31:17 +08:00
|
|
|
param->req = param->sinsr;
|
2014-10-21 10:00:56 +08:00
|
|
|
*SAPORT(¶m->req) = *SAPORT(¶m->sinsr) = htons((unsigned short)((b5<<8)^b6));
|
2016-05-14 05:09:51 +08:00
|
|
|
*SAPORT(¶m->sinsl) = 0;
|
2014-04-08 17:03:21 +08:00
|
|
|
i = param->operation;
|
|
|
|
param->operation = FTP_DATA;
|
2014-10-21 10:00:56 +08:00
|
|
|
if((param->res = (*param->srv->authfunc)(param))) {
|
2016-05-14 05:09:51 +08:00
|
|
|
if(param->remsock != INVALID_SOCKET) {
|
2024-02-17 22:31:25 +08:00
|
|
|
so._closesocket(param->sostate, param->remsock);
|
2016-05-14 05:09:51 +08:00
|
|
|
param->remsock = INVALID_SOCKET;
|
|
|
|
}
|
|
|
|
memset(¶m->sinsl, 0, sizeof(param->sinsl));
|
|
|
|
if((param->res = (*param->srv->authfunc)(param))) {
|
|
|
|
param->remsock = rem;
|
|
|
|
return INVALID_SOCKET;
|
|
|
|
}
|
2014-10-21 10:00:56 +08:00
|
|
|
}
|
2014-04-08 17:03:21 +08:00
|
|
|
param->operation = i;
|
|
|
|
s = param->remsock;
|
|
|
|
param->remsock = rem;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
SOCKET ftpcommand(struct clientparam *param, unsigned char * command, unsigned char *arg) {
|
|
|
|
char buf[1024];
|
|
|
|
int i;
|
|
|
|
SOCKET s;
|
|
|
|
|
|
|
|
|
|
|
|
s = ftpdata(param);
|
|
|
|
if(s==INVALID_SOCKET) return INVALID_SOCKET;
|
|
|
|
sprintf(buf, "%.15s%s%.512s\r\n", command, arg?
|
|
|
|
(unsigned char *)" ":(unsigned char *)"",
|
|
|
|
arg?arg:(unsigned char *)"");
|
2024-02-17 22:31:25 +08:00
|
|
|
if((int)socksend(param, param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){
|
|
|
|
so._closesocket(param->sostate, s);
|
2014-04-08 17:03:21 +08:00
|
|
|
return INVALID_SOCKET;
|
|
|
|
}
|
2014-04-10 07:34:59 +08:00
|
|
|
param->statscli64 += (int)strlen(buf);
|
2014-04-08 17:03:21 +08:00
|
|
|
param->nwrites++;
|
|
|
|
while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){
|
|
|
|
}
|
|
|
|
if(i < 3) {
|
2024-02-17 22:31:25 +08:00
|
|
|
so._closesocket(param->sostate, s);
|
2014-04-08 17:03:21 +08:00
|
|
|
return INVALID_SOCKET;
|
|
|
|
}
|
|
|
|
if(buf[0] != '1') {
|
2024-02-17 22:31:25 +08:00
|
|
|
so._closesocket(param->sostate, s);
|
2014-04-08 17:03:21 +08:00
|
|
|
return INVALID_SOCKET;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|