/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 * Copyright (C) 1989,1990,1991,1992,1993,1994,1995,2000,2001,
 * 2003,2006,2007,2008,2009 by the Massachusetts Institute of Technology,
 * Cambridge, MA, USA.  All Rights Reserved.
 *
 * This software is being provided to you, the LICENSEE, by the
 * Massachusetts Institute of Technology (M.I.T.) under the following
 * license.  By obtaining, using and/or copying this software, you agree
 * that you have read, understood, and will comply with these terms and
 * conditions:
 *
 * Export of this software from the United States of America may
 * require a specific license from the United States Government.
 * It is the responsibility of any person or organization contemplating
 * export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute
 * this software and its documentation for any purpose and without fee or
 * royalty is hereby granted, provided that you agree to comply with the
 * following copyright notice and statements, including the disclaimer, and
 * that the same appear on ALL copies of the software and documentation,
 * including modifications that you make for internal use or for
 * distribution:
 *
 * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS
 * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
 * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF
 * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
 * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY
 * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
 *
 * The name of the Massachusetts Institute of Technology or M.I.T. may NOT
 * be used in advertising or publicity pertaining to distribution of the
 * software.  Title to copyright in this software and any associated
 * documentation shall at all times remain with M.I.T., and USER agrees to
 * preserve same.
 *
 * Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 */
/*
 * Copyright (C) 1998 by the FundsXpress, INC.
 *
 * All rights reserved.
 *
 * Export of this software from the United States of America may require
 * a specific license from the United States Government.  It is the
 * responsibility of any person or organization contemplating export to
 * obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of FundsXpress. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  FundsXpress makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
 * This prototype for k5-int.h (Krb5 internals include file)
 * includes the user-visible definitions from krb5.h and then
 * includes other definitions that are not user-visible but are
 * required for compiling Kerberos internal routines.
 *
 * John Gilmore, Cygnus Support, Sat Jan 21 22:45:52 PST 1995
 */

#ifndef _KRB5_INT_H
#define _KRB5_INT_H

#ifdef KRB5_GENERAL__
#error krb5.h included before k5-int.h
#endif /* KRB5_GENERAL__ */

#include "osconf.h"

#if defined(__MACH__) && defined(__APPLE__)
#       include <TargetConditionals.h>
#    if TARGET_RT_MAC_CFM
#       error "Use KfM 4.0 SDK headers for CFM compilation."
#    endif
#endif

/*
 * Begin "k5-config.h"
 */
#ifndef KRB5_CONFIG__
#define KRB5_CONFIG__

/*
 * Machine-type definitions: PC Clone 386 running Microloss Windows
 */

#if defined(_MSDOS) || defined(_WIN32)
#include "win-mac.h"

/* Kerberos Windows initialization file */
#define KERBEROS_INI    "kerberos.ini"
#define INI_FILES       "Files"
#define INI_KRB_CCACHE  "krb5cc"        /* Location of the ccache */
#define INI_KRB5_CONF   "krb5.ini"      /* Location of krb5.conf file */
#define ANSI_STDIO
#endif

#include "autoconf.h"

#ifndef KRB5_SYSTYPES__
#define KRB5_SYSTYPES__

#ifdef HAVE_SYS_TYPES_H         /* From autoconf.h */
#include <sys/types.h>
#else /* HAVE_SYS_TYPES_H */
typedef unsigned long   u_long;
typedef unsigned int    u_int;
typedef unsigned short  u_short;
typedef unsigned char   u_char;
#endif /* HAVE_SYS_TYPES_H */
#endif /* KRB5_SYSTYPES__ */


#include "k5-platform.h"

#define KRB5_KDB_MAX_LIFE       (60*60*24) /* one day */
#define KRB5_KDB_MAX_RLIFE      (60*60*24*7) /* one week */
#define KRB5_KDB_EXPIRATION     2145830400 /* Thu Jan  1 00:00:00 2038 UTC */

/*
 * Windows requires a different api interface to each function. Here
 * just define it as NULL.
 */
#ifndef KRB5_CALLCONV
#define KRB5_CALLCONV
#define KRB5_CALLCONV_C
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif

/* #define KRB5_OLD_CRYPTO is done in krb5.h */

#endif /* KRB5_CONFIG__ */

/*
 * End "k5-config.h"
 */

/*
 * After loading the configuration definitions, load the Kerberos definitions.
 */
#include <errno.h>
#include "krb5.h"
#include <krb5/plugin.h>
#include "profile.h"

#include "port-sockets.h"
#include "socket-utils.h"

/* Get mutex support; currently used only for the replay cache.  */
#include "k5-thread.h"

/* Get error info support.  */
#include "k5-err.h"

/* Get string buffer support. */
#include "k5-buf.h"

/* Define tracing macros. */
#include "k5-trace.h"

/* Profile variables.  Constants are named KRB5_CONF_STRING, where STRING
 * matches the variable name.  Keep these alphabetized. */
#define KRB5_CONF_ACL_FILE                     "acl_file"
#define KRB5_CONF_ADMIN_SERVER                 "admin_server"
#define KRB5_CONF_ALLOW_WEAK_CRYPTO            "allow_weak_crypto"
#define KRB5_CONF_AP_REQ_CHECKSUM_TYPE         "ap_req_checksum_type"
#define KRB5_CONF_AUTH_TO_LOCAL                "auth_to_local"
#define KRB5_CONF_AUTH_TO_LOCAL_NAMES          "auth_to_local_names"
#define KRB5_CONF_CANONICALIZE                 "canonicalize"
#define KRB5_CONF_CCACHE_TYPE                  "ccache_type"
#define KRB5_CONF_CLOCKSKEW                    "clockskew"
#define KRB5_CONF_DATABASE_NAME                "database_name"
#define KRB5_CONF_DB_MODULE_DIR                "db_module_dir"
#define KRB5_CONF_DEFAULT                      "default"
#define KRB5_CONF_DEFAULT_CCACHE_NAME          "default_ccache_name"
#define KRB5_CONF_DEFAULT_CLIENT_KEYTAB_NAME   "default_client_keytab_name"
#define KRB5_CONF_DEFAULT_DOMAIN               "default_domain"
#define KRB5_CONF_DEFAULT_KEYTAB_NAME          "default_keytab_name"
#define KRB5_CONF_DEFAULT_PRINCIPAL_EXPIRATION "default_principal_expiration"
#define KRB5_CONF_DEFAULT_PRINCIPAL_FLAGS      "default_principal_flags"
#define KRB5_CONF_DEFAULT_REALM                "default_realm"
#define KRB5_CONF_DEFAULT_TGS_ENCTYPES         "default_tgs_enctypes"
#define KRB5_CONF_DEFAULT_TKT_ENCTYPES         "default_tkt_enctypes"
#define KRB5_CONF_DES_CRC_SESSION_SUPPORTED    "des_crc_session_supported"
#define KRB5_CONF_DICT_FILE                    "dict_file"
#define KRB5_CONF_DISABLE                      "disable"
#define KRB5_CONF_DISABLE_LAST_SUCCESS         "disable_last_success"
#define KRB5_CONF_DISABLE_LOCKOUT              "disable_lockout"
#define KRB5_CONF_DNS_CANONICALIZE_HOSTNAME    "dns_canonicalize_hostname"
#define KRB5_CONF_DNS_FALLBACK                 "dns_fallback"
#define KRB5_CONF_DNS_LOOKUP_KDC               "dns_lookup_kdc"
#define KRB5_CONF_DNS_LOOKUP_REALM             "dns_lookup_realm"
#define KRB5_CONF_DOMAIN_REALM                 "domain_realm"
#define KRB5_CONF_ENABLE_ONLY                  "enable_only"
#define KRB5_CONF_EXTRA_ADDRESSES              "extra_addresses"
#define KRB5_CONF_FORWARDABLE                  "forwardable"
#define KRB5_CONF_HOST_BASED_SERVICES          "host_based_services"
#define KRB5_CONF_HTTP_ANCHORS                 "http_anchors"
#define KRB5_CONF_IGNORE_ACCEPTOR_HOSTNAME     "ignore_acceptor_hostname"
#define KRB5_CONF_IPROP_ENABLE                 "iprop_enable"
#define KRB5_CONF_IPROP_LOGFILE                "iprop_logfile"
#define KRB5_CONF_IPROP_MASTER_ULOGSIZE        "iprop_master_ulogsize"
#define KRB5_CONF_IPROP_PORT                   "iprop_port"
#define KRB5_CONF_IPROP_RESYNC_TIMEOUT         "iprop_resync_timeout"
#define KRB5_CONF_IPROP_SLAVE_POLL             "iprop_slave_poll"
#define KRB5_CONF_K5LOGIN_AUTHORITATIVE        "k5login_authoritative"
#define KRB5_CONF_K5LOGIN_DIRECTORY            "k5login_directory"
#define KRB5_CONF_KADMIND_PORT                 "kadmind_port"
#define KRB5_CONF_KCM_MACH_SERVICE             "kcm_mach_service"
#define KRB5_CONF_KCM_SOCKET                   "kcm_socket"
#define KRB5_CONF_KDC                          "kdc"
#define KRB5_CONF_KDCDEFAULTS                  "kdcdefaults"
#define KRB5_CONF_KDC_DEFAULT_OPTIONS          "kdc_default_options"
#define KRB5_CONF_KDC_MAX_DGRAM_REPLY_SIZE     "kdc_max_dgram_reply_size"
#define KRB5_CONF_KDC_PORTS                    "kdc_ports"
#define KRB5_CONF_KDC_REQ_CHECKSUM_TYPE        "kdc_req_checksum_type"
#define KRB5_CONF_KDC_TCP_PORTS                "kdc_tcp_ports"
#define KRB5_CONF_KDC_TIMESYNC                 "kdc_timesync"
#define KRB5_CONF_KEY_STASH_FILE               "key_stash_file"
#define KRB5_CONF_KPASSWD_PORT                 "kpasswd_port"
#define KRB5_CONF_KPASSWD_SERVER               "kpasswd_server"
#define KRB5_CONF_KRB524_SERVER                "krb524_server"
#define KRB5_CONF_LDAP_CONNS_PER_SERVER        "ldap_conns_per_server"
#define KRB5_CONF_LDAP_KADMIND_DN              "ldap_kadmind_dn"
#define KRB5_CONF_LDAP_KADMIND_SASL_AUTHCID    "ldap_kadmind_sasl_authcid"
#define KRB5_CONF_LDAP_KADMIND_SASL_AUTHZID    "ldap_kadmind_sasl_authzid"
#define KRB5_CONF_LDAP_KADMIND_SASL_MECH       "ldap_kadmind_sasl_mech"
#define KRB5_CONF_LDAP_KADMIND_SASL_REALM      "ldap_kadmind_sasl_realm"
#define KRB5_CONF_LDAP_KDC_DN                  "ldap_kdc_dn"
#define KRB5_CONF_LDAP_KDC_SASL_AUTHCID        "ldap_kdc_sasl_authcid"
#define KRB5_CONF_LDAP_KDC_SASL_AUTHZID        "ldap_kdc_sasl_authzid"
#define KRB5_CONF_LDAP_KDC_SASL_MECH           "ldap_kdc_sasl_mech"
#define KRB5_CONF_LDAP_KDC_SASL_REALM          "ldap_kdc_sasl_realm"
#define KRB5_CONF_LDAP_KERBEROS_CONTAINER_DN   "ldap_kerberos_container_dn"
#define KRB5_CONF_LDAP_SERVERS                 "ldap_servers"
#define KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE   "ldap_service_password_file"
#define KRB5_CONF_LIBDEFAULTS                  "libdefaults"
#define KRB5_CONF_LOGGING                      "logging"
#define KRB5_CONF_MASTER_KDC                   "master_kdc"
#define KRB5_CONF_MASTER_KEY_NAME              "master_key_name"
#define KRB5_CONF_MASTER_KEY_TYPE              "master_key_type"
#define KRB5_CONF_MAX_LIFE                     "max_life"
#define KRB5_CONF_MAX_RENEWABLE_LIFE           "max_renewable_life"
#define KRB5_CONF_MODULE                       "module"
#define KRB5_CONF_NOADDRESSES                  "noaddresses"
#define KRB5_CONF_NO_HOST_REFERRAL             "no_host_referral"
#define KRB5_CONF_PERMITTED_ENCTYPES           "permitted_enctypes"
#define KRB5_CONF_PLUGINS                      "plugins"
#define KRB5_CONF_PLUGIN_BASE_DIR              "plugin_base_dir"
#define KRB5_CONF_PREFERRED_PREAUTH_TYPES      "preferred_preauth_types"
#define KRB5_CONF_PROXIABLE                    "proxiable"
#define KRB5_CONF_RDNS                         "rdns"
#define KRB5_CONF_REALMS                       "realms"
#define KRB5_CONF_REALM_TRY_DOMAINS            "realm_try_domains"
#define KRB5_CONF_REJECT_BAD_TRANSIT           "reject_bad_transit"
#define KRB5_CONF_RENEW_LIFETIME               "renew_lifetime"
#define KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT    "restrict_anonymous_to_tgt"
#define KRB5_CONF_SAFE_CHECKSUM_TYPE           "safe_checksum_type"
#define KRB5_CONF_SUPPORTED_ENCTYPES           "supported_enctypes"
#define KRB5_CONF_TICKET_LIFETIME              "ticket_lifetime"
#define KRB5_CONF_UDP_PREFERENCE_LIMIT         "udp_preference_limit"
#define KRB5_CONF_UNLOCKITER                   "unlockiter"
#define KRB5_CONF_V4_INSTANCE_CONVERT          "v4_instance_convert"
#define KRB5_CONF_V4_REALM                     "v4_realm"
#define KRB5_CONF_VERIFY_AP_REQ_NOFAIL         "verify_ap_req_nofail"

