krb5: drop support for Kerberos FTP

It was accidentally broken in commit 0f4c439fc7, shipped since
8.8.0 (May 2024) and yet not a single person has noticed or reported,
indicating that we might as well drop support for FTP Kerberos.

Krb5 support was added in 54967d2a3a (July 2007), and we have
been carrying the extra license information around since then for this
code. This commit removes the last traces of that code and thus we can
remove the extra copyright notices along with it.

Reported-by: Joshua Rogers
Closes #18577
This commit is contained in:
Daniel Stenberg
2025-09-17 08:32:39 +02:00
parent bb46d42407
commit 5ab120bc4e
22 changed files with 43 additions and 1200 deletions

View File

@@ -356,7 +356,6 @@ HTTPS
https
HTTPSRR
hyper's
Högskolan
IANA
Icecast
ICONV
@@ -424,7 +423,6 @@ Krb
krb
Kubernetes
Kuhrt
Kungliga
Largefile
LDAP
ldap
@@ -848,7 +846,6 @@ Tatsuhiro
TBD
TCP
tcpdump
Tekniska
testability
testcurl
TFTP

View File

@@ -1,11 +0,0 @@
Copyright (c) <year> <owner>.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

6
README
View File

@@ -47,9 +47,3 @@ SECURITY PROBLEMS
Report suspected security problems via our HackerOne page and not in public.
https://hackerone.com/curl
NOTICE
Curl contains pieces of source code that is Copyright (c) 1998, 1999
Kungliga Tekniska Högskolan. This notice is included here to comply with the
distribution terms.

View File

@@ -53,12 +53,6 @@ Download the latest source from the Git server:
Report suspected security problems via [our HackerOne
page](https://hackerone.com/curl) and not in public.
## Notice
curl contains pieces of source code that is Copyright (c) 1998, 1999 Kungliga
Tekniska Högskolan. This notice is included here to comply with the
distribution terms.
## Backers
Thank you to all our backers :pray: [Become a backer](https://opencollective.com/curl#section-contribute).

View File

@@ -6,7 +6,7 @@ Arg: <level>
Help: Enable Kerberos with security <level>
Protocols: FTP
Requires: Kerberos
Category: ftp
Category: deprecated
Added: 7.3
Multi: single
See-also:
@@ -18,6 +18,8 @@ Example:
# `--krb`
Deprecated option (added in 8.17.0). It has no function anymore.
Enable Kerberos authentication and use. The level must be entered and should
be one of 'clear', 'safe', 'confidential', or 'private'. Should you use a
level that is not one of these, 'private' is used.
be one of `clear`, `safe`, `confidential`, or `private`. Should you use a
level that is not one of these, `private` is used.

View File

@@ -540,7 +540,7 @@ Client key password. See CURLOPT_KEYPASSWD(3)
## CURLOPT_KRBLEVEL
Kerberos security level. See CURLOPT_KRBLEVEL(3)
**OBSOLETE**. Kerberos security level. See CURLOPT_KRBLEVEL(3)
## CURLOPT_LOCALPORT

View File

@@ -5,7 +5,6 @@ Title: CURLOPT_KRBLEVEL
Section: 3
Source: libcurl
See-also:
- CURLOPT_KRBLEVEL (3)
- CURLOPT_USE_SSL (3)
Protocol:
- FTP
@@ -26,11 +25,13 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KRBLEVEL, char *level);
# DESCRIPTION
Deprecated. It serves no purpose anymore.
Pass a char pointer as parameter. Set the kerberos security level for FTP;
this also enables kerberos awareness. This is a string that should match one
of the following: &'clear', &'safe', &'confidential' or &'private'. If the
string is set but does not match one of these, 'private' is used. Set the
string to NULL to disable kerberos support for FTP.
of the following: `clear`, `safe`, `confidential` or `private`. If the string
is set but does not match one of these, `private` is used. Set the string to
NULL to disable kerberos support for FTP.
The application does not have to keep the string around after setting this
option.
@@ -62,8 +63,14 @@ int main(void)
# HISTORY
Functionality removed in 8.17.0
This option was known as CURLOPT_KRB4LEVEL up to 7.16.3
# DEPRECATED
Deprecated since 8.17.0
# %AVAILABILITY%
# RETURN VALUE

View File

@@ -704,7 +704,7 @@ CURLOPT_ISSUERCERT_BLOB 7.71.0
CURLOPT_KEEP_SENDING_ON_ERROR 7.51.0
CURLOPT_KEYPASSWD 7.17.0
CURLOPT_KRB4LEVEL 7.3 7.17.0
CURLOPT_KRBLEVEL 7.16.4
CURLOPT_KRBLEVEL 7.16.4 8.17.0
CURLOPT_LOCALPORT 7.15.2
CURLOPT_LOCALPORTRANGE 7.15.2
CURLOPT_LOGIN_OPTIONS 7.34.0

View File

@@ -1357,7 +1357,8 @@ typedef enum {
/* Set the krb4/5 security level, this also enables krb4/5 awareness. This
* is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
* is set but does not match one of these, 'private' will be used. */
CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63),
CURLOPTDEPRECATED(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63,
8.17.0, "removed"),
/* Set if we should verify the peer in ssl handshake, set 1 to verify. */
CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64),

