xref: /curl/CMake/FindGSS.cmake (revision 4490761a)
1#***************************************************************************
2#                                  _   _ ____  _
3#  Project                     ___| | | |  _ \| |
4#                             / __| | | | |_) | |
5#                            | (__| |_| |  _ <| |___
6#                             \___|\___/|_| \_\_____|
7#
8# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9#
10# This software is licensed as described in the file COPYING, which
11# you should have received as part of this distribution. The terms
12# are also available at https://curl.se/docs/copyright.html.
13#
14# You may opt to use, copy, modify, merge, publish, distribute and/or sell
15# copies of the Software, and permit persons to whom the Software is
16# furnished to do so, under the terms of the COPYING file.
17#
18# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19# KIND, either express or implied.
20#
21# SPDX-License-Identifier: curl
22#
23###########################################################################
24# Find the GSS Kerberos library
25#
26# Input variables:
27#
28# - `GSS_ROOT_DIR`:      Set this variable to the root installation of GSS. (also supported as environment)
29#
30# Result variables:
31#
32# - `GSS_FOUND`:         System has the Heimdal library.
33# - `GSS_FLAVOUR`:       "GNU", "MIT" or "Heimdal" if anything found.
34# - `GSS_INCLUDE_DIRS`:  The GSS include directories.
35# - `GSS_LIBRARIES`:     The GSS library names.
36# - `GSS_LIBRARY_DIRS`:  The GSS library directories.
37# - `GSS_PC_REQUIRES`:   The GSS pkg-config packages.
38# - `GSS_CFLAGS`:        Required compiler flags.
39# - `GSS_VERSION`:       This is set to version advertised by pkg-config or read from manifest.
40#                        In case the library is found but no version info available it is set to "unknown"
41
42set(_gnu_modname "gss")
43set(_mit_modname "mit-krb5-gssapi")
44set(_heimdal_modname "heimdal-gssapi")
45
46include(CheckIncludeFile)
47include(CheckIncludeFiles)
48include(CheckTypeSize)
49
50set(_gss_root_hints
51  "${GSS_ROOT_DIR}"
52  "$ENV{GSS_ROOT_DIR}"
53)
54
55# Try to find library using system pkg-config if user did not specify root dir
56if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
57  if(CURL_USE_PKGCONFIG)
58    find_package(PkgConfig QUIET)
59    pkg_search_module(_GSS ${_gnu_modname} ${_mit_modname} ${_heimdal_modname})
60    list(APPEND _gss_root_hints "${_GSS_PREFIX}")
61  endif()
62  if(WIN32)
63    list(APPEND _gss_root_hints "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
64  endif()
65endif()
66
67if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional approach.
68  find_file(_gss_configure_script
69    NAMES
70      "krb5-config"
71    HINTS
72      ${_gss_root_hints}
73    PATH_SUFFIXES
74      "bin"
75    NO_CMAKE_PATH
76    NO_CMAKE_ENVIRONMENT_PATH
77  )
78
79  # If not found in user-supplied directories, maybe system knows better
80  find_file(_gss_configure_script
81    NAMES
82      "krb5-config"
83    PATH_SUFFIXES
84      "bin"
85  )
86
87  if(_gss_configure_script)
88    execute_process(
89      COMMAND ${_gss_configure_script} "--cflags" "gssapi"
90      OUTPUT_VARIABLE _GSS_CFLAGS
91      RESULT_VARIABLE _gss_configure_failed
92      OUTPUT_STRIP_TRAILING_WHITESPACE
93    )
94    message(STATUS "FindGSS krb5-config --cflags: ${_GSS_CFLAGS}")
95    if(NOT _gss_configure_failed)  # 0 means success
96      # Should also work in an odd case when multiple directories are given
97      string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
98      string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
99      string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")
100
101      foreach(_flag IN LISTS _GSS_CFLAGS)
102        if(_flag MATCHES "^-I")
103          string(REGEX REPLACE "^-I" "" _val "${_flag}")
104          list(APPEND _GSS_INCLUDE_DIRS "${_val}")
105        else()
106          list(APPEND _GSS_CFLAGS "${_flag}")
107        endif()
108      endforeach()
109    endif()
110
111    execute_process(
112      COMMAND ${_gss_configure_script} "--libs" "gssapi"
113      OUTPUT_VARIABLE _gss_lib_flags
114      RESULT_VARIABLE _gss_configure_failed
115      OUTPUT_STRIP_TRAILING_WHITESPACE
116    )
117    message(STATUS "FindGSS krb5-config --libs: ${_gss_lib_flags}")
118
119    if(NOT _gss_configure_failed)  # 0 means success
120      # This script gives us libraries and link directories. Blah. We have to deal with it.
121      string(STRIP "${_gss_lib_flags}" _gss_lib_flags)
122      string(REGEX REPLACE " +-(L|l)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
123      string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
124
125      foreach(_flag IN LISTS _gss_lib_flags)
126        if(_flag MATCHES "^-l")
127          string(REGEX REPLACE "^-l" "" _val "${_flag}")
128          list(APPEND _GSS_LIBRARIES "${_val}")
129        elseif(_flag MATCHES "^-L")
130          string(REGEX REPLACE "^-L" "" _val "${_flag}")
131          list(APPEND _GSS_LIBRARY_DIRS "${_val}")
132        endif()
133      endforeach()
134    endif()
135
136    execute_process(
137      COMMAND ${_gss_configure_script} "--version"
138      OUTPUT_VARIABLE _GSS_VERSION
139      RESULT_VARIABLE _gss_configure_failed
140      OUTPUT_STRIP_TRAILING_WHITESPACE
141    )
142
143    # Older versions may not have the "--version" parameter. In this case we just do not care.
144    if(_gss_configure_failed)
145      set(_GSS_VERSION 0)
146    endif()
147
148    execute_process(
149      COMMAND ${_gss_configure_script} "--vendor"
150      OUTPUT_VARIABLE _gss_vendor
151      RESULT_VARIABLE _gss_configure_failed
152      OUTPUT_STRIP_TRAILING_WHITESPACE
153    )
154
155    # Older versions may not have the "--vendor" parameter. In this case we just do not care.
156    if(_gss_configure_failed)
157      set(GSS_FLAVOUR "Heimdal")  # most probably, should not really matter
158    else()
159      if(_gss_vendor MATCHES "H|heimdal")
160        set(GSS_FLAVOUR "Heimdal")
161      else()
162        set(GSS_FLAVOUR "MIT")
163      endif()
164    endif()
165
166  else()  # Either there is no config script or we are on a platform that does not provide one (Windows?)
167
168    find_path(_GSS_INCLUDE_DIRS NAMES "gssapi/gssapi.h"
169      HINTS
170        ${_gss_root_hints}
171      PATH_SUFFIXES
172        "include"
173        "inc"
174    )
175
176    if(_GSS_INCLUDE_DIRS)  # jay, we have found something
177      cmake_push_check_state()
178      list(APPEND CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
179      check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
180
181      if(_gss_have_mit_headers)
182        set(GSS_FLAVOUR "MIT")
183      else()
184        # Prevent compiling the header - just check if we can include it
185        list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D__ROKEN_H__")
186        check_include_file("roken.h" _gss_have_roken_h)
187
188        check_include_file("heimdal/roken.h" _gss_have_heimdal_roken_h)
189        if(_gss_have_roken_h OR _gss_have_heimdal_roken_h)
190          set(GSS_FLAVOUR "Heimdal")
191        endif()
192      endif()
193      cmake_pop_check_state()
194    else()
195      # I am not convinced if this is the right way but this is what autotools do at the moment
196      find_path(_GSS_INCLUDE_DIRS NAMES "gssapi.h"
197        HINTS
198          ${_gss_root_hints}
199        PATH_SUFFIXES
200          "include"
201          "inc"
202      )
203
204      if(_GSS_INCLUDE_DIRS)
205        set(GSS_FLAVOUR "Heimdal")
206      else()
207        find_path(_GSS_INCLUDE_DIRS NAMES "gss.h"
208          HINTS
209            ${_gss_root_hints}
210          PATH_SUFFIXES
211            "include"
212        )
213
214        if(_GSS_INCLUDE_DIRS)
215          set(GSS_FLAVOUR "GNU")
216          set(GSS_PC_REQUIRES "gss")
217        endif()
218      endif()
219    endif()
220
221    # If we have headers, check if we can link libraries
222    if(GSS_FLAVOUR)
223      set(_gss_libdir_suffixes "")
224      set(_gss_libdir_hints ${_gss_root_hints})
225      get_filename_component(_gss_calculated_potential_root "${_GSS_INCLUDE_DIRS}" DIRECTORY)
226      list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root})
227
228      if(WIN32)
229        if(CMAKE_SIZEOF_VOID_P EQUAL 8)
230          list(APPEND _gss_libdir_suffixes "lib/AMD64")
231          if(GSS_FLAVOUR STREQUAL "GNU")
232            set(_gss_libname "gss")
233          elseif(GSS_FLAVOUR STREQUAL "MIT")
234            set(_gss_libname "gssapi64")
235          else()
236            set(_gss_libname "libgssapi")
237          endif()
238        else()
239          list(APPEND _gss_libdir_suffixes "lib/i386")
240          if(GSS_FLAVOUR STREQUAL "GNU")
241            set(_gss_libname "gss")
242          elseif(GSS_FLAVOUR STREQUAL "MIT")
243            set(_gss_libname "gssapi32")
244          else()
245            set(_gss_libname "libgssapi")
246          endif()
247        endif()
248      else()
249        list(APPEND _gss_libdir_suffixes "lib;lib64")  # those suffixes are not checked for HINTS
250        if(GSS_FLAVOUR STREQUAL "GNU")
251          set(_gss_libname "gss")
252        elseif(GSS_FLAVOUR STREQUAL "MIT")
253          set(_gss_libname "gssapi_krb5")
254        else()
255          set(_gss_libname "gssapi")
256        endif()
257      endif()
258
259      find_library(_GSS_LIBRARIES NAMES ${_gss_libname}
260        HINTS
261          ${_gss_libdir_hints}
262        PATH_SUFFIXES
263          ${_gss_libdir_suffixes}
264      )
265    endif()
266  endif()
267else()
268  # _GSS_MODULE_NAME set since CMake 3.16
269  if(_GSS_MODULE_NAME STREQUAL _gnu_modname OR _GSS_${_gnu_modname}_VERSION)
270    set(GSS_FLAVOUR "GNU")
271    set(GSS_PC_REQUIRES "gss")
272    if(NOT _GSS_VERSION)  # for old CMake versions?
273      set(_GSS_VERSION ${_GSS_${_gnu_modname}_VERSION})
274    endif()
275  elseif(_GSS_MODULE_NAME STREQUAL _mit_modname OR _GSS_${_mit_modname}_VERSION)
276    set(GSS_FLAVOUR "MIT")
277    set(GSS_PC_REQUIRES "mit-krb5-gssapi")
278    if(NOT _GSS_VERSION)  # for old CMake versions?
279      set(_GSS_VERSION ${_GSS_${_mit_modname}_VERSION})
280    endif()
281  else()
282    set(GSS_FLAVOUR "Heimdal")
283    set(GSS_PC_REQUIRES "heimdal-gssapi")
284    if(NOT _GSS_VERSION)  # for old CMake versions?
285      set(_GSS_VERSION ${_GSS_${_heimdal_modname}_VERSION})
286    endif()
287  endif()
288  message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_GSS_INCLUDE_DIRS} (found version \"${_GSS_VERSION}\")")
289endif()
290
291string(REPLACE ";" " " _GSS_CFLAGS "${_GSS_CFLAGS}")
292
293set(GSS_INCLUDE_DIRS ${_GSS_INCLUDE_DIRS})
294set(GSS_LIBRARIES ${_GSS_LIBRARIES})
295set(GSS_LIBRARY_DIRS ${_GSS_LIBRARY_DIRS})
296set(GSS_CFLAGS ${_GSS_CFLAGS})
297set(GSS_VERSION ${_GSS_VERSION})
298
299if(GSS_FLAVOUR)
300  if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal")
301    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
302      set(_heimdal_manifest_file "Heimdal.Application.amd64.manifest")
303    else()
304      set(_heimdal_manifest_file "Heimdal.Application.x86.manifest")
305    endif()
306
307    if(EXISTS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}")
308      file(STRINGS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}" _heimdal_version_str
309        REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$")
310
311      string(REGEX MATCH "[0-9]\\.[^\"]+" GSS_VERSION "${_heimdal_version_str}")
312    endif()
313
314    if(NOT GSS_VERSION)
315      set(GSS_VERSION "Heimdal Unknown")
316    endif()
317  elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT")
318    get_filename_component(_mit_version "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME
319      CACHE)
320    if(WIN32 AND _mit_version)
321      set(GSS_VERSION "${_mit_version}")
322    else()
323      set(GSS_VERSION "MIT Unknown")
324    endif()
325  elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "GNU")
326    if(GSS_INCLUDE_DIRS AND EXISTS "${GSS_INCLUDE_DIRS}/gss.h")
327      set(_version_regex "#[\t ]*define[\t ]+GSS_VERSION[\t ]+\"([^\"]*)\"")
328      file(STRINGS "${GSS_INCLUDE_DIRS}/gss.h" _version_str REGEX "${_version_regex}")
329      string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
330      set(GSS_VERSION "${_version_str}")
331      unset(_version_regex)
332      unset(_version_str)
333    endif()
334  endif()
335endif()
336
337include(FindPackageHandleStandardArgs)
338find_package_handle_standard_args(GSS
339  REQUIRED_VARS
340    GSS_FLAVOUR
341    GSS_LIBRARIES
342  VERSION_VAR
343    GSS_VERSION
344  FAIL_MESSAGE
345    "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
346)
347
348mark_as_advanced(
349  _GSS_CFLAGS
350  _GSS_FOUND
351  _GSS_INCLUDE_DIRS
352  _GSS_LIBRARIES
353  _GSS_LIBRARY_DIRS
354  _GSS_MODULE_NAME
355  _GSS_PREFIX
356  _GSS_VERSION
357)
358