Commit 558814e1 authored by Jakub Zakrzewski's avatar Jakub Zakrzewski Committed by Daniel Stenberg
Browse files

Cmake: Build with GSSAPI (MIT or Heimdal)

It tries hard to recognise SDK's on different platforms. On windows MIT
Kerberos installs SDK with other things and puts path into registry.
Heimdal have separate zip archive. On linux pkg-config is tried, then
krb5-config script and finally old-style libs and headers detection.

Command line args:
* CMAKE_USE_GSSAPI - enables GSSAPI detection
* GSS_ROOT_DIR - if set, should point to the root of GSSAPI installation
                 (the one with include and lib directories)
parent a3154295
Loading
Loading
Loading
Loading

CMake/FindGSS.cmake

0 → 100644
+289 −0
Original line number Diff line number Diff line
# - Try to find the GSS Kerberos library
# Once done this will define
#
#  GSS_ROOT_DIR - Set this variable to the root installation of GSS
#
# Read-Only variables:
#  GSS_FOUND - system has the Heimdal library
#  GSS_FLAVOUR - "MIT" or "Heimdal" if anything found.
#  GSS_INCLUDE_DIR - the Heimdal include directory
#  GSS_LIBRARIES - The libraries needed to use GSS
#  GSS_LINK_DIRECTORIES - Directories to add to linker search path
#  GSS_LINKER_FLAGS - Additional linker flags
#  GSS_COMPILER_FLAGS - Additional compiler flags
#  GSS_VERSION - This is set to version advertised by pkg-config or read from manifest.
#                In case the library is found but no version info availabe it'll be set to "unknown"

set(_MIT_MODNAME mit-krb5-gssapi)
set(_HEIMDAL_MODNAME heimdal-gssapi)

include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckTypeSize)

set(_GSS_ROOT_HINTS
    "${GSS_ROOT_DIR}"
    "$ENV{GSS_ROOT_DIR}"
)

# try to find library using system pkg-config if user didn't specify root dir
if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
    if(UNIX)
        find_package(PkgConfig QUIET)
        pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME})
        list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}")
    elseif(WIN32)
        list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
    endif()
endif()

if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach.
    find_file(_GSS_CONFIGURE_SCRIPT
        NAMES
            "krb5-config"
        HINTS
            ${_GSS_ROOT_HINTS}
        PATH_SUFFIXES
            bin
        NO_CMAKE_PATH
        NO_CMAKE_ENVIRONMENT_PATH
    )

    # if not found in user-supplied directories, maybe system knows better
    find_file(_GSS_CONFIGURE_SCRIPT
        NAMES
            "krb5-config"
        PATH_SUFFIXES
            bin
    )

    if(_GSS_CONFIGURE_SCRIPT)
        execute_process(
            COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
            OUTPUT_VARIABLE _GSS_CFLAGS
            RESULT_VARIABLE _GSS_CONFIGURE_FAILED
        )
message(STATUS "CFLAGS: ${_GSS_CFLAGS}")
        if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
            # should also work in an odd case when multiple directories are given
            string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
            string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
            string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1"_GSS_CFLAGS "${_GSS_CFLAGS}")

            foreach(_flag ${_GSS_CFLAGS})
                if(_flag MATCHES "^-I.*")
                    string(REGEX REPLACE "^-I" "" _val "${_flag}")
                    list(APPEND _GSS_INCLUDE_DIR "${_val}")
                else()
                    list(APPEND _GSS_COMPILER_FLAGS "${_flag}")
                endif()
            endforeach()
        endif()

        execute_process(
            COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
            OUTPUT_VARIABLE _GSS_LIB_FLAGS
            RESULT_VARIABLE _GSS_CONFIGURE_FAILED
        )
