summaryrefslogtreecommitdiffstats
path: root/lib/security.c
diff options
context:
space:
mode:
authorCurl Upstream <curl-library@cool.haxx.se>2014-09-10 06:07:58 (GMT)
committerBrad King <brad.king@kitware.com>2014-10-08 19:53:25 (GMT)
commit3fe5d9bff98b4716e219516c30d71462495324f4 (patch)
treecd369c3f671882cefde2f68a1ac8146f97c6bc84 /lib/security.c
parentf086cb372e41035260fcd9b4ed3d2cfb272f138f (diff)
downloadCMake-3fe5d9bff98b4716e219516c30d71462495324f4.zip
CMake-3fe5d9bff98b4716e219516c30d71462495324f4.tar.gz
CMake-3fe5d9bff98b4716e219516c30d71462495324f4.tar.bz2
curl 7.38.0 (reduced)
Extract upstream curl using the following shell code. url=git://github.com/bagder/curl.git && v=7.38.0 && r=202aa9f7 && paths=" CMake/* CMakeLists.txt COPYING include/curl/*.h include/curl/curlbuild.h.cmake lib/*.c lib/*.h lib/CMakeLists.txt lib/Makefile.inc lib/curl_config.h.cmake lib/libcurl.rc lib/vtls/*.c lib/vtls/*.h " && mkdir curl-$v-g$r-reduced && git clone $url curl-git && date=$(cd curl-git && git log -n 1 --format='%cd' $r) && (cd curl-git && git checkout $r && git archive --format=tar $r -- $paths) | (cd curl-$v-g$r-reduced && tar xv && rm lib/config-*.h) && echo "g$r date: $date"
Diffstat (limited to 'lib/security.c')
-rw-r--r--lib/security.c700
1 files changed, 404 insertions, 296 deletions
diff --git a/lib/security.c b/lib/security.c
index 4c9aed8..508c7b4 100644
--- a/lib/security.c
+++ b/lib/security.c
@@ -7,8 +7,11 @@
* rewrite to work around the paragraph 2 in the BSD licenses as explained
* below.
*
- * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * Copyright (c) 1998, 1999, 2013 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
+ *
+ * Copyright (C) 2001 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,42 +41,39 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. */
-#include "setup.h"
+#include "curl_setup.h"
#ifndef CURL_DISABLE_FTP
-#ifdef HAVE_KRB4
+#ifdef HAVE_GSSAPI
-#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
-#include <curl/mprintf.h>
-
-#include <stdlib.h>
-#include <string.h>
+#ifdef HAVE_NETDB_H
#include <netdb.h>
+#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
#endif
#include "urldata.h"
-#include "krb4.h"
-#include "base64.h"
-#include "sendf.h"
+#include "curl_base64.h"
+#include "curl_memory.h"
+#include "curl_sec.h"
#include "ftp.h"
-#include "memory.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "warnless.h"
/* The last #include file should be: */
#include "memdebug.h"
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
static const struct {
- enum protection_level level;
- const char *name;
+ enum protection_level level;
+ const char *name;
} level_names[] = {
- { prot_clear, "clear" },
- { prot_safe, "safe" },
- { prot_confidential, "confidential" },
- { prot_private, "private" }
+ { PROT_CLEAR, "clear" },
+ { PROT_SAFE, "safe" },
+ { PROT_CONFIDENTIAL, "confidential" },
+ { PROT_PRIVATE, "private" }
};
static enum protection_level
@@ -81,196 +81,270 @@ name_to_level(const char *name)
{
int i;
for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
- if(curl_strnequal(level_names[i].name, name, strlen(name)))
+ if(checkprefix(name, level_names[i].name))
return level_names[i].level;
- return (enum protection_level)-1;
+ return PROT_NONE;
+}
+
+/* Convert a protocol |level| to its char representation.
+ We take an int to catch programming mistakes. */
+static char level_to_char(int level) {
+ switch(level) {
+ case PROT_CLEAR:
+ return 'C';
+ case PROT_SAFE:
+ return 'S';
+ case PROT_CONFIDENTIAL:
+ return 'E';
+ case PROT_PRIVATE:
+ return 'P';
+ case PROT_CMD:
+ /* Fall through */
+ default:
+ /* Those 2 cases should not be reached! */
+ break;
+ }
+ DEBUGASSERT(0);
+ /* Default to the most secure alternative. */
+ return 'P';
}
static const struct Curl_sec_client_mech * const mechs[] = {
-#ifdef KRB5
- /* not supported */
+#ifdef HAVE_GSSAPI
+ &Curl_krb5_client_mech,
#endif
-#ifdef HAVE_KRB4
- &Curl_krb4_client_mech,
-#endif
- NULL
+ NULL
};
-int
-Curl_sec_getc(struct connectdata *conn, FILE *F)
+/* Send an FTP command defined by |message| and the optional arguments. The
+ function returns the ftp_code. If an error occurs, -1 is returned. */
+static int ftp_send_command(struct connectdata *conn, const char *message, ...)
{
- if(conn->sec_complete && conn->data_prot) {
- char c;
- if(Curl_sec_read(conn, fileno(F), &c, 1) <= 0)
- return EOF;
- return c;
+ int ftp_code;
+ ssize_t nread;
+ va_list args;
+ char print_buffer[50];
+
+ va_start(args, message);
+ vsnprintf(print_buffer, sizeof(print_buffer), message, args);
+ va_end(args);
+
+ if(Curl_ftpsendf(conn, print_buffer) != CURLE_OK) {
+ ftp_code = -1;
}
- else
- return getc(F);
+ else {
+ if(Curl_GetFTPResponse(&nread, conn, &ftp_code) != CURLE_OK)
+ ftp_code = -1;
+ }
+
+ (void)nread; /* Unused */
+ return ftp_code;
}
-static int
-block_read(int fd, void *buf, size_t len)
+/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
+ saying whether an error occurred or CURLE_OK if |len| was read. */
+static CURLcode
+socket_read(curl_socket_t fd, void *to, size_t len)
{
- unsigned char *p = buf;
- int b;
- while(len) {
- b = read(fd, p, len);
- if (b == 0)
- return 0;
- else if (b < 0)
- return -1;
- len -= b;
- p += b;
+ char *to_p = to;
+ CURLcode code;
+ ssize_t nread;
+
+ while(len > 0) {
+ code = Curl_read_plain(fd, to_p, len, &nread);
+ if(code == CURLE_OK) {
+ len -= nread;
+ to_p += nread;
+ }
+ else {
+ /* FIXME: We are doing a busy wait */
+ if(code == CURLE_AGAIN)
+ continue;
+ return code;
+ }
}
- return p - (unsigned char*)buf;
+ return CURLE_OK;
}
-static int
-block_write(int fd, void *buf, size_t len)
+
+/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a
+ CURLcode saying whether an error occurred or CURLE_OK if |len| was
+ written. */
+static CURLcode
+socket_write(struct connectdata *conn, curl_socket_t fd, const void *to,
+ size_t len)
{
- unsigned char *p = buf;
- int b;
- while(len) {
- b = write(fd, p, len);
- if(b < 0)
- return -1;
- len -= b;
- p += b;
+ const char *to_p = to;
+ CURLcode code;
+ ssize_t written;
+
+ while(len > 0) {
+ code = Curl_write_plain(conn, fd, to_p, len, &written);
+ if(code == CURLE_OK) {
+ len -= written;
+ to_p += written;
+ }
+ else {
+ /* FIXME: We are doing a busy wait */
+ if(code == CURLE_AGAIN)
+ continue;
+ return code;
+ }
}
- return p - (unsigned char*)buf;
+ return CURLE_OK;
}
-static int
-sec_get_data(struct connectdata *conn,
- int fd, struct krb4buffer *buf)
+static CURLcode read_data(struct connectdata *conn,
+ curl_socket_t fd,
+ struct krb5buffer *buf)
{
int len;
- int b;
+ void* tmp;
+ CURLcode ret;
+
+ ret = socket_read(fd, &len, sizeof(len));
+ if(ret != CURLE_OK)
+ return ret;
- b = block_read(fd, &len, sizeof(len));
- if (b == 0)
- return 0;
- else if (b < 0)
- return -1;
len = ntohl(len);
- buf->data = realloc(buf->data, len);
- b = block_read(fd, buf->data, len);
- if (b == 0)
- return 0;
- else if (b < 0)
- return -1;
- buf->size = (conn->mech->decode)(conn->app_data, buf->data, len,
- conn->data_prot, conn);
+ tmp = realloc(buf->data, len);
+ if(tmp == NULL)
+ return CURLE_OUT_OF_MEMORY;
+
+ buf->data = tmp;
+ ret = socket_read(fd, buf->data, len);
+ if(ret != CURLE_OK)
+ return ret;
+ buf->size = conn->mech->decode(conn->app_data, buf->data, len,
+ conn->data_prot, conn);
buf->index = 0;
- return 0;
+ return CURLE_OK;
}
static size_t
-buffer_read(struct krb4buffer *buf, void *data, size_t len)
+buffer_read(struct krb5buffer *buf, void *data, size_t len)
{
- len = min(len, buf->size - buf->index);
- memcpy(data, (char*)buf->data + buf->index, len);
- buf->index += len;
- return len;
+ if(buf->size - buf->index < len)
+ len = buf->size - buf->index;
+ memcpy(data, (char*)buf->data + buf->index, len);
+ buf->index += len;
+ return len;
}
-static size_t
-buffer_write(struct krb4buffer *buf, void *data, size_t len)
+/* Matches Curl_recv signature */
+static ssize_t sec_recv(struct connectdata *conn, int sockindex,
+ char *buffer, size_t len, CURLcode *err)
{
- if(buf->index + len > buf->size) {
- void *tmp;
- if(buf->data == NULL)
- tmp = malloc(1024);
- else
- tmp = realloc(buf->data, buf->index + len);
- if(tmp == NULL)
- return -1;
- buf->data = tmp;
- buf->size = buf->index + len;
- }
- memcpy((char*)buf->data + buf->index, data, len);
- buf->index += len;
- return len;
-}
+ size_t bytes_read;
+ size_t total_read = 0;
+ curl_socket_t fd = conn->sock[sockindex];
-int
-Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length)
-{
- size_t len;
- int rx = 0;
+ *err = CURLE_OK;
- if(conn->sec_complete == 0 || conn->data_prot == 0)
- return read(fd, buffer, length);
+ /* Handle clear text response. */
+ if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
+ return read(fd, buffer, len);
- if(conn->in_buffer.eof_flag){
- conn->in_buffer.eof_flag = 0;
- return 0;
- }
+ if(conn->in_buffer.eof_flag) {
+ conn->in_buffer.eof_flag = 0;
+ return 0;
+ }
- len = buffer_read(&conn->in_buffer, buffer, length);
- length -= len;
- rx += len;
- buffer = (char*)buffer + len;
-
- while(length) {
- if(sec_get_data(conn, fd, &conn->in_buffer) < 0)
- return -1;
- if(conn->in_buffer.size == 0) {
- if(rx)
- conn->in_buffer.eof_flag = 1;
- return rx;
- }
- len = buffer_read(&conn->in_buffer, buffer, length);
- length -= len;
- rx += len;
- buffer = (char*)buffer + len;
- }
- return rx;
-}
+ bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+ len -= bytes_read;
+ total_read += bytes_read;
+ buffer += bytes_read;
-static int
-sec_send(struct connectdata *conn, int fd, char *from, int length)
-{
- int bytes;
- void *buf;
- bytes = (conn->mech->encode)(conn->app_data, from, length, conn->data_prot,
- &buf, conn);
- bytes = htonl(bytes);
- block_write(fd, &bytes, sizeof(bytes));
- block_write(fd, buf, ntohl(bytes));
- free(buf);
- return length;
+ while(len > 0) {
+ if(read_data(conn, fd, &conn->in_buffer) != CURLE_OK)
+ return -1;
+ if(conn->in_buffer.size == 0) {
+ if(bytes_read > 0)
+ conn->in_buffer.eof_flag = 1;
+ return bytes_read;
+ }
+ bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+ len -= bytes_read;
+ total_read += bytes_read;
+ buffer += bytes_read;
+ }
+ /* FIXME: Check for overflow */
+ return total_read;
}
-int
-Curl_sec_fflush_fd(struct connectdata *conn, int fd)
+/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
+ and negociating with the server. |from| can be NULL. */
+/* FIXME: We don't check for errors nor report any! */
+static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
+ const char *from, int length)
{
- if(conn->data_prot != prot_clear) {
- if(conn->out_buffer.index > 0){
- Curl_sec_write(conn, fd,
- conn->out_buffer.data, conn->out_buffer.index);
- conn->out_buffer.index = 0;
+ int bytes, htonl_bytes; /* 32-bit integers for htonl */
+ char *buffer = NULL;
+ char *cmd_buffer;
+ size_t cmd_size = 0;
+ CURLcode error;
+ enum protection_level prot_level = conn->data_prot;
+ bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE;
+
+ DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
+
+ if(iscmd) {
+ if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
+ prot_level = PROT_PRIVATE;
+ else
+ prot_level = conn->command_prot;
+ }
+ bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
+ (void**)&buffer, conn);
+ if(!buffer || bytes <= 0)
+ return; /* error */
+
+ if(iscmd) {
+ error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes),
+ &cmd_buffer, &cmd_size);
+ if(error) {
+ free(buffer);
+ return; /* error */
+ }
+ if(cmd_size > 0) {
+ static const char *enc = "ENC ";
+ static const char *mic = "MIC ";
+ if(prot_level == PROT_PRIVATE)
+ socket_write(conn, fd, enc, 4);
+ else
+ socket_write(conn, fd, mic, 4);
+
+ socket_write(conn, fd, cmd_buffer, cmd_size);
+ socket_write(conn, fd, "\r\n", 2);
+ infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
+ cmd_buffer);
+ free(cmd_buffer);
}
- sec_send(conn, fd, NULL, 0);
}
- return 0;
+ else {
+ htonl_bytes = htonl(bytes);
+ socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes));
+ socket_write(conn, fd, buffer, curlx_sitouz(bytes));
+ }
+ free(buffer);
}
-int
-Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
+static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
+ const char *buffer, size_t length)
{
- int len = conn->buffer_size;
- int tx = 0;
-
- if(conn->data_prot == prot_clear)
- return write(fd, buffer, length);
-
- len -= (conn->mech->overhead)(conn->app_data, conn->data_prot, len);
- while(length){
- if(length < len)
+ /* FIXME: Check for overflow */
+ ssize_t tx = 0, len = conn->buffer_size;
+
+ len -= conn->mech->overhead(conn->app_data, conn->data_prot,
+ curlx_sztosi(len));
+ if(len <= 0)
+ len = length;
+ while(length) {
+ if(len >= 0 || length < (size_t)len) {
+ /* FIXME: Check for overflow. */
len = length;
- sec_send(conn, fd, buffer, len);
+ }
+ do_sec_send(conn, fd, buffer, curlx_sztosi(len));
length -= len;
buffer += len;
tx += len;
@@ -278,216 +352,250 @@ Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
return tx;
}
-ssize_t
-Curl_sec_send(struct connectdata *conn, int num, char *buffer, int length)
-{
- curl_socket_t fd = conn->sock[num];
- return (ssize_t)Curl_sec_write(conn, fd, buffer, length);
-}
-
-int
-Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
+/* Matches Curl_send signature */
+static ssize_t sec_send(struct connectdata *conn, int sockindex,
+ const void *buffer, size_t len, CURLcode *err)
{
- char ch = c;
- if(conn->data_prot == prot_clear)
- return putc(c, F);
-
- buffer_write(&conn->out_buffer, &ch, 1);
- if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) {
- Curl_sec_write(conn, fileno(F), conn->out_buffer.data,
- conn->out_buffer.index);
- conn->out_buffer.index = 0;
- }
- return c;
+ curl_socket_t fd = conn->sock[sockindex];
+ *err = CURLE_OK;
+ return sec_write(conn, fd, buffer, len);
}
-int
-Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
+int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
+ enum protection_level level)
{
- int len;
- unsigned char *buf;
- int code;
+ /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
+ int */
+ int decoded_len;
+ char *buf;
+ int ret_code;
+ size_t decoded_sz = 0;
+ CURLcode error;
+
+ DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+ error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
+ if(error || decoded_sz == 0)
+ return -1;
- len = Curl_base64_decode(s + 4, &buf); /* XXX */
- if(len > 0)
- len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
- else
+ if(decoded_sz > (size_t)INT_MAX) {
+ free(buf);
return -1;
+ }
+ decoded_len = curlx_uztosi(decoded_sz);
- if(len < 0) {
+ decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
+ level, conn);
+ if(decoded_len <= 0) {
free(buf);
return -1;
}
- buf[len] = '\0';
+ if(conn->data->set.verbose) {
+ buf[decoded_len] = '\n';
+ Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1, conn);
+ }
+ buf[decoded_len] = '\0';
+ DEBUGASSERT(decoded_len > 3);
if(buf[3] == '-')
- code = 0;
- else
- sscanf((char *)buf, "%d", &code);
- if(buf[len-1] == '\n')
- buf[len-1] = '\0';
- strcpy(s, (char *)buf);
+ ret_code = 0;
+ else {
+ /* Check for error? */
+ sscanf(buf, "%d", &ret_code);
+ }
+
+ if(buf[decoded_len - 1] == '\n')
+ buf[decoded_len - 1] = '\0';
+ /* FIXME: Is |buffer| length always greater than |decoded_len|? */
+ strcpy(buffer, buf);
free(buf);
- return code;
+ return ret_code;
}
-enum protection_level
-Curl_set_command_prot(struct connectdata *conn, enum protection_level level)
+/* FIXME: The error code returned here is never checked. */
+static int sec_set_protection_level(struct connectdata *conn)
{
- enum protection_level old = conn->command_prot;
- conn->command_prot = level;
- return old;
-}
+ int code;
+ char* pbsz;
+ static unsigned int buffer_size = 1 << 20; /* 1048576 */
+ enum protection_level level = conn->request_data_prot;
-static int
-sec_prot_internal(struct connectdata *conn, int level)
-{
- char *p;
- unsigned int s = 1048576;
- ssize_t nread;
+ DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
- if(!conn->sec_complete){
- infof(conn->data, "No security data exchange has taken place.\n");
+ if(!conn->sec_complete) {
+ infof(conn->data, "Trying to change the protection level after the"
+ "completion of the data exchange.\n");
return -1;
}
- if(level){
- int code;
- if(Curl_ftpsendf(conn, "PBSZ %u", s))
- return -1;
+ /* Bail out if we try to set up the same level */
+ if(conn->data_prot == level)
+ return 0;
- if(Curl_GetFTPResponse(&nread, conn, &code))
+ if(level) {
+ code = ftp_send_command(conn, "PBSZ %u", buffer_size);
+ if(code < 0)
return -1;
- if(code/100 != '2'){
- failf(conn->data, "Failed to set protection buffer size.");
+ if(code/100 != 2) {
+ failf(conn->data, "Failed to set the protection's buffer size.");
return -1;
}
- conn->buffer_size = s;
-
- p = strstr(conn->data->state.buffer, "PBSZ=");
- if(p)
- sscanf(p, "PBSZ=%u", &s);
- if(s < conn->buffer_size)
- conn->buffer_size = s;
+ conn->buffer_size = buffer_size;
+
+ pbsz = strstr(conn->data->state.buffer, "PBSZ=");
+ if(pbsz) {
+ /* FIXME: Checks for errors in sscanf? */
+ sscanf(pbsz, "PBSZ=%u", &buffer_size);
+ if(buffer_size < conn->buffer_size)
+ conn->buffer_size = buffer_size;
+ }
}
- if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"]))
- return -1;
+ /* Now try to negiociate the protection level. */
+ code = ftp_send_command(conn, "PROT %c", level_to_char(level));
- if(Curl_GetFTPResponse(&nread, conn, NULL))
+ if(code < 0)
return -1;
- if(conn->data->state.buffer[0] != '2'){
- failf(conn->data, "Failed to set protection level.");
+ if(code/100 != 2) {
+ failf(conn->data, "Failed to set the protection level.");
return -1;
}
- conn->data_prot = (enum protection_level)level;
- return 0;
-}
+ conn->data_prot = level;
+ if(level == PROT_PRIVATE)
+ conn->command_prot = level;
-void
-Curl_sec_set_protection_level(struct connectdata *conn)
-{
- if(conn->sec_complete && conn->data_prot != conn->request_data_prot)
- sec_prot_internal(conn, conn->request_data_prot);
+ return 0;
}
-
int
Curl_sec_request_prot(struct connectdata *conn, const char *level)
{
- int l = name_to_level(level);
- if(l == -1)
+ enum protection_level l = name_to_level(level);
+ if(l == PROT_NONE)
return -1;
- conn->request_data_prot = (enum protection_level)l;
+ DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
+ conn->request_data_prot = l;
return 0;
}
-int
-Curl_sec_login(struct connectdata *conn)
+static CURLcode choose_mech(struct connectdata *conn)
{
int ret;
- const struct Curl_sec_client_mech * const *m;
- ssize_t nread;
- struct SessionHandle *data=conn->data;
- int ftpcode;
-
- for(m = mechs; *m && (*m)->name; m++) {
- void *tmp;
-
- tmp = realloc(conn->app_data, (*m)->size);
- if (tmp == NULL) {
- failf (data, "realloc %u failed", (*m)->size);
- return -1;
- }
- conn->app_data = tmp;
-
- if((*m)->init && (*(*m)->init)(conn->app_data) != 0) {
- infof(data, "Skipping %s...\n", (*m)->name);
+ struct SessionHandle *data = conn->data;
+ const struct Curl_sec_client_mech * const *mech;
+ void *tmp_allocation;
+ const char *mech_name;
+
+ for(mech = mechs; (*mech); ++mech) {
+ mech_name = (*mech)->name;
+ /* We have no mechanism with a NULL name but keep this check */
+ DEBUGASSERT(mech_name != NULL);
+ if(mech_name == NULL) {
+ infof(data, "Skipping mechanism with empty name (%p)\n", (void *)mech);
continue;
}
- infof(data, "Trying %s...\n", (*m)->name);
+ tmp_allocation = realloc(conn->app_data, (*mech)->size);
+ if(tmp_allocation == NULL) {
+ failf(data, "Failed realloc of size %u", (*mech)->size);
+ mech = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ conn->app_data = tmp_allocation;
- if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name))
- return -1;
+ if((*mech)->init) {
+ ret = (*mech)->init(conn->app_data);
+ if(ret != 0) {
+ infof(data, "Failed initialization for %s. Skipping it.\n", mech_name);
+ continue;
+ }
+ }
- if(Curl_GetFTPResponse(&nread, conn, &ftpcode))
- return -1;
+ infof(data, "Trying mechanism %s...\n", mech_name);
+ ret = ftp_send_command(conn, "AUTH %s", mech_name);
+ if(ret < 0)
+ /* FIXME: This error is too generic but it is OK for now. */
+ return CURLE_COULDNT_CONNECT;
- if(conn->data->state.buffer[0] != '3'){
- switch(ftpcode) {
+ if(ret/100 != 3) {
+ switch(ret) {
case 504:
- infof(data,
- "%s is not supported by the server.\n", (*m)->name);
+ infof(data, "Mechanism %s is not supported by the server (server "
+ "returned ftp code: 504).\n", mech_name);
break;
case 534:
- infof(data, "%s rejected as security mechanism.\n", (*m)->name);
+ infof(data, "Mechanism %s was rejected by the server (server returned "
+ "ftp code: 534).\n", mech_name);
break;
default:
- if(conn->data->state.buffer[0] == '5') {
- infof(data, "The server doesn't support the FTP "
- "security extensions.\n");
- return -1;
+ if(ret/100 == 5) {
+ infof(data, "server does not support the security extensions\n");
+ return CURLE_USE_SSL_FAILED;
}
break;
}
continue;
}
- ret = (*(*m)->auth)(conn->app_data, conn);
+ /* Authenticate */
+ ret = (*mech)->auth(conn->app_data, conn);
if(ret == AUTH_CONTINUE)
continue;
- else if(ret != AUTH_OK){
- /* mechanism is supposed to output error string */
+ else if(ret != AUTH_OK) {
+ /* Mechanism has dumped the error to stderr, don't error here. */
return -1;
}
- conn->mech = *m;
+ DEBUGASSERT(ret == AUTH_OK);
+
+ conn->mech = *mech;
conn->sec_complete = 1;
- conn->command_prot = prot_safe;
+ conn->recv[FIRSTSOCKET] = sec_recv;
+ conn->send[FIRSTSOCKET] = sec_send;
+ conn->recv[SECONDARYSOCKET] = sec_recv;
+ conn->send[SECONDARYSOCKET] = sec_send;
+ conn->command_prot = PROT_SAFE;
+ /* Set the requested protection level */
+ /* BLOCKING */
+ (void)sec_set_protection_level(conn);
break;
}
- return *m == NULL;
+ return mech != NULL ? CURLE_OK : CURLE_FAILED_INIT;
}
+CURLcode
+Curl_sec_login(struct connectdata *conn)
+{
+ return choose_mech(conn);
+}
+
+
void
Curl_sec_end(struct connectdata *conn)
{
- if (conn->mech != NULL) {
- if(conn->mech->end)
- (conn->mech->end)(conn->app_data);
- memset(conn->app_data, 0, conn->mech->size);
+ if(conn->mech != NULL && conn->mech->end)
+ conn->mech->end(conn->app_data);
+ if(conn->app_data) {
free(conn->app_data);
conn->app_data = NULL;
}
+ if(conn->in_buffer.data) {
+ free(conn->in_buffer.data);
+ conn->in_buffer.data = NULL;
+ conn->in_buffer.size = 0;
+ conn->in_buffer.index = 0;
+ /* FIXME: Is this really needed? */
+ conn->in_buffer.eof_flag = 0;
+ }
conn->sec_complete = 0;
- conn->data_prot = (enum protection_level)0;
- conn->mech=NULL;
+ conn->data_prot = PROT_CLEAR;
+ conn->mech = NULL;
}
-#endif /* HAVE_KRB4 */
+#endif /* HAVE_GSSAPI */
+
#endif /* CURL_DISABLE_FTP */