📄 cmd.c
字号:
#include "CMD.h"
#include "Public.h"
#include "NetWork.h"
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/ipc.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>
FTPCMD cmdList[] =
{
{"USER", do_user, NO_LOGIN | NEED_PARAM },
{"PASS", do_pass, },
{"XCUP", do_cdup, NEED_LOGIN },
{"SYST", do_syst, NEED_LOGIN },
{"PWD", do_pwd, NEED_LOGIN },
{"XPWD", do_pwd, NEED_LOGIN },
{"PASV", do_pasv, NEED_LOGIN },
{"TYPE", do_type, NEED_LOGIN | NEED_PARAM },
{"PORT", do_port, NEED_LOGIN | NEED_PARAM },
{"LIST", do_list, NEED_LOGIN },
{"FEAT", NULL, },
{"NLST", do_nlst, NEED_LOGIN },
{"CWD", do_cwd, NEED_LOGIN | NEED_PARAM },
{"XCWD", do_cwd, NEED_LOGIN | NEED_PARAM },
{"CDUP", do_cdup, NEED_LOGIN },
{"RMD", do_rmd, NEED_LOGIN | NEED_PARAM },
{"XRMD", do_rmd, NEED_LOGIN | NEED_PARAM },
{"MKD", do_mkd, NEED_LOGIN | NEED_PARAM },
{"XMKD", do_mkd, NEED_LOGIN | NEED_PARAM },
{"DELE", do_dele, NEED_LOGIN | NEED_PARAM },
{"REIN", do_rein, NEED_LOGIN },
{"HELP", do_help, NEED_LOGIN },
{"QUIT", do_quit, },
{"REST", do_rest, NEED_LOGIN | NEED_PARAM },
{"RNFR", do_rnfr, NEED_LOGIN | NEED_PARAM },
{"RNTO", do_rnto, NEED_LOGIN | NEED_PARAM },
{"SIZE", do_size, NEED_LOGIN | NEED_PARAM },
{"NOOP", do_noop, },
{"STOR", do_stor, NEED_LOGIN | NEED_PARAM },
{"RETR", do_retr, NEED_LOGIN | NEED_PARAM },
{"APPE", do_appe, NEED_LOGIN | NEED_PARAM },
{"ABOR", do_abor, NEED_LOGIN },
{"ACCT", NULL, },
{"SMNT", NULL, },
{"STRU", NULL, },
{"MODE", NULL, },
{"STOU", NULL, },
{"ALLO", NULL, },
{"MDTM", NULL, NEED_LOGIN | NEED_PARAM },
{"SITE", NULL, NEED_LOGIN | NEED_PARAM },
{"STAT", do_stat, NEED_LOGIN | NEED_PARAM },
{NULL}
};
/* 用户 */
int do_user(char *userName)
{
RTrim(userName);
if (strcmp(userName, "anonymous") == 0 || strlen(userName) == 0)
strcpy(State.uname, "ftp");
else
strcpy(State.uname, userName);
if (strlen(State.uname) == 0)
{
Write(State.s, FTP_BADCMD, strlen(FTP_BADCMD));
return -1;
}
Write(State.s, FTP_GIVEPWORD, strlen(FTP_GIVEPWORD));
return 0;
}
/* 密码 */
int do_pass(char *userPass)
{
if (strlen(State.uname) == 0)
{
Write(State.s, FTP_NEEDUSER, strlen(FTP_NEEDUSER));
return -1;
}
memset(State.homeDir, 0, sizeof(State.homeDir));
strcpy(State.upass, userPass);
struct passwd *userInfo;
memset(&userInfo, 0, sizeof(userInfo));
GetUser(State.uname, &userInfo);
if (strcmp(State.uname, "ftp") != 0)
{
int rt = CheckPass(State.uname, State.upass);
if (rt != PASS_OK)
{
Write(State.s, FTP_LOGINERR, strlen(FTP_LOGINERR));
return -1;
}
}
else
{
if (State.anologin == 0)
{
Write(State.s, "530 Anonymous can not login\r\n", strlen("530 Anonymous can not login\r\n"));
return 0;
}
}
State.isLogin = 1;
setegid(userInfo->pw_gid);
seteuid(userInfo->pw_uid);
GetHomeDir(State.uname, State.homeDir);
if (chdir(State.homeDir) == -1)
{
Write(State.s, FTP_FILEFAIL, strlen(FTP_FILEFAIL));
return -1;
}
Write(State.s, FTP_LOGINOK, strlen(FTP_LOGINOK));
return 0;
}
/* 打印服务器信息 */
int do_syst(char *param)
{
Write(State.s, FTP_SYSTOK, strlen(FTP_SYSTOK));
return 0;
}
/* 打印当前目录 */
int do_pwd(char *param)
{
char path[MAX_BUF_SIZE];
char *cpath = path;
memset(path, 0, sizeof(path));
getcwd(cpath, MAX_BUF_SIZE-1);
if (strcmp(State.uname, "ftp") == 0)
{
char hhPath[MAX_BUF_SIZE];
char *hPath = hhPath;
GetHomeDir("ftp", hPath);
while (*cpath == *hPath)
{
cpath++;
hPath++;
}
*cpath = '/';
}
char fs257[MAX_BUF_SIZE];
memset(fs257, 0, sizeof(fs257));
sprintf(fs257, "257 \"%s\"\r\n", cpath);
Write(State.s, fs257, strlen(fs257));
return 0;
}
/* 列出文件详情 */
int do_list(char *mode)
{
if (Connect() == -1)
{
//....................
return -1;
}
Write(State.s, FTP_DATACONN, strlen(FTP_DATACONN));
signal(SIGUSR1, TransOK);
signal(SIGCHLD, SIG_IGN);
if (fork() == 0)
{
if (lsdir(2) == -1)
{
//.................
close(State.Socket);
return -1;
}
close(State.Socket);
exit(0);
}
close(State.Socket);
return 0;
}
/* 列出文件夹与文件 */
int do_nlst(char *param)
{
if (Connect() == -1)
{
//....................
return -1;
}
Write(State.s, FTP_DATACONN, strlen(FTP_DATACONN));
signal(SIGUSR1, TransOK);
signal(SIGCHLD, SIG_IGN);
if (fork() == 0)
{
if (lsdir(1) == -1)
{
//.................
close(State.Socket);
return -1;
}
close(State.Socket);
exit(0);
}
close(State.Socket);
return 0;
}
/* 列出目录 */
int lsdir(int flag)
{
struct stat sbuf;
mode_t mode;
char buf[MAX_BUF_SIZE];
DIR *dp;
struct dirent *link;
dp = opendir(".");
if (dp == NULL)
return -1;
while ((link = readdir(dp)) != 0)
{
memset(buf, 0, MAX_BUF_SIZE);
if (lstat(link->d_name, &sbuf) == -1)
continue;
if (strcmp(link->d_name, ".") == 0 || strcmp(link->d_name, "..") == 0)
continue;
if (flag == 1)
{
sprintf(buf, "%s\r\n", link->d_name);
Write(State.Socket, buf, strlen(buf));
}
else
{
mode=sbuf.st_mode;
char perms[] = "----------";
perms[0]='?';
switch (mode & S_IFMT)
{
case S_IFREG:
perms[0] = '-';
break;
case S_IFDIR:
perms[0] = 'd';
break;
case S_IFLNK:
perms[0] = 'l';
break;
case S_IFIFO:
perms[0] = 'p';
break;
case S_IFSOCK:
perms[0] = 's';
break;
case S_IFCHR:
perms[0] = 'c';
break;
case S_IFBLK:
perms[0] = 'b';
break;
}
if (mode & S_IRUSR)
perms[1] = 'r';
if (mode & S_IWUSR)
perms[2] = 'w';
if (mode & S_IXUSR)
perms[3] = 'x';
if (mode & S_IRGRP)
perms[4] = 'r';
if (mode & S_IWGRP)
perms[5] = 'w';
if (mode & S_IXGRP)
perms[6] = 'x';
if (mode & S_IROTH)
perms[7] = 'r';
if (mode & S_IWOTH)
perms[8] = 'w';
if (mode & S_IXOTH)
perms[9] = 'x';
perms[10] = '\0';
int off = 0;
memset(buf, 0, sizeof(buf));
off += sprintf(buf+off, "%s ", perms);
off += sprintf(buf+off, " %3d %-8d %-8d ", sbuf.st_nlink, sbuf.st_uid, sbuf.st_gid);
off += sprintf(buf+off, "%8lu ", (unsigned long)sbuf.st_size);
char *p_date_format = "%b %e %H:%M";
char datebuf[13]={0};
struct tm *p_tm;
struct timeval tv;
long local_time;
gettimeofday(&tv, NULL);
local_time = tv.tv_sec;
p_tm = localtime(&sbuf.st_mtime);
if (sbuf.st_mtime > local_time || (local_time - sbuf.st_mtime) > 60*60*24*182)
p_date_format = "%b %e %Y";
strftime(datebuf, sizeof(datebuf), p_date_format, p_tm);
off += sprintf (buf+off, "%s ", datebuf);
if (S_ISLNK(sbuf.st_mode))
{
char tmp[1024]={0};
readlink(link->d_name,tmp,sizeof(tmp));
off += sprintf (buf+off, "%s -> %s", link->d_name,tmp);
}
else
off += sprintf (buf+off, "%s", link->d_name);
off += sprintf (buf+off, "%s", "\r\n");
Write(State.Socket, buf, strlen(buf));
}
}
close(State.Socket);
closedir(dp);
Write(State.s, FTP_TRANSFEROK, strlen(FTP_TRANSFEROK));
kill(getppid(), SIGUSR1);
return 0;
}
/* 返回文件大小 */
int do_size(char *file)
{
struct stat filestat;
char m213[MIN_BUF_SIZE];
memset(&filestat, 0, sizeof(filestat));
lstat(file, &filestat);
memset(m213, 0, sizeof(m213));
sprintf(m213, "213 %d\r\n", filestat.st_size);
Write(State.s, m213, strlen(m213));
return 0;
}
/* 回到上一层目录 */
int do_cdup(char *param)
{
if (strcmp(State.uname, "ftp") == 0)
{
char buf[MIN_BUF_SIZE];
char buf2[MIN_BUF_SIZE];
memset(buf, 0, sizeof(buf));
memset(buf2, 0, sizeof(buf2));
getcwd(buf, MIN_BUF_SIZE);
GetHomeDir(State.uname, buf2);
if (strcmp(buf, buf2) == 0)
{
Write(State.s, FTP_CWDOK, strlen(FTP_CWDOK));
return 1;
}
}
chdir("..");
Write(State.s, FTP_CWDOK, strlen(FTP_CWDOK));
return 0;
}
/* 修改传输模式 */
int do_type(char *tType)
{
if (strcmp(tType, "A") == 0)
{
strcpy(State.type, "ASCII");
Write(State.s, "200 Switching to ASCII Mode\r\n", strlen("200 Switching to ASCII Mode\r\n"));
return 0;
}
else
{
strcpy(State.type, "IMAGE");
Write(State.s, "200 Switching to IMAGE Mode\r\n", strlen("200 Switching to IMAGE Mode\r\n"));
return 0;
}
}
/* 主动模式 */
int do_port(char *ipPort)
{
char ip[MIN_BUF_SIZE];
int port;
GetIpPort(ipPort, ip, &port);
strcpy(State.ip, ip);
State.port = port;
State.mode = 1;
Write(State.s, FTP_PORTOK, strlen(FTP_PORTOK));
return 0;
}
/* 被动模式 */
int do_pasv(char *param)
{
int cSize, port;
char ip[MIN_BUF_SIZE];
char sIp[MIN_BUF_SIZE];
socklen_t namelen;
struct sockaddr_in name;
struct sockaddr_in addr;
memset(ip, 0, sizeof(ip));
if ((State.sSocket = NetContral(NULL, 0, -1, 2)) == SERVER_LISTEN_EXCEPTION)
return -1;
namelen = sizeof(name);
getsockname(State.sSocket, (struct sockaddr*)&name, &namelen);
port = ntohs(name.sin_port);
GetLocalIp(ip);
PutIpPort(sIp, ip, port);
strcpy(State.ip, ip);
State.port = port;
State.mode = 2;
char m227[MAX_BUF_SIZE];
memset(m227, 0, sizeof(m227));
sprintf(m227, "227 Entering Passive Mode(%s)\r\n", sIp);
Write(State.s, m227, strlen(m227));
return 0;
}
/* 连接 */
int Connect()
{
if (State.mode == 1)
{
int oldid = getuid();
seteuid(0);
if ((State.Socket = NetContral(State.ip, State.port, 20, 1)) == CLIENT_CONNECT_FAIL)
{
seteuid(oldid);
return -1;
}
else
{
seteuid(oldid);
return 0;
}
}
else
{
State.Socket = accept(State.sSocket, NULL, NULL);
close(State.sSocket);
State.sSocket = -1;
return 0;
}
}
/* 下载OK */
void DownloadOK(int i)
{
Write(State.s, FTP_TRANSFEROK, strlen(FTP_TRANSFEROK));
close(State.Socket);
State.Socket = -1;
}
/* 下载 */
int do_retr(char *fileName)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -