ftpd.c
来自「C实现的MUD,对大家基本入门网络游戏很有帮助!」· C语言 代码 · 共 1,581 行 · 第 1/3 页
C
1,581 行
CHECK_LOGIN();
/* Send directory file list (like exec'ing "ls") */
if ( sizeof( command ) > 1 )
tmp = get_path( fd, command[ 1 ] );
else
tmp = socket_info[ fd ][ CWD ];
if ( check_valid_read( tmp, fd ) ) {
tmp2 = ls( tmp, 0, fd );
if (tmp2 == "")
socket_write( fd, "550 No files found.\n");
else
data_conn( fd, tmp2, "ls", STRING );
} else
PERMISSION_DENIED550(tmp);
break;
case "xpwd": // print the current working directory (deprecated)
case "pwd": // print the current working directory
CHECK_LOGIN();
socket_write( fd, sprintf("257 \"%s\" is the current directory.\n",
socket_info[ fd ][ CWD ]) );
break;
case "xcup": // change to parent of current working directory (deprecated)
case "cdup": // change to parent of current working directory
if (sizeof(command) > 1)
command[ 1 ] = "..";
else
command += ({ ".." });
case "xcwd": // change working directory (deprecated)
case "cwd": // change working directory
CHECK_LOGIN();
if ( sizeof( command ) > 1 )
tmp = get_path( fd, command[ 1 ] );
else
tmp = socket_info[ fd ][ CWD ];
if ( check_valid_read( tmp, fd ) ) {
tmp = get_path( fd, tmp );
if ( !directory_exists( tmp ) ) {
socket_write( fd, sprintf("550 %s: Not a directory.\n", tmp) );
break;
}
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_CD_SIZE
log_file( LOG_FILE, sprintf("%s cd to %s.\n", UNAME, tmp) );
#endif
socket_info[ fd ][ CWD ] = tmp;
#ifdef MESSAGE_FILES
if (file_size(tmp + "/.message") > 0) {
tmp = read_file(tmp + "/.message");
tmp = tmp[0..<2];
tmp = sprintf("250- %s\n250 %s command successful.\n",
replace_string(tmp, "\n", "\n250- "), command[0]);
socket_write(fd, tmp);
} else
#endif
socket_write( fd, sprintf("250 %s command successful.\n",
command[0]) );
} else
PERMISSION_DENIED550(command[ 1 ]);
break;
case "quit": // terminate session
socket_write( fd, "221 Goodbye.\n" );
logout( fd );
lose_user( fd );
break;
case "type": // specify data transfer type
CHECK_CMD(1);
if ( command[ 1 ] == "I" ) {
socket_info[ fd ][ TYPE ] = BINARY;
socket_write( fd, "200 Type set to I.\n" );
} else
if ( command[ 1 ] == "A" ) {
socket_info[ fd ][ TYPE ] = STRING;
socket_write( fd, "200 Type set to A.\n" );
} else
socket_write( fd, sprintf("504 Type %s not implemented.\n",
command[ 1 ]) );
break;
case "stat": // return status of server
socket_write( fd, sprintf(
"211 FTP server status: %s FTP Version %s\r\n",
THE_MUD_NAME, FTPD_VERSION) );
socket_write( fd, sprintf(" Connected to %s\r\n", USITE) );
if ( socket_info[ fd ][ LOGGED_IN ] )
socket_write( fd, sprintf(" Logged in as %s\r\n", UNAME) );
else
if ( UNAME )
socket_write( fd, " Waiting for password.\r\n" );
else
socket_write( fd, " Waiting for user name.\r\n" );
socket_write( fd, " TYPE: ASCII, FORM: Nonprint; STRUcture: "
"File; transfer MODE: Stream.\r\n" );
if ( socket_info[ fd ][ DATA_FD ] )
socket_write( fd, " Data connection open.\r\n" );
else
if ( socket_info[ fd ][ DATA_ADDR ] )
socket_write( fd, sprintf(" %s %d\r\n",
socket_info[ fd ][ DATA_ADDR ],
socket_info[ fd ][ DATA_PORT ]) );
else
socket_write( fd, " No data connection.\r\n" );
socket_write( fd, "211 End of status.\n" );
break;
case "abor": // abort previous command
/* Stops recvs and stors. At least thats what it is supposed to do. */
if ( socket_info[ fd ][ DATA_FD ] ) {
socket_write( fd,
"426 Transfer aborted. Data connection closed.\n");
#ifdef FILE_LOCKING
if ( (socket_info[ fd ][ DATA_FD ])[ TYPE ] == DOWNLOAD )
flock_wrapper( (socket_info[ fd ][ DATA_FD ])[ PATH ],
F_UNLOCK, socket_info[ fd ] );
#endif
socket_close( socket_info[ fd ][ DATA_FD ] );
map_delete( socket_info[fd], DATA_FD );
}
socket_write( fd, "226 Abort successful.\n" );
break;
case "syst": // show operating system type of server system
socket_write( fd, "215 UNIX Type: MUD\n" );
break;
case "xmkd": // make a directory (deprecated)
case "mkd": // make a directory
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if (file_size( tmp ) == -1) {
if (check_valid_write(tmp, fd)) {
if (mkdir(tmp)) {
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s mkd %s.\n",
UNAME, tmp) );
#endif
socket_write(fd, sprintf("257 %s command successful.\n",
command[ 0 ]) );
} else
socket_write(fd, sprintf("550 %s command failed.\n",
command[ 0 ]) );
} else
PERMISSION_DENIED550(command[ 1 ]);
} else
socket_write(fd, sprintf(
"550 %s: Directory or file already exists.\n",
command[ 1 ]));
break;
case "xrmd": // remove a directory (deprecated)
case "rmd": // remove a directory
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if (file_size( tmp ) == -2) {
if (check_valid_write(tmp, fd)) {
if (rmdir(tmp)) {
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s rmd %s.\n",
UNAME, tmp) );
#endif
socket_write(fd, sprintf("250 %s command successful.\n",
command[ 0 ]) );
} else
socket_write(fd, sprintf("550 %s command failed.\n",
command[ 0 ]) );
} else
PERMISSION_DENIED550(command[ 1 ]);
} else
socket_write(fd, sprintf("550 %s: No such file or directory.\n",
command[ 1 ]) );
break;
case "site": // non-standard commands
CHECK_LOGIN();
CHECK_CMD(1);
switch (lower_case(command[ 1 ])) {
case "idle":
if (sizeof(command) < 3) {
socket_write(fd,
sprintf("200 Current IDLE time limit is %d seconds; max %d\n",
socket_info[fd][IDLE_SETTING], MAX_FTPD_IDLE));
break;
}
if (!sscanf(command[2], "%d", i)) {
socket_write(fd, "550 SITE IDLE command failed.\n");
break;
}
i = (i < FTPD_TIMEOUT ? FTPD_TIMEOUT : (i > MAX_FTPD_IDLE ? MAX_FTPD_IDLE : i));
socket_info[fd][IDLE_SETTING] = i;
socket_write(fd, sprintf("200 Maximum IDLE time set to %d seconds\n", i));
break;
case "time":
socket_write(fd,
sprintf("200 Local TIME is %s.\n", ctime(time())[4..15] ) );
break;
case "help":
if (sizeof(command) > 1) {
tmp = lower_case(command[1]);
if (!undefinedp(sitecmdtab[ tmp ])) {
misc = sitecmdtab[ tmp ];
if (misc[1])
socket_write(fd, sprintf("214 Syntax: %s %s.\n",
misc[0], misc[2]) );
else
socket_write(fd, sprintf("214 %s %s; unimplemented.\n",
misc[0], misc[2]) );
} else {
socket_write(fd, sprintf("502 Unknown command %s.\n",
command[ 1 ]) );
}
} else {
socket_write(fd, "214- The following SITE commands are recognized "
"(* =>'s unimplemented).\n214-\n");
misc = keys(sitecmdtab);
s = sizeof(misc);
tmp = "214- ";
for (i = 0; i < s; i++) {
tmp += sprintf("%c%-7s", sitecmdtab[misc[i]][1] ? ' ' : '*',
sitecmdtab[misc[i]][0]);
if (i % 8 == 7) {
socket_write(fd, tmp + "\n");
tmp = "214- ";
}
}
if (i % 8)
socket_write(fd, tmp + "\n");
socket_write(fd, sprintf("214-\n214 Direct comments to %s.\n",
FTP_BUGS_EMAIL));
}
break;
case "chmod":
case "umask":
socket_write( fd, sprintf("502 '%s' command not implemented.\n",
command[ 0 ]) );
break;
default:
socket_write( fd, sprintf("500 '%s %s' command "
"not understood.\n", command[ 0 ], command[ 1 ]) );
break;
}
break;
case "rnfr": // specify rename-from file name
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[1] );
i = file_size( tmp );
if (i == -2) {
socket_write( fd, sprintf("550 %s: Not a plain file.\n",
command[ 1 ]) );
} else if (i == -1) {
socket_write(fd, sprintf("550 %s: No such file or directory.\n",
command[ 1 ]) );
} else if (check_valid_write(tmp, fd)) {
socket_info[fd][FROMNAME] = tmp;
socket_write(fd, "350 File exists, ready for destination name.\n");
} else {
PERMISSION_DENIED550(command[ 1 ]);
}
break;
case "rnto": // specify rename-to file name
CHECK_LOGIN();
CHECK_CMD(1);
if (!socket_info[fd][FROMNAME]) {
socket_write(fd, "503 Bad sequence of commands.\n");
} else {
tmp = get_path( fd, command[1] );
i = file_size( tmp );
if (i != -1) {
socket_write(fd, sprintf(
"550 %s: Directory or file already exists.\n",
command[ 1 ]) );
} else if (!check_valid_write(tmp, fd)) {
PERMISSION_DENIED550(command[ 1 ]);
} else {
tmp2 = socket_info[fd][FROMNAME];
if (!check_valid_write(tmp2, fd)) {
PERMISSION_DENIED550(tmp2);
socket_info[fd][FROMNAME] = 0;
} else {
#ifdef FILE_LOCKING
if (flock_wrapper(tmp, F_LOCK, fd)) {
if (flock_wrapper(tmp2, F_LOCK, fd)) {
#endif
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s rnfr %s "
"rnto %s.\n", UNAME, tmp2, tmp) );
#endif
if (catch( i = rename(tmp2, tmp) ) || i)
socket_write(fd,
"550 RNTO command failed.\n");
else
socket_write(fd,
"250 RNTO command successful.\n");
#ifdef FILE_LOCKING
flock_wrapper(tmp2, F_UNLOCK, fd);
flock_wrapper(tmp, F_UNLOCK, fd);
socket_info[fd][FROMNAME] = 0;
} else {
PERMISSION_DENIED550(tmp2);
flock_wrapper(tmp, F_UNLOCK, fd);
}
} else {
PERMISSION_DENIED550(command[ 1 ]);
}
#endif
}
}
}
break;
case "help": // give help information
if (sizeof(command) > 1) {
tmp = lower_case(command[1]);
if (!undefinedp(cmdtab[ tmp ])) {
misc = cmdtab[ tmp ];
if (misc[1])
socket_write(fd, sprintf("214 Syntax: %s %s.\n",
misc[0], misc[2]) );
else
socket_write(fd, sprintf("214 %s %s; unimplemented.\n",
misc[0], misc[2]) );
} else {
socket_write(fd, sprintf("502 Unknown command %s.\n",
command[ 1 ]) );
}
} else {
socket_write(fd, "214- The following commands are recognized "
"(* =>'s unimplemented).\n214-\n");
misc = keys(cmdtab);
s = sizeof(misc);
tmp = "214- ";
for (i = 0; i < s; i++) {
tmp += sprintf("%c%-7s", cmdtab[misc[i]][1] ? ' ' : '*',
cmdtab[misc[i]][0]);
if (i % 8 == 7) {
socket_write(fd, tmp + "\n");
tmp = "214- ";
}
}
if (i % 8)
socket_write(fd, tmp + "\n");
socket_write(fd, sprintf("214-\n214 Direct comments to %s.\n",
FTP_BUGS_EMAIL));
}
break;
case "rest": // restart command/incomplete transfer
if (sizeof(command) > 1) {
rest_pos = atoi(command[1]);
socket_write( fd, sprintf("350 Restarting at %d.\n", rest_pos) );
} else
socket_write( fd, "214 command without parameter.\n" );
break;
case "acct": // specify account (ignored)
case "mail": // mail to user
case "mlfl": // mail file
case "mode": // specify data transfer mode
case "mrcp": // mail recipient
case "mrsq": // mail recipient scheme question
case "msnd": // mail send to terminal
case "msam": // mail send to terminal and mailbox
case "msom": // mail send to terminal or mailbox
case "pasv": // prepare for server-to-server transfer
case "rein": // reinitialize server state
case "smnt": // structure mount
case "stru": // specify data transfer/file structure
socket_write( fd, sprintf("502 '%s' command not implemented.\n",
command[ 0 ]) );
break;
default:
socket_write( fd, sprintf("500 '%s': command not understood.\n",
command[ 0 ]) );
break;
}
} /* parse_com() */
/*
* accept user command
*/
void in_read_callback( int fd, string str )
{
string *command;
int i, j;
if (undefinedp( socket_info[ fd ][ CONNECTED ] )
|| !socket_info[ fd ][ CONNECTED ] )
return;
if (!str) str = "";
str = replace_string( str, "\r", "" );
command = explode( str, "\n" ) - ({ 0 });
j = sizeof(command);
for ( i = 0; i < j; i++ )
parse_comm( fd, command[i] );
}
/*
* Handle when the socket closes unexpectedly
*/
void in_close_callback( int fd )
{
/*
* Handle case where user aborts (eg CTRL-C) their ftp client, causing
* connection to close before getting to login prompt.
*/
if (undefinedp(socket_info[fd][CONNECTED])) return;
logout( fd );
lose_user( fd );
}
/*
* resolve path (absolute vs relative) ... does not validate path here
*/
protected string get_path( int fd, string str )
{
string apath;
apath = resolve_path(socket_info[fd][CWD], str);
#ifdef ANONYMOUS_FTP
if( UNAME == "anonymous" && strsrch(apath, FTP_DIR)!=0 )
apath = FTP_DIR + apath;
#endif
return apath;
}
protected void check_connections()
{
int *sockets, i, limit;
int pfd;
sockets = keys( socket_info );
i = sizeof( sockets );
/*
* check control connections for idle users
*/
while ( i-- ) {
if ( !undefinedp(socket_info[ sockets[i]][LAST_DATA]) ) {
limit = time() - socket_info[ sockets[i]][IDLE_SETTING];
if ( socket_info[ sockets[i]][LAST_DATA] < limit ) {
socket_write( sockets[i],
"421 Timeout: closing control session.\n" );
logout( sockets[i] );
lose_user( sockets[i] );
}
}
}
sockets = keys( socket_info );
i = sizeof( sockets );
/*
* check data connections for orphans
*/
while ( i-- ) {
if (!undefinedp( socket_info[ sockets[i] ][ PARENT_FD ] )) {
pfd = socket_info[ sockets[i] ][ PARENT_FD ];
if (undefinedp(socket_info[ pfd ])) {
#ifdef FILE_LOCKING
if (!undefinedp(socket_info[ sockets[i] ][ TYPE ]) &&
socket_info[ sockets[i] ][ TYPE ] == DOWNLOAD ) {
flock_wrapper( socket_info[ sockets[i] ][ PATH ], F_UNLOCK,
sockets[i] );
}
#endif
lose_connection( sockets[i] );
}
}
}
call_out( "check_connections", 3 * 60 );
}
void resolve_callback( string address, string resolved, int key )
{
int id;
/*
* An example where these two errors can occur:
* update the ftpd daemon while a user is logging in
*/
if ( undefinedp( id = temp_map[ key ] ) ) {
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("No such key in temp_map: %d.\n", key) )
#endif
;
} else if ( undefinedp( socket_info[ id ] )) {
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("No such fd in socket_info: %d.\n", id) )
#endif
;
} else {
if ( address && address != "" )
socket_info[id][USER_SITE] = address;
// else retain unresolved ip number address
}
}
void remove()
{
if (number_of_users
&& this_player(1)
&& wizhood(this_player()) != "(admin)" )
error( "Cannot destruct while there are active ftp sessions.\n" );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?