]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
krb5: drop support for Kerberos FTP
authorDaniel Stenberg <daniel@haxx.se>
Wed, 17 Sep 2025 06:32:39 +0000 (08:32 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 20 Sep 2025 21:58:28 +0000 (23:58 +0200)
It was accidentally broken in commit 0f4c439fc7347f499cf5, 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 54967d2a3ab55596314 (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

22 files changed:
.github/scripts/spellcheck.words
LICENSES/BSD-3-Clause.txt [deleted file]
README
README.md
docs/cmdline-opts/krb.md
docs/libcurl/curl_easy_setopt.md
docs/libcurl/opts/CURLOPT_KRBLEVEL.md
docs/libcurl/symbols-in-versions
include/curl/curl.h
lib/Makefile.inc
lib/curl_krb5.h [deleted file]
lib/ftp.c
lib/ftp.h
lib/krb5.c [deleted file]
lib/pingpong.c
lib/setopt.c
lib/url.c
lib/urldata.h
src/config2setopts.c
src/tool_getparam.c
src/tool_listhelp.c
tests/data/test1282

index 46c05b741bcfee135140bd1e1d673192577739fd..aafaeff6d927d85713feeade3f9b86fbff3532cf 100644 (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
diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt
deleted file mode 100644 (file)
index 086d399..0000000
+++ /dev/null
@@ -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.
diff --git a/README b/README
index f5efbd70a69decce435bacce9f0da0702edecb6e..df320f94810eea198e4d67fc507d0fd46a4af618 100644 (file)
--- a/README
+++ b/README
@@ -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.
index 3359818fd5723d258f0099f228a02b8bcda26f1b..32a3c34fb0f2dc8219ee058f960d55aa7bb68c60 100644 (file)
--- a/README.md
+++ b/README.md
@@ -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).
index c353a0c7400986b9cbf82bec0543e867070af834..6d47a76d6ec493638998292048fcc3a339d821a8 100644 (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.
index ccca56de6b24f8657bcf4a42a19ecd011c26d28c..430c3c14abbcdb498182a6c07ec150b3788476fa 100644 (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
 
index bdea064600cc0991c0480aa7676aedfae7a1b4ee..8dc5de7cee7ccf6971c9211c555f1f3fa52625d3 100644 (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
index bfcf357bf6fb099d8b1d3388630088c66e5f5255..43435cb16b5ba8fde0e273393e2a7b3ffef0a8ca 100644 (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
index 6f4aa90f1349ba8b417866d2c92925d0da2cf609..49552558ddb742941eb3ec94a0c75a34565c93a2 100644 (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),
index 524fdcc53d5a7c0513729d50926096cda359e6ef..c17a8d9c3cade643a9a5251e001bc147fa874cb7 100644 (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         \
diff --git a/lib/curl_krb5.h b/lib/curl_krb5.h
deleted file mode 100644 (file)
index 574340f..0000000
+++ /dev/null
@@ -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 */
index 1e2cd4d3cfebce1eea2138ed31b1399c329a3890..df94ea5e6684401f1231f4f83e8b5fc197ef86fa 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -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;
index aba1db7f2d3d6f96e503d25c271d9b2d9e878d90..fdbb4b0539f260018cb42d16ec59b2f1e0086e02 100644 (file)
--- a/lib/ftp.h
+++ b/lib/ftp.h
@@ -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 */
diff --git a/lib/krb5.c b/lib/krb5.c
deleted file mode 100644 (file)
index b041d2f..0000000
+++ /dev/null
@@ -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 */
index 003ad58441c7b672bc8e0857ad96e7293fe5d624..195e059ed1f4f9f06eaeefe0a9a6515badb1e602 100644 (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
index d958c5492a8dbb8803555ae62474e387da0b05b2..3f628c443ca4787b4bab711aef0365dad73dd6e3 100644 (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:
     /*
index 3f792ec7655e4839e99e9024d6e34f45acdd4374..a03a111995e285d53f5953e18e7b463c38774c9a 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -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)
index 4f00c8c9a093c7bb24f3e4347d28cad8237ea948..b2e83c4a0eef4984a325540b75aa4ffe4a1a92b4 100644 (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 */
index e8f4b0a407aec7d8f55e9f549ee2146982e8bf14..533fe992d34b2d89330ed39a6bdcf11cf7031683 100644 (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);
index 43d30778de6440563a9189161dbbf9a8330c7091..d7bdadb5d6d33fada0f0f0b3015515ca3d72a76a 100644 (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;
index ecbd8bf4595ef5fcee15411d3bc6ea1478c7133c..bd72dbe15c51c04976e0102e8f6ac305046ed683 100644 (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},
index f57275187f2e4026e37dbffe6e364aebe271d678..a54166be96613bd9aba88a4ed331924cd668317e 100644 (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