jpayne@69: /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ jpayne@69: /* jpayne@69: * Copyright (c) 2006 Red Hat, Inc. jpayne@69: * Portions copyright (c) 2006, 2011 Massachusetts Institute of Technology jpayne@69: * All Rights Reserved. jpayne@69: * jpayne@69: * Redistribution and use in source and binary forms, with or without jpayne@69: * modification, are permitted provided that the following conditions are met: jpayne@69: * jpayne@69: * * Redistributions of source code must retain the above copyright jpayne@69: * notice, this list of conditions and the following disclaimer. jpayne@69: * * Redistributions in binary form must reproduce the above copyright jpayne@69: * notice, this list of conditions and the following disclaimer in jpayne@69: * the documentation and/or other materials provided with the jpayne@69: * distribution. jpayne@69: * * Neither the name of Red Hat, Inc., nor the names of its jpayne@69: * contributors may be used to endorse or promote products derived jpayne@69: * from this software without specific prior written permission. jpayne@69: * jpayne@69: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS jpayne@69: * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED jpayne@69: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A jpayne@69: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER jpayne@69: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, jpayne@69: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, jpayne@69: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR jpayne@69: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF jpayne@69: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING jpayne@69: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS jpayne@69: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jpayne@69: */ jpayne@69: jpayne@69: /* jpayne@69: * Declarations for kdcpreauth plugin module implementors. jpayne@69: * jpayne@69: * The kdcpreauth interface has a single supported major version, which is 1. jpayne@69: * Major version 1 has a current minor version of 2. kdcpreauth modules should jpayne@69: * define a function named kdcpreauth__initvt, matching the jpayne@69: * signature: jpayne@69: * jpayne@69: * krb5_error_code jpayne@69: * kdcpreauth_modname_initvt(krb5_context context, int maj_ver, int min_ver, jpayne@69: * krb5_plugin_vtable vtable); jpayne@69: * jpayne@69: * The initvt function should: jpayne@69: * jpayne@69: * - Check that the supplied maj_ver number is supported by the module, or jpayne@69: * return KRB5_PLUGIN_VER_NOTSUPP if it is not. jpayne@69: * jpayne@69: * - Cast the vtable pointer as appropriate for the interface and maj_ver: jpayne@69: * kdcpreauth, maj_ver == 1: Cast to krb5_kdcpreauth_vtable jpayne@69: * jpayne@69: * - Initialize the methods of the vtable, stopping as appropriate for the jpayne@69: * supplied min_ver. Optional methods may be left uninitialized. jpayne@69: * jpayne@69: * Memory for the vtable is allocated by the caller, not by the module. jpayne@69: */ jpayne@69: jpayne@69: #ifndef KRB5_KDCPREAUTH_PLUGIN_H jpayne@69: #define KRB5_KDCPREAUTH_PLUGIN_H jpayne@69: jpayne@69: #include jpayne@69: #include jpayne@69: jpayne@69: /* kdcpreauth mechanism property flags */ jpayne@69: jpayne@69: /* jpayne@69: * Causes the KDC to include this mechanism in a list of supported preauth jpayne@69: * types if the user's DB entry flags the user as requiring hardware-based jpayne@69: * preauthentication. jpayne@69: */ jpayne@69: #define PA_HARDWARE 0x00000004 jpayne@69: jpayne@69: /* jpayne@69: * Causes the KDC to include this mechanism in a list of supported preauth jpayne@69: * types if the user's DB entry flags the user as requiring preauthentication, jpayne@69: * and to fail preauthentication if we can't verify the client data. The jpayne@69: * flipside of PA_SUFFICIENT. jpayne@69: */ jpayne@69: #define PA_REQUIRED 0x00000008 jpayne@69: jpayne@69: /* jpayne@69: * Causes the KDC to include this mechanism in a list of supported preauth jpayne@69: * types if the user's DB entry flags the user as requiring preauthentication, jpayne@69: * and to mark preauthentication as successful if we can verify the client jpayne@69: * data. The flipside of PA_REQUIRED. jpayne@69: */ jpayne@69: #define PA_SUFFICIENT 0x00000010 jpayne@69: jpayne@69: /* jpayne@69: * Marks this preauthentication mechanism as one which changes the key which is jpayne@69: * used for encrypting the response to the client. Modules which have this jpayne@69: * flag have their server_return_fn called before modules which do not, and are jpayne@69: * passed over if a previously-called module has modified the encrypting key. jpayne@69: */ jpayne@69: #define PA_REPLACES_KEY 0x00000020 jpayne@69: jpayne@69: /* jpayne@69: * Not really a padata type, so don't include it in any list of preauth types jpayne@69: * which gets sent over the wire. jpayne@69: */ jpayne@69: #define PA_PSEUDO 0x00000080 jpayne@69: jpayne@69: /* jpayne@69: * Indicates that e_data in non-FAST errors should be encoded as typed data jpayne@69: * instead of padata. jpayne@69: */ jpayne@69: #define PA_TYPED_E_DATA 0x00000100 jpayne@69: jpayne@69: /* Abstract type for a KDC callback data handle. */ jpayne@69: typedef struct krb5_kdcpreauth_rock_st *krb5_kdcpreauth_rock; jpayne@69: jpayne@69: /* Abstract type for module data and per-request module data. */ jpayne@69: typedef struct krb5_kdcpreauth_moddata_st *krb5_kdcpreauth_moddata; jpayne@69: typedef struct krb5_kdcpreauth_modreq_st *krb5_kdcpreauth_modreq; jpayne@69: jpayne@69: /* The verto context structure type (typedef is in verto.h; we want to avoid a jpayne@69: * header dependency for the moment). */ jpayne@69: struct verto_ctx; jpayne@69: jpayne@69: /* Before using a callback after version 1, modules must check the vers jpayne@69: * field of the callback structure. */ jpayne@69: typedef struct krb5_kdcpreauth_callbacks_st { jpayne@69: int vers; jpayne@69: jpayne@69: krb5_deltat (*max_time_skew)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* jpayne@69: * Get an array of krb5_keyblock structures containing the client keys jpayne@69: * matching the request enctypes, terminated by an entry with key type = 0. jpayne@69: * Returns ENOENT if no keys are available for the request enctypes. Free jpayne@69: * the resulting object with the free_keys callback. jpayne@69: */ jpayne@69: krb5_error_code (*client_keys)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: krb5_keyblock **keys_out); jpayne@69: jpayne@69: /* Free the result of client_keys. */ jpayne@69: void (*free_keys)(krb5_context context, krb5_kdcpreauth_rock rock, jpayne@69: krb5_keyblock *keys); jpayne@69: jpayne@69: /* jpayne@69: * Get the encoded request body, which is sometimes needed for checksums. jpayne@69: * For a FAST request this is the encoded inner request body. The returned jpayne@69: * pointer is an alias and should not be freed. jpayne@69: */ jpayne@69: krb5_data *(*request_body)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* Get a pointer to the FAST armor key, or NULL if the request did not use jpayne@69: * FAST. The returned pointer is an alias and should not be freed. */ jpayne@69: krb5_keyblock *(*fast_armor)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* Retrieve a string attribute from the client DB entry, or NULL if no such jpayne@69: * attribute is set. Free the result with the free_string callback. */ jpayne@69: krb5_error_code (*get_string)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock, const char *key, jpayne@69: char **value_out); jpayne@69: jpayne@69: /* Free the result of get_string. */ jpayne@69: void (*free_string)(krb5_context context, krb5_kdcpreauth_rock rock, jpayne@69: char *string); jpayne@69: jpayne@69: /* Get a pointer to the client DB entry (returned as a void pointer to jpayne@69: * avoid a dependency on a libkdb5 type). */ jpayne@69: void *(*client_entry)(krb5_context context, krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* Get a pointer to the verto context which should be used by an jpayne@69: * asynchronous edata or verify method. */ jpayne@69: struct verto_ctx *(*event_context)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* End of version 1 kdcpreauth callbacks. */ jpayne@69: jpayne@69: /* Return true if the client DB entry contains any keys matching the jpayne@69: * request enctypes. */ jpayne@69: krb5_boolean (*have_client_keys)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* End of version 2 kdcpreauth callbacks. */ jpayne@69: jpayne@69: /* jpayne@69: * Get the current reply key. Initially the reply key is the decrypted jpayne@69: * client long-term key chosen according to the request enctype list, or jpayne@69: * NULL if no matching key was found. The value may be changed by the jpayne@69: * replace_reply_key callback or a return_padata method modifying jpayne@69: * encrypting_key. The returned pointer is an alias and should not be jpayne@69: * freed. jpayne@69: */ jpayne@69: const krb5_keyblock *(*client_keyblock)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* Assert an authentication indicator in the AS-REP authdata. Duplicate jpayne@69: * indicators will be ignored. */ jpayne@69: krb5_error_code (*add_auth_indicator)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: const char *indicator); jpayne@69: jpayne@69: /* jpayne@69: * Read a data value for pa_type from the request cookie, placing it in jpayne@69: * *out. The value placed there is an alias and must not be freed. jpayne@69: * Returns true if a value for pa_type was retrieved, false if not. jpayne@69: */ jpayne@69: krb5_boolean (*get_cookie)(krb5_context context, krb5_kdcpreauth_rock rock, jpayne@69: krb5_preauthtype pa_type, krb5_data *out); jpayne@69: jpayne@69: /* jpayne@69: * Set a data value for pa_type to be sent in a secure cookie in the next jpayne@69: * error response. If pa_type is already present, the value is ignored. jpayne@69: * If the preauth mechanism has different preauth types for requests and jpayne@69: * responses, use the request type. Secure cookies are encrypted in a key jpayne@69: * known only to the KDCs, but can be replayed within a short time window jpayne@69: * for requests using the same client principal. jpayne@69: */ jpayne@69: krb5_error_code (*set_cookie)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: krb5_preauthtype pa_type, jpayne@69: const krb5_data *data); jpayne@69: jpayne@69: /* End of version 3 kdcpreauth callbacks. */ jpayne@69: jpayne@69: /* jpayne@69: * Return true if princ matches the principal named in the request or the jpayne@69: * client principal (possibly canonicalized). If princ does not match, jpayne@69: * attempt a database lookup of princ with aliases allowed and compare the jpayne@69: * result to the client principal, returning true if it matches. jpayne@69: * Otherwise, return false. jpayne@69: */ jpayne@69: krb5_boolean (*match_client)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: krb5_principal princ); jpayne@69: jpayne@69: /* jpayne@69: * Get an alias to the client DB entry principal (possibly canonicalized). jpayne@69: */ jpayne@69: krb5_principal (*client_name)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* End of version 4 kdcpreauth callbacks. */ jpayne@69: jpayne@69: /* jpayne@69: * Instruct the KDC to send a freshness token in the method data jpayne@69: * accompanying a PREAUTH_REQUIRED or PREAUTH_FAILED error, if the client jpayne@69: * indicated support for freshness tokens. This callback should only be jpayne@69: * invoked from the edata method. jpayne@69: */ jpayne@69: void (*send_freshness_token)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock); jpayne@69: jpayne@69: /* Validate a freshness token sent by the client. Return 0 on success, jpayne@69: * KRB5KDC_ERR_PREAUTH_EXPIRED on error. */ jpayne@69: krb5_error_code (*check_freshness_token)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: const krb5_data *token); jpayne@69: jpayne@69: /* End of version 5 kdcpreauth callbacks. */ jpayne@69: jpayne@69: /* jpayne@69: * Replace the reply key with key. If is_strengthen is true, key must be a jpayne@69: * derivative of the client long-term key. This callback may be invoked jpayne@69: * from the verify or return_padata methods. If it is invoked from the jpayne@69: * verify method, the new key will appear as the encrypting_key input to jpayne@69: * return_padata. jpayne@69: */ jpayne@69: krb5_error_code (*replace_reply_key)(krb5_context context, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: const krb5_keyblock *key, jpayne@69: krb5_boolean is_strengthen); jpayne@69: jpayne@69: /* End of version 6 kdcpreauth callbacks. */ jpayne@69: jpayne@69: } *krb5_kdcpreauth_callbacks; jpayne@69: jpayne@69: /* Optional: preauth plugin initialization function. */ jpayne@69: typedef krb5_error_code jpayne@69: (*krb5_kdcpreauth_init_fn)(krb5_context context, jpayne@69: krb5_kdcpreauth_moddata *moddata_out, jpayne@69: const char **realmnames); jpayne@69: jpayne@69: /* Optional: preauth plugin cleanup function. */ jpayne@69: typedef void jpayne@69: (*krb5_kdcpreauth_fini_fn)(krb5_context context, jpayne@69: krb5_kdcpreauth_moddata moddata); jpayne@69: jpayne@69: /* jpayne@69: * Optional: return the flags which the KDC should use for this module. This jpayne@69: * is a callback instead of a static value because the module may or may not jpayne@69: * wish to count itself as a hardware preauthentication module (in other words, jpayne@69: * the flags may be affected by the configuration, for example if a site jpayne@69: * administrator can force a particular preauthentication type to be supported jpayne@69: * using only hardware). This function is called for each entry entry in the jpayne@69: * server_pa_type_list. jpayne@69: */ jpayne@69: typedef int jpayne@69: (*krb5_kdcpreauth_flags_fn)(krb5_context context, krb5_preauthtype pa_type); jpayne@69: jpayne@69: /* jpayne@69: * Responder for krb5_kdcpreauth_edata_fn. If invoked with a non-zero code, pa jpayne@69: * will be ignored and the padata type will not be included in the hint list. jpayne@69: * If invoked with a zero code and a null pa value, the padata type will be jpayne@69: * included in the list with an empty value. If invoked with a zero code and a jpayne@69: * non-null pa value, pa will be included in the hint list and will later be jpayne@69: * freed by the KDC. jpayne@69: */ jpayne@69: typedef void jpayne@69: (*krb5_kdcpreauth_edata_respond_fn)(void *arg, krb5_error_code code, jpayne@69: krb5_pa_data *pa); jpayne@69: jpayne@69: /* jpayne@69: * Optional: provide pa_data to send to the client as part of the "you need to jpayne@69: * use preauthentication" error. The implementation must invoke the respond jpayne@69: * when complete, whether successful or not, either before returning or jpayne@69: * asynchronously using the verto context returned by cb->event_context(). jpayne@69: * jpayne@69: * This function is not allowed to create a modreq object because we have no jpayne@69: * guarantee that the client will ever make a follow-up request, or that it jpayne@69: * will hit this KDC if it does. jpayne@69: */ jpayne@69: typedef void jpayne@69: (*krb5_kdcpreauth_edata_fn)(krb5_context context, krb5_kdc_req *request, jpayne@69: krb5_kdcpreauth_callbacks cb, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: krb5_kdcpreauth_moddata moddata, jpayne@69: krb5_preauthtype pa_type, jpayne@69: krb5_kdcpreauth_edata_respond_fn respond, jpayne@69: void *arg); jpayne@69: jpayne@69: /* jpayne@69: * Responder for krb5_kdcpreauth_verify_fn. Invoke with the arg parameter jpayne@69: * supplied to verify, the error code (0 for success), an optional module jpayne@69: * request state object to be consumed by return_fn or free_modreq_fn, optional jpayne@69: * e_data to be passed to the caller if code is nonzero, and optional jpayne@69: * authorization data to be included in the ticket. In non-FAST replies, jpayne@69: * e_data will be encoded as typed-data if the module sets the PA_TYPED_E_DATA jpayne@69: * flag, and as pa-data otherwise. e_data and authz_data will be freed by the jpayne@69: * KDC. jpayne@69: */ jpayne@69: typedef void jpayne@69: (*krb5_kdcpreauth_verify_respond_fn)(void *arg, krb5_error_code code, jpayne@69: krb5_kdcpreauth_modreq modreq, jpayne@69: krb5_pa_data **e_data, jpayne@69: krb5_authdata **authz_data); jpayne@69: jpayne@69: /* jpayne@69: * Optional: verify preauthentication data sent by the client, setting the jpayne@69: * TKT_FLG_PRE_AUTH or TKT_FLG_HW_AUTH flag in the enc_tkt_reply's "flags" jpayne@69: * field as appropriate. The implementation must invoke the respond function jpayne@69: * when complete, whether successful or not, either before returning or jpayne@69: * asynchronously using the verto context returned by cb->event_context(). jpayne@69: */ jpayne@69: typedef void jpayne@69: (*krb5_kdcpreauth_verify_fn)(krb5_context context, jpayne@69: krb5_data *req_pkt, krb5_kdc_req *request, jpayne@69: krb5_enc_tkt_part *enc_tkt_reply, jpayne@69: krb5_pa_data *data, jpayne@69: krb5_kdcpreauth_callbacks cb, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: krb5_kdcpreauth_moddata moddata, jpayne@69: krb5_kdcpreauth_verify_respond_fn respond, jpayne@69: void *arg); jpayne@69: jpayne@69: /* jpayne@69: * Optional: generate preauthentication response data to send to the client as jpayne@69: * part of the AS-REP. If it needs to override the key which is used to jpayne@69: * encrypt the response, it can do so by modifying encrypting_key, but it is jpayne@69: * preferrable to use the replace_reply_key callback. jpayne@69: */ jpayne@69: typedef krb5_error_code jpayne@69: (*krb5_kdcpreauth_return_fn)(krb5_context context, jpayne@69: krb5_pa_data *padata, jpayne@69: krb5_data *req_pkt, jpayne@69: krb5_kdc_req *request, jpayne@69: krb5_kdc_rep *reply, jpayne@69: krb5_keyblock *encrypting_key, jpayne@69: krb5_pa_data **send_pa_out, jpayne@69: krb5_kdcpreauth_callbacks cb, jpayne@69: krb5_kdcpreauth_rock rock, jpayne@69: krb5_kdcpreauth_moddata moddata, jpayne@69: krb5_kdcpreauth_modreq modreq); jpayne@69: jpayne@69: /* Optional: free a per-request context. */ jpayne@69: typedef void jpayne@69: (*krb5_kdcpreauth_free_modreq_fn)(krb5_context, jpayne@69: krb5_kdcpreauth_moddata moddata, jpayne@69: krb5_kdcpreauth_modreq modreq); jpayne@69: jpayne@69: /* Optional: invoked after init_fn to provide the module with a pointer to the jpayne@69: * verto main loop. */ jpayne@69: typedef krb5_error_code jpayne@69: (*krb5_kdcpreauth_loop_fn)(krb5_context context, jpayne@69: krb5_kdcpreauth_moddata moddata, jpayne@69: struct verto_ctx *ctx); jpayne@69: jpayne@69: typedef struct krb5_kdcpreauth_vtable_st { jpayne@69: /* Mandatory: name of module. */ jpayne@69: const char *name; jpayne@69: jpayne@69: /* Mandatory: pointer to zero-terminated list of pa_types which this module jpayne@69: * can provide services for. */ jpayne@69: krb5_preauthtype *pa_type_list; jpayne@69: jpayne@69: krb5_kdcpreauth_init_fn init; jpayne@69: krb5_kdcpreauth_fini_fn fini; jpayne@69: krb5_kdcpreauth_flags_fn flags; jpayne@69: krb5_kdcpreauth_edata_fn edata; jpayne@69: krb5_kdcpreauth_verify_fn verify; jpayne@69: krb5_kdcpreauth_return_fn return_padata; jpayne@69: krb5_kdcpreauth_free_modreq_fn free_modreq; jpayne@69: /* Minor 1 ends here. */ jpayne@69: jpayne@69: krb5_kdcpreauth_loop_fn loop; jpayne@69: /* Minor 2 ends here. */ jpayne@69: } *krb5_kdcpreauth_vtable; jpayne@69: jpayne@69: #endif /* KRB5_KDCPREAUTH_PLUGIN_H */