/* Copyright (C) 1999 Beau Kuiper This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "ftpd.h" #include "ftpcmd.h" #include "reply.h" extern FTPCMD mainftpcmd[]; /* This will print a NICE! error to the user */ void reporterror(FTPSTATE *peer, char *filename, int errorno) { ftp_write(peer, FALSE, 550, "'%s': %s", filename, strerror(errorno)); } int readipstr(char *data, int *port, unsigned int *ip) { int a1,a2,a3,a4,a5,a6, result; result = sscanf(data, "%d,%d,%d,%d,%d,%d",&a1, &a2, &a3, &a4, &a5, &a6); if (result != 6) return(FALSE); *ip = (a1 << 24) | (a2 << 16) | (a3 << 8) | (a4); *port = (a5 * 256) + a6; return(TRUE); } int readeipstr(char *ip, unsigned int *outip) { int a1, a2, a3, a4, result; result = sscanf(ip, "%d.%d.%d.%d", &a1, &a2, &a3, &a4); if (result != 4) return(FALSE); *outip = (a1 << 24) | (a2 << 16) | (a3 << 8) | (a4); return(TRUE); } int ftp_dele(FTPSTATE *peer, char *filename) { if (file_unlink(peer, filename) == 0) ftp_write(peer, FALSE, 250, REPLY_DELETE(filename)); else reporterror(peer, filename, errno); return(FALSE); } int ftp_chmod(FTPSTATE *peer, char *filename, int mode) { if (file_chmod(peer, filename, mode) == 0) ftp_write(peer, FALSE, 250, REPLY_CHMOD(filename, mode)); else reporterror(peer, filename, errno); return(FALSE); } int ftp_size(FTPSTATE *peer, char *filename) { int filefd; off_t size = 0; int asize; struct stat statdata; if (peer->binary) { filefd = file_stat(peer, filename, &statdata); if (filefd == 0) size = statdata.st_size; } else { char *rname; size = 0; filefd = file_readopen(peer, filename, &rname); freewrapper(rname); if (filefd > 0) { char *chin, buffer[BUFFERSIZE]; asize = read(filefd, buffer, BUFFERSIZE-1); while (asize > 0) { buffer[asize] = 0; size += asize; chin = buffer; while ((chin = strchr(chin, 10)) != NULL) { chin++; size++; } asize = read(filefd, buffer, BUFFERSIZE-1); } close(filefd); } } if (filefd >= 0) ftp_write(peer, FALSE, 213, "%s", offt_tostr(size)); else reporterror(peer, filename, errno); return(FALSE); } int ftp_mdtm(FTPSTATE *peer, char *filename) { struct stat statdata; if (file_stat(peer, filename, &statdata) == 0) { char timestr[20]; struct tm *resulttm = gmtime(&statdata.st_mtime); strftime(timestr, 20, "%Y%m%d%H%M%S", resulttm); ftp_write(peer, FALSE, 213, timestr); } else reporterror(peer, filename, errno); return(FALSE); } void setdumptokens(FTPSTATE *peer, TOKENSET *ts) { char *outstr; time_t mytime = time(NULL); outstr = ctime(&mytime); outstr[strlen(outstr) - 1] = 0; tokenset_settoken(ts, 'T', strdupwrapper(outstr)); tokenset_settoken(ts, 'U', strdupwrapper(peer->username)); if (peer->pwd) tokenset_settoken(ts, 'C', strdupwrapper(dir_getvirtual(peer, peer->pwd))); tokenset_settoken(ts, 'E', strdupwrapper(peer->vserver->email)); tokenset_settoken(ts, 'M', safe_snprintf("%d", peer->maxusers)); if (peer->loggedin) tokenset_settoken(ts, 'N', safe_snprintf("%d", peer->usercount)); tokenset_settoken(ts, 'R', strdupwrapper(peer->hostname)); tokenset_settoken(ts, 'L', strdupwrapper(peer->vserver->vhostname)); tokenset_settoken(ts, 'f', safe_snprintf("%d", peer->downloadedfiles)); tokenset_settoken(ts, 'F', safe_snprintf("%d", peer->uploadedfiles)); tokenset_settoken(ts, 'b', safe_snprintf("%s", offt_tostr(peer->downloadedfilebytes))); tokenset_settoken(ts, 'B', safe_snprintf("%s", offt_tostr(peer->uploadedfilebytes))); tokenset_settoken(ts, 'I', safe_snprintf("%s", offt_tostr(peer->listdownloadedbytes))); tokenset_settoken(ts, 'i', safe_snprintf("%d", peer->listconns)); tokenset_settoken(ts, 'D', safe_snprintf("%s", offt_tostr(peer->listdownloadedbytes + peer->downloadedfilebytes))); tokenset_settoken(ts, 't', safe_snprintf("%s", offt_tostr(peer->listdownloadedbytes + peer->downloadedfilebytes + peer->uploadedfilebytes))); tokenset_settoken(ts, 'c', safe_snprintf("%d", peer->listconns + peer->downloadedfiles + peer->uploadedfiles)); tokenset_settoken(ts, 'd', safe_snprintf("%d", peer->listconns + peer->downloadedfiles)); if (peer->ratioinfo) ratio_settokens(peer->ratioinfo, ts); tokenset_settoken(ts, 'v', strdupwrapper(peer->vserver->sectionname)); } int ftp_dumper(FTPSTATE *peer, NEWFILE *infile, int number, char *fmessage, int dotokens, int endtokens) { TOKENSET *ts = NULL; char *inp, *tfmessage; int first; if (dotokens) if ((infile != NULL) || (endtokens)) { ts = tokenset_new(); setdumptokens(peer, ts); } if (infile != NULL) { first = TRUE; while ((inp = nfgetcs(infile, '\n')) != NULL) { if (inp[strlen(inp)-1] == '\n') inp[strlen(inp)-1] = 0; if (dotokens) inp = tokenset_apply(ts, inp, FALSE); if (first || config->altlongreplies) { ftp_write(peer, TRUE, 0, "%d-%s", number, inp); first = FALSE; } else ftp_write(peer, TRUE, 0, " %s", inp); freewrapper(inp); } nfclose(infile); } if (endtokens) { tfmessage = tokenset_apply(ts, strdupwrapper(fmessage), FALSE); ftp_write(peer, FALSE, number, "%s", tfmessage); freewrapper(tfmessage); } else ftp_write(peer, FALSE, number, "%s", fmessage); if (ts) tokenset_finish(ts); return(FALSE); } int ftp_dumpstr(FTPSTATE *peer, char *dumpstr, int number, char *fmessage, int endtokens) { TOKENSET *ts = NULL; char *oldinp = dumpstr; char *inp = dumpstr; char *datline, *tfmessage; int first; ts = tokenset_new(); setdumptokens(peer, ts); first = TRUE; while (oldinp != NULL) { inp = strchr(inp, '\n'); if (inp != NULL) *inp = 0; datline = strdupwrapper(oldinp); if (inp != NULL) { *inp = '\n'; inp++; } oldinp = inp; datline = tokenset_apply(ts, datline, FALSE); if (first || config->altlongreplies) { ftp_write(peer, TRUE, 0, "%d-%s", number, datline); first = FALSE; } else ftp_write(peer, TRUE, 0, " %s", datline); freewrapper(datline); } if (endtokens) { tfmessage = tokenset_apply(ts, strdupwrapper(fmessage), FALSE); ftp_write(peer, FALSE, number, "%s", tfmessage); freewrapper(tfmessage); } else ftp_write(peer, FALSE, number, "%s", fmessage); tokenset_finish(ts); return(FALSE); } VSERVER *find_vserver_byname(char *name) { VSERVER *v = config->vservers; while((v != NULL) && (strcasecmp(v->vhostname, name) != 0)) v = v->next; return(v); } int host_isip(char *name) { while(((*name >= '0') && (*name <= '9')) || (*name == '.')) name++; return(*name == 0); } int ftp_host(FTPSTATE *peer, char *params) { VSERVER *v; /* if there are no vservers, or hostname vservers are not defined, return with not implemented */ if ((!config->vservers) || (!config->hostvservers)) return(ftp_write(peer, FALSE, 502, REPLY_NOHOSTS)); /* if a vserver has already been selected, return 530 */ if (peer->vserver != config->defaults) return(ftp_write(peer, FALSE, 530, REPLY_HOSTSELECTED)); if (config->defaulthost && (host_isip(params))) v = config->defaulthost; else v = find_vserver_byname(params); if (!v) return(ftp_write(peer, FALSE, 533, REPLY_HOSTNOTFOUND(params))); switch(vserver_select(peer, v)) { case 1: return(ftp_write(peer, FALSE, 533, REPLY_HOSTMISCONF(params))); case 2: return(ftp_write(peer, FALSE, 533, REPLY_HOSTNOTFOUND(params))); case 3: ftp_write(peer, FALSE, 421, REPLY_HOSTTOOBUSY(params)); return(TRUE); } ftp_write(peer, FALSE, 202, REPLY_HOSTSEL(v->vhostname)); return(3); } int ftp_rnto(FTPSTATE *peer, char *filename) { char *badfile; char *oldname; if (!peer->renameoldname) return(ftp_write(peer, FALSE, 503, REPLY_RENAMENOSOURCE)); oldname = dir_getvirtual(peer, peer->renameoldname); if ((badfile = file_rename(peer, oldname, filename)) == NULL) ftp_write(peer, FALSE, 250, REPLY_RENAME(oldname, filename)); else reporterror(peer, badfile, errno); freewrapper(peer->renameoldname); peer->renameoldname = NULL; return(FALSE); } int ftp_mkd(FTPSTATE *peer, char *filename) { if (file_mkdir(peer, filename) == 0) { char *newfile = file_expand(peer, filename); ftp_write(peer, FALSE, 257, REPLY_MKDIR(dir_getvirtual(peer, newfile))); freewrapper(newfile); } else reporterror(peer, filename, errno); return(FALSE); } int ftp_rmd(FTPSTATE *peer, char *filename) { if (file_rmdir(peer, filename) == 0) ftp_write(peer, FALSE, 250, REPLY_RMDIR(filename)); else reporterror(peer, filename, errno); return(FALSE); } int ftp_cwddo(FTPSTATE *peer, char *newdir, int dump) { char *tmp = strdupwrapper(peer->pwd); dir_combine(peer, &tmp, newdir); if (!checkchdir(peer, tmp)) { freewrapper(tmp); reporterror(peer, newdir, errno); return(FALSE); } chdir(tmp); if (peer->realdir) { char *nt; /* this relies on the side effect of checkchdir where the server changes dir to check */ nt = (char *)dir_getreal(peer); if (nt != NULL) { freewrapper(tmp); tmp = nt; } } { NEWFILE *nfile = NULL; char *outstr; int ret = 257; /* If we need to print a file, then open it */ /* Oh bugger, crap, and other things, I left a big security hole here! :-(, now fixed */ if (dump) ret = 250; freewrapper(peer->pwd); peer->pwd = tmp; if ((dump) && (peer->cwddump) && (!peer->cwddumpdata)) { if (peer->cwddump[0] == '/') /* if it is an absolute file, don't worry about permissions accessing file */ nfile = nfopen(peer->cwddump); else /* worry like hell and pass request via both ACL's and file permissions! */ nfile = file_nfopen(peer, peer->cwddump); } outstr = safe_snprintf(REPLY_PWD(dir_getvirtual(peer, peer->pwd))); if ((dump) && (peer->cwddumpdata)) ftp_dumpstr(peer, peer->cwddumpdata, ret, outstr, FALSE); else ftp_dumper(peer, nfile, ret, outstr, TRUE, FALSE); freewrapper(outstr); } return(FALSE); } int ftp_cwd(FTPSTATE *peer, char *newdir) { return(ftp_cwddo(peer, newdir, TRUE)); } int ftp_run(FTPSTATE *peer, INPUTLINE *cmd, char *token) { if ((cmd->command->ftpfunc) == NULL) return(ftp_write(peer, FALSE, 500, REPLY_CMDNOTKNOWN(token))); if (cmd->command->paramnum) { if (cmd->parameters == NULL) return(ftp_write(peer, FALSE, 500, REPLY_NOPARAM(token))); else if (cmd->parameters[0] == 0) return(ftp_write(peer, FALSE, 500, REPLY_NOPARAM(token))); } if ((cmd->command->needslogin) && (peer->loggedin != TRUE)) return(ftp_write(peer, FALSE, 530, REPLY_NOLOGIN)); if ((!cmd->command->dataportok) && (peer->dport)) return(ftp_write(peer, FALSE, 520, REPLY_DATACONNINVALID(token))); else return(cmd->command->ftpfunc(peer, cmd->parameters)); } int ftp_quit(FTPSTATE *peer, char *param) { if (peer->quitdump) { NEWFILE *nfile = nfopen(peer->quitdump); ftp_dumper(peer, nfile, 221, REPLY_QUIT, TRUE, FALSE); } else if (peer->quitdumpdata) ftp_dumpstr(peer, peer->quitdumpdata, 221, REPLY_QUIT, FALSE); else ftp_write(peer, FALSE, 221, REPLY_QUIT); return(TRUE); } int ftp_user(FTPSTATE *peer, char *param) { if (peer->jailenabled) return(ftp_write(peer, FALSE, 530, REPLY_JAILUSER)); if (peer->loginsleft == 0) return(ftp_write(peer, FALSE, 530, REPLY_NOCREDITS)); if (peer->loggedin) shinfo_delusergroup(peer->groupname); shinfo_changeuser(param); peer->loggedin = 0; freewrapper(peer->username); peer->username = strdupwrapper(param); return(ftp_write(peer, FALSE, 331, REPLY_USER(peer->username))); } int ftp_host_compat(FTPSTATE *peer) { VSERVER *v; char *name; /* if there are no vservers, or hostname vservers are not defined, return with not implemented */ if ((!config->vservers) || (!config->hostvservers)) return(1); /* if a vserver has already been selected, return 530 */ if (peer->vserver != config->defaults) return(1); name = strchr(peer->username, '%'); if (!name) v = config->defaulthost; else { *name = 0; name++; if (config->defaulthost && (host_isip(name))) v = config->defaulthost; else v = find_vserver_byname(name); } if (!v) return(0); switch(vserver_select(peer, v)) { case 1: case 2: return(0); case 3: return(2); } return(1); } int ftp_pass(FTPSTATE *peer, char *param) { int result = FALSE; int loginok, oldnice = peer->nicevalue; int toomany = FALSE; char *errmsg = NULL; switch(ftp_host_compat(peer)) { case 0: return(ftp_write(peer, FALSE, 530, REPLY_LOGINFAIL(peer->username, "Bad password"))); case 2: ftp_write(peer, FALSE, 421, REPLY_TOOMANYUSERS); return(TRUE); } if (peer->loggedin) return(ftp_write(peer, FALSE, 530, REPLY_ALREADYLOGGEDIN)); if (strcmp(peer->username, "") == 0) return(ftp_write(peer, FALSE, 503, REPLY_USEUSERFIRST)); loginok = (param != NULL); if (loginok) { file_becomeroot(peer); setgroups(0, NULL); errmsg = setuseropts(peer, param); loginok = (errmsg == NULL); } /* check some stuff, set basedir to real pathname */ if (loginok) { file_becomeuser(peer); if (chdir(peer->basedir) == -1) { loginok = FALSE; log_giveentry(MYLOG_INFO, NULL, safe_snprintf("rootdir(%s) for user '%s' is not accessable. Check rootdir and rootdir permissions", peer->basedir, peer->username)); } else { char *curdir = getcwd2(); if (strcmp(curdir, peer->basedir) != 0) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("rootdir changed from '%s' to '%s', symbolic links resolved for user '%s'", peer->basedir, curdir, peer->username)); freewrapper(peer->basedir); peer->basedir = curdir; } else freewrapper(curdir); } file_becomeroot(peer); } if (loginok) { peer->usercount = toomany = shinfo_addusergroup(peer->groupname, peer->maxusers); toomany = (toomany == -1); if (toomany) loginok = FALSE; } if (loginok) { char *outstr; NEWFILE *nfile; log_addentry(MYLOG_LOGIN, peer, "Login successful."); outstr = safe_snprintf(REPLY_PASSOK(peer->username)); /* perform chroot if needed */ if (peer->chroot) dochroot(peer); if (nice(peer->nicevalue + (-oldnice)) == -1) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("nice(%d) gave error %s", peer->nicevalue + (-oldnice), strerror(errno))); peer->nicevalue = oldnice; } if (config->rootmode) setgroups(peer->supgids[0], peer->supgids + 1); /* see if rootdir == "/", change to "" */ if (peer->basedir[1] == 0) peer->basedir[0] = 0; if ((peer->droproot) && (config->rootmode)) { if (giveuproot(peer->uidt_asuid, peer->gidt_asgid)) log_addentry(MYLOG_INFO, peer, "Failed to set capabilities!"); peer->jailenabled = TRUE; /* we are not root anymore and can never be root again! */ config->rootmode = FALSE; } file_becomeuser(peer); nfile = nfopen(peer->logindump); peer->pwd = strdupwrapper(peer->basedir); dir_combine(peer, &(peer->pwd), peer->homedir); if (peer->logindumpdata) result = ftp_dumpstr(peer, peer->logindumpdata, 230, outstr, FALSE); else result = ftp_dumper(peer, nfile, 230, outstr, TRUE, FALSE); freewrapper(outstr); } else { peer->loggedin = FALSE; log_addentry(MYLOG_LOGIN, peer, "Login failed"); peer->timeout = peer->vserver->timeout; if (toomany) { NEWFILE *nfile = nfopen(peer->busydump); logfullmessage(GROUPFULL, peer->remoteip); if (peer->busydumpdata) ftp_dumpstr(peer, peer->busydumpdata, 421, REPLY_TOOMANYUSERS, FALSE); else ftp_dumper(peer, nfile, 421, REPLY_TOOMANYUSERS, TRUE, FALSE); } else { usleep(peer->vserver->authwait); if (errmsg == NULL) errmsg = strdupwrapper("Bad password"); result = ftp_write(peer, FALSE, 530, REPLY_LOGINFAIL(peer->username, errmsg)); if (peer->loginsleft > 0) peer->loginsleft--; freewrapper(errmsg); } freewrapper(peer->username); peer->username = strdupwrapper(""); } if (toomany) return(TRUE); /* quit */ return(3); /* make sure timeout gets updated */ } int ftp_rest(FTPSTATE *peer, char *param) { off_t newpos; int res; res = strto_offt(param, &newpos); if ((res != 0) || (newpos < 0)) return(ftp_write(peer, FALSE, 501, REPLY_INVALIDREST)); else { peer->restartpos = newpos; return(ftp_write(peer, FALSE, 350, REPLY_RESTOK(peer->restartpos))); } } int ftp_syst(FTPSTATE *peer, char *param) { return(ftp_write(peer, FALSE, 215, "UNIX Type: L8")); } int ftp_port(FTPSTATE *peer, char *param) { if (peer->epsv_forced) return(ftp_write(peer, FALSE, 500, REPLY_EPSVSET)); /* reset remoteport */ peer->remoteport = 0; if (peer->passiveport) { select_delfd(peer->sel, peer->passiveport); peer->passiveport = 0; } if (readipstr(param, &(peer->remoteport), &(peer->dataip))) { if ((peer->remoteport <= 1024) || (peer->remoteport >= 65536)) { peer->remoteport = 0; return(ftp_write(peer, FALSE, 500, REPLY_PORTBADPORT)); } if ((peer->dataip != peer->remoteip) && (!peer->fxpallow)) { peer->remoteport = 0; peer->dataip = peer->remoteip; return(ftp_write(peer, FALSE, 500, REPLY_PORTBADFXP)); } return(ftp_write(peer, FALSE, 200, REPLY_PORTOK( peer->dataip >> 24, peer->dataip >> 16 & 255, peer->dataip >> 8 & 255, peer->dataip & 255, peer->remoteport))); } else return(ftp_write(peer, FALSE, 501, REPLY_PORTBADPARM)); } int ftp_eprt(FTPSTATE *peer, char *param) { char *ipstr; int proto, tcpport; unsigned int remote_ip; if (peer->epsv_forced) return(ftp_write(peer, FALSE, 500, REPLY_EPSVSET)); ipstr = mallocwrapper(strlen(param) + 1); /* clear off old ports */ peer->remoteport = 0; if (peer->passiveport) { select_delfd(peer->sel, peer->passiveport); peer->passiveport = 0; } if (sscanf(param, "|%d|%[0-9.]|%d|", &proto, ipstr, &tcpport) != 3) ftp_write(peer, FALSE, 500, REPLY_EPRTBADPARM); else if (proto != FTP_IPV4) ftp_write(peer, FALSE, 522, REPLY_BADPROTO); else if (!readeipstr(ipstr, &(remote_ip))) ftp_write(peer, FALSE, 500, REPLY_EPRTBADPARM); else if (tcpport <= 1024) ftp_write(peer, FALSE, 500, REPLY_EPRTBADPORT); else if ((remote_ip != peer->remoteip) && (!peer->fxpallow)) ftp_write(peer, FALSE, 500, REPLY_EPRTBADFXP); else { /* everything seems to be ok */ peer->remoteport = tcpport; peer->dataip = remote_ip; ftp_write(peer, FALSE, 200, REPLY_EPRTOK( peer->dataip >> 24, peer->dataip >> 16 & 255, peer->dataip >> 8 & 255, peer->dataip & 255, peer->remoteport)); } freewrapper(ipstr); return(FALSE); } int ftp_pwd(FTPSTATE *peer, char *param) { return(ftp_cwddo(peer, ".", FALSE)); } int ftp_type(FTPSTATE *peer, char *param) { if ((param[0] & (255-32)) == 'A') { peer->binary = FALSE; return(ftp_write(peer, FALSE, 200, REPLY_TYPEASCII)); } else if ((param[0] & (255-32)) == 'I') { peer->binary = TRUE; return(ftp_write(peer, FALSE, 200, REPLY_TYPEBINARY)); } else return(ftp_write(peer, FALSE, 504, REPLY_TYPEUNIMP)); } int ftp_abor(FTPSTATE *peer, char *param) { /* abort any active or pending data port */ abortdatasocket(peer); return(ftp_write(peer, FALSE, 226, REPLY_ABORT)); } int ftp_pasv(FTPSTATE *peer, char *param) { unsigned int a1, a2, a3, a4, a5, a6; if (peer->epsv_forced) return(ftp_write(peer, FALSE, 500, REPLY_EPSVSET)); if (peer->passiveport != 0) select_delfd(peer->sel, peer->passiveport); peer->remoteport = 0; peer->passiveport = listenparrelelport(peer->remotefd, &(peer->remoteport), &a1, 5); if (peer->passiveport == -1) { peer->passiveport = 0; reporterror(peer, "passive port", errno); return(FALSE); } select_addfd(peer->sel, peer->passiveport); a2 = ((a1 >> 8) & 255); a3 = ((a1 >> 16) & 255); a4 = ((a1 >> 24) & 255); a1 = a1 & 255; a5 = (peer->remoteport >> 8); a6 = (peer->remoteport & 255); return(ftp_write(peer, FALSE, 227, REPLY_PASV(a4, a3, a2, a1, a5, a6))); } int ftp_epsv(FTPSTATE *peer, char *param) { int proto, a1; /* the all parameter means that only epsv can be used from now on */ if (peer->passiveport != 0) select_delfd(peer->sel, peer->passiveport); peer->remoteport = 0; peer->passiveport = 0; if (param) { if (strcasecmp(param, "ALL") == 0) { peer->epsv_forced = 1; return(ftp_write(peer, FALSE, 200, REPLY_EPSVON)); } else if (sscanf(param, "%d", &proto) == 1) { if (proto != FTP_IPV4) return(ftp_write(peer, FALSE, 522, REPLY_BADPROTO)); } else return(ftp_write(peer, FALSE, 500, REPLY_EPSVERR)); } peer->passiveport = listenparrelelport(peer->remotefd, &(peer->remoteport), &a1, 5); if (peer->passiveport == -1) { peer->passiveport = 0; reporterror(peer, "passive port", errno); return(FALSE); } select_addfd(peer->sel, peer->passiveport); return(ftp_write(peer, FALSE, 229, REPLY_EPSV(peer->remoteport))); } int ftp_list(FTPSTATE *peer, char *param) { char *p = param; int done = FALSE; int parm = 0; while (!done) { if (p == NULL) done = TRUE; else if ((p[0] != '-') && (p[0] != ' ') && (p[0] != 0)) done = TRUE; else { parm = parm | ftplist_parseflags(p + 1); p = strchr(p, ' '); if (p != NULL) p++; } } return(ftp_lister(peer, p, FALSE, parm)); } int ftp_nlst(FTPSTATE *peer, char *param) { char *p = param; int done = FALSE; int parm = 0; while (!done) { if (p == NULL) done = TRUE; else if ((p[0] != '-') && (p[0] != ' ') && (p[0] != 0)) done = TRUE; else { parm = parm | ftplist_parseflags(p + 1); p = strchr(p, ' '); if (p != NULL) p++; } } return(ftp_lister(peer, p, TRUE, parm)); } int ftp_cdup(FTPSTATE *peer, char *param) { return(ftp_cwd(peer, "..")); } int ftp_rnfr(FTPSTATE *peer, char *param) { freeifnotnull(peer->renameoldname); peer->renameoldname = file_expand(peer, param); return(ftp_write(peer, FALSE, 350, REPLY_RENAMESOURCE)); } int ftp_noop(FTPSTATE *peer, char *param) { return(ftp_write(peer, FALSE, 200, REPLY_NOOP)); } int ftp_rein(FTPSTATE *peer, char *param) { if (peer->jailenabled) return(ftp_write(peer, FALSE, 530, REPLY_JAILUSER)); if (peer->loggedin) shinfo_delusergroup(peer->groupname); peer->loggedin = FALSE; abortdatasocket(peer); return(ftp_write(peer, FALSE, 220, "Reinitialize successful, enter username.")); } int ftp_none(FTPSTATE *peer, char *param) { return(FALSE); } int ftp_help(FTPSTATE *peer, char *param) { return(ftp_dohelp(peer, mainftpcmd, param, peer->cmddisableset)); } int ftp_dohelp(FTPSTATE *peer, FTPCMD *ftpcmds, char *command, int *disableset) { char outstr[128]; char cmd[10]; int result = FALSE; int count2,count = 0; if (command != NULL) { while(((strcasecmp(ftpcmds[count].command, command) != 0) && (ftpcmds[count].ftpfunc != NULL)) || (peer->loggedin ? disableset[count] : ftpcmds[count].needslogin)) count++; if (ftpcmds[count].ftpfunc == NULL) ftp_write(peer, FALSE, 502, REPLY_HELPUNKNOWN(command)); else ftp_write(peer, FALSE, 214, "%-8s : %s", ftpcmds[count].command, ftpcmds[count].helpdesc); return(FALSE); } ftp_write(peer, TRUE, 0, REPLY_HELPSTART); while (ftpcmds[count].ftpfunc != NULL) { count2 = 0; if (config->altlongreplies) strcpy(outstr, "214-"); else strcpy(outstr, " "); /* now increment past disabled commands */ while((peer->loggedin ? disableset[count] : ftpcmds[count].needslogin)) count++; while ((count2 < 7) && (ftpcmds[count].ftpfunc != NULL)) { snprintf(cmd, 10, "%-9s", ftpcmds[count].command); strcat(outstr, cmd); count2++; count++; /* now increment past disabled commands */ while((peer->loggedin ? disableset[count] : ftpcmds[count].needslogin)) count++; } ftp_write(peer, TRUE, 0, outstr); } result = ftp_write(peer, FALSE, 214, REPLY_HELPEND(peer->vserver->email)); return(result); } int ftp_allo(FTPSTATE *peer, char *param) { return(ftp_write(peer, FALSE, 202, REPLY_ALLO)); } int ftp_acct(FTPSTATE *peer, char *param) { return(ftp_write(peer, FALSE, 200, REPLY_ACCT)); } int ftp_stru(FTPSTATE *peer, char *param) { if ((param[0] & (255-32)) == 'F') return(ftp_write(peer, FALSE, 200, REPLY_STRUFILE)); else return(ftp_write(peer, FALSE, 500, REPLY_STRUUNKNOWN)); }