View File

@@ -209,7 +209,6 @@ LIB_CFILES = \
idn.c \
if2ip.c \
imap.c \
krb5.c \
ldap.c \
llist.c \
macos.c \
@@ -292,7 +291,6 @@ LIB_HFILES = \
curl_gethostname.h \
curl_gssapi.h \
curl_hmac.h \
curl_krb5.h \
curl_ldap.h \
curl_md4.h \
curl_md5.h \

View File

@@ -1,54 +0,0 @@
#ifndef HEADER_CURL_KRB5_H
#define HEADER_CURL_KRB5_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
struct Curl_sec_client_mech {
const char *name;
size_t size;
int (*init)(void *);
int (*auth)(void *, struct Curl_easy *data, struct connectdata *);
void (*end)(void *);
int (*check_prot)(void *, int);
int (*encode)(void *, const void *, int, int, void **);
int (*decode)(void *, void *, int, int, struct connectdata *);
};
#define AUTH_OK 0
#define AUTH_CONTINUE 1
#define AUTH_ERROR 2
#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP)
void Curl_sec_conn_init(struct connectdata *);
void Curl_sec_conn_destroy(struct connectdata *);
int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *,
enum protection_level);
CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *);
int Curl_sec_request_prot(struct connectdata *conn, const char *level);
#else
#define Curl_sec_conn_init(x) Curl_nop_stmt
#define Curl_sec_conn_destroy(x) Curl_nop_stmt
#endif
#endif /* HEADER_CURL_KRB5_H */

View File

@@ -53,7 +53,6 @@
#include "fileinfo.h"
#include "ftplistparser.h"
#include "curl_range.h"
#include "curl_krb5.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "cfilters.h"
@@ -431,6 +430,9 @@ static const struct Curl_cwtype ftp_cw_lc = {
#endif /* CURL_PREFER_LF_LINEENDS */
static CURLcode getftpresponse(struct Curl_easy *data, ssize_t *nread,
int *ftpcode);
/***********************************************************************
*
* ftp_check_ctrl_on_data_wait()
@@ -450,7 +452,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data,
if(curlx_dyn_len(&pp->recvbuf) && (*curlx_dyn_ptr(&pp->recvbuf) > '3')) {
/* Data connection could not be established, let's return */
infof(data, "There is negative response in cache while serv connect");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
(void)getftpresponse(data, &nread, &ftpcode);
return CURLE_FTP_ACCEPT_FAILED;
}
@@ -496,7 +498,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data,
}
}
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
(void)getftpresponse(data, &nread, &ftpcode);
infof(data, "FTP code: %03d", ftpcode);
@@ -578,28 +580,6 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
int code;
CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size);
DEBUGASSERT(ftpcodep);
#ifdef HAVE_GSSAPI
{
struct connectdata *conn = data->conn;
char * const buf = curlx_dyn_ptr(&ftpc->pp.recvbuf);
/* handle the security-oriented responses 6xx ***/
switch(code) {
case 631:
code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE);
break;
case 632:
code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE);
break;
case 633:
code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL);
break;
default:
/* normal ftp stuff we pass through! */
break;
}
}
#endif
/* store the latest code for later retrieval, except during shutdown */
if(!ftpc->shutdown)
@@ -626,13 +606,14 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
/* --- parse FTP server responses --- */
/*
* Curl_GetFTPResponse() is a BLOCKING function to read the full response
* from a server after a command.
* getftpresponse() is a BLOCKING function to read the full response from a
* server after a command.
*
*/
CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
ssize_t *nreadp, /* return number of bytes read */
int *ftpcodep) /* return the ftp-code */
static CURLcode getftpresponse(struct Curl_easy *data,
ssize_t *nreadp, /* return number of bytes
read */
int *ftpcodep) /* return the ftp-code */
{
/*
* We cannot read just one byte per read() and then go back to select() as
@@ -650,7 +631,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
int cache_skip = 0;
DEBUGASSERT(ftpcodep);
CURL_TRC_FTP(data, "getFTPResponse start");
CURL_TRC_FTP(data, "getftpresponse start");
*nreadp = 0;
*ftpcodep = 0; /* 0 for errors */
@@ -733,7 +714,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
} /* while there is buffer left and loop is requested */
pp->pending_resp = FALSE;
CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d",
CURL_TRC_FTP(data, "getftpresponse -> result=%d, nread=%zd, ftpcode=%d",
result, *nreadp, *ftpcodep);
return result;
@@ -2814,25 +2795,6 @@ static CURLcode ftp_wait_resp(struct Curl_easy *data,
return CURLE_WEIRD_SERVER_REPLY;
}
/* We have received a 220 response fine, now we proceed. */
#ifdef HAVE_GSSAPI
if(data->set.krb) {
/* If not anonymous login, try a secure login. Note that this
procedure is still BLOCKING. */
Curl_sec_request_prot(conn, "private");
/* We set private first as default, in case the line below fails to
set a valid level */
Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
if(Curl_sec_login(data, conn)) {
failf(data, "secure login failed");
return CURLE_WEIRD_SERVER_REPLY;
}
infof(data, "Authentication successful");
}
#endif
if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
/* We do not have an SSL/TLS control connection yet, but FTPS is
requested. Try an FTPS connection now */
@@ -3403,7 +3365,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
pp->response_time = 60*1000; /* give it only a minute for now */
pp->response = curlx_now(); /* timeout relative now */
result = Curl_GetFTPResponse(data, &nread, &ftpcode);
result = getftpresponse(data, &nread, &ftpcode);
pp->response_time = old_time; /* set this back to previous value */
@@ -3526,7 +3488,7 @@ CURLcode ftp_sendquote(struct Curl_easy *data,
result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
if(!result) {
pp->response = curlx_now(); /* timeout relative now */
result = Curl_GetFTPResponse(data, &nread, &ftpcode);
result = getftpresponse(data, &nread, &ftpcode);
}
if(result)
return result;

View File

@@ -35,9 +35,6 @@ extern const struct Curl_handler Curl_handler_ftp;
extern const struct Curl_handler Curl_handler_ftps;
#endif
CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nread,
int *ftpcode);
bool ftp_conns_match(struct connectdata *needle, struct connectdata *conn);
#endif /* CURL_DISABLE_FTP */

