xref: /curl/CMake/FindGSS.cmake (revision f66af623)
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_LDFLAGS`:       Required linker flags.
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 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 LDFLAGS: ${_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        else()
133          list(APPEND _GSS_LDFLAGS "${_flag}")
134        endif()
135      endforeach()
136    endif()
137
138    execute_process(
139      COMMAND ${_gss_configure_script} "--version"
140      OUTPUT_VARIABLE _GSS_VERSION
141      RESULT_VARIABLE _gss_configure_failed
142      OUTPUT_STRIP_TRAILING_WHITESPACE
143    )
144
145    # Older versions may not have the "--version" parameter. In this case we just do not care.
146    if(_gss_configure_failed)
147      set(_GSS_VERSION 0)
148    endif()
149
150    execute_process(
151      COMMAND ${_gss_configure_script} "--vendor"
152      OUTPUT_VARIABLE _gss_vendor
153      RESULT_VARIABLE _gss_configure_failed
154      OUTPUT_STRIP_TRAILING_WHITESPACE
155    )
156
157    # Older versions may not have the "--vendor" parameter. In this case we just do not care.
158    if(_gss_configure_failed)
159      set(GSS_FLAVOUR "Heimdal")  # most probably, should not really matter
160    else()
161      if(_gss_vendor MATCHES ".*H|heimdal.*")
162        set(GSS_FLAVOUR "Heimdal")
163      else()
164        set(GSS_FLAVOUR "MIT")
165      endif()
166    endif()
167
168  else()  # Either there is no config script or we are on a platform that does not provide one (Windows?)
169
170    find_path(_GSS_INCLUDE_DIRS NAMES "gssapi/gssapi.h"
171      HINTS
172        ${_gss_root_hints}
173      PATH_SUFFIXES
174        "include"
175        "inc"
176    )
177
178    if(_GSS_INCLUDE_DIRS)  # jay, we have found something
179      cmake_push_check_state()
180      set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
181      check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
182
183      if(_gss_have_mit_headers)
184        set(GSS_FLAVOUR "MIT")
185      else()
186        # Prevent compiling the header - just check if we can include it
187        list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D__ROKEN_H__")
188        check_include_file("roken.h" _gss_have_roken_h)
189
190        check_include_file("heimdal/roken.h" _gss_have_heimdal_roken_h)
191        if(_gss_have_roken_h OR _gss_have_heimdal_roken_h)
192          set(GSS_FLAVOUR "Heimdal")
193        endif()
194      endif()
195      cmake_pop_check_state()
196    else()
197      # I am not convinced if this is the right way but this is what autotools do at the moment
198      find_path(_GSS_INCLUDE_DIRS NAMES "gssapi.h"
199        HINTS
200          ${_gss_root_hints}
201        PATH_SUFFIXES
202          "include"
203          "inc"
204      )
205
206      if(_GSS_INCLUDE_DIRS)
207        set(GSS_FLAVOUR "Heimdal")
208      else()
209        find_path(_GSS_INCLUDE_DIRS NAMES "gss.h"
210          HINTS
211            ${_gss_root_hints}
212          PATH_SUFFIXES
213            "include"
214        )
215
216        if(_GSS_INCLUDE_DIRS)
217          set(GSS_FLAVOUR "GNU")
218        endif()
219      endif()
220    endif()
221
222    # If we have headers, check if we can link libraries
223    if(GSS_FLAVOUR)
224      set(_gss_libdir_suffixes "")
225      set(_gss_libdir_hints ${_gss_root_hints})
226      get_filename_component(_gss_calculated_potential_root "${_GSS_INCLUDE_DIRS}" DIRECTORY)
227      list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root})
228
229      if(WIN32)
230        if(CMAKE_SIZEOF_VOID_P EQUAL 8)
231          list(APPEND _gss_libdir_suffixes "lib/AMD64")
232          if(GSS_FLAVOUR STREQUAL "GNU")
233            set(_gss_libname "gss")
234          elseif(GSS_FLAVOUR STREQUAL "MIT")
235            set(_gss_libname "gssapi64")
236          else()
237            set(_gss_libname "libgssapi")
238          endif()
239        else()
240          list(APPEND _gss_libdir_suffixes "lib/i386")
241          if(GSS_FLAVOUR STREQUAL "GNU")
242            set(_gss_libname "gss")
243          elseif(GSS_FLAVOUR STREQUAL "MIT")
244            set(_gss_libname "gssapi32")
245          else()
246            set(_gss_libname "libgssapi")
247          endif()
248        endif()
249      else()
250        list(APPEND _gss_libdir_suffixes "lib;lib64")  # those suffixes are not checked for HINTS
251        if(GSS_FLAVOUR STREQUAL "GNU")
252          set(_gss_libname "gss")
253        elseif(GSS_FLAVOUR STREQUAL "MIT")
254          set(_gss_libname "gssapi_krb5")
255        else()
256          set(_gss_libname "gssapi")
257        endif()
258      endif()
259
260      find_library(_GSS_LIBRARIES NAMES ${_gss_libname}
261        HINTS
262          ${_gss_libdir_hints}
263        PATH_SUFFIXES
264          ${_gss_libdir_suffixes}
265      )
266    endif()
267  endif()
268else()
269  # _GSS_MODULE_NAME set since CMake 3.16
270  if(_GSS_MODULE_NAME STREQUAL _gnu_modname OR _GSS_${_gnu_modname}_VERSION)
271    set(GSS_FLAVOUR "GNU")
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    if(NOT _GSS_VERSION)  # for old CMake versions?
278      set(_GSS_VERSION ${_GSS_${_mit_modname}_VERSION})
279    endif()
280  else()
281    set(GSS_FLAVOUR "Heimdal")
282    if(NOT _GSS_VERSION)  # for old CMake versions?
283      set(_GSS_VERSION ${_GSS_${_heimdal_modname}_VERSION})
284    endif()
285  endif()
286  message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_GSS_INCLUDE_DIRS} (found version \"${_GSS_VERSION}\")")
287endif()
288
289set(GSS_INCLUDE_DIRS ${_GSS_INCLUDE_DIRS})
290set(GSS_LIBRARIES ${_GSS_LIBRARIES})
291set(GSS_LIBRARY_DIRS ${_GSS_LIBRARY_DIRS})
292set(GSS_LDFLAGS ${_GSS_LDFLAGS})
293set(GSS_CFLAGS ${_GSS_CFLAGS})
294set(GSS_VERSION ${_GSS_VERSION})
295
296if(GSS_FLAVOUR)
297  if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal")
298    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
299      set(_heimdal_manifest_file "Heimdal.Application.amd64.manifest")
300    else()
301      set(_heimdal_manifest_file "Heimdal.Application.x86.manifest")
302    endif()
303
304    if(EXISTS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}")
305      file(STRINGS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}" _heimdal_version_str
306        REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$")
307
308      string(REGEX MATCH "[0-9]\\.[^\"]+" GSS_VERSION "${_heimdal_version_str}")
309    endif()
310
311    if(NOT GSS_VERSION)
312      set(GSS_VERSION "Heimdal Unknown")
313    endif()
314  elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT")
315    get_filename_component(_mit_version "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME
316      CACHE)
317    if(WIN32 AND _mit_version)
318      set(GSS_VERSION "${_mit_version}")
319    else()
320      set(GSS_VERSION "MIT Unknown")
321    endif()
322  elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "GNU")
323    if(GSS_INCLUDE_DIRS AND EXISTS "${GSS_INCLUDE_DIRS}/gss.h")
324      set(_version_regex "#[\t ]*define[\t ]+GSS_VERSION[\t ]+\"([^\"]*)\"")
325      file(STRINGS "${GSS_INCLUDE_DIRS}/gss.h" _version_str REGEX "${_version_regex}")
326      string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
327      set(GSS_VERSION "${_version_str}")
328      unset(_version_regex)
329      unset(_version_str)
330    endif()
331  endif()
332endif()
333
334include(FindPackageHandleStandardArgs)
335find_package_handle_standard_args(GSS
336  REQUIRED_VARS
337    GSS_FLAVOUR
338    GSS_LIBRARIES
339  VERSION_VAR
340    GSS_VERSION
341  FAIL_MESSAGE
342    "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
343)
344
345mark_as_advanced(
346  _GSS_CFLAGS
347  _GSS_FOUND
348  _GSS_INCLUDE_DIRS
349  _GSS_LDFLAGS
350  _GSS_LIBRARIES
351  _GSS_LIBRARY_DIRS
352  _GSS_MODULE_NAME
353  _GSS_PREFIX
354  _GSS_VERSION
355)
356