if (bind(listenfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
fprintf(stderr, "Pacific FTP: Can not bind port %d\n", ftp_port);
return -1;
};
if (listen(listenfd, max_conn) == -1) {
perror("Pacific FTP:");
return -1;
};
/* set the program a daemon */
if(fork()) exit(0);
for (n = 0; n<3; n++) close(n);
open("/dev/null", O_RDONLY);
dup2(0,1);
dup2(0,2);
if((n=open("/dev/tty",O_RDWR)) > 0) {
ioctl(n, TIOCNOTTY, 0) ;
close(n);
}
setsid();
if(fork()) exit(0);
/* get the uid */
system_uid = getuid();
}
int main(int argc, char **argv)
{
struct sockaddr_in sa;
int len, cur;
int okay=1, i;
char *cmd, *param;
/* get the param */
for (i=1; i<argc; i++) {
if (argv[i][0] != '-' || argv[i][2] != ':') okay = 0;
switch (argv[i][1]) {
case 'p':
ftp_port = atoi(&argv[i][3]);
if (ftp_port == 0) okay = 0;
break;
case 'm':
max_conn = atoi(&argv[i][3]);
if (max_conn == 0) okay = 0;
break;
case 't':
timeout = atoi(&argv[i][3]);
if (timeout == 0) okay = 0;
break;
default:
okay = 0;
};
if (!okay) break;
};
if (!okay) {
printf("Usage: %s [-p:port] [-m:maxconn] [-t:timeout]\n\tport: default is 21.\n\tmaxconn: the max client num connected.\n", argv[0]);
return -1;
};
if (init() == -1) return -1;
/* main loop */
while (1)
{
len = sizeof(sa);
connfd = accept(listenfd, (struct sockaddr *)&sa, &len);
if (connfd == -1) continue;
if (fork() == 0)
{
len = sizeof(sa);
getsockname(connfd, (struct sockaddr *)&sa, &len);
local_port.host = sa.sin_addr.s_addr;
file = fdopen(connfd, "rt+");
setbuf(file, (char *)0);
getcwd(path, PATH_MAX);
outs("220 PacificFTP ready, hostname: %s", hostname);
signal(SIGALRM, do_alarm);
alarm(timeout);
/* child process's main loop */
while (fgets(inbuf, BUFSIZE, file) != NULL)
{
explode(inbuf, &cmd, ¶m);
if (strcmp(cmd, "") == 0) continue;
/* Make cmd UPPERCASE */
for (i=0;i<strlen(cmd);i++) cmd[i]=toupper(cmd[i]);
cur = 0;
okay = 0;
while (strcmp(cmd_list[cur].cmd, "") != 0)
{
if (strcmp(cmd_list[cur].cmd, cmd) == 0) {
if (cmd_list[cur].func == NULL) outs("502 %s command unimplemented.", cmd);
else
if ((cmd_list[cur].check & NO_CHECK) || Check(cmd, param, cmd_list[cur].check))
(*cmd_list[cur].func)(param);
okay = 1;
break;
};
cur++;
};
if (!okay) outs("500 %s not understood", cmd);
};
if (r < 0 || (r == 0 && param[0] != '0')) {
outs("501 REST requires a value greater than or equal to 0.");
return;
};
file_rest = r;
outs("350 Restarting at %u. Send STORE or RETRIEVE to initiate transfer.", file_rest);
};
void Rnfr(char *param)
{
char tmp[PATH_MAX];
struct stat s;
MakePath(tmp, path, param);
if (stat(tmp, &s) == -1) {
Error(tmp);
} else {
outs("350 File or directory exists, ready for destination name.");
strncpy(rename_file, param, PATH_MAX);
};
};
void Help(char *param)
{
if (!param) {
outs("214 The following commands are recognized (* =>'s unimplemented).");
outs("214 USER PASS ACCT* CWD XCWD CDUP XCUP SMNT* ");
outs("214 QUIT REIN* PORT PASV TYPE STRU* MODE* RETR ");
outs("214 STOR STOU* APPE ALLO* REST RNFR RNTO ABOR ");
outs("214 DELE MDTM RMD XRMD MKD XMKD PWD XPWD ");
outs("214 SIZE LIST NLST SITE SYST STAT HELP NOOP ");
outs("214 Direct comments to nolove@263.net");
} else {
outs("214 Sorry, I haven't write the topic help.");
};
};
void User(char *param)
{
if (user_valid) {
outs("503 You are already logged in!");
return;
};
if (!param) {
outs("500 \'USER\': command requires a parameter.");
return;
};
strncpy(username, param, 100);
if (strcasecmp(username, "anonymous") == 0) {
anonymous_login = 1;
strncpy(username, "ftp", 100);
outs("331 Anonymous login ok, send your complete e-mail address as password.");
} else outs("331 Password required for %s", username);
Support command:
214 The following commands are recognized (* =>'s unimplemented).
214 USER PASS ACCT* CWD XCWD CDUP XCUP SMNT*
214 QUIT REIN* PORT PASV TYPE STRU* MODE* RETR
214 STOR STOU* APPE ALLO* REST RNFR RNTO ABOR
214 DELE MDTM RMD XRMD MKD XMKD PWD XPWD
214 SIZE LIST NLST SITE SYST STAT HELP NOOP
214 Direct comments to nolove@263.net
void Error(char *param)
{
switch (errno) {
case ENOTEMPTY:
ERRS("Directory not empty");
break;
case ENOSPC:
ERRS("disk full");
break;
case EEXIST:
ERRS("File exists");
break;
case ENAMETOOLONG:
ERRS("path is too long");
break;
case ENOENT:
ERRS("No such file or directory");
break;
case ENOTDIR:
ERRS("Not a directory");
break;
case EISDIR:
ERRS("Is a directory");
default:
ERRS("Permission denied");
};
}
int Check(char *cmd, char *param, int check)
{
if (check & CHECK_LOGIN && !user_valid) {
outs("530 Please login with USER and PASS");
return 0;
};
if (check & CHECK_NOLOGIN && user_valid) {
outs("503 You are already logged in!");
return 0;
};
if (check & NEED_PARAM) {
if (!param) outs("501 Invalid number of arguments, check more arguments.");
return (param != NULL);
};
if (check & NO_PARAM) {
if (param) outs("501 Invalid number of arguments.");
return (param == NULL);
};
return 1;
};