/* Cache configuration variables */
#define KRB5_CC_CONF_FAST_AVAIL                "fast_avail"
#define KRB5_CC_CONF_PA_CONFIG_DATA            "pa_config_data"
#define KRB5_CC_CONF_PA_TYPE                   "pa_type"
#define KRB5_CC_CONF_PROXY_IMPERSONATOR        "proxy_impersonator"
#define KRB5_CC_CONF_REFRESH_TIME              "refresh_time"

/* Error codes used in KRB_ERROR protocol messages.
   Return values of library routines are based on a different error table
   (which allows non-ambiguous error codes between subsystems) */

/* KDC errors */
#define KDC_ERR_NONE                    0 /* No error */
#define KDC_ERR_NAME_EXP                1 /* Client's entry in DB expired */
#define KDC_ERR_SERVICE_EXP             2 /* Server's entry in DB expired */
#define KDC_ERR_BAD_PVNO                3 /* Requested pvno not supported */
#define KDC_ERR_C_OLD_MAST_KVNO         4 /* C's key encrypted in old master */
#define KDC_ERR_S_OLD_MAST_KVNO         5 /* S's key encrypted in old master */
#define KDC_ERR_C_PRINCIPAL_UNKNOWN     6 /* Client not found in Kerberos DB */
#define KDC_ERR_S_PRINCIPAL_UNKNOWN     7 /* Server not found in Kerberos DB */
#define KDC_ERR_PRINCIPAL_NOT_UNIQUE    8 /* Multiple entries in Kerberos DB */
#define KDC_ERR_NULL_KEY                9 /* The C or S has a null key */
#define KDC_ERR_CANNOT_POSTDATE         10 /* Tkt ineligible for postdating */
#define KDC_ERR_NEVER_VALID             11 /* Requested starttime > endtime */
#define KDC_ERR_POLICY                  12 /* KDC policy rejects request */
#define KDC_ERR_BADOPTION               13 /* KDC can't do requested opt. */
#define KDC_ERR_ENCTYPE_NOSUPP          14 /* No support for encryption type */
#define KDC_ERR_SUMTYPE_NOSUPP          15 /* No support for checksum type */
#define KDC_ERR_PADATA_TYPE_NOSUPP      16 /* No support for padata type */
#define KDC_ERR_TRTYPE_NOSUPP           17 /* No support for transited type */
#define KDC_ERR_CLIENT_REVOKED          18 /* C's creds have been revoked */
#define KDC_ERR_SERVICE_REVOKED         19 /* S's creds have been revoked */
#define KDC_ERR_TGT_REVOKED             20 /* TGT has been revoked */
#define KDC_ERR_CLIENT_NOTYET           21 /* C not yet valid */
#define KDC_ERR_SERVICE_NOTYET          22 /* S not yet valid */
#define KDC_ERR_KEY_EXP                 23 /* Password has expired */
#define KDC_ERR_PREAUTH_FAILED          24 /* Preauthentication failed */
#define KDC_ERR_PREAUTH_REQUIRED        25 /* Additional preauthentication */
                                           /* required */
#define KDC_ERR_SERVER_NOMATCH          26 /* Requested server and */
                                           /* ticket don't match*/
#define KDC_ERR_MUST_USE_USER2USER      27 /* Server principal valid for */
                                           /*   user2user only */
#define KDC_ERR_PATH_NOT_ACCEPTED       28 /* KDC policy rejected transited */
                                           /*   path */
#define KDC_ERR_SVC_UNAVAILABLE         29 /* A service is not
                                            * available that is
                                            * required to process the
                                            * request */
/* Application errors */
#define KRB_AP_ERR_BAD_INTEGRITY 31     /* Decrypt integrity check failed */
#define KRB_AP_ERR_TKT_EXPIRED  32      /* Ticket expired */
#define KRB_AP_ERR_TKT_NYV      33      /* Ticket not yet valid */
#define KRB_AP_ERR_REPEAT       34      /* Request is a replay */
#define KRB_AP_ERR_NOT_US       35      /* The ticket isn't for us */
#define KRB_AP_ERR_BADMATCH     36      /* Ticket/authenticator don't match */
#define KRB_AP_ERR_SKEW         37      /* Clock skew too great */
#define KRB_AP_ERR_BADADDR      38      /* Incorrect net address */
#define KRB_AP_ERR_BADVERSION   39      /* Protocol version mismatch */
#define KRB_AP_ERR_MSG_TYPE     40      /* Invalid message type */
#define KRB_AP_ERR_MODIFIED     41      /* Message stream modified */
#define KRB_AP_ERR_BADORDER     42      /* Message out of order */
#define KRB_AP_ERR_BADKEYVER    44      /* Key version is not available */
#define KRB_AP_ERR_NOKEY        45      /* Service key not available */
#define KRB_AP_ERR_MUT_FAIL     46      /* Mutual authentication failed */
#define KRB_AP_ERR_BADDIRECTION 47      /* Incorrect message direction */
#define KRB_AP_ERR_METHOD       48      /* Alternative authentication */
                                        /* method required */
#define KRB_AP_ERR_BADSEQ       49      /* Incorrect sequence numnber */
                                        /* in message */
#define KRB_AP_ERR_INAPP_CKSUM  50      /* Inappropriate type of */
                                        /* checksum in message */
#define KRB_AP_PATH_NOT_ACCEPTED 51     /* Policy rejects transited path */
#define KRB_ERR_RESPONSE_TOO_BIG 52     /* Response too big for UDP, */
                                        /*   retry with TCP */

/* other errors */
#define KRB_ERR_GENERIC         60      /* Generic error (description */
                                        /* in e-text) */
#define KRB_ERR_FIELD_TOOLONG   61      /* Field is too long for impl. */

/* PKINIT server-reported errors */
#define KDC_ERR_CLIENT_NOT_TRUSTED              62 /* client cert not trusted */
#define KDC_ERR_KDC_NOT_TRUSTED                 63
#define KDC_ERR_INVALID_SIG                     64 /* client signature verify failed */
#define KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED  65 /* invalid Diffie-Hellman parameters */
#define KDC_ERR_CERTIFICATE_MISMATCH            66
#define KRB_AP_ERR_NO_TGT                       67
#define KDC_ERR_WRONG_REALM                     68
#define KRB_AP_ERR_USER_TO_USER_REQUIRED        69
#define KDC_ERR_CANT_VERIFY_CERTIFICATE         70 /* client cert not verifiable to */
                                                   /* trusted root cert */
#define KDC_ERR_INVALID_CERTIFICATE             71 /* client cert had invalid signature */
#define KDC_ERR_REVOKED_CERTIFICATE             72 /* client cert was revoked */
#define KDC_ERR_REVOCATION_STATUS_UNKNOWN       73 /* client cert revoked, reason unknown */
#define KDC_ERR_REVOCATION_STATUS_UNAVAILABLE   74
#define KDC_ERR_CLIENT_NAME_MISMATCH            75 /* mismatch between client cert and */
                                                   /* principal name */
#define KDC_ERR_INCONSISTENT_KEY_PURPOSE        77 /* bad extended key use */
#define KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED     78 /* bad digest algorithm in client cert */
#define KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED    79 /* missing paChecksum in PA-PK-AS-REQ */
#define KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED 80 /* bad digest algorithm in SignedData */
#define KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED 81
#define KRB_AP_ERR_IAKERB_KDC_NOT_FOUND         85 /* The IAKERB proxy could
                                                      not find a KDC */
#define KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE       86 /* The KDC did not respond
                                                      to the IAKERB proxy */
#define KDC_ERR_MORE_PREAUTH_DATA_REQUIRED      91 /* RFC 6113 */
#define KRB_ERR_MAX 127 /* err table base max offset for protocol err codes */

/*
 * A null-terminated array of this structure is returned by the KDC as
 * the data part of the ETYPE_INFO preauth type.  It informs the
 * client which encryption types are supported.
 * The  same data structure is used by both etype-info and etype-info2
 * but s2kparams must be null when encoding etype-info.
 */
typedef struct _krb5_etype_info_entry {
    krb5_magic      magic;
    krb5_enctype    etype;
    unsigned int    length;
    krb5_octet      *salt;
    krb5_data s2kparams;
} krb5_etype_info_entry;

/*
 *  This is essentially -1 without sign extension which can screw up
 *  comparisons on 64 bit machines. If the length is this value, then
 *  the salt data is not present. This is to distinguish between not
 *  being set and being of 0 length.
 */
#define KRB5_ETYPE_NO_SALT VALID_UINT_BITS

typedef krb5_etype_info_entry ** krb5_etype_info;

/* RFC 4537 */
typedef struct _krb5_etype_list {
    int             length;
    krb5_enctype    *etypes;
} krb5_etype_list;

/* sam_type values -- informational only */
#define PA_SAM_TYPE_ENIGMA     1   /*  Enigma Logic */
#define PA_SAM_TYPE_DIGI_PATH  2   /*  Digital Pathways */
#define PA_SAM_TYPE_SKEY_K0    3   /*  S/key where  KDC has key 0 */
#define PA_SAM_TYPE_SKEY       4   /*  Traditional S/Key */
#define PA_SAM_TYPE_SECURID    5   /*  Security Dynamics */
#define PA_SAM_TYPE_CRYPTOCARD 6   /*  CRYPTOCard */
#if 1 /* XXX need to figure out who has which numbers assigned */
#define PA_SAM_TYPE_ACTIVCARD_DEC  6   /*  ActivCard decimal mode */
#define PA_SAM_TYPE_ACTIVCARD_HEX  7   /*  ActivCard hex mode */
#define PA_SAM_TYPE_DIGI_PATH_HEX  8   /*  Digital Pathways hex mode */
#endif
#define PA_SAM_TYPE_EXP_BASE    128 /* experimental */
#define PA_SAM_TYPE_GRAIL               (PA_SAM_TYPE_EXP_BASE+0) /* testing */
#define PA_SAM_TYPE_SECURID_PREDICT     (PA_SAM_TYPE_EXP_BASE+1) /* special */