message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}")
        if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
            # this script gives us libraries and link directories. Blah. We have to deal with it.
            string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS)
            string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
            string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1"_GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")

            foreach(_flag ${_GSS_LIB_FLAGS})
                if(_flag MATCHES "^-l.*")
                    string(REGEX REPLACE "^-l" "" _val "${_flag}")
                    list(APPEND _GSS_LIBRARIES "${_val}")
                elseif(_flag MATCHES "^-L.*")
                    string(REGEX REPLACE "^-L" "" _val "${_flag}")
                    list(APPEND _GSS_LINK_DIRECTORIES "${_val}")
                else()
                    list(APPEND _GSS_LINKER_FLAGS "${_flag}")
                endif()
            endforeach()
        endif()


        execute_process(
            COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
            OUTPUT_VARIABLE _GSS_VERSION
            RESULT_VARIABLE _GSS_CONFIGURE_FAILED
        )

        # older versions may not have the "--version" parameter. In this case we just don't care.
        if(_GSS_CONFIGURE_FAILED)
            set(_GSS_VERSION 0)
        endif()


        execute_process(
            COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
            OUTPUT_VARIABLE _GSS_VENDOR
            RESULT_VARIABLE _GSS_CONFIGURE_FAILED
        )

        # older versions may not have the "--vendor" parameter. In this case we just don't care.
        if(_GSS_CONFIGURE_FAILED)
            set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter
        else()
            if(_GSS_VENDOR MATCHES ".*H|heimdal.*")
                set(GSS_FLAVOUR "Heimdal")
            else()
                set(GSS_FLAVOUR "MIT")
            endif()
        endif()

    else() # either there is no config script or we are on platform that doesn't provide one (Windows?)

        find_path(_GSS_INCLUDE_DIR
            NAMES
                "gssapi/gssapi.h"
            HINTS
                ${_GSS_ROOT_HINTS}
            PATH_SUFFIXES
                include
                inc
        )

        if(_GSS_INCLUDE_DIR) #jay, we've found something
            set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}")
            check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS)

            if(_GSS_HAVE_MIT_HEADERS)
                set(GSS_FLAVOUR "MIT")
            else()
                # prevent compiling the header - just check if we can include it
                set(CMAKE_REQUIRED_DEFINITIONS "-D__ROKEN_H__")
                check_include_file( "roken.h" _GSS_HAVE_ROKEN_H)

                check_include_file( "heimdal/roken.h" _GSS_HAVE_HEIMDAL_ROKEN_H)
                if(_GSS_HAVE_ROKEN_H OR _GSS_HAVE_HEIMDAL_ROKEN_H)
                    set(GSS_FLAVOUR "Heimdal")
                endif()
                set(CMAKE_REQUIRED_DEFINITIONS "")
            endif()
        else()
            # I'm not convienced if this is the right way but this is what autotools do at the moment
            find_path(_GSS_INCLUDE_DIR
                NAMES
                    "gssapi.h"
                HINTS
                    ${_GSS_ROOT_HINTS}
                PATH_SUFFIXES
                    include
                    inc
            )

            if(_GSS_INCLUDE_DIR)
                set(GSS_FLAVOUR "Heimdal")
            endif()
        endif()

        # if we have headers, check if we can link libraries
        if(GSS_FLAVOUR)
            set(_GSS_LIBDIR_SUFFIXES "")
            set(_GSS_LIBDIR_HINTS ${_GSS_ROOT_HINTS})
            get_filename_component(_GSS_CALCULATED_POTENTIAL_ROOT "${_GSS_INCLUDE_DIR}" PATH)
            list(APPEND _GSS_LIBDIR_HINTS ${_GSS_CALCULATED_POTENTIAL_ROOT})

            if(WIN32)
                if(CMAKE_SIZEOF_VOID_P EQUAL 8)
                    list(APPEND _GSS_LIBDIR_SUFFIXES "lib/AMD64")
                    if(GSS_FLAVOUR STREQUAL "MIT")
                        set(_GSS_LIBNAME "gssapi64")
                    else()
                        set(_GSS_LIBNAME "libgssapi")
                    endif()
                else()
                    list(APPEND _GSS_LIBDIR_SUFFIXES "lib/i386")
                    if(GSS_FLAVOUR STREQUAL "MIT")
                        set(_GSS_LIBNAME "gssapi32")
                    else()
                        set(_GSS_LIBNAME "libgssapi")
                    endif()
                endif()
            else()
                list(APPEND _GSS_LIBDIR_SUFFIXES "lib;lib64") # those suffixes are not checked for HINTS
                if(GSS_FLAVOUR STREQUAL "MIT")
                    set(_GSS_LIBNAME "gssapi_krb5")
                else()
                    set(_GSS_LIBNAME "gssapi")
                endif()
            endif()

            find_library(_GSS_LIBRARIES
                NAMES
                    ${_GSS_LIBNAME}
                HINTS
                    ${_GSS_LIBDIR_HINTS}
                PATH_SUFFIXES
                    ${_GSS_LIBDIR_SUFFIXES}
            )

        endif()

    endif()
else()
    if(_GSS_PKG_${_MIT_MODNAME}_VERSION)
        set(GSS_FLAVOUR "MIT")
        set(_GSS_VERSION _GSS_PKG_${_MIT_MODNAME}_VERSION)
    else()
        set(GSS_FLAVOUR "Heimdal")
        set(_GSS_VERSION _GSS_PKG_${_MIT_HEIMDAL}_VERSION)
    endif()
endif()

set(GSS_INCLUDE_DIR ${_GSS_INCLUDE_DIR})
set(GSS_LIBRARIES ${_GSS_LIBRARIES})
set(GSS_LINK_DIRECTORIES ${_GSS_LINK_DIRECTORIES})
set(GSS_LINKER_FLAGS ${_GSS_LINKER_FLAGS})
set(GSS_COMPILER_FLAGS ${_GSS_COMPILER_FLAGS})
set(GSS_VERSION ${_GSS_VERSION})

if(GSS_FLAVOUR)

    if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal")
        if(CMAKE_SIZEOF_VOID_P EQUAL 8)
            set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.amd64.manifest")
        else()
            set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.x86.manifest")
        endif()

        if(EXISTS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}")
            file(STRINGS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}" heimdal_version_str
                 REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$")

            string(REGEX MATCH "[0-9]\\.[^\"]+"
                   GSS_VERSION "${heimdal_version_str}")
        endif()

        if(NOT GSS_VERSION)
            set(GSS_VERSION "Heimdal Unknown")
        endif()
    elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT")
        get_filename_component(_MIT_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE)
        if(WIN32 AND _MIT_VERSION)
            set(GSS_VERSION "${_MIT_VERSION}")
        else()
            set(GSS_VERSION "MIT Unknown")
        endif()
    endif()
endif()


include(FindPackageHandleStandardArgs)

set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR)

find_package_handle_standard_args(GSS
    REQUIRED_VARS
        ${_GSS_REQUIRED_VARS}
    VERSION_VAR
        GSS_VERSION
    FAIL_MESSAGE
        "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
)

mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES)
+64 −10
Original line number Diff line number Diff line
@@ -416,8 +416,64 @@ if(CMAKE_USE_LIBSSH2)
  endif(LIBSSH2_FOUND)
endif(CMAKE_USE_LIBSSH2)

# For other tests to use the same libraries
set(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBS})
option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
mark_as_advanced(CMAKE_USE_GSSAPI)

if(CMAKE_USE_GSSAPI)
  find_package(GSS)

  set(HAVE_GSS_API ${GSS_FOUND})
  if(GSS_FOUND)

    message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"")

    set(CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR})
    check_include_file_concat("gssapi/gssapi.h"  HAVE_GSSAPI_GSSAPI_H)
    check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
    check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)

    if(GSS_FLAVOUR STREQUAL "Heimdal")
      set(HAVE_GSSHEIMDAL ON)
    else() # MIT
      set(HAVE_GSSMIT ON)
      set(_INCLUDE_LIST "")
      if(HAVE_GSSAPI_GSSAPI_H)
        list(APPEND _INCLUDE_LIST "gssapi/gssapi.h")
      endif()
      if(HAVE_GSSAPI_GSSAPI_GENERIC_H)
        list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h")
      endif()
      if(HAVE_GSSAPI_GSSAPI_KRB5_H)
        list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h")
      endif()

      string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}")
      string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}")

      foreach(_dir ${GSS_LINK_DIRECTORIES})
        set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"")
      endforeach()

      set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}")
      set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES})
      check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE)
      if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE)
        set(HAVE_OLD_GSSMIT ON)
      endif()

    endif()

    include_directories(${GSS_INCLUDE_DIR})
    link_directories(${GSS_LINK_DIRECTORIES})
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
    list(APPEND CURL_LIBS ${GSS_LIBRARIES})

  else()
    message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.")
  endif()
endif()

# If we have features.h, then do the _BSD_SOURCE magic
check_include_file("features.h"       HAVE_FEATURES_H)
@@ -457,9 +513,6 @@ check_include_file_concat("des.h" HAVE_DES_H)
check_include_file_concat("err.h"            HAVE_ERR_H)
check_include_file_concat("errno.h"          HAVE_ERRNO_H)
check_include_file_concat("fcntl.h"          HAVE_FCNTL_H)
check_include_file_concat("gssapi/gssapi.h"  HAVE_GSSAPI_GSSAPI_H)
check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)
check_include_file_concat("idn-free.h"       HAVE_IDN_FREE_H)
check_include_file_concat("ifaddrs.h"        HAVE_IFADDRS_H)
check_include_file_concat("io.h"             HAVE_IO_H)
@@ -579,6 +632,12 @@ find_file(RANDOM_FILE urandom /dev)
mark_as_advanced(RANDOM_FILE)

# Check for some functions that are used
if(HAVE_LIBWS2_32)
  set(CMAKE_REQUIRED_LIBRARIES ws2_32)
elseif(HAVE_LIBSOCKET)
  set(CMAKE_REQUIRED_LIBRARIES socket)
endif()

check_symbol_exists(basename      "${CURL_INCLUDES}" HAVE_BASENAME)
check_symbol_exists(socket        "${CURL_INCLUDES}" HAVE_SOCKET)
check_symbol_exists(poll          "${CURL_INCLUDES}" HAVE_POLL)
@@ -680,12 +739,7 @@ if(NOT HAVE_STRICMP)
  set(HAVE_LDAP_URL_PARSE 1)
endif(NOT HAVE_STRICMP)



# Do curl specific tests
if(HAVE_LIBWS2_32)
  set(CMAKE_REQUIRED_LIBRARIES ws2_32)
endif()
foreach(CURL_TEST
    HAVE_FCNTL_O_NONBLOCK
    HAVE_IOCTLSOCKET
+3 −2
Original line number Diff line number Diff line
@@ -26,8 +26,9 @@ ACLOCAL_AMFLAGS = -I m4

CMAKE_DIST = CMakeLists.txt CMake/CMakeConfigurableFile.in		    \
CMake/CurlCheckCSourceCompiles.cmake CMake/CurlCheckCSourceRuns.cmake	    \
CMake/CurlTests.c CMake/OtherTests.cmake CMake/Platforms/WindowsCache.cmake \
CMake/Utilities.cmake include/curl/curlbuild.h.cmake
CMake/CurlTests.c CMake/FindGSS.cmake CMake/OtherTests.cmake                \
CMake/Platforms/WindowsCache.cmake CMake/Utilities.cmake                    \
include/curl/curlbuild.h.cmake

VC6_LIBTMPL = projects/Windows/VC6/lib/libcurl.tmpl
VC6_LIBDSP = projects/Windows/VC6/lib/libcurl.dsp