Unverified Commit c92d2e14 authored by Nikos Mavrogiannopoulos's avatar Nikos Mavrogiannopoulos Committed by Daniel Stenberg
Browse files

Added support for libssh SSH SCP back-end

libssh is an alternative library to libssh2.
https://www.libssh.org/



That patch set also introduces support for ECDSA
ed25519 keys, as well as gssapi authentication.

Signed-off-by: default avatarNikos Mavrogiannopoulos <nmav@redhat.com>
parent 3973ee6a
Loading
Loading
Loading
Loading
+85 −2
Original line number Diff line number Diff line
@@ -2716,8 +2716,15 @@ dnl Default to compiler & linker defaults for LIBSSH2 files & libraries.
OPT_LIBSSH2=off
AC_ARG_WITH(libssh2,dnl
AC_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points to the LIBSSH2 installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option])
AC_HELP_STRING([--without-libssh2], [disable LIBSSH2]),
  OPT_LIBSSH2=$withval)
AC_HELP_STRING([--with-libssh2], [enable LIBSSH2]),
  OPT_LIBSSH2=$withval, OPT_LIBSSH2=no)


OPT_LIBSSH=off
AC_ARG_WITH(libssh,dnl
AC_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to the LIBSSH installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option])
AC_HELP_STRING([--with-libssh], [enable LIBSSH]),
  OPT_LIBSSH=$withval, OPT_LIBSSH=no)

if test X"$OPT_LIBSSH2" != Xno; then
  dnl backup the pre-libssh2 variables
@@ -2792,6 +2799,79 @@ if test X"$OPT_LIBSSH2" != Xno; then
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_LIBSSH" != Xno; then
  dnl backup the pre-libssh variables
  CLEANLDFLAGS="$LDFLAGS"
  CLEANCPPFLAGS="$CPPFLAGS"
  CLEANLIBS="$LIBS"

  case "$OPT_LIBSSH" in
  yes)
    dnl --with-libssh (without path) used
    CURL_CHECK_PKGCONFIG(libssh)

    if test "$PKGCONFIG" != "no" ; then
      LIB_SSH=`$PKGCONFIG --libs-only-l libssh`
      LD_SSH=`$PKGCONFIG --libs-only-L libssh`
      CPP_SSH=`$PKGCONFIG --cflags-only-I libssh`
      version=`$PKGCONFIG --modversion libssh`
      DIR_SSH=`echo $LD_SSH | $SED -e 's/-L//'`
    fi

    ;;
  off)
    dnl no --with-libssh option given, just check default places
    ;;
  *)
    dnl use the given --with-libssh spot
    PREFIX_SSH=$OPT_LIBSSH
    ;;
  esac

  dnl if given with a prefix, we set -L and -I based on that
  if test -n "$PREFIX_SSH"; then
    LIB_SSH="-lssh"
    LD_SSH=-L${PREFIX_SSH}/lib$libsuff
    CPP_SSH=-I${PREFIX_SSH}/include
    DIR_SSH=${PREFIX_SSH;}/lib$libsuff
  fi

  LDFLAGS="$LDFLAGS $LD_SSH"
  CPPFLAGS="$CPPFLAGS $CPP_SSH"
  LIBS="$LIB_SSH $LIBS"

  AC_CHECK_LIB(ssh, ssh_new)

  AC_CHECK_HEADERS(libssh/libssh.h,
    curl_ssh_msg="enabled (libSSH)"
    LIBSSH_ENABLED=1
    AC_DEFINE(USE_LIBSSH, 1, [if libSSH is in use])
    AC_SUBST(USE_LIBSSH, [1])
  )

  if test X"$OPT_LIBSSH" != Xoff &&
     test "$LIBSSH_ENABLED" != "1"; then
    AC_MSG_ERROR([libSSH libs and/or directories were not found where specified!])
  fi

  if test "$LIBSSH_ENABLED" = "1"; then
    if test -n "$DIR_SSH"; then
       dnl when the libssh shared libs were found in a path that the run-time
       dnl linker doesn't search through, we need to add it to LD_LIBRARY_PATH
       dnl to prevent further configure tests to fail due to this

       if test "x$cross_compiling" != "xyes"; then
         LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$DIR_SSH"
         export LD_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_SSH to LD_LIBRARY_PATH])
       fi
    fi
  else
    dnl no libssh, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi

