diff options
author | Bertrand SIMONNET <bsimonnet@google.com> | 2015-07-01 15:39:44 -0700 |
---|---|---|
committer | Bertrand SIMONNET <bsimonnet@google.com> | 2015-07-08 10:51:12 -0700 |
commit | e6cd738ed3716c02557fb3a47515244e949ade39 (patch) | |
tree | 8d093306c27b850f828317ed67d6efea3ec7e084 /lib/security.c | |
parent | d43abe883892fe84137052fd27ecd956a2c7cacf (diff) | |
download | android_external_curl-e6cd738ed3716c02557fb3a47515244e949ade39.tar.gz android_external_curl-e6cd738ed3716c02557fb3a47515244e949ade39.tar.bz2 android_external_curl-e6cd738ed3716c02557fb3a47515244e949ade39.zip |
Import curl 7.43
This is a simple import of curl 7.43.
The only change from the official release is the fact that the
Android.mk was removed to avoid build error trying to parse it.
BUG: 22347561
Change-Id: I52ef6798d30b25d22d1f62770d571adec8bcf4d5
Diffstat (limited to 'lib/security.c')
-rw-r--r-- | lib/security.c | 320 |
1 files changed, 154 insertions, 166 deletions
diff --git a/lib/security.c b/lib/security.c index 73a5540..014bbf1 100644 --- a/lib/security.c +++ b/lib/security.c @@ -10,7 +10,7 @@ * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * - * Copyright (C) 2001 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2001 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * All rights reserved. * @@ -41,29 +41,27 @@ * 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 -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - -#include <stdarg.h> -#include <string.h> +#ifdef HAVE_GSSAPI #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 "curl_base64.h" #include "curl_memory.h" -#include "krb4.h" +#include "curl_sec.h" #include "ftp.h" #include "sendf.h" #include "rawstr.h" +#include "warnless.h" /* The last #include file should be: */ #include "memdebug.h" @@ -72,10 +70,10 @@ static const struct { 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 @@ -85,22 +83,22 @@ name_to_level(const char *name) for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) 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: + case PROT_CLEAR: return 'C'; - case prot_safe: + case PROT_SAFE: return 'S'; - case prot_confidential: + case PROT_CONFIDENTIAL: return 'E'; - case prot_private: + case PROT_PRIVATE: return 'P'; - case prot_cmd: + case PROT_CMD: /* Fall through */ default: /* Those 2 cases should not be reached! */ @@ -111,22 +109,12 @@ static char level_to_char(int level) { return 'P'; } -static const struct Curl_sec_client_mech * const mechs[] = { -#if defined(HAVE_GSSAPI) - &Curl_krb5_client_mech, -#endif -#if defined(HAVE_KRB4) - &Curl_krb4_client_mech, -#endif - NULL -}; - /* 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, ...) { int ftp_code; - ssize_t nread; + ssize_t nread=0; va_list args; char print_buffer[50]; @@ -134,11 +122,11 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) vsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); - if(Curl_ftpsendf(conn, print_buffer) != CURLE_OK) { + if(Curl_ftpsendf(conn, print_buffer)) { ftp_code = -1; } else { - if(Curl_GetFTPResponse(&nread, conn, &ftp_code) != CURLE_OK) + if(Curl_GetFTPResponse(&nread, conn, &ftp_code)) ftp_code = -1; } @@ -147,25 +135,25 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) } /* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode - saying whether an error occured or CURLE_OK if |len| was read. */ + 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) { char *to_p = to; - CURLcode code; + CURLcode result; ssize_t nread; while(len > 0) { - code = Curl_read_plain(fd, to_p, len, &nread); - if(code == CURLE_OK) { + result = Curl_read_plain(fd, to_p, len, &nread); + if(!result) { len -= nread; to_p += nread; } else { /* FIXME: We are doing a busy wait */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) continue; - return code; + return result; } } return CURLE_OK; @@ -173,27 +161,27 @@ socket_read(curl_socket_t fd, void *to, size_t len) /* Write |len| bytes from the buffer |to| to the socket |fd|. Return a - CURLcode saying whether an error occured or CURLE_OK if |len| was + 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) { const char *to_p = to; - CURLcode code; + CURLcode result; ssize_t written; while(len > 0) { - code = Curl_write_plain(conn, fd, to_p, len, &written); - if(code == CURLE_OK) { + result = Curl_write_plain(conn, fd, to_p, len, &written); + if(!result) { len -= written; to_p += written; } else { /* FIXME: We are doing a busy wait */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) continue; - return code; + return result; } } return CURLE_OK; @@ -201,25 +189,25 @@ socket_write(struct connectdata *conn, curl_socket_t fd, const void *to, static CURLcode read_data(struct connectdata *conn, curl_socket_t fd, - struct krb4buffer *buf) + struct krb5buffer *buf) { int len; void* tmp; - CURLcode ret; + CURLcode result; - ret = socket_read(fd, &len, sizeof(len)); - if (ret != CURLE_OK) - return ret; + result = socket_read(fd, &len, sizeof(len)); + if(result) + return result; len = ntohl(len); tmp = realloc(buf->data, len); - if (tmp == NULL) + if(tmp == NULL) return CURLE_OUT_OF_MEMORY; buf->data = tmp; - ret = socket_read(fd, buf->data, len); - if (ret != CURLE_OK) - return ret; + result = socket_read(fd, buf->data, len); + if(result) + return result; buf->size = conn->mech->decode(conn->app_data, buf->data, len, conn->data_prot, conn); buf->index = 0; @@ -227,7 +215,7 @@ static CURLcode read_data(struct connectdata *conn, } static size_t -buffer_read(struct krb4buffer *buf, void *data, size_t len) +buffer_read(struct krb5buffer *buf, void *data, size_t len) { if(buf->size - buf->index < len) len = buf->size - buf->index; @@ -247,7 +235,7 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, *err = CURLE_OK; /* Handle clear text response. */ - if(conn->sec_complete == 0 || conn->data_prot == prot_clear) + if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) return read(fd, buffer, len); if(conn->in_buffer.eof_flag) { @@ -261,7 +249,7 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, buffer += bytes_read; while(len > 0) { - if(read_data(conn, fd, &conn->in_buffer) != CURLE_OK) + if(read_data(conn, fd, &conn->in_buffer)) return -1; if(conn->in_buffer.size == 0) { if(bytes_read > 0) @@ -283,34 +271,45 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, static void do_sec_send(struct connectdata *conn, curl_socket_t fd, const char *from, int length) { - size_t bytes; - size_t htonl_bytes; - char *buffer; + 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; + 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; + prot_level = PROT_PRIVATE; else prot_level = conn->command_prot; } bytes = conn->mech->encode(conn->app_data, from, length, prot_level, - (void**)&buffer, conn); + (void**)&buffer); + if(!buffer || bytes <= 0) + return; /* error */ + if(iscmd) { - bytes = Curl_base64_encode(conn->data, buffer, bytes, &cmd_buffer); - if(bytes > 0) { + 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) + if(prot_level == PROT_PRIVATE) socket_write(conn, fd, enc, 4); else socket_write(conn, fd, mic, 4); - socket_write(conn, fd, cmd_buffer, bytes); + 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, + infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic, cmd_buffer); free(cmd_buffer); } @@ -318,7 +317,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, else { htonl_bytes = htonl(bytes); socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes)); - socket_write(conn, fd, buffer, bytes); + socket_write(conn, fd, buffer, curlx_sitouz(bytes)); } free(buffer); } @@ -326,19 +325,17 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd, const char *buffer, size_t length) { - /* FIXME: Check for overflow */ - ssize_t len = conn->buffer_size; - int tx = 0; + ssize_t tx = 0, len = conn->buffer_size; - len -= conn->mech->overhead(conn->app_data, conn->data_prot, len); + 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. */ + if(length < (size_t)len) len = length; - } - do_sec_send(conn, fd, buffer, len); + + do_sec_send(conn, fd, buffer, curlx_sztosi(len)); length -= len; buffer += len; tx += len; @@ -355,20 +352,28 @@ static ssize_t sec_send(struct connectdata *conn, int sockindex, return sec_write(conn, fd, buffer, len); } -/* FIXME: |level| should not be an int but a struct protection_level */ -int Curl_sec_read_msg(struct connectdata *conn, char *buffer, int level) +int Curl_sec_read_msg(struct connectdata *conn, char *buffer, + enum protection_level level) { /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an int */ int decoded_len; char *buf; - int ret_code; + int ret_code = 0; + size_t decoded_sz = 0; + CURLcode error; - decoded_len = Curl_base64_decode(buffer + 4, (unsigned char **)&buf); - if(decoded_len <= 0) { + 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; + + if(decoded_sz > (size_t)INT_MAX) { free(buf); return -1; } + decoded_len = curlx_uztosi(decoded_sz); decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, level, conn); @@ -383,13 +388,13 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, int level) } buf[decoded_len] = '\0'; - DEBUGASSERT(decoded_len > 3); - if(buf[3] == '-') - ret_code = 0; - else { - /* Check for error? */ - sscanf(buf, "%d", &ret_code); - } + if(decoded_len <= 3) + /* suspiciously short */ + return 0; + + if(buf[3] != '-') + /* safe to ignore return code */ + (void)sscanf(buf, "%d", &ret_code); if(buf[decoded_len - 1] == '\n') buf[decoded_len - 1] = '\0'; @@ -399,22 +404,16 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, int level) return ret_code; } -enum protection_level -Curl_set_command_prot(struct connectdata *conn, enum protection_level level) -{ - enum protection_level old = conn->command_prot; - conn->command_prot = level; - return old; -} - /* FIXME: The error code returned here is never checked. */ -int Curl_sec_set_protection_level(struct connectdata *conn) +static int sec_set_protection_level(struct connectdata *conn) { int code; char* pbsz; static unsigned int buffer_size = 1 << 20; /* 1048576 */ enum protection_level level = conn->request_data_prot; + DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); + if(!conn->sec_complete) { infof(conn->data, "Trying to change the protection level after the" "completion of the data exchange.\n"); @@ -438,8 +437,8 @@ int Curl_sec_set_protection_level(struct connectdata *conn) pbsz = strstr(conn->data->state.buffer, "PBSZ="); if(pbsz) { - /* FIXME: Checks for errors in sscanf? */ - sscanf(pbsz, "PBSZ=%u", &buffer_size); + /* ignore return code, use default value if it fails */ + (void)sscanf(pbsz, "PBSZ=%u", &buffer_size); if(buffer_size < conn->buffer_size) conn->buffer_size = buffer_size; } @@ -457,7 +456,7 @@ int Curl_sec_set_protection_level(struct connectdata *conn) } conn->data_prot = level; - if(level == prot_private) + if(level == PROT_PRIVATE) conn->command_prot = level; return 0; @@ -466,10 +465,11 @@ int Curl_sec_set_protection_level(struct connectdata *conn) 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; } @@ -477,85 +477,75 @@ static CURLcode choose_mech(struct connectdata *conn) { int ret; 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", mech); - continue; - } - 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; + const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; - if((*mech)->init) { - ret = (*mech)->init(conn); - if(ret != 0) { - infof(data, "Failed initialization for %s. Skipping it.\n", mech_name); - continue; - } + 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(mech->init) { + ret = mech->init(conn->app_data); + if(ret) { + infof(data, "Failed initialization for %s. Skipping it.\n", + mech->name); + return CURLE_FAILED_INIT; } + } - 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(ret/100 != 3) { - switch(ret) { - case 504: - infof(data, "Mechanism %s is not supported by the server (server " - "returned ftp code: 504).\n", mech_name); - break; - case 534: - infof(data, "Mechanism %s was rejected by the server (server returned " - "ftp code: 534).\n", mech_name); - break; - default: - if(ret/100 == 5) { - infof(data, "The server does not support the security extensions.\n"); - return CURLE_USE_SSL_FAILED; - } - break; + 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(ret/100 != 3) { + switch(ret) { + case 504: + infof(data, "Mechanism %s is not supported by the server (server " + "returned ftp code: 504).\n", mech->name); + break; + case 534: + infof(data, "Mechanism %s was rejected by the server (server returned " + "ftp code: 534).\n", mech->name); + break; + default: + if(ret/100 == 5) { + infof(data, "server does not support the security extensions\n"); + return CURLE_USE_SSL_FAILED; } - continue; + break; } + return CURLE_LOGIN_DENIED; + } - /* Authenticate */ - ret = (*mech)->auth(conn->app_data, conn); + /* Authenticate */ + ret = mech->auth(conn->app_data, conn); - if(ret == AUTH_CONTINUE) - continue; - else if(ret != AUTH_OK) { + if(ret != AUTH_CONTINUE) { + if(ret != AUTH_OK) { /* Mechanism has dumped the error to stderr, don't error here. */ return -1; } DEBUGASSERT(ret == AUTH_OK); - conn->mech = *mech; + conn->mech = mech; conn->sec_complete = 1; 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; + conn->command_prot = PROT_SAFE; /* Set the requested protection level */ /* BLOCKING */ - Curl_sec_set_protection_level(conn); - break; + (void)sec_set_protection_level(conn); } - return mech != NULL ? CURLE_OK : CURLE_FAILED_INIT; + return CURLE_OK; } CURLcode @@ -570,10 +560,8 @@ Curl_sec_end(struct connectdata *conn) { 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; - } + free(conn->app_data); + conn->app_data = NULL; if(conn->in_buffer.data) { free(conn->in_buffer.data); conn->in_buffer.data = NULL; @@ -583,10 +571,10 @@ Curl_sec_end(struct connectdata *conn) conn->in_buffer.eof_flag = 0; } conn->sec_complete = 0; - conn->data_prot = (enum protection_level)0; + conn->data_prot = PROT_CLEAR; conn->mech = NULL; } -#endif /* HAVE_KRB4 || HAVE_GSSAPI */ +#endif /* HAVE_GSSAPI */ #endif /* CURL_DISABLE_FTP */ |