46 #ifndef CURL_DISABLE_FTP 70 enum protection_level level;
73 { PROT_CLEAR,
"clear" },
74 { PROT_SAFE,
"safe" },
75 { PROT_CONFIDENTIAL,
"confidential" },
76 { PROT_PRIVATE,
"private" }
79 static enum protection_level
80 name_to_level(
const char *
name)
83 for(i = 0; i < (int)
sizeof(level_names)/(int)
sizeof(level_names[0]); i++)
85 return level_names[i].level;
91 static char level_to_char(
int level)
98 case PROT_CONFIDENTIAL:
115 static int ftp_send_command(
struct connectdata *conn,
const char *message, ...)
120 char print_buffer[50];
122 va_start(args, message);
123 vsnprintf(print_buffer,
sizeof(print_buffer), message, args);
171 const char *to_p = to;
193 struct krb5buffer *
buf)
199 result = socket_read(fd, &len,
sizeof(len));
212 result = socket_read(fd, buf->data, len);
215 buf->size = conn->mech->decode(conn->app_data, buf->
data, len,
216 conn->data_prot, conn);
222 buffer_read(
struct krb5buffer *buf,
void *
data,
size_t len)
224 if(buf->size - buf->index < len)
225 len = buf->size - buf->index;
226 memcpy(data, (
char *)buf->data + buf->index, len);
236 size_t total_read = 0;
242 if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
243 return read(fd, buffer, len);
245 if(conn->in_buffer.eof_flag) {
246 conn->in_buffer.eof_flag = 0;
250 bytes_read = buffer_read(&conn->in_buffer, buffer, len);
252 total_read += bytes_read;
253 buffer += bytes_read;
256 if(read_data(conn, fd, &conn->in_buffer))
258 if(conn->in_buffer.size == 0) {
260 conn->in_buffer.eof_flag = 1;
263 bytes_read = buffer_read(&conn->in_buffer, buffer, len);
265 total_read += bytes_read;
266 buffer += bytes_read;
276 const char *
from,
int length)
278 int bytes, htonl_bytes;
283 enum protection_level prot_level = conn->data_prot;
284 bool iscmd = (prot_level == PROT_CMD)?
TRUE:
FALSE;
286 DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
289 if(!strncmp(from,
"PASS ", 5) || !strncmp(from,
"ACCT ", 5))
290 prot_level = PROT_PRIVATE;
292 prot_level = conn->command_prot;
294 bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
296 if(!buffer || bytes <= 0)
301 &cmd_buffer, &cmd_size);
307 static const char *enc =
"ENC ";
308 static const char *mic =
"MIC ";
309 if(prot_level == PROT_PRIVATE)
310 socket_write(conn, fd, enc, 4);
312 socket_write(conn, fd, mic, 4);
314 socket_write(conn, fd, cmd_buffer, cmd_size);
315 socket_write(conn, fd,
"\r\n", 2);
316 infof(conn->
data,
"Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
322 htonl_bytes = htonl(bytes);
323 socket_write(conn, fd, &htonl_bytes,
sizeof(htonl_bytes));
330 const char *buffer,
size_t length)
332 ssize_t tx = 0, len = conn->buffer_size;
334 len -= conn->mech->overhead(conn->app_data, conn->data_prot,
339 if(length < (
size_t)len)
352 const void *buffer,
size_t len,
CURLcode *err)
356 return sec_write(conn, fd, buffer, len);
359 int Curl_sec_read_msg(
struct connectdata *conn,
char *buffer,
360 enum protection_level level)
367 size_t decoded_sz = 0;
374 DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
377 if(error || decoded_sz == 0)
380 if(decoded_sz > (
size_t)INT_MAX) {
386 decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
388 if(decoded_len <= 0) {
394 buf[decoded_len] =
'\n';
398 buf[decoded_len] =
'\0';
405 (void)sscanf(buf,
"%d", &ret_code);
407 if(buf[decoded_len - 1] ==
'\n')
408 buf[decoded_len - 1] =
'\0';
416 static int sec_set_protection_level(
struct connectdata *conn)
420 static unsigned int buffer_size = 1 << 20;
421 enum protection_level level = conn->request_data_prot;
423 DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
425 if(!conn->sec_complete) {
426 infof(conn->
data,
"Trying to change the protection level after the" 427 "completion of the data exchange.\n");
432 if(conn->data_prot == level)
436 code = ftp_send_command(conn,
"PBSZ %u", buffer_size);
441 failf(conn->
data,
"Failed to set the protection's buffer size.");
444 conn->buffer_size = buffer_size;
449 (void)sscanf(pbsz,
"PBSZ=%u", &buffer_size);
450 if(buffer_size < conn->buffer_size)
451 conn->buffer_size = buffer_size;
456 code = ftp_send_command(conn,
"PROT %c", level_to_char(level));
462 failf(conn->
data,
"Failed to set the protection level.");
466 conn->data_prot = level;
467 if(level == PROT_PRIVATE)
468 conn->command_prot = level;
474 Curl_sec_request_prot(
struct connectdata *conn,
const char *level)
476 enum protection_level l = name_to_level(level);
480 conn->request_data_prot = l;
488 void *tmp_allocation;
491 tmp_allocation =
realloc(conn->app_data, mech->
size);
492 if(tmp_allocation == NULL) {
493 failf(data,
"Failed realloc of size %u", mech->
size);
497 conn->app_data = tmp_allocation;
500 ret = mech->
init(conn->app_data);
502 infof(data,
"Failed initialization for %s. Skipping it.\n",
508 infof(data,
"Trying mechanism %s...\n", mech->
name);
509 ret = ftp_send_command(conn,
"AUTH %s", mech->
name);
517 infof(data,
"Mechanism %s is not supported by the server (server " 518 "returned ftp code: 504).\n", mech->
name);
521 infof(data,
"Mechanism %s was rejected by the server (server returned " 522 "ftp code: 534).\n", mech->
name);
526 infof(data,
"server does not support the security extensions\n");
535 ret = mech->
auth(conn->app_data, conn);
545 conn->sec_complete = 1;
550 conn->command_prot = PROT_SAFE;
553 (void)sec_set_protection_level(conn);
562 return choose_mech(conn);
569 if(conn->mech != NULL && conn->mech->end)
570 conn->mech->end(conn->app_data);
571 free(conn->app_data);
572 conn->app_data = NULL;
573 if(conn->in_buffer.
data) {
575 conn->in_buffer.
data = NULL;
576 conn->in_buffer.size = 0;
577 conn->in_buffer.index = 0;
579 conn->in_buffer.eof_flag = 0;
581 conn->sec_complete = 0;
582 conn->data_prot = PROT_CLEAR;
int Curl_debug(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size, struct connectdata *conn)
CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
CURLcode Curl_base64_decode(const char *src, unsigned char **outptr, size_t *outlen)
CURLcode Curl_write_plain(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written)
size_t curlx_sitouz(int sinum)
CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen)
CURLcode Curl_GetFTPResponse(ssize_t *nreadp, struct connectdata *conn, int *ftpcode)
#define realloc(ptr, size)
int curlx_uztosi(size_t uznum)
UNITTEST_START int result
static srvr_sockaddr_union_t from
CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, ssize_t *n)
memcpy(filename, filename1, strlen(filename1))
void * Curl_saferealloc(void *ptr, size_t size)
int(* auth)(void *, struct connectdata *)
int curlx_sztosi(ssize_t sznum)
#define checkprefix(a, b)