mirror of
https://github.com/wiiu-env/ftpiiu_plugin.git
synced 2024-11-18 02:39:21 +01:00
Improve pathname encoding compatibility
This commit is contained in:
parent
b0d0b03874
commit
7ffa6d6255
172
source/ftp.c
172
source/ftp.c
@ -1,3 +1,7 @@
|
|||||||
|
/* This is FTP server implementation is based on RFC 959
|
||||||
|
* (https://tools.ietf.org/html/rfc959) and suggested implementation details
|
||||||
|
* from https://cr.yp.to/ftp/filesystem.html
|
||||||
|
*/
|
||||||
#include "ftp.h"
|
#include "ftp.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -659,42 +663,36 @@ ftp_session_transfer(ftp_session_t *session)
|
|||||||
} while(rc == 0);
|
} while(rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! escape a buffer
|
/*! encode a path
|
||||||
*
|
*
|
||||||
* @param[in] buffer buffer to escape
|
* @param[in] path path to encode
|
||||||
* @param[in,out] len buffer length
|
* @param[in,out] len path length
|
||||||
* @param[in] quotes whether to escape quotes
|
* @param[in] quotes whether to encode quotes
|
||||||
*
|
*
|
||||||
* @returns escaped buffer
|
* @returns encoded path
|
||||||
*
|
*
|
||||||
* @note The caller must free the returned buffer
|
* @note The caller must free the returned path
|
||||||
*/
|
*/
|
||||||
static char*
|
static char*
|
||||||
escape_buffer(const char *buffer,
|
encode_path(const char *path,
|
||||||
size_t *len,
|
size_t *len,
|
||||||
bool quotes)
|
bool quotes)
|
||||||
{
|
{
|
||||||
|
bool enc = false;
|
||||||
size_t i, diff = 0;
|
size_t i, diff = 0;
|
||||||
char *out, *p = (char*)buffer;
|
char *out, *p = (char*)path;
|
||||||
|
|
||||||
/* check for \r that needs to be escaped */
|
/* check for \n that needs to be encoded */
|
||||||
do
|
if(memchr(p, '\n', *len) != NULL)
|
||||||
{
|
enc = true;
|
||||||
p = memchr(p, '\r', buffer + *len - p);
|
|
||||||
if(p != NULL)
|
|
||||||
{
|
|
||||||
++p;
|
|
||||||
++diff;
|
|
||||||
}
|
|
||||||
} while(p != NULL);
|
|
||||||
|
|
||||||
if(quotes)
|
if(quotes)
|
||||||
{
|
{
|
||||||
/* check for " that needs to be escaped */
|
/* check for " that needs to be encoded */
|
||||||
p = (char*)buffer;
|
p = (char*)path;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
p = memchr(p, '"', buffer + *len - p);
|
p = memchr(p, '"', path + *len - p);
|
||||||
if(p != NULL)
|
if(p != NULL)
|
||||||
{
|
{
|
||||||
++p;
|
++p;
|
||||||
@ -703,38 +701,71 @@ escape_buffer(const char *buffer,
|
|||||||
} while(p != NULL);
|
} while(p != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if an escape was needed */
|
/* check if an encode was needed */
|
||||||
if(diff == 0)
|
if(!enc && diff == 0)
|
||||||
return strdup(buffer);
|
return strdup(path);
|
||||||
|
|
||||||
/* escape \r */
|
/* allocate space for encoded path */
|
||||||
p = out = (char*)malloc(*len + diff);
|
p = out = (char*)malloc(*len + diff);
|
||||||
if(out == NULL)
|
if(out == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* copy the buffer while performing escapes */
|
/* copy the path while performing encoding */
|
||||||
for(i = 0; i < *len; ++i)
|
for(i = 0; i < *len; ++i)
|
||||||
{
|
{
|
||||||
if(*buffer == '\r')
|
if(*path == '\n')
|
||||||
{
|
{
|
||||||
/* escaped \r is \r\0 */
|
/* encoded \n is \0 */
|
||||||
*p++ = *buffer++;
|
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
}
|
}
|
||||||
else if(quotes && *buffer == '"')
|
else if(quotes && *path == '"')
|
||||||
{
|
{
|
||||||
/* escaped " is "" */
|
/* encoded " is "" */
|
||||||
*p++ = *buffer++;
|
*p++ = '"';
|
||||||
*p++ = '"';
|
*p++ = '"';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*p++ = *buffer++;
|
*p++ = *path;
|
||||||
|
++path;
|
||||||
}
|
}
|
||||||
|
|
||||||
*len += diff;
|
*len += diff;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! decode a path
|
||||||
|
*
|
||||||
|
* @param[in] session ftp session
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
decode_path(ftp_session_t *session)
|
||||||
|
{
|
||||||
|
size_t in, out;
|
||||||
|
size_t diff = 0;
|
||||||
|
|
||||||
|
/* decode \0 from the first command */
|
||||||
|
for(in = out = 0; in < session->cmd_buffersize && session->cmd_buffer[in] != 0; ++in)
|
||||||
|
{
|
||||||
|
if(session->cmd_buffer[in] == 0)
|
||||||
|
{
|
||||||
|
/* this is an encoded \r */
|
||||||
|
session->cmd_buffer[out++] = session->cmd_buffer[in++];
|
||||||
|
++diff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
session->cmd_buffer[out++] = session->cmd_buffer[in];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy remaining buffer */
|
||||||
|
if(diff > 0)
|
||||||
|
memmove(session->cmd_buffer + out, session->cmd_buffer + in, session->cmd_buffersize - in);
|
||||||
|
|
||||||
|
/* adjust the buffer size */
|
||||||
|
session->cmd_buffersize -= diff;
|
||||||
|
}
|
||||||
|
|
||||||
/*! send a response on the command socket
|
/*! send a response on the command socket
|
||||||
*
|
*
|
||||||
* @param[in] session ftp session
|
* @param[in] session ftp session
|
||||||
@ -1037,41 +1068,6 @@ ftp_session_connect(ftp_session_t *session)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! unescape a command
|
|
||||||
*
|
|
||||||
* @param[in] session ftp session
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
ftp_session_unescape_command(ftp_session_t *session)
|
|
||||||
{
|
|
||||||
size_t in, out;
|
|
||||||
size_t diff = 0;
|
|
||||||
|
|
||||||
/* escape \r\0 from the first command */
|
|
||||||
for(in = out = 0; in < session->cmd_buffersize && session->cmd_buffer[in] != 0; ++in)
|
|
||||||
{
|
|
||||||
if(session->cmd_buffer[in] == '\r'
|
|
||||||
&& in < session->cmd_buffersize - 1
|
|
||||||
&& session->cmd_buffer[in+1] == 0)
|
|
||||||
{
|
|
||||||
/* this is an escaped \r */
|
|
||||||
session->cmd_buffer[out++] = session->cmd_buffer[in++];
|
|
||||||
++diff;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
session->cmd_buffer[out++] = session->cmd_buffer[in];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy remaining buffer */
|
|
||||||
if(diff > 0)
|
|
||||||
memmove(session->cmd_buffer + out, session->cmd_buffer + in, session->cmd_buffersize - in);
|
|
||||||
|
|
||||||
/* adjust the buffer size */
|
|
||||||
session->cmd_buffersize -= diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! read command for ftp session
|
/*! read command for ftp session
|
||||||
*
|
*
|
||||||
* @param[in] session ftp session
|
* @param[in] session ftp session
|
||||||
@ -1185,28 +1181,36 @@ ftp_session_read_command(ftp_session_t *session,
|
|||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
/* must have at least enough data for the delimiter */
|
/* must have at least enough data for the delimiter */
|
||||||
if(session->cmd_buffersize < 2)
|
if(session->cmd_buffersize < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* look for \r\n delimiter */
|
/* look for \r\n or \n delimiter */
|
||||||
for(i = 0; i < session->cmd_buffersize-1; ++i)
|
for(i = 0; i < session->cmd_buffersize; ++i)
|
||||||
{
|
{
|
||||||
if(session->cmd_buffer[i] == '\r'
|
if(i < session->cmd_buffersize-1
|
||||||
|
&& session->cmd_buffer[i] == '\r'
|
||||||
&& session->cmd_buffer[i+1] == '\n')
|
&& session->cmd_buffer[i+1] == '\n')
|
||||||
{
|
{
|
||||||
/* we found a delimiter */
|
/* we found a \r\n delimiter */
|
||||||
session->cmd_buffer[i] = 0;
|
session->cmd_buffer[i] = 0;
|
||||||
next = &session->cmd_buffer[i+2];
|
next = &session->cmd_buffer[i+2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if(session->cmd_buffer[i] == '\n')
|
||||||
|
{
|
||||||
|
/* we found a \n delimiter */
|
||||||
|
session->cmd_buffer[i] = 0;
|
||||||
|
next = &session->cmd_buffer[i+1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if a delimiter was found */
|
/* check if a delimiter was found */
|
||||||
if(i == session->cmd_buffersize-1)
|
if(i == session->cmd_buffersize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* unescape the command */
|
/* decode the command */
|
||||||
ftp_session_unescape_command(session);
|
decode_path(session);
|
||||||
|
|
||||||
/* split command from arguments */
|
/* split command from arguments */
|
||||||
args = buffer = session->cmd_buffer;
|
args = buffer = session->cmd_buffer;
|
||||||
@ -1812,9 +1816,9 @@ list_transfer(ftp_session_t *session)
|
|||||||
session->buffersize = 0;
|
session->buffersize = 0;
|
||||||
if(build_path(session, session->lwd, dent->d_name) == 0)
|
if(build_path(session, session->lwd, dent->d_name) == 0)
|
||||||
{
|
{
|
||||||
/* escape \r as per telnet standard */
|
/* encode \n in path */
|
||||||
len = strlen(session->buffer);
|
len = strlen(session->buffer);
|
||||||
buffer = escape_buffer(session->buffer, &len, false);
|
buffer = encode_path(session->buffer, &len, false);
|
||||||
if(buffer != NULL)
|
if(buffer != NULL)
|
||||||
{
|
{
|
||||||
/* copy to the session buffer to send */
|
/* copy to the session buffer to send */
|
||||||
@ -1854,9 +1858,9 @@ list_transfer(ftp_session_t *session)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* escape \r as per telnet standard */
|
/* encode \n in path */
|
||||||
len = strlen(dent->d_name);
|
len = strlen(dent->d_name);
|
||||||
buffer = escape_buffer(dent->d_name, &len, false);
|
buffer = encode_path(dent->d_name, &len, false);
|
||||||
if(buffer != NULL)
|
if(buffer != NULL)
|
||||||
{
|
{
|
||||||
/* copy to the session buffer to send */
|
/* copy to the session buffer to send */
|
||||||
@ -2185,9 +2189,9 @@ ftp_xfer_dir(ftp_session_t *session,
|
|||||||
/* get the base name */
|
/* get the base name */
|
||||||
base = strrchr(args, '/') + 1;
|
base = strrchr(args, '/') + 1;
|
||||||
|
|
||||||
/* escape \r as per telnet standard */
|
/* encode \n in path */
|
||||||
len = strlen(base);
|
len = strlen(base);
|
||||||
buffer = escape_buffer(base, &len, false);
|
buffer = encode_path(base, &len, false);
|
||||||
if(buffer != NULL)
|
if(buffer != NULL)
|
||||||
{
|
{
|
||||||
/* copy to the session buffer to send */
|
/* copy to the session buffer to send */
|
||||||
@ -2878,9 +2882,9 @@ FTP_DECLARE(PWD)
|
|||||||
|
|
||||||
ftp_session_set_state(session, COMMAND_STATE, 0);
|
ftp_session_set_state(session, COMMAND_STATE, 0);
|
||||||
|
|
||||||
/* escape the cwd */
|
/* encode the cwd */
|
||||||
len = strlen(session->cwd);
|
len = strlen(session->cwd);
|
||||||
path = escape_buffer(session->cwd, &len, true);
|
path = encode_path(session->cwd, &len, true);
|
||||||
if(path != NULL)
|
if(path != NULL)
|
||||||
{
|
{
|
||||||
i = sprintf(buffer, "257 \"");
|
i = sprintf(buffer, "257 \"");
|
||||||
|
Loading…
Reference in New Issue
Block a user