scp: Do not allow newlines in pushed files names
When pushing files or directories, encode the newlines contained in the names as the string "\\n". This way the user cannot inject protocol messages through the file name. Fixes T189 Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org> Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Этот коммит содержится в:
родитель
c9ce8fa40b
Коммит
bab7ba0146
87
src/scp.c
87
src/scp.c
@ -323,6 +323,8 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
|
||||
int rc;
|
||||
char *dir = NULL;
|
||||
char *perms = NULL;
|
||||
char *vis_encoded = NULL;
|
||||
size_t vis_encoded_len;
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
@ -340,16 +342,40 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
perms = ssh_scp_string_mode(mode);
|
||||
if (perms == NULL) {
|
||||
SAFE_FREE(dir);
|
||||
ssh_set_error_oom(scp->session);
|
||||
return SSH_ERROR;
|
||||
vis_encoded_len = (2 * strlen(dir)) + 1;
|
||||
vis_encoded = (char *)calloc(1, vis_encoded_len);
|
||||
if (vis_encoded == NULL) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Failed to allocate buffer to vis encode directory name");
|
||||
goto error;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
|
||||
rc = ssh_newline_vis(dir, vis_encoded, vis_encoded_len);
|
||||
if (rc <= 0) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Failed to vis encode directory name");
|
||||
goto error;
|
||||
}
|
||||
|
||||
perms = ssh_scp_string_mode(mode);
|
||||
if (perms == NULL) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Failed to get directory permission string");
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"SCP pushing directory %s with permissions '%s'",
|
||||
vis_encoded, perms);
|
||||
|
||||
/* Use vis encoded directory name */
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"D%s 0 %s\n",
|
||||
perms, vis_encoded);
|
||||
|
||||
SAFE_FREE(dir);
|
||||
SAFE_FREE(perms);
|
||||
SAFE_FREE(vis_encoded);
|
||||
|
||||
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
@ -363,6 +389,13 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
SAFE_FREE(dir);
|
||||
SAFE_FREE(perms);
|
||||
SAFE_FREE(vis_encoded);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,6 +460,8 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
|
||||
int rc;
|
||||
char *file = NULL;
|
||||
char *perms = NULL;
|
||||
char *vis_encoded = NULL;
|
||||
size_t vis_encoded_len;
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
@ -443,18 +478,41 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
|
||||
ssh_set_error_oom(scp->session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
vis_encoded_len = (2 * strlen(file)) + 1;
|
||||
vis_encoded = (char *)calloc(1, vis_encoded_len);
|
||||
if (vis_encoded == NULL) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Failed to allocate buffer to vis encode file name");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_newline_vis(file, vis_encoded, vis_encoded_len);
|
||||
if (rc <= 0) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Failed to vis encode file name");
|
||||
goto error;
|
||||
}
|
||||
|
||||
perms = ssh_scp_string_mode(mode);
|
||||
if (perms == NULL) {
|
||||
SAFE_FREE(file);
|
||||
ssh_set_error_oom(scp->session);
|
||||
return SSH_ERROR;
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Failed to get file permission string");
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"SCP pushing file %s, size %" PRIu64 " with permissions '%s'",
|
||||
file, size, perms);
|
||||
snprintf(buffer, sizeof(buffer), "C%s %" PRIu64 " %s\n", perms, size, file);
|
||||
vis_encoded, size, perms);
|
||||
|
||||
/* Use vis encoded file name */
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"C%s %" PRIu64 " %s\n",
|
||||
perms, size, vis_encoded);
|
||||
|
||||
SAFE_FREE(file);
|
||||
SAFE_FREE(perms);
|
||||
SAFE_FREE(vis_encoded);
|
||||
|
||||
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
@ -472,6 +530,13 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
|
||||
scp->state = SSH_SCP_WRITE_WRITING;
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
SAFE_FREE(file);
|
||||
SAFE_FREE(perms);
|
||||
SAFE_FREE(vis_encoded);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user