typedef struct _krb5_sam_challenge_2 {
    krb5_data       sam_challenge_2_body;
    krb5_checksum   **sam_cksum;            /* Array of checksums */
} krb5_sam_challenge_2;

typedef struct _krb5_sam_challenge_2_body {
    krb5_magic      magic;
    krb5_int32      sam_type; /* information */
    krb5_flags      sam_flags; /* KRB5_SAM_* values */
    krb5_data       sam_type_name;
    krb5_data       sam_track_id;
    krb5_data       sam_challenge_label;
    krb5_data       sam_challenge;
    krb5_data       sam_response_prompt;
    krb5_data       sam_pk_for_sad;
    krb5_int32      sam_nonce;
    krb5_enctype    sam_etype;
} krb5_sam_challenge_2_body;

typedef struct _krb5_sam_response_2 {
    krb5_magic      magic;
    krb5_int32      sam_type; /* informational */
    krb5_flags      sam_flags; /* KRB5_SAM_* values */
    krb5_data       sam_track_id; /* copied */
    krb5_enc_data   sam_enc_nonce_or_sad; /* krb5_enc_sam_response_enc */
    krb5_int32      sam_nonce;
} krb5_sam_response_2;

typedef struct _krb5_enc_sam_response_enc_2 {
    krb5_magic      magic;
    krb5_int32      sam_nonce;
    krb5_data       sam_sad;
} krb5_enc_sam_response_enc_2;

/*
 * Keep the pkinit definitions in a separate file so that the plugin
 * only has to include k5-int-pkinit.h rather than k5-int.h
 */

#include "k5-int-pkinit.h"

#define KRB5_OTP_FLAG_NEXTOTP        0x40000000
#define KRB5_OTP_FLAG_COMBINE        0x20000000
#define KRB5_OTP_FLAG_COLLECT_PIN    0x10000000
#define KRB5_OTP_FLAG_NO_COLLECT_PIN 0x08000000
#define KRB5_OTP_FLAG_ENCRYPT_NONCE  0x04000000
#define KRB5_OTP_FLAG_SEPARATE_PIN   0x02000000
#define KRB5_OTP_FLAG_CHECK_DIGIT    0x01000000

#define KRB5_OTP_FORMAT_DECIMAL      0x00000000
#define KRB5_OTP_FORMAT_HEXADECIMAL  0x00000001
#define KRB5_OTP_FORMAT_ALPHANUMERIC 0x00000002
#define KRB5_OTP_FORMAT_BINARY       0x00000003
#define KRB5_OTP_FORMAT_BASE64       0x00000004

typedef struct _krb5_otp_tokeninfo {
    krb5_flags flags;
    krb5_data vendor;
    krb5_data challenge;
    krb5_int32 length;          /* -1 for unspecified */
    krb5_int32 format;          /* -1 for unspecified */
    krb5_data token_id;
    krb5_data alg_id;
    krb5_algorithm_identifier **supported_hash_alg;
    krb5_int32 iteration_count; /* -1 for unspecified */
} krb5_otp_tokeninfo;

typedef struct _krb5_pa_otp_challenge {
    krb5_data nonce;
    krb5_data service;
    krb5_otp_tokeninfo **tokeninfo;
    krb5_data salt;
    krb5_data s2kparams;
} krb5_pa_otp_challenge;

typedef struct _krb5_pa_otp_req {
    krb5_int32 flags;
    krb5_data nonce;
    krb5_enc_data enc_data;
    krb5_algorithm_identifier *hash_alg;
    krb5_int32 iteration_count; /* -1 for unspecified */
    krb5_data otp_value;
    krb5_data pin;
    krb5_data challenge;
    krb5_timestamp time;
    krb5_data counter;
    krb5_int32 format;          /* -1 for unspecified */
    krb5_data token_id;
    krb5_data alg_id;
    krb5_data vendor;
} krb5_pa_otp_req;

typedef struct _krb5_kkdcp_message {
    krb5_data kerb_message;
    krb5_data target_domain;
    krb5_int32 dclocator_hint;
} krb5_kkdcp_message;

#include <stdlib.h>
#include <string.h>

#ifndef HAVE_STRDUP
extern char *strdup (const char *);
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#ifdef TIME_WITH_SYS_TIME
#include <time.h>
#endif
#else
#include <time.h>
#endif

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>                   /* struct stat, stat() */
#endif

#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>                  /* MAXPATHLEN */
#endif

#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>                   /* prototypes for file-related
                                           syscalls; flags for open &
                                           friends */
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#include <stdio.h>

#include "k5-gmt_mktime.h"

/* libos.spec */
krb5_error_code krb5_lock_file(krb5_context, int, int);
krb5_error_code krb5_unlock_file(krb5_context, int);
krb5_error_code krb5_sendto_kdc(krb5_context, const krb5_data *,
                                const krb5_data *, krb5_data *, int *, int);

krb5_error_code krb5int_init_context_kdc(krb5_context *);

struct derived_key {
    krb5_data constant;
    krb5_key dkey;
    struct derived_key *next;
};

/* Internal structure of an opaque key identifier */
struct krb5_key_st {
    krb5_keyblock keyblock;
    int refcount;
    struct derived_key *derived;
    /*
     * Cache of data private to the cipher implementation, which we
     * don't want to have to recompute for every operation.  This may
     * include key schedules, iteration counts, etc.
     *
     * The cipher implementation is responsible for setting this up
     * whenever needed, and the enc_provider key_cleanup method must
     * then be provided to dispose of it.
     */
    void *cache;
};

krb5_error_code
krb5int_arcfour_gsscrypt(const krb5_keyblock *keyblock, krb5_keyusage usage,
                         const krb5_data *kd_data, krb5_crypto_iov *data,
                         size_t num_data);

/*
 * Attempt to zero memory in a way that compilers won't optimize out.
 *
 * This mechanism should work even for heap storage about to be freed,
 * or automatic storage right before we return from a function.
 *
 * Then, even if we leak uninitialized memory someplace, or UNIX
 * "core" files get created with world-read access, some of the most
 * sensitive data in the process memory will already be safely wiped.
 *
 * We're not going so far -- yet -- as to try to protect key data that
 * may have been written into swap space....
 */
#ifdef _WIN32
# define zap(ptr, len) SecureZeroMemory(ptr, len)
#elif defined(__GNUC__)
static inline void zap(void *ptr, size_t len)
{
    memset(ptr, 0, len);
    /*
     * Some versions of gcc have gotten clever enough to eliminate a
     * memset call right before the block in question is released.
     * This (empty) asm requires it to assume that we're doing
     * something interesting with the stored (zero) value, so the
     * memset can't be eliminated.
     *
     * An optimizer that looks at assembly or object code may not be
     * fooled, and may still cause the memset to go away.  Address
     * that problem if and when we encounter it.
     *
     * This also may not be enough if free() does something
     * interesting like purge memory locations from a write-back cache
     * that hasn't written back the zero bytes yet.  A memory barrier
     * instruction would help in that case.
     */
    asm volatile ("" : : "g" (ptr), "g" (len));
}
#else
/* Use a function from libkrb5support to defeat inlining. */
# define zap(ptr, len) krb5int_zap(ptr, len)
#endif

/* Convenience function: zap and free ptr if it is non-NULL. */
static inline void
zapfree(void *ptr, size_t len)
{
    if (ptr != NULL) {
        zap(ptr, len);
        free(ptr);
    }
}

/* Convenience function: zap and free zero-terminated str if it is non-NULL. */
static inline void
zapfreestr(void *str)
{
    if (str != NULL) {
        zap(str, strlen((char *)str));
        free(str);
    }
}

/*
 * Combine two keys (normally used by the hardware preauth mechanism)
 */
krb5_error_code
krb5int_c_combine_keys(krb5_context context, krb5_keyblock *key1,
                       krb5_keyblock *key2, krb5_keyblock *outkey);

void krb5int_c_free_keyblock(krb5_context, krb5_keyblock *key);
void krb5int_c_free_keyblock_contents(krb5_context, krb5_keyblock *);
krb5_error_code krb5int_c_init_keyblock(krb5_context, krb5_enctype enctype,
                                        size_t length, krb5_keyblock **out);
krb5_error_code krb5int_c_copy_keyblock(krb5_context context,
                                        const krb5_keyblock *from,
                                        krb5_keyblock **to);
krb5_error_code krb5int_c_copy_keyblock_contents(krb5_context context,
                                                 const krb5_keyblock *from,
                                                 krb5_keyblock *to);

krb5_error_code krb5_crypto_us_timeofday(krb5_int32 *, krb5_int32 *);

/*
 * End "los-proto.h"
 */

typedef struct _krb5_os_context {
    krb5_magic              magic;
    krb5_int32              time_offset;
    krb5_int32              usec_offset;
    krb5_int32              os_flags;
    char *                  default_ccname;
} *krb5_os_context;

/*
 * Flags for the os_flags field
 *
 * KRB5_OS_TOFFSET_VALID means that the time offset fields are valid.
 * The intention is that this facility to correct the system clocks so
 * that they reflect the "real" time, for systems where for some
 * reason we can't set the system clock.  Instead we calculate the
 * offset between the system time and real time, and store the offset
 * in the os context so that we can correct the system clock as necessary.
 *
 * KRB5_OS_TOFFSET_TIME means that the time offset fields should be
 * returned as the time by the krb5 time routines.  This should only
 * be used for testing purposes (obviously!)
 */
#define KRB5_OS_TOFFSET_VALID   1
#define KRB5_OS_TOFFSET_TIME    2

/* lock mode flags */
#define KRB5_LOCKMODE_SHARED    0x0001
#define KRB5_LOCKMODE_EXCLUSIVE 0x0002
#define KRB5_LOCKMODE_DONTBLOCK 0x0004
#define KRB5_LOCKMODE_UNLOCK    0x0008

/*
 * Begin "preauth.h"
 *
 * (Originally written by Glen Machin at Sandia Labs.)
 */
/*
 * Sandia National Laboratories also makes no representations about the
 * suitability of the modifications, or additions to this software for
 * any purpose.  It is provided "as is" without express or implied warranty.
 */
#ifndef KRB5_PREAUTH__
#define KRB5_PREAUTH__

typedef struct _krb5_pa_enc_ts {
    krb5_timestamp      patimestamp;
    krb5_int32          pausec;
} krb5_pa_enc_ts;

typedef struct _krb5_pa_for_user {
    krb5_principal      user;
    krb5_checksum       cksum;
    krb5_data           auth_package;
} krb5_pa_for_user;

typedef struct _krb5_s4u_userid {
    krb5_int32          nonce;
    krb5_principal      user;
    krb5_data           subject_cert;
    krb5_flags          options;
} krb5_s4u_userid;

#define KRB5_S4U_OPTS_CHECK_LOGON_HOURS         0x40000000 /* check logon hour restrictions */
#define KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE       0x20000000 /* sign with usage 27 instead of 26 */

typedef struct _krb5_pa_s4u_x509_user {
    krb5_s4u_userid     user_id;
    krb5_checksum       cksum;
} krb5_pa_s4u_x509_user;

enum {
    KRB5_FAST_ARMOR_AP_REQUEST = 0x1
};

typedef struct _krb5_fast_armor {
    krb5_int32 armor_type;
    krb5_data armor_value;
} krb5_fast_armor;
typedef struct _krb5_fast_armored_req {
    krb5_magic magic;
    krb5_fast_armor *armor;
    krb5_checksum req_checksum;
    krb5_enc_data enc_part;
} krb5_fast_armored_req;