View File

@@ -1,953 +0,0 @@
/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
*
* Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* Copyright (C) Daniel Stenberg
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. */
#include "curl_setup.h"
#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP)
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include "urldata.h"
#include "url.h"
#include "cfilters.h"
#include "cf-socket.h"
#include "curlx/base64.h"
#include "ftp.h"
#include "curl_gssapi.h"
#include "sendf.h"
#include "transfer.h"
#include "curl_krb5.h"
#include "curlx/warnless.h"
#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
#if defined(__GNUC__) && defined(__APPLE__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
const char *cmd)
{
size_t bytes_written;
#define SBUF_SIZE 1024
char s[SBUF_SIZE];
size_t write_len;
char *sptr = s;
CURLcode result = CURLE_OK;
#ifdef HAVE_GSSAPI
unsigned char data_sec = conn->data_prot;
#endif
DEBUGASSERT(cmd);
write_len = strlen(cmd);
if(!write_len || write_len > (sizeof(s) -3))
return CURLE_BAD_FUNCTION_ARGUMENT;
memcpy(&s, cmd, write_len);
strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
write_len += 2;
bytes_written = 0;
for(;;) {
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
#ifdef HAVE_GSSAPI
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
conn->data_prot = data_sec;
#endif
if(result)
break;
Curl_debug(data, CURLINFO_HEADER_OUT, sptr, bytes_written);
if(bytes_written != write_len) {
write_len -= bytes_written;
sptr += bytes_written;
}
else
break;
}
return result;
}
static int
krb5_init(void *app_data)
{
gss_ctx_id_t *context = app_data;
/* Make sure our context is initialized for krb5_end. */
*context = GSS_C_NO_CONTEXT;
return 0;
}
static int
krb5_check_prot(void *app_data, int level)
{
(void)app_data;
if(level == PROT_CONFIDENTIAL)
return -1;
return 0;
}
static int
krb5_decode(void *app_data, void *buf, int len,
int level, struct connectdata *conn)
{
gss_ctx_id_t *context = app_data;
OM_uint32 maj, min;
gss_buffer_desc enc, dec;
(void)level;
(void)conn;
enc.value = buf;
enc.length = len;
maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL);
if(maj != GSS_S_COMPLETE)
return -1;
memcpy(buf, dec.value, dec.length);
len = curlx_uztosi(dec.length);
gss_release_buffer(&min, &dec);
return len;
}
static int
krb5_encode(void *app_data, const void *from, int length, int level, void **to)
{
gss_ctx_id_t *context = app_data;
gss_buffer_desc dec, enc;
OM_uint32 maj, min;
int state;
int len;
/* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
* libraries modify the input buffer in gss_wrap()
*/
dec.value = CURL_UNCONST(from);
dec.length = (size_t)length;
maj = gss_wrap(&min, *context,
level == PROT_PRIVATE,
GSS_C_QOP_DEFAULT,
&dec, &state, &enc);
if(maj != GSS_S_COMPLETE)
return -1;
/* malloc a new buffer, in case gss_release_buffer does not work as
expected */
*to = malloc(enc.length);
if(!*to)
return -1;
memcpy(*to, enc.value, enc.length);
len = curlx_uztosi(enc.length);
gss_release_buffer(&min, &enc);
return len;
}
static int
krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
{
int ret = AUTH_OK;
char *p;
const char *host = conn->host.name;
ssize_t nread;
curl_socklen_t l = sizeof(conn->local_addr);
CURLcode result;
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
"ftp";
const char *srv_host = "host";
gss_buffer_desc input_buffer, output_buffer, *gssresp;
gss_buffer_desc _gssresp = GSS_C_EMPTY_BUFFER;
OM_uint32 maj, min;
gss_name_t gssname;
gss_ctx_id_t *context = app_data;
struct gss_channel_bindings_struct chan;
size_t base64_sz = 0;
const struct Curl_sockaddr_ex *remote_addr =
Curl_conn_get_remote_addr(data, FIRSTSOCKET);
struct sockaddr_in *remote_in_addr = remote_addr ?
(struct sockaddr_in *)CURL_UNCONST(&remote_addr->curl_sa_addr) : NULL;
char *stringp;
struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN);
if(!ftpc || !remote_in_addr)
return -2;
if(getsockname(conn->sock[FIRSTSOCKET],
(struct sockaddr *)&conn->local_addr, &l) < 0)
perror("getsockname()");
chan.initiator_addrtype = GSS_C_AF_INET;
chan.initiator_address.length = l - 4;
chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr;
chan.acceptor_addrtype = GSS_C_AF_INET;
chan.acceptor_address.length = l - 4;
chan.acceptor_address.value = &remote_in_addr->sin_addr.s_addr;
chan.application_data.length = 0;
chan.application_data.value = NULL;
/* this loop will execute twice (once for service, once for host) */
for(;;) {
/* this really should not be repeated here, but cannot help it */
if(service == srv_host) {
result = ftpsend(data, conn, "AUTH GSSAPI");
if(result)
return -2;
if(Curl_GetFTPResponse(data, &nread, NULL))
return -1;
else {
char *line = curlx_dyn_ptr(&ftpc->pp.recvbuf);
if(line[0] != '3')
return -1;
}
}
stringp = aprintf("%s@%s", service, host);
if(!stringp)
return -2;
input_buffer.value = stringp;
input_buffer.length = strlen(stringp);
maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE,
&gssname);
free(stringp);
if(maj != GSS_S_COMPLETE) {
gss_release_name(&min, &gssname);
if(service == srv_host) {
failf(data, "Error importing service name %s@%s", service, host);
return AUTH_ERROR;
}
service = srv_host;
continue;
}
/* We pass NULL as |output_name_type| to avoid a leak. */
gss_display_name(&min, gssname, &output_buffer, NULL);
infof(data, "Trying against %s", (char *)output_buffer.value);
gssresp = GSS_C_NO_BUFFER;
*context = GSS_C_NO_CONTEXT;
do {
/* Release the buffer at each iteration to avoid leaking: the first time
we are releasing the memory from gss_display_name. The last item is
taken care by a final gss_release_buffer. */
gss_release_buffer(&min, &output_buffer);
ret = AUTH_OK;
maj = Curl_gss_init_sec_context(data,
&min,
context,
gssname,
&Curl_krb5_mech_oid,
&chan,
gssresp,
&output_buffer,
TRUE,
NULL);
if(gssresp) {
free(_gssresp.value);
gssresp = NULL;
}
if(GSS_ERROR(maj)) {
infof(data, "Error creating security context");
ret = AUTH_ERROR;
break;
}
if(output_buffer.length) {
char *cmd;
result = curlx_base64_encode((char *)output_buffer.value,
output_buffer.length, &p, &base64_sz);
if(result) {
infof(data, "base64-encoding: %s", curl_easy_strerror(result));
ret = AUTH_ERROR;
break;
}
cmd = aprintf("ADAT %s", p);
if(cmd)
result = ftpsend(data, conn, cmd);
else
result = CURLE_OUT_OF_MEMORY;
free(p);
free(cmd);
if(result) {
ret = -2;
break;
}
if(Curl_GetFTPResponse(data, &nread, NULL)) {
ret = -1;
break;
}
else {
size_t len = curlx_dyn_len(&ftpc->pp.recvbuf);
p = curlx_dyn_ptr(&ftpc->pp.recvbuf);
if((len < 4) || (p[0] != '2' && p[0] != '3')) {
infof(data, "Server did not accept auth data");
ret = AUTH_ERROR;
break;
}
}
_gssresp.value = NULL; /* make sure it is initialized */
_gssresp.length = 0;
p += 4; /* over '789 ' */
p = strstr(p, "ADAT=");
if(p) {
unsigned char *outptr;
size_t outlen;
result = curlx_base64_decode(p + 5, &outptr, &outlen);
if(result) {
failf(data, "base64-decoding: %s", curl_easy_strerror(result));
ret = AUTH_CONTINUE;
break;
}
_gssresp.value = outptr;
_gssresp.length = outlen;
}
gssresp = &_gssresp;
}
} while(maj == GSS_S_CONTINUE_NEEDED);
gss_release_name(&min, &gssname);
gss_release_buffer(&min, &output_buffer);
if(gssresp)
free(_gssresp.value);
if(ret == AUTH_OK || service == srv_host)
break;
service = srv_host;
}
return ret;
}
static void krb5_end(void *app_data)
{
OM_uint32 min;
gss_ctx_id_t *context = app_data;
if(*context != GSS_C_NO_CONTEXT) {
OM_uint32 maj = Curl_gss_delete_sec_context(&min, context,
GSS_C_NO_BUFFER);
(void)maj;
DEBUGASSERT(maj == GSS_S_COMPLETE);
}
}
static const struct Curl_sec_client_mech Curl_krb5_client_mech = {
"GSSAPI",
sizeof(gss_ctx_id_t),
krb5_init,
krb5_auth,
krb5_end,
krb5_check_prot,
krb5_encode,
krb5_decode
};
static const struct {
unsigned char level;
const char *name;
} level_names[] = {
{ PROT_CLEAR, "clear" },
{ PROT_SAFE, "safe" },
{ PROT_CONFIDENTIAL, "confidential" },
{ PROT_PRIVATE, "private" }
};
static unsigned char name_to_level(const char *name)
{
int i;
for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
if(curl_strequal(name, level_names[i].name))
return level_names[i].level;
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:
default:
/* Those 2 cases should not be reached! */
break;
}
DEBUGASSERT(0);
/* Default to the most secure alternative. */
return 'P';
}
/* 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 Curl_easy *data, const char *message, ...)
CURL_PRINTF(2, 3);
static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
{
int ftp_code;
ssize_t nread = 0;
va_list args;
char print_buffer[50];
va_start(args, message);
mvsnprintf(print_buffer, sizeof(print_buffer), message, args);
va_end(args);
if(ftpsend(data, data->conn, print_buffer)) {
ftp_code = -1;
}
else {
if(Curl_GetFTPResponse(data, &nread, &ftp_code))
ftp_code = -1;
}
(void)nread;
return ftp_code;
}
/* 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(struct Curl_easy *data, int sockindex, void *to, size_t len)
{
char *to_p = to;
CURLcode result;
size_t nread = 0;
while(len > 0) {
result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
if(result == CURLE_AGAIN)
continue;
if(result)
return result;
if(nread > len)
return CURLE_RECV_ERROR;
len -= nread;
to_p += nread;
}
return CURLE_OK;
}
/* 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 Curl_easy *data, int sockindex, const void *to,
size_t len)
{
const char *to_p = to;
CURLcode result;
size_t written;
while(len > 0) {
result = Curl_conn_send(data, sockindex, to_p, len, FALSE, &written);
if(!result && written > 0) {
len -= written;
to_p += written;
}
else {
if(result == CURLE_AGAIN)
continue;
return result;
}
}
return CURLE_OK;
}
static CURLcode krb5_read_data(struct Curl_easy *data, int sockindex,
struct krb5buffer *buf)
{
struct connectdata *conn = data->conn;
int len;
CURLcode result;
int nread;
result = socket_read(data, sockindex, &len, sizeof(len));
if(result)
return result;
if(len) {
len = (int)ntohl((uint32_t)len);
if(len > CURL_MAX_INPUT_LENGTH)
return CURLE_TOO_LARGE;
curlx_dyn_reset(&buf->buf);
}
else
return CURLE_RECV_ERROR;
do {
char buffer[1024];
nread = CURLMIN(len, (int)sizeof(buffer));
result = socket_read(data, sockindex, buffer, (size_t)nread);
if(result)
return result;
result = curlx_dyn_addn(&buf->buf, buffer, nread);
if(result)
return result;
len -= nread;
} while(len);
/* this decodes the dynbuf *in place* */
nread = conn->mech->decode(conn->app_data,
curlx_dyn_ptr(&buf->buf),
len, conn->data_prot, conn);
if(nread < 0)
return CURLE_RECV_ERROR;
curlx_dyn_setlen(&buf->buf, nread);
buf->index = 0;
return CURLE_OK;
}
static size_t
buffer_read(struct krb5buffer *buf, void *data, size_t len)
{
size_t size = curlx_dyn_len(&buf->buf);
if(size - buf->index < len)
len = size - buf->index;
memcpy(data, curlx_dyn_ptr(&buf->buf) + buf->index, len);
buf->index += len;
return len;
}
/* Matches Curl_recv signature */
static CURLcode sec_recv(struct Curl_easy *data, int sockindex,
char *buffer, size_t len, size_t *pnread)
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
size_t bytes_read;
/* Handle clear text response. */
if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
return Curl_conn_recv(data, sockindex, buffer, len, pnread);
if(conn->in_buffer.eof_flag) {
conn->in_buffer.eof_flag = 0;
*pnread = 0;
return CURLE_OK;
}
bytes_read = buffer_read(&conn->in_buffer, buffer, len);
buffer += bytes_read;
len -= bytes_read;
*pnread += bytes_read;
while(len > 0) {
result = krb5_read_data(data, sockindex, &conn->in_buffer);
if(result)
return result;
if(curlx_dyn_len(&conn->in_buffer.buf) == 0) {
if(*pnread > 0)
conn->in_buffer.eof_flag = 1;
return result;
}
bytes_read = buffer_read(&conn->in_buffer, buffer, len);
buffer += bytes_read;
len -= bytes_read;
*pnread += bytes_read;
}
return result;
}
/* Send |length| bytes from |from| to the |sockindex| socket taking care of
encoding and negotiating with the server. |from| can be NULL. */
static CURLcode do_sec_send(struct Curl_easy *data, struct connectdata *conn,
int sockindex, const char *from, size_t length)
{
int bytes, htonl_bytes; /* 32-bit integers for htonl */
char *buffer = NULL;
char *cmd_buffer;
size_t cmd_size = 0;
enum protection_level prot_level = conn->data_prot;
bool iscmd = (prot_level == PROT_CMD);
CURLcode result = CURLE_OK;
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, (int)length,
(int)prot_level, (void **)&buffer);
if(!buffer || bytes <= 0)
return CURLE_OUT_OF_MEMORY; /* error */
if(iscmd) {
result = curlx_base64_encode(buffer, curlx_sitouz(bytes),
&cmd_buffer, &cmd_size);
if(result) {
free(buffer);
return result; /* error */
}
if(cmd_size > 0) {
static const char *enc = "ENC ";
static const char *mic = "MIC ";
if(prot_level == PROT_PRIVATE)
result = socket_write(data, sockindex, enc, 4);
else
result = socket_write(data, sockindex, mic, 4);
if(!result)
result = socket_write(data, sockindex, cmd_buffer, cmd_size);
if(!result)
result = socket_write(data, sockindex, "\r\n", 2);
if(!result)
infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic,
cmd_buffer);
}
free(cmd_buffer);
}
else {
htonl_bytes = (int)htonl((OM_uint32)bytes);
result = socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes));
if(!result)
result = socket_write(data, sockindex, buffer, curlx_sitouz(bytes));
}
free(buffer);
return result;
}
static CURLcode sec_write(struct Curl_easy *data, int sockindex,
const char *buffer, size_t length,
size_t *pnwritten)
{
struct connectdata *conn = data->conn;
size_t len = conn->buffer_size;
*pnwritten = 0;
if(len <= 0)
len = length;
while(length) {
CURLcode result;
if(length < len)
len = length;
result = do_sec_send(data, conn, sockindex, buffer, len);
if(result)
return result;
length -= len;
buffer += len;
*pnwritten += len;
}
return CURLE_OK;
}
/* Matches Curl_send signature */
static CURLcode sec_send(struct Curl_easy *data, int sockindex,
const void *buffer, size_t len, bool eos,
size_t *pnwritten)
{
(void)eos;
return sec_write(data, sockindex, buffer, len, pnwritten);
}
int Curl_sec_read_msg(struct Curl_easy *data, 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 = 0;
size_t decoded_sz = 0;
CURLcode error;
(void)data;
if(!conn->mech)
/* not initialized, return error */
return -1;
DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
error = curlx_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,
(int)level, conn);
if(decoded_len <= 0) {
free(buf);
return -1;
}
{
buf[decoded_len] = '\n';
Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1);
}
buf[decoded_len] = '\0';
if(decoded_len <= 3)
/* suspiciously short */
return 0;
if(buf[3] != '-')
ret_code = atoi(buf);
if(buf[decoded_len - 1] == '\n')
buf[decoded_len - 1] = '\0';
strcpy(buffer, buf);
free(buf);
return ret_code;
}
static int sec_set_protection_level(struct Curl_easy *data)
{
int code;
struct connectdata *conn = data->conn;
unsigned char level = conn->request_data_prot;
DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
if(!conn->sec_complete) {
infof(data, "Trying to change the protection level after the"
" completion of the data exchange.");
return -1;
}
/* Bail out if we try to set up the same level */
if(conn->data_prot == level)
return 0;
if(level) {
char *pbsz;
unsigned int buffer_size = 1 << 20; /* 1048576 */
struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN);
char *line;
if(!ftpc)
return -2;
code = ftp_send_command(data, "PBSZ %u", buffer_size);
if(code < 0)
return -1;
if(code/100 != 2) {
failf(data, "Failed to set the protection's buffer size.");
return -1;
}
conn->buffer_size = buffer_size;
line = curlx_dyn_ptr(&ftpc->pp.recvbuf);
pbsz = strstr(line, "PBSZ=");
if(pbsz) {
/* stick to default value if the check fails */
if(ISDIGIT(pbsz[5]))
buffer_size = (unsigned int)atoi(&pbsz[5]);
if(buffer_size < conn->buffer_size)
conn->buffer_size = buffer_size;
}
}
/* Now try to negotiate the protection level. */
code = ftp_send_command(data, "PROT %c", level_to_char(level));
if(code < 0)
return -1;
if(code/100 != 2) {
failf(data, "Failed to set the protection level.");
return -1;
}
conn->data_prot = level;
if(level == PROT_PRIVATE)
conn->command_prot = level;
return 0;
}
int
Curl_sec_request_prot(struct connectdata *conn, const char *level)
{
unsigned char l = name_to_level(level);
if(l == PROT_NONE)
return -1;
DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
conn->request_data_prot = l;
return 0;
}
static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
{
int ret;
void *tmp_allocation;
const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
tmp_allocation = realloc(conn->app_data, mech->size);
if(!tmp_allocation) {
failf(data, "Failed realloc of size %zu", 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.",
mech->name);
return CURLE_FAILED_INIT;
}
}
infof(data, "Trying mechanism %s...", mech->name);
ret = ftp_send_command(data, "AUTH %s", mech->name);
if(ret < 0)
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).", mech->name);
break;
case 534:
infof(data, "Mechanism %s was rejected by the server (server returned "
"ftp code: 534).", mech->name);
break;
default:
if(ret/100 == 5) {
infof(data, "server does not support the security extensions");
return CURLE_USE_SSL_FAILED;
}
break;
}
return CURLE_LOGIN_DENIED;
}
/* Authenticate */
ret = mech->auth(conn->app_data, data, conn);
if(ret != AUTH_CONTINUE) {
if(ret != AUTH_OK) {
/* Mechanism has dumped the error to stderr, do not error here. */
return CURLE_USE_SSL_FAILED;
}
DEBUGASSERT(ret == AUTH_OK);
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;
/* Set the requested protection level */
/* BLOCKING */
(void)sec_set_protection_level(data);
}
return CURLE_OK;
}
CURLcode
Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
{
return choose_mech(data, conn);
}
void
Curl_sec_conn_init(struct connectdata *conn)
{
curlx_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH);
conn->in_buffer.index = 0;
conn->in_buffer.eof_flag = 0;
}
void
Curl_sec_conn_destroy(struct connectdata *conn)
{
if(conn->mech && conn->mech->end)
conn->mech->end(conn->app_data);
Curl_safefree(conn->app_data);
curlx_dyn_free(&conn->in_buffer.buf);
conn->in_buffer.index = 0;
conn->in_buffer.eof_flag = 0;
conn->sec_complete = 0;
conn->data_prot = PROT_CLEAR;
conn->mech = NULL;
}
#if defined(__GNUC__) && defined(__APPLE__)
#pragma GCC diagnostic pop
#endif
#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */

View File

@@ -182,10 +182,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
CURLcode result;
struct connectdata *conn = data->conn;
#ifdef HAVE_GSSAPI
enum protection_level data_sec;
#endif
DEBUGASSERT(pp->sendleft == 0);
DEBUGASSERT(pp->sendsize == 0);
DEBUGASSERT(pp->sendthis == NULL);
@@ -208,9 +204,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
write_len = curlx_dyn_len(&pp->sendbuf);
s = curlx_dyn_ptr(&pp->sendbuf);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, FALSE,
&bytes_written);
if(result == CURLE_AGAIN) {
@@ -218,11 +211,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
}
else if(result)
return result;
#ifdef HAVE_GSSAPI
data_sec = conn->data_prot;
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
conn->data_prot = (unsigned char)data_sec;
#endif
Curl_debug(data, CURLINFO_HEADER_OUT, s, bytes_written);
@@ -272,17 +260,7 @@ static CURLcode pingpong_read(struct Curl_easy *data,
size_t buflen,
size_t *nread)
{
CURLcode result;
#ifdef HAVE_GSSAPI
enum protection_level prot = data->conn->data_prot;
data->conn->data_prot = PROT_CLEAR;
#endif
result = Curl_conn_recv(data, sockindex, buffer, buflen, nread);
#ifdef HAVE_GSSAPI
DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
data->conn->data_prot = (unsigned char)prot;
#endif
return result;
return Curl_conn_recv(data, sockindex, buffer, buflen, nread);
}
/*
@@ -348,10 +326,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
size_t length = nl - line + 1;
/* output debug output if that is requested */
#ifdef HAVE_GSSAPI
if(!conn->sec_complete)
#endif
Curl_debug(data, CURLINFO_HEADER_IN, line, length);
Curl_debug(data, CURLINFO_HEADER_IN, line, length);
/*
* Pass all response-lines to the callback function registered for

View File

@@ -1967,15 +1967,8 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
case CURLOPT_FTP_ALTERNATIVE_TO_USER:
return Curl_setstropt(&s->str[STRING_FTP_ALTERNATIVE_TO_USER], ptr);
#ifdef HAVE_GSSAPI
case CURLOPT_KRBLEVEL:
/*
* A string that defines the kerberos security level.
*/
result = Curl_setstropt(&s->str[STRING_KRB_LEVEL], ptr);
s->krb = !!(s->str[STRING_KRB_LEVEL]);
break;
#endif
return CURLE_NOT_BUILT_IN; /* removed in 8.17.0 */
#endif
case CURLOPT_URL:
/*

View File

@@ -98,7 +98,6 @@
#include "hsts.h"
#include "noproxy.h"
#include "cfilters.h"
#include "curl_krb5.h"
#include "idn.h"
/* And now for the protocols */
@@ -606,7 +605,6 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
#endif
Curl_sec_conn_destroy(conn);
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
Curl_safefree(conn->sasl_authzid);
@@ -1455,10 +1453,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
/* Initialize the attached xfers bitset */
Curl_uint_spbset_init(&conn->xfers_attached);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CLEAR;
#endif
/* Store the local bind parameters that will be used for this connection */
if(data->set.str[STRING_DEVICE]) {
conn->localdev = strdup(data->set.str[STRING_DEVICE]);
@@ -3473,10 +3467,7 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Do the unfailable inits first, before checks that may early return */
Curl_hash_init(&conn->meta_hash, 23,
Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
/* GSSAPI related inits */
Curl_sec_conn_init(conn);
Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
result = parseurlandfillconn(data, conn);
if(result)

View File

@@ -234,25 +234,6 @@ typedef CURLcode (Curl_recv)(struct Curl_easy *data, /* transfer */
((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
#endif
#ifdef HAVE_GSSAPI
/* Types needed for krb5-ftp connections */
struct krb5buffer {
struct dynbuf buf;
size_t index;
BIT(eof_flag);
};
enum protection_level {
PROT_NONE, /* first in list */
PROT_CLEAR,
PROT_SAFE,
PROT_CONFIDENTIAL,
PROT_PRIVATE,
PROT_CMD,
PROT_LAST /* last in list */
};
#endif
/* SSL backend-specific data; declared differently by each SSL backend */
struct ssl_backend_data;
struct Curl_ssl_scache_entry;
@@ -703,20 +684,6 @@ struct connectdata {
was used on this connection. */
struct curltime keepalive;
/**** curl_get() phase fields */
#ifdef HAVE_GSSAPI
BIT(sec_complete); /* if Kerberos is enabled for this connection */
unsigned char command_prot; /* enum protection_level */
unsigned char data_prot; /* enum protection_level */
unsigned char request_data_prot; /* enum protection_level */
size_t buffer_size;
struct krb5buffer in_buffer;
void *app_data;
const struct Curl_sec_client_mech *mech;
struct sockaddr_in local_addr;
#endif
struct uint_spbset xfers_attached; /* mids of attached transfers */
/* A connection cache from a SHARE might be used in several multi handles.
* We MUST not reuse connections that are running in another multi,
@@ -1239,9 +1206,6 @@ enum dupstring {
STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
STRING_FTPPORT, /* port to send with the FTP PORT command */
#endif
#ifdef HAVE_GSSAPI
STRING_KRB_LEVEL, /* krb security level */
#endif
#ifndef CURL_DISABLE_NETRC
STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find
$HOME/.netrc */
@@ -1604,9 +1568,6 @@ struct UserDefined {
location: */
BIT(opt_no_body); /* as set with CURLOPT_NOBODY */
BIT(verbose); /* output verbosity */
#ifdef HAVE_GSSAPI
BIT(krb); /* Kerberos connection requested */
#endif
BIT(reuse_forbid); /* forbidden to be reused, close after use */
BIT(reuse_fresh); /* do not reuse an existing connection */
BIT(no_signal); /* do not use any signal/alarm handler */

View File

@@ -973,7 +973,6 @@ CURLcode config2setopts(struct OperationConfig *config,
customrequest_helper(config->httpreq, config->customrequest);
my_setopt(curl, CURLOPT_STDERR, tool_stderr);
my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
progressbarinit(&per->progressbar, config);
my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers);
my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface);

View File

@@ -196,8 +196,8 @@ static const struct LongShort aliases[]= {
{"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME},
{"key", ARG_FILE, ' ', C_KEY},
{"key-type", ARG_STRG|ARG_TLS, ' ', C_KEY_TYPE},
{"krb", ARG_STRG, ' ', C_KRB},
{"krb4", ARG_STRG, ' ', C_KRB4},
{"krb", ARG_STRG|ARG_DEPR, ' ', C_KRB},
{"krb4", ARG_STRG|ARG_DEPR, ' ', C_KRB4},
{"libcurl", ARG_STRG, ' ', C_LIBCURL},
{"limit-rate", ARG_STRG, ' ', C_LIMIT_RATE},
{"list-only", ARG_BOOL, 'l', C_LIST_ONLY},
@@ -2371,13 +2371,6 @@ static ParameterError opt_string(struct OperationConfig *config,
/* interface */
err = getstr(&config->iface, nextarg, DENY_BLANK);
break;
case C_KRB: /* --krb */
/* kerberos level string */
if(!feature_spnego)
err = PARAM_LIBCURL_DOESNT_SUPPORT;
else
err = getstr(&config->krblevel, nextarg, DENY_BLANK);
break;
case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */
err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK);
break;

View File

@@ -343,7 +343,7 @@ const struct helptxt helptext[] = {
CURLHELP_TLS},
{" --krb <level>",
"Enable Kerberos with security <level>",
CURLHELP_FTP},
CURLHELP_DEPRECATED},
{" --libcurl <file>",
"Generate libcurl code for this command line",
CURLHELP_CURL | CURLHELP_GLOBAL},

View File

@@ -18,11 +18,8 @@ REPLY PASS 633 XXXXXXXX\x00\x00XXXXXXXX
<server>
ftp
</server>
<features>
GSS-API
</features>
<name>
FTP with 633 response before gss initialized
FTP with 633 response to auth
</name>
<command>
ftp://%HOSTIP:%FTPPORT/%TESTNUMBER