dnl **********************************************************************
@@ -4009,6 +4089,9 @@ if test "x$USE_LIBSSH2" = "x1"; then
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP"
fi
if test "x$USE_LIBSSH" = "x1"; then
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
fi
if test "x$CURL_DISABLE_RTSP" != "x1"; then
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP"
fi
+4 −1
Original line number Diff line number Diff line
@@ -715,6 +715,7 @@ typedef enum {
#define CURLSSH_AUTH_HOST      (1<<2) /* host key files */
#define CURLSSH_AUTH_KEYBOARD  (1<<3) /* keyboard interactive */
#define CURLSSH_AUTH_AGENT     (1<<4) /* agent (ssh-agent, pageant...) */
#define CURLSSH_AUTH_GSSAPI    (1<<5) /* gssapi (kerberos, ...) */
#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY

#define CURLGSSAPI_DELEGATION_NONE        0      /* no delegation (default) */
@@ -727,7 +728,9 @@ enum curl_khtype {
  CURLKHTYPE_UNKNOWN,
  CURLKHTYPE_RSA1,
  CURLKHTYPE_RSA,
  CURLKHTYPE_DSS
  CURLKHTYPE_DSS,
  CURLKHTYPE_ECDSA,
  CURLKHTYPE_ED25519
};

struct curl_khkey {
+4 −3
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
  http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c    \
  strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c         \
  inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c      \
  ssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c            \
  ssh.c ssh-libssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c            \
  curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c    \
  pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c        \
  openldap.c curl_gethostname.c gopher.c idn_win32.c                    \
@@ -54,7 +54,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
  http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c        \
  curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c          \
  x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c      \
  mime.c sha256.c setopt.c
  mime.c sha256.c setopt.c curl_path.c

LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
  formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h         \
@@ -73,7 +73,8 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
  curl_sasl.h curl_multibyte.h hostcheck.h conncache.h                  \
  curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h       \
  x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h           \
  curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h
  curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h     \
  curl_path.h

LIB_RCFILES = libcurl.rc

lib/curl_path.c

0 → 100644
+179 −0
Original line number Diff line number Diff line
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2017, 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.haxx.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.
 *
 ***************************************************************************/

#include "curl_setup.h"

#include <curl/curl.h>
#include "curl_memory.h"
#include "curl_path.h"
#include "escape.h"
#include "memdebug.h"

/* figure out the path to work with in this particular request */
CURLcode Curl_getworkingpath(struct connectdata *conn,
                             char *homedir,  /* when SFTP is used */
                             char **path) /* returns the  allocated
                                             real path to work with */
{
  struct Curl_easy *data = conn->data;
  char *real_path = NULL;
  char *working_path;
  size_t working_path_len;
  CURLcode result =
    Curl_urldecode(data, data->state.path, 0, &working_path,
                   &working_path_len, FALSE);
  if(result)
    return result;

  /* Check for /~/, indicating relative to the user's home directory */
  if(conn->handler->protocol & CURLPROTO_SCP) {
    real_path = malloc(working_path_len + 1);
    if(real_path == NULL) {
      free(working_path);
      return CURLE_OUT_OF_MEMORY;
    }
    if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
      /* It is referenced to the home directory, so strip the leading '/~/' */
      memcpy(real_path, working_path + 3, 4 + working_path_len-3);
    else
      memcpy(real_path, working_path, 1 + working_path_len);
  }
  else if(conn->handler->protocol & CURLPROTO_SFTP) {
    if((working_path_len > 1) && (working_path[1] == '~')) {
      size_t homelen = strlen(homedir);
      real_path = malloc(homelen + working_path_len + 1);
      if(real_path == NULL) {
        free(working_path);
        return CURLE_OUT_OF_MEMORY;
      }
      /* It is referenced to the home directory, so strip the
         leading '/' */
      memcpy(real_path, homedir, homelen);
      real_path[homelen] = '/';
      real_path[homelen + 1] = '\0';
      if(working_path_len > 3) {
        memcpy(real_path + homelen + 1, working_path + 3,
               1 + working_path_len -3);
      }
    }
    else {
      real_path = malloc(working_path_len + 1);
      if(real_path == NULL) {
        free(working_path);
        return CURLE_OUT_OF_MEMORY;
      }
      memcpy(real_path, working_path, 1 + working_path_len);
    }
  }

  free(working_path);

  /* store the pointer for the caller to receive */
  *path = real_path;

  return CURLE_OK;
}

/* The get_pathname() function is being borrowed from OpenSSH sftp.c
   version 4.6p1. */
/*
 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
CURLcode Curl_get_pathname(const char **cpp, char **path)
{
  const char *cp = *cpp, *end;
  char quot;
  unsigned int i, j;
  static const char WHITESPACE[] = " \t\r\n";

  cp += strspn(cp, WHITESPACE);
  if(!*cp) {
    *cpp = cp;
    *path = NULL;
    return CURLE_QUOTE_ERROR;
  }

  *path = malloc(strlen(cp) + 1);
  if(*path == NULL)
    return CURLE_OUT_OF_MEMORY;

  /* Check for quoted filenames */
  if(*cp == '\"' || *cp == '\'') {
    quot = *cp++;

    /* Search for terminating quote, unescape some chars */
    for(i = j = 0; i <= strlen(cp); i++) {
      if(cp[i] == quot) {  /* Found quote */
        i++;
        (*path)[j] = '\0';
        break;
      }
      if(cp[i] == '\0') {  /* End of string */
        /*error("Unterminated quote");*/
        goto fail;
      }
      if(cp[i] == '\\') {  /* Escaped characters */
        i++;
        if(cp[i] != '\'' && cp[i] != '\"' &&
            cp[i] != '\\') {
          /*error("Bad escaped character '\\%c'",
              cp[i]);*/
          goto fail;
        }
      }
      (*path)[j++] = cp[i];
    }

    if(j == 0) {
      /*error("Empty quotes");*/
      goto fail;
    }
    *cpp = cp + i + strspn(cp + i, WHITESPACE);
  }
  else {
    /* Read to end of filename */
    end = strpbrk(cp, WHITESPACE);
    if(end == NULL)
      end = strchr(cp, '\0');
    *cpp = end + strspn(end, WHITESPACE);

    memcpy(*path, cp, end - cp);
    (*path)[end - cp] = '\0';
  }
  return CURLE_OK;

  fail:
  Curl_safefree(*path);
  return CURLE_QUOTE_ERROR;
}

lib/curl_path.h

0 → 100644
+45 −0
Original line number Diff line number Diff line
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2017, 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.haxx.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.
 *
 ***************************************************************************/

#include "curl_setup.h"
#include <curl/curl.h>
#include "urldata.h"

#ifdef WIN32
#  undef  PATH_MAX
#  define PATH_MAX MAX_PATH
#  ifndef R_OK
#    define R_OK 4
#  endif
#endif

#ifndef PATH_MAX
#define PATH_MAX 1024 /* just an extra precaution since there are systems that
                         have their definition hidden well */
#endif

CURLcode Curl_getworkingpath(struct connectdata *conn,
                             char *homedir,
                             char **path);

CURLcode
Curl_get_pathname(const char **cpp, char **path);
Loading