typedef struct _krb5_fast_req {
    krb5_magic magic;
    krb5_flags fast_options;
    /* padata from req_body is used*/
    krb5_kdc_req *req_body;
} krb5_fast_req;

/* Bits 0-15 are critical in FAST options (RFC 6113 section 7.3). */
#define UNSUPPORTED_CRITICAL_FAST_OPTIONS   0xbfff0000
#define KRB5_FAST_OPTION_HIDE_CLIENT_NAMES  0x40000000

typedef struct _krb5_fast_finished {
    krb5_timestamp timestamp;
    krb5_int32 usec;
    krb5_principal client;
    krb5_checksum ticket_checksum;
} krb5_fast_finished;

typedef struct _krb5_fast_response {
    krb5_magic magic;
    krb5_pa_data **padata;
    krb5_keyblock *strengthen_key;
    krb5_fast_finished *finished;
    krb5_int32 nonce;
} krb5_fast_response;

typedef struct _krb5_ad_kdcissued {
    krb5_checksum ad_checksum;
    krb5_principal i_principal;
    krb5_authdata **elements;
} krb5_ad_kdcissued;

typedef struct _krb5_ad_signedpath_data {
    krb5_principal client;
    krb5_timestamp authtime;
    krb5_principal *delegated;
    krb5_pa_data **method_data;
    krb5_authdata **authorization_data;
} krb5_ad_signedpath_data;

typedef struct _krb5_ad_signedpath {
    krb5_enctype enctype;
    krb5_checksum checksum;
    krb5_principal *delegated;
    krb5_pa_data **method_data;
} krb5_ad_signedpath;

typedef struct _krb5_iakerb_header {
    krb5_data target_realm;
    krb5_data *cookie;
} krb5_iakerb_header;

typedef struct _krb5_iakerb_finished {
    krb5_checksum checksum;
} krb5_iakerb_finished;

krb5_pa_data *
krb5int_find_pa_data(krb5_context, krb5_pa_data *const *, krb5_preauthtype);
/* Does not return a copy; original padata sequence responsible for freeing*/

void krb5_free_etype_info(krb5_context, krb5_etype_info);

#endif /* KRB5_PREAUTH__ */
/*
 * End "preauth.h"
 */

krb5_error_code
krb5int_copy_data_contents(krb5_context, const krb5_data *, krb5_data *);

krb5_error_code
krb5int_copy_data_contents_add0(krb5_context, const krb5_data *, krb5_data *);

void KRB5_CALLCONV
krb5_free_sam_challenge_2(krb5_context, krb5_sam_challenge_2 *);

void KRB5_CALLCONV
krb5_free_sam_challenge_2_body(krb5_context, krb5_sam_challenge_2_body *);

void KRB5_CALLCONV
krb5_free_sam_response_2(krb5_context, krb5_sam_response_2 *);

void KRB5_CALLCONV
krb5_free_enc_sam_response_enc_2(krb5_context, krb5_enc_sam_response_enc_2 *);

void KRB5_CALLCONV
krb5_free_sam_challenge_2_contents(krb5_context, krb5_sam_challenge_2 *);

void KRB5_CALLCONV
krb5_free_sam_challenge_2_body_contents(krb5_context,
                                        krb5_sam_challenge_2_body *);

void KRB5_CALLCONV
krb5_free_sam_response_2_contents(krb5_context, krb5_sam_response_2 *);

void KRB5_CALLCONV
krb5_free_enc_sam_response_enc_2_contents(krb5_context,
                                          krb5_enc_sam_response_enc_2 * );

void KRB5_CALLCONV
krb5_free_pa_enc_ts(krb5_context, krb5_pa_enc_ts *);

void KRB5_CALLCONV
krb5_free_pa_for_user(krb5_context, krb5_pa_for_user *);

void KRB5_CALLCONV
krb5_free_s4u_userid_contents(krb5_context, krb5_s4u_userid *);

void KRB5_CALLCONV
krb5_free_pa_s4u_x509_user(krb5_context, krb5_pa_s4u_x509_user *);

void KRB5_CALLCONV
krb5_free_pa_pac_req(krb5_context, krb5_pa_pac_req * );

void KRB5_CALLCONV krb5_free_fast_armor(krb5_context, krb5_fast_armor *);
void KRB5_CALLCONV krb5_free_fast_armored_req(krb5_context,
                                              krb5_fast_armored_req *);
void KRB5_CALLCONV krb5_free_fast_req(krb5_context, krb5_fast_req *);
void KRB5_CALLCONV krb5_free_fast_finished(krb5_context, krb5_fast_finished *);
void KRB5_CALLCONV krb5_free_fast_response(krb5_context, krb5_fast_response *);
void KRB5_CALLCONV krb5_free_ad_kdcissued(krb5_context, krb5_ad_kdcissued *);
void KRB5_CALLCONV krb5_free_ad_signedpath(krb5_context, krb5_ad_signedpath *);
void KRB5_CALLCONV krb5_free_iakerb_header(krb5_context, krb5_iakerb_header *);
void KRB5_CALLCONV krb5_free_iakerb_finished(krb5_context,
                                             krb5_iakerb_finished *);
void k5_free_algorithm_identifier(krb5_context context,
                                  krb5_algorithm_identifier *val);
void k5_free_otp_tokeninfo(krb5_context context, krb5_otp_tokeninfo *val);
void k5_free_pa_otp_challenge(krb5_context context,
                              krb5_pa_otp_challenge *val);
void k5_free_pa_otp_req(krb5_context context, krb5_pa_otp_req *val);
void k5_free_kkdcp_message(krb5_context context, krb5_kkdcp_message *val);

/* #include "krb5/wordsize.h" -- comes in through base-defs.h. */
#include "com_err.h"
#include "k5-plugin.h"

#include <krb5/authdata_plugin.h>

struct _krb5_authdata_context {
    krb5_magic magic;
    int n_modules;
    struct _krb5_authdata_context_module {
        krb5_authdatatype ad_type;
        void *plugin_context;
        authdata_client_plugin_fini_proc client_fini;
        krb5_flags flags;
        krb5plugin_authdata_client_ftable_v0 *ftable;
        authdata_client_request_init_proc client_req_init;
        authdata_client_request_fini_proc client_req_fini;
        const char *name;
        void *request_context;
        void **request_context_pp;
    } *modules;
    struct plugin_dir_handle plugins;
};

typedef struct _krb5_authdata_context *krb5_authdata_context;

void KRB5_CALLCONV
krb5int_free_data_list(krb5_context context, krb5_data *data);

krb5_error_code KRB5_CALLCONV
krb5_authdata_context_init(krb5_context kcontext,
                           krb5_authdata_context *pcontext);

void KRB5_CALLCONV
krb5_authdata_context_free(krb5_context kcontext,
                           krb5_authdata_context context);

krb5_error_code KRB5_CALLCONV
krb5_authdata_export_authdata(krb5_context kcontext,
                              krb5_authdata_context context, krb5_flags usage,
                              krb5_authdata ***pauthdata);

krb5_error_code KRB5_CALLCONV
krb5_authdata_get_attribute_types(krb5_context kcontext,
                                  krb5_authdata_context context,
                                  krb5_data **attrs);

krb5_error_code KRB5_CALLCONV
krb5_authdata_get_attribute(krb5_context kcontext,
                            krb5_authdata_context context,
                            const krb5_data *attribute,
                            krb5_boolean *authenticated,
                            krb5_boolean *complete, krb5_data *value,
                            krb5_data *display_value, int *more);

krb5_error_code KRB5_CALLCONV
krb5_authdata_set_attribute(krb5_context kcontext,
                            krb5_authdata_context context,
                            krb5_boolean complete, const krb5_data *attribute,
                            const krb5_data *value);

krb5_error_code KRB5_CALLCONV
krb5_authdata_delete_attribute(krb5_context kcontext,
                               krb5_authdata_context context,
                               const krb5_data *attribute);

krb5_error_code KRB5_CALLCONV
krb5_authdata_import_attributes(krb5_context kcontext,
                                krb5_authdata_context context,
                                krb5_flags usage, const krb5_data *attributes);

krb5_error_code KRB5_CALLCONV
krb5_authdata_export_attributes(krb5_context kcontext,
                                krb5_authdata_context context,
                                krb5_flags usage, krb5_data **pattributes);

krb5_error_code KRB5_CALLCONV
krb5_authdata_export_internal(krb5_context kcontext,
                              krb5_authdata_context context,
                              krb5_boolean restrict_authenticated,
                              const char *module, void **ptr);

krb5_error_code KRB5_CALLCONV
krb5_authdata_context_copy(krb5_context kcontext, krb5_authdata_context src,
                           krb5_authdata_context *dst);

krb5_error_code KRB5_CALLCONV
krb5_authdata_free_internal(krb5_context kcontext,
                            krb5_authdata_context context, const char *module,
                            void *ptr);

/*** Plugin framework ***/

/*
 * This framework can be used to create pluggable interfaces.  Not all existing
 * pluggable interface use this framework, but new ones should.  A new
 * pluggable interface entails:
 *
 * - An interface ID definition in the list of #defines below.
 *
 * - A name in the interface_names array in lib/krb5/krb/plugins.c.
 *
 * - An installed public header file in include/krb5.  The public header should
 *   include <krb5/plugin.h> and should declare a vtable structure for each
 *   supported major version of the interface.
 *
 * - A consumer API implementation, located within the code unit which makes
 *   use of the pluggable interface.  The consumer API should consist of:
 *
 *   . An interface-specific handle type which contains a vtable structure for
 *     the module (or a union of several such structures, if there are multiple
 *     supported major versions) and, optionally, resource data bound to the
 *     handle.
 *
 *   . An interface-specific loader function which creates a handle or list of
 *     handles.  A list of handles would be created if the interface is a
 *     one-to-many interface where the consumer wants to consult all available
 *     modules; a single handle would be created for an interface where the
 *     consumer wants to consult a specific module.  The loader function should
 *     use k5_plugin_load or k5_plugin_load_all to produce one or a list of
 *     vtable initializer functions, and should use those functions to fill in
 *     the vtable structure for the module (if necessary, trying each supported
 *     major version starting from the most recent).  The loader function can
 *     also bind resource data into the handle based on caller arguments, if
 *     appropriate.
 *
 *   . For each plugin method, a wrapper function which accepts a krb5_context,
 *     a plugin handle, and the method arguments.  Wrapper functions should
 *     invoke the method function contained in the handle's vtable.
 *
 * - Possibly, built-in implementations of the interface, also located within
 *   the code unit which makes use of the interface.  Built-in implementations
 *   must be registered with k5_plugin_register before the first call to
 *   k5_plugin_load or k5_plugin_load_all.
 *
 * A pluggable interface should have one or more currently supported major
 * versions, starting at 1.  Each major version should have a current minor
 * version, also starting at 1.  If new methods are added to a vtable, the
 * minor version should be incremented and the vtable stucture should document
 * where each minor vtable version ends.  If method signatures for a vtable are
 * changed, the major version should be incremented.
 *
 * Plugin module implementations (either built-in or dynamically loaded) should
 * define a function named <interfacename>_<modulename>_initvt, matching the
 * signature of krb5_plugin_initvt_fn as declared in include/krb5/plugin.h.
 * The initvt function should check the given maj_ver argument against its own
 * supported major versions, cast the vtable pointer to the appropriate
 * interface-specific vtable type, and fill in the vtable methods, stopping as
 * appropriate for the given min_ver.  Memory for the vtable structure is
 * allocated by the caller, not by the module.
 *
 * Dynamic plugin modules are registered with the framework through the
 * [plugins] section of the profile, as described in the admin documentation
 * and krb5.conf man page.
 */

struct plugin_mapping;

/* Holds krb5_context information about each pluggable interface. */
struct plugin_interface {
    struct plugin_mapping **modules;
    krb5_boolean configured;
};

/* A list of plugin interface IDs.  Make sure to increment
 * PLUGIN_NUM_INTERFACES when a new interface is added, and add an entry to the
 * interface_names table in lib/krb5/krb/plugin.c. */
#define PLUGIN_INTERFACE_PWQUAL      0
#define PLUGIN_INTERFACE_KADM5_HOOK  1
#define PLUGIN_INTERFACE_CLPREAUTH   2
#define PLUGIN_INTERFACE_KDCPREAUTH  3
#define PLUGIN_INTERFACE_CCSELECT    4
#define PLUGIN_INTERFACE_LOCALAUTH   5
#define PLUGIN_INTERFACE_HOSTREALM   6
#define PLUGIN_INTERFACE_AUDIT       7
#define PLUGIN_INTERFACE_TLS         8
#define PLUGIN_NUM_INTERFACES        9

/* Retrieve the plugin module of type interface_id and name modname,
 * storing the result into module. */
krb5_error_code
k5_plugin_load(krb5_context context, int interface_id, const char *modname,
               krb5_plugin_initvt_fn *module);

/* Retrieve all plugin modules of type interface_id, storing the result
 * into modules.  Free the result with k5_plugin_free_handles. */
krb5_error_code
k5_plugin_load_all(krb5_context context, int interface_id,
                   krb5_plugin_initvt_fn **modules);

/* Release a module list allocated by k5_plugin_load_all. */
void
k5_plugin_free_modules(krb5_context context, krb5_plugin_initvt_fn *modules);

/* Register a plugin module of type interface_id and name modname. */
krb5_error_code
k5_plugin_register(krb5_context context, int interface_id, const char *modname,
                   krb5_plugin_initvt_fn module);

/*
 * Register a plugin module which is part of the krb5 tree but is built as a
 * dynamic plugin.  Look for the module in modsubdir relative to the
 * context->base_plugin_dir.
 */
krb5_error_code
k5_plugin_register_dyn(krb5_context context, int interface_id,
                       const char *modname, const char *modsubdir);

/* Destroy the module state within context; used by krb5_free_context. */
void
k5_plugin_free_context(krb5_context context);

struct _kdb5_dal_handle;        /* private, in kdb5.h */
typedef struct _kdb5_dal_handle kdb5_dal_handle;
struct _kdb_log_context;
typedef struct krb5_preauth_context_st krb5_preauth_context;
struct ccselect_module_handle;
struct localauth_module_handle;
struct hostrealm_module_handle;
struct k5_tls_vtable_st;
struct _krb5_context {
    krb5_magic      magic;
    krb5_enctype    *in_tkt_etypes;
    krb5_enctype    *tgs_etypes;
    struct _krb5_os_context os_context;
    char            *default_realm;
    profile_t       profile;
    kdb5_dal_handle *dal_handle;
    int             ser_ctx_count;
    void            *ser_ctx;
    /* allowable clock skew */
    krb5_deltat     clockskew;
    krb5_cksumtype  kdc_req_sumtype;
    krb5_cksumtype  default_ap_req_sumtype;
    krb5_cksumtype  default_safe_sumtype;
    krb5_flags      kdc_default_options;
    krb5_flags      library_options;
    krb5_boolean    profile_secure;
    int             fcc_default_format;
    krb5_prompt_type *prompt_types;
    /* Message size above which we'll try TCP first in send-to-kdc
       type code.  Aside from the 2**16 size limit, we put no
       absolute limit on the UDP packet size.  */
    int             udp_pref_limit;

    /* Use the config-file ktypes instead of app-specified?  */
    krb5_boolean    use_conf_ktypes;

    /* locate_kdc module stuff */
    struct plugin_dir_handle libkrb5_plugins;

    /* preauth module stuff */
    krb5_preauth_context *preauth_context;

    /* cache module stuff */
    struct ccselect_module_handle **ccselect_handles;

    /* localauth module stuff */
    struct localauth_module_handle **localauth_handles;

    /* hostrealm module stuff */
    struct hostrealm_module_handle **hostrealm_handles;

    /* TLS module vtable (if loaded) */
    struct k5_tls_vtable_st *tls;

    /* error detail info */
    struct errinfo err;

    /* For Sun iprop code; does this really have to be here?  */
    struct _kdb_log_context *kdblog_context;

    krb5_boolean allow_weak_crypto;
    krb5_boolean ignore_acceptor_hostname;
    krb5_boolean dns_canonicalize_hostname;

    krb5_trace_callback trace_callback;
    void *trace_callback_data;

    struct plugin_interface plugins[PLUGIN_NUM_INTERFACES];
    char *plugin_base_dir;
};

/* could be used in a table to find an etype and initialize a block */


#define KRB5_LIBOPT_SYNC_KDCTIME        0x0001

/* internal message representations */

typedef struct _krb5_safe {
    krb5_magic magic;
    krb5_data user_data;                /* user data */
    krb5_timestamp timestamp;           /* client time, optional */
    krb5_int32 usec;                    /* microsecond portion of time,
                                           optional */
    krb5_ui_4 seq_number;               /* sequence #, optional */
    krb5_address *s_address;    /* sender address */
    krb5_address *r_address;    /* recipient address, optional */
    krb5_checksum *checksum;    /* data integrity checksum */
} krb5_safe;

typedef struct _krb5_priv {
    krb5_magic magic;
    krb5_enc_data enc_part;             /* encrypted part */
} krb5_priv;

typedef struct _krb5_priv_enc_part {
    krb5_magic magic;
    krb5_data user_data;                /* user data */
    krb5_timestamp timestamp;           /* client time, optional */
    krb5_int32 usec;                    /* microsecond portion of time, opt. */
    krb5_ui_4 seq_number;               /* sequence #, optional */
    krb5_address *s_address;    /* sender address */
    krb5_address *r_address;    /* recipient address, optional */
} krb5_priv_enc_part;

void KRB5_CALLCONV krb5_free_safe(krb5_context, krb5_safe *);
void KRB5_CALLCONV krb5_free_priv(krb5_context, krb5_priv *);
void KRB5_CALLCONV krb5_free_priv_enc_part(krb5_context, krb5_priv_enc_part *);

/*
 * Begin "asn1.h"
 */
#ifndef KRB5_ASN1__
#define KRB5_ASN1__

/* ASN.1 encoding knowledge; KEEP IN SYNC WITH ASN.1 defs! */
/* here we use some knowledge of ASN.1 encodings */
/*
  Ticket is APPLICATION 1.
  Authenticator is APPLICATION 2.
  AS_REQ is APPLICATION 10.
  AS_REP is APPLICATION 11.
  TGS_REQ is APPLICATION 12.
  TGS_REP is APPLICATION 13.
  AP_REQ is APPLICATION 14.
  AP_REP is APPLICATION 15.
  KRB_SAFE is APPLICATION 20.
  KRB_PRIV is APPLICATION 21.
  KRB_CRED is APPLICATION 22.
  EncASRepPart is APPLICATION 25.
  EncTGSRepPart is APPLICATION 26.
  EncAPRepPart is APPLICATION 27.
  EncKrbPrivPart is APPLICATION 28.
  EncKrbCredPart is APPLICATION 29.
  KRB_ERROR is APPLICATION 30.
*/
/* allow either constructed or primitive encoding, so check for bit 6
   set or reset */
#define krb5int_is_app_tag(dat,tag)                     \
    ((dat != NULL) && (dat)->length &&                  \
     ((((dat)->data[0] & ~0x20) == ((tag) | 0x40))))
#define krb5_is_krb_ticket(dat)               krb5int_is_app_tag(dat, 1)
#define krb5_is_krb_authenticator(dat)        krb5int_is_app_tag(dat, 2)
#define krb5_is_as_req(dat)                   krb5int_is_app_tag(dat, 10)
#define krb5_is_as_rep(dat)                   krb5int_is_app_tag(dat, 11)
#define krb5_is_tgs_req(dat)                  krb5int_is_app_tag(dat, 12)
#define krb5_is_tgs_rep(dat)                  krb5int_is_app_tag(dat, 13)
#define krb5_is_ap_req(dat)                   krb5int_is_app_tag(dat, 14)
#define krb5_is_ap_rep(dat)                   krb5int_is_app_tag(dat, 15)
#define krb5_is_krb_safe(dat)                 krb5int_is_app_tag(dat, 20)
#define krb5_is_krb_priv(dat)                 krb5int_is_app_tag(dat, 21)
#define krb5_is_krb_cred(dat)                 krb5int_is_app_tag(dat, 22)
#define krb5_is_krb_enc_as_rep_part(dat)      krb5int_is_app_tag(dat, 25)
#define krb5_is_krb_enc_tgs_rep_part(dat)     krb5int_is_app_tag(dat, 26)
#define krb5_is_krb_enc_ap_rep_part(dat)      krb5int_is_app_tag(dat, 27)
#define krb5_is_krb_enc_krb_priv_part(dat)    krb5int_is_app_tag(dat, 28)
#define krb5_is_krb_enc_krb_cred_part(dat)    krb5int_is_app_tag(dat, 29)
#define krb5_is_krb_error(dat)                krb5int_is_app_tag(dat, 30)

/*************************************************************************
 * Prototypes for krb5_encode.c
 *************************************************************************/

/*
  krb5_error_code encode_krb5_structure(const krb5_structure *rep,
  krb5_data **code);
  modifies  *code
  effects   Returns the ASN.1 encoding of *rep in **code.
  Returns ASN1_MISSING_FIELD if a required field is emtpy in *rep.
  Returns ENOMEM if memory runs out.
*/

krb5_error_code
encode_krb5_authenticator(const krb5_authenticator *rep, krb5_data **code);

krb5_error_code
encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);

krb5_error_code
encode_krb5_enc_tkt_part(const krb5_enc_tkt_part *rep, krb5_data **code);

krb5_error_code
encode_krb5_enc_kdc_rep_part(const krb5_enc_kdc_rep_part *rep,
                             krb5_data **code);

/* yes, the translation is identical to that used for KDC__REP */
krb5_error_code
encode_krb5_as_rep(const krb5_kdc_rep *rep, krb5_data **code);

/* yes, the translation is identical to that used for KDC__REP */
krb5_error_code
encode_krb5_tgs_rep(const krb5_kdc_rep *rep, krb5_data **code);

krb5_error_code
encode_krb5_ap_req(const krb5_ap_req *rep, krb5_data **code);

krb5_error_code
encode_krb5_ap_rep(const krb5_ap_rep *rep, krb5_data **code);

krb5_error_code
encode_krb5_ap_rep_enc_part(const krb5_ap_rep_enc_part *rep, krb5_data **code);

krb5_error_code
encode_krb5_as_req(const krb5_kdc_req *rep, krb5_data **code);

krb5_error_code
encode_krb5_tgs_req(const krb5_kdc_req *rep, krb5_data **code);

krb5_error_code
encode_krb5_kdc_req_body(const krb5_kdc_req *rep, krb5_data **code);

krb5_error_code
encode_krb5_safe(const krb5_safe *rep, krb5_data **code);

struct krb5_safe_with_body {
    krb5_safe *safe;
    krb5_data *body;
};
krb5_error_code
encode_krb5_safe_with_body(const struct krb5_safe_with_body *rep,
                           krb5_data **code);

krb5_error_code
encode_krb5_priv(const krb5_priv *rep, krb5_data **code);

krb5_error_code
encode_krb5_enc_priv_part(const krb5_priv_enc_part *rep, krb5_data **code);

krb5_error_code
encode_krb5_cred(const krb5_cred *rep, krb5_data **code);
krb5_error_code
encode_krb5_checksum(const krb5_checksum *, krb5_data **);

krb5_error_code
encode_krb5_enc_cred_part(const krb5_cred_enc_part *rep, krb5_data **code);

