1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
|
#!/usr/bin/env python
import subprocess
import platform
import re
import sys
import os
import shutil
import shlex
# Enables the vendored distutils in setuptools over the stdlib one to avoid
# the deprecation warning. Must be done before importing setuptools,
# setuptools also must be imported before distutils.
# https://github.com/pypa/setuptools/blob/main/docs/deprecated/distutils-legacy.rst
os.environ['SETUPTOOLS_USE_DISTUTILS'] = 'local'
from setuptools import setup # noqa: E402
from setuptools.extension import Extension # noqa: E402
from Cython.Build import cythonize # noqa: E402
def get_output(*args, **kwargs):
res = subprocess.check_output(*args, shell=True, **kwargs)
decoded = res.decode('utf-8')
return decoded.strip()
# get the compile and link args
kc = "krb5-config"
autodetect_kc = True
posix = os.name != 'nt'
# Per https://docs.python.org/3/library/platform.html#platform.architecture
# this is the preferred way of determining "64-bitness".
is64bit = sys.maxsize > 2**32
kc_env = 'GSSAPI_KRB5CONFIG'
if kc_env in os.environ:
kc = os.environ[kc_env]
autodetect_kc = False
print(f"Using {kc} from env")
link_args, compile_args = [
shlex.split(os.environ[e], posix=posix) if e in os.environ else None
for e in ['GSSAPI_LINKER_ARGS', 'GSSAPI_COMPILER_ARGS']
]
osx_has_gss_framework = False
if sys.platform == 'darwin':
mac_ver = [int(v) for v in platform.mac_ver()[0].split('.')]
osx_has_gss_framework = (mac_ver >= [10, 7, 0])
winkrb_path = None
if os.name == 'nt':
# Try to find location of MIT kerberos
# First check program files of the appropriate architecture
_pf_path = os.path.join(os.environ['ProgramFiles'], 'MIT', 'Kerberos')
if os.path.exists(_pf_path):
winkrb_path = _pf_path
else:
# Try to detect kinit in PATH
_kinit_path = shutil.which('kinit')
if _kinit_path is None:
print("Failed find MIT kerberos!")
else:
winkrb_path = os.path.dirname(os.path.dirname(_kinit_path))
# Monkey patch distutils if it throws errors getting msvcr.
# For MinGW it won't need it.
from distutils import cygwinccompiler
try:
cygwinccompiler.get_msvcr()
except ValueError:
cygwinccompiler.get_msvcr = lambda *a, **kw: []
if sys.platform.startswith("freebsd") and autodetect_kc:
# FreeBSD does $PATH backward, for our purposes. That is, the package
# manager's version of the software is in /usr/local, which is in PATH
# *after* the version in /usr. We prefer the package manager's version
# because the Heimdal in base is truly ancient, but this can be overridden
# - either in the "normal" fashion by putting something in PATH in front
# of it, or by removing /usr/local from PATH.
bins = []
for b in os.environ["PATH"].split(":"):
p = f"{b}/krb5-config"
if not os.path.exists(p):
continue
bins.append(p)
if len(bins) > 1 and bins[0] == "/usr/bin/krb5-config" and \
"/usr/local/bin/krb5-config" in bins:
kc = "/usr/local/bin/krb5-config"
print(f"Detected: {kc}")
if link_args is None:
if osx_has_gss_framework:
link_args = ['-framework', 'GSS']
elif winkrb_path:
_libs = os.path.join(
winkrb_path, 'lib', 'amd64' if is64bit else 'i386'
)
link_args = (
['-L%s' % _libs]
+ ['-l%s' % os.path.splitext(lib)[0] for lib in os.listdir(_libs)]
)
elif os.environ.get('MINGW_PREFIX'):
link_args = ['-lgss']
else:
link_args = shlex.split(get_output(f"{kc} --libs gssapi"))
if compile_args is None:
if osx_has_gss_framework:
compile_args = ['-DOSX_HAS_GSS_FRAMEWORK']
elif winkrb_path:
compile_args = [
'-I%s' % os.path.join(winkrb_path, 'include'),
]
if is64bit:
compile_args.append('-DMS_WIN64')
elif os.environ.get('MINGW_PREFIX'):
compile_args = ['-fPIC']
else:
compile_args = shlex.split(get_output(f"{kc} --cflags gssapi"))
# add in the extra workarounds for different include structures
if winkrb_path:
prefix = winkrb_path
else:
try:
prefix = get_output(f"{kc} gssapi --prefix")
except Exception:
print("WARNING: couldn't find krb5-config; assuming prefix of %s"
% str(sys.prefix))
prefix = sys.prefix
gssapi_ext_h = os.path.join(prefix, 'include/gssapi/gssapi_ext.h')
if os.path.exists(gssapi_ext_h):
compile_args.append("-DHAS_GSSAPI_EXT_H")
# Create a define to detect msys in the headers
if sys.platform == 'msys':
compile_args.append('-D__MSYS__')
# ensure that any specific directories are listed before any generic system
# directories inserted by setuptools
# Also separate out specified libraries as MSBuild requires different args
_link_args = link_args
library_dirs, libraries, link_args = [], [], []
for arg in _link_args:
if arg.startswith('-L'):
library_dirs.append(arg[2:])
elif arg.startswith('-l'):
libraries.append(arg[2:])
else:
link_args.append(arg)
ENABLE_SUPPORT_DETECTION = \
(os.environ.get('GSSAPI_SUPPORT_DETECT', 'true').lower() == 'true')
wrap_iov_symbol_name = 'gss_wrap_iov'
if ENABLE_SUPPORT_DETECTION:
import ctypes.util
main_lib = os.environ.get('GSSAPI_MAIN_LIB', None)
main_path = ""
if main_lib is None and osx_has_gss_framework:
main_lib = ctypes.util.find_library('GSS')
if not main_lib:
# https://github.com/pythongssapi/python-gssapi/issues/235
# CPython has a bug on Big Sur where find_library will fail to
# find the library path of shared frameworks. This has been fixed
# in newer versions but we have this fallback in case an older
# version is still in use. This fix is expected to be included in
# 3.8.8 and 3.9.2.
main_lib = '/System/Library/Frameworks/GSS.framework/GSS'
elif os.environ.get('MINGW_PREFIX'):
main_lib = os.environ.get('MINGW_PREFIX')+'/bin/libgss-3.dll'
elif sys.platform == 'msys':
# Plain msys, not running in MINGW_PREFIX. Try to get the lib from one
_main_lib = f'/mingw{64 if is64bit else 32}/bin/libgss-3.dll'
if os.path.exists(_main_lib):
main_lib = _main_lib
os.environ['PATH'] += os.pathsep + os.path.dirname(main_lib)
elif main_lib is None:
for opt in libraries:
if opt.startswith('gssapi'):
if os.name == 'nt':
main_lib = '%s.dll' % opt
if winkrb_path:
main_path = os.path.join(winkrb_path, 'bin')
else:
main_lib = 'lib%s.so' % opt
for opt in link_args:
# To support Heimdal on Debian, read the linker path.
if opt.startswith('-Wl,/'):
main_path = opt[4:] + "/"
if main_path == "":
for d in library_dirs:
if os.path.exists(os.path.join(d, main_lib)):
main_path = d
break
if main_lib is None:
raise Exception("Could not find main GSSAPI shared library. Please "
"try setting GSSAPI_MAIN_LIB yourself or setting "
"GSSAPI_SUPPORT_DETECT to 'false'")
GSSAPI_LIB = ctypes.CDLL(os.path.join(main_path, main_lib))
if hasattr(GSSAPI_LIB, '__ApplePrivate_gss_wrap_iov'):
wrap_iov_symbol_name = '__ApplePrivate_gss_wrap_iov'
def make_extension(name_fmt, module, **kwargs):
"""Helper method to remove the repetition in extension declarations."""
source = name_fmt.replace('.', '/') % module + '.pyx'
if not os.path.exists(source):
raise OSError(source)
return Extension(
name_fmt % module,
extra_link_args=link_args,
extra_compile_args=compile_args,
library_dirs=library_dirs,
libraries=libraries,
sources=[source],
**kwargs
)
# detect support
def main_file(module):
return make_extension('gssapi.raw.%s', module)
ENUM_EXTS = []
def extension_file(module, canary):
if ENABLE_SUPPORT_DETECTION and not hasattr(GSSAPI_LIB, canary):
print('Skipping the %s extension because it '
'is not supported by your GSSAPI implementation...' % module)
return
try:
ENUM_EXTS.append(
make_extension('gssapi.raw._enum_extensions.ext_%s', module,
include_dirs=['gssapi/raw/'])
)
except OSError:
pass
return make_extension('gssapi.raw.ext_%s', module)
def gssapi_modules(lst):
# filter out missing files
res = [mod for mod in lst if mod is not None]
# add in supported mech files
res.extend(
make_extension('gssapi.raw.mech_%s', mech)
for mech in os.environ.get('GSSAPI_MECHS', 'krb5').split(',')
)
# add in any present enum extension files
res.extend(ENUM_EXTS)
return cythonize(res, language_level=2)
long_desc = re.sub(r'\.\. role:: \w+\(code\)\s*\n\s*.+', '',
re.sub(r':(python|bash|code):', '',
re.sub(r'\.\. code-block:: \w+', '::',
open('README.txt').read())))
install_requires = [
'decorator',
]
setup(
name='gssapi',
version='1.10.0',
author='The Python GSSAPI Team',
author_email='jborean93@gmail.com',
packages=['gssapi', 'gssapi.raw', 'gssapi.raw._enum_extensions',
'gssapi.tests'],
package_data={
"gssapi": ["py.typed"],
"gssapi.raw": ["*.pyi"],
},
description='Python GSSAPI Wrapper',
long_description=long_desc,
license='LICENSE.txt',
url="https://github.com/pythongssapi/python-gssapi",
python_requires=">=3.9",
classifiers=[
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: 3.14',
'Intended Audience :: Developers',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Cython',
'Topic :: Security',
'Topic :: Software Development :: Libraries :: Python Modules'
],
ext_modules=gssapi_modules([
main_file('misc'),
main_file('exceptions'),
main_file('creds'),
main_file('names'),
main_file('sec_contexts'),
main_file('types'),
main_file('message'),
main_file('oids'),
main_file('cython_converters'),
main_file('chan_bindings'),
extension_file('s4u', 'gss_acquire_cred_impersonate_name'),
extension_file('cred_store', 'gss_store_cred_into'),
extension_file('rfc4178', 'gss_set_neg_mechs'),
extension_file('rfc5587', 'gss_indicate_mechs_by_attrs'),
extension_file('rfc5588', 'gss_store_cred'),
extension_file('rfc5801', 'gss_inquire_saslname_for_mech'),
extension_file('cred_imp_exp', 'gss_import_cred'),
extension_file('dce', wrap_iov_symbol_name),
extension_file('dce_aead', 'gss_wrap_aead'),
extension_file('iov_mic', 'gss_get_mic_iov'),
extension_file('ggf', 'gss_inquire_sec_context_by_oid'),
extension_file('set_cred_opt', 'gss_set_cred_option'),
# see ext_rfc6680_comp_oid for more information on this split
extension_file('rfc6680', 'gss_display_name_ext'),
extension_file('rfc6680_comp_oid', 'GSS_C_NT_COMPOSITE_EXPORT'),
# see ext_password{,_add}.pyx for more information on this split
extension_file('password', 'gss_acquire_cred_with_password'),
extension_file('password_add', 'gss_add_cred_with_password'),
extension_file('krb5', 'gss_krb5_ccache_name'),
]),
keywords=['gssapi', 'security'],
install_requires=install_requires
)
|