Browse Source

HUE-9225 [core] Upgrade certain third party python libraries that has identified vulnerabilities (#1102)

Hue Aquascan CVEs

- Removing kerberos-1.1.1
- Upgrading kerberos-1.3.0

(cherry picked from commit aa94a9520436bf0164276bfe8fc0a18416658478)
Prakash Ranade 5 years ago
parent
commit
812cd39fa4

+ 0 - 202
desktop/core/ext-py/kerberos-1.1.1/LICENSE

@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.

+ 0 - 20
desktop/core/ext-py/kerberos-1.1.1/PKG-INFO

@@ -1,20 +0,0 @@
-Metadata-Version: 1.0
-Name: kerberos
-Version: 1.1.1
-Summary: Kerberos high-level interface
-Home-page: UNKNOWN
-Author: UNKNOWN
-Author-email: UNKNOWN
-License: UNKNOWN
-Description: 
-        This Python package is a high-level wrapper for Kerberos (GSSAPI) operations.
-        The goal is to avoid having to build a module that wraps the entire Kerberos.framework,
-        and instead offer a limited set of functions that do what is needed for client/server
-        Kerberos authentication based on <http://www.ietf.org/rfc/rfc4559.txt>.
-        
-        
-Platform: UNKNOWN
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Programming Language :: Python :: 2
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: System :: Systems Administration :: Authentication/Directory

+ 0 - 69
desktop/core/ext-py/kerberos-1.1.1/README.txt

@@ -1,69 +0,0 @@
-=========================================================
-PyKerberos Package
-
-Copyright (c) 2006-2008 Apple Inc. All rights reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-=========================================================
-
-This Python package is a high-level wrapper for Kerberos (GSSAPI) operations.
-The goal is to avoid having to build a module that wraps the entire Kerberos.framework,
-and instead offer a limited set of functions that do what is needed for client/server
-Kerberos authentication based on <http://www.ietf.org/rfc/rfc4559.txt>.
-
-Much of the C-code here is adapted from Apache's mod_auth_kerb-5.0rc7.
-
-========
-CONTENTS
-========
-
-    src/               : directory in which C source code resides.
-    setup.py           : Python distutils extension build script.
-    config/            : directory of useful Kerberos config files.
-      edu.mit.Kerberos : example Kerberos .ini file.
-    README.txt         : this file!
-    kerberos.py        : Python api documentation/stub implementation.
-
-=====
-BUILD
-=====
-
-In this directory, run:
-
-    python setup.py build
-
-=======
-TESTING
-=======
-
-You must have a valid Kerberos setup on the test machine and you should ensure that you have valid
-Kerberos tickets for any client authentication being done (run 'klist' on the command line).
-Additionally, for the server: it must have been configured as a valid Kerberos service with the Kerbersos server
-for its realm - this usually requires running kadmin on the server machine to add the principal and generate a keytab
-entry for it (run 'sudo klist -k' to see the currently available keytab entries).
-
-Make sure that PYTHONPATH includes the appropriate build/lib.xxxx directory.
-Then run test.py with suitable command line arguments:
-
-    python test.py -u userid -p password -s service
-    
-    -u : user id for basic authenticate
-    -p : password for basic authenticate
-    -s : service principal for GSSAPI authentication (defaults to 'http@host.example.com')
-
-===========
-Python APIs
-===========
-
-See kerberos.py.

+ 0 - 14
desktop/core/ext-py/kerberos-1.1.1/config/edu.mit.Kerberos

@@ -1,14 +0,0 @@
-[libdefaults]
-    default_realm = EXAMPLE.COM
-    dns_fallback = NO
-    default_tkt_enctypes = des-cbc-crc
-    default_tgs_enctypes = des-cbc-crc
-
-[realms]
-	EXAMPLE.COM = {
-		kdc = kdc.example.com
-	}
-
-[domain_realm]
-	.example.com = EXAMPLE.COM
-	example.com = EXAMPLE.COM

+ 0 - 225
desktop/core/ext-py/kerberos-1.1.1/pysrc/kerberos.py

@@ -1,225 +0,0 @@
-##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-"""
-PyKerberos Function Description.
-"""
-
-class KrbError(Exception):
-    pass
-
-class BasicAuthError(KrbError):
-    pass
-
-class GSSError(KrbError):
-    pass
-
-def checkPassword(user, pswd, service, default_realm):
-    """
-    This function provides a simple way to verify that a user name and password match
-    those normally used for Kerberos authentication. It does this by checking that the
-    supplied user name and password can be used to get a ticket for the supplied service.
-    If the user name does not contain a realm, then the default realm supplied is used.
-    
-    NB For this to work properly the Kerberos must be configured properly on this machine.
-    That will likely mean ensuring that the edu.mit.Kerberos preference file has the correct
-    realms and KDCs listed.
-    
-    @param user:          a string containing the Kerberos user name. A realm may be
-        included by appending an '@' followed by the realm string to the actual user id.
-        If no realm is supplied, then the realm set in the default_realm argument will
-        be used.
-    @param pswd:          a string containing the password for the user.
-    @param service:       a string containging the Kerberos service to check access for.
-        This will be of the form 'sss/xx.yy.zz', where 'sss' is the service identifier
-        (e.g., 'http', 'krbtgt'), and 'xx.yy.zz' is the hostname of the server.
-    @param default_realm: a string containing the default realm to use if one is not
-        supplied in the user argument. Note that Kerberos realms are normally all
-        uppercase (e.g., 'EXAMPLE.COM').
-    @return:              True if authentication succeeds, False otherwise.
-    """
-
-def changePassword(user, oldpswd, newpswd):
-    """
-    This function allows to change the user password on the KDC.
-
-    @param user:          a string containing the Kerberos user name. A realm may be
-        included by appending an '@' followed by the realm string to the actual user id.
-        If no realm is supplied, then the realm set in the default_realm argument will
-        be used.
-    @param oldpswd:       a string containing the old (current) password for the user.
-    @param newpswd:       a string containging the new password for the user.
-    @return:              True if password changing succeeds, False otherwise.
-    """
-
-def getServerPrincipalDetails(service, hostname):
-    """
-    This function returns the service principal for the server given a service type
-    and hostname. Details are looked up via the /etc/keytab file.
-    
-    @param service:       a string containing the Kerberos service type for the server.
-    @param hostname:      a string containing the hostname of the server.
-    @return:              a string containing the service principal.
-    """
-
-"""
-GSSAPI Function Result Codes:
-    
-    -1 : Error
-    0  : GSSAPI step continuation (only returned by 'Step' function)
-    1  : GSSAPI step complete, or function return OK
-
-"""
-
-# Some useful result codes
-AUTH_GSS_CONTINUE     = 0 
-AUTH_GSS_COMPLETE     = 1 
-     
-# Some useful gss flags 
-GSS_C_DELEG_FLAG      = 1 
-GSS_C_MUTUAL_FLAG     = 2 
-GSS_C_REPLAY_FLAG     = 4 
-GSS_C_SEQUENCE_FLAG   = 8 
-GSS_C_CONF_FLAG       = 16 
-GSS_C_INTEG_FLAG      = 32 
-GSS_C_ANON_FLAG       = 64 
-GSS_C_PROT_READY_FLAG = 128 
-GSS_C_TRANS_FLAG      = 256 
-     
-def authGSSClientInit(service, gssflags=GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG):
-    """
-    Initializes a context for GSSAPI client-side authentication with the given service principal.
-    authGSSClientClean must be called after this function returns an OK result to dispose of
-    the context once all GSSAPI operations are complete.
-
-    @param service: a string containing the service principal in the form 'type@fqdn'
-        (e.g. 'imap@mail.apple.com').
-    @param gssflags: optional integer used to set GSS flags.
-        (e.g.  GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG will allow 
-        for forwarding credentials to the remote host)
-    @return: a tuple of (result, context) where result is the result code (see above) and
-        context is an opaque value that will need to be passed to subsequent functions.
-    """
-
-def authGSSClientClean(context):
-    """
-    Destroys the context for GSSAPI client-side authentication. After this call the context
-    object is invalid and should not be used again.
-
-    @param context: the context object returned from authGSSClientInit.
-    @return: a result code (see above).
-    """
-
-def authGSSClientStep(context, challenge):
-    """
-    Processes a single GSSAPI client-side step using the supplied server data.
-
-    @param context: the context object returned from authGSSClientInit.
-    @param challenge: a string containing the base64-encoded server data (which may be empty
-        for the first step).
-    @return: a result code (see above).
-    """
-
-def authGSSClientResponse(context):
-    """
-    Get the client response from the last successful GSSAPI client-side step.
-
-    @param context: the context object returned from authGSSClientInit.
-    @return: a string containing the base64-encoded client data to be sent to the server.
-    """
-
-def authGSSClientUserName(context):
-    """
-    Get the user name of the principal authenticated via the now complete GSSAPI client-side operations.
-    This method must only be called after authGSSClientStep returns a complete response code.
-
-    @param context:   the context object returned from authGSSClientInit.
-    @return: a string containing the user name.
-    """
-
-def authGSSClientUnwrap(context, challenge): 
-    """ 
-    Perform the client side GSSAPI unwrap step 
-    
-    @param challenge: a string containing the base64-encoded server data. 
-    @return: a result code (see above) 
-    """ 
-
-def authGSSClientWrap(context, data, user=None): 
-    """ 
-    Perform the client side GSSAPI wrap step.  
-    
-    @param data:the result of the authGSSClientResponse after the authGSSClientUnwrap 
-    @param user: the user to authorize 
-    @return: a result code (see above) 
-    """ 
-
-def authGSSServerInit(service):
-    """
-    Initializes a context for GSSAPI server-side authentication with the given service principal.
-    authGSSServerClean must be called after this function returns an OK result to dispose of
-    the context once all GSSAPI operations are complete.
-
-    @param service: a string containing the service principal in the form 'type@fqdn'
-        (e.g. 'imap@mail.apple.com').
-    @return: a tuple of (result, context) where result is the result code (see above) and
-        context is an opaque value that will need to be passed to subsequent functions.
-    """
-
-def authGSSServerClean(context):
-    """
-    Destroys the context for GSSAPI server-side authentication. After this call the context
-    object is invalid and should not be used again.
-
-    @param context: the context object returned from authGSSServerInit.
-    @return: a result code (see above).
-    """
-
-def authGSSServerStep(context, challenge):
-    """
-    Processes a single GSSAPI server-side step using the supplied client data.
-
-    @param context: the context object returned from authGSSServerInit.
-    @param challenge: a string containing the base64-encoded client data.
-    @return: a result code (see above).
-    """
-
-def authGSSServerResponse(context):
-    """
-    Get the server response from the last successful GSSAPI server-side step.
-
-    @param context: the context object returned from authGSSServerInit.
-    @return: a string containing the base64-encoded server data to be sent to the client.
-    """
-
-def authGSSServerUserName(context):
-    """
-    Get the user name of the principal trying to authenticate to the server.
-    This method must only be called after authGSSServerStep returns a complete or continue response code.
-
-    @param context: the context object returned from authGSSServerInit.
-    @return: a string containing the user name.
-    """
-
-def authGSSServerTargetName(context):
-    """
-    Get the target name if the server did not supply its own credentials.
-    This method must only be called after authGSSServerStep returns a complete or continue response code.
-
-    @param context: the context object returned from authGSSServerInit.
-    @return: a string containing the target name.
-    """
-

+ 0 - 54
desktop/core/ext-py/kerberos-1.1.1/setup.py

@@ -1,54 +0,0 @@
-##
-# Copyright (c) 2006-2008 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-from distutils.core import setup, Extension
-import sys
-import commands
-
-long_description = """
-This Python package is a high-level wrapper for Kerberos (GSSAPI) operations.
-The goal is to avoid having to build a module that wraps the entire Kerberos.framework,
-and instead offer a limited set of functions that do what is needed for client/server
-Kerberos authentication based on <http://www.ietf.org/rfc/rfc4559.txt>.
-
-"""
-
-setup (
-    name = "kerberos",
-    version = "1.1.1",
-    description = "Kerberos high-level interface",
-    long_description=long_description,
-    classifiers = [
-        "License :: OSI Approved :: Apache Software License",
-        "Programming Language :: Python :: 2",
-        "Topic :: Software Development :: Libraries :: Python Modules",
-        "Topic :: System :: Systems Administration :: Authentication/Directory"
-        ],
-    ext_modules = [
-        Extension(
-            "kerberos",
-            extra_link_args = commands.getoutput("krb5-config --libs gssapi").split(),
-            extra_compile_args = commands.getoutput("krb5-config --cflags gssapi").split(),
-            sources = [
-                "src/kerberos.c",
-                "src/kerberosbasic.c",
-                "src/kerberosgss.c",
-                "src/kerberospw.c",
-                "src/base64.c"
-            ],
-        ),
-    ],
-)

+ 0 - 465
desktop/core/ext-py/kerberos-1.1.1/src/kerberos.c

@@ -1,465 +0,0 @@
-/**
- * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
-
-#include <Python.h>
-
-#include "kerberosbasic.h"
-#include "kerberospw.h"
-#include "kerberosgss.h"
-
-PyObject *KrbException_class;
-PyObject *BasicAuthException_class;
-PyObject *PwdChangeException_class;
-PyObject *GssException_class;
-
-static PyObject *checkPassword(PyObject *self, PyObject *args)
-{
-    const char *user;
-    const char *pswd;
-    const char *service;
-    const char *default_realm;
-    int result = 0;
-
-    if (!PyArg_ParseTuple(args, "ssss", &user, &pswd, &service, &default_realm))
-        return NULL;
-
-    result = authenticate_user_krb5pwd(user, pswd, service, default_realm);
-
-    if (result)
-        return Py_INCREF(Py_True), Py_True;
-    else
-        return NULL;
-}
-
-static PyObject *changePassword(PyObject *self, PyObject *args)
-{
-    const char *newpswd, *oldpswd;
-    const char *user;
-    int result = 0;
-
-    if (!PyArg_ParseTuple(args, "sss", &user, &oldpswd, &newpswd))
-        return NULL;
-
-    result = change_user_krb5pwd(user, oldpswd, newpswd);
-
-    if (result)
-	return Py_INCREF(Py_True), Py_True;
-    else
-	return NULL;
-}
-
-static PyObject *getServerPrincipalDetails(PyObject *self, PyObject *args)
-{
-    const char *service;
-    const char *hostname;
-    char* result;
-
-    if (!PyArg_ParseTuple(args, "ss", &service, &hostname))
-        return NULL;
-
-    result = server_principal_details(service, hostname);
-
-    if (result != NULL)
-    {
-        PyObject* pyresult = Py_BuildValue("s", result);
-        free(result);
-        return pyresult;
-    }
-    else
-        return NULL;
-}
-
-static PyObject* authGSSClientInit(PyObject* self, PyObject* args, PyObject* keywds)
-{
-    const char *service;
-    gss_client_state *state;
-    PyObject *pystate;
-    static char *kwlist[] = {"service", "gssflags", NULL};
-    long int gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
-    int result = 0;
-
-    if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|l", kwlist, &service, &gss_flags))
-        return NULL;
-
-    state = (gss_client_state *) malloc(sizeof(gss_client_state));
-    pystate = PyCObject_FromVoidPtr(state, NULL);
-
-    result = authenticate_gss_client_init(service, gss_flags, state);
-    if (result == AUTH_GSS_ERROR)
-        return NULL;
-
-    return Py_BuildValue("(iO)", result, pystate);
-}
-
-static PyObject *authGSSClientClean(PyObject *self, PyObject *args)
-{
-    gss_client_state *state;
-    PyObject *pystate;
-    int result = 0;
-
-    if (!PyArg_ParseTuple(args, "O", &pystate))
-        return NULL;
-
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-
-    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
-    if (state != NULL)
-    {
-        result = authenticate_gss_client_clean(state);
-
-        free(state);
-        PyCObject_SetVoidPtr(pystate, NULL);
-    }
-
-    return Py_BuildValue("i", result);
-}
-
-static PyObject *authGSSClientStep(PyObject *self, PyObject *args)
-{
-    gss_client_state *state;
-    PyObject *pystate;
-    char *challenge;
-    int result = 0;
-
-    if (!PyArg_ParseTuple(args, "Os", &pystate, &challenge))
-        return NULL;
-
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-
-    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
-    if (state == NULL)
-        return NULL;
-
-    result = authenticate_gss_client_step(state, challenge);
-    if (result == AUTH_GSS_ERROR)
-        return NULL;
-
-    return Py_BuildValue("i", result);
-}
-
-static PyObject *authGSSClientResponse(PyObject *self, PyObject *args)
-{
-    gss_client_state *state;
-    PyObject *pystate;
-
-    if (!PyArg_ParseTuple(args, "O", &pystate))
-        return NULL;
-
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-
-    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
-    if (state == NULL)
-        return NULL;
-
-    return Py_BuildValue("s", state->response);
-}
-
-static PyObject *authGSSClientUserName(PyObject *self, PyObject *args)
-{
-    gss_client_state *state;
-    PyObject *pystate;
-
-    if (!PyArg_ParseTuple(args, "O", &pystate))
-        return NULL;
-
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-
-    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
-    if (state == NULL)
-        return NULL;
-
-    return Py_BuildValue("s", state->username);
-}
-
-static PyObject *authGSSClientUnwrap(PyObject *self, PyObject *args)
-{
-	gss_client_state *state;
-	PyObject *pystate;
-	char *challenge;
-	int result = 0;
-
-	if (!PyArg_ParseTuple(args, "Os", &pystate, &challenge))
-		return NULL;
-
-	if (!PyCObject_Check(pystate)) {
-		PyErr_SetString(PyExc_TypeError, "Expected a context object");
-		return NULL;
-	}
-
-	state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
-	if (state == NULL)
-		return NULL;
-
-	result = authenticate_gss_client_unwrap(state, challenge);
-	if (result == AUTH_GSS_ERROR)
-		return NULL;
-
-	return Py_BuildValue("i", result);
-}
-
-static PyObject *authGSSClientWrap(PyObject *self, PyObject *args)
-{
-	gss_client_state *state;
-	PyObject *pystate;
-	char *challenge, *user = NULL;
-	int result = 0;
-
-	if (!PyArg_ParseTuple(args, "Os|z", &pystate, &challenge, &user))
-		return NULL;
-
-	if (!PyCObject_Check(pystate)) {
-		PyErr_SetString(PyExc_TypeError, "Expected a context object");
-		return NULL;
-	}
-
-	state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
-	if (state == NULL)
-		return NULL;
-
-	result = authenticate_gss_client_wrap(state, challenge, user);
-	if (result == AUTH_GSS_ERROR)
-		return NULL;
-
-	return Py_BuildValue("i", result);
-}
-
-static PyObject *authGSSServerInit(PyObject *self, PyObject *args)
-{
-    const char *service;
-    gss_server_state *state;
-    PyObject *pystate;
-    int result = 0;
-
-    if (!PyArg_ParseTuple(args, "s", &service))
-        return NULL;
-
-    state = (gss_server_state *) malloc(sizeof(gss_server_state));
-    pystate = PyCObject_FromVoidPtr(state, NULL);
-
-    result = authenticate_gss_server_init(service, state);
-    if (result == AUTH_GSS_ERROR)
-        return NULL;
-
-    return Py_BuildValue("(iO)", result, pystate);
-}
-
-static PyObject *authGSSServerClean(PyObject *self, PyObject *args)
-{
-    gss_server_state *state;
-    PyObject *pystate;
-    int result = 0;
-
-    if (!PyArg_ParseTuple(args, "O", &pystate))
-        return NULL;
-
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-
-    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
-    if (state != NULL)
-    {
-        result = authenticate_gss_server_clean(state);
-
-        free(state);
-        PyCObject_SetVoidPtr(pystate, NULL);
-    }
-
-    return Py_BuildValue("i", result);
-}
-
-static PyObject *authGSSServerStep(PyObject *self, PyObject *args)
-{
-    gss_server_state *state;
-    PyObject *pystate;
-    char *challenge;
-    int result = 0;
-
-    if (!PyArg_ParseTuple(args, "Os", &pystate, &challenge))
-        return NULL;
-
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-
-    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
-    if (state == NULL)
-        return NULL;
-
-    result = authenticate_gss_server_step(state, challenge);
-    if (result == AUTH_GSS_ERROR)
-        return NULL;
-
-    return Py_BuildValue("i", result);
-}
-
-static PyObject *authGSSServerResponse(PyObject *self, PyObject *args)
-{
-    gss_server_state *state;
-    PyObject *pystate;
-
-    if (!PyArg_ParseTuple(args, "O", &pystate))
-        return NULL;
-
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-
-    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
-    if (state == NULL)
-        return NULL;
-
-    return Py_BuildValue("s", state->response);
-}
-
-static PyObject *authGSSServerUserName(PyObject *self, PyObject *args)
-{
-    gss_server_state *state;
-    PyObject *pystate;
-    
-    if (!PyArg_ParseTuple(args, "O", &pystate))
-        return NULL;
-    
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-    
-    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
-    if (state == NULL)
-        return NULL;
-    
-    return Py_BuildValue("s", state->username);
-}
-
-static PyObject *authGSSServerTargetName(PyObject *self, PyObject *args)
-{
-    gss_server_state *state;
-    PyObject *pystate;
-    
-    if (!PyArg_ParseTuple(args, "O", &pystate))
-        return NULL;
-    
-    if (!PyCObject_Check(pystate)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a context object");
-        return NULL;
-    }
-    
-    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
-    if (state == NULL)
-        return NULL;
-    
-    return Py_BuildValue("s", state->targetname);
-}
-
-static PyMethodDef KerberosMethods[] = {
-    {"checkPassword",  checkPassword, METH_VARARGS,
-     "Check the supplied user/password against Kerberos KDC."},
-    {"changePassword",  changePassword, METH_VARARGS,
-     "Change the user password."},
-    {"getServerPrincipalDetails",  getServerPrincipalDetails, METH_VARARGS,
-     "Return the service principal for a given service and hostname."},
-    {"authGSSClientInit",  (PyCFunction)authGSSClientInit, METH_VARARGS | METH_KEYWORDS,
-     "Initialize client-side GSSAPI operations."},
-    {"authGSSClientClean",  authGSSClientClean, METH_VARARGS,
-     "Terminate client-side GSSAPI operations."},
-    {"authGSSClientStep",  authGSSClientStep, METH_VARARGS,
-     "Do a client-side GSSAPI step."},
-    {"authGSSClientResponse",  authGSSClientResponse, METH_VARARGS,
-     "Get the response from the last client-side GSSAPI step."},
-    {"authGSSClientUserName",  authGSSClientUserName, METH_VARARGS,
-     "Get the user name from the last client-side GSSAPI step."},
-    {"authGSSServerInit",  authGSSServerInit, METH_VARARGS,
-     "Initialize server-side GSSAPI operations."},
-    {"authGSSClientWrap",  authGSSClientWrap, METH_VARARGS,
-     "Do a GSSAPI wrap."},
-    {"authGSSClientUnwrap",  authGSSClientUnwrap, METH_VARARGS,
-     "Do a GSSAPI unwrap."},
-    {"authGSSServerClean",  authGSSServerClean, METH_VARARGS,
-     "Terminate server-side GSSAPI operations."},
-    {"authGSSServerStep",  authGSSServerStep, METH_VARARGS,
-     "Do a server-side GSSAPI step."},
-    {"authGSSServerResponse",  authGSSServerResponse, METH_VARARGS,
-     "Get the response from the last server-side GSSAPI step."},
-    {"authGSSServerUserName",  authGSSServerUserName, METH_VARARGS,
-        "Get the user name from the last server-side GSSAPI step."},
-    {"authGSSServerTargetName",  authGSSServerTargetName, METH_VARARGS,
-        "Get the target name from the last server-side GSSAPI step."},
-    {NULL, NULL, 0, NULL}        /* Sentinel */
-};
-
-PyMODINIT_FUNC initkerberos(void)
-{
-    PyObject *m,*d;
-
-    m = Py_InitModule("kerberos", KerberosMethods);
-
-    d = PyModule_GetDict(m);
-
-    /* create the base exception class */
-    if (!(KrbException_class = PyErr_NewException("kerberos.KrbError", NULL, NULL)))
-        goto error;
-    PyDict_SetItemString(d, "KrbError", KrbException_class);
-    Py_INCREF(KrbException_class);
-
-    /* ...and the derived exceptions */
-    if (!(BasicAuthException_class = PyErr_NewException("kerberos.BasicAuthError", KrbException_class, NULL)))
-        goto error;
-    Py_INCREF(BasicAuthException_class);
-    PyDict_SetItemString(d, "BasicAuthError", BasicAuthException_class);
-
-    if (!(PwdChangeException_class = PyErr_NewException("kerberos.PwdChangeError", KrbException_class, NULL)))
-        goto error;
-    Py_INCREF(PwdChangeException_class);
-    PyDict_SetItemString(d, "PwdChangeError", PwdChangeException_class);
-
-    if (!(GssException_class = PyErr_NewException("kerberos.GSSError", KrbException_class, NULL)))
-        goto error;
-    Py_INCREF(GssException_class);
-    PyDict_SetItemString(d, "GSSError", GssException_class);
-
-    PyDict_SetItemString(d, "AUTH_GSS_COMPLETE", PyInt_FromLong(AUTH_GSS_COMPLETE));
-    PyDict_SetItemString(d, "AUTH_GSS_CONTINUE", PyInt_FromLong(AUTH_GSS_CONTINUE));
-
-    PyDict_SetItemString(d, "GSS_C_DELEG_FLAG", PyInt_FromLong(GSS_C_DELEG_FLAG));
-    PyDict_SetItemString(d, "GSS_C_MUTUAL_FLAG", PyInt_FromLong(GSS_C_MUTUAL_FLAG));
-    PyDict_SetItemString(d, "GSS_C_REPLAY_FLAG", PyInt_FromLong(GSS_C_REPLAY_FLAG));
-    PyDict_SetItemString(d, "GSS_C_SEQUENCE_FLAG", PyInt_FromLong(GSS_C_SEQUENCE_FLAG));
-    PyDict_SetItemString(d, "GSS_C_CONF_FLAG", PyInt_FromLong(GSS_C_CONF_FLAG));
-    PyDict_SetItemString(d, "GSS_C_INTEG_FLAG", PyInt_FromLong(GSS_C_INTEG_FLAG));
-    PyDict_SetItemString(d, "GSS_C_ANON_FLAG", PyInt_FromLong(GSS_C_ANON_FLAG));
-    PyDict_SetItemString(d, "GSS_C_PROT_READY_FLAG", PyInt_FromLong(GSS_C_PROT_READY_FLAG));
-    PyDict_SetItemString(d, "GSS_C_TRANS_FLAG", PyInt_FromLong(GSS_C_TRANS_FLAG));
-
-error:
-    if (PyErr_Occurred())
-        PyErr_SetString(PyExc_ImportError, "kerberos: init failed");
-}

+ 0 - 609
desktop/core/ext-py/kerberos-1.1.1/src/kerberosgss.c

@@ -1,609 +0,0 @@
-/**
- * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
-
-#include <Python.h>
-#include "kerberosgss.h"
-
-#include "base64.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <arpa/inet.h>
-
-static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min);
-
-extern PyObject *GssException_class;
-extern PyObject *KrbException_class;
-
-char* server_principal_details(const char* service, const char* hostname)
-{
-    char match[1024];
-    int match_len = 0;
-    char* result = NULL;
-    
-    int code;
-    krb5_context kcontext;
-    krb5_keytab kt = NULL;
-    krb5_kt_cursor cursor = NULL;
-    krb5_keytab_entry entry;
-    char* pname = NULL;
-    
-    // Generate the principal prefix we want to match
-    snprintf(match, 1024, "%s/%s@", service, hostname);
-    match_len = strlen(match);
-    
-    code = krb5_init_context(&kcontext);
-    if (code)
-    {
-        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
-                                                          "Cannot initialize Kerberos5 context", code));
-        return NULL;
-    }
-    
-    if ((code = krb5_kt_default(kcontext, &kt)))
-    {
-        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
-                                                          "Cannot get default keytab", code));
-        goto end;
-    }
-    
-    if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor)))
-    {
-        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
-                                                          "Cannot get sequence cursor from keytab", code));
-        goto end;
-    }
-    
-    while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0)
-    {
-        if ((code = krb5_unparse_name(kcontext, entry.principal, &pname)))
-        {
-            PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
-                                                              "Cannot parse principal name from keytab", code));
-            goto end;
-        }
-        
-        if (strncmp(pname, match, match_len) == 0)
-        {
-            result = malloc(strlen(pname) + 1);
-            strcpy(result, pname);
-            krb5_free_unparsed_name(kcontext, pname);
-            krb5_free_keytab_entry_contents(kcontext, &entry);
-            break;
-        }
-        
-        krb5_free_unparsed_name(kcontext, pname);
-        krb5_free_keytab_entry_contents(kcontext, &entry);
-    }
-    
-    if (result == NULL)
-    {
-        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
-                                                          "Principal not found in keytab", -1));
-    }
-    
-end:
-    if (cursor)
-        krb5_kt_end_seq_get(kcontext, kt, &cursor);
-    if (kt)
-        krb5_kt_close(kcontext, kt);
-    krb5_free_context(kcontext);
-    
-    return result;
-}
-
-int authenticate_gss_client_init(const char* service, long int gss_flags, gss_client_state* state)
-{
-    OM_uint32 maj_stat;
-    OM_uint32 min_stat;
-    gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
-    int ret = AUTH_GSS_COMPLETE;
-    
-    state->server_name = GSS_C_NO_NAME;
-    state->context = GSS_C_NO_CONTEXT;
-    state->gss_flags = gss_flags;
-    state->username = NULL;
-    state->response = NULL;
-    
-    // Import server name first
-    name_token.length = strlen(service);
-    name_token.value = (char *)service;
-    
-    maj_stat = gss_import_name(&min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name);
-    
-    if (GSS_ERROR(maj_stat))
-    {
-        set_gss_error(maj_stat, min_stat);
-        ret = AUTH_GSS_ERROR;
-        goto end;
-    }
-    
-end:
-    return ret;
-}
-
-int authenticate_gss_client_clean(gss_client_state *state)
-{
-    OM_uint32 maj_stat;
-    OM_uint32 min_stat;
-    int ret = AUTH_GSS_COMPLETE;
-    
-    if (state->context != GSS_C_NO_CONTEXT)
-        maj_stat = gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER);
-    if (state->server_name != GSS_C_NO_NAME)
-        maj_stat = gss_release_name(&min_stat, &state->server_name);
-    if (state->username != NULL)
-    {
-        free(state->username);
-        state->username = NULL;
-    }
-    if (state->response != NULL)
-    {
-        free(state->response);
-        state->response = NULL;
-    }
-    
-    return ret;
-}
-
-int authenticate_gss_client_step(gss_client_state* state, const char* challenge)
-{
-    OM_uint32 maj_stat;
-    OM_uint32 min_stat;
-    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
-    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
-    int ret = AUTH_GSS_CONTINUE;
-    
-    // Always clear out the old response
-    if (state->response != NULL)
-    {
-        free(state->response);
-        state->response = NULL;
-    }
-    
-    // If there is a challenge (data from the server) we need to give it to GSS
-    if (challenge && *challenge)
-    {
-        int len;
-        input_token.value = base64_decode(challenge, &len);
-        input_token.length = len;
-    }
-    
-    // Do GSSAPI step
-    maj_stat = gss_init_sec_context(&min_stat,
-                                    GSS_C_NO_CREDENTIAL,
-                                    &state->context,
-                                    state->server_name,
-                                    GSS_C_NO_OID,
-                                    (OM_uint32)state->gss_flags,
-                                    0,
-                                    GSS_C_NO_CHANNEL_BINDINGS,
-                                    &input_token,
-                                    NULL,
-                                    &output_token,
-                                    NULL,
-                                    NULL);
-    
-    if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
-    {
-        set_gss_error(maj_stat, min_stat);
-        ret = AUTH_GSS_ERROR;
-        goto end;
-    }
-    
-    ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
-    // Grab the client response to send back to the server
-    if (output_token.length)
-    {
-        state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
-        maj_stat = gss_release_buffer(&min_stat, &output_token);
-    }
-    
-    // Try to get the user name if we have completed all GSS operations
-    if (ret == AUTH_GSS_COMPLETE)
-    {
-        gss_name_t gssuser = GSS_C_NO_NAME;
-        maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL,  NULL, NULL, NULL);
-        if (GSS_ERROR(maj_stat))
-        {
-            set_gss_error(maj_stat, min_stat);
-            ret = AUTH_GSS_ERROR;
-            goto end;
-        }
-        
-        gss_buffer_desc name_token;
-        name_token.length = 0;
-        maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL);
-        if (GSS_ERROR(maj_stat))
-        {
-            if (name_token.value)
-                gss_release_buffer(&min_stat, &name_token);
-            gss_release_name(&min_stat, &gssuser);
-            
-            set_gss_error(maj_stat, min_stat);
-            ret = AUTH_GSS_ERROR;
-            goto end;
-        }
-        else
-        {
-            state->username = (char *)malloc(name_token.length + 1);
-            strncpy(state->username, (char*) name_token.value, name_token.length);
-            state->username[name_token.length] = 0;
-            gss_release_buffer(&min_stat, &name_token);
-            gss_release_name(&min_stat, &gssuser);
-        }
-    }
-end:
-    if (output_token.value)
-        gss_release_buffer(&min_stat, &output_token);
-    if (input_token.value)
-        free(input_token.value);
-    return ret;
-}
-
-int authenticate_gss_client_unwrap(gss_client_state *state, const char *challenge)
-{
-	OM_uint32 maj_stat;
-	OM_uint32 min_stat;
-	gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
-	gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
-	int ret = AUTH_GSS_CONTINUE;
-    
-	// Always clear out the old response
-	if (state->response != NULL)
-	{
-		free(state->response);
-		state->response = NULL;
-	}
-    
-	// If there is a challenge (data from the server) we need to give it to GSS
-	if (challenge && *challenge)
-	{
-		int len;
-		input_token.value = base64_decode(challenge, &len);
-		input_token.length = len;
-	}
-    
-	// Do GSSAPI step
-	maj_stat = gss_unwrap(&min_stat,
-                          state->context,
-                          &input_token,
-                          &output_token,
-                          NULL,
-                          NULL);
-    
-	if (maj_stat != GSS_S_COMPLETE)
-	{
-		set_gss_error(maj_stat, min_stat);
-		ret = AUTH_GSS_ERROR;
-		goto end;
-	}
-	else
-		ret = AUTH_GSS_COMPLETE;
-    
-	// Grab the client response
-	if (output_token.length)
-	{
-		state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
-		maj_stat = gss_release_buffer(&min_stat, &output_token);
-	}
-end:
-	if (output_token.value)
-		gss_release_buffer(&min_stat, &output_token);
-	if (input_token.value)
-		free(input_token.value);
-	return ret;
-}
-
-int authenticate_gss_client_wrap(gss_client_state* state, const char* challenge, const char* user)
-{
-	OM_uint32 maj_stat;
-	OM_uint32 min_stat;
-	gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
-	gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
-	int ret = AUTH_GSS_CONTINUE;
-	char buf[4096], server_conf_flags;
-	unsigned long buf_size;
-    
-	// Always clear out the old response
-	if (state->response != NULL)
-	{
-		free(state->response);
-		state->response = NULL;
-	}
-    
-	if (challenge && *challenge)
-	{
-		int len;
-		input_token.value = base64_decode(challenge, &len);
-		input_token.length = len;
-	}
-    
-	if (user) {
-		// get bufsize
-		server_conf_flags = ((char*) input_token.value)[0];
-		((char*) input_token.value)[0] = 0;
-		buf_size = ntohl(*((long *) input_token.value));
-		free(input_token.value);
-#ifdef PRINTFS
-		printf("User: %s, %c%c%c\n", user,
-               server_conf_flags & GSS_AUTH_P_NONE      ? 'N' : '-',
-               server_conf_flags & GSS_AUTH_P_INTEGRITY ? 'I' : '-',
-               server_conf_flags & GSS_AUTH_P_PRIVACY   ? 'P' : '-');
-		printf("Maximum GSS token size is %ld\n", buf_size);
-#endif
-        
-		// agree to terms (hack!)
-		buf_size = htonl(buf_size); // not relevant without integrity/privacy
-		memcpy(buf, &buf_size, 4);
-		buf[0] = GSS_AUTH_P_NONE;
-		// server decides if principal can log in as user
-		strncpy(buf + 4, user, sizeof(buf) - 4);
-		input_token.value = buf;
-		input_token.length = 4 + strlen(user);
-	}
-    
-	// Do GSSAPI wrap
-	maj_stat = gss_wrap(&min_stat,
-						state->context,
-						0,
-						GSS_C_QOP_DEFAULT,
-						&input_token,
-						NULL,
-						&output_token);
-    
-	if (maj_stat != GSS_S_COMPLETE)
-	{
-		set_gss_error(maj_stat, min_stat);
-		ret = AUTH_GSS_ERROR;
-		goto end;
-	}
-	else
-		ret = AUTH_GSS_COMPLETE;
-	// Grab the client response to send back to the server
-	if (output_token.length)
-	{
-		state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
-		maj_stat = gss_release_buffer(&min_stat, &output_token);
-	}
-end:
-	if (output_token.value)
-		gss_release_buffer(&min_stat, &output_token);
-	return ret;
-}
-
-int authenticate_gss_server_init(const char *service, gss_server_state *state)
-{
-    OM_uint32 maj_stat;
-    OM_uint32 min_stat;
-    gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
-    int ret = AUTH_GSS_COMPLETE;
-    
-    state->context = GSS_C_NO_CONTEXT;
-    state->server_name = GSS_C_NO_NAME;
-    state->client_name = GSS_C_NO_NAME;
-    state->server_creds = GSS_C_NO_CREDENTIAL;
-    state->client_creds = GSS_C_NO_CREDENTIAL;
-    state->username = NULL;
-    state->targetname = NULL;
-    state->response = NULL;
-    
-    // Server name may be empty which means we aren't going to create our own creds
-    size_t service_len = strlen(service);
-    if (service_len != 0)
-    {
-        // Import server name first
-        name_token.length = strlen(service);
-        name_token.value = (char *)service;
-        
-        maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &state->server_name);
-        
-        if (GSS_ERROR(maj_stat))
-        {
-            set_gss_error(maj_stat, min_stat);
-            ret = AUTH_GSS_ERROR;
-            goto end;
-        }
-        
-        // Get credentials
-        maj_stat = gss_acquire_cred(&min_stat, state->server_name, GSS_C_INDEFINITE,
-                                    GSS_C_NO_OID_SET, GSS_C_ACCEPT, &state->server_creds, NULL, NULL);
-        
-        if (GSS_ERROR(maj_stat))
-        {
-            set_gss_error(maj_stat, min_stat);
-            ret = AUTH_GSS_ERROR;
-            goto end;
-        }
-    }
-    
-end:
-    return ret;
-}
-
-int authenticate_gss_server_clean(gss_server_state *state)
-{
-    OM_uint32 maj_stat;
-    OM_uint32 min_stat;
-    int ret = AUTH_GSS_COMPLETE;
-    
-    if (state->context != GSS_C_NO_CONTEXT)
-        maj_stat = gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER);
-    if (state->server_name != GSS_C_NO_NAME)
-        maj_stat = gss_release_name(&min_stat, &state->server_name);
-    if (state->client_name != GSS_C_NO_NAME)
-        maj_stat = gss_release_name(&min_stat, &state->client_name);
-    if (state->server_creds != GSS_C_NO_CREDENTIAL)
-        maj_stat = gss_release_cred(&min_stat, &state->server_creds);
-    if (state->client_creds != GSS_C_NO_CREDENTIAL)
-        maj_stat = gss_release_cred(&min_stat, &state->client_creds);
-    if (state->username != NULL)
-    {
-        free(state->username);
-        state->username = NULL;
-    }
-    if (state->targetname != NULL)
-    {
-        free(state->targetname);
-        state->targetname = NULL;
-    }
-    if (state->response != NULL)
-    {
-        free(state->response);
-        state->response = NULL;
-    }
-    
-    return ret;
-}
-
-int authenticate_gss_server_step(gss_server_state *state, const char *challenge)
-{
-    OM_uint32 maj_stat;
-    OM_uint32 min_stat;
-    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
-    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
-    int ret = AUTH_GSS_CONTINUE;
-    
-    // Always clear out the old response
-    if (state->response != NULL)
-    {
-        free(state->response);
-        state->response = NULL;
-    }
-    
-    // If there is a challenge (data from the server) we need to give it to GSS
-    if (challenge && *challenge)
-    {
-        int len;
-        input_token.value = base64_decode(challenge, &len);
-        input_token.length = len;
-    }
-    else
-    {
-        PyErr_SetString(KrbException_class, "No challenge parameter in request from client");
-        ret = AUTH_GSS_ERROR;
-        goto end;
-    }
-    
-    maj_stat = gss_accept_sec_context(&min_stat,
-                                      &state->context,
-                                      state->server_creds,
-                                      &input_token,
-                                      GSS_C_NO_CHANNEL_BINDINGS,
-                                      &state->client_name,
-                                      NULL,
-                                      &output_token,
-                                      NULL,
-                                      NULL,
-                                      &state->client_creds);
-    
-    if (GSS_ERROR(maj_stat))
-    {
-        set_gss_error(maj_stat, min_stat);
-        ret = AUTH_GSS_ERROR;
-        goto end;
-    }
-    
-    // Grab the server response to send back to the client
-    if (output_token.length)
-    {
-        state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
-        maj_stat = gss_release_buffer(&min_stat, &output_token);
-    }
-    
-    // Get the user name
-    maj_stat = gss_display_name(&min_stat, state->client_name, &output_token, NULL);
-    if (GSS_ERROR(maj_stat))
-    {
-        set_gss_error(maj_stat, min_stat);
-        ret = AUTH_GSS_ERROR;
-        goto end;
-    }
-    state->username = (char *)malloc(output_token.length + 1);
-    strncpy(state->username, (char*) output_token.value, output_token.length);
-    state->username[output_token.length] = 0;
-    
-    // Get the target name if no server creds were supplied
-    if (state->server_creds == GSS_C_NO_CREDENTIAL)
-    {
-        gss_name_t target_name = GSS_C_NO_NAME;
-        maj_stat = gss_inquire_context(&min_stat, state->context, NULL, &target_name, NULL, NULL, NULL, NULL, NULL);
-        if (GSS_ERROR(maj_stat))
-        {
-            set_gss_error(maj_stat, min_stat);
-            ret = AUTH_GSS_ERROR;
-            goto end;
-        }
-        maj_stat = gss_display_name(&min_stat, target_name, &output_token, NULL);
-        if (GSS_ERROR(maj_stat))
-        {
-            set_gss_error(maj_stat, min_stat);
-            ret = AUTH_GSS_ERROR;
-            goto end;
-        }
-        state->targetname = (char *)malloc(output_token.length + 1);
-        strncpy(state->targetname, (char*) output_token.value, output_token.length);
-        state->targetname[output_token.length] = 0;
-    }
-
-    ret = AUTH_GSS_COMPLETE;
-    
-end:
-    if (output_token.length)
-        gss_release_buffer(&min_stat, &output_token);
-    if (input_token.value)
-        free(input_token.value);
-    return ret;
-}
-
-
-static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min)
-{
-    OM_uint32 maj_stat, min_stat;
-    OM_uint32 msg_ctx = 0;
-    gss_buffer_desc status_string;
-    char buf_maj[512];
-    char buf_min[512];
-    
-    do
-    {
-        maj_stat = gss_display_status (&min_stat,
-                                       err_maj,
-                                       GSS_C_GSS_CODE,
-                                       GSS_C_NO_OID,
-                                       &msg_ctx,
-                                       &status_string);
-        if (GSS_ERROR(maj_stat))
-            break;
-        strncpy(buf_maj, (char*) status_string.value, sizeof(buf_maj));
-        gss_release_buffer(&min_stat, &status_string);
-        
-        maj_stat = gss_display_status (&min_stat,
-                                       err_min,
-                                       GSS_C_MECH_CODE,
-                                       GSS_C_NULL_OID,
-                                       &msg_ctx,
-                                       &status_string);
-        if (!GSS_ERROR(maj_stat))
-        {
-            strncpy(buf_min, (char*) status_string.value, sizeof(buf_min));
-            gss_release_buffer(&min_stat, &status_string);
-        }
-    } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
-    
-    PyErr_SetObject(GssException_class, Py_BuildValue("((s:i)(s:i))", buf_maj, err_maj, buf_min, err_min));
-}

+ 3 - 0
desktop/core/ext-py/kerberos-1.3.0/MANIFEST.in

@@ -0,0 +1,3 @@
+include LICENSE README.rst
+recursive-include src *.c *.h
+recursive-include pysrc *.py

+ 148 - 0
desktop/core/ext-py/kerberos-1.3.0/PKG-INFO

@@ -0,0 +1,148 @@
+Metadata-Version: 1.1
+Name: kerberos
+Version: 1.3.0
+Summary: Kerberos high-level interface
+Home-page: https://github.com/apple/ccs-pykerberos
+Author: Apple Inc.
+Author-email: calendarserver-dev@lists.macosforge.org
+License: Apache License, Version 2.0
+Description-Content-Type: UNKNOWN
+Description: PyKerberos Package
+        ==================
+        
+        .. image:: https://travis-ci.org/apple/ccs-pykerberos.svg?branch=master
+            :target: https://travis-ci.org/apple/ccs-pykerberos
+        
+        This Python package is a high-level wrapper for Kerberos (GSSAPI)
+        operations.  The goal is to avoid having to build a module that wraps
+        the entire Kerberos.framework, and instead offer a limited set of
+        functions that do what is needed for client/server Kerberos
+        authentication based on <http://www.ietf.org/rfc/rfc4559.txt>.
+        
+        Much of the C-code here is adapted from Apache's mod_auth_kerb-5.0rc7.
+        
+        
+        Build
+        =====
+        
+        In this directory, run:
+        
+          python setup.py build
+        
+        
+        Testing
+        =======
+        
+        To run the tests in the tests folder, you must have a valid Kerberos setup on
+        the test machine. You can use the script .travis.sh as quick and easy way to
+        setup a Kerberos KDC and Apache web endpoint that can be used for the tests.
+        Otherwise you can also run the following to run a self contained Docker
+        container
+        
+        .. code-block: bash
+        
+          docker run \
+          -v $(pwd):/app \
+          -w /app \
+          -e PYENV=2.7.13 \
+          -e KERBEROS_USERNAME=administrator \
+          -e KERBEROS_PASSWORD=Password01 \
+          -e KERBEROS_REALM=example.com \
+          -e KERBEROS_PORT=80 \
+          ubuntu:16.04 \
+          /bin/bash .travis.sh
+        
+        The docker command needs to be run in the same directory as this library and
+        you can test it with different Python versions by changing the value of the
+        PYENV environment value set in the command.
+        
+        Please have a look at testing_notes.md for more information.
+        
+        
+        IMPORTANT
+        =========
+        
+        The checkPassword method provided by this library is meant only for testing purposes as it does
+        not offer any protection against possible KDC spoofing. That method should not be used in any
+        production code.
+        
+        
+        Channel Bindings
+        ================
+        
+        You can use this library to authenticate with Channel Binding support. Channel
+        Bindings are tags that identify the particular data channel being used with the
+        authentication. You can use Channel bindings to offer more proof of a valid
+        identity. Some services like Microsoft's Extended Protection can enforce
+        Channel Binding support on authorisation and you can use this library to meet
+        those requirements.
+        
+        More details on Channel Bindings as set through the GSSAPI can be found here
+        <https://docs.oracle.com/cd/E19455-01/806-3814/overview-52/index.html>. Using
+        TLS as a example this is how you would add Channel Binding support to your
+        authentication mechanism. The following code snippet is based on RFC5929
+        <https://tools.ietf.org/html/rfc5929> using the 'tls-server-endpoint-point'
+        type.
+        
+        .. code-block:: python
+        
+           import hashlib
+        
+            def get_channel_bindings_application_data(socket):
+                # This is a highly simplified example, there are other use cases
+                # where you might need to use different hash types or get a socket
+                # object somehow.
+                server_certificate = socket.getpeercert(True)
+                certificate_hash = hashlib.sha256(server_certificate).hexdigest().upper()
+                certificate_digest = base64.b16decode(certificate_hash)
+                application_data = b'tls-server-end-point:%s' % certificate_digest
+        
+                return application_data
+        
+            def main():
+                # Code to setup a socket with the server
+                # A lot of code to setup the handshake and start the auth process
+                socket = getsocketsomehow()
+        
+                # Connect to the host and start the auth process
+        
+                # Build the channel bindings object
+                application_data = get_channel_bindings_application_data(socket)
+                channel_bindings = kerberos.channelBindings(application_data=application_data)
+        
+                # More work to get responses from the server
+        
+                result, context = kerberos.authGSSClientInit(kerb_spn, gssflags=gssflags, principal=principal)
+        
+                # Pass through the channel_bindings object as created in the kerberos.channelBindings method
+                result = kerberos.authGSSClientStep(context, neg_resp_value, channel_bindings=channel_bindings)
+        
+                # Repeat as necessary
+        
+        
+        Python APIs
+        ===========
+        
+        See kerberos.py.
+        
+        
+        Copyright and License
+        =====================
+        
+        Copyright (c) 2006-2018 Apple Inc.  All rights reserved.
+        
+        This software is licensed under the Apache License, Version 2.0.  The
+        Apache License is a well-established open source license, enabling
+        collaborative open source software development.
+        
+        See the "LICENSE" file for the full text of the license terms.
+        
+Platform: all
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: System :: Systems Administration :: Authentication/Directory

+ 129 - 0
desktop/core/ext-py/kerberos-1.3.0/README.rst

@@ -0,0 +1,129 @@
+PyKerberos Package
+==================
+
+.. image:: https://travis-ci.org/apple/ccs-pykerberos.svg?branch=master
+    :target: https://travis-ci.org/apple/ccs-pykerberos
+
+This Python package is a high-level wrapper for Kerberos (GSSAPI)
+operations.  The goal is to avoid having to build a module that wraps
+the entire Kerberos.framework, and instead offer a limited set of
+functions that do what is needed for client/server Kerberos
+authentication based on <http://www.ietf.org/rfc/rfc4559.txt>.
+
+Much of the C-code here is adapted from Apache's mod_auth_kerb-5.0rc7.
+
+
+Build
+=====
+
+In this directory, run:
+
+  python setup.py build
+
+
+Testing
+=======
+
+To run the tests in the tests folder, you must have a valid Kerberos setup on
+the test machine. You can use the script .travis.sh as quick and easy way to
+setup a Kerberos KDC and Apache web endpoint that can be used for the tests.
+Otherwise you can also run the following to run a self contained Docker
+container
+
+.. code-block: bash
+
+  docker run \
+  -v $(pwd):/app \
+  -w /app \
+  -e PYENV=2.7.13 \
+  -e KERBEROS_USERNAME=administrator \
+  -e KERBEROS_PASSWORD=Password01 \
+  -e KERBEROS_REALM=example.com \
+  -e KERBEROS_PORT=80 \
+  ubuntu:16.04 \
+  /bin/bash .travis.sh
+
+The docker command needs to be run in the same directory as this library and
+you can test it with different Python versions by changing the value of the
+PYENV environment value set in the command.
+
+Please have a look at testing_notes.md for more information.
+
+
+IMPORTANT
+=========
+
+The checkPassword method provided by this library is meant only for testing purposes as it does
+not offer any protection against possible KDC spoofing. That method should not be used in any
+production code.
+
+
+Channel Bindings
+================
+
+You can use this library to authenticate with Channel Binding support. Channel
+Bindings are tags that identify the particular data channel being used with the
+authentication. You can use Channel bindings to offer more proof of a valid
+identity. Some services like Microsoft's Extended Protection can enforce
+Channel Binding support on authorisation and you can use this library to meet
+those requirements.
+
+More details on Channel Bindings as set through the GSSAPI can be found here
+<https://docs.oracle.com/cd/E19455-01/806-3814/overview-52/index.html>. Using
+TLS as a example this is how you would add Channel Binding support to your
+authentication mechanism. The following code snippet is based on RFC5929
+<https://tools.ietf.org/html/rfc5929> using the 'tls-server-endpoint-point'
+type.
+
+.. code-block:: python
+
+   import hashlib
+
+    def get_channel_bindings_application_data(socket):
+        # This is a highly simplified example, there are other use cases
+        # where you might need to use different hash types or get a socket
+        # object somehow.
+        server_certificate = socket.getpeercert(True)
+        certificate_hash = hashlib.sha256(server_certificate).hexdigest().upper()
+        certificate_digest = base64.b16decode(certificate_hash)
+        application_data = b'tls-server-end-point:%s' % certificate_digest
+
+        return application_data
+
+    def main():
+        # Code to setup a socket with the server
+        # A lot of code to setup the handshake and start the auth process
+        socket = getsocketsomehow()
+
+        # Connect to the host and start the auth process
+
+        # Build the channel bindings object
+        application_data = get_channel_bindings_application_data(socket)
+        channel_bindings = kerberos.channelBindings(application_data=application_data)
+
+        # More work to get responses from the server
+
+        result, context = kerberos.authGSSClientInit(kerb_spn, gssflags=gssflags, principal=principal)
+
+        # Pass through the channel_bindings object as created in the kerberos.channelBindings method
+        result = kerberos.authGSSClientStep(context, neg_resp_value, channel_bindings=channel_bindings)
+
+        # Repeat as necessary
+
+
+Python APIs
+===========
+
+See kerberos.py.
+
+
+Copyright and License
+=====================
+
+Copyright (c) 2006-2018 Apple Inc.  All rights reserved.
+
+This software is licensed under the Apache License, Version 2.0.  The
+Apache License is a well-established open source license, enabling
+collaborative open source software development.
+
+See the "LICENSE" file for the full text of the license terms.

+ 461 - 0
desktop/core/ext-py/kerberos-1.3.0/pysrc/kerberos.py

@@ -0,0 +1,461 @@
+##
+# Copyright (c) 2006-2018 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+"""
+PyKerberos Function Description.
+"""
+
+
+
+class KrbError(Exception):
+    pass
+
+
+
+class BasicAuthError(KrbError):
+    pass
+
+
+
+class GSSError(KrbError):
+    pass
+
+
+
+def checkPassword(user, pswd, service, default_realm):
+    """
+    This function provides a simple way to verify that a user name and password
+    match those normally used for Kerberos authentication.
+    It does this by checking that the supplied user name and password can be
+    used to get a ticket for the supplied service.
+    If the user name does not contain a realm, then the default realm supplied
+    is used.
+
+    For this to work properly the Kerberos must be configured properly on this
+    machine.
+    That will likely mean ensuring that the edu.mit.Kerberos preference file
+    has the correct realms and KDCs listed.
+
+    IMPORTANT: This method is vulnerable to KDC spoofing attacks and it should
+    only used for testing. Do not use this in any production system - your
+    security could be compromised if you do.
+
+    @param user: A string containing the Kerberos user name.
+        A realm may be included by appending an C{"@"} followed by the realm
+        string to the actual user id.
+        If no realm is supplied, then the realm set in the default_realm
+        argument will be used.
+
+    @param pswd: A string containing the password for the user.
+
+    @param service: A string containing the Kerberos service to check access
+        for.
+        This will be of the form C{"sss/xx.yy.zz"}, where C{"sss"} is the
+        service identifier (e.g., C{"http"}, C{"krbtgt"}), and C{"xx.yy.zz"} is
+        the hostname of the server.
+
+    @param default_realm: A string containing the default realm to use if one
+        is not supplied in the user argument.
+        Note that Kerberos realms are normally all uppercase (e.g.,
+        C{"EXAMPLE.COM"}).
+
+    @return: True if authentication succeeds, false otherwise.
+    """
+
+
+
+def changePassword(user, oldpswd, newpswd):
+    """
+    This function allows to change the user password on the KDC.
+
+    @param user: A string containing the Kerberos user name.
+        A realm may be included by appending a C{"@"} followed by the realm
+        string to the actual user id.
+        If no realm is supplied, then the realm set in the default_realm
+        argument will be used.
+
+    @param oldpswd: A string containing the old (current) password for the
+        user.
+
+    @param newpswd: A string containing the new password for the user.
+
+    @return: True if password changing succeeds, false otherwise.
+    """
+
+
+
+def getServerPrincipalDetails(service, hostname):
+    """
+    This function returns the service principal for the server given a service
+    type and hostname.
+    Details are looked up via the C{/etc/keytab} file.
+
+    @param service: A string containing the Kerberos service type for the
+        server.
+
+    @param hostname: A string containing the hostname of the server.
+
+    @return: A string containing the service principal.
+    """
+
+
+
+"""
+GSSAPI Function Result Codes:
+
+    -1 : Error
+    0  : GSSAPI step continuation (only returned by 'Step' function)
+    1  : GSSAPI step complete, or function return OK
+
+"""
+
+# Some useful result codes
+AUTH_GSS_CONTINUE     = 0
+AUTH_GSS_COMPLETE     = 1
+
+# Some useful gss flags
+GSS_C_DELEG_FLAG      = 1
+GSS_C_MUTUAL_FLAG     = 2
+GSS_C_REPLAY_FLAG     = 4
+GSS_C_SEQUENCE_FLAG   = 8
+GSS_C_CONF_FLAG       = 16
+GSS_C_INTEG_FLAG      = 32
+GSS_C_ANON_FLAG       = 64
+GSS_C_PROT_READY_FLAG = 128
+GSS_C_TRANS_FLAG      = 256
+
+
+
+def authGSSClientInit(service, **kwargs):
+    """
+    Initializes a context for GSSAPI client-side authentication with the given
+    service principal.
+    L{authGSSClientClean} must be called after this function returns an OK
+    result to dispose of the context once all GSSAPI operations are complete.
+
+    @param service: A string containing the service principal in the form
+        C{"type@fqdn"}.
+
+    @param principal: Optional string containing the client principal in the
+        form C{"user@realm"}.
+
+    @param gssflags: Optional integer used to set GSS flags.
+        (e.g. C{GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG} will
+        allow for forwarding credentials to the remote host)
+
+    @param delegated: Optional server context containing delegated credentials
+
+    @param mech_oid: Optional GGS mech OID
+
+    @return: A tuple of (result, context) where result is the result code (see
+        above) and context is an opaque value that will need to be passed to
+        subsequent functions.
+    """
+
+
+
+def authGSSClientClean(context):
+    """
+    Destroys the context for GSSAPI client-side authentication. This function
+    is provided for compatibility with earlier versions of PyKerberos but does
+    nothing. The context object destroys itself when it is reclaimed.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A result code (see above).
+    """
+
+
+
+def authGSSClientInquireCred(context):
+    """
+    Get the current user name, if any, without a client-side GSSAPI step.
+    If the principal has already been authenticated via completed client-side
+    GSSAPI steps then the user name of the authenticated principal is kept. The
+    user name will be available via authGSSClientUserName.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A result code (see above).
+    """
+
+
+
+"""
+Address Types for Channel Bindings
+https://docs.oracle.com/cd/E19455-01/806-3814/6jcugr7dp/index.html#reference-9
+
+"""
+
+GSS_C_AF_UNSPEC    = 0
+GSS_C_AF_LOCAL     = 1
+GSS_C_AF_INET      = 2
+GSS_C_AF_IMPLINK   = 3
+GSS_C_AF_PUP       = 4
+GSS_C_AF_CHAOS     = 5
+GSS_C_AF_NS        = 6
+GSS_C_AF_NBS       = 7
+GSS_C_AF_ECMA      = 8
+GSS_C_AF_DATAKIT   = 9
+GSS_C_AF_CCITT     = 10
+GSS_C_AF_SNA       = 11
+GSS_C_AF_DECnet    = 12
+GSS_C_AF_DLI       = 13
+GSS_C_AF_LAT       = 14
+GSS_C_AF_HYLINK    = 15
+GSS_C_AF_APPLETALK = 16
+GSS_C_AF_BSC       = 17
+GSS_C_AF_DSS       = 18
+GSS_C_AF_OSI       = 19
+GSS_C_AF_X25       = 21
+GSS_C_AF_NULLADDR  = 255
+
+
+
+def channelBindings(**kwargs):
+    """
+    Builds a gss_channel_bindings_struct which can be used to pass onto
+    L{authGSSClientStep} to bind onto the auth. Details on Channel Bindings
+    can be foud at https://tools.ietf.org/html/rfc5929. More details on the
+    struct can be found at
+    https://docs.oracle.com/cd/E19455-01/806-3814/overview-52/index.html
+
+    @param initiator_addrtype: Optional integer used to set the
+        initiator_addrtype, defaults to GSS_C_AF_UNSPEC if not set
+
+    @param initiator_address: Optional byte string containing the
+        initiator_address
+
+    @param acceptor_addrtype: Optional integer used to set the
+        acceptor_addrtype, defaults to GSS_C_AF_UNSPEC if not set
+
+    @param acceptor_address: Optional byte string containing the
+        acceptor_address
+
+    @param application_data: Optional byte string containing the
+        application_data. An example would be 'tls-server-end-point:{cert-hash}'
+        where {cert-hash} is the hash of the server's certificate
+
+    @return: A tuple of (result, gss_channel_bindings_struct) where result is
+        the result code and gss_channel_bindings_struct is the channel bindings
+        structure that can be passed onto L{authGSSClientStep}
+    """
+
+
+
+def authGSSClientStep(context, challenge, **kwargs):
+    """
+    Processes a single GSSAPI client-side step using the supplied server data.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @param challenge: A string containing the base64-encoded server data (which
+        may be empty for the first step).
+
+    @param channel_bindings: Optional channel bindings to bind onto the auth
+        request. This struct can be built using :{channelBindings}
+        and if not specified it will pass along GSS_C_NO_CHANNEL_BINDINGS as
+        a default.
+
+    @return: A result code (see above).
+    """
+
+
+
+def authGSSClientResponse(context):
+    """
+    Get the client response from the last successful GSSAPI client-side step.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A string containing the base64-encoded client data to be sent to
+        the server.
+    """
+
+
+
+def authGSSClientResponseConf(context):
+    """
+    Determine whether confidentiality was enabled in the previously unwrapped
+    buffer.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: C{1} if confidentiality was enabled in the previously unwrapped
+        buffer, C{0} otherwise.
+    """
+
+
+
+def authGSSClientUserName(context):
+    """
+    Get the user name of the principal authenticated via the now complete
+    GSSAPI client-side operations, or the current user name obtained via
+    authGSSClientInquireCred. This method must only be called after
+    authGSSClientStep or authGSSClientInquireCred return a complete response
+    code.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A string containing the user name.
+    """
+
+
+
+def authGSSClientUnwrap(context, challenge):
+    """
+    Perform the client side GSSAPI unwrap step.
+
+    @param challenge: A string containing the base64-encoded server data.
+
+    @return: A result code (see above)
+    """
+
+
+
+def authGSSClientWrap(context, data, user=None, protect=0):
+    """
+    Perform the client side GSSAPI wrap step.
+
+    @param data: The result of the L{authGSSClientResponse} after the
+        L{authGSSClientUnwrap}.
+
+    @param user: The user to authorize.
+
+    @param protect: If C{0}, then just provide integrity protection.
+        If C{1}, then provide confidentiality as well.
+
+    @return: A result code (see above)
+    """
+
+
+
+def authGSSServerInit(service):
+    """
+    Initializes a context for GSSAPI server-side authentication with the given
+    service principal.
+    authGSSServerClean must be called after this function returns an OK result
+    to dispose of the context once all GSSAPI operations are complete.
+
+    @param service: A string containing the service principal in the form
+        C{"type@fqdn"}. To initialize the context for the purpose of accepting
+        delegated credentials, pass the literal string C{"DELEGATE"}.
+
+    @return: A tuple of (result, context) where result is the result code (see
+        above) and context is an opaque value that will need to be passed to
+        subsequent functions.
+    """
+
+
+
+def authGSSServerClean(context):
+    """
+    Destroys the context for GSSAPI server-side authentication. This function
+    is provided for compatibility with earlier versions of PyKerberos but does
+    nothing. The context object destroys itself when it is reclaimed.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A result code (see above).
+    """
+
+
+
+def authGSSServerStep(context, challenge):
+    """
+    Processes a single GSSAPI server-side step using the supplied client data.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @param challenge: A string containing the base64-encoded client data.
+
+    @return: A result code (see above).
+    """
+
+
+
+def authGSSServerResponse(context):
+    """
+    Get the server response from the last successful GSSAPI server-side step.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A string containing the base64-encoded server data to be sent to
+        the client.
+    """
+
+
+
+def authGSSServerHasDelegated(context):
+    """
+    Checks whether a server context has delegated credentials.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A bool saying whether delegated credentials are available.
+    """
+
+
+
+def authGSSServerUserName(context):
+    """
+    Get the user name of the principal trying to authenticate to the server.
+    This method must only be called after L{authGSSServerStep} returns a
+    complete or continue response code.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A string containing the user name.
+    """
+
+
+
+def authGSSServerTargetName(context):
+    """
+    Get the target name if the server did not supply its own credentials.
+    This method must only be called after L{authGSSServerStep} returns a
+    complete or continue response code.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A string containing the target name.
+    """
+
+
+
+def authGSSServerStoreDelegate(context):
+    """
+    Save the ticket sent to the server in the file C{/tmp/krb5_pyserv_XXXXXX}.
+    This method must only be called after L{authGSSServerStep} returns a
+    complete or continue response code.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A result code (see above).
+    """
+
+
+
+def authGSSServerCacheName(context):
+    """
+    Get the name of the credential cache created with
+    L{authGSSServerStoreDelegate}.
+    This method must only be called after L{authGSSServerStoreDelegate}.
+
+    @param context: The context object returned from L{authGSSClientInit}.
+
+    @return: A string containing the cache name.
+    """

+ 4 - 0
desktop/core/ext-py/kerberos-1.3.0/setup.cfg

@@ -0,0 +1,4 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+

+ 132 - 0
desktop/core/ext-py/kerberos-1.3.0/setup.py

@@ -0,0 +1,132 @@
+##
+# Copyright (c) 2006-2018 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from os.path import dirname, join as joinpath
+from setuptools import setup, Extension
+
+try:
+    from subprocess import getoutput
+except ImportError:
+    from commands import getoutput
+
+
+#
+# Options
+#
+
+project_name = "kerberos"
+
+version_string = "1.3.0"
+
+description = "Kerberos high-level interface"
+
+long_description = open(joinpath(dirname(__file__), "README.rst")).read()
+
+url = "https://github.com/apple/ccs-pykerberos"
+
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Operating System :: OS Independent",
+    "Programming Language :: Python :: 2",
+    "Programming Language :: Python :: 3",
+    "Topic :: Software Development :: Libraries :: Python Modules",
+    "Topic :: System :: Systems Administration :: Authentication/Directory",
+]
+
+author = "Apple Inc."
+
+author_email = "calendarserver-dev@lists.macosforge.org"
+
+license = "Apache License, Version 2.0"
+
+platforms = ["all"]
+
+
+#
+# Entry points
+#
+
+entry_points = {
+    "console_scripts": [],
+}
+
+
+#
+# Dependencies
+#
+
+setup_requirements = []
+
+install_requirements = []
+
+extras_requirements = {}
+
+extra_link_args = getoutput("krb5-config --libs gssapi").split()
+
+extra_compile_args = getoutput("krb5-config --cflags gssapi").split()
+
+
+#
+# Set up Extension modules that need to be built
+#
+
+extensions = [
+    Extension(
+        "kerberos",
+        extra_link_args=extra_link_args,
+        extra_compile_args=extra_compile_args,
+        sources=[
+            "src/base64.c",
+            "src/kerberos.c",
+            "src/kerberosbasic.c",
+            "src/kerberosgss.c",
+            "src/kerberospw.c",
+        ],
+    ),
+]
+
+
+#
+# Run setup
+#
+
+def doSetup():
+    setup(
+        name=project_name,
+        version=version_string,
+        description=description,
+        long_description=long_description,
+        url=url,
+        classifiers=classifiers,
+        author=author,
+        author_email=author_email,
+        license=license,
+        platforms=platforms,
+        ext_modules=extensions,
+        setup_requires=setup_requirements,
+        install_requires=install_requirements,
+        extras_require=extras_requirements,
+    )
+
+
+#
+# Main
+#
+
+if __name__ == "__main__":
+    doSetup()

+ 28 - 15
desktop/core/ext-py/kerberos-1.1.1/src/base64.c → desktop/core/ext-py/kerberos-1.3.0/src/base64.c

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -40,9 +40,13 @@ static signed char index_64[128] =
 // value            :    data to encode
 // value            :    data to encode
 // vlen             :    length of data
 // vlen             :    length of data
 // (result)         :    new char[] - c-str of result
 // (result)         :    new char[] - c-str of result
-char *base64_encode(const unsigned char *value, int vlen)
+char *base64_encode(const unsigned char *value, size_t vlen)
 {
 {
     char *result = (char *)malloc((vlen * 4) / 3 + 5);
     char *result = (char *)malloc((vlen * 4) / 3 + 5);
+    if (result == NULL)
+    {
+        return NULL;
+    }
     char *out = result;
     char *out = result;
     while (vlen >= 3)
     while (vlen >= 3)
     {
     {
@@ -72,41 +76,49 @@ char *base64_encode(const unsigned char *value, int vlen)
 // value            :    c-str to decode
 // value            :    c-str to decode
 // rlen             :    length of decoded result
 // rlen             :    length of decoded result
 // (result)         :    new unsigned char[] - decoded result
 // (result)         :    new unsigned char[] - decoded result
-unsigned char *base64_decode(const char *value, int *rlen)
+unsigned char *base64_decode(const char *value, size_t *rlen)
 {
 {
     *rlen = 0;
     *rlen = 0;
     int c1, c2, c3, c4;
     int c1, c2, c3, c4;
 
 
-    int vlen = strlen(value);
+    size_t vlen = strlen(value);
     unsigned char *result =(unsigned char *)malloc((vlen * 3) / 4 + 1);
     unsigned char *result =(unsigned char *)malloc((vlen * 3) / 4 + 1);
+    if (result == NULL)
+    {
+        return NULL;
+    }
     unsigned char *out = result;
     unsigned char *out = result;
 
 
-    while (1)
-    {
-        if (value[0]==0)
+    while (1) {
+        if (value[0]==0) {
             return result;
             return result;
+        }
         c1 = value[0];
         c1 = value[0];
-        if (CHAR64(c1) == -1)
+        if (CHAR64(c1) == -1) {
             goto base64_decode_error;;
             goto base64_decode_error;;
+        }
         c2 = value[1];
         c2 = value[1];
-        if (CHAR64(c2) == -1)
+        if (CHAR64(c2) == -1) {
             goto base64_decode_error;;
             goto base64_decode_error;;
+        }
         c3 = value[2];
         c3 = value[2];
-        if ((c3 != '=') && (CHAR64(c3) == -1))
+        if ((c3 != '=') && (CHAR64(c3) == -1)) {
             goto base64_decode_error;;
             goto base64_decode_error;;
+        }
         c4 = value[3];
         c4 = value[3];
-        if ((c4 != '=') && (CHAR64(c4) == -1))
+        if ((c4 != '=') && (CHAR64(c4) == -1)) {
             goto base64_decode_error;;
             goto base64_decode_error;;
+        }
 
 
         value += 4;
         value += 4;
         *out++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4);
         *out++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4);
         *rlen += 1;
         *rlen += 1;
-        if (c3 != '=')
-        {
+
+        if (c3 != '=') {
             *out++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2);
             *out++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2);
             *rlen += 1;
             *rlen += 1;
-            if (c4 != '=')
-            {
+
+            if (c4 != '=') {
                 *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4);
                 *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4);
                 *rlen += 1;
                 *rlen += 1;
             }
             }
@@ -116,5 +128,6 @@ unsigned char *base64_decode(const char *value, int *rlen)
 base64_decode_error:
 base64_decode_error:
     *result = 0;
     *result = 0;
     *rlen = 0;
     *rlen = 0;
+
     return result;
     return result;
 }
 }

+ 5 - 3
desktop/core/ext-py/kerberos-1.1.1/src/base64.h → desktop/core/ext-py/kerberos-1.3.0/src/base64.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,5 +14,7 @@
  * limitations under the License.
  * limitations under the License.
  **/
  **/
 
 
-char *base64_encode(const unsigned char *value, int vlen);
-unsigned char *base64_decode(const char *value, int *rlen);
+#include <stddef.h>
+
+char *base64_encode(const unsigned char *value, size_t vlen);
+unsigned char *base64_decode(const char *value, size_t *rlen);

+ 918 - 0
desktop/core/ext-py/kerberos-1.3.0/src/kerberos.c

@@ -0,0 +1,918 @@
+/**
+ * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+#include <Python.h>
+
+#include "kerberosbasic.h"
+#include "kerberospw.h"
+#include "kerberosgss.h"
+
+
+/*
+ * Support the Python 3 API while maintaining backward compatibility for the
+ * Python 2 API.
+ * Thanks to Lennart Regebro for http://python3porting.com/cextensions.html
+ */
+// Handle basic API changes
+#if PY_MAJOR_VERSION >= 3
+    // Basic renames (function parameters are the same)
+    // No more int objects
+    #define PyInt_FromLong PyLong_FromLong
+#endif
+
+#if PY_VERSION_HEX >= 0x03020000
+    // CObjects to Capsules
+    #define PyCObject_Check PyCapsule_CheckExact
+    #define PyCObject_SetVoidPtr PyCapsule_SetPointer
+
+    // More complex macros (function parameters are not the same)
+    // Note for PyCObject_FromVoidPtr, destr is now the third parameter
+    #define PyCObject_FromVoidPtr(cobj, destr) PyCapsule_New(cobj, NULL, destr)
+    #define PyCObject_AsVoidPtr(pobj) PyCapsule_GetPointer(pobj, NULL)
+#endif
+// Handle differences in module definition syntax and interface
+#if PY_MAJOR_VERSION >= 3
+    #define MOD_ERROR_VAL NULL
+    #define MOD_SUCCESS_VAL(val) val
+    #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+    #define MOD_DEF(ob, name, doc, methods) \
+          static struct PyModuleDef moduledef = { \
+            PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \
+          ob = PyModule_Create(&moduledef);
+#else
+    #define MOD_ERROR_VAL
+    #define MOD_SUCCESS_VAL(val)
+    #define MOD_INIT(name) void init##name(void)
+    #define MOD_DEF(ob, name, doc, methods) \
+          ob = Py_InitModule3(name, methods, doc);
+#endif
+
+static char krb5_mech_oid_bytes [] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02";
+gss_OID_desc krb5_mech_oid = { 9, &krb5_mech_oid_bytes };
+
+static char spnego_mech_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02";
+gss_OID_desc spnego_mech_oid = { 6, &spnego_mech_oid_bytes };
+
+PyObject *KrbException_class;
+PyObject *BasicAuthException_class;
+PyObject *PwdChangeException_class;
+PyObject *GssException_class;
+
+static PyObject *checkPassword(PyObject *self, PyObject *args)
+{
+    const char *user = NULL;
+    const char *pswd = NULL;
+    const char *service = NULL;
+    const char *default_realm = NULL;
+    int result = 0;
+
+    if (! PyArg_ParseTuple(args, "ssss", &user, &pswd, &service, &default_realm)) {
+        return NULL;
+    }
+
+    result = authenticate_user_krb5pwd(user, pswd, service, default_realm);
+
+    if (result) {
+        return Py_INCREF(Py_True), Py_True;
+    } else {
+        return NULL;
+    }
+}
+
+static PyObject *changePassword(PyObject *self, PyObject *args)
+{
+    const char *newpswd = NULL;
+    const char *oldpswd = NULL;
+    const char *user = NULL;
+    int result = 0;
+
+    if (! PyArg_ParseTuple(args, "sss", &user, &oldpswd, &newpswd)) {
+        return NULL;
+    }
+
+    result = change_user_krb5pwd(user, oldpswd, newpswd);
+
+    if (result) {
+        return Py_INCREF(Py_True), Py_True;
+    } else {
+        return NULL;
+    }
+}
+
+static PyObject *getServerPrincipalDetails(PyObject *self, PyObject *args)
+{
+    const char *service = NULL;
+    const char *hostname = NULL;
+    char* result = NULL;
+
+    if (! PyArg_ParseTuple(args, "ss", &service, &hostname)) {
+        return NULL;
+    }
+
+    result = server_principal_details(service, hostname);
+
+    if (result != NULL) {
+        PyObject* pyresult = Py_BuildValue("s", result);
+        free(result);
+        return pyresult;
+    } else {
+        return NULL;
+    }
+}
+
+static void
+#if PY_VERSION_HEX >= 0x03020000
+destroy_gss_client(PyObject *obj) {
+    gss_client_state *state = PyCapsule_GetPointer(obj, NULL);
+#else
+destroy_gss_client(void *obj) {
+    gss_client_state *state = (gss_client_state *)obj;
+#endif
+    if (state) {
+        authenticate_gss_client_clean(state);
+        free(state);
+    }
+}
+
+static PyObject* authGSSClientInit(PyObject* self, PyObject* args, PyObject* keywds)
+{
+    const char *service = NULL;
+    const char *principal = NULL;
+    gss_client_state *state = NULL;
+    PyObject *pystate = NULL;
+    gss_server_state *delegatestate = NULL;
+    PyObject *pydelegatestate = NULL;
+    gss_OID mech_oid = GSS_C_NO_OID;
+    PyObject *pymech_oid = NULL;
+    static char *kwlist[] = {
+        "service", "principal", "gssflags", "delegated", "mech_oid", NULL
+    };
+    long int gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
+    int result = 0;
+
+    if (! PyArg_ParseTupleAndKeywords(
+        args, keywds, "s|zlOO", kwlist,
+        &service, &principal, &gss_flags, &pydelegatestate, &pymech_oid
+    )) {
+        return NULL;
+    }
+
+    state = (gss_client_state *) malloc(sizeof(gss_client_state));
+    if (state == NULL)
+    {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    pystate = PyCObject_FromVoidPtr(state, &destroy_gss_client);
+
+    if (pydelegatestate != NULL && PyCObject_Check(pydelegatestate)) {
+        delegatestate = (gss_server_state*)PyCObject_AsVoidPtr(pydelegatestate);
+    }
+
+    if (pymech_oid != NULL && PyCObject_Check(pymech_oid)) {
+        mech_oid = (gss_OID)PyCObject_AsVoidPtr(pymech_oid);
+    }
+
+    result = authenticate_gss_client_init(
+        service, principal, gss_flags, delegatestate, mech_oid, state
+    );
+
+    if (result == AUTH_GSS_ERROR) {
+        return NULL;
+    }
+
+    return Py_BuildValue("(iO)", result, pystate);
+}
+
+static PyObject *authGSSClientClean(PyObject *self, PyObject *args)
+{
+    return Py_BuildValue("i", AUTH_GSS_COMPLETE);
+}
+
+#if PY_VERSION_HEX >= 0x03020000
+void destruct_channel_bindings(PyObject* o) {
+    struct gss_channel_bindings_struct *channel_bindings = PyCapsule_GetPointer(o, NULL);
+#else
+void destruct_channel_bindings(void* o) {
+    struct gss_channel_bindings_struct *channel_bindings = (struct gss_channel_bindings_struct *)o;
+#endif
+
+    if (channel_bindings != NULL) {
+        if (channel_bindings->initiator_address.value != NULL) {
+            PyMem_Free(channel_bindings->initiator_address.value);
+        }
+
+        if (channel_bindings->acceptor_address.value != NULL) {
+            PyMem_Free(channel_bindings->acceptor_address.value);
+        }
+
+        if (channel_bindings->application_data.value != NULL) {
+            PyMem_Free(channel_bindings->application_data.value);
+        }
+
+        free(channel_bindings);
+    }
+}
+
+static PyObject *channelBindings(PyObject *self, PyObject *args, PyObject* keywds)
+{
+    int initiator_addrtype = GSS_C_AF_UNSPEC;
+    int acceptor_addrtype = GSS_C_AF_UNSPEC;
+
+    const char *encoding = NULL;
+    char *initiator_address = NULL;
+    char *acceptor_address = NULL;
+    char *application_data = NULL;
+    int initiator_length = 0;
+    int acceptor_length = 0;
+    int application_length = 0;
+
+    PyObject *pychan_bindings = NULL;
+    struct gss_channel_bindings_struct *input_chan_bindings;
+    static char *kwlist[] = {"initiator_addrtype", "initiator_address", "acceptor_addrtype",
+        "acceptor_address", "application_data", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iet#iet#et#", kwlist,
+            &initiator_addrtype, &encoding, &initiator_address, &initiator_length,
+            &acceptor_addrtype, &encoding, &acceptor_address, &acceptor_length,
+            &encoding, &application_data, &application_length)) {
+        return NULL;
+    }
+
+    input_chan_bindings = (struct gss_channel_bindings_struct *) malloc(sizeof(struct gss_channel_bindings_struct));
+    pychan_bindings = PyCObject_FromVoidPtr(input_chan_bindings, &destruct_channel_bindings);
+
+    input_chan_bindings->initiator_addrtype = initiator_addrtype;
+    input_chan_bindings->initiator_address.length = initiator_length;
+    input_chan_bindings->initiator_address.value = initiator_address;
+
+    input_chan_bindings->acceptor_addrtype = acceptor_addrtype;
+    input_chan_bindings->acceptor_address.length = acceptor_length;
+    input_chan_bindings->acceptor_address.value = acceptor_address;
+
+    input_chan_bindings->application_data.length = application_length;
+    input_chan_bindings->application_data.value = application_data;
+
+    return Py_BuildValue("N", pychan_bindings);
+}
+
+static PyObject *authGSSClientStep(PyObject *self, PyObject *args, PyObject* keywds)
+{
+    gss_client_state *state = NULL;
+    PyObject *pystate = NULL;
+    char *challenge = NULL;
+    PyObject *pychan_bindings = NULL;
+    struct gss_channel_bindings_struct *channel_bindings;
+    static char *kwlist[] = {"state", "challenge", "channel_bindings", NULL};
+    int result = 0;
+
+    if (! PyArg_ParseTupleAndKeywords(args, keywds, "Os|O", kwlist, &pystate, &challenge, &pychan_bindings)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    if (pychan_bindings == NULL) {
+        channel_bindings = GSS_C_NO_CHANNEL_BINDINGS;
+    } else {
+        if (!PyCObject_Check(pychan_bindings)) {
+            PyErr_SetString(PyExc_TypeError, "Expected a gss_channel_bindings_struct object");
+            return NULL;
+        }
+        channel_bindings = (struct gss_channel_bindings_struct *)PyCObject_AsVoidPtr(pychan_bindings);
+    }
+
+    result = authenticate_gss_client_step(state, challenge, channel_bindings);
+
+    if (result == AUTH_GSS_ERROR) {
+        return NULL;
+    }
+
+    return Py_BuildValue("i", result);
+}
+
+static PyObject *authGSSClientResponseConf(PyObject *self, PyObject *args)
+{
+    gss_client_state *state = NULL;
+    PyObject *pystate = NULL;
+
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    return Py_BuildValue("i", state->responseConf);
+}
+
+static PyObject *authGSSServerHasDelegated(PyObject *self, PyObject *args)
+{
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    return PyBool_FromLong(authenticate_gss_server_has_delegated(state));
+}
+
+static PyObject *authGSSClientResponse(PyObject *self, PyObject *args)
+{
+    gss_client_state *state = NULL;
+    PyObject *pystate = NULL;
+
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    return Py_BuildValue("s", state->response);
+}
+
+static PyObject *authGSSClientUserName(PyObject *self, PyObject *args)
+{
+    gss_client_state *state = NULL;
+    PyObject *pystate = NULL;
+
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    return Py_BuildValue("s", state->username);
+}
+
+static PyObject *authGSSClientUnwrap(PyObject *self, PyObject *args)
+{
+	gss_client_state *state = NULL;
+	PyObject *pystate = NULL;
+	char *challenge = NULL;
+	int result = 0;
+
+	if (! PyArg_ParseTuple(args, "Os", &pystate, &challenge)) {
+		return NULL;
+    }
+
+	if (! PyCObject_Check(pystate)) {
+		PyErr_SetString(PyExc_TypeError, "Expected a context object");
+		return NULL;
+	}
+
+	state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
+
+	if (state == NULL) {
+		return NULL;
+    }
+
+	result = authenticate_gss_client_unwrap(state, challenge);
+
+	if (result == AUTH_GSS_ERROR) {
+		return NULL;
+    }
+
+	return Py_BuildValue("i", result);
+}
+
+static PyObject *authGSSClientWrap(PyObject *self, PyObject *args)
+{
+	gss_client_state *state = NULL;
+	PyObject *pystate = NULL;
+	char *challenge = NULL;
+	char *user = NULL;
+	int protect = 0;
+	int result = 0;
+
+	if (! PyArg_ParseTuple(
+        args, "Os|zi", &pystate, &challenge, &user, &protect
+    )) {
+		return NULL;
+    }
+
+	if (! PyCObject_Check(pystate)) {
+		PyErr_SetString(PyExc_TypeError, "Expected a context object");
+		return NULL;
+	}
+
+	state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
+
+	if (state == NULL) {
+		return NULL;
+    }
+
+	result = authenticate_gss_client_wrap(state, challenge, user, protect);
+
+	if (result == AUTH_GSS_ERROR) {
+		return NULL;
+    }
+
+	return Py_BuildValue("i", result);
+}
+
+static PyObject *authGSSClientInquireCred(PyObject *self, PyObject *args)
+{
+    gss_client_state *state = NULL;
+    PyObject *pystate = NULL;
+    int result = 0;
+    if (!PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+
+    if (!PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
+    if (state == NULL) {
+        return NULL;
+    }
+
+    result = authenticate_gss_client_inquire_cred(state);
+    if (result == AUTH_GSS_ERROR) {
+        return NULL;
+    }
+
+    return Py_BuildValue("i", result);
+}
+
+static void
+#if PY_VERSION_HEX >= 0x03020000
+destroy_gss_server(PyObject *obj) {
+    gss_server_state *state = PyCapsule_GetPointer(obj, NULL);
+#else
+destroy_gss_server(void *obj) {
+    gss_server_state *state = (gss_server_state *)obj;
+#endif
+    if (state) {
+        authenticate_gss_server_clean(state);
+        free(state);
+    }
+}
+
+static PyObject *authGSSServerInit(PyObject *self, PyObject *args)
+{
+    const char *service = NULL;
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+    int result = 0;
+
+    if (! PyArg_ParseTuple(args, "s", &service)) {
+        return NULL;
+    }
+
+    state = (gss_server_state *) malloc(sizeof(gss_server_state));
+    if (state == NULL)
+    {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    pystate = PyCObject_FromVoidPtr(state, &destroy_gss_server);
+
+    result = authenticate_gss_server_init(service, state);
+
+    if (result == AUTH_GSS_ERROR) {
+        return NULL;
+    }
+
+    return Py_BuildValue("(iO)", result, pystate);
+}
+
+static PyObject *authGSSServerClean(PyObject *self, PyObject *args)
+{
+    return Py_BuildValue("i", AUTH_GSS_COMPLETE);
+}
+
+static PyObject *authGSSServerStep(PyObject *self, PyObject *args)
+{
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+    char *challenge = NULL;
+    int result = 0;
+
+    if (! PyArg_ParseTuple(args, "Os", &pystate, &challenge)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    result = authenticate_gss_server_step(state, challenge);
+
+    if (result == AUTH_GSS_ERROR) {
+        return NULL;
+    }
+
+    return Py_BuildValue("i", result);
+}
+
+static PyObject *authGSSServerStoreDelegate(PyObject *self, PyObject *args)
+{
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+    int result = 0;
+
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    result = authenticate_gss_server_store_delegate(state);
+
+    if (result == AUTH_GSS_ERROR) {
+        return NULL;
+    }
+    
+    return Py_BuildValue("i", result);
+}
+
+static PyObject *authGSSServerResponse(PyObject *self, PyObject *args)
+{
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+
+    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    return Py_BuildValue("s", state->response);
+}
+
+static PyObject *authGSSServerUserName(PyObject *self, PyObject *args)
+{
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+    
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+    
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+    
+    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+    
+    return Py_BuildValue("s", state->username);
+}
+
+static PyObject *authGSSServerCacheName(PyObject *self, PyObject *args)
+{
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+    
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+    
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+    
+    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+
+    return Py_BuildValue("s", state->ccname);
+}
+
+static PyObject *authGSSServerTargetName(PyObject *self, PyObject *args)
+{
+    gss_server_state *state = NULL;
+    PyObject *pystate = NULL;
+    
+    if (! PyArg_ParseTuple(args, "O", &pystate)) {
+        return NULL;
+    }
+    
+    if (! PyCObject_Check(pystate)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a context object");
+        return NULL;
+    }
+    
+    state = (gss_server_state *)PyCObject_AsVoidPtr(pystate);
+
+    if (state == NULL) {
+        return NULL;
+    }
+    
+    return Py_BuildValue("s", state->targetname);
+}
+
+static PyMethodDef KerberosMethods[] = {
+    {
+        "checkPassword",
+        checkPassword, METH_VARARGS,
+        "Check the supplied user/password against Kerberos KDC."
+    },
+    {
+        "changePassword",
+        changePassword, METH_VARARGS,
+        "Change the user password."
+    },
+    {
+        "getServerPrincipalDetails",
+        getServerPrincipalDetails, METH_VARARGS,
+        "Return the service principal for a given service and hostname."
+    },
+    {
+        "authGSSClientInit",
+        (PyCFunction)authGSSClientInit, METH_VARARGS | METH_KEYWORDS,
+        "Initialize client-side GSSAPI operations."
+    },
+    {
+        "channelBindings",
+        (PyCFunction)channelBindings, METH_VARARGS | METH_KEYWORDS,
+        "Build the Channel Bindings Structure for authGSSClientStep."
+    },
+    {
+        "authGSSClientClean",
+        authGSSClientClean, METH_VARARGS,
+        "Terminate client-side GSSAPI operations."
+    },
+    {
+        "authGSSClientStep",
+        (PyCFunction)authGSSClientStep, METH_VARARGS | METH_KEYWORDS,
+        "Do a client-side GSSAPI step."
+    },
+    {
+        "authGSSClientResponse",
+        authGSSClientResponse, METH_VARARGS,
+        "Get the response from the last client-side GSSAPI step."
+    },
+    {
+        "authGSSClientInquireCred",  authGSSClientInquireCred, METH_VARARGS,
+        "Get the current user name, if any, without a client-side GSSAPI step"
+    },
+    {
+        "authGSSClientResponseConf",
+        authGSSClientResponseConf, METH_VARARGS,
+        "return 1 if confidentiality was set in the last unwrapped buffer, 0 otherwise."
+    },
+    {
+        "authGSSClientUserName",
+        authGSSClientUserName, METH_VARARGS,
+        "Get the user name from the last client-side GSSAPI step."
+    },
+    {
+        "authGSSServerInit",
+        authGSSServerInit, METH_VARARGS,
+        "Initialize server-side GSSAPI operations."
+    },
+    {
+        "authGSSClientWrap",
+        authGSSClientWrap, METH_VARARGS,
+        "Do a GSSAPI wrap."
+    },
+    {
+        "authGSSClientUnwrap",
+        authGSSClientUnwrap, METH_VARARGS,
+        "Do a GSSAPI unwrap."
+    },
+    {
+        "authGSSClientInquireCred", authGSSClientInquireCred, METH_VARARGS,
+        "Get the current user name, if any."
+    },
+    {
+        "authGSSServerClean",
+        authGSSServerClean, METH_VARARGS,
+        "Terminate server-side GSSAPI operations."
+    },
+    {
+        "authGSSServerStep",
+        authGSSServerStep, METH_VARARGS,
+        "Do a server-side GSSAPI step."
+    },
+    {
+        "authGSSServerHasDelegated",
+        authGSSServerHasDelegated, METH_VARARGS,
+        "Check whether the client delegated credentials to us."
+    },
+    {
+        "authGSSServerStoreDelegate",
+        authGSSServerStoreDelegate, METH_VARARGS,
+        "Store the delegated Credentials."
+    },
+    {
+        "authGSSServerResponse",
+        authGSSServerResponse, METH_VARARGS,
+        "Get the response from the last server-side GSSAPI step."
+    },
+    {
+        "authGSSServerUserName",
+        authGSSServerUserName, METH_VARARGS,
+        "Get the user name from the last server-side GSSAPI step."
+    },
+    {
+        "authGSSServerCacheName",
+        authGSSServerCacheName, METH_VARARGS,
+        "Get the location of the cache where delegated credentials are stored."
+    },
+    {
+        "authGSSServerTargetName",
+        authGSSServerTargetName, METH_VARARGS,
+        "Get the target name from the last server-side GSSAPI step."
+    },
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+MOD_INIT(kerberos)
+{
+    PyObject *m,*d;
+
+    MOD_DEF(m, "kerberos", NULL, KerberosMethods);
+
+    if (m == NULL) {
+        return MOD_ERROR_VAL;
+    }
+
+    d = PyModule_GetDict(m);
+
+    /* create the base exception class */
+    if (! (KrbException_class = PyErr_NewException(
+        "kerberos.KrbError", NULL, NULL
+    ))) {
+        goto error;
+    }
+
+    PyDict_SetItemString(d, "KrbError", KrbException_class);
+    Py_INCREF(KrbException_class);
+
+    /* ...and the derived exceptions */
+    if (! (BasicAuthException_class = PyErr_NewException(
+        "kerberos.BasicAuthError", KrbException_class, NULL
+    ))) {
+        goto error;
+    }
+
+    Py_INCREF(BasicAuthException_class);
+    PyDict_SetItemString(d, "BasicAuthError", BasicAuthException_class);
+
+    if (! (PwdChangeException_class = PyErr_NewException(
+        "kerberos.PwdChangeError", KrbException_class, NULL
+    ))) {
+        goto error;
+    }
+
+    Py_INCREF(PwdChangeException_class);
+    PyDict_SetItemString(d, "PwdChangeError", PwdChangeException_class);
+
+    if (! (GssException_class = PyErr_NewException(
+        "kerberos.GSSError", KrbException_class, NULL
+    ))) {
+        goto error;
+    }
+
+    Py_INCREF(GssException_class);
+    PyDict_SetItemString(
+        d, "GSSError", GssException_class
+    );
+
+    PyDict_SetItemString(
+        d, "AUTH_GSS_COMPLETE", PyInt_FromLong(AUTH_GSS_COMPLETE)
+    );
+    PyDict_SetItemString(
+        d, "AUTH_GSS_CONTINUE", PyInt_FromLong(AUTH_GSS_CONTINUE)
+    );
+
+    PyDict_SetItemString(
+        d, "GSS_C_DELEG_FLAG", PyInt_FromLong(GSS_C_DELEG_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_MUTUAL_FLAG", PyInt_FromLong(GSS_C_MUTUAL_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_REPLAY_FLAG", PyInt_FromLong(GSS_C_REPLAY_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_SEQUENCE_FLAG", PyInt_FromLong(GSS_C_SEQUENCE_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_CONF_FLAG", PyInt_FromLong(GSS_C_CONF_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_INTEG_FLAG", PyInt_FromLong(GSS_C_INTEG_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_ANON_FLAG", PyInt_FromLong(GSS_C_ANON_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_PROT_READY_FLAG", PyInt_FromLong(GSS_C_PROT_READY_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_C_TRANS_FLAG", PyInt_FromLong(GSS_C_TRANS_FLAG)
+    );
+    PyDict_SetItemString(
+        d, "GSS_MECH_OID_KRB5", PyCObject_FromVoidPtr(&krb5_mech_oid, NULL)
+    );
+    PyDict_SetItemString(
+        d, "GSS_MECH_OID_SPNEGO", PyCObject_FromVoidPtr(&spnego_mech_oid, NULL)
+    );
+
+error:
+    if (PyErr_Occurred()) {
+         PyErr_SetString(PyExc_ImportError, "kerberos: init failed");
+        return MOD_ERROR_VAL;
+    }
+
+    return MOD_SUCCESS_VAL(m);
+}

+ 51 - 31
desktop/core/ext-py/kerberos-1.1.1/src/kerberosbasic.c → desktop/core/ext-py/kerberos-1.3.0/src/kerberosbasic.c

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -26,10 +26,15 @@
 extern PyObject *BasicAuthException_class;
 extern PyObject *BasicAuthException_class;
 static void set_basicauth_error(krb5_context context, krb5_error_code code);
 static void set_basicauth_error(krb5_context context, krb5_error_code code);
 
 
-static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal principal, const char *password, krb5_principal server);
+static krb5_error_code verify_krb5_user(
+    krb5_context context, krb5_principal principal, const char *password,
+    krb5_principal server
+);
 
 
-int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *service, const char *default_realm)
-{
+int authenticate_user_krb5pwd(
+    const char *user, const char *pswd, const char *service,
+    const char *default_realm
+) {
     krb5_context    kcontext = NULL;
     krb5_context    kcontext = NULL;
     krb5_error_code code;
     krb5_error_code code;
     krb5_principal  client = NULL;
     krb5_principal  client = NULL;
@@ -41,23 +46,25 @@ int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *se
     code = krb5_init_context(&kcontext);
     code = krb5_init_context(&kcontext);
     if (code)
     if (code)
     {
     {
-        PyErr_SetObject(BasicAuthException_class, Py_BuildValue("((s:i))",
-                                                                "Cannot initialize Kerberos5 context", code));
+        PyErr_SetObject(
+            BasicAuthException_class,
+            Py_BuildValue(
+                "((s:i))", "Cannot initialize Kerberos5 context", code
+            )
+        );
         return 0;
         return 0;
     }
     }
 
 
     ret = krb5_parse_name (kcontext, service, &server);
     ret = krb5_parse_name (kcontext, service, &server);
 
 
-    if (ret)
-    {
+    if (ret) {
         set_basicauth_error(kcontext, ret);
         set_basicauth_error(kcontext, ret);
         ret = 0;
         ret = 0;
         goto end;
         goto end;
     }
     }
 
 
     code = krb5_unparse_name(kcontext, server, &name);
     code = krb5_unparse_name(kcontext, server, &name);
-    if (code)
-    {
+    if (code) {
         set_basicauth_error(kcontext, code);
         set_basicauth_error(kcontext, code);
         ret = 0;
         ret = 0;
         goto end;
         goto end;
@@ -69,19 +76,21 @@ int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *se
     name = NULL;
     name = NULL;
 
 
     name = (char *)malloc(256);
     name = (char *)malloc(256);
-    p = strchr(user, '@');
-    if (p == NULL)
+    if (name == NULL)
     {
     {
-        snprintf(name, 256, "%s@%s", user, default_realm);
+        PyErr_NoMemory();
+        ret = 0;
+        goto end;
     }
     }
-    else
-    {
+    p = strchr(user, '@');
+    if (p == NULL) {
+        snprintf(name, 256, "%s@%s", user, default_realm);
+    } else {
         snprintf(name, 256, "%s", user);
         snprintf(name, 256, "%s", user);
     }
     }
 
 
     code = krb5_parse_name(kcontext, name, &client);
     code = krb5_parse_name(kcontext, name, &client);
-    if (code)
-    {
+    if (code) {
         set_basicauth_error(kcontext, code);
         set_basicauth_error(kcontext, code);
         ret = 0;
         ret = 0;
         goto end;
         goto end;
@@ -89,8 +98,7 @@ int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *se
 
 
     code = verify_krb5_user(kcontext, client, pswd, server);
     code = verify_krb5_user(kcontext, client, pswd, server);
 
 
-    if (code)
-    {
+    if (code) {
         ret = 0;
         ret = 0;
         goto end;
         goto end;
     }
     }
@@ -99,22 +107,30 @@ int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *se
 
 
 end:
 end:
 #ifdef PRINTFS
 #ifdef PRINTFS
-    printf("kerb_authenticate_user_krb5pwd ret=%d user=%s authtype=%s\n", ret, user, "Basic");
+    printf(
+        "kerb_authenticate_user_krb5pwd ret=%d user=%s authtype=%s\n",
+        ret, user, "Basic"
+    );
 #endif
 #endif
-    if (name)
+    if (name) {
         free(name);
         free(name);
-    if (client)
+    }
+    if (client) {
         krb5_free_principal(kcontext, client);
         krb5_free_principal(kcontext, client);
-    if (server)
+    }
+    if (server) {
         krb5_free_principal(kcontext, server);
         krb5_free_principal(kcontext, server);
+    }
     krb5_free_context(kcontext);
     krb5_free_context(kcontext);
 
 
     return ret;
     return ret;
 }
 }
 
 
 /* Inspired by krb5_verify_user from Heimdal */
 /* Inspired by krb5_verify_user from Heimdal */
-static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal principal, const char *password, krb5_principal server)
-{
+static krb5_error_code verify_krb5_user(
+    krb5_context context, krb5_principal principal, const char *password,
+    krb5_principal server
+) {
     krb5_creds creds;
     krb5_creds creds;
     krb5_get_init_creds_opt gic_options;
     krb5_get_init_creds_opt gic_options;
     krb5_error_code ret;
     krb5_error_code ret;
@@ -123,8 +139,7 @@ static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal pri
     memset(&creds, 0, sizeof(creds));
     memset(&creds, 0, sizeof(creds));
 
 
     ret = krb5_unparse_name(context, principal, &name);
     ret = krb5_unparse_name(context, principal, &name);
-    if (ret == 0)
-    {
+    if (ret == 0) {
 #ifdef PRINTFS
 #ifdef PRINTFS
         printf("Trying to get TGT for user %s\n", name);
         printf("Trying to get TGT for user %s\n", name);
 #endif
 #endif
@@ -132,9 +147,11 @@ static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal pri
     }
     }
 
 
     krb5_get_init_creds_opt_init(&gic_options);
     krb5_get_init_creds_opt_init(&gic_options);
-    ret = krb5_get_init_creds_password(context, &creds, principal, (char *)password, NULL, NULL, 0, NULL, &gic_options);
-    if (ret)
-    {
+    ret = krb5_get_init_creds_password(
+        context, &creds, principal, (char *)password,
+        NULL, NULL, 0, NULL, &gic_options
+    );
+    if (ret) {
         set_basicauth_error(context, ret);
         set_basicauth_error(context, ret);
         goto end;
         goto end;
     }
     }
@@ -147,5 +164,8 @@ end:
 
 
 static void set_basicauth_error(krb5_context context, krb5_error_code code)
 static void set_basicauth_error(krb5_context context, krb5_error_code code)
 {
 {
-    PyErr_SetObject(BasicAuthException_class, Py_BuildValue("(s:i)", krb5_get_err_text(context, code), code));
+    PyErr_SetObject(
+        BasicAuthException_class,
+        Py_BuildValue("(s:i)", krb5_get_err_text(context, code), code)
+    );
 }
 }

+ 5 - 2
desktop/core/ext-py/kerberos-1.1.1/src/kerberosbasic.h → desktop/core/ext-py/kerberos-1.3.0/src/kerberosbasic.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -20,4 +20,7 @@
 
 
 #define krb5_get_err_text(context,code) error_message(code)
 #define krb5_get_err_text(context,code) error_message(code)
 
 
-int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *service, const char *default_realm);
+int authenticate_user_krb5pwd(
+    const char *user, const char *pswd, const char *service,
+    const char *default_realm
+);

+ 1007 - 0
desktop/core/ext-py/kerberos-1.3.0/src/kerberosgss.c

@@ -0,0 +1,1007 @@
+/**
+ * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+#include <Python.h>
+#include "kerberosgss.h"
+
+#include "base64.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min);
+
+int create_krb5_ccache(
+    gss_server_state *state, krb5_context kcontext, krb5_principal princ,
+    krb5_ccache *ccache
+);
+
+extern PyObject *GssException_class;
+extern PyObject *KrbException_class;
+
+char* server_principal_details(const char* service, const char* hostname)
+{
+    char match[1024];
+    size_t match_len = 0;
+    char* result = NULL;
+    
+    int code;
+    krb5_context kcontext;
+    krb5_keytab kt = NULL;
+    krb5_kt_cursor cursor = NULL;
+    krb5_keytab_entry entry;
+    char* pname = NULL;
+    
+    // Generate the principal prefix we want to match
+    snprintf(match, 1024, "%s/%s@", service, hostname);
+    match_len = strlen(match);
+    
+    code = krb5_init_context(&kcontext);
+    if (code) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue(
+                "((s:i))", "Cannot initialize Kerberos5 context", code
+            )
+        );
+        return NULL;
+    }
+    
+    if ((code = krb5_kt_default(kcontext, &kt))) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue("((s:i))", "Cannot get default keytab", code)
+        );
+        goto end;
+    }
+    
+    if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue(
+                "((s:i))", "Cannot get sequence cursor from keytab", code
+            )
+        );
+        goto end;
+    }
+    
+    while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
+        if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) {
+            PyErr_SetObject(
+                KrbException_class,
+                Py_BuildValue(
+                    "((s:i))", "Cannot parse principal name from keytab", code
+                )
+            );
+            goto end;
+        }
+        
+        if (strncmp(pname, match, match_len) == 0) {
+            result = malloc(strlen(pname) + 1);
+            if (result == NULL) {
+                PyErr_NoMemory();
+                goto end;
+            }
+            strcpy(result, pname);
+            krb5_free_unparsed_name(kcontext, pname);
+            krb5_free_keytab_entry_contents(kcontext, &entry);
+            break;
+        }
+        
+        krb5_free_unparsed_name(kcontext, pname);
+        krb5_free_keytab_entry_contents(kcontext, &entry);
+    }
+    
+    if (result == NULL) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue("((s:i))", "Principal not found in keytab", -1)
+        );
+    }
+    
+end:
+    if (cursor) {
+        krb5_kt_end_seq_get(kcontext, kt, &cursor);
+    }
+    if (kt) {
+        krb5_kt_close(kcontext, kt);
+    }
+    krb5_free_context(kcontext);
+    
+    return result;
+}
+
+int authenticate_gss_client_init(
+    const char* service, const char* principal, long int gss_flags,
+    gss_server_state* delegatestate, gss_OID mech_oid, gss_client_state* state
+)
+{
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+    gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc principal_token = GSS_C_EMPTY_BUFFER;
+    int ret = AUTH_GSS_COMPLETE;
+    
+    state->server_name = GSS_C_NO_NAME;
+    state->mech_oid = mech_oid;
+    state->context = GSS_C_NO_CONTEXT;
+    state->gss_flags = gss_flags;
+    state->client_creds = GSS_C_NO_CREDENTIAL;
+    state->username = NULL;
+    state->response = NULL;
+    
+    // Import server name first
+    name_token.length = strlen(service);
+    name_token.value = (char *)service;
+    
+    maj_stat = gss_import_name(
+        &min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name
+    );
+    
+    if (GSS_ERROR(maj_stat)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+    // Use the delegate credentials if they exist
+    if (delegatestate && delegatestate->client_creds != GSS_C_NO_CREDENTIAL) {
+        state->client_creds = delegatestate->client_creds;
+    }
+    // If available use the principal to extract its associated credentials
+    else if (principal && *principal) {
+        gss_name_t name;
+        principal_token.length = strlen(principal);
+        principal_token.value = (char *)principal;
+
+        maj_stat = gss_import_name(
+            &min_stat, &principal_token, GSS_C_NT_USER_NAME, &name
+        );
+        if (GSS_ERROR(maj_stat)) {
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+    	    goto end;
+        }
+
+        maj_stat = gss_acquire_cred(
+            &min_stat, name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+            GSS_C_INITIATE, &state->client_creds, NULL, NULL
+        );
+        if (GSS_ERROR(maj_stat)) {
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+
+        maj_stat = gss_release_name(&min_stat, &name);
+        if (GSS_ERROR(maj_stat)) {
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+    }
+
+end:
+    return ret;
+}
+
+int authenticate_gss_client_clean(gss_client_state *state)
+{
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+    int ret = AUTH_GSS_COMPLETE;
+    
+    if (state->context != GSS_C_NO_CONTEXT) {
+        maj_stat = gss_delete_sec_context(
+            &min_stat, &state->context, GSS_C_NO_BUFFER
+        );
+    }
+    if (state->server_name != GSS_C_NO_NAME) {
+        maj_stat = gss_release_name(&min_stat, &state->server_name);
+    }
+    if (
+        state->client_creds != GSS_C_NO_CREDENTIAL &&
+        ! (state->gss_flags & GSS_C_DELEG_FLAG)
+    ) {
+        maj_stat = gss_release_cred(&min_stat, &state->client_creds);
+    }
+    if (state->username != NULL) {
+        free(state->username);
+        state->username = NULL;
+    }
+    if (state->response != NULL) {
+        free(state->response);
+        state->response = NULL;
+    }
+    
+    return ret;
+}
+
+int authenticate_gss_client_step(
+    gss_client_state* state, const char* challenge, struct gss_channel_bindings_struct* channel_bindings
+) {
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+    int ret = AUTH_GSS_CONTINUE;
+    
+    // Always clear out the old response
+    if (state->response != NULL) {
+        free(state->response);
+        state->response = NULL;
+    }
+    
+    // If there is a challenge (data from the server) we need to give it to GSS
+    if (challenge && *challenge) {
+        size_t len;
+        input_token.value = base64_decode(challenge, &len);
+        if (input_token.value == NULL)
+        {
+            PyErr_NoMemory();
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        input_token.length = len;
+    }
+    
+    // Do GSSAPI step
+    Py_BEGIN_ALLOW_THREADS
+    maj_stat = gss_init_sec_context(
+        &min_stat,
+        state->client_creds,
+        &state->context,
+        state->server_name,
+        state->mech_oid,
+        (OM_uint32)state->gss_flags,
+        0,
+        channel_bindings,
+        &input_token,
+        NULL,
+        &output_token,
+        NULL,
+        NULL
+    );
+    Py_END_ALLOW_THREADS
+    
+    if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+    
+    ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
+    // Grab the client response to send back to the server
+    if (output_token.length) {
+        state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
+        if (state->response == NULL) {
+            PyErr_NoMemory();
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        maj_stat = gss_release_buffer(&min_stat, &output_token);
+    }
+    
+    // Try to get the user name if we have completed all GSS operations
+    if (ret == AUTH_GSS_COMPLETE) {
+        gss_name_t gssuser = GSS_C_NO_NAME;
+        maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL,  NULL, NULL, NULL);
+        if (GSS_ERROR(maj_stat)) {
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        
+        gss_buffer_desc name_token;
+        name_token.length = 0;
+        maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL);
+        if (GSS_ERROR(maj_stat)) {
+            if (name_token.value) {
+                gss_release_buffer(&min_stat, &name_token);
+            }
+            gss_release_name(&min_stat, &gssuser);
+            
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        } else {
+            if (state->username != NULL) {                                                                                                    
+                free(state->username);                                                                                                        
+                state->username = NULL;                                                                                                       
+            }                                                                                                                                 
+            state->username = (char *)malloc(name_token.length + 1);
+            if (state->username == NULL) {
+                PyErr_NoMemory();
+                ret = AUTH_GSS_ERROR;
+                goto end;
+            }
+            strncpy(state->username, (char*) name_token.value, name_token.length);
+            state->username[name_token.length] = 0;
+            gss_release_buffer(&min_stat, &name_token);
+            gss_release_name(&min_stat, &gssuser);
+        }
+    }
+
+end:
+    if (output_token.value) {
+        gss_release_buffer(&min_stat, &output_token);
+    }
+    if (input_token.value) {
+        free(input_token.value);
+    }
+    return ret;
+}
+
+int authenticate_gss_client_unwrap(
+    gss_client_state *state, const char *challenge
+) {
+	OM_uint32 maj_stat;
+	OM_uint32 min_stat;
+	gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+	int ret = AUTH_GSS_CONTINUE;
+	int conf = 0;
+    
+	// Always clear out the old response
+	if (state->response != NULL) {
+		free(state->response);
+		state->response = NULL;
+		state->responseConf = 0;
+	}
+    
+	// If there is a challenge (data from the server) we need to give it to GSS
+	if (challenge && *challenge) {
+		size_t len;
+		input_token.value = base64_decode(challenge, &len);
+		if (input_token.value == NULL) {
+		    PyErr_NoMemory();
+		    ret = AUTH_GSS_ERROR;
+		    goto end;
+		}
+		input_token.length = len;
+	}
+    
+	// Do GSSAPI step
+	maj_stat = gss_unwrap(
+        &min_stat,
+        state->context,
+        &input_token,
+        &output_token,
+        &conf,
+        NULL
+    );
+    
+	if (maj_stat != GSS_S_COMPLETE)	{
+		set_gss_error(maj_stat, min_stat);
+		ret = AUTH_GSS_ERROR;
+		goto end;
+	} else {
+		ret = AUTH_GSS_COMPLETE;
+    }
+    
+	// Grab the client response
+	if (output_token.length) {
+		state->response = base64_encode(
+            (const unsigned char *)output_token.value, output_token.length
+        );
+		if (state->response == NULL)
+		{
+		    PyErr_NoMemory();
+		    ret = AUTH_GSS_ERROR;
+		    goto end;
+		}
+		state->responseConf = conf;
+		maj_stat = gss_release_buffer(&min_stat, &output_token);
+	}
+
+end:
+	if (output_token.value) {
+		gss_release_buffer(&min_stat, &output_token);
+    }
+	if (input_token.value) {
+		free(input_token.value);
+    }
+	return ret;
+}
+
+int authenticate_gss_client_wrap(
+    gss_client_state* state, const char* challenge, const char* user,
+    int protect
+) {
+	OM_uint32 maj_stat;
+	OM_uint32 min_stat;
+	gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+	int ret = AUTH_GSS_CONTINUE;
+	char buf[4096], server_conf_flags;
+	unsigned long buf_size;
+    
+	// Always clear out the old response
+	if (state->response != NULL) {
+		free(state->response);
+		state->response = NULL;
+	}
+    
+	if (challenge && *challenge) {
+		size_t len;
+		input_token.value = base64_decode(challenge, &len);
+		if (input_token.value == NULL)
+		{
+		    PyErr_NoMemory();
+		    ret = AUTH_GSS_ERROR;
+		    goto end;
+		}
+		input_token.length = len;
+	}
+    
+	if (user) {
+		// get bufsize
+		server_conf_flags = ((char*) input_token.value)[0];
+		((char*) input_token.value)[0] = 0;
+		buf_size = ntohl(*((long *) input_token.value));
+		free(input_token.value);
+#ifdef PRINTFS
+		printf(
+            "User: %s, %c%c%c\n", user,
+            server_conf_flags & GSS_AUTH_P_NONE      ? 'N' : '-',
+            server_conf_flags & GSS_AUTH_P_INTEGRITY ? 'I' : '-',
+            server_conf_flags & GSS_AUTH_P_PRIVACY   ? 'P' : '-'
+        );
+		printf("Maximum GSS token size is %ld\n", buf_size);
+#endif
+        
+		// agree to terms (hack!)
+		buf_size = htonl(buf_size); // not relevant without integrity/privacy
+		memcpy(buf, &buf_size, 4);
+		buf[0] = GSS_AUTH_P_NONE;
+		// server decides if principal can log in as user
+		strncpy(buf + 4, user, sizeof(buf) - 4);
+		input_token.value = buf;
+		input_token.length = 4 + strlen(user);
+	}
+    
+	// Do GSSAPI wrap
+	maj_stat = gss_wrap(
+        &min_stat,
+        state->context,
+        protect,
+        GSS_C_QOP_DEFAULT,
+        &input_token,
+        NULL,
+        &output_token
+    );
+    
+	if (maj_stat != GSS_S_COMPLETE)	{
+		set_gss_error(maj_stat, min_stat);
+		ret = AUTH_GSS_ERROR;
+		goto end;
+	} else {
+		ret = AUTH_GSS_COMPLETE;
+    }
+	// Grab the client response to send back to the server
+	if (output_token.length) {
+		state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
+		if (state->response == NULL) {
+		    PyErr_NoMemory();
+		    ret = AUTH_GSS_ERROR;
+		    goto end;
+		}
+		maj_stat = gss_release_buffer(&min_stat, &output_token);
+	}
+
+end:
+	if (output_token.value) {
+		gss_release_buffer(&min_stat, &output_token);
+    }
+	return ret;
+}
+
+int authenticate_gss_client_inquire_cred(gss_client_state* state)
+{
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+    gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL;
+    gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
+    gss_name_t name = GSS_C_NO_NAME;
+    int ret = AUTH_GSS_COMPLETE;
+
+    // Check whether credentials have already been obtained.
+    if (state->username != NULL) {
+        goto end;
+    }
+
+    // Get credentials
+    maj_stat = gss_acquire_cred(
+        &min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE,
+        GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_creds, NULL, NULL
+    );
+
+    if (GSS_ERROR(maj_stat)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+
+    // Get the name
+    maj_stat = gss_inquire_cred(
+        &min_stat, client_creds, &name, NULL, NULL, NULL
+    );
+
+    if (GSS_ERROR(maj_stat)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+
+    maj_stat = gss_display_name(&min_stat, name, &name_token, NULL);
+
+    if (GSS_ERROR(maj_stat)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+
+    state->username = (char *)malloc(name_token.length + 1);
+    if (state->username == NULL) {
+        PyErr_NoMemory();
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+    strncpy(state->username, (char*) name_token.value, name_token.length);
+    state->username[name_token.length] = 0;
+
+end:
+    if (client_creds != GSS_C_NO_CREDENTIAL) {
+        gss_release_cred(&min_stat, &client_creds);
+    }
+    if (name_token.length) {
+        gss_release_buffer(&min_stat, &name_token);
+    }
+    if (name != GSS_C_NO_NAME) {
+        gss_release_name(&min_stat, &name);
+    }
+    return ret;
+}
+
+int authenticate_gss_server_init(const char *service, gss_server_state *state)
+{
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+    gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
+    int ret = AUTH_GSS_COMPLETE;
+    
+    state->context = GSS_C_NO_CONTEXT;
+    state->server_name = GSS_C_NO_NAME;
+    state->client_name = GSS_C_NO_NAME;
+    state->server_creds = GSS_C_NO_CREDENTIAL;
+    state->client_creds = GSS_C_NO_CREDENTIAL;
+    state->username = NULL;
+    state->targetname = NULL;
+    state->response = NULL;
+    state->ccname = NULL;
+    int cred_usage = GSS_C_ACCEPT;
+    
+    // Server name may be empty which means we aren't going to create our own creds
+    size_t service_len = strlen(service);
+    if (service_len != 0) {
+        // Import server name first
+        if (strcmp(service, "DELEGATE") == 0) {
+	    cred_usage = GSS_C_BOTH;
+        }
+        else {
+            name_token.length = strlen(service);
+            name_token.value = (char *)service;
+        
+            maj_stat = gss_import_name(
+                &min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE,
+                &state->server_name
+            );
+        
+            if (GSS_ERROR(maj_stat)) {
+                set_gss_error(maj_stat, min_stat);
+                ret = AUTH_GSS_ERROR;
+                goto end;
+            }
+	}
+
+        // Get credentials
+        maj_stat = gss_acquire_cred(
+            &min_stat, state->server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+            cred_usage, &state->server_creds, NULL, NULL
+        );
+
+        if (GSS_ERROR(maj_stat)) {
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+    }
+    
+end:
+    return ret;
+}
+
+int authenticate_gss_server_clean(gss_server_state *state)
+{
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+    int ret = AUTH_GSS_COMPLETE;
+    
+    if (state->context != GSS_C_NO_CONTEXT) {
+        maj_stat = gss_delete_sec_context(
+            &min_stat, &state->context, GSS_C_NO_BUFFER
+        );
+    }
+    if (state->server_name != GSS_C_NO_NAME) {
+        maj_stat = gss_release_name(&min_stat, &state->server_name);
+    }
+    if (state->client_name != GSS_C_NO_NAME) {
+        maj_stat = gss_release_name(&min_stat, &state->client_name);
+    }
+    if (state->server_creds != GSS_C_NO_CREDENTIAL) {
+        maj_stat = gss_release_cred(&min_stat, &state->server_creds);
+    }
+    if (state->client_creds != GSS_C_NO_CREDENTIAL) {
+        maj_stat = gss_release_cred(&min_stat, &state->client_creds);
+    }
+    if (state->username != NULL) {
+        free(state->username);
+        state->username = NULL;
+    }
+    if (state->targetname != NULL) {
+        free(state->targetname);
+        state->targetname = NULL;
+    }
+    if (state->response != NULL) {
+        free(state->response);
+        state->response = NULL;
+    }
+    if (state->ccname != NULL) {
+        free(state->ccname);
+        state->ccname = NULL;
+    }
+    
+    return ret;
+}
+
+int authenticate_gss_server_step(
+    gss_server_state *state, const char *challenge
+) {
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+    int ret = AUTH_GSS_CONTINUE;
+    
+    // Always clear out the old response
+    if (state->response != NULL) {
+        free(state->response);
+        state->response = NULL;
+    }
+    
+    // If there is a challenge (data from the server) we need to give it to GSS
+    if (challenge && *challenge) {
+        size_t len;
+        input_token.value = base64_decode(challenge, &len);
+        if (input_token.value == NULL)
+        {
+            PyErr_NoMemory();
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        input_token.length = len;
+    } else {
+        PyErr_SetString(
+            KrbException_class, "No challenge parameter in request from client"
+        );
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+    
+    Py_BEGIN_ALLOW_THREADS
+    maj_stat = gss_accept_sec_context(
+        &min_stat,
+        &state->context,
+        state->server_creds,
+        &input_token,
+        GSS_C_NO_CHANNEL_BINDINGS,
+        &state->client_name,
+        NULL,
+        &output_token,
+        NULL,
+        NULL,
+        &state->client_creds
+    );
+    Py_END_ALLOW_THREADS
+    
+    if (GSS_ERROR(maj_stat)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+    
+    // Grab the server response to send back to the client
+    if (output_token.length) {
+        state->response = base64_encode(
+            (const unsigned char *)output_token.value, output_token.length
+        );
+        if (state->response == NULL)
+        {
+            PyErr_NoMemory();
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        maj_stat = gss_release_buffer(&min_stat, &output_token);
+    }
+    
+    // Get the user name
+    maj_stat = gss_display_name(
+        &min_stat, state->client_name, &output_token, NULL
+    );
+    if (GSS_ERROR(maj_stat)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+    state->username = (char *)malloc(output_token.length + 1);
+    if (state->username == NULL)
+    {
+        PyErr_NoMemory();
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+    strncpy(state->username, (char*) output_token.value, output_token.length);
+    state->username[output_token.length] = 0;
+    
+    // Get the target name if no server creds were supplied
+    if (state->server_creds == GSS_C_NO_CREDENTIAL) {
+        gss_name_t target_name = GSS_C_NO_NAME;
+        maj_stat = gss_inquire_context(
+            &min_stat, state->context, NULL, &target_name, NULL, NULL, NULL,
+            NULL, NULL
+        );
+        if (GSS_ERROR(maj_stat)) {
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        maj_stat = gss_display_name(
+            &min_stat, target_name, &output_token, NULL
+        );
+        if (GSS_ERROR(maj_stat)) {
+            set_gss_error(maj_stat, min_stat);
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        state->targetname = (char *)malloc(output_token.length + 1);
+        if (state->targetname == NULL)
+        {
+            PyErr_NoMemory();
+            ret = AUTH_GSS_ERROR;
+            goto end;
+        }
+        strncpy(
+            state->targetname, (char*) output_token.value, output_token.length
+        );
+        state->targetname[output_token.length] = 0;
+    }
+
+    ret = AUTH_GSS_COMPLETE;
+    
+end:
+    if (output_token.length) {
+        gss_release_buffer(&min_stat, &output_token);
+    }
+    if (input_token.value) {
+        free(input_token.value);
+    }
+    return ret;
+}
+
+int authenticate_gss_server_has_delegated(gss_server_state *state)
+{
+    return (state->client_creds != GSS_C_NO_CREDENTIAL);
+}
+
+static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min)
+{
+    OM_uint32 maj_stat, min_stat;
+    OM_uint32 msg_ctx = 0;
+    gss_buffer_desc status_string;
+    char buf_maj[512];
+    char buf_min[512];
+    
+    do {
+        maj_stat = gss_display_status(
+            &min_stat,
+            err_maj,
+            GSS_C_GSS_CODE,
+            GSS_C_NO_OID,
+            &msg_ctx,
+            &status_string
+        );
+        if (GSS_ERROR(maj_stat)) {
+            break;
+        }
+        strncpy(buf_maj, (char*) status_string.value, sizeof(buf_maj));
+        gss_release_buffer(&min_stat, &status_string);
+        
+        maj_stat = gss_display_status(
+            &min_stat,
+            err_min,
+            GSS_C_MECH_CODE,
+            GSS_C_NULL_OID,
+            &msg_ctx,
+            &status_string
+        );
+        if (! GSS_ERROR(maj_stat)) {
+            strncpy(buf_min, (char*) status_string.value, sizeof(buf_min));
+            gss_release_buffer(&min_stat, &status_string);
+        }
+    } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
+    
+    PyErr_SetObject(
+        GssException_class,
+        Py_BuildValue("((s:i)(s:i))", buf_maj, err_maj, buf_min, err_min)
+    );
+}
+
+int authenticate_gss_server_store_delegate(gss_server_state *state)
+{
+    gss_cred_id_t delegated_cred = state->client_creds;
+    char *princ_name = state->username;
+    OM_uint32 maj_stat, min_stat;
+    krb5_principal princ = NULL;
+    krb5_ccache ccache = NULL;
+    krb5_error_code problem;
+    krb5_context context;
+    int ret = 500;
+
+    if (delegated_cred == GSS_C_NO_CREDENTIAL){
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue("(s)", "Ticket is not delegatable")
+        );
+        return AUTH_GSS_ERROR;
+    }
+
+    problem = krb5_init_context(&context);
+    if (problem) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue("(s)", "Cannot initialize krb5 context")
+        );
+        return AUTH_GSS_ERROR;
+    }
+
+    problem = krb5_parse_name(context, princ_name, &princ);
+    if (problem) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue(
+                "(s:s)", "Cannot parse delegated username",
+                krb5_get_err_text(context, problem)
+            )
+        );
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+
+    problem = create_krb5_ccache(state, context, princ, &ccache);
+    if (problem) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue(
+                "(s:s)", "Error in creating krb5 cache",
+                krb5_get_err_text(context, problem)
+            )
+        );
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+
+    maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
+    if (GSS_ERROR(maj_stat)) {
+        set_gss_error(maj_stat, min_stat);
+        ret = AUTH_GSS_ERROR;
+        goto end;
+    }
+
+    krb5_cc_close(context, ccache);
+    ccache = NULL;
+    ret = 0;
+
+end:
+    if (princ) {
+        krb5_free_principal(context, princ);
+    }
+    if (ccache) {
+        krb5_cc_destroy(context, ccache);
+    }
+    krb5_free_context(context);
+
+    return ret;
+}
+
+int create_krb5_ccache(
+    gss_server_state *state, krb5_context kcontext, krb5_principal princ,
+    krb5_ccache *ccache
+) {
+    int fd;
+    char ccname[32];
+    krb5_error_code problem;
+    int ret;
+    krb5_ccache tmp_ccache = NULL;
+
+    snprintf(ccname, sizeof(ccname), "/tmp/krb5cc_pyserv_XXXXXX");
+    fd = mkstemp(ccname);
+    if (fd < 0) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue("(s:s)", "Error in mkstemp", strerror(errno))
+        );
+        ret = 1;
+        goto end;
+    }
+    close(fd);
+
+    problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache);
+    if (problem) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue(
+                "(s:s)", "Error resolving the credential cache",
+                krb5_get_err_text(kcontext, problem)
+            )
+        );
+        ret = 1;
+        unlink(ccname);
+        goto end;
+    }
+
+    problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
+    if (problem) {
+        PyErr_SetObject(
+            KrbException_class,
+            Py_BuildValue(
+                "(s:s)", "Error initialising the credential cache",
+                krb5_get_err_text(kcontext, problem)
+            )
+        );
+        ret = 1;
+        goto end;
+    }
+
+    *ccache = tmp_ccache;
+    tmp_ccache = NULL;
+
+    ret = 0;
+
+end:
+    if (tmp_ccache) {
+        krb5_cc_destroy(kcontext, tmp_ccache);
+    }
+
+    state->ccname = (char *)malloc(32*sizeof(char));
+    if (state->ccname == NULL) {
+        PyErr_NoMemory();
+        return 1;
+    }
+    strcpy(state->ccname, ccname);
+
+    return ret;
+}

+ 40 - 9
desktop/core/ext-py/kerberos-1.1.1/src/kerberosgss.h → desktop/core/ext-py/kerberos-1.3.0/src/kerberosgss.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -31,9 +31,12 @@
 typedef struct {
 typedef struct {
     gss_ctx_id_t     context;
     gss_ctx_id_t     context;
     gss_name_t       server_name;
     gss_name_t       server_name;
+    gss_OID          mech_oid;
     long int         gss_flags;
     long int         gss_flags;
+    gss_cred_id_t    client_creds;
     char*            username;
     char*            username;
     char*            response;
     char*            response;
+    int              responseConf;
 } gss_client_state;
 } gss_client_state;
 
 
 typedef struct {
 typedef struct {
@@ -45,16 +48,44 @@ typedef struct {
     char*            username;
     char*            username;
     char*            targetname;
     char*            targetname;
     char*            response;
     char*            response;
+    char*            ccname;
 } gss_server_state;
 } gss_server_state;
 
 
 char* server_principal_details(const char* service, const char* hostname);
 char* server_principal_details(const char* service, const char* hostname);
 
 
-int authenticate_gss_client_init(const char* service, long int gss_flags, gss_client_state* state);
-int authenticate_gss_client_clean(gss_client_state *state);
-int authenticate_gss_client_step(gss_client_state *state, const char *challenge);
-int authenticate_gss_client_unwrap(gss_client_state* state, const char* challenge);
-int authenticate_gss_client_wrap(gss_client_state* state, const char* challenge, const char* user);
+int authenticate_gss_client_init(
+    const char* service, const char* principal, long int gss_flags,
+    gss_server_state* delegatestate, gss_OID mech_oid, gss_client_state* state
+);
+int authenticate_gss_client_clean(
+    gss_client_state *state
+);
+int authenticate_gss_client_step(
+    gss_client_state *state, const char *challenge, struct gss_channel_bindings_struct *channel_bindings
+);
+int authenticate_gss_client_unwrap(
+    gss_client_state* state, const char* challenge
+);
+int authenticate_gss_client_wrap(
+    gss_client_state* state, const char* challenge, const char* user,
+    int protect
+);
+int authenticate_gss_client_inquire_cred(
+    gss_client_state* state
+);
 
 
-int authenticate_gss_server_init(const char* service, gss_server_state* state);
-int authenticate_gss_server_clean(gss_server_state *state);
-int authenticate_gss_server_step(gss_server_state *state, const char *challenge);
+int authenticate_gss_server_init(
+    const char* service, gss_server_state* state
+);
+int authenticate_gss_server_clean(
+    gss_server_state *state
+);
+int authenticate_gss_server_step(
+    gss_server_state *state, const char *challenge
+);
+int authenticate_gss_server_store_delegate(
+    gss_server_state *state
+);
+int authenticate_gss_server_has_delegated(
+    gss_server_state *state
+);

+ 65 - 30
desktop/core/ext-py/kerberos-1.1.1/src/kerberospw.c → desktop/core/ext-py/kerberos-1.3.0/src/kerberospw.c

@@ -27,17 +27,20 @@ extern PyObject *PwdChangeException_class;
 
 
 static void set_pwchange_error(krb5_context context, krb5_error_code code)
 static void set_pwchange_error(krb5_context context, krb5_error_code code)
 {
 {
-    PyErr_SetObject(PwdChangeException_class, Py_BuildValue("(s:i)",
-                                                            krb5_get_err_text(context, code), code));
+    PyErr_SetObject(
+        PwdChangeException_class,
+        Py_BuildValue("(s:i)", krb5_get_err_text(context, code), code)
+    );
 }
 }
 
 
 /* Inspired by krb5_verify_user from Heimdal */
 /* Inspired by krb5_verify_user from Heimdal */
-static krb5_error_code verify_krb5_user(krb5_context context,
-                                        krb5_principal principal,
-                                        const char *password,
-                                        const char *service,
-                                        krb5_creds* creds)
-{
+static krb5_error_code verify_krb5_user(
+    krb5_context context,
+    krb5_principal principal,
+    const char *password,
+    const char *service,
+    krb5_creds* creds
+) {
     krb5_get_init_creds_opt gic_options;
     krb5_get_init_creds_opt gic_options;
     krb5_error_code code;
     krb5_error_code code;
     int ret = 0;
     int ret = 0;
@@ -46,11 +49,13 @@ static krb5_error_code verify_krb5_user(krb5_context context,
     {
     {
         char *name = NULL;
         char *name = NULL;
         code = krb5_unparse_name(context, principal, &name);
         code = krb5_unparse_name(context, principal, &name);
-        if (!code)
+        if (!code) {
             printf("Trying to get TGT for user %s\n", name);
             printf("Trying to get TGT for user %s\n", name);
+        }
         free(name);
         free(name);
     }
     }
 #endif
 #endif
+
     krb5_get_init_creds_opt_init(&gic_options);
     krb5_get_init_creds_opt_init(&gic_options);
     krb5_get_init_creds_opt_set_forwardable(&gic_options, 0);
     krb5_get_init_creds_opt_set_forwardable(&gic_options, 0);
     krb5_get_init_creds_opt_set_proxiable(&gic_options, 0);
     krb5_get_init_creds_opt_set_proxiable(&gic_options, 0);
@@ -58,39 +63,53 @@ static krb5_error_code verify_krb5_user(krb5_context context,
 
 
     memset(creds, 0, sizeof(krb5_creds));
     memset(creds, 0, sizeof(krb5_creds));
     
     
-    code = krb5_get_init_creds_password(context, creds, principal,
-                                        (char *)password, NULL, NULL, 0,
-                                        (char *)service, &gic_options);
+    code = krb5_get_init_creds_password(
+        context, creds, principal,
+        (char *)password, NULL, NULL, 0,
+        (char *)service, &gic_options
+    );
     if (code) {
     if (code) {
         set_pwchange_error(context, code);
         set_pwchange_error(context, code);
         goto end;
         goto end;
     }
     }
     ret = 1; /* success */
     ret = 1; /* success */
+
 end:
 end:
     return ret;
     return ret;
 }
 }
 
 
-int change_user_krb5pwd(const char *user, const char* oldpswd, const char *newpswd)
-{
+int change_user_krb5pwd(
+    const char *user, const char* oldpswd, const char *newpswd
+) {
     krb5_context    kcontext = NULL;
     krb5_context    kcontext = NULL;
     krb5_error_code code;
     krb5_error_code code;
     krb5_principal  client = NULL;
     krb5_principal  client = NULL;
-    krb5_creds    creds;
+    krb5_creds      creds;
     int             ret = 0;
     int             ret = 0;
+    int             bytes = 0;
     char            *name = NULL;
     char            *name = NULL;
+
     const char* service = "kadmin/changepw";
     const char* service = "kadmin/changepw";
     int result_code;
     int result_code;
     krb5_data result_code_string, result_string;
     krb5_data result_code_string, result_string;
 
 
     code = krb5_init_context(&kcontext);
     code = krb5_init_context(&kcontext);
     if (code) {
     if (code) {
-        PyErr_SetObject(PwdChangeException_class, Py_BuildValue("((s:i))",
-                                                                "Cannot initialize Kerberos5 context",
-                                                                code));
+        PyErr_SetObject(
+            PwdChangeException_class,
+            Py_BuildValue(
+                "((s:i))", "Cannot initialize Kerberos5 context", code
+            )
+        );
         return 0;
         return 0;
     }
     }
 
 
     name = (char *)malloc(256);
     name = (char *)malloc(256);
+    if (name == NULL)
+    {
+        PyErr_NoMemory();
+        goto end;
+    }
     snprintf(name, 256, "%s", user);
     snprintf(name, 256, "%s", user);
         
         
     code = krb5_parse_name(kcontext, name, &client);
     code = krb5_parse_name(kcontext, name, &client);
@@ -100,8 +119,9 @@ int change_user_krb5pwd(const char *user, const char* oldpswd, const char *newps
     }
     }
 
 
     code = verify_krb5_user(kcontext, client, oldpswd, service, &creds);
     code = verify_krb5_user(kcontext, client, oldpswd, service, &creds);
-    if (!code) /* exception set by verify_krb5_user */
+    if (! code) {  /* exception set by verify_krb5_user */
         goto end;
         goto end;
+    }
 
 
     code = krb5_change_password(kcontext, &creds, (char*)newpswd,
     code = krb5_change_password(kcontext, &creds, (char*)newpswd,
                                 &result_code, &result_code_string, &result_string);
                                 &result_code, &result_code_string, &result_string);
@@ -111,27 +131,42 @@ int change_user_krb5pwd(const char *user, const char* oldpswd, const char *newps
     }
     }
     if (result_code) {
     if (result_code) {
         char *message = NULL;
         char *message = NULL;
-        asprintf(&message, "%.*s: %.*s",
-                 (int) result_code_string.length,
-                 (char *) result_code_string.data,
-                 (int) result_string.length,
-                 (char *) result_string.data);
-        PyErr_SetObject(PwdChangeException_class, Py_BuildValue("((s:i))",
-                                                                message, result_code));
-        free(message);
+        bytes = asprintf(
+            &message, "%.*s: %.*s",
+            (int) result_code_string.length,
+            (char *) result_code_string.data,
+            (int) result_string.length,
+            (char *) result_string.data
+        );
+        if (bytes == -1)
+        {
+            PyErr_NoMemory();
+        }
+        else
+        {
+            PyErr_SetObject(
+                PwdChangeException_class,
+                Py_BuildValue("((s:i))", message, result_code)
+            );
+            free(message);
+        }
         goto end;
         goto end;
     }
     }
 
 
     ret = 1; /* success */
     ret = 1; /* success */
+
 end:
 end:
 #ifdef PRINTFS
 #ifdef PRINTFS
     printf("%s: ret=%d user=%s\n", __FUNCTION__, ret, name);
     printf("%s: ret=%d user=%s\n", __FUNCTION__, ret, name);
 #endif
 #endif
-    if (name)
+
+    if (name) {
         free(name);
         free(name);
-    if (client)
+    }
+    if (client) {
         krb5_free_principal(kcontext, client);
         krb5_free_principal(kcontext, client);
+    }
     krb5_free_context(kcontext);
     krb5_free_context(kcontext);
+
     return ret;
     return ret;
 }
 }
-

+ 3 - 1
desktop/core/ext-py/kerberos-1.1.1/src/kerberospw.h → desktop/core/ext-py/kerberos-1.3.0/src/kerberospw.h

@@ -21,4 +21,6 @@
 
 
 #define krb5_get_err_text(context,code) error_message(code)
 #define krb5_get_err_text(context,code) error_message(code)
 
 
-int change_user_krb5pwd(const char *user, const char* oldpswd, const char *newpswd);
+int change_user_krb5pwd(
+    const char *user, const char* oldpswd, const char *newpswd
+);