krb5_error_code
encode_krb5_error(const krb5_error *rep, krb5_data **code);

krb5_error_code
encode_krb5_authdata(krb5_authdata *const *rep, krb5_data **code);

krb5_error_code
encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);

krb5_error_code
encode_krb5_typed_data(krb5_pa_data *const *rep, krb5_data **code);

krb5_error_code
encode_krb5_etype_info(krb5_etype_info_entry *const *, krb5_data **code);

krb5_error_code
encode_krb5_etype_info2(krb5_etype_info_entry *const *, krb5_data **code);

krb5_error_code
encode_krb5_pa_enc_ts(const krb5_pa_enc_ts *, krb5_data **);

krb5_error_code
encode_krb5_sam_challenge_2(const krb5_sam_challenge_2 * , krb5_data **);

krb5_error_code
encode_krb5_sam_challenge_2_body(const krb5_sam_challenge_2_body *,
                                 krb5_data **);

krb5_error_code
encode_krb5_enc_sam_response_enc_2(const krb5_enc_sam_response_enc_2 *,
                                   krb5_data **);

krb5_error_code
encode_krb5_sam_response_2(const krb5_sam_response_2 * , krb5_data **);

struct krb5_setpw_req {
    krb5_principal target;
    krb5_data password;
};
krb5_error_code
encode_krb5_setpw_req(const struct krb5_setpw_req *rep, krb5_data **code);

krb5_error_code
encode_krb5_pa_for_user(const krb5_pa_for_user *, krb5_data **);

krb5_error_code
encode_krb5_s4u_userid(const krb5_s4u_userid *, krb5_data **);

krb5_error_code
encode_krb5_pa_s4u_x509_user(const krb5_pa_s4u_x509_user *, krb5_data **);

krb5_error_code
encode_krb5_pa_pac_req(const krb5_pa_pac_req *, krb5_data **);

krb5_error_code
encode_krb5_etype_list(const krb5_etype_list * , krb5_data **);

krb5_error_code
encode_krb5_pa_fx_fast_request(const krb5_fast_armored_req *, krb5_data **);

krb5_error_code
encode_krb5_fast_req(const krb5_fast_req *, krb5_data **);

krb5_error_code
encode_krb5_pa_fx_fast_reply(const krb5_enc_data *, krb5_data **);

krb5_error_code
encode_krb5_iakerb_header(const krb5_iakerb_header *, krb5_data **);

krb5_error_code
encode_krb5_iakerb_finished(const krb5_iakerb_finished *, krb5_data **);

krb5_error_code
encode_krb5_fast_response(const krb5_fast_response *, krb5_data **);

krb5_error_code
encode_krb5_ad_kdcissued(const krb5_ad_kdcissued *, krb5_data **);

krb5_error_code
encode_krb5_ad_signedpath(const krb5_ad_signedpath *, krb5_data **);

krb5_error_code
encode_krb5_ad_signedpath_data(const krb5_ad_signedpath_data *, krb5_data **);

krb5_error_code
encode_krb5_otp_tokeninfo(const krb5_otp_tokeninfo *, krb5_data **);

krb5_error_code
encode_krb5_pa_otp_challenge(const krb5_pa_otp_challenge *, krb5_data **);

krb5_error_code
encode_krb5_pa_otp_req(const krb5_pa_otp_req *, krb5_data **);

krb5_error_code
encode_krb5_pa_otp_enc_req(const krb5_data *, krb5_data **);

krb5_error_code
encode_krb5_kkdcp_message(const krb5_kkdcp_message *, krb5_data **);

/*************************************************************************
 * End of prototypes for krb5_encode.c
 *************************************************************************/

krb5_error_code
decode_krb5_sam_challenge_2(const krb5_data *, krb5_sam_challenge_2 **);

krb5_error_code
decode_krb5_sam_challenge_2_body(const krb5_data *,
                                 krb5_sam_challenge_2_body **);

krb5_error_code
decode_krb5_enc_sam_response_enc_2(const krb5_data *,
                                   krb5_enc_sam_response_enc_2 **);

krb5_error_code
decode_krb5_sam_response_2(const krb5_data *, krb5_sam_response_2 **);


/*************************************************************************
 * Prototypes for krb5_decode.c
 *************************************************************************/
/*
  krb5_error_code decode_krb5_structure(const krb5_data *code,
  krb5_structure **rep);

  requires  Expects **rep to not have been allocated;
  a new *rep is allocated regardless of the old value.
  effects   Decodes *code into **rep.
  Returns ENOMEM if memory is exhausted.
  Returns asn1 and krb5 errors.
*/

krb5_error_code
decode_krb5_authenticator(const krb5_data *code, krb5_authenticator **rep);

krb5_error_code
decode_krb5_ticket(const krb5_data *code, krb5_ticket **rep);

krb5_error_code
decode_krb5_encryption_key(const krb5_data *output, krb5_keyblock **rep);

krb5_error_code
decode_krb5_enc_tkt_part(const krb5_data *output, krb5_enc_tkt_part **rep);

krb5_error_code
decode_krb5_enc_kdc_rep_part(const krb5_data *output,
                             krb5_enc_kdc_rep_part **rep);

krb5_error_code
decode_krb5_as_rep(const krb5_data *output, krb5_kdc_rep **rep);

krb5_error_code
decode_krb5_tgs_rep(const krb5_data *output, krb5_kdc_rep **rep);

krb5_error_code
decode_krb5_ap_req(const krb5_data *output, krb5_ap_req **rep);

krb5_error_code
decode_krb5_ap_rep(const krb5_data *output, krb5_ap_rep **rep);

krb5_error_code
decode_krb5_ap_rep_enc_part(const krb5_data *output,
                            krb5_ap_rep_enc_part **rep);

krb5_error_code
decode_krb5_as_req(const krb5_data *output, krb5_kdc_req **rep);

krb5_error_code
decode_krb5_tgs_req(const krb5_data *output, krb5_kdc_req **rep);

krb5_error_code
decode_krb5_kdc_req_body(const krb5_data *output, krb5_kdc_req **rep);

krb5_error_code
decode_krb5_safe(const krb5_data *output, krb5_safe **rep);

krb5_error_code
decode_krb5_safe_with_body(const krb5_data *output, krb5_safe **rep,
                           krb5_data **body);

krb5_error_code
decode_krb5_priv(const krb5_data *output, krb5_priv **rep);

krb5_error_code
decode_krb5_enc_priv_part(const krb5_data *output, krb5_priv_enc_part **rep);
krb5_error_code
decode_krb5_checksum(const krb5_data *, krb5_checksum **);

krb5_error_code
decode_krb5_cred(const krb5_data *output, krb5_cred **rep);

krb5_error_code
decode_krb5_enc_cred_part(const krb5_data *output, krb5_cred_enc_part **rep);

krb5_error_code
decode_krb5_error(const krb5_data *output, krb5_error **rep);

krb5_error_code
decode_krb5_authdata(const krb5_data *output, krb5_authdata ***rep);

krb5_error_code
decode_krb5_padata_sequence(const krb5_data *output, krb5_pa_data ***rep);

krb5_error_code
decode_krb5_typed_data(const krb5_data *, krb5_pa_data ***);

krb5_error_code
decode_krb5_etype_info(const krb5_data *output, krb5_etype_info_entry ***rep);

krb5_error_code
decode_krb5_etype_info2(const krb5_data *output, krb5_etype_info_entry ***rep);

krb5_error_code
decode_krb5_enc_data(const krb5_data *output, krb5_enc_data **rep);

krb5_error_code
decode_krb5_pa_enc_ts(const krb5_data *output, krb5_pa_enc_ts **rep);

krb5_error_code
decode_krb5_setpw_req(const krb5_data *, krb5_data **, krb5_principal *);

krb5_error_code
decode_krb5_pa_for_user(const krb5_data *, krb5_pa_for_user **);

krb5_error_code
decode_krb5_pa_s4u_x509_user(const krb5_data *, krb5_pa_s4u_x509_user **);

krb5_error_code
decode_krb5_pa_pac_req(const krb5_data *, krb5_pa_pac_req **);

krb5_error_code
decode_krb5_etype_list(const krb5_data *, krb5_etype_list **);

krb5_error_code
decode_krb5_pa_fx_fast_request(const krb5_data *, krb5_fast_armored_req **);

krb5_error_code
decode_krb5_fast_req(const krb5_data *, krb5_fast_req **);

krb5_error_code
decode_krb5_pa_fx_fast_reply(const krb5_data *, krb5_enc_data **);

krb5_error_code
decode_krb5_fast_response(const krb5_data *, krb5_fast_response **);

krb5_error_code
decode_krb5_ad_kdcissued(const krb5_data *, krb5_ad_kdcissued **);

krb5_error_code
decode_krb5_ad_signedpath(const krb5_data *, krb5_ad_signedpath **);

krb5_error_code
decode_krb5_iakerb_header(const krb5_data *, krb5_iakerb_header **);

krb5_error_code
decode_krb5_iakerb_finished(const krb5_data *, krb5_iakerb_finished **);

krb5_error_code
decode_krb5_otp_tokeninfo(const krb5_data *, krb5_otp_tokeninfo **);

krb5_error_code
decode_krb5_pa_otp_challenge(const krb5_data *, krb5_pa_otp_challenge **);

krb5_error_code
decode_krb5_pa_otp_req(const krb5_data *, krb5_pa_otp_req **);

krb5_error_code
decode_krb5_pa_otp_enc_req(const krb5_data *, krb5_data **);

krb5_error_code
decode_krb5_kkdcp_message(const krb5_data *, krb5_kkdcp_message **);

struct _krb5_key_data;          /* kdb.h */

struct ldap_seqof_key_data {
    krb5_int32 mkvno;           /* Master key version number */
    krb5_int16 kvno;            /* kvno of key_data elements (all the same) */
    struct _krb5_key_data *key_data;
    krb5_int16 n_key_data;
};
typedef struct ldap_seqof_key_data ldap_seqof_key_data;

krb5_error_code
krb5int_ldap_encode_sequence_of_keys(const ldap_seqof_key_data *val,
                                     krb5_data **code);

krb5_error_code
krb5int_ldap_decode_sequence_of_keys(const krb5_data *in,
                                     ldap_seqof_key_data **rep);

/*************************************************************************
 * End of prototypes for krb5_decode.c
 *************************************************************************/

#endif /* KRB5_ASN1__ */
/*
 * End "asn1.h"
 */


/*
 * Internal krb5 library routines
 */
krb5_error_code
krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);

krb5_error_code
krb5_encode_kdc_rep(krb5_context, krb5_msgtype, const krb5_enc_kdc_rep_part *,
                    int using_subkey, const krb5_keyblock *, krb5_kdc_rep *,
                    krb5_data ** );

/*
 * [De]Serialization Handle and operations.
 */
struct __krb5_serializer {
    krb5_magic          odtype;
    krb5_error_code     (*sizer) (krb5_context,
                                  krb5_pointer,
                                  size_t *);
    krb5_error_code     (*externalizer) (krb5_context,
                                         krb5_pointer,
                                         krb5_octet **,
                                         size_t *);
    krb5_error_code     (*internalizer) (krb5_context,
                                         krb5_pointer *,
                                         krb5_octet **,
                                         size_t *);
};
typedef const struct __krb5_serializer * krb5_ser_handle;
typedef struct __krb5_serializer krb5_ser_entry;

krb5_ser_handle krb5_find_serializer(krb5_context, krb5_magic);
krb5_error_code krb5_register_serializer(krb5_context, const krb5_ser_entry *);

/* Determine the external size of a particular opaque structure */
krb5_error_code KRB5_CALLCONV
krb5_size_opaque(krb5_context, krb5_magic, krb5_pointer, size_t *);

/* Serialize the structure into a buffer */
krb5_error_code KRB5_CALLCONV
krb5_externalize_opaque(krb5_context, krb5_magic, krb5_pointer, krb5_octet **,
                        size_t *);

/* Deserialize the structure from a buffer */
krb5_error_code KRB5_CALLCONV
krb5_internalize_opaque(krb5_context, krb5_magic, krb5_pointer *,
                        krb5_octet **, size_t *);

/* Serialize data into a buffer */
krb5_error_code
krb5_externalize_data(krb5_context, krb5_pointer, krb5_octet **, size_t *);
/*
 * Initialization routines.
 */

/* Initialize serialization for krb5_[os_]context */
krb5_error_code KRB5_CALLCONV krb5_ser_context_init(krb5_context);

/* Initialize serialization for krb5_auth_context */
krb5_error_code KRB5_CALLCONV krb5_ser_auth_context_init(krb5_context);

/* Initialize serialization for krb5_keytab */
krb5_error_code KRB5_CALLCONV krb5_ser_keytab_init(krb5_context);

/* Initialize serialization for krb5_ccache */
krb5_error_code KRB5_CALLCONV krb5_ser_ccache_init(krb5_context);

/* Initialize serialization for krb5_rcache */
krb5_error_code KRB5_CALLCONV krb5_ser_rcache_init(krb5_context);

/* [De]serialize 4-byte integer */
krb5_error_code KRB5_CALLCONV
krb5_ser_pack_int32(krb5_int32, krb5_octet **, size_t *);

krb5_error_code KRB5_CALLCONV
krb5_ser_unpack_int32(krb5_int32 *, krb5_octet **, size_t *);

/* [De]serialize 8-byte integer */
krb5_error_code KRB5_CALLCONV
krb5_ser_pack_int64(int64_t, krb5_octet **, size_t *);

krb5_error_code KRB5_CALLCONV
krb5_ser_unpack_int64(int64_t *, krb5_octet **, size_t *);

/* [De]serialize byte string */
krb5_error_code KRB5_CALLCONV
krb5_ser_pack_bytes(krb5_octet *, size_t, krb5_octet **, size_t *);

krb5_error_code KRB5_CALLCONV
krb5_ser_unpack_bytes(krb5_octet *, size_t, krb5_octet **, size_t *);

krb5_error_code KRB5_CALLCONV
krb5int_cc_default(krb5_context, krb5_ccache *);

/* Fill in the buffer with random alpha-numeric data. */
krb5_error_code
krb5int_random_string(krb5_context, char *string, unsigned int length);

/* value to use when requesting a keytab entry and KVNO doesn't matter */
#define IGNORE_VNO 0
/* value to use when requesting a keytab entry and enctype doesn't matter */
#define IGNORE_ENCTYPE 0

/* To keep happy libraries which are (for now) accessing internal stuff */

/* Make sure to increment by one when changing the struct */
#define KRB5INT_ACCESS_STRUCT_VERSION 21

typedef struct _krb5int_access {
    krb5_error_code (*auth_con_get_subkey_enctype)(krb5_context,
                                                   krb5_auth_context,
                                                   krb5_enctype *);

    krb5_error_code (*clean_hostname)(krb5_context, const char *, char *,
                                      size_t);

    krb5_error_code (*mandatory_cksumtype)(krb5_context, krb5_enctype,
                                           krb5_cksumtype *);
    krb5_error_code (KRB5_CALLCONV *ser_pack_int64)(int64_t, krb5_octet **,
                                                    size_t *);
    krb5_error_code (KRB5_CALLCONV *ser_unpack_int64)(int64_t *, krb5_octet **,
                                                      size_t *);

    /* Used for KDB LDAP back end.  */
    krb5_error_code
    (*asn1_ldap_encode_sequence_of_keys)(const ldap_seqof_key_data *val,
                                         krb5_data **code);

    krb5_error_code
    (*asn1_ldap_decode_sequence_of_keys)(const krb5_data *in,
                                         ldap_seqof_key_data **);

    /*
     * pkinit asn.1 encode/decode functions
     */
    krb5_error_code
    (*encode_krb5_auth_pack)(const krb5_auth_pack *rep, krb5_data **code);

    krb5_error_code
    (*encode_krb5_auth_pack_draft9)(const krb5_auth_pack_draft9 *rep,
                                    krb5_data **code);

    krb5_error_code
    (*encode_krb5_kdc_dh_key_info)(const krb5_kdc_dh_key_info *rep,
                                   krb5_data **code);

    krb5_error_code
    (*encode_krb5_pa_pk_as_rep)(const krb5_pa_pk_as_rep *rep,
                                krb5_data **code);

    krb5_error_code
    (*encode_krb5_pa_pk_as_rep_draft9)(const krb5_pa_pk_as_rep_draft9 *rep,
                                       krb5_data **code);

    krb5_error_code
    (*encode_krb5_pa_pk_as_req)(const krb5_pa_pk_as_req *rep,
                                krb5_data **code);

    krb5_error_code
    (*encode_krb5_pa_pk_as_req_draft9)(const krb5_pa_pk_as_req_draft9 *rep,
                                       krb5_data **code);

    krb5_error_code
    (*encode_krb5_reply_key_pack)(const krb5_reply_key_pack *,
                                  krb5_data **code);

    krb5_error_code
    (*encode_krb5_reply_key_pack_draft9)(const krb5_reply_key_pack_draft9 *,
                                         krb5_data **code);

    krb5_error_code
    (*encode_krb5_td_dh_parameters)(krb5_algorithm_identifier *const *,
                                    krb5_data **code);

    krb5_error_code
    (*encode_krb5_td_trusted_certifiers)(krb5_external_principal_identifier *
                                         const *, krb5_data **code);

    krb5_error_code
    (*decode_krb5_auth_pack)(const krb5_data *, krb5_auth_pack **);

    krb5_error_code
    (*decode_krb5_auth_pack_draft9)(const krb5_data *,
                                    krb5_auth_pack_draft9 **);

    krb5_error_code
    (*decode_krb5_pa_pk_as_req)(const krb5_data *, krb5_pa_pk_as_req **);

    krb5_error_code
    (*decode_krb5_pa_pk_as_req_draft9)(const krb5_data *,
                                       krb5_pa_pk_as_req_draft9 **);

    krb5_error_code
    (*decode_krb5_pa_pk_as_rep)(const krb5_data *, krb5_pa_pk_as_rep **);

    krb5_error_code
    (*decode_krb5_kdc_dh_key_info)(const krb5_data *, krb5_kdc_dh_key_info **);

    krb5_error_code
    (*decode_krb5_principal_name)(const krb5_data *, krb5_principal_data **);

    krb5_error_code
    (*decode_krb5_reply_key_pack)(const krb5_data *, krb5_reply_key_pack **);

    krb5_error_code
    (*decode_krb5_reply_key_pack_draft9)(const krb5_data *,
                                         krb5_reply_key_pack_draft9 **);

    krb5_error_code
    (*decode_krb5_td_dh_parameters)(const krb5_data *,
                                    krb5_algorithm_identifier ***);

    krb5_error_code
    (*decode_krb5_td_trusted_certifiers)(const krb5_data *,
                                         krb5_external_principal_identifier
                                         ***);

    krb5_error_code
    (*encode_krb5_kdc_req_body)(const krb5_kdc_req *rep, krb5_data **code);

    void
    (KRB5_CALLCONV *free_kdc_req)(krb5_context, krb5_kdc_req * );
    void
    (*set_prompt_types)(krb5_context, krb5_prompt_type *);
} krb5int_access;

#define KRB5INT_ACCESS_VERSION                                          \
    (((krb5_int32)((sizeof(krb5int_access) & 0xFFFF) |                  \
                   (KRB5INT_ACCESS_STRUCT_VERSION << 16))) & 0xFFFFFFFF)

krb5_error_code KRB5_CALLCONV
krb5int_accessor(krb5int_access*, krb5_int32);

typedef struct _krb5_donot_replay {
    krb5_magic magic;
    krb5_ui_4 hash;
    char *server;                       /* null-terminated */
    char *client;                       /* null-terminated */
    char *msghash;                      /* null-terminated */
    krb5_int32 cusec;
    krb5_timestamp ctime;
} krb5_donot_replay;

krb5_error_code KRB5_CALLCONV
krb5int_cc_user_set_default_name(krb5_context context, const char *name);

krb5_error_code krb5_rc_default(krb5_context, krb5_rcache *);
krb5_error_code krb5_rc_resolve_type(krb5_context, krb5_rcache *,
                                     const char *);
krb5_error_code krb5_rc_resolve_full(krb5_context, krb5_rcache *,
                                     const char *);
char *krb5_rc_get_type(krb5_context, krb5_rcache);
char *krb5_rc_default_type(krb5_context);
char *krb5_rc_default_name(krb5_context);
krb5_error_code krb5_auth_to_rep(krb5_context, krb5_tkt_authent *,
                                 krb5_donot_replay *);
krb5_error_code krb5_rc_hash_message(krb5_context context,
                                     const krb5_data *message, char **out);

krb5_error_code KRB5_CALLCONV
krb5_rc_initialize(krb5_context, krb5_rcache, krb5_deltat);

krb5_error_code KRB5_CALLCONV
krb5_rc_recover_or_initialize(krb5_context, krb5_rcache,krb5_deltat);

krb5_error_code KRB5_CALLCONV
krb5_rc_recover(krb5_context, krb5_rcache);

krb5_error_code KRB5_CALLCONV
krb5_rc_destroy(krb5_context, krb5_rcache);

krb5_error_code KRB5_CALLCONV
krb5_rc_close(krb5_context, krb5_rcache);

krb5_error_code KRB5_CALLCONV
krb5_rc_store(krb5_context, krb5_rcache, krb5_donot_replay *);

krb5_error_code KRB5_CALLCONV
krb5_rc_expunge(krb5_context, krb5_rcache);

krb5_error_code KRB5_CALLCONV
krb5_rc_get_lifespan(krb5_context, krb5_rcache,krb5_deltat *);

char *KRB5_CALLCONV
krb5_rc_get_name(krb5_context, krb5_rcache);

krb5_error_code KRB5_CALLCONV
krb5_rc_resolve(krb5_context, krb5_rcache, char *);

/*
 * This structure was exposed and used in macros in krb5 1.2, so do not
 * change its ABI.
 */
typedef struct _krb5_kt_ops {
    krb5_magic magic;
    char *prefix;

    /* routines always present */
    krb5_error_code (KRB5_CALLCONV *resolve)(krb5_context, const char *,
                                             krb5_keytab *);
    krb5_error_code (KRB5_CALLCONV *get_name)(krb5_context, krb5_keytab,
                                              char *, unsigned int);
    krb5_error_code (KRB5_CALLCONV *close)(krb5_context, krb5_keytab);
    krb5_error_code (KRB5_CALLCONV *get)(krb5_context, krb5_keytab,
                                         krb5_const_principal, krb5_kvno,
                                         krb5_enctype, krb5_keytab_entry *);
    krb5_error_code (KRB5_CALLCONV *start_seq_get)(krb5_context, krb5_keytab,
                                                   krb5_kt_cursor *);
    krb5_error_code (KRB5_CALLCONV *get_next)(krb5_context, krb5_keytab,
                                              krb5_keytab_entry *,
                                              krb5_kt_cursor *);
    krb5_error_code (KRB5_CALLCONV *end_get)(krb5_context, krb5_keytab,
                                             krb5_kt_cursor *);
    /* routines to be included on extended version (write routines) */
    krb5_error_code (KRB5_CALLCONV *add)(krb5_context, krb5_keytab,
                                         krb5_keytab_entry *);
    krb5_error_code (KRB5_CALLCONV *remove)(krb5_context, krb5_keytab,
                                            krb5_keytab_entry *);

    /* Handle for serializer */
    const krb5_ser_entry *serializer;
} krb5_kt_ops;

/* Not sure it's ready for exposure just yet.  */
extern krb5_error_code
krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);

/*
 * Referral definitions and subfunctions.
 */
#define        KRB5_REFERRAL_MAXHOPS    10

struct _krb5_kt {       /* should move into k5-int.h */
    krb5_magic magic;
    const struct _krb5_kt_ops *ops;
    krb5_pointer data;
};

krb5_error_code krb5_set_default_in_tkt_ktypes(krb5_context,
                                               const krb5_enctype *);

krb5_error_code krb5_get_default_in_tkt_ktypes(krb5_context, krb5_enctype **);

krb5_error_code krb5_set_default_tgs_ktypes(krb5_context,
                                            const krb5_enctype *);

krb5_error_code KRB5_CALLCONV
krb5_get_tgs_ktypes(krb5_context, krb5_const_principal, krb5_enctype **);

krb5_boolean krb5_is_permitted_enctype(krb5_context, krb5_enctype);

krb5_boolean KRB5_CALLCONV krb5int_c_weak_enctype(krb5_enctype);

krb5_error_code krb5_kdc_rep_decrypt_proc(krb5_context, const krb5_keyblock *,
                                          krb5_const_pointer, krb5_kdc_rep *);
krb5_error_code KRB5_CALLCONV krb5_decrypt_tkt_part(krb5_context,
                                                    const krb5_keyblock *,
                                                    krb5_ticket * );

krb5_error_code krb5_get_cred_via_tkt(krb5_context, krb5_creds *, krb5_flags,
                                      krb5_address *const *, krb5_creds *,
                                      krb5_creds **);

krb5_error_code KRB5_CALLCONV krb5_copy_addr(krb5_context,
                                             const krb5_address *,
                                             krb5_address **);

void krb5_init_ets(krb5_context);
void krb5_free_ets(krb5_context);
krb5_error_code krb5_generate_subkey(krb5_context, const krb5_keyblock *,
                                     krb5_keyblock **);
krb5_error_code krb5_generate_subkey_extended(krb5_context,
                                              const krb5_keyblock *,
                                              krb5_enctype, krb5_keyblock **);
krb5_error_code krb5_generate_seq_number(krb5_context, const krb5_keyblock *,
                                         krb5_ui_4 *);

krb5_error_code KRB5_CALLCONV krb5_kt_register(krb5_context,
                                               const struct _krb5_kt_ops *);

krb5_error_code k5_kt_get_principal(krb5_context context, krb5_keytab keytab,
                                    krb5_principal *princ_out);

krb5_error_code krb5_principal2salt_norealm(krb5_context, krb5_const_principal,
                                            krb5_data *);

unsigned int KRB5_CALLCONV krb5_get_notification_message(void);

/* chk_trans.c */
krb5_error_code krb5_check_transited_list(krb5_context, const krb5_data *trans,
                                          const krb5_data *realm1,
                                          const krb5_data *realm2);

/* free_rtree.c */
void krb5_free_realm_tree(krb5_context, krb5_principal *);

void KRB5_CALLCONV krb5_free_authenticator_contents(krb5_context,
                                                    krb5_authenticator *);

void KRB5_CALLCONV krb5_free_address(krb5_context, krb5_address *);

void KRB5_CALLCONV krb5_free_enc_tkt_part(krb5_context, krb5_enc_tkt_part *);

void KRB5_CALLCONV krb5_free_tickets(krb5_context, krb5_ticket **);
void KRB5_CALLCONV krb5_free_kdc_req(krb5_context, krb5_kdc_req *);
void KRB5_CALLCONV krb5_free_kdc_rep(krb5_context, krb5_kdc_rep *);
void KRB5_CALLCONV krb5_free_last_req(krb5_context, krb5_last_req_entry **);
void KRB5_CALLCONV krb5_free_enc_kdc_rep_part(krb5_context,
                                              krb5_enc_kdc_rep_part *);
void KRB5_CALLCONV krb5_free_ap_req(krb5_context, krb5_ap_req *);
void KRB5_CALLCONV krb5_free_ap_rep(krb5_context, krb5_ap_rep *);
void KRB5_CALLCONV krb5_free_cred(krb5_context, krb5_cred *);
void KRB5_CALLCONV krb5_free_cred_enc_part(krb5_context, krb5_cred_enc_part *);
void KRB5_CALLCONV krb5_free_pa_data(krb5_context, krb5_pa_data **);
void KRB5_CALLCONV krb5_free_tkt_authent(krb5_context, krb5_tkt_authent *);
void KRB5_CALLCONV krb5_free_enc_data(krb5_context, krb5_enc_data *);
krb5_error_code krb5_set_config_files(krb5_context, const char **);

krb5_error_code KRB5_CALLCONV krb5_get_default_config_files(char ***filenames);

void KRB5_CALLCONV krb5_free_config_files(char **filenames);

krb5_error_code krb5_rd_req_decoded(krb5_context, krb5_auth_context *,
                                    const krb5_ap_req *, krb5_const_principal,
                                    krb5_keytab, krb5_flags *, krb5_ticket **);

krb5_error_code krb5_rd_req_decoded_anyflag(krb5_context, krb5_auth_context *,
                                            const krb5_ap_req *,
                                            krb5_const_principal, krb5_keytab,
                                            krb5_flags *, krb5_ticket **);

krb5_error_code KRB5_CALLCONV
krb5_cc_register(krb5_context, const krb5_cc_ops *, krb5_boolean );

krb5_error_code krb5_walk_realm_tree(krb5_context, const krb5_data *,
                                     const krb5_data *, krb5_principal **,
                                     int);

krb5_error_code
krb5_auth_con_set_safe_cksumtype(krb5_context, krb5_auth_context,
                                 krb5_cksumtype);

krb5_error_code krb5_auth_con_setivector(krb5_context, krb5_auth_context,
                                         krb5_pointer);

krb5_error_code krb5_auth_con_getivector(krb5_context, krb5_auth_context,
                                         krb5_pointer *);

krb5_error_code krb5_auth_con_setpermetypes(krb5_context, krb5_auth_context,
                                            const krb5_enctype *);

krb5_error_code krb5_auth_con_getpermetypes(krb5_context, krb5_auth_context,
                                            krb5_enctype **);

krb5_error_code krb5_auth_con_get_subkey_enctype(krb5_context context,
                                                 krb5_auth_context,
                                                 krb5_enctype *);

krb5_error_code
krb5_auth_con_get_authdata_context(krb5_context context,
                                   krb5_auth_context auth_context,
                                   krb5_authdata_context *ad_context);

krb5_error_code
krb5_auth_con_set_authdata_context(krb5_context context,
                                   krb5_auth_context auth_context,
                                   krb5_authdata_context ad_context);

krb5_error_code krb5_read_message(krb5_context, krb5_pointer, krb5_data *);
krb5_error_code krb5_write_message(krb5_context, krb5_pointer, krb5_data *);
int krb5_net_read(krb5_context, int , char *, int);
int krb5_net_write(krb5_context, int , const char *, int);

krb5_error_code KRB5_CALLCONV krb5_get_realm_domain(krb5_context,
                                                    const char *, char ** );

krb5_error_code krb5_gen_portaddr(krb5_context, const krb5_address *,
                                  krb5_const_pointer, krb5_address **);

krb5_error_code krb5_gen_replay_name(krb5_context, const krb5_address *,
                                     const char *, char **);
krb5_error_code krb5_make_fulladdr(krb5_context, krb5_address *,
                                   krb5_address *, krb5_address *);

krb5_error_code krb5_set_debugging_time(krb5_context, krb5_timestamp,
                                        krb5_int32);
krb5_error_code krb5_use_natural_time(krb5_context);
krb5_error_code krb5_set_time_offsets(krb5_context, krb5_timestamp,
                                      krb5_int32);

/* Some data comparison and conversion functions.  */
static inline int
data_eq(krb5_data d1, krb5_data d2)
{
    return (d1.length == d2.length && (d1.length == 0 ||
                                       !memcmp(d1.data, d2.data, d1.length)));
}

static inline int
data_eq_string (krb5_data d, const char *s)
{
    return (d.length == strlen(s) && (d.length == 0 ||
                                      !memcmp(d.data, s, d.length)));
}

static inline krb5_data
make_data(void *data, unsigned int len)
{
    krb5_data d;

    d.magic = KV5M_DATA;
    d.data = (char *) data;
    d.length = len;
    return d;
}

static inline krb5_data
empty_data()
{
    return make_data(NULL, 0);
}

static inline krb5_data
string2data(char *str)
{
    return make_data(str, strlen(str));
}

static inline krb5_error_code
alloc_data(krb5_data *data, unsigned int len)
{
    /* Allocate at least one byte since zero-byte allocs may return NULL. */
    char *ptr = (char *) calloc((len > 0) ? len : 1, 1);

    if (ptr == NULL)
        return ENOMEM;
    data->magic = KV5M_DATA;
    data->data = ptr;
    data->length = len;
    return 0;
}

static inline int
authdata_eq(krb5_authdata a1, krb5_authdata a2)
{
    return (a1.ad_type == a2.ad_type && a1.length == a2.length &&
            (a1.length == 0 || !memcmp(a1.contents, a2.contents, a1.length)));
}

/* Allocate zeroed memory; set *code to 0 on success or ENOMEM on failure. */
static inline void *
k5calloc(size_t nmemb, size_t size, krb5_error_code *code)
{
    void *ptr;

    /* Allocate at least one byte since zero-byte allocs may return NULL. */
    ptr = calloc(nmemb ? nmemb : 1, size ? size : 1);
    *code = (ptr == NULL) ? ENOMEM : 0;
    return ptr;
}

/* Allocate zeroed memory; set *code to 0 on success or ENOMEM on failure. */
static inline void *
k5alloc(size_t size, krb5_error_code *code)
{
    return k5calloc(1, size, code);
}

/* Return a copy of the len bytes of memory at in; set *code to 0 or ENOMEM. */
static inline void *
k5memdup(const void *in, size_t len, krb5_error_code *code)
{
    void *ptr = k5alloc(len, code);

    if (ptr != NULL && len > 0)
        memcpy(ptr, in, len);
    return ptr;
}

/* Like k5memdup, but add a final null byte. */
static inline void *
k5memdup0(const void *in, size_t len, krb5_error_code *code)
{
    void *ptr = k5alloc(len + 1, code);

    if (ptr != NULL && len > 0)
        memcpy(ptr, in, len);
    return ptr;
}

krb5_error_code KRB5_CALLCONV
krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
                              krb5_ccache ccache,
                              krb5_creds *in_creds,
                              krb5_data *cert,
                              krb5_creds **out_creds);

krb5_error_code KRB5_CALLCONV
krb5_get_credentials_for_proxy(krb5_context context,
                               krb5_flags options,
                               krb5_ccache ccache,
                               krb5_creds *in_creds,
                               krb5_ticket *evidence_tkt,
                               krb5_creds **out_creds);

krb5_error_code KRB5_CALLCONV
krb5int_get_authdata_containee_types(krb5_context context,
                                     const krb5_authdata *container,
                                     unsigned int *nad_types,
                                     krb5_authdatatype **ad_types);

krb5_error_code krb5int_parse_enctype_list(krb5_context context,
                                           const char *profkey, char *profstr,
                                           krb5_enctype *default_list,
                                           krb5_enctype **result);

krb5_boolean k5_etypes_contains(const krb5_enctype *list, krb5_enctype etype);

void k5_change_error_message_code(krb5_context ctx, krb5_error_code oldcode,
                                  krb5_error_code newcode);

/* Define a shorter internal name for krb5_set_error_message. */
#define k5_setmsg krb5_set_error_message

#endif /* _KRB5_INT_H */
