diff options
author | Andrew Bartlett <abartlet@samba.org> | 2009-06-08 19:06:16 +1000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2009-06-12 07:45:48 +1000 |
commit | 9b261c008a395a323e0516f4cd3f3134aa050577 (patch) | |
tree | 91cf543ba7ccd560313bea52fa8678f0456e8485 /source4/heimdal | |
parent | 5cef57ff7d899773a084d23838b7f18a83f6e79d (diff) | |
download | samba-9b261c008a395a323e0516f4cd3f3134aa050577.tar.gz samba-9b261c008a395a323e0516f4cd3f3134aa050577.tar.bz2 samba-9b261c008a395a323e0516f4cd3f3134aa050577.zip |
s4:heimdal: import lorikeet-heimdal-200906080040 (commit 904d0124b46eed7a8ad6e5b73e892ff34b6865ba)
Also including the supporting changes required to pass make test
A number of heimdal functions and constants have changed since we last
imported a tree (for the better, but inconvenient for us).
Andrew Bartlett
Diffstat (limited to 'source4/heimdal')
315 files changed, 9362 insertions, 7002 deletions
diff --git a/source4/heimdal/README b/source4/heimdal/README index 3b938248fc..f130698597 100644 --- a/source4/heimdal/README +++ b/source4/heimdal/README @@ -1,4 +1,3 @@ -$Id$ Heimdal is a Kerberos 5 implementation. diff --git a/source4/heimdal/cf/make-proto.pl b/source4/heimdal/cf/make-proto.pl index b89ef79067..04733e1281 100644 --- a/source4/heimdal/cf/make-proto.pl +++ b/source4/heimdal/cf/make-proto.pl @@ -100,13 +100,16 @@ while(<>) { s/^\s*//; s/\s*$//; s/\s+/ /g; - if($_ =~ /\)$/){ + if($_ =~ /\)$/ or $_ =~ /DEPRECATED$/){ if(!/^static/ && !/^PRIVATE/){ - if(/(.*)(__attribute__\s?\(.*\))/) { - $attr = $2; + $attr = ""; + if(m/(.*)(__attribute__\s?\(.*\))/) { + $attr .= " $2"; + $_ = $1; + } + if(m/(.*)\s(\w+DEPRECATED)/) { + $attr .= " $2"; $_ = $1; - } else { - $attr = ""; } # remove outer () s/\s*\(/</; @@ -308,7 +311,7 @@ extern \"C\" { if ($opt_E) { $public_h_header .= "#ifndef $opt_E #if defined(_WIN32) -#define ${opt_E}_FUNCTION _stdcall __declspec(dllimport) +#define ${opt_E}_FUNCTION __stdcall __declspec(dllimport) #define ${opt_E}_VARIABLE __declspec(dllimport) #else #define ${opt_E}_FUNCTION @@ -320,7 +323,7 @@ if ($opt_E) { $private_h_header .= "#ifndef $opt_E #if defined(_WIN32) -#define ${opt_E}_FUNCTION _stdcall __declspec(dllimport) +#define ${opt_E}_FUNCTION __stdcall __declspec(dllimport) #define ${opt_E}_VARIABLE __declspec(dllimport) #else #define ${opt_E}_FUNCTION diff --git a/source4/heimdal/cf/resolv.m4 b/source4/heimdal/cf/resolv.m4 index b4045094d8..49c868ab0e 100644 --- a/source4/heimdal/cf/resolv.m4 +++ b/source4/heimdal/cf/resolv.m4 @@ -5,7 +5,7 @@ dnl AC_DEFUN([rk_RESOLV],[ -AC_CHECK_HEADERS([arpa/nameser.h]) +AC_CHECK_HEADERS([arpa/nameser.h dns.h]) AC_CHECK_HEADERS(resolv.h, , , [AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_TYPES_H @@ -73,6 +73,15 @@ AC_FIND_FUNC(res_ndestroy, resolv, ], [0]) +AC_FIND_FUNC_NO_LIBS(dns_search,, +[ +#ifdef HAVE_DNS_H +#include <dns.h> +#endif +], +[0,0,0,0,0,0,0,0]) + + AC_FIND_FUNC(dn_expand, resolv, [ #include <stdio.h> diff --git a/source4/heimdal/lib/krb5/heim_threads.h b/source4/heimdal/include/heim_threads.h index c4f841fb61..c4f841fb61 100644 --- a/source4/heimdal/lib/krb5/heim_threads.h +++ b/source4/heimdal/include/heim_threads.h diff --git a/source4/heimdal/kdc/524.c b/source4/heimdal/kdc/524.c deleted file mode 100644 index d15310384a..0000000000 --- a/source4/heimdal/kdc/524.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "kdc_locl.h" - -RCSID("$Id$"); - -#include <krb5-v4compat.h> - -/* - * fetch the server from `t', returning the name in malloced memory in - * `spn' and the entry itself in `server' - */ - -static krb5_error_code -fetch_server (krb5_context context, - krb5_kdc_configuration *config, - const Ticket *t, - char **spn, - hdb_entry_ex **server, - const char *from) -{ - krb5_error_code ret; - krb5_principal sprinc; - - ret = _krb5_principalname2krb5_principal(context, &sprinc, - t->sname, t->realm); - if (ret) { - kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s", - krb5_get_err_text(context, ret)); - return ret; - } - ret = krb5_unparse_name(context, sprinc, spn); - if (ret) { - krb5_free_principal(context, sprinc); - kdc_log(context, config, 0, "krb5_unparse_name: %s", - krb5_get_err_text(context, ret)); - return ret; - } - ret = _kdc_db_fetch(context, config, sprinc, HDB_F_GET_SERVER, - NULL, server); - krb5_free_principal(context, sprinc); - if (ret) { - kdc_log(context, config, 0, - "Request to convert ticket from %s for unknown principal %s: %s", - from, *spn, krb5_get_err_text(context, ret)); - if (ret == HDB_ERR_NOENTRY) - ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; - return ret; - } - return 0; -} - -static krb5_error_code -log_524 (krb5_context context, - krb5_kdc_configuration *config, - const EncTicketPart *et, - const char *from, - const char *spn) -{ - krb5_principal client; - char *cpn; - krb5_error_code ret; - - ret = _krb5_principalname2krb5_principal(context, &client, - et->cname, et->crealm); - if (ret) { - kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s", - krb5_get_err_text (context, ret)); - return ret; - } - ret = krb5_unparse_name(context, client, &cpn); - if (ret) { - krb5_free_principal(context, client); - kdc_log(context, config, 0, "krb5_unparse_name: %s", - krb5_get_err_text (context, ret)); - return ret; - } - kdc_log(context, config, 1, "524-REQ %s from %s for %s", cpn, from, spn); - free(cpn); - krb5_free_principal(context, client); - return 0; -} - -static krb5_error_code -verify_flags (krb5_context context, - krb5_kdc_configuration *config, - const EncTicketPart *et, - const char *spn) -{ - if(et->endtime < kdc_time){ - kdc_log(context, config, 0, "Ticket expired (%s)", spn); - return KRB5KRB_AP_ERR_TKT_EXPIRED; - } - if(et->flags.invalid){ - kdc_log(context, config, 0, "Ticket not valid (%s)", spn); - return KRB5KRB_AP_ERR_TKT_NYV; - } - return 0; -} - -/* - * set the `et->caddr' to the most appropriate address to use, where - * `addr' is the address the request was received from. - */ - -static krb5_error_code -set_address (krb5_context context, - krb5_kdc_configuration *config, - EncTicketPart *et, - struct sockaddr *addr, - const char *from) -{ - krb5_error_code ret; - krb5_address *v4_addr; - - v4_addr = malloc (sizeof(*v4_addr)); - if (v4_addr == NULL) - return ENOMEM; - - ret = krb5_sockaddr2address(context, addr, v4_addr); - if(ret) { - free (v4_addr); - kdc_log(context, config, 0, "Failed to convert address (%s)", from); - return ret; - } - - if (et->caddr && !krb5_address_search (context, v4_addr, et->caddr)) { - kdc_log(context, config, 0, "Incorrect network address (%s)", from); - krb5_free_address(context, v4_addr); - free (v4_addr); - return KRB5KRB_AP_ERR_BADADDR; - } - if(v4_addr->addr_type == KRB5_ADDRESS_INET) { - /* we need to collapse the addresses in the ticket to a - single address; best guess is to use the address the - connection came from */ - - if (et->caddr != NULL) { - free_HostAddresses(et->caddr); - } else { - et->caddr = malloc (sizeof (*et->caddr)); - if (et->caddr == NULL) { - krb5_free_address(context, v4_addr); - free(v4_addr); - return ENOMEM; - } - } - et->caddr->val = v4_addr; - et->caddr->len = 1; - } else { - krb5_free_address(context, v4_addr); - free(v4_addr); - } - return 0; -} - - -static krb5_error_code -encrypt_v4_ticket(krb5_context context, - krb5_kdc_configuration *config, - void *buf, - size_t len, - krb5_keyblock *skey, - EncryptedData *reply) -{ - krb5_crypto crypto; - krb5_error_code ret; - ret = krb5_crypto_init(context, skey, ETYPE_DES_PCBC_NONE, &crypto); - if (ret) { - free(buf); - kdc_log(context, config, 0, "krb5_crypto_init failed: %s", - krb5_get_err_text(context, ret)); - return ret; - } - - ret = krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_TICKET, - buf, - len, - 0, - reply); - krb5_crypto_destroy(context, crypto); - if(ret) { - kdc_log(context, config, 0, "Failed to encrypt data: %s", - krb5_get_err_text(context, ret)); - return ret; - } - return 0; -} - -static krb5_error_code -encode_524_response(krb5_context context, - krb5_kdc_configuration *config, - const char *spn, const EncTicketPart et, - const Ticket *t, hdb_entry_ex *server, - EncryptedData *ticket, int *kvno) -{ - krb5_error_code ret; - int use_2b; - size_t len; - - use_2b = krb5_config_get_bool(context, NULL, "kdc", "use_2b", spn, NULL); - if(use_2b) { - ASN1_MALLOC_ENCODE(EncryptedData, - ticket->cipher.data, ticket->cipher.length, - &t->enc_part, &len, ret); - - if (ret) { - kdc_log(context, config, 0, - "Failed to encode v4 (2b) ticket (%s)", spn); - return ret; - } - - ticket->etype = 0; - ticket->kvno = NULL; - *kvno = 213; /* 2b's use this magic kvno */ - } else { - unsigned char buf[MAX_KTXT_LEN + 4 * 4]; - Key *skey; - - if (!config->enable_v4_cross_realm && strcmp (et.crealm, t->realm) != 0) { - kdc_log(context, config, 0, "524 cross-realm %s -> %s disabled", et.crealm, - t->realm); - return KRB5KDC_ERR_POLICY; - } - - ret = _kdc_encode_v4_ticket(context, config, - buf + sizeof(buf) - 1, sizeof(buf), - &et, &t->sname, &len); - if(ret){ - kdc_log(context, config, 0, - "Failed to encode v4 ticket (%s)", spn); - return ret; - } - ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey); - if(ret){ - kdc_log(context, config, 0, - "no suitable DES key for server (%s)", spn); - return ret; - } - ret = encrypt_v4_ticket(context, config, buf + sizeof(buf) - len, len, - &skey->key, ticket); - if(ret){ - kdc_log(context, config, 0, - "Failed to encrypt v4 ticket (%s)", spn); - return ret; - } - *kvno = server->entry.kvno; - } - - return 0; -} - -/* - * process a 5->4 request, based on `t', and received `from, addr', - * returning the reply in `reply' - */ - -krb5_error_code -_kdc_do_524(krb5_context context, - krb5_kdc_configuration *config, - const Ticket *t, krb5_data *reply, - const char *from, struct sockaddr *addr) -{ - krb5_error_code ret = 0; - krb5_crypto crypto; - hdb_entry_ex *server = NULL; - Key *skey; - krb5_data et_data; - EncTicketPart et; - EncryptedData ticket; - krb5_storage *sp; - char *spn = NULL; - unsigned char buf[MAX_KTXT_LEN + 4 * 4]; - size_t len; - int kvno = 0; - - if(!config->enable_524) { - ret = KRB5KDC_ERR_POLICY; - kdc_log(context, config, 0, - "Rejected ticket conversion request from %s", from); - goto out; - } - - ret = fetch_server (context, config, t, &spn, &server, from); - if (ret) { - goto out; - } - - ret = hdb_enctype2key(context, &server->entry, t->enc_part.etype, &skey); - if(ret){ - kdc_log(context, config, 0, - "No suitable key found for server (%s) from %s", spn, from); - goto out; - } - ret = krb5_crypto_init(context, &skey->key, 0, &crypto); - if (ret) { - kdc_log(context, config, 0, "krb5_crypto_init failed: %s", - krb5_get_err_text(context, ret)); - goto out; - } - ret = krb5_decrypt_EncryptedData (context, - crypto, - KRB5_KU_TICKET, - &t->enc_part, - &et_data); - krb5_crypto_destroy(context, crypto); - if(ret){ - kdc_log(context, config, 0, - "Failed to decrypt ticket from %s for %s", from, spn); - goto out; - } - ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length, - &et, &len); - krb5_data_free(&et_data); - if(ret){ - kdc_log(context, config, 0, - "Failed to decode ticket from %s for %s", from, spn); - goto out; - } - - ret = log_524 (context, config, &et, from, spn); - if (ret) { - free_EncTicketPart(&et); - goto out; - } - - ret = verify_flags (context, config, &et, spn); - if (ret) { - free_EncTicketPart(&et); - goto out; - } - - ret = set_address (context, config, &et, addr, from); - if (ret) { - free_EncTicketPart(&et); - goto out; - } - - ret = encode_524_response(context, config, spn, et, t, - server, &ticket, &kvno); - free_EncTicketPart(&et); - - out: - /* make reply */ - memset(buf, 0, sizeof(buf)); - sp = krb5_storage_from_mem(buf, sizeof(buf)); - if (sp) { - krb5_store_int32(sp, ret); - if(ret == 0){ - krb5_store_int32(sp, kvno); - krb5_store_data(sp, ticket.cipher); - /* Aargh! This is coded as a KTEXT_ST. */ - krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR); - krb5_store_int32(sp, 0); /* mbz */ - free_EncryptedData(&ticket); - } - ret = krb5_storage_to_data(sp, reply); - reply->length = krb5_storage_seek(sp, 0, SEEK_CUR); - krb5_storage_free(sp); - } else - krb5_data_zero(reply); - if(spn) - free(spn); - if(server) - _kdc_free_ent (context, server); - return ret; -} diff --git a/source4/heimdal/kdc/default_config.c b/source4/heimdal/kdc/default_config.c index 60fbc92903..bf65af3cb9 100644 --- a/source4/heimdal/kdc/default_config.c +++ b/source4/heimdal/kdc/default_config.c @@ -84,6 +84,7 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) krb5_config_get_bool_default(context, NULL, c->enable_v4, "kdc", "enable-524", NULL); +#ifdef DIGEST c->enable_digest = krb5_config_get_bool_default(context, NULL, FALSE, @@ -110,7 +111,9 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) c->enable_digest = 0; } } +#endif +#ifdef KX509 c->enable_kx509 = krb5_config_get_bool_default(context, NULL, FALSE, @@ -129,6 +132,7 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) c->enable_kx509 = FALSE; } } +#endif c->check_ticket_addresses = krb5_config_get_bool_default(context, NULL, @@ -220,7 +224,7 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) "enable-pkinit", NULL); if (c->enable_pkinit) { - const char *user_id, *anchors, *ocsp_file; + const char *user_id, *anchors, *file; char **pool_list, **revoke_list; user_id = @@ -242,15 +246,23 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) krb5_config_get_strings(context, NULL, "kdc", "pkinit_revoke", NULL); - ocsp_file = - krb5_config_get_string(context, NULL, - "kdc", "pkinit_kdc_ocsp", NULL); - if (ocsp_file) { - c->pkinit_kdc_ocsp_file = strdup(ocsp_file); + file = krb5_config_get_string(context, NULL, + "kdc", "pkinit_kdc_ocsp", NULL); + if (file) { + c->pkinit_kdc_ocsp_file = strdup(file); if (c->pkinit_kdc_ocsp_file == NULL) krb5_errx(context, 1, "out of memory"); } + file = krb5_config_get_string(context, NULL, + "kdc", "pkinit_kdc_friendly_name", NULL); + if (file) { + c->pkinit_kdc_friendly_name = strdup(file); + if (c->pkinit_kdc_friendly_name == NULL) + krb5_errx(context, 1, "out of memory"); + } + + _kdc_pk_initialize(context, c, user_id, anchors, pool_list, revoke_list); diff --git a/source4/heimdal/kdc/digest.c b/source4/heimdal/kdc/digest.c index 96986c1a87..d13507fc1f 100644 --- a/source4/heimdal/kdc/digest.c +++ b/source4/heimdal/kdc/digest.c @@ -34,7 +34,7 @@ #include "kdc_locl.h" #include <hex.h> -RCSID("$Id$"); +#ifdef DIGEST #define MS_CHAP_V2 0x20 #define CHAP_MD5 0x10 @@ -201,7 +201,7 @@ get_password_entry(krb5_context context, krb5_error_code _kdc_do_digest(krb5_context context, krb5_kdc_configuration *config, - const DigestREQ *req, krb5_data *reply, + const struct DigestREQ *req, krb5_data *reply, const char *from, struct sockaddr *addr) { krb5_error_code ret = 0; @@ -234,6 +234,7 @@ _kdc_do_digest(krb5_context context, memset(&ireq, 0, sizeof(ireq)); memset(&r, 0, sizeof(r)); memset(&rep, 0, sizeof(rep)); + memset(&res, 0, sizeof(res)); kdc_log(context, config, 0, "Digest request from %s", from); @@ -487,6 +488,7 @@ _kdc_do_digest(krb5_context context, hex_encode(buf.data, buf.length, &r.u.initReply.opaque); free(buf.data); + krb5_data_zero(&buf); if (r.u.initReply.opaque == NULL) { krb5_clear_error_message(context); ret = ENOMEM; @@ -539,8 +541,10 @@ _kdc_do_digest(krb5_context context, ret = decode_Checksum(buf.data, buf.length, &res, NULL); free(buf.data); + krb5_data_zero(&buf); if (ret) { - krb5_set_error_message(context, ret, "Failed to decode digest Checksum"); + krb5_set_error_message(context, ret, + "Failed to decode digest Checksum"); goto out; } @@ -582,6 +586,8 @@ _kdc_do_digest(krb5_context context, ret = krb5_verify_checksum(context, crypto, KRB5_KU_DIGEST_OPAQUE, buf.data, buf.length, &res); + free_Checksum(&res); + krb5_data_free(&buf); krb5_crypto_destroy(context, crypto); crypto = NULL; if (ret) @@ -1165,6 +1171,8 @@ _kdc_do_digest(krb5_context context, krb5_set_error_message(context, ret, "NTLM storage read flags"); goto out; } + krb5_storage_free(sp); + sp = NULL; krb5_data_free(&buf); if ((flags & NTLM_NEG_NTLM) == 0) { @@ -1450,9 +1458,12 @@ _kdc_do_digest(krb5_context context, free (client_name); krb5_data_free(&buf); krb5_data_free(&serverNonce); + free_Checksum(&res); free_DigestREP(&rep); free_DigestRepInner(&r); free_DigestReqInner(&ireq); return ret; } + +#endif /* DIGEST */ diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h index 3635d3c56a..2240336e31 100644 --- a/source4/heimdal/kdc/headers.h +++ b/source4/heimdal/kdc/headers.h @@ -91,13 +91,19 @@ #include <parse_units.h> #include <krb5.h> #include <krb5_locl.h> +#ifdef DIGEST #include <digest_asn1.h> +#endif +#ifdef KX509 #include <kx509_asn1.h> +#endif #include <hdb.h> #include <hdb_err.h> #include <der.h> +#ifndef NO_NTLM #include <heimntlm.h> +#endif #include <windc_plugin.h> #undef ALLOC diff --git a/source4/heimdal/kdc/kaserver.c b/source4/heimdal/kdc/kaserver.c index 9226ae115d..3702ab9281 100644 --- a/source4/heimdal/kdc/kaserver.c +++ b/source4/heimdal/kdc/kaserver.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id$"); +#ifdef KRB4 #include <krb5-v4compat.h> #include <rx.h> @@ -949,3 +949,5 @@ out: krb5_storage_free (sp); return ret; } + +#endif /* KRB4 */ diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h index 843bd5fa56..285a33af14 100644 --- a/source4/heimdal/kdc/kdc.h +++ b/source4/heimdal/kdc/kdc.h @@ -75,8 +75,10 @@ typedef struct krb5_kdc_configuration { krb5_boolean enable_pkinit; krb5_boolean pkinit_princ_in_cert; char *pkinit_kdc_ocsp_file; + char *pkinit_kdc_friendly_name; int pkinit_dh_min_bits; int pkinit_require_binding; + int pkinit_allow_proxy_certs; krb5_log_facility *logf; @@ -91,6 +93,20 @@ typedef struct krb5_kdc_configuration { } krb5_kdc_configuration; +struct krb5_kdc_service { + unsigned int flags; +#define KS_KRB5 1 +#define KS_NO_LENGTH 2 + krb5_error_code (*process)(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim); +}; + #include <kdc-protos.h> #endif diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h index 8e34c50049..9b291ac896 100644 --- a/source4/heimdal/kdc/kdc_locl.h +++ b/source4/heimdal/kdc/kdc_locl.h @@ -42,6 +42,8 @@ #include "kdc.h" typedef struct pk_client_params pk_client_params; +struct DigestREQ; +struct Kx509Request; #include <kdc-private.h> extern sig_atomic_t exit_flag; @@ -52,9 +54,12 @@ extern krb5_addresses explicit_addresses; extern int enable_http; +#ifdef SUPPORT_DETACH + #define DETACH_IS_DEFAULT FALSE extern int detach_from_console; +#endif extern const struct units _kdc_digestunits[]; diff --git a/source4/heimdal/kdc/kerberos4.c b/source4/heimdal/kdc/kerberos4.c deleted file mode 100644 index 2bd2383940..0000000000 --- a/source4/heimdal/kdc/kerberos4.c +++ /dev/null @@ -1,794 +0,0 @@ -/* - * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "kdc_locl.h" - -#include <krb5-v4compat.h> - -RCSID("$Id$"); - -#ifndef swap32 -static uint32_t -swap32(uint32_t x) -{ - return ((x << 24) & 0xff000000) | - ((x << 8) & 0xff0000) | - ((x >> 8) & 0xff00) | - ((x >> 24) & 0xff); -} -#endif /* swap32 */ - -int -_kdc_maybe_version4(unsigned char *buf, int len) -{ - return len > 0 && *buf == 4; -} - -static void -make_err_reply(krb5_context context, krb5_data *reply, - int code, const char *msg) -{ - _krb5_krb_cr_err_reply(context, "", "", "", - kdc_time, code, msg, reply); -} - -struct valid_princ_ctx { - krb5_kdc_configuration *config; - unsigned flags; -}; - -static krb5_boolean -valid_princ(krb5_context context, - void *funcctx, - krb5_principal princ) -{ - struct valid_princ_ctx *ctx = funcctx; - krb5_error_code ret; - char *s; - hdb_entry_ex *ent; - - ret = krb5_unparse_name(context, princ, &s); - if (ret) - return FALSE; - ret = _kdc_db_fetch(context, ctx->config, princ, ctx->flags, NULL, &ent); - if (ret) { - kdc_log(context, ctx->config, 7, "Lookup %s failed: %s", s, - krb5_get_err_text (context, ret)); - free(s); - return FALSE; - } - kdc_log(context, ctx->config, 7, "Lookup %s succeeded", s); - free(s); - _kdc_free_ent(context, ent); - return TRUE; -} - -krb5_error_code -_kdc_db_fetch4(krb5_context context, - krb5_kdc_configuration *config, - const char *name, const char *instance, const char *realm, - unsigned flags, - hdb_entry_ex **ent) -{ - krb5_principal p; - krb5_error_code ret; - struct valid_princ_ctx ctx; - - ctx.config = config; - ctx.flags = flags; - - ret = krb5_425_conv_principal_ext2(context, name, instance, realm, - valid_princ, &ctx, 0, &p); - if(ret) - return ret; - ret = _kdc_db_fetch(context, config, p, flags, NULL, ent); - krb5_free_principal(context, p); - return ret; -} - -#define RCHECK(X, L) if(X){make_err_reply(context, reply, KFAILURE, "Packet too short"); goto L;} - -/* - * Process the v4 request in `buf, len' (received from `addr' - * (with string `from'). - * Return an error code and a reply in `reply'. - */ - -krb5_error_code -_kdc_do_version4(krb5_context context, - krb5_kdc_configuration *config, - unsigned char *buf, - size_t len, - krb5_data *reply, - const char *from, - struct sockaddr_in *addr) -{ - krb5_storage *sp; - krb5_error_code ret = EINVAL; - hdb_entry_ex *client = NULL, *server = NULL; - Key *ckey, *skey; - int8_t pvno; - int8_t msg_type; - int lsb; - char *name = NULL, *inst = NULL, *realm = NULL; - char *sname = NULL, *sinst = NULL; - int32_t req_time; - time_t max_life; - uint8_t life; - char client_name[256]; - char server_name[256]; - - if(!config->enable_v4) { - kdc_log(context, config, 0, - "Rejected version 4 request from %s", from); - make_err_reply(context, reply, KRB4ET_KDC_GEN_ERR, - "Function not enabled"); - return 0; - } - - sp = krb5_storage_from_mem(buf, len); - RCHECK(krb5_ret_int8(sp, &pvno), out); - if(pvno != 4){ - kdc_log(context, config, 0, - "Protocol version mismatch (krb4) (%d)", pvno); - make_err_reply(context, reply, KRB4ET_KDC_PKT_VER, "protocol mismatch"); - ret = KRB4ET_KDC_PKT_VER; - goto out; - } - RCHECK(krb5_ret_int8(sp, &msg_type), out); - lsb = msg_type & 1; - msg_type &= ~1; - switch(msg_type){ - case AUTH_MSG_KDC_REQUEST: { - krb5_data ticket, cipher; - krb5_keyblock session; - - krb5_data_zero(&ticket); - krb5_data_zero(&cipher); - - RCHECK(krb5_ret_stringz(sp, &name), out1); - RCHECK(krb5_ret_stringz(sp, &inst), out1); - RCHECK(krb5_ret_stringz(sp, &realm), out1); - RCHECK(krb5_ret_int32(sp, &req_time), out1); - if(lsb) - req_time = swap32(req_time); - RCHECK(krb5_ret_uint8(sp, &life), out1); - RCHECK(krb5_ret_stringz(sp, &sname), out1); - RCHECK(krb5_ret_stringz(sp, &sinst), out1); - snprintf (client_name, sizeof(client_name), - "%s.%s@%s", name, inst, realm); - snprintf (server_name, sizeof(server_name), - "%s.%s@%s", sname, sinst, config->v4_realm); - - kdc_log(context, config, 0, "AS-REQ (krb4) %s from %s for %s", - client_name, from, server_name); - - ret = _kdc_db_fetch4(context, config, name, inst, realm, - HDB_F_GET_CLIENT, &client); - if(ret) { - kdc_log(context, config, 0, "Client not found in database: %s: %s", - client_name, krb5_get_err_text(context, ret)); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, - "principal unknown"); - goto out1; - } - ret = _kdc_db_fetch4(context, config, sname, sinst, config->v4_realm, - HDB_F_GET_SERVER, &server); - if(ret){ - kdc_log(context, config, 0, "Server not found in database: %s: %s", - server_name, krb5_get_err_text(context, ret)); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, - "principal unknown"); - goto out1; - } - - ret = _kdc_check_flags (context, config, - client, client_name, - server, server_name, - TRUE); - if (ret) { - /* good error code? */ - make_err_reply(context, reply, KRB4ET_KDC_NAME_EXP, - "operation not allowed"); - goto out1; - } - - if (config->enable_v4_per_principal && - client->entry.flags.allow_kerberos4 == 0) - { - kdc_log(context, config, 0, - "Per principal Kerberos 4 flag not turned on for %s", - client_name); - make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, - "allow kerberos4 flag required"); - goto out1; - } - - /* - * There's no way to do pre-authentication in v4 and thus no - * good error code to return if preauthentication is required. - */ - - if (config->require_preauth - || client->entry.flags.require_preauth - || server->entry.flags.require_preauth) { - kdc_log(context, config, 0, - "Pre-authentication required for v4-request: " - "%s for %s", - client_name, server_name); - make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, - "preauth required"); - goto out1; - } - - ret = _kdc_get_des_key(context, client, FALSE, FALSE, &ckey); - if(ret){ - kdc_log(context, config, 0, "no suitable DES key for client"); - make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, - "no suitable DES key for client"); - goto out1; - } - - ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey); - if(ret){ - kdc_log(context, config, 0, "no suitable DES key for server"); - make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, - "no suitable DES key for server"); - goto out1; - } - - max_life = _krb5_krb_life_to_time(0, life); - if(client->entry.max_life) - max_life = min(max_life, *client->entry.max_life); - if(server->entry.max_life) - max_life = min(max_life, *server->entry.max_life); - - life = krb_time_to_life(kdc_time, kdc_time + max_life); - - ret = krb5_generate_random_keyblock(context, - ETYPE_DES_PCBC_NONE, - &session); - if (ret) { - make_err_reply(context, reply, KFAILURE, - "Not enough random i KDC"); - goto out1; - } - - ret = _krb5_krb_create_ticket(context, - 0, - name, - inst, - config->v4_realm, - addr->sin_addr.s_addr, - &session, - life, - kdc_time, - sname, - sinst, - &skey->key, - &ticket); - if (ret) { - krb5_free_keyblock_contents(context, &session); - make_err_reply(context, reply, KFAILURE, - "failed to create v4 ticket"); - goto out1; - } - - ret = _krb5_krb_create_ciph(context, - &session, - sname, - sinst, - config->v4_realm, - life, - server->entry.kvno % 255, - &ticket, - kdc_time, - &ckey->key, - &cipher); - krb5_free_keyblock_contents(context, &session); - krb5_data_free(&ticket); - if (ret) { - make_err_reply(context, reply, KFAILURE, - "Failed to create v4 cipher"); - goto out1; - } - - ret = _krb5_krb_create_auth_reply(context, - name, - inst, - realm, - req_time, - 0, - client->entry.pw_end ? *client->entry.pw_end : 0, - client->entry.kvno % 256, - &cipher, - reply); - krb5_data_free(&cipher); - - out1: - break; - } - case AUTH_MSG_APPL_REQUEST: { - struct _krb5_krb_auth_data ad; - int8_t kvno; - int8_t ticket_len; - int8_t req_len; - krb5_data auth; - int32_t address; - size_t pos; - krb5_principal tgt_princ = NULL; - hdb_entry_ex *tgt = NULL; - Key *tkey; - time_t max_end, actual_end, issue_time; - - memset(&ad, 0, sizeof(ad)); - krb5_data_zero(&auth); - - RCHECK(krb5_ret_int8(sp, &kvno), out2); - RCHECK(krb5_ret_stringz(sp, &realm), out2); - - ret = krb5_425_conv_principal(context, "krbtgt", realm, - config->v4_realm, - &tgt_princ); - if(ret){ - kdc_log(context, config, 0, - "Converting krbtgt principal (krb4): %s", - krb5_get_err_text(context, ret)); - make_err_reply(context, reply, KFAILURE, - "Failed to convert v4 principal (krbtgt)"); - goto out2; - } - - ret = _kdc_db_fetch(context, config, tgt_princ, - HDB_F_GET_KRBTGT, NULL, &tgt); - if(ret){ - char *s; - s = kdc_log_msg(context, config, 0, "Ticket-granting ticket not " - "found in database (krb4): krbtgt.%s@%s: %s", - realm, config->v4_realm, - krb5_get_err_text(context, ret)); - make_err_reply(context, reply, KFAILURE, s); - free(s); - goto out2; - } - - if(tgt->entry.kvno % 256 != kvno){ - kdc_log(context, config, 0, - "tgs-req (krb4) with old kvno %d (current %d) for " - "krbtgt.%s@%s", kvno, tgt->entry.kvno % 256, - realm, config->v4_realm); - make_err_reply(context, reply, KRB4ET_KDC_AUTH_EXP, - "old krbtgt kvno used"); - goto out2; - } - - ret = _kdc_get_des_key(context, tgt, TRUE, FALSE, &tkey); - if(ret){ - kdc_log(context, config, 0, - "no suitable DES key for krbtgt (krb4)"); - make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, - "no suitable DES key for krbtgt"); - goto out2; - } - - RCHECK(krb5_ret_int8(sp, &ticket_len), out2); - RCHECK(krb5_ret_int8(sp, &req_len), out2); - - pos = krb5_storage_seek(sp, ticket_len + req_len, SEEK_CUR); - - auth.data = buf; - auth.length = pos; - - if (config->check_ticket_addresses) - address = addr->sin_addr.s_addr; - else - address = 0; - - ret = _krb5_krb_rd_req(context, &auth, "krbtgt", realm, - config->v4_realm, - address, &tkey->key, &ad); - if(ret){ - kdc_log(context, config, 0, "krb_rd_req: %d", ret); - make_err_reply(context, reply, ret, "failed to parse request"); - goto out2; - } - - RCHECK(krb5_ret_int32(sp, &req_time), out2); - if(lsb) - req_time = swap32(req_time); - RCHECK(krb5_ret_uint8(sp, &life), out2); - RCHECK(krb5_ret_stringz(sp, &sname), out2); - RCHECK(krb5_ret_stringz(sp, &sinst), out2); - snprintf (server_name, sizeof(server_name), - "%s.%s@%s", - sname, sinst, config->v4_realm); - snprintf (client_name, sizeof(client_name), - "%s.%s@%s", - ad.pname, ad.pinst, ad.prealm); - - kdc_log(context, config, 0, "TGS-REQ (krb4) %s from %s for %s", - client_name, from, server_name); - - if(strcmp(ad.prealm, realm)){ - kdc_log(context, config, 0, - "Can't hop realms (krb4) %s -> %s", realm, ad.prealm); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, - "Can't hop realms"); - goto out2; - } - - if (!config->enable_v4_cross_realm && strcmp(realm, config->v4_realm) != 0) { - kdc_log(context, config, 0, - "krb4 Cross-realm %s -> %s disabled", - realm, config->v4_realm); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, - "Can't hop realms"); - goto out2; - } - - if(strcmp(sname, "changepw") == 0){ - kdc_log(context, config, 0, - "Bad request for changepw ticket (krb4)"); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, - "Can't authorize password change based on TGT"); - goto out2; - } - - ret = _kdc_db_fetch4(context, config, ad.pname, ad.pinst, ad.prealm, - HDB_F_GET_CLIENT, &client); - if(ret && ret != HDB_ERR_NOENTRY) { - char *s; - s = kdc_log_msg(context, config, 0, - "Client not found in database: (krb4) %s: %s", - client_name, krb5_get_err_text(context, ret)); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s); - free(s); - goto out2; - } - if (client == NULL && strcmp(ad.prealm, config->v4_realm) == 0) { - char *s; - s = kdc_log_msg(context, config, 0, - "Local client not found in database: (krb4) " - "%s", client_name); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s); - free(s); - goto out2; - } - - ret = _kdc_db_fetch4(context, config, sname, sinst, config->v4_realm, - HDB_F_GET_SERVER, &server); - if(ret){ - char *s; - s = kdc_log_msg(context, config, 0, - "Server not found in database (krb4): %s: %s", - server_name, krb5_get_err_text(context, ret)); - make_err_reply(context, reply, KRB4ET_KDC_PR_UNKNOWN, s); - free(s); - goto out2; - } - - ret = _kdc_check_flags (context, config, - client, client_name, - server, server_name, - FALSE); - if (ret) { - make_err_reply(context, reply, KRB4ET_KDC_NAME_EXP, - "operation not allowed"); - goto out2; - } - - ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey); - if(ret){ - kdc_log(context, config, 0, - "no suitable DES key for server (krb4)"); - make_err_reply(context, reply, KRB4ET_KDC_NULL_KEY, - "no suitable DES key for server"); - goto out2; - } - - max_end = _krb5_krb_life_to_time(ad.time_sec, ad.life); - max_end = min(max_end, _krb5_krb_life_to_time(kdc_time, life)); - if(server->entry.max_life) - max_end = min(max_end, kdc_time + *server->entry.max_life); - if(client && client->entry.max_life) - max_end = min(max_end, kdc_time + *client->entry.max_life); - life = min(life, krb_time_to_life(kdc_time, max_end)); - - issue_time = kdc_time; - actual_end = _krb5_krb_life_to_time(issue_time, life); - while (actual_end > max_end && life > 1) { - /* move them into the next earlier lifetime bracket */ - life--; - actual_end = _krb5_krb_life_to_time(issue_time, life); - } - if (actual_end > max_end) { - /* if life <= 1 and it's still too long, backdate the ticket */ - issue_time -= actual_end - max_end; - } - - { - krb5_data ticket, cipher; - krb5_keyblock session; - - krb5_data_zero(&ticket); - krb5_data_zero(&cipher); - - ret = krb5_generate_random_keyblock(context, - ETYPE_DES_PCBC_NONE, - &session); - if (ret) { - make_err_reply(context, reply, KFAILURE, - "Not enough random i KDC"); - goto out2; - } - - ret = _krb5_krb_create_ticket(context, - 0, - ad.pname, - ad.pinst, - ad.prealm, - addr->sin_addr.s_addr, - &session, - life, - issue_time, - sname, - sinst, - &skey->key, - &ticket); - if (ret) { - krb5_free_keyblock_contents(context, &session); - make_err_reply(context, reply, KFAILURE, - "failed to create v4 ticket"); - goto out2; - } - - ret = _krb5_krb_create_ciph(context, - &session, - sname, - sinst, - config->v4_realm, - life, - server->entry.kvno % 255, - &ticket, - issue_time, - &ad.session, - &cipher); - krb5_free_keyblock_contents(context, &session); - if (ret) { - make_err_reply(context, reply, KFAILURE, - "failed to create v4 cipher"); - goto out2; - } - - ret = _krb5_krb_create_auth_reply(context, - ad.pname, - ad.pinst, - ad.prealm, - req_time, - 0, - 0, - 0, - &cipher, - reply); - krb5_data_free(&cipher); - } - out2: - _krb5_krb_free_auth_data(context, &ad); - if(tgt_princ) - krb5_free_principal(context, tgt_princ); - if(tgt) - _kdc_free_ent(context, tgt); - break; - } - case AUTH_MSG_ERR_REPLY: - ret = EINVAL; - break; - default: - kdc_log(context, config, 0, "Unknown message type (krb4): %d from %s", - msg_type, from); - - make_err_reply(context, reply, KFAILURE, "Unknown message type"); - ret = EINVAL; - } - out: - if(name) - free(name); - if(inst) - free(inst); - if(realm) - free(realm); - if(sname) - free(sname); - if(sinst) - free(sinst); - if(client) - _kdc_free_ent(context, client); - if(server) - _kdc_free_ent(context, server); - krb5_storage_free(sp); - return ret; -} - -krb5_error_code -_kdc_encode_v4_ticket(krb5_context context, - krb5_kdc_configuration *config, - void *buf, size_t len, const EncTicketPart *et, - const PrincipalName *service, size_t *size) -{ - krb5_storage *sp; - krb5_error_code ret; - char name[40], inst[40], realm[40]; - char sname[40], sinst[40]; - - { - krb5_principal princ; - _krb5_principalname2krb5_principal(context, - &princ, - *service, - et->crealm); - ret = krb5_524_conv_principal(context, - princ, - sname, - sinst, - realm); - krb5_free_principal(context, princ); - if(ret) - return ret; - - _krb5_principalname2krb5_principal(context, - &princ, - et->cname, - et->crealm); - - ret = krb5_524_conv_principal(context, - princ, - name, - inst, - realm); - krb5_free_principal(context, princ); - } - if(ret) - return ret; - - sp = krb5_storage_emem(); - - krb5_store_int8(sp, 0); /* flags */ - krb5_store_stringz(sp, name); - krb5_store_stringz(sp, inst); - krb5_store_stringz(sp, realm); - { - unsigned char tmp[4] = { 0, 0, 0, 0 }; - int i; - if(et->caddr){ - for(i = 0; i < et->caddr->len; i++) - if(et->caddr->val[i].addr_type == AF_INET && - et->caddr->val[i].address.length == 4){ - memcpy(tmp, et->caddr->val[i].address.data, 4); - break; - } - } - krb5_storage_write(sp, tmp, sizeof(tmp)); - } - - if((et->key.keytype != ETYPE_DES_CBC_MD5 && - et->key.keytype != ETYPE_DES_CBC_MD4 && - et->key.keytype != ETYPE_DES_CBC_CRC) || - et->key.keyvalue.length != 8) - return -1; - krb5_storage_write(sp, et->key.keyvalue.data, 8); - - { - time_t start = et->starttime ? *et->starttime : et->authtime; - krb5_store_int8(sp, krb_time_to_life(start, et->endtime)); - krb5_store_int32(sp, start); - } - - krb5_store_stringz(sp, sname); - krb5_store_stringz(sp, sinst); - - { - krb5_data data; - krb5_storage_to_data(sp, &data); - krb5_storage_free(sp); - *size = (data.length + 7) & ~7; /* pad to 8 bytes */ - if(*size > len) - return -1; - memset((unsigned char*)buf - *size + 1, 0, *size); - memcpy((unsigned char*)buf - *size + 1, data.data, data.length); - krb5_data_free(&data); - } - return 0; -} - -krb5_error_code -_kdc_get_des_key(krb5_context context, - hdb_entry_ex *principal, krb5_boolean is_server, - krb5_boolean prefer_afs_key, Key **ret_key) -{ - Key *v5_key = NULL, *v4_key = NULL, *afs_key = NULL, *server_key = NULL; - int i; - krb5_enctype etypes[] = { ETYPE_DES_CBC_MD5, - ETYPE_DES_CBC_MD4, - ETYPE_DES_CBC_CRC }; - - for(i = 0; - i < sizeof(etypes)/sizeof(etypes[0]) - && (v5_key == NULL || v4_key == NULL || - afs_key == NULL || server_key == NULL); - ++i) { - Key *key = NULL; - while(hdb_next_enctype2key(context, &principal->entry, etypes[i], &key) == 0) { - if(key->salt == NULL) { - if(v5_key == NULL) - v5_key = key; - } else if(key->salt->type == hdb_pw_salt && - key->salt->salt.length == 0) { - if(v4_key == NULL) - v4_key = key; - } else if(key->salt->type == hdb_afs3_salt) { - if(afs_key == NULL) - afs_key = key; - } else if(server_key == NULL) - server_key = key; - } - } - - if(prefer_afs_key) { - if(afs_key) - *ret_key = afs_key; - else if(v4_key) - *ret_key = v4_key; - else if(v5_key) - *ret_key = v5_key; - else if(is_server && server_key) - *ret_key = server_key; - else - return KRB4ET_KDC_NULL_KEY; - } else { - if(v4_key) - *ret_key = v4_key; - else if(afs_key) - *ret_key = afs_key; - else if(v5_key) - *ret_key = v5_key; - else if(is_server && server_key) - *ret_key = server_key; - else - return KRB4ET_KDC_NULL_KEY; - } - - if((*ret_key)->key.keyvalue.length == 0) - return KRB4ET_KDC_NULL_KEY; - return 0; -} - diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index c715e0812f..941a2e0572 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -90,7 +90,7 @@ _kdc_find_padata(const KDC_REQ *req, int *start, int type) */ krb5_boolean -_kdc_is_weak_expection(krb5_principal principal, krb5_enctype etype) +_kdc_is_weak_exception(krb5_principal principal, krb5_enctype etype) { if (principal->name.name_string.len > 0 && strcmp(principal->name.name_string.val[0], "afs") == 0 && @@ -139,7 +139,7 @@ _kdc_find_etype(krb5_context context, const hdb_entry_ex *princ, Key *key = NULL; if (krb5_enctype_valid(context, etypes[i]) != 0 && - !_kdc_is_weak_expection(princ->entry.principal, etypes[i])) + !_kdc_is_weak_exception(princ->entry.principal, etypes[i])) continue; while (hdb_next_enctype2key(context, &princ->entry, etypes[i], &key) == 0) { @@ -260,7 +260,7 @@ _kdc_encode_reply(krb5_context context, KDC_REP *rep, const EncTicketPart *et, EncKDCRepPart *ek, krb5_enctype etype, int skvno, const EncryptionKey *skey, - int ckvno, const EncryptionKey *ckey, + int ckvno, const EncryptionKey *reply_key, const char **e_text, krb5_data *reply) { @@ -321,7 +321,7 @@ _kdc_encode_reply(krb5_context context, *e_text = "KDC internal error"; return KRB5KRB_ERR_GENERIC; } - ret = krb5_crypto_init(context, ckey, 0, &crypto); + ret = krb5_crypto_init(context, reply_key, 0, &crypto); if (ret) { free(buf); kdc_log(context, config, 0, "krb5_crypto_init failed: %s", @@ -394,18 +394,6 @@ older_enctype(krb5_enctype enctype) } } -static int -only_older_enctype_p(const KDC_REQ *req) -{ - int i; - - for(i = 0; i < req->req_body.etype.len; i++) { - if (!older_enctype(req->req_body.etype.val[i])) - return 0; - } - return 1; -} - /* * */ @@ -461,72 +449,23 @@ make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key) static krb5_error_code get_pa_etype_info(krb5_context context, krb5_kdc_configuration *config, - METHOD_DATA *md, hdb_entry *client, - ENCTYPE *etypes, unsigned int etypes_len) + METHOD_DATA *md, Key *ckey) { krb5_error_code ret = 0; - int i, j; - unsigned int n = 0; ETYPE_INFO pa; unsigned char *buf; size_t len; - pa.len = client->keys.len; - if(pa.len > UINT_MAX/sizeof(*pa.val)) - return ERANGE; - pa.val = malloc(pa.len * sizeof(*pa.val)); + pa.len = 1; + pa.val = calloc(1, sizeof(pa.val[0])); if(pa.val == NULL) return ENOMEM; - memset(pa.val, 0, pa.len * sizeof(*pa.val)); - - for(i = 0; i < client->keys.len; i++) { - for (j = 0; j < n; j++) - if (pa.val[j].etype == client->keys.val[i].key.keytype) - goto skip1; - for(j = 0; j < etypes_len; j++) { - if(client->keys.val[i].key.keytype == etypes[j]) { - if (krb5_enctype_valid(context, etypes[j]) != 0) - continue; - if (!older_enctype(etypes[j])) - continue; - if (n >= pa.len) - krb5_abortx(context, "internal error: n >= p.len"); - if((ret = make_etype_info_entry(context, - &pa.val[n++], - &client->keys.val[i])) != 0) { - free_ETYPE_INFO(&pa); - return ret; - } - break; - } - } - skip1:; - } - for(i = 0; i < client->keys.len; i++) { - /* already added? */ - for(j = 0; j < etypes_len; j++) { - if(client->keys.val[i].key.keytype == etypes[j]) - goto skip2; - } - if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0) - continue; - if (!older_enctype(etypes[j])) - continue; - if (n >= pa.len) - krb5_abortx(context, "internal error: n >= p.len"); - if((ret = make_etype_info_entry(context, - &pa.val[n++], - &client->keys.val[i])) != 0) { - free_ETYPE_INFO(&pa); - return ret; - } - skip2:; - } - if(n < pa.len) { - /* stripped out dups, newer enctypes, and not valid enctypes */ - pa.len = n; + ret = make_etype_info_entry(context, &pa.val[0], ckey); + if (ret) { + free_ETYPE_INFO(&pa); + return ret; } ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret); @@ -623,66 +562,22 @@ make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, Key *key) static krb5_error_code get_pa_etype_info2(krb5_context context, krb5_kdc_configuration *config, - METHOD_DATA *md, hdb_entry *client, - ENCTYPE *etypes, unsigned int etypes_len) + METHOD_DATA *md, Key *ckey) { krb5_error_code ret = 0; - int i, j; - unsigned int n = 0; ETYPE_INFO2 pa; unsigned char *buf; size_t len; - pa.len = client->keys.len; - if(pa.len > UINT_MAX/sizeof(*pa.val)) - return ERANGE; - pa.val = malloc(pa.len * sizeof(*pa.val)); + pa.len = 1; + pa.val = calloc(1, sizeof(pa.val[0])); if(pa.val == NULL) return ENOMEM; - memset(pa.val, 0, pa.len * sizeof(*pa.val)); - - for(i = 0; i < client->keys.len; i++) { - for (j = 0; j < n; j++) - if (pa.val[j].etype == client->keys.val[i].key.keytype) - goto skip1; - for(j = 0; j < etypes_len; j++) { - if(client->keys.val[i].key.keytype == etypes[j]) { - if (krb5_enctype_valid(context, etypes[j]) != 0) - continue; - if (n >= pa.len) - krb5_abortx(context, "internal error: n >= p.len"); - if((ret = make_etype_info2_entry(&pa.val[n++], - &client->keys.val[i])) != 0) { - free_ETYPE_INFO2(&pa); - return ret; - } - break; - } - } - skip1:; - } - /* send enctypes that the client doesn't know about too */ - for(i = 0; i < client->keys.len; i++) { - /* already added? */ - for(j = 0; j < etypes_len; j++) { - if(client->keys.val[i].key.keytype == etypes[j]) - goto skip2; - } - if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0) - continue; - if (n >= pa.len) - krb5_abortx(context, "internal error: n >= p.len"); - if((ret = make_etype_info2_entry(&pa.val[n++], - &client->keys.val[i])) != 0) { - free_ETYPE_INFO2(&pa); - return ret; - } - skip2:; - } - if(n < pa.len) { - /* stripped out dups, and not valid enctypes */ - pa.len = n; + ret = make_etype_info2_entry(&pa.val[0], ckey); + if (ret) { + free_ETYPE_INFO2(&pa); + return ret; } ASN1_MALLOC_ENCODE(ETYPE_INFO2, buf, len, &pa, &len, ret); @@ -712,10 +607,12 @@ log_as_req(krb5_context context, const KDC_REQ_BODY *b) { krb5_error_code ret; - struct rk_strpool *p = NULL; + struct rk_strpool *p; char *str; int i; + p = rk_strpoolprintf(NULL, "%s", "Client supported enctypes: "); + for (i = 0; i < b->etype.len; i++) { ret = krb5_enctype_to_string(context, b->etype.val[i], &str); if (ret == 0) { @@ -733,10 +630,6 @@ log_as_req(krb5_context context, if (p == NULL) p = rk_strpoolprintf(p, "no encryption types"); - str = rk_strpoolcollect(p); - kdc_log(context, config, 0, "Client supported enctypes: %s", str); - free(str); - { char *cet; char *set; @@ -745,21 +638,26 @@ log_as_req(krb5_context context, if(ret == 0) { ret = krb5_enctype_to_string(context, setype, &set); if (ret == 0) { - kdc_log(context, config, 5, "Using %s/%s", cet, set); + p = rk_strpoolprintf(p, ", using %s/%s", cet, set); free(set); } free(cet); } if (ret != 0) - kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype); + p = rk_strpoolprintf(p, ", using enctypes %d/%d", + cetype, setype); } + str = rk_strpoolcollect(p); + kdc_log(context, config, 0, "%s", str); + free(str); + { char fixedstr[128]; unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(), fixedstr, sizeof(fixedstr)); if(*fixedstr) - kdc_log(context, config, 2, "Requested flags: %s", fixedstr); + kdc_log(context, config, 0, "Requested flags: %s", fixedstr); } } @@ -956,6 +854,17 @@ send_pac_p(krb5_context context, KDC_REQ *req) return TRUE; } +krb5_boolean +_kdc_is_anonymous(krb5_context context, krb5_principal principal) +{ + if (principal->name.name_type != KRB5_NT_WELLKNOWN || + principal->name.name_string.len != 2 || + strcmp(principal->name.name_string.val[0], KRB5_WELLKNOWN_NAME) != 0 || + strcmp(principal->name.name_string.val[1], KRB5_ANON_NAME) != 0) + return 0; + return 1; +} + /* * */ @@ -1039,6 +948,7 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; } + ret = krb5_unparse_name(context, client_princ, &client_name); } if (ret) { @@ -1050,6 +960,28 @@ _kdc_as_rep(krb5_context context, kdc_log(context, config, 0, "AS-REQ %s from %s for %s", client_name, from, server_name); + /* + * + */ + + if (_kdc_is_anonymous(context, client_princ)) { + if (!b->kdc_options.request_anonymous) { + kdc_log(context, config, 0, "Anonymous ticket w/o anonymous flag"); + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; + goto out; + } + } else if (b->kdc_options.request_anonymous) { + kdc_log(context, config, 0, + "Request for a anonymous ticket with non " + "anonymous client name: %s", client_name); + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; + goto out; + } + + /* + * + */ + ret = _kdc_db_fetch(context, config, client_princ, HDB_F_GET_CLIENT | flags, NULL, &client); if(ret){ @@ -1069,19 +1001,27 @@ _kdc_as_rep(krb5_context context, goto out; } - ret = _kdc_windc_client_access(context, client, req, &e_data); - if(ret) - goto out; + memset(&et, 0, sizeof(et)); + memset(&ek, 0, sizeof(ek)); - ret = _kdc_check_flags(context, config, - client, client_name, - server, server_name, - TRUE); - if(ret) + /* + * Find the client key for reply encryption and pa-type salt, Pick + * the client key upfront before the other keys because that is + * going to affect what enctypes we are going to use in + * ETYPE-INFO{,2}. + */ + + ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len, + &ckey, &cetype); + if (ret) { + kdc_log(context, config, 0, + "Client (%s) has no support for etypes", client_name); goto out; + } - memset(&et, 0, sizeof(et)); - memset(&ek, 0, sizeof(ek)); + /* + * Pre-auth processing + */ if(req->padata){ int i; @@ -1097,17 +1037,15 @@ _kdc_as_rep(krb5_context context, e_text = "No PKINIT PA found"; i = 0; - if ((pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ))) - ; + pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ); if (pa == NULL) { i = 0; - if((pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN))) - ; + pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN); } if (pa) { char *client_cert = NULL; - ret = _kdc_pk_rd_padata(context, config, req, pa, &pkp); + ret = _kdc_pk_rd_padata(context, config, req, pa, client, &pkp); if (ret) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; kdc_log(context, config, 5, @@ -1127,11 +1065,12 @@ _kdc_as_rep(krb5_context context, e_text = "PKINIT certificate not allowed to " "impersonate principal"; _kdc_pk_free_client_param(context, pkp); - + kdc_log(context, config, 0, "%s", e_text); pkp = NULL; goto out; } + found_pa = 1; et.flags.pre_authent = 1; kdc_log(context, config, 0, @@ -1158,6 +1097,12 @@ _kdc_as_rep(krb5_context context, found_pa = 1; + if (b->kdc_options.request_anonymous) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(context, config, 0, "ENC-TS doesn't support anon"); + goto out; + } + ret = decode_EncryptedData(pa->padata_value.data, pa->padata_value.length, &enc_data, @@ -1206,6 +1151,11 @@ _kdc_as_rep(krb5_context context, &enc_data, &ts_data); krb5_crypto_destroy(context, crypto); + /* + * Since the user might have several keys with the same + * enctype but with diffrent salting, we need to try all + * the keys with the same enctype. + */ if(ret){ krb5_error_code ret2; ret2 = krb5_enctype_to_string(context, @@ -1298,6 +1248,7 @@ _kdc_as_rep(krb5_context context, goto out; } }else if (config->require_preauth + || b->kdc_options.request_anonymous /* hack to force anon */ || client->entry.flags.require_preauth || server->entry.flags.require_preauth) { METHOD_DATA method_data; @@ -1310,6 +1261,10 @@ _kdc_as_rep(krb5_context context, method_data.val = NULL; ret = realloc_method_data(&method_data); + if (ret) { + free_METHOD_DATA(&method_data); + goto out; + } pa = &method_data.val[method_data.len-1]; pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP; pa->padata_value.length = 0; @@ -1317,12 +1272,20 @@ _kdc_as_rep(krb5_context context, #ifdef PKINIT ret = realloc_method_data(&method_data); + if (ret) { + free_METHOD_DATA(&method_data); + goto out; + } pa = &method_data.val[method_data.len-1]; pa->padata_type = KRB5_PADATA_PK_AS_REQ; pa->padata_value.length = 0; pa->padata_value.data = NULL; ret = realloc_method_data(&method_data); + if (ret) { + free_METHOD_DATA(&method_data); + goto out; + } pa = &method_data.val[method_data.len-1]; pa->padata_type = KRB5_PADATA_PK_AS_REQ_WIN; pa->padata_value.length = 0; @@ -1330,22 +1293,37 @@ _kdc_as_rep(krb5_context context, #endif /* - * RFC4120 requires: - * - If the client only knows about old enctypes, then send - * both info replies (we send 'info' first in the list). - * - If the client is 'modern', because it knows about 'new' - * enctype types, then only send the 'info2' reply. + * If there is a client key, send ETYPE_INFO{,2} */ - - /* XXX check ret */ - if (only_older_enctype_p(req)) - ret = get_pa_etype_info(context, config, - &method_data, &client->entry, - b->etype.val, b->etype.len); - /* XXX check ret */ - ret = get_pa_etype_info2(context, config, &method_data, - &client->entry, b->etype.val, b->etype.len); - + if (ckey) { + + /* + * RFC4120 requires: + * - If the client only knows about old enctypes, then send + * both info replies (we send 'info' first in the list). + * - If the client is 'modern', because it knows about 'new' + * enctype types, then only send the 'info2' reply. + * + * Before we send the full list of etype-info data, we pick + * the client key we would have used anyway below, just pick + * that instead. + */ + + if (older_enctype(ckey->key.keytype)) { + ret = get_pa_etype_info(context, config, + &method_data, ckey); + if (ret) { + free_METHOD_DATA(&method_data); + goto out; + } + } + ret = get_pa_etype_info2(context, config, + &method_data, ckey); + if (ret) { + free_METHOD_DATA(&method_data); + goto out; + } + } ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret); free_METHOD_DATA(&method_data); @@ -1363,20 +1341,26 @@ _kdc_as_rep(krb5_context context, } /* - * Find the client key (for preauth ENC-TS verification and reply - * encryption). Then the best encryption type for the KDC and - * last the best session key that shared between the client and - * KDC runtime enctypes. + * Verify flags after the user been required to prove its identity + * with in a preauth mech. */ - ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len, - &ckey, &cetype); - if (ret) { - kdc_log(context, config, 0, - "Client (%s) has no support for etypes", client_name); + ret = _kdc_check_flags(context, config, + client, client_name, + server, server_name, + TRUE); + if(ret) goto out; - } - + + ret = _kdc_windc_client_access(context, client, req, &e_data); + if(ret) + goto out; + + /* + * Selelct the best encryption type for the KDC with out regard to + * the client since the client never needs to read that data. + */ + ret = _kdc_get_preferred_key(context, config, server, server_name, &setype, &skey); @@ -1449,12 +1433,14 @@ _kdc_as_rep(krb5_context context, rep.pvno = 5; rep.msg_type = krb_as_rep; - copy_Realm(&client->entry.principal->realm, &rep.crealm); - if (f.request_anonymous) - _kdc_make_anonymous_principalname (&rep.cname); - else - _krb5_principal2principalname(&rep.cname, - client->entry.principal); + + ret = copy_Realm(&client->entry.principal->realm, &rep.crealm); + if (ret) + goto out; + ret = _krb5_principal2principalname(&rep.cname, client->entry.principal); + if (ret) + goto out; + rep.ticket.tkt_vno = 5; copy_Realm(&server->entry.principal->realm, &rep.ticket.realm); _krb5_principal2principalname(&rep.ticket.sname, @@ -1500,11 +1486,12 @@ _kdc_as_rep(krb5_context context, goto out; } - ret = krb5_generate_random_keyblock(context, sessionetype, &et.key); + ret = copy_PrincipalName(&rep.cname, &et.cname); + if (ret) + goto out; + ret = copy_Realm(&rep.crealm, &et.crealm); if (ret) goto out; - copy_PrincipalName(&rep.cname, &et.cname); - copy_Realm(&rep.crealm, &et.crealm); { time_t start; @@ -1568,8 +1555,6 @@ _kdc_as_rep(krb5_context context, et.transited.tr_type = DOMAIN_X500_COMPRESS; krb5_data_zero(&et.transited.contents); - copy_EncryptionKey(&et.key, &ek.key); - /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded * as 0 and as 0x80 (meaning indefinite length) apart, and is thus * incapable of correctly decoding SEQUENCE OF's of zero length. @@ -1637,12 +1622,12 @@ _kdc_as_rep(krb5_context context, rep.padata->len = 0; rep.padata->val = NULL; - reply_key = &ckey->key; #if PKINIT if (pkp) { + e_text = "Failed to build PK-INIT reply"; ret = _kdc_pk_mk_pa_reply(context, config, pkp, client, - req, req_buffer, - &reply_key, rep.padata); + sessionetype, req, req_buffer, + &reply_key, &et.key, rep.padata); if (ret) goto out; ret = _kdc_add_inital_verified_cas(context, @@ -1651,10 +1636,25 @@ _kdc_as_rep(krb5_context context, &et); if (ret) goto out; - } + } else #endif + if (ckey) { + reply_key = &ckey->key; + ret = krb5_generate_random_keyblock(context, sessionetype, &et.key); + if (ret) + goto out; + } else { + e_text = "Client have no reply key"; + ret = KRB5KDC_ERR_CLIENT_NOTYET; + goto out; + } + + ret = copy_EncryptionKey(&et.key, &ek.key); + if (ret) + goto out; - set_salt_padata (rep.padata, ckey->salt); + if (ckey) + set_salt_padata (rep.padata, ckey->salt); /* Add signing of alias referral */ if (f.canonicalize) { diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index 4cf93e5a54..3abdb18ae4 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -107,7 +107,7 @@ _kdc_add_KRB5SignedPath(krb5_context context, hdb_entry_ex *krbtgt, krb5_enctype enctype, krb5_const_principal server, - KRB5SignedPathPrincipals *principals, + krb5_principals principals, EncTicketPart *tkt) { krb5_error_code ret; @@ -117,7 +117,7 @@ _kdc_add_KRB5SignedPath(krb5_context context, size_t size; if (server && principals) { - ret = add_KRB5SignedPathPrincipals(principals, server); + ret = add_Principals(principals, server); if (ret) return ret; } @@ -186,7 +186,7 @@ check_KRB5SignedPath(krb5_context context, krb5_kdc_configuration *config, hdb_entry_ex *krbtgt, EncTicketPart *tkt, - KRB5SignedPathPrincipals **delegated, + krb5_principals *delegated, int *signedpath) { krb5_error_code ret; @@ -255,7 +255,7 @@ check_KRB5SignedPath(krb5_context context, return ENOMEM; } - ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated); + ret = copy_Principals(*delegated, sp.delegated); if (ret) { free_KRB5SignedPath(&sp); free(*delegated); @@ -668,7 +668,7 @@ tgs_make_reply(krb5_context context, krb5_principal client_principal, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, - KRB5SignedPathPrincipals *spp, + krb5_principals spp, const krb5_data *rspac, const METHOD_DATA *enc_pa_data, const char **e_text, @@ -725,14 +725,13 @@ tgs_make_reply(krb5_context context, PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) || GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), &tgt->transited, &et, - *krb5_princ_realm(context, client_principal), - *krb5_princ_realm(context, server->entry.principal), - *krb5_princ_realm(context, krbtgt->entry.principal)); + krb5_principal_get_realm(context, client_principal), + krb5_principal_get_realm(context, server->entry.principal), + krb5_principal_get_realm(context, krbtgt->entry.principal)); if(ret) goto out; - copy_Realm(krb5_princ_realm(context, server_principal), - &rep.ticket.realm); + copy_Realm(&server_principal->realm, &rep.ticket.realm); _krb5_principal2principalname(&rep.ticket.sname, server_principal); copy_Realm(&tgt_name->realm, &rep.crealm); /* @@ -888,7 +887,7 @@ tgs_make_reply(krb5_context context, } if (krb5_enctype_valid(context, et.key.keytype) != 0 - && _kdc_is_weak_expection(server->entry.principal, et.key.keytype)) + && _kdc_is_weak_exception(server->entry.principal, et.key.keytype)) { krb5_enctype_enable(context, et.key.keytype); is_weak = 1; @@ -1035,7 +1034,7 @@ need_referral(krb5_context context, krb5_kdc_configuration *config, if (server->name.name_string.len == 1) name = server->name.name_string.val[0]; - if (server->name.name_string.len > 1) + else if (server->name.name_string.len > 1) name = server->name.name_string.val[1]; else return FALSE; @@ -1205,9 +1204,7 @@ tgs_parse_request(krb5_context context, krb5_keyblock *subkey; krb5_data ad; - ret = krb5_auth_con_getremotesubkey(context, - ac, - &subkey); + ret = krb5_auth_con_getremotesubkey(context, ac, &subkey); if(ret){ krb5_auth_con_free(context, ac); kdc_log(context, config, 0, "Failed to get remote subkey: %s", @@ -1232,6 +1229,7 @@ tgs_parse_request(krb5_context context, goto out; } ret = krb5_crypto_init(context, subkey, 0, &crypto); + krb5_free_keyblock(context, subkey); if (ret) { krb5_auth_con_free(context, ac); kdc_log(context, config, 0, "krb5_crypto_init failed: %s", @@ -1251,7 +1249,6 @@ tgs_parse_request(krb5_context context, ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ goto out; } - krb5_free_keyblock(context, subkey); ALLOC(*auth_data); if (*auth_data == NULL) { krb5_auth_con_free(context, ac); @@ -1365,8 +1362,7 @@ tgs_build_reply(krb5_context context, const char *from, const char **e_text, AuthorizationData **auth_data, - const struct sockaddr *from_addr, - int datagram_reply) + const struct sockaddr *from_addr) { krb5_error_code ret; krb5_principal cp = NULL, sp = NULL; @@ -1375,13 +1371,11 @@ tgs_build_reply(krb5_context context, hdb_entry_ex *server = NULL, *client = NULL; krb5_realm ref_realm = NULL; EncTicketPart *tgt = &ticket->ticket; - KRB5SignedPathPrincipals *spp = NULL; - Key *tkey; + krb5_principals spp = NULL; const EncryptionKey *ekey; krb5_keyblock sessionkey; krb5_kvno kvno; krb5_data rspac; - int cross_realm = 0; METHOD_DATA enc_pa_data; @@ -1392,6 +1386,8 @@ tgs_build_reply(krb5_context context, char opt_str[128]; int signedpath = 0; + Key *tkey; + memset(&sessionkey, 0, sizeof(sessionkey)); memset(&adtkt, 0, sizeof(adtkt)); krb5_data_zero(&rspac); @@ -1559,8 +1555,6 @@ server_lookup: kdc_log(context, config, 1, "Client not found in database: %s: %s", cpn, krb5_get_err_text(context, ret)); - - cross_realm = 1; } /* @@ -1578,9 +1572,10 @@ server_lookup: break; if(i == b->etype.len) { kdc_log(context, config, 0, - "Addition ticket have not matching etypes", spp); + "Addition ticket have not matching etypes"); krb5_clear_error_message(context); - return KRB5KDC_ERR_ETYPE_NOSUPP; + ret = KRB5KDC_ERR_ETYPE_NOSUPP; + goto out; } etype = b->etype.val[i]; kvno = 0; @@ -1592,7 +1587,7 @@ server_lookup: if(ret) { kdc_log(context, config, 0, "Server (%s) has no support for etypes", spn); - return ret; + goto out; } ekey = &skey->key; kvno = server->entry.kvno; @@ -1604,10 +1599,6 @@ server_lookup: } /* - * Validate authoriation data - */ - - /* * Check that service is in the same realm as the krbtgt. If it's * not the same, it's someone that is using a uni-directional trust * backward. @@ -1628,13 +1619,15 @@ server_lookup: goto out; } - /* check PAC if there is one */ + /* + * Validate authoriation data + */ ret = hdb_enctype2key(context, &krbtgt->entry, krbtgt_etype, &tkey); if(ret) { kdc_log(context, config, 0, - "Failed to find key for krbtgt PAC check"); + "Failed to find key for krbtgt PAC check"); goto out; } @@ -1672,7 +1665,7 @@ server_lookup: const PA_DATA *sdata; int i = 0; - sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF); + sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER); if (sdata) { krb5_crypto crypto; krb5_data datack; @@ -2044,8 +2037,7 @@ _kdc_tgs_rep(krb5_context context, from, &e_text, &auth_data, - from_addr, - datagram_reply); + from_addr); if (ret) { kdc_log(context, config, 0, "Failed building TGS-REP to %s", from); diff --git a/source4/heimdal/kdc/kx509.c b/source4/heimdal/kdc/kx509.c index 83e05b81c5..8f7f3a27fb 100644 --- a/source4/heimdal/kdc/kx509.c +++ b/source4/heimdal/kdc/kx509.c @@ -36,14 +36,14 @@ #include <rfc2459_asn1.h> #include <hx509.h> -RCSID("$Id$"); +#ifdef KX509 /* * */ krb5_error_code -_kdc_try_kx509_request(void *ptr, size_t len, Kx509Request *req, size_t *size) +_kdc_try_kx509_request(void *ptr, size_t len, struct Kx509Request *req, size_t *size) { if (len < 4) return -1; @@ -97,16 +97,15 @@ calculate_reply_hash(krb5_context context, krb5_keyblock *key, Kx509Response *rep) { + krb5_error_code ret; HMAC_CTX ctx; HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, - key->keyvalue.data, key->keyvalue.length, + HMAC_Init_ex(&ctx, key->keyvalue.data, key->keyvalue.length, EVP_sha1(), NULL); - rep->hash->length = HMAC_size(&ctx); - rep->hash->data = malloc(rep->hash->length); - if (rep->hash->data == NULL) { + ret = krb5_data_alloc(rep->hash, HMAC_size(&ctx)); + if (ret) { HMAC_CTX_cleanup(&ctx); krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; @@ -208,7 +207,7 @@ build_certificate(krb5_context context, spki.subjectPublicKey.data = key->data; spki.subjectPublicKey.length = key->length * 8; - ret = der_copy_oid(oid_id_pkcs1_rsaEncryption(), + ret = der_copy_oid(&asn1_oid_id_pkcs1_rsaEncryption, &spki.algorithm.algorithm); any.data = "\x05\x00"; @@ -289,7 +288,7 @@ out: krb5_error_code _kdc_do_kx509(krb5_context context, krb5_kdc_configuration *config, - const Kx509Request *req, krb5_data *reply, + const struct Kx509Request *req, krb5_data *reply, const char *from, struct sockaddr *addr) { krb5_error_code ret; @@ -385,8 +384,10 @@ _kdc_do_kx509(krb5_context context, if (ret) goto out; free_RSAPublicKey(&key); - if (size != req->pk_key.length) - ; + if (size != req->pk_key.length) { + ret = ASN1_EXTRA_DATA; + goto out; + } } ALLOC(rep.certificate); @@ -458,3 +459,5 @@ out: return 0; } + +#endif /* KX509 */ diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c index 82358682d8..22734be811 100644 --- a/source4/heimdal/kdc/pkinit.c +++ b/source4/heimdal/kdc/pkinit.c @@ -47,14 +47,26 @@ RCSID("$Id$"); struct pk_client_params { enum krb5_pk_type type; - BIGNUM *dh_public_key; + enum { USE_RSA, USE_DH, USE_ECDH } keyex; + union { + struct { + BIGNUM *public_key; + DH *key; + } dh; +#ifdef HAVE_OPENSSL + struct { + EC_KEY *public_key; + EC_KEY *key; + } ecdh; +#endif + } u; hx509_cert cert; unsigned nonce; - DH *dh; EncryptionKey reply_key; char *dh_group_name; hx509_peer_info peer; hx509_certs client_anchors; + hx509_verify_ctx verify_ctx; }; struct pk_principal_mapping { @@ -155,29 +167,43 @@ out: } void -_kdc_pk_free_client_param(krb5_context context, - pk_client_params *client_params) +_kdc_pk_free_client_param(krb5_context context, pk_client_params *cp) { - if (client_params->cert) - hx509_cert_free(client_params->cert); - if (client_params->dh) - DH_free(client_params->dh); - if (client_params->dh_public_key) - BN_free(client_params->dh_public_key); - krb5_free_keyblock_contents(context, &client_params->reply_key); - if (client_params->dh_group_name) - free(client_params->dh_group_name); - if (client_params->peer) - hx509_peer_info_free(client_params->peer); - if (client_params->client_anchors) - hx509_certs_free(&client_params->client_anchors); - memset(client_params, 0, sizeof(*client_params)); - free(client_params); + if (cp == NULL) + return; + if (cp->cert) + hx509_cert_free(cp->cert); + if (cp->verify_ctx) + hx509_verify_destroy_ctx(cp->verify_ctx); + if (cp->keyex == USE_DH) { + if (cp->u.dh.key) + DH_free(cp->u.dh.key); + if (cp->u.dh.public_key) + BN_free(cp->u.dh.public_key); + } +#ifdef HAVE_OPENSSL + if (cp->keyex == USE_ECDH) { + if (cp->u.ecdh.key) + EC_KEY_free(cp->u.ecdh.key); + if (cp->u.ecdh.public_key) + EC_KEY_free(cp->u.ecdh.public_key); + } +#endif + krb5_free_keyblock_contents(context, &cp->reply_key); + if (cp->dh_group_name) + free(cp->dh_group_name); + if (cp->peer) + hx509_peer_info_free(cp->peer); + if (cp->client_anchors) + hx509_certs_free(&cp->client_anchors); + memset(cp, 0, sizeof(*cp)); + free(cp); } static krb5_error_code -generate_dh_keyblock(krb5_context context, pk_client_params *client_params, - krb5_enctype enctype, krb5_keyblock *reply_key) +generate_dh_keyblock(krb5_context context, + pk_client_params *client_params, + krb5_enctype enctype) { unsigned char *dh_gen_key = NULL; krb5_keyblock key; @@ -186,36 +212,84 @@ generate_dh_keyblock(krb5_context context, pk_client_params *client_params, memset(&key, 0, sizeof(key)); - if (!DH_generate_key(client_params->dh)) { - ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, "Can't generate Diffie-Hellman keys"); - goto out; - } - if (client_params->dh_public_key == NULL) { - ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, "dh_public_key"); - goto out; - } + if (client_params->keyex == USE_DH) { - dh_gen_keylen = DH_size(client_params->dh); - size = BN_num_bytes(client_params->dh->p); - if (size < dh_gen_keylen) - size = dh_gen_keylen; + if (client_params->u.dh.public_key == NULL) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, "public_key"); + goto out; + } - dh_gen_key = malloc(size); - if (dh_gen_key == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, "malloc: out of memory"); - goto out; - } - memset(dh_gen_key, 0, size - dh_gen_keylen); + if (!DH_generate_key(client_params->u.dh.key)) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + "Can't generate Diffie-Hellman keys"); + goto out; + } + + dh_gen_keylen = DH_size(client_params->u.dh.key); + size = BN_num_bytes(client_params->u.dh.key->p); + if (size < dh_gen_keylen) + size = dh_gen_keylen; + + dh_gen_key = malloc(size); + if (dh_gen_key == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + memset(dh_gen_key, 0, size - dh_gen_keylen); + + dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), + client_params->u.dh.public_key, + client_params->u.dh.key); + if (dh_gen_keylen == -1) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + "Can't compute Diffie-Hellman key"); + goto out; + } + ret = 0; +#ifdef HAVE_OPENSSL + } else if (client_params->keyex == USE_ECDH) { + + if (client_params->u.ecdh.public_key == NULL) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, "public_key"); + goto out; + } + + client_params->u.ecdh.key = EC_KEY_new(); + if (client_params->u.ecdh.key == NULL) { + ret = ENOMEM; + goto out; + } + EC_KEY_set_group(client_params->u.ecdh.key, + EC_KEY_get0_group(client_params->u.ecdh.public_key)); - dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), - client_params->dh_public_key, - client_params->dh); - if (dh_gen_keylen == -1) { + if (EC_KEY_generate_key(client_params->u.ecdh.key) != 1) { + ret = ENOMEM; + goto out; + } + + size = (EC_GROUP_get_degree(EC_KEY_get0_group(client_params->u.ecdh.key)) + 7) / 8; + dh_gen_key = malloc(size); + if (dh_gen_key == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto out; + } + + dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, + EC_KEY_get0_public_key(client_params->u.ecdh.public_key), + client_params->u.ecdh.key, NULL); + ret = 0; +#endif /* HAVE_OPENSSL */ + } else { ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, "Can't compute Diffie-Hellman key"); + krb5_set_error_message(context, ret, + "Diffie-Hellman not selected keys"); goto out; } @@ -223,7 +297,7 @@ generate_dh_keyblock(krb5_context context, pk_client_params *client_params, enctype, dh_gen_key, dh_gen_keylen, NULL, NULL, - reply_key); + &client_params->reply_key); out: if (dh_gen_key) @@ -261,10 +335,12 @@ get_dh_param(krb5_context context, memset(&dhparam, 0, sizeof(dhparam)); - if (der_heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) { - krb5_set_error_message(context, KRB5_BADMSGTYPE, - "PKINIT invalid oid in clientPublicValue"); - return KRB5_BADMSGTYPE; + if ((dh_key_info->subjectPublicKey.length % 8) != 0) { + ret = KRB5_BADMSGTYPE; + krb5_set_error_message(context, ret, + "PKINIT: subjectPublicKey not aligned " + "to 8 bit boundary"); + goto out; } if (dh_key_info->algorithm.parameters == NULL) { @@ -284,15 +360,6 @@ get_dh_param(krb5_context context, goto out; } - if ((dh_key_info->subjectPublicKey.length % 8) != 0) { - ret = KRB5_BADMSGTYPE; - krb5_set_error_message(context, ret, - "PKINIT: subjectPublicKey not aligned " - "to 8 bit boundary"); - goto out; - } - - ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits, &dhparam.p, &dhparam.g, &dhparam.q, moduli, &client_params->dh_group_name); @@ -331,17 +398,17 @@ get_dh_param(krb5_context context, return ret; } - client_params->dh_public_key = integer_to_BN(context, - "subjectPublicKey", - &glue); + client_params->u.dh.public_key = integer_to_BN(context, + "subjectPublicKey", + &glue); der_free_heim_integer(&glue); - if (client_params->dh_public_key == NULL) { + if (client_params->u.dh.public_key == NULL) { ret = KRB5_BADMSGTYPE; goto out; } } - client_params->dh = dh; + client_params->u.dh.key = dh; dh = NULL; ret = 0; @@ -352,20 +419,88 @@ get_dh_param(krb5_context context, return ret; } +#ifdef HAVE_OPENSSL + +static krb5_error_code +get_ecdh_param(krb5_context context, + krb5_kdc_configuration *config, + SubjectPublicKeyInfo *dh_key_info, + pk_client_params *client_params) +{ + ECParameters ecp; + EC_KEY *public = NULL; + krb5_error_code ret; + const unsigned char *p; + size_t len; + int nid; + + if (dh_key_info->algorithm.parameters == NULL) { + krb5_set_error_message(context, KRB5_BADMSGTYPE, + "PKINIT missing algorithm parameter " + "in clientPublicValue"); + return KRB5_BADMSGTYPE; + } + + memset(&ecp, 0, sizeof(ecp)); + + ret = decode_ECParameters(dh_key_info->algorithm.parameters->data, + dh_key_info->algorithm.parameters->length, &ecp, &len); + if (ret) + goto out; + + if (ecp.element != choice_ECParameters_namedCurve) { + ret = KRB5_BADMSGTYPE; + goto out; + } + + if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0) + nid = NID_X9_62_prime256v1; + else { + ret = KRB5_BADMSGTYPE; + goto out; + } + + /* XXX verify group is ok */ + + public = EC_KEY_new_by_curve_name(nid); + + p = dh_key_info->subjectPublicKey.data; + len = dh_key_info->subjectPublicKey.length / 8; + if (o2i_ECPublicKey(&public, &p, len) == NULL) { + ret = KRB5_BADMSGTYPE; + krb5_set_error_message(context, ret, + "PKINIT failed to decode ECDH key"); + goto out; + } + client_params->u.ecdh.public_key = public; + public = NULL; + + out: + if (public) + EC_KEY_free(public); + free_ECParameters(&ecp); + return ret; +} + +#endif /* HAVE_OPENSSL */ + krb5_error_code _kdc_pk_rd_padata(krb5_context context, krb5_kdc_configuration *config, const KDC_REQ *req, const PA_DATA *pa, + hdb_entry_ex *client, pk_client_params **ret_params) { - pk_client_params *client_params; + pk_client_params *cp; krb5_error_code ret; heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL }; krb5_data eContent = { 0, NULL }; krb5_data signed_content = { 0, NULL }; const char *type = "unknown type"; + hx509_certs trust_anchors; int have_data = 0; + const HDB_Ext_PKINIT_cert *pc; *ret_params = NULL; @@ -375,20 +510,73 @@ _kdc_pk_rd_padata(krb5_context context, return 0; } - hx509_verify_set_time(kdc_identity->verify_ctx, kdc_time); - - client_params = calloc(1, sizeof(*client_params)); - if (client_params == NULL) { + cp = calloc(1, sizeof(*cp)); + if (cp == NULL) { krb5_clear_error_message(context); ret = ENOMEM; goto out; } + ret = hx509_certs_init(kdc_identity->hx509ctx, + "MEMORY:trust-anchors", + 0, NULL, &trust_anchors); + if (ret) { + krb5_set_error_message(context, ret, "failed to create trust anchors"); + goto out; + } + + ret = hx509_certs_merge(kdc_identity->hx509ctx, trust_anchors, + kdc_identity->anchors); + if (ret) { + hx509_certs_free(&trust_anchors); + krb5_set_error_message(context, ret, "failed to create verify context"); + goto out; + } + + /* Add any registered certificates for this client as trust anchors */ + ret = hdb_entry_get_pkinit_cert(&client->entry, &pc); + if (ret == 0 && pc != NULL) { + hx509_cert cert; + unsigned int i; + + for (i = 0; i < pc->len; i++) { + ret = hx509_cert_init_data(kdc_identity->hx509ctx, + pc->val[i].cert.data, + pc->val[i].cert.length, + &cert); + if (ret) + continue; + hx509_certs_add(kdc_identity->hx509ctx, trust_anchors, cert); + hx509_cert_free(cert); + } + } + + ret = hx509_verify_init_ctx(kdc_identity->hx509ctx, &cp->verify_ctx); + if (ret) { + hx509_certs_free(&trust_anchors); + krb5_set_error_message(context, ret, "failed to create verify context"); + goto out; + } + + hx509_verify_set_time(cp->verify_ctx, kdc_time); + hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors); + hx509_certs_free(&trust_anchors); + + if (config->pkinit_allow_proxy_certs) + hx509_verify_set_proxy_certificate(cp->verify_ctx, 1); + if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { PA_PK_AS_REQ_Win2k r; type = "PK-INIT-Win2k"; + if (req->req_body.kdc_options.request_anonymous) { + ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; + krb5_set_error_message(context, ret, + "Anon not supported in RSA mode"); + goto out; + } + ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data, pa->padata_value.length, &r, @@ -406,7 +594,7 @@ _kdc_pk_rd_padata(krb5_context context, free_PA_PK_AS_REQ_Win2k(&r); if (ret) { krb5_set_error_message(context, ret, - "Can't decode PK-AS-REQ: %d", ret); + "Can't unwrap ContentInfo(win): %d", ret); goto out; } @@ -420,25 +608,35 @@ _kdc_pk_rd_padata(krb5_context context, &r, NULL); if (ret) { - krb5_set_error_message(context, ret, "Can't decode PK-AS-REQ: %d", ret); + krb5_set_error_message(context, ret, + "Can't decode PK-AS-REQ: %d", ret); goto out; } /* XXX look at r.kdcPkId */ if (r.trustedCertifiers) { ExternalPrincipalIdentifiers *edi = r.trustedCertifiers; - unsigned int i; + unsigned int i, maxedi; ret = hx509_certs_init(kdc_identity->hx509ctx, "MEMORY:client-anchors", 0, NULL, - &client_params->client_anchors); + &cp->client_anchors); if (ret) { - krb5_set_error_message(context, ret, "Can't allocate client anchors: %d", ret); + krb5_set_error_message(context, ret, + "Can't allocate client anchors: %d", + ret); goto out; } - for (i = 0; i < edi->len; i++) { + /* + * If the client sent more then 10 EDI, don't bother + * looking more then 10 of performance reasons. + */ + maxedi = edi->len; + if (maxedi > 10) + maxedi = 10; + for (i = 0; i < maxedi; i++) { IssuerAndSerialNumber iasn; hx509_query *q; hx509_cert cert; @@ -464,8 +662,10 @@ _kdc_pk_rd_padata(krb5_context context, } ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber); free_IssuerAndSerialNumber(&iasn); - if (ret) + if (ret) { + hx509_query_free(kdc_identity->hx509ctx, q); continue; + } ret = hx509_certs_find(kdc_identity->hx509ctx, kdc_identity->certs, @@ -475,7 +675,7 @@ _kdc_pk_rd_padata(krb5_context context, if (ret) continue; hx509_certs_add(kdc_identity->hx509ctx, - client_params->client_anchors, cert); + cp->client_anchors, cert); hx509_cert_free(cert); } } @@ -497,7 +697,7 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - ret = der_heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData()); + ret = der_heim_oid_cmp(&contentInfoOid, &asn1_oid_id_pkcs7_signedData); if (ret != 0) { ret = KRB5KRB_ERR_GENERIC; krb5_set_error_message(context, ret, @@ -514,9 +714,14 @@ _kdc_pk_rd_padata(krb5_context context, { hx509_certs signer_certs; + int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */ + + if (req->req_body.kdc_options.request_anonymous) + flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER; ret = hx509_cms_verify_signed(kdc_identity->hx509ctx, - kdc_identity->verify_ctx, + cp->verify_ctx, + flags, signed_content.data, signed_content.length, NULL, @@ -532,16 +737,18 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs, - &client_params->cert); - hx509_certs_free(&signer_certs); + if (signer_certs) { + ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs, + &cp->cert); + hx509_certs_free(&signer_certs); + } if (ret) goto out; } /* Signature is correct, now verify the signed message */ - if (der_heim_oid_cmp(&eContentType, oid_id_pkcs7_data()) != 0 && - der_heim_oid_cmp(&eContentType, oid_id_pkauthdata()) != 0) + if (der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkcs7_data) != 0 && + der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkauthdata) != 0) { ret = KRB5_BADMSGTYPE; krb5_set_error_message(context, ret, "got wrong oid for pkauthdata"); @@ -556,7 +763,8 @@ _kdc_pk_rd_padata(krb5_context context, &ap, NULL); if (ret) { - krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret); + krb5_set_error_message(context, ret, + "Can't decode AuthPack: %d", ret); goto out; } @@ -568,12 +776,13 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - client_params->type = PKINIT_WIN2K; - client_params->nonce = ap.pkAuthenticator.nonce; + cp->type = PKINIT_WIN2K; + cp->nonce = ap.pkAuthenticator.nonce; if (ap.clientPublicValue) { ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, "DH not supported for windows"); + krb5_set_error_message(context, ret, + "DH not supported for windows"); goto out; } free_AuthPack_Win2k(&ap); @@ -586,11 +795,21 @@ _kdc_pk_rd_padata(krb5_context context, &ap, NULL); if (ret) { - krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret); + krb5_set_error_message(context, ret, + "Can't decode AuthPack: %d", ret); free_AuthPack(&ap); goto out; } + if (req->req_body.kdc_options.request_anonymous && + ap.clientPublicValue == NULL) { + free_AuthPack(&ap); + ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; + krb5_set_error_message(context, ret, + "Anon not supported in RSA mode"); + goto out; + } + ret = pk_check_pkauthenticator(context, &ap.pkAuthenticator, req); @@ -599,33 +818,55 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - client_params->type = PKINIT_27; - client_params->nonce = ap.pkAuthenticator.nonce; + cp->type = PKINIT_27; + cp->nonce = ap.pkAuthenticator.nonce; if (ap.clientPublicValue) { - ret = get_dh_param(context, config, - ap.clientPublicValue, client_params); + if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) { + cp->keyex = USE_DH; + ret = get_dh_param(context, config, + ap.clientPublicValue, cp); +#ifdef HAVE_OPENSSL + } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) { + cp->keyex = USE_ECDH; + ret = get_ecdh_param(context, config, + ap.clientPublicValue, cp); +#endif /* HAVE_OPENSSL */ + } else { + ret = KRB5_BADMSGTYPE; + krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism"); + } if (ret) { free_AuthPack(&ap); goto out; } - } + } else + cp->keyex = USE_RSA; + ret = hx509_peer_info_alloc(kdc_identity->hx509ctx, + &cp->peer); + if (ret) { + free_AuthPack(&ap); + goto out; + } + if (ap.supportedCMSTypes) { - ret = hx509_peer_info_alloc(kdc_identity->hx509ctx, - &client_params->peer); - if (ret) { - free_AuthPack(&ap); - goto out; - } ret = hx509_peer_info_set_cms_algs(kdc_identity->hx509ctx, - client_params->peer, + cp->peer, ap.supportedCMSTypes->val, ap.supportedCMSTypes->len); if (ret) { free_AuthPack(&ap); goto out; } + } else { + /* assume old client */ + hx509_peer_info_add_cms_alg(kdc_identity->hx509ctx, cp->peer, + hx509_crypto_des_rsdi_ede3_cbc()); + hx509_peer_info_add_cms_alg(kdc_identity->hx509ctx, cp->peer, + hx509_signature_rsa_with_sha1()); + hx509_peer_info_add_cms_alg(kdc_identity->hx509ctx, cp->peer, + hx509_signature_sha1()); } free_AuthPack(&ap); } else @@ -642,10 +883,10 @@ out: krb5_data_free(&eContent); der_free_oid(&eContentType); der_free_oid(&contentInfoOid); - if (ret) - _kdc_pk_free_client_param(context, client_params); - else - *ret_params = client_params; + if (ret) { + _kdc_pk_free_client_param(context, cp); + } else + *ret_params = cp; return ret; } @@ -670,11 +911,12 @@ BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) static krb5_error_code pk_mk_pa_reply_enckey(krb5_context context, krb5_kdc_configuration *config, - pk_client_params *client_params, + pk_client_params *cp, const KDC_REQ *req, const krb5_data *req_buffer, krb5_keyblock *reply_key, - ContentInfo *content_info) + ContentInfo *content_info, + hx509_cert *kdc_cert) { const heim_oid *envelopedAlg = NULL, *sdAlg = NULL, *evAlg = NULL; krb5_error_code ret; @@ -685,13 +927,15 @@ pk_mk_pa_reply_enckey(krb5_context context, krb5_data_zero(&buf); krb5_data_zero(&signed_data); + *kdc_cert = NULL; + /* * If the message client is a win2k-type but it send pa data * 09-binding it expects a IETF (checksum) reply so there can be * no replay attacks. */ - switch (client_params->type) { + switch (cp->type) { case PKINIT_WIN2K: { int i = 0; if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL @@ -699,14 +943,14 @@ pk_mk_pa_reply_enckey(krb5_context context, { do_win2k = 1; } - sdAlg = oid_id_pkcs7_data(); - evAlg = oid_id_pkcs7_data(); - envelopedAlg = oid_id_rsadsi_des_ede3_cbc(); + sdAlg = &asn1_oid_id_pkcs7_data; + evAlg = &asn1_oid_id_pkcs7_data; + envelopedAlg = &asn1_oid_id_rsadsi_des_ede3_cbc; break; } case PKINIT_27: - sdAlg = oid_id_pkrkeydata(); - evAlg = oid_id_pkcs7_signedData(); + sdAlg = &asn1_oid_id_pkrkeydata; + evAlg = &asn1_oid_id_pkcs7_signedData; break; default: krb5_abortx(context, "internal pkinit error"); @@ -721,7 +965,7 @@ pk_mk_pa_reply_enckey(krb5_context context, krb5_clear_error_message(context); goto out; } - kp.nonce = client_params->nonce; + kp.nonce = cp->nonce; ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k, buf.data, buf.length, @@ -777,7 +1021,8 @@ pk_mk_pa_reply_enckey(krb5_context context, goto out; hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); - hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + if (config->pkinit_kdc_friendly_name) + hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); ret = hx509_certs_find(kdc_identity->hx509ctx, kdc_identity->certs, @@ -794,19 +1039,19 @@ pk_mk_pa_reply_enckey(krb5_context context, buf.length, NULL, cert, - client_params->peer, - client_params->client_anchors, + cp->peer, + cp->client_anchors, kdc_identity->certpool, &signed_data); - hx509_cert_free(cert); + *kdc_cert = cert; } krb5_data_free(&buf); if (ret) goto out; - if (client_params->type == PKINIT_WIN2K) { - ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), + if (cp->type == PKINIT_WIN2K) { + ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &signed_data, &buf); if (ret) @@ -816,8 +1061,8 @@ pk_mk_pa_reply_enckey(krb5_context context, } ret = hx509_cms_envelope_1(kdc_identity->hx509ctx, - 0, - client_params->cert, + HX509_CMS_EV_NO_KU_CHECK, + cp->cert, signed_data.data, signed_data.length, envelopedAlg, evAlg, &buf); @@ -826,9 +1071,14 @@ pk_mk_pa_reply_enckey(krb5_context context, ret = _krb5_pk_mk_ContentInfo(context, &buf, - oid_id_pkcs7_envelopedData(), + &asn1_oid_id_pkcs7_envelopedData, content_info); out: + if (ret && *kdc_cert) { + hx509_cert_free(*kdc_cert); + *kdc_cert = NULL; + } + krb5_data_free(&buf); krb5_data_free(&signed_data); return ret; @@ -840,9 +1090,8 @@ out: static krb5_error_code pk_mk_pa_reply_dh(krb5_context context, - DH *kdc_dh, - pk_client_params *client_params, - krb5_keyblock *reply_key, + krb5_kdc_configuration *config, + pk_client_params *cp, ContentInfo *content_info, hx509_cert *kdc_cert) { @@ -850,33 +1099,63 @@ pk_mk_pa_reply_dh(krb5_context context, krb5_data signed_data, buf; ContentInfo contentinfo; krb5_error_code ret; + hx509_cert cert; + hx509_query *q; size_t size; - heim_integer i; memset(&contentinfo, 0, sizeof(contentinfo)); memset(&dh_info, 0, sizeof(dh_info)); - krb5_data_zero(&buf); krb5_data_zero(&signed_data); + krb5_data_zero(&buf); *kdc_cert = NULL; - ret = BN_to_integer(context, kdc_dh->pub_key, &i); - if (ret) - return ret; + if (cp->keyex == USE_DH) { + DH *kdc_dh = cp->u.dh.key; + heim_integer i; - ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret); - if (ret) { - krb5_set_error_message(context, ret, "ASN.1 encoding of " - "DHPublicKey failed (%d)", ret); - return ret; - } - if (buf.length != size) - krb5_abortx(context, "Internal ASN.1 encoder error"); - - dh_info.subjectPublicKey.length = buf.length * 8; - dh_info.subjectPublicKey.data = buf.data; + ret = BN_to_integer(context, kdc_dh->pub_key, &i); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret); + der_free_heim_integer(&i); + if (ret) { + krb5_set_error_message(context, ret, "ASN.1 encoding of " + "DHPublicKey failed (%d)", ret); + return ret; + } + if (buf.length != size) + krb5_abortx(context, "Internal ASN.1 encoder error"); + + dh_info.subjectPublicKey.length = buf.length * 8; + dh_info.subjectPublicKey.data = buf.data; + krb5_data_zero(&buf); +#ifdef HAVE_OPENSSL + } else if (cp->keyex == USE_ECDH) { + unsigned char *p; + int len; + + len = i2o_ECPublicKey(cp->u.ecdh.key, NULL); + if (len <= 0) + abort(); + + p = malloc(len); + if (p == NULL) + abort(); + + dh_info.subjectPublicKey.length = len * 8; + dh_info.subjectPublicKey.data = p; + + len = i2o_ECPublicKey(cp->u.ecdh.key, &p); + if (len <= 0) + abort(); +#endif + } else + krb5_abortx(context, "no keyex selected ?"); - dh_info.nonce = client_params->nonce; + + dh_info.nonce = cp->nonce; ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size, ret); @@ -893,44 +1172,42 @@ pk_mk_pa_reply_dh(krb5_context context, * filled in above */ - { - hx509_query *q; - hx509_cert cert; - - ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); - if (ret) - goto out; - - hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); - hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); - - ret = hx509_certs_find(kdc_identity->hx509ctx, - kdc_identity->certs, - q, - &cert); - hx509_query_free(kdc_identity->hx509ctx, q); - if (ret) - goto out; - - ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx, - 0, - oid_id_pkdhkeydata(), - buf.data, - buf.length, - NULL, - cert, - client_params->peer, - client_params->client_anchors, - kdc_identity->certpool, - &signed_data); - *kdc_cert = cert; - } + ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); + if (ret) + goto out; + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + if (config->pkinit_kdc_friendly_name) + hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); + + ret = hx509_certs_find(kdc_identity->hx509ctx, + kdc_identity->certs, + q, + &cert); + hx509_query_free(kdc_identity->hx509ctx, q); if (ret) goto out; + + ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx, + 0, + &asn1_oid_id_pkdhkeydata, + buf.data, + buf.length, + NULL, + cert, + cp->peer, + cp->client_anchors, + kdc_identity->certpool, + &signed_data); + if (ret) { + kdc_log(context, config, 0, "Failed signing the DH* reply: %d", ret); + goto out; + } + *kdc_cert = cert; ret = _krb5_pk_mk_ContentInfo(context, &signed_data, - oid_id_pkcs7_signedData(), + &asn1_oid_id_pkcs7_signedData, content_info); if (ret) goto out; @@ -955,11 +1232,13 @@ pk_mk_pa_reply_dh(krb5_context context, krb5_error_code _kdc_pk_mk_pa_reply(krb5_context context, krb5_kdc_configuration *config, - pk_client_params *client_params, + pk_client_params *cp, const hdb_entry_ex *client, + krb5_enctype sessionetype, const KDC_REQ *req, const krb5_data *req_buffer, krb5_keyblock **reply_key, + krb5_keyblock *sessionkey, METHOD_DATA *md) { krb5_error_code ret; @@ -989,7 +1268,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, } else enctype = ETYPE_DES3_CBC_SHA1; - if (client_params->type == PKINIT_27) { + if (cp->type == PKINIT_27) { PA_PK_AS_REP rep; const char *type, *other = ""; @@ -997,7 +1276,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, pa_type = KRB5_PADATA_PK_AS_REP; - if (client_params->dh == NULL) { + if (cp->keyex == USE_RSA) { ContentInfo info; type = "enckey"; @@ -1005,18 +1284,19 @@ _kdc_pk_mk_pa_reply(krb5_context context, rep.element = choice_PA_PK_AS_REP_encKeyPack; ret = krb5_generate_random_keyblock(context, enctype, - &client_params->reply_key); + &cp->reply_key); if (ret) { free_PA_PK_AS_REP(&rep); goto out; } ret = pk_mk_pa_reply_enckey(context, config, - client_params, + cp, req, req_buffer, - &client_params->reply_key, - &info); + &cp->reply_key, + &info, + &kdc_cert); if (ret) { free_PA_PK_AS_REP(&rep); goto out; @@ -1034,32 +1314,52 @@ _kdc_pk_mk_pa_reply(krb5_context context, if (rep.u.encKeyPack.length != size) krb5_abortx(context, "Internal ASN.1 encoder error"); + ret = krb5_generate_random_keyblock(context, sessionetype, + sessionkey); + if (ret) { + free_PA_PK_AS_REP(&rep); + goto out; + } + } else { ContentInfo info; - type = "dh"; - if (client_params->dh_group_name) - other = client_params->dh_group_name; + switch (cp->keyex) { + case USE_DH: type = "dh"; break; +#ifdef HAVE_OPENSSL + case USE_ECDH: type = "ecdh"; break; +#endif + default: krb5_abortx(context, "unknown keyex"); break; + } + + if (cp->dh_group_name) + other = cp->dh_group_name; rep.element = choice_PA_PK_AS_REP_dhInfo; - ret = generate_dh_keyblock(context, client_params, enctype, - &client_params->reply_key); + ret = generate_dh_keyblock(context, cp, enctype); if (ret) return ret; - ret = pk_mk_pa_reply_dh(context, client_params->dh, - client_params, - &client_params->reply_key, + ret = pk_mk_pa_reply_dh(context, config, + cp, &info, &kdc_cert); + if (ret) { + free_PA_PK_AS_REP(&rep); + krb5_set_error_message(context, ret, + "create pa-reply-dh " + "failed %d", ret); + goto out; + } ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data, rep.u.dhInfo.dhSignedData.length, &info, &size, ret); free_ContentInfo(&info); if (ret) { - krb5_set_error_message(context, ret, "encoding of Key ContentInfo " + krb5_set_error_message(context, ret, + "encoding of Key ContentInfo " "failed %d", ret); free_PA_PK_AS_REP(&rep); goto out; @@ -1067,17 +1367,23 @@ _kdc_pk_mk_pa_reply(krb5_context context, if (rep.u.encKeyPack.length != size) krb5_abortx(context, "Internal ASN.1 encoder error"); - } - if (ret) { - free_PA_PK_AS_REP(&rep); - goto out; + /* XXX KRB-FX-CF2 */ + ret = krb5_generate_random_keyblock(context, sessionetype, + sessionkey); + if (ret) { + free_PA_PK_AS_REP(&rep); + goto out; + } + + /* XXX Add PA-PKINIT-KX */ + } ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret); free_PA_PK_AS_REP(&rep); if (ret) { - krb5_set_error_message(context, ret, "encode PA-PK-AS-REP failed %d", - ret); + krb5_set_error_message(context, ret, + "encode PA-PK-AS-REP failed %d", ret); goto out; } if (len != size) @@ -1085,13 +1391,14 @@ _kdc_pk_mk_pa_reply(krb5_context context, kdc_log(context, config, 0, "PK-INIT using %s %s", type, other); - } else if (client_params->type == PKINIT_WIN2K) { + } else if (cp->type == PKINIT_WIN2K) { PA_PK_AS_REP_Win2k rep; ContentInfo info; - if (client_params->dh) { + if (cp->keyex != USE_RSA) { ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, "Windows PK-INIT doesn't support DH"); + krb5_set_error_message(context, ret, + "Windows PK-INIT doesn't support DH"); goto out; } @@ -1101,18 +1408,19 @@ _kdc_pk_mk_pa_reply(krb5_context context, rep.element = choice_PA_PK_AS_REP_encKeyPack; ret = krb5_generate_random_keyblock(context, enctype, - &client_params->reply_key); + &cp->reply_key); if (ret) { free_PA_PK_AS_REP_Win2k(&rep); goto out; } ret = pk_mk_pa_reply_enckey(context, config, - client_params, + cp, req, req_buffer, - &client_params->reply_key, - &info); + &cp->reply_key, + &info, + &kdc_cert); if (ret) { free_PA_PK_AS_REP_Win2k(&rep); goto out; @@ -1140,13 +1448,19 @@ _kdc_pk_mk_pa_reply(krb5_context context, if (len != size) krb5_abortx(context, "Internal ASN.1 encoder error"); + ret = krb5_generate_random_keyblock(context, sessionetype, + sessionkey); + if (ret) + goto out; + } else krb5_abortx(context, "PK-INIT internal error"); ret = krb5_padata_add(context, md, pa_type, buf, len); if (ret) { - krb5_set_error_message(context, ret, "failed adding PA-PK-AS-REP %d", ret); + krb5_set_error_message(context, ret, + "Failed adding PA-PK-AS-REP %d", ret); free(buf); goto out; } @@ -1232,7 +1546,7 @@ out: hx509_cert_free(kdc_cert); if (ret == 0) - *reply_key = &client_params->reply_key; + *reply_key = &cp->reply_key; return ret; } @@ -1250,7 +1564,7 @@ match_rfc_san(krb5_context context, ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, client_cert, - oid_id_pkinit_san(), + &asn1_oid_id_pkinit_san, &list); if (ret) goto out; @@ -1311,7 +1625,7 @@ match_ms_upn_san(krb5_context context, ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, client_cert, - oid_id_pkinit_ms_san(), + &asn1_oid_id_pkinit_ms_san, &list); if (ret) goto out; @@ -1363,16 +1677,25 @@ krb5_error_code _kdc_pk_check_client(krb5_context context, krb5_kdc_configuration *config, const hdb_entry_ex *client, - pk_client_params *client_params, + pk_client_params *cp, char **subject_name) { const HDB_Ext_PKINIT_acl *acl; + const HDB_Ext_PKINIT_cert *pc; krb5_error_code ret; hx509_name name; int i; + if (cp->cert == NULL) { + + *subject_name = strdup("anonymous client client"); + if (*subject_name == NULL) + return ENOMEM; + return 0; + } + ret = hx509_cert_get_base_subject(kdc_identity->hx509ctx, - client_params->cert, + cp->cert, &name); if (ret) return ret; @@ -1386,10 +1709,33 @@ _kdc_pk_check_client(krb5_context context, "Trying to authorize PK-INIT subject DN %s", *subject_name); + ret = hdb_entry_get_pkinit_cert(&client->entry, &pc); + if (ret == 0 && pc) { + hx509_cert cert; + unsigned int i; + + for (i = 0; i < pc->len; i++) { + ret = hx509_cert_init_data(kdc_identity->hx509ctx, + pc->val[i].cert.data, + pc->val[i].cert.length, + &cert); + if (ret) + continue; + ret = hx509_cert_cmp(cert, cp->cert); + hx509_cert_free(cert); + if (ret == 0) { + kdc_log(context, config, 5, + "Found matching PK-INIT cert in hdb"); + return 0; + } + } + } + + if (config->pkinit_princ_in_cert) { ret = match_rfc_san(context, config, kdc_identity->hx509ctx, - client_params->cert, + cp->cert, client->entry.principal); if (ret == 0) { kdc_log(context, config, 5, @@ -1398,7 +1744,7 @@ _kdc_pk_check_client(krb5_context context, } ret = match_ms_upn_san(context, config, kdc_identity->hx509ctx, - client_params->cert, + cp->cert, client->entry.principal); if (ret == 0) { kdc_log(context, config, 5, @@ -1493,7 +1839,7 @@ add_principal_mapping(krb5_context context, krb5_error_code _kdc_add_inital_verified_cas(krb5_context context, krb5_kdc_configuration *config, - pk_client_params *params, + pk_client_params *cp, EncTicketPart *tkt) { AD_INITIAL_VERIFIED_CAS cas; @@ -1594,6 +1940,7 @@ _kdc_pk_initialize(krb5_context context, ret = _krb5_pk_load_id(context, &kdc_identity, + 0, user_id, anchors, pool, @@ -1618,7 +1965,8 @@ _kdc_pk_initialize(krb5_context context, } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); - hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + if (config->pkinit_kdc_friendly_name) + hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); ret = hx509_certs_find(kdc_identity->hx509ctx, kdc_identity->certs, @@ -1627,23 +1975,30 @@ _kdc_pk_initialize(krb5_context context, hx509_query_free(kdc_identity->hx509ctx, q); if (ret == 0) { if (hx509_cert_check_eku(kdc_identity->hx509ctx, cert, - oid_id_pkkdcekuoid(), 0)) - krb5_warnx(context, "WARNING Found KDC certificate " + &asn1_oid_id_pkkdcekuoid, 0)) { + hx509_name name; + char *str; + ret = hx509_cert_get_subject(cert, &name); + hx509_name_to_string(name, &str); + krb5_warnx(context, "WARNING Found KDC certificate (%s)" "is missing the PK-INIT KDC EKU, this is bad for " - "interoperability."); + "interoperability.", str); + hx509_name_free(&name); + free(str); + } hx509_cert_free(cert); } else krb5_warnx(context, "PKINIT: failed to find a signing " "certifiate with a public key"); } - ret = krb5_config_get_bool_default(context, - NULL, - FALSE, - "kdc", - "pkinit_allow_proxy_certificate", - NULL); - _krb5_pk_allow_proxy_certificate(kdc_identity, ret); + if (krb5_config_get_bool_default(context, + NULL, + FALSE, + "kdc", + "pkinit_allow_proxy_certificate", + NULL)) + config->pkinit_allow_proxy_certs = 1; file = krb5_config_get_string(context, NULL, diff --git a/source4/heimdal/kdc/process.c b/source4/heimdal/kdc/process.c index a27911914b..d3557ee6c9 100644 --- a/source4/heimdal/kdc/process.c +++ b/source4/heimdal/kdc/process.c @@ -34,8 +34,6 @@ #include "kdc_locl.h" -RCSID("$Id$"); - /* * */ @@ -49,6 +47,209 @@ krb5_kdc_update_time(struct timeval *tv) _kdc_now = *tv; } +static krb5_error_code +kdc_as_req(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim) +{ + krb5_error_code ret; + KDC_REQ req; + size_t len; + + ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &req, &len); + if (ret) + return ret; + + *claim = 1; + + ret = _kdc_as_rep(context, config, &req, req_buffer, + reply, from, addr, datagram_reply); + free_AS_REQ(&req); + return ret; +} + + +static krb5_error_code +kdc_tgs_req(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim) +{ + krb5_error_code ret; + KDC_REQ req; + size_t len; + + ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len); + if (ret) + return ret; + + *claim = 1; + + ret = _kdc_tgs_rep(context, config, &req, reply, + from, addr, datagram_reply); + free_TGS_REQ(&req); + return ret; +} + +#ifdef DIGEST + +static krb5_error_code +kdc_digest(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim) +{ + DigestREQ digestreq; + krb5_error_code ret; + size_t len; + + ret = decode_DigestREQ(req_buffer->data, req_buffer->length, + &digestreq, &len); + if (ret) + return ret; + + *claim = 1; + + ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr); + free_DigestREQ(&digestreq); + return ret; +} + +#endif + +#ifdef KX509 + +static krb5_error_code +kdc_kx509(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim) +{ + Kx509Request kx509req; + krb5_error_code ret; + size_t len; + + ret = _kdc_try_kx509_request(req_buffer->data, req_buffer->length, + &kx509req, &len); + if (ret) + return ret; + + *claim = 1; + + ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr); + free_Kx509Request(&kx509req); + return ret; +} + +#endif + + +#ifdef KRB4 + +static krb5_error_code +kdc_524(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim) +{ + krb5_error_code ret; + Ticket ticket; + size_t len; + + ret = decode_Ticket(req_buffer->data, req_buffer->length, &ticket, &len); + if (ret) + return ret; + + *claim = 1; + + ret = _kdc_do_524(context, config, &ticket, reply, from, addr); + free_Ticket(&ticket); + return ret; +} + +static krb5_error_code +kdc_krb4(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim) +{ + if (_kdc_maybe_version4(req_buffer->data, req_buffer->length) == 0) + return -1; + + *claim = 1; + + return _kdc_do_version4(context, config, + req_buffer->data, req_buffer->length, + reply, from, + (struct sockaddr_in*)addr); +} + +static krb5_error_code +kdc_kaserver(krb5_context context, + krb5_kdc_configuration *config, + krb5_data *req_buffer, + krb5_data *reply, + const char *from, + struct sockaddr *addr, + int datagram_reply, + int *claim) +{ + if (config->enable_kaserver == 0) + return -1; + + *claim = 1; + + return _kdc_do_kaserver(context, config, + req_buffer->data, req_buffer->length, + reply, from, + (struct sockaddr_in*)addr); +} + +#endif /* KRB4 */ + + +static struct krb5_kdc_service services[] = { + { KS_KRB5, kdc_as_req }, + { KS_KRB5, kdc_tgs_req }, +#ifdef DIGEST + { 0, kdc_digest }, +#endif +#ifdef KX509 + { 0, kdc_kx509 }, +#endif +#ifdef KRB4 + { 0, kdc_524 }, + { KS_NO_LENGTH, kdc_krb4 }, + { 0, kdc_kaserver }, +#endif + { 0, NULL } +}; + /* * handle the request in `buf, len', from `addr' (or `from' as a string), * sending a reply in `reply'. @@ -65,50 +266,25 @@ krb5_kdc_process_request(krb5_context context, struct sockaddr *addr, int datagram_reply) { - KDC_REQ req; - Ticket ticket; - DigestREQ digestreq; - Kx509Request kx509req; krb5_error_code ret; - size_t i; - - if(decode_AS_REQ(buf, len, &req, &i) == 0){ - krb5_data req_buffer; + unsigned int i; + krb5_data req_buffer; + int claim = 0; + + req_buffer.data = buf; + req_buffer.length = len; - req_buffer.data = buf; - req_buffer.length = len; - - ret = _kdc_as_rep(context, config, &req, &req_buffer, - reply, from, addr, datagram_reply); - free_AS_REQ(&req); - return ret; - }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ - ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply); - free_TGS_REQ(&req); - return ret; - }else if(decode_Ticket(buf, len, &ticket, &i) == 0){ - ret = _kdc_do_524(context, config, &ticket, reply, from, addr); - free_Ticket(&ticket); - return ret; - }else if(decode_DigestREQ(buf, len, &digestreq, &i) == 0){ - ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr); - free_DigestREQ(&digestreq); - return ret; - } else if (_kdc_try_kx509_request(buf, len, &kx509req, &i) == 0) { - ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr); - free_Kx509Request(&kx509req); - return ret; - } else if(_kdc_maybe_version4(buf, len)){ - *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */ - ret = _kdc_do_version4(context, config, buf, len, reply, from, - (struct sockaddr_in*)addr); - return ret; - } else if (config->enable_kaserver) { - ret = _kdc_do_kaserver(context, config, buf, len, reply, from, - (struct sockaddr_in*)addr); - return ret; + for (i = 0; services[i].process != NULL; i++) { + ret = (*services[i].process)(context, config, &req_buffer, + reply, from, addr, datagram_reply, + &claim); + if (claim) { + if (services[i].flags & KS_NO_LENGTH) + *prependlength = 0; + return ret; + } } - + return -1; } @@ -129,25 +305,24 @@ krb5_kdc_process_krb5_request(krb5_context context, struct sockaddr *addr, int datagram_reply) { - KDC_REQ req; krb5_error_code ret; - size_t i; + unsigned int i; + krb5_data req_buffer; + int claim = 0; + + req_buffer.data = buf; + req_buffer.length = len; - if(decode_AS_REQ(buf, len, &req, &i) == 0){ - krb5_data req_buffer; - - req_buffer.data = buf; - req_buffer.length = len; - - ret = _kdc_as_rep(context, config, &req, &req_buffer, - reply, from, addr, datagram_reply); - free_AS_REQ(&req); - return ret; - }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ - ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply); - free_TGS_REQ(&req); - return ret; + for (i = 0; services[i].process != NULL; i++) { + if ((services[i].flags & KS_KRB5) == 0) + continue; + ret = (*services[i].process)(context, config, &req_buffer, + reply, from, addr, datagram_reply, + &claim); + if (claim) + return ret; } + return -1; } diff --git a/source4/heimdal/kpasswd/kpasswd.c b/source4/heimdal/kpasswd/kpasswd.c index f67130a052..c2f980b25f 100644 --- a/source4/heimdal/kpasswd/kpasswd.c +++ b/source4/heimdal/kpasswd/kpasswd.c @@ -153,9 +153,9 @@ main (int argc, char **argv) if (ret) krb5_err (context, 1, ret, "krb5_cc_resolve"); } else { - ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id); + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if (ret) - krb5_err (context, 1, ret, "krb5_cc_gen_new"); + krb5_err (context, 1, ret, "krb5_cc_new_unique"); } if (cred_cache_str == NULL) { diff --git a/source4/heimdal/kuser/kinit.c b/source4/heimdal/kuser/kinit.c index fbb2d2287b..350988dbac 100644 --- a/source4/heimdal/kuser/kinit.c +++ b/source4/heimdal/kuser/kinit.c @@ -32,11 +32,19 @@ */ #include "kuser_locl.h" -RCSID("$Id$"); +#ifndef HEIMDAL_SMALLER #include "krb5-v4compat.h" +#endif + +struct krb5_dh_moduli; +struct AlgorithmIdentifier; +struct _krb5_krb_auth_data; +#include <krb5-private.h> +#ifndef NO_NTLM #include "heimntlm.h" +#endif int forwardable_flag = -1; int proxiable_flag = -1; @@ -54,6 +62,7 @@ char *renew_life = NULL; char *server_str = NULL; char *cred_cache = NULL; char *start_str = NULL; +static int switch_cache_flags = 1; struct getarg_strings etype_str; int use_keytab = 0; char *keytab_str = NULL; @@ -66,13 +75,17 @@ static char *krb4_cc_name; int fcache_version; char *password_file = NULL; char *pk_user_id = NULL; +int pk_enterprise_flag = 0; char *pk_x509_anchors = NULL; int pk_use_enckey = 0; static int canonicalize_flag = 0; +static int enterprise_flag = 0; static int ok_as_delegate_flag = 0; static int use_referrals_flag = 0; static int windows_flag = 0; +#ifndef NO_NTLM static char *ntlm_domain; +#endif static struct getargs args[] = { @@ -154,7 +167,13 @@ static struct getargs args[] = { { "canonicalize",0, arg_flag, &canonicalize_flag, NP_("canonicalize client principal", "") }, + + { "enterprise",0, arg_flag, &enterprise_flag, + NP_("parse principal as a KRB5-NT-ENTERPRISE name", "") }, #ifdef PKINIT + { "pk-enterprise", 0, arg_flag, &pk_enterprise_flag, + NP_("use enterprise name from certificate", "") }, + { "pk-user", 'C', arg_string, &pk_user_id, NP_("principal's public/private/certificate identifier", ""), "id" }, @@ -164,8 +183,13 @@ static struct getargs args[] = { { "pk-use-enckey", 0, arg_flag, &pk_use_enckey, NP_("Use RSA encrypted reply (instead of DH)", "") }, #endif +#ifndef NO_NTLM { "ntlm-domain", 0, arg_string, &ntlm_domain, NP_("NTLM domain", ""), "domain" }, +#endif + + { "change-default", 0, arg_negative_flag, &switch_cache_flags, + NP_("switch the default cache to the new credentials cache", "") }, { "ok-as-delegate", 0, arg_flag, &ok_as_delegate_flag, NP_("honor ok-as-delegate on tickets", "") }, @@ -198,13 +222,13 @@ get_server(krb5_context context, const char *server, krb5_principal *princ) { - krb5_realm *client_realm; + krb5_const_realm realm; if(server) return krb5_parse_name(context, server, princ); - client_realm = krb5_princ_realm (context, client); - return krb5_make_principal(context, princ, *client_realm, - KRB5_TGS_NAME, *client_realm, NULL); + realm = krb5_principal_get_realm(context, client); + return krb5_make_principal(context, princ, realm, + KRB5_TGS_NAME, realm, NULL); } #ifndef HEIMDAL_SMALLER @@ -301,7 +325,7 @@ renew_validate(krb5_context context, else if (out) flags.b.proxiable = out->flags.b.proxiable; - if (anonymous_flag != -1) + if (anonymous_flag) flags.b.request_anonymous = anonymous_flag; if(life) in.times.endtime = time(NULL) + life; @@ -337,8 +361,10 @@ renew_validate(krb5_context context, if(get_v4_tgt) do_524init(context, cache, out, NULL); #endif +#ifndef NO_AFS if(do_afslog && k_hasafs()) krb5_afslog(context, cache, NULL, NULL); +#endif } krb5_free_creds (context, out); @@ -351,6 +377,8 @@ out: return ret; } +#ifndef NO_NTLM + static krb5_error_code store_ntlmkey(krb5_context context, krb5_ccache id, const char *domain, struct ntlm_buf *buf) @@ -372,6 +400,7 @@ store_ntlmkey(krb5_context context, krb5_ccache id, free(name); return ret; } +#endif static krb5_error_code get_new_tickets(krb5_context context, @@ -388,10 +417,11 @@ get_new_tickets(krb5_context context, krb5_deltat renew = 0; char *renewstr = NULL; krb5_enctype *enctype = NULL; - struct ntlm_buf ntlmkey; krb5_ccache tempccache; - +#ifndef NO_NTLM + struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); +#endif passwd[0] = '\0'; if (password_file) { @@ -428,21 +458,24 @@ get_new_tickets(krb5_context context, krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag); if(proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag); - if(anonymous_flag != -1) + if(anonymous_flag) krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); - if (pk_user_id) { + if (pk_enterprise_flag && windows_flag) + krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); + if (pk_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, - pk_use_enckey ? 2 : 0, + pk_use_enckey ? 2 : 0 | + anonymous_flag ? 4 : 0, krb5_prompter_posix, NULL, passwd); @@ -510,7 +543,7 @@ get_new_tickets(krb5_context context, server_str, opt); krb5_kt_close(context, kt); - } else if (pk_user_id) { + } else if (pk_user_id || anonymous_flag) { ret = krb5_get_init_creds_password (context, &cred, principal, @@ -552,8 +585,10 @@ get_new_tickets(krb5_context context, opt); } krb5_get_init_creds_opt_free(context, opt); +#ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); +#endif memset(passwd, 0, sizeof(passwd)); switch(ret){ @@ -611,8 +646,13 @@ get_new_tickets(krb5_context context, if (ret) krb5_err (context, 1, ret, "krb5_cc_move"); + if (switch_cache_flags) + krb5_cc_switch(context, ccache); + +#ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); +#endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; @@ -704,8 +744,10 @@ renew_func(void *ptr) if(get_v4_tgt || convert_524) do_524init(ctx->context, ctx->ccache, NULL, server_str); #endif +#ifndef NO_AFS if(do_afslog && k_hasafs()) krb5_afslog(ctx->context, ctx->ccache, NULL, NULL); +#endif expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal, server_str) / 2; @@ -751,17 +793,35 @@ main (int argc, char **argv) argc -= optidx; argv += optidx; - if (canonicalize_flag) + if (canonicalize_flag || enterprise_flag) parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; - if (argv[0]) { - ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal); + if (pk_enterprise_flag) { + ret = _krb5_pk_enterprise_cert(context, pk_user_id, + argv[0], &principal); if (ret) - krb5_err (context, 1, ret, "krb5_parse_name"); - } else { - ret = krb5_get_default_principal (context, &principal); + krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); + + } else if (anonymous_flag) { + + ret = krb5_make_principal(context, &principal, argv[0], + KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, + NULL); if (ret) - krb5_err (context, 1, ret, "krb5_get_default_principal"); + krb5_err(context, 1, ret, "krb5_build_principal"); + krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN); + + } else { + if (argv[0]) { + ret = krb5_parse_name_flags (context, argv[0], parseflags, + &principal); + if (ret) + krb5_err (context, 1, ret, "krb5_parse_name"); + } else { + ret = krb5_get_default_principal (context, &principal); + if (ret) + krb5_err (context, 1, ret, "krb5_get_default_principal"); + } } if(fcache_version) @@ -788,7 +848,7 @@ main (int argc, char **argv) else { if(argc > 1) { char s[1024]; - ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache); + ret = krb5_cc_new_unique(context, NULL, NULL, &ccache); if(ret) krb5_err(context, 1, ret, "creating cred cache"); snprintf(s, sizeof(s), "%s:%s", @@ -818,8 +878,10 @@ main (int argc, char **argv) if (ret) krb5_err (context, 1, ret, N_("resolving credentials cache", "")); +#ifndef NO_AFS if(argc > 1 && k_hasafs ()) k_setpag(); +#endif if (lifetime) { int tmp = parse_time (lifetime, "s"); @@ -863,8 +925,10 @@ main (int argc, char **argv) if(get_v4_tgt || convert_524) do_524init(context, ccache, NULL, server_str); #endif +#ifndef NO_AFS if(do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); +#endif if(argc > 1) { struct renew_ctx ctx; time_t timeout; @@ -889,8 +953,10 @@ main (int argc, char **argv) #ifndef HEIMDAL_SMALLER _krb5_krb_dest_tkt(context, krb4_cc_name); #endif +#ifndef NO_AFS if(k_hasafs()) k_unlog(); +#endif } else { krb5_cc_close (context, ccache); ret = 0; diff --git a/source4/heimdal/kuser/kuser_locl.h b/source4/heimdal/kuser/kuser_locl.h index eed9e00af6..eafffe9bff 100644 --- a/source4/heimdal/kuser/kuser_locl.h +++ b/source4/heimdal/kuser/kuser_locl.h @@ -36,9 +36,7 @@ #ifndef __KUSER_LOCL_H__ #define __KUSER_LOCL_H__ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include <stdio.h> #include <stdlib.h> @@ -81,7 +79,9 @@ #ifdef HAVE_SYS_IOCCOM_H #include <sys/ioccom.h> #endif +#ifndef NO_AFS #include <kafs.h> +#endif #include "crypto-headers.h" /* for UI_UTIL_read_pw_string */ #ifdef HAVE_LOCALE_H diff --git a/source4/heimdal/lib/asn1/asn1_err.et b/source4/heimdal/lib/asn1/asn1_err.et index 26bda55c19..f1a653b1f9 100644 --- a/source4/heimdal/lib/asn1/asn1_err.et +++ b/source4/heimdal/lib/asn1/asn1_err.et @@ -22,4 +22,6 @@ error_code BAD_CHARACTER, "ASN.1 invalid character in string" error_code MIN_CONSTRAINT, "ASN.1 too few elements" error_code MAX_CONSTRAINT, "ASN.1 too many elements" error_code EXACT_CONSTRAINT, "ASN.1 wrong number of elements" +error_code INDEF_OVERRUN, "ASN.1 BER indefinte encoding overrun" +error_code INDEF_UNDERRUN, "ASN.1 BER indefinte encoding underun" end diff --git a/source4/heimdal/lib/asn1/asn1_gen.c b/source4/heimdal/lib/asn1/asn1_gen.c index e25f6d919e..925cc72cb4 100644 --- a/source4/heimdal/lib/asn1/asn1_gen.c +++ b/source4/heimdal/lib/asn1/asn1_gen.c @@ -119,24 +119,24 @@ doit(const char *fn) &sz); if (ret) errx(1, "der_put_length_and_tag: %d", ret); - + if (fwrite(p + sizeof(p) - sz , sz, 1, fout) != 1) err(1, "fwrite length/tag failed"); offset += sz; - + if (data) { size_t datalen; - + datalen = strlen(data) / 2; pdata = emalloc(sz); - + if (hex_decode(data, pdata, datalen) != datalen) errx(1, "failed to decode data"); - + if (fwrite(pdata, datalen, 1, fout) != 1) err(1, "fwrite data failed"); offset += datalen; - + free(pdata); } } diff --git a/source4/heimdal/lib/asn1/canthandle.asn1 b/source4/heimdal/lib/asn1/canthandle.asn1 index 5c2690f9b6..a335ee89e3 100644 --- a/source4/heimdal/lib/asn1/canthandle.asn1 +++ b/source4/heimdal/lib/asn1/canthandle.asn1 @@ -7,7 +7,7 @@ CANTHANDLE DEFINITIONS ::= BEGIN -- Code the tag [2] but it should be primitive since KAKA3 is -- Workaround: use the INTEGER type directly -Kaka2 ::= SEQUENCE { +Kaka2 ::= SEQUENCE { kaka2-1 [0] INTEGER } diff --git a/source4/heimdal/lib/asn1/CMS.asn1 b/source4/heimdal/lib/asn1/cms.asn1 index 65a467521d..1c13d5f387 100644 --- a/source4/heimdal/lib/asn1/CMS.asn1 +++ b/source4/heimdal/lib/asn1/cms.asn1 @@ -18,8 +18,8 @@ id-pkcs7-digestedData OBJECT IDENTIFIER ::= { id-pkcs7 5 } id-pkcs7-encryptedData OBJECT IDENTIFIER ::= { id-pkcs7 6 } CMSVersion ::= INTEGER { - CMSVersion_v0(0), - CMSVersion_v1(1), + CMSVersion_v0(0), + CMSVersion_v1(1), CMSVersion_v2(2), CMSVersion_v3(3), CMSVersion_v4(4) @@ -34,7 +34,7 @@ MessageDigest ::= OCTET STRING ContentInfo ::= SEQUENCE { contentType ContentType, - content [0] EXPLICIT heim_any OPTIONAL -- DEFINED BY contentType + content [0] EXPLICIT heim_any OPTIONAL -- DEFINED BY contentType } EncapsulatedContentInfo ::= SEQUENCE { @@ -53,7 +53,7 @@ IssuerAndSerialNumber ::= SEQUENCE { serialNumber CertificateSerialNumber } --- RecipientIdentifier is same as SignerIdentifier, +-- RecipientIdentifier is same as SignerIdentifier, -- lets glue them togheter and save some bytes and share code for them CMSIdentifier ::= CHOICE { @@ -67,7 +67,7 @@ RecipientIdentifier ::= CMSIdentifier --- CMSAttributes are the combined UnsignedAttributes and SignedAttributes --- to store space and share code -CMSAttributes ::= SET OF Attribute -- SIZE (1..MAX) +CMSAttributes ::= SET OF Attribute -- SIZE (1..MAX) SignatureValue ::= OCTET STRING @@ -79,7 +79,7 @@ SignerInfo ::= SEQUENCE { SET OF Attribute OPTIONAL, signatureAlgorithm SignatureAlgorithmIdentifier, signature SignatureValue, - unsignedAttrs [1] IMPLICIT -- CMSAttributes -- + unsignedAttrs [1] IMPLICIT -- CMSAttributes -- SET OF Attribute OPTIONAL } diff --git a/source4/heimdal/lib/asn1/cms.opt b/source4/heimdal/lib/asn1/cms.opt new file mode 100644 index 0000000000..bf7d396529 --- /dev/null +++ b/source4/heimdal/lib/asn1/cms.opt @@ -0,0 +1 @@ +--decode-dce-ber diff --git a/source4/heimdal/lib/asn1/der.h b/source4/heimdal/lib/asn1/der.h index 3b6f30887c..5b24b917d8 100644 --- a/source4/heimdal/lib/asn1/der.h +++ b/source4/heimdal/lib/asn1/der.h @@ -52,7 +52,7 @@ typedef enum {PRIM = 0, CONS = 1} Der_type; enum { UT_EndOfContent = 0, UT_Boolean = 1, - UT_Integer = 2, + UT_Integer = 2, UT_BitString = 3, UT_OctetString = 4, UT_Null = 5, diff --git a/source4/heimdal/lib/asn1/der_get.c b/source4/heimdal/lib/asn1/der_get.c index 8a70966413..8144639b9a 100644 --- a/source4/heimdal/lib/asn1/der_get.c +++ b/source4/heimdal/lib/asn1/der_get.c @@ -33,10 +33,6 @@ #include "der_locl.h" -RCSID("$Id$"); - -#include <version.h> - /* * All decoding functions take a pointer `p' to first position in * which to read, from the left, `len' which means the maximum number @@ -252,6 +248,75 @@ der_get_octet_string (const unsigned char *p, size_t len, } int +der_get_octet_string_ber (const unsigned char *p, size_t len, + heim_octet_string *data, size_t *size) +{ + int e; + Der_type type; + Der_class class; + unsigned int tag, depth = 0; + size_t l, datalen, oldlen = len; + + data->length = 0; + data->data = NULL; + + while (len) { + e = der_get_tag (p, len, &class, &type, &tag, &l); + if (e) goto out; + if (class != ASN1_C_UNIV) { + e = ASN1_BAD_ID; + goto out; + } + if (type == PRIM && tag == UT_EndOfContent) { + if (depth == 0) + break; + depth--; + } + if (tag != UT_OctetString) { + e = ASN1_BAD_ID; + goto out; + } + + p += l; + len -= l; + e = der_get_length (p, len, &datalen, &l); + if (e) goto out; + p += l; + len -= l; + + if (datalen > len) + return ASN1_OVERRUN; + + if (type == PRIM) { + void *ptr; + + ptr = realloc(data->data, data->length + datalen); + if (ptr == NULL) { + e = ENOMEM; + goto out; + } + data->data = ptr; + memcpy(((unsigned char *)data->data) + data->length, p, datalen); + data->length += datalen; + } else + depth++; + + p += datalen; + len -= datalen; + } + if (depth != 0) + return ASN1_INDEF_OVERRUN; + if(size) *size = oldlen - len; + return 0; + out: + free(data->data); + data->data = NULL; + data->length = 0; + return e; +} + + +int der_get_heim_integer (const unsigned char *p, size_t len, heim_integer *data, size_t *size) { @@ -397,7 +462,7 @@ der_get_oid (const unsigned char *p, size_t len, ++p; for (n = 2; len > 0; ++n) { unsigned u = 0, u1; - + do { --len; u1 = u * 128 + (*p++ % 128); @@ -457,15 +522,28 @@ der_match_tag (const unsigned char *p, size_t len, Der_class class, Der_type type, unsigned int tag, size_t *size) { + Der_type thistype; + int e; + + e = der_match_tag2(p, len, class, &thistype, tag, size); + if (e) return e; + if (thistype != type) return ASN1_BAD_ID; + return 0; +} + +int +der_match_tag2 (const unsigned char *p, size_t len, + Der_class class, Der_type *type, + unsigned int tag, size_t *size) +{ size_t l; Der_class thisclass; - Der_type thistype; unsigned int thistag; int e; - e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l); + e = der_get_tag (p, len, &thisclass, type, &thistag, &l); if (e) return e; - if (class != thisclass || type != thistype) + if (class != thisclass) return ASN1_BAD_ID; if(tag > thistag) return ASN1_MISPLACED_FIELD; @@ -477,26 +555,25 @@ der_match_tag (const unsigned char *p, size_t len, int der_match_tag_and_length (const unsigned char *p, size_t len, - Der_class class, Der_type type, unsigned int tag, + Der_class class, Der_type *type, unsigned int tag, size_t *length_ret, size_t *size) { size_t l, ret = 0; int e; - e = der_match_tag (p, len, class, type, tag, &l); + e = der_match_tag2 (p, len, class, type, tag, &l); if (e) return e; p += l; len -= l; ret += l; e = der_get_length (p, len, length_ret, &l); if (e) return e; - p += l; - len -= l; - ret += l; - if(size) *size = ret; + if(size) *size = ret + l; return 0; } + + /* * Old versions of DCE was based on a very early beta of the MIT code, * which used MAVROS for ASN.1 encoding. MAVROS had the interesting @@ -539,8 +616,11 @@ der_get_bit_string (const unsigned char *p, size_t len, data->data = malloc(len - 1); if (data->data == NULL && (len - 1) != 0) return ENOMEM; - memcpy (data->data, p + 1, len - 1); - data->length -= p[0]; + /* copy data is there is data to copy */ + if (len - 1 != 0) { + memcpy (data->data, p + 1, len - 1); + data->length -= p[0]; + } if(size) *size = len; return 0; } diff --git a/source4/heimdal/lib/asn1/der_locl.h b/source4/heimdal/lib/asn1/der_locl.h index f8a21de71c..1f27e72903 100644 --- a/source4/heimdal/lib/asn1/der_locl.h +++ b/source4/heimdal/lib/asn1/der_locl.h @@ -36,9 +36,9 @@ #ifndef __DER_LOCL_H__ #define __DER_LOCL_H__ -#ifdef HAVE_CONFIG_H + #include <config.h> -#endif + #include <assert.h> #include <stdio.h> #include <stdlib.h> diff --git a/source4/heimdal/lib/asn1/der_put.c b/source4/heimdal/lib/asn1/der_put.c index 5afddb1d05..7e71443da5 100644 --- a/source4/heimdal/lib/asn1/der_put.c +++ b/source4/heimdal/lib/asn1/der_put.c @@ -384,7 +384,7 @@ der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type, } else { size_t ret = 0; unsigned int continuation = 0; - + do { if (len < 1) return ASN1_OVERFLOW; diff --git a/source4/heimdal/lib/asn1/digest.asn1 b/source4/heimdal/lib/asn1/digest.asn1 index 1cf58b4638..5ee5bd4a99 100644 --- a/source4/heimdal/lib/asn1/digest.asn1 +++ b/source4/heimdal/lib/asn1/digest.asn1 @@ -139,7 +139,7 @@ DigestREP ::= [APPLICATION 129] SEQUENCE { -- qop == auth -- A2 = Method ":" digest-uri-value -- qop == auth-int --- A2 = Method ":" digest-uri-value ":" H(entity-body) +-- A2 = Method ":" digest-uri-value ":" H(entity-body) -- request-digest = HEX(KD(HEX(H(A1)), -- unq(nonce-value) ":" nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" HEX(H(A2)))) diff --git a/source4/heimdal/lib/asn1/extra.c b/source4/heimdal/lib/asn1/extra.c index 49240605c8..b244dbb52a 100644 --- a/source4/heimdal/lib/asn1/extra.c +++ b/source4/heimdal/lib/asn1/extra.c @@ -67,15 +67,21 @@ decode_heim_any(const unsigned char *p, size_t len, return ASN1_OVERFLOW; e = der_get_length(p + l, len - l, &length, &len_len); if (e) return e; - if (length + len_len + l > len) - return ASN1_OVERFLOW; - + if (length == ASN1_INDEFINITE) { + if (len < len_len + l) + return ASN1_OVERFLOW; + length = len - (len_len + l); + } else { + if (len < length + len_len + l) + return ASN1_OVERFLOW; + } + data->data = malloc(length + len_len + l); if (data->data == NULL) return ENOMEM; data->length = length + len_len + l; memcpy(data->data, p, length + len_len + l); - + if (size) *size = length + len_len + l; diff --git a/source4/heimdal/lib/asn1/gen.c b/source4/heimdal/lib/asn1/gen.c index 52fd0d393b..e156c7cefb 100644 --- a/source4/heimdal/lib/asn1/gen.c +++ b/source4/heimdal/lib/asn1/gen.c @@ -83,12 +83,19 @@ init_generate (const char *filename, const char *base) if (headerbase == NULL) errx(1, "strdup"); } + + /* public header file */ asprintf(&header, "%s.h", headerbase); if (header == NULL) errx(1, "malloc"); - headerfile = fopen (header, "w"); + asprintf(&fn, "%s.hx", headerbase); + if (fn == NULL) + errx(1, "malloc"); + headerfile = fopen (fn, "w"); if (headerfile == NULL) - err (1, "open %s", header); + err (1, "open %s", fn); + free(fn); + fprintf (headerfile, "/* Generated from %s */\n" "/* Do not edit */\n\n", @@ -229,7 +236,7 @@ gen_compare_defval(const char *var, struct value *val) } } -static void +void generate_header_of_codefile(const char *name) { char *filename; @@ -267,7 +274,7 @@ generate_header_of_codefile(const char *name) } -static void +void close_codefile(void) { if (codefile == NULL) @@ -296,7 +303,8 @@ generate_constant (const Symbol *s) struct objid *o, **list; unsigned int i, len; - generate_header_of_codefile(s->gen_name); + if (!one_code_file) + generate_header_of_codefile(s->gen_name); len = 0; for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next) @@ -320,9 +328,13 @@ generate_constant (const Symbol *s) } fprintf (headerfile, "} */\n"); - fprintf (headerfile, "const heim_oid *oid_%s(void);\n\n", + fprintf (headerfile, "const heim_oid *oid_%s(void);\n", + s->gen_name); + fprintf (headerfile, + "extern const heim_oid asn1_oid_%s;\n\n", s->gen_name); + fprintf (codefile, "static unsigned oid_%s_variable_num[%d] = {", s->gen_name, len); for (i = len ; i > 0; i--) { @@ -330,17 +342,20 @@ generate_constant (const Symbol *s) } fprintf(codefile, "};\n"); - fprintf (codefile, "static const heim_oid oid_%s_variable = " + fprintf (codefile, "const heim_oid asn1_oid_%s = " "{ %d, oid_%s_variable_num };\n\n", s->gen_name, len, s->gen_name); fprintf (codefile, "const heim_oid *oid_%s(void)\n" "{\n" - "return &oid_%s_variable;\n" + "return &asn1_oid_%s;\n" "}\n\n", s->gen_name, s->gen_name); - close_codefile(); + free(list); + + if (!one_code_file) + close_codefile(); break; } @@ -587,7 +602,7 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) fprintf (headerfile, "struct %s {\n", typedefp ? name : ""); ASN1_TAILQ_FOREACH(m, t->members, members) { char *n; - + asprintf (&n, "%s:1", m->gen_name); if (n == NULL) errx(1, "malloc"); @@ -787,7 +802,8 @@ generate_type_header (const Symbol *s) void generate_type (const Symbol *s) { - generate_header_of_codefile(s->gen_name); + if (!one_code_file) + generate_header_of_codefile(s->gen_name); generate_type_header (s); generate_type_encode (s); @@ -798,5 +814,9 @@ generate_type (const Symbol *s) generate_type_seq (s); generate_glue (s->type, s->gen_name); fprintf(headerfile, "\n\n"); - close_codefile(); + + if (!one_code_file) { + fprintf(codefile, "\n\n"); + close_codefile(); + } } diff --git a/source4/heimdal/lib/asn1/gen_copy.c b/source4/heimdal/lib/asn1/gen_copy.c index 37c9304779..5042ed64ed 100644 --- a/source4/heimdal/lib/asn1/gen_copy.c +++ b/source4/heimdal/lib/asn1/gen_copy.c @@ -149,7 +149,7 @@ copy_type (const char *from, const char *to, const Type *t, int preserve) to, have_ellipsis->gen_name); used_fail++; } - fprintf(codefile, "}\n"); + fprintf(codefile, "}\n"); } break; } diff --git a/source4/heimdal/lib/asn1/gen_decode.c b/source4/heimdal/lib/asn1/gen_decode.c index 2bd5acb47e..cf7f0b05dc 100644 --- a/source4/heimdal/lib/asn1/gen_decode.c +++ b/source4/heimdal/lib/asn1/gen_decode.c @@ -230,7 +230,7 @@ range_check(const char *name, static int decode_type (const char *name, const Type *t, int optional, - const char *forwstr, const char *tmpstr) + const char *forwstr, const char *tmpstr, const char *dertype) { switch (t->type) { case TType: { @@ -289,7 +289,17 @@ decode_type (const char *name, const Type *t, int optional, decode_primitive ("enumerated", name, forwstr); break; case TOctetString: + if (dertype) { + fprintf(codefile, + "if (%s == CONS) {\n", + dertype); + decode_primitive("octet_string_ber", name, forwstr); + fprintf(codefile, + "} else {\n"); + } decode_primitive ("octet_string", name, forwstr); + if (dertype) + fprintf(codefile, "}\n"); if (t->range) range_check(name, "length", forwstr, t->range); break; @@ -340,10 +350,10 @@ decode_type (const char *name, const Type *t, int optional, name, m->gen_name); if (s == NULL) errx(1, "malloc"); - decode_type (s, m->type, m->optional, forwstr, m->gen_name); + decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL); free (s); } - + break; } case TSet: { @@ -382,7 +392,7 @@ decode_type (const char *name, const Type *t, int optional, "%s = calloc(1, sizeof(*%s));\n" "if (%s == NULL) { e = ENOMEM; %s; }\n", s, s, s, forwstr); - decode_type (s, m->type, 0, forwstr, m->gen_name); + decode_type (s, m->type, 0, forwstr, m->gen_name, NULL); free (s); fprintf(codefile, "members |= (1 << %d);\n", memno); @@ -458,7 +468,7 @@ decode_type (const char *name, const Type *t, int optional, asprintf (&sname, "%s_s_of", tmpstr); if (sname == NULL) errx(1, "malloc"); - decode_type (n, t->subtype, 0, forwstr, sname); + decode_type (n, t->subtype, 0, forwstr, sname, NULL); fprintf (codefile, "(%s)->len++;\n" "len = %s_origlen - ret;\n" @@ -480,21 +490,37 @@ decode_type (const char *name, const Type *t, int optional, decode_primitive ("general_string", name, forwstr); break; case TTag:{ - char *tname; + char *tname, *typestring; + char *ide = NULL; + + asprintf(&typestring, "%s_type", tmpstr); fprintf(codefile, "{\n" - "size_t %s_datalen, %s_oldlen;\n", - tmpstr, tmpstr); - if(dce_fix) + "size_t %s_datalen, %s_oldlen;\n" + "Der_type %s;\n", + tmpstr, tmpstr, typestring); + if(support_ber) fprintf(codefile, - "int dce_fix;\n"); - fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, %s, %s, " + "int is_indefinite;\n"); + + fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, " "&%s_datalen, &l);\n", classname(t->tag.tagclass), - is_primitive_type(t->subtype->type) ? "PRIM" : "CONS", + typestring, valuename(t->tag.tagclass, t->tag.tagvalue), tmpstr); + + /* XXX hardcode for now */ + if (support_ber && t->subtype->type == TOctetString) { + ide = typestring; + } else { + fprintf(codefile, + "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n", + typestring, + is_primitive_type(t->subtype->type) ? "PRIM" : "CONS"); + } + if(optional) { fprintf(codefile, "if(e) {\n" @@ -510,11 +536,12 @@ decode_type (const char *name, const Type *t, int optional, "p += l; len -= l; ret += l;\n" "%s_oldlen = len;\n", tmpstr); - if(dce_fix) + if(support_ber) fprintf (codefile, - "if((dce_fix = _heim_fix_dce(%s_datalen, &len)) < 0)\n" - "{ e = ASN1_BAD_FORMAT; %s; }\n", - tmpstr, forwstr); + "if((is_indefinite = _heim_fix_dce(%s_datalen, &len)) < 0)\n" + "{ e = ASN1_BAD_FORMAT; %s; }\n" + "if (is_indefinite) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }", + tmpstr, forwstr, forwstr); else fprintf(codefile, "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n" @@ -522,15 +549,22 @@ decode_type (const char *name, const Type *t, int optional, asprintf (&tname, "%s_Tag", tmpstr); if (tname == NULL) errx(1, "malloc"); - decode_type (name, t->subtype, 0, forwstr, tname); - if(dce_fix) + decode_type (name, t->subtype, 0, forwstr, tname, ide); + if(support_ber) fprintf(codefile, - "if(dce_fix){\n" - "e = der_match_tag_and_length (p, len, " - "(Der_class)0,(Der_type)0, UT_EndOfContent, " + "if(is_indefinite){\n" + "len += 2;\n" + "e = der_match_tag_and_length(p, len, " + "(Der_class)0, &%s, UT_EndOfContent, " "&%s_datalen, &l);\n" - "if(e) %s;\np += l; len -= l; ret += l;\n" - "} else \n", tmpstr, forwstr); + "if(e) %s;\n" + "p += l; len -= l; ret += l;\n" + "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n" + "} else \n", + typestring, + tmpstr, + forwstr, + typestring, forwstr); fprintf(codefile, "len = %s_oldlen - %s_datalen;\n", tmpstr, tmpstr); @@ -540,6 +574,7 @@ decode_type (const char *name, const Type *t, int optional, fprintf(codefile, "}\n"); free(tname); + free(typestring); break; } case TChoice: { @@ -555,7 +590,7 @@ decode_type (const char *name, const Type *t, int optional, Der_class cl; Der_type ty; unsigned tag; - + if (m->ellipsis) { have_ellipsis = m; continue; @@ -573,7 +608,7 @@ decode_type (const char *name, const Type *t, int optional, name, m->gen_name); if (s == NULL) errx(1, "malloc"); - decode_type (s, m->type, m->optional, forwstr, m->gen_name); + decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL); fprintf(codefile, "(%s)->element = %s;\n", name, m->label); @@ -695,7 +730,7 @@ generate_type_decode (const Symbol *s) fprintf (codefile, "\n"); fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */ - decode_type ("data", s->type, 0, "goto fail", "Top"); + decode_type ("data", s->type, 0, "goto fail", "Top", NULL); if (preserve) fprintf (codefile, "data->_save.data = calloc(1, ret);\n" diff --git a/source4/heimdal/lib/asn1/gen_encode.c b/source4/heimdal/lib/asn1/gen_encode.c index d80a2f8d1f..1f8078a0ee 100644 --- a/source4/heimdal/lib/asn1/gen_encode.c +++ b/source4/heimdal/lib/asn1/gen_encode.c @@ -257,7 +257,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) if (t->members == NULL) break; - + ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { char *s; @@ -388,7 +388,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) int c; asprintf (&tname, "%s_tag", tmpstr); if (tname == NULL) - errx(1, "malloc"); + errx(1, "malloc"); c = encode_type (name, t->subtype, tname); fprintf (codefile, "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n" diff --git a/source4/heimdal/lib/asn1/gen_free.c b/source4/heimdal/lib/asn1/gen_free.c index 305d7de247..fac1f6da5d 100644 --- a/source4/heimdal/lib/asn1/gen_free.c +++ b/source4/heimdal/lib/asn1/gen_free.c @@ -110,7 +110,7 @@ free_type (const char *name, const Type *t, int preserve) if(t->type == TChoice) fprintf(codefile, "break;\n"); } - + if(t->type == TChoice) { if (have_ellipsis) fprintf(codefile, diff --git a/source4/heimdal/lib/asn1/gen_length.c b/source4/heimdal/lib/asn1/gen_length.c index a1df4eef6b..7f9755e2da 100644 --- a/source4/heimdal/lib/asn1/gen_length.c +++ b/source4/heimdal/lib/asn1/gen_length.c @@ -139,7 +139,7 @@ length_type (const char *name, const Type *t, ASN1_TAILQ_FOREACH(m, t->members, members) { char *s; - + if (m->ellipsis) { have_ellipsis = m; continue; diff --git a/source4/heimdal/lib/asn1/gen_locl.h b/source4/heimdal/lib/asn1/gen_locl.h index c8b3896314..2bb64b5a38 100644 --- a/source4/heimdal/lib/asn1/gen_locl.h +++ b/source4/heimdal/lib/asn1/gen_locl.h @@ -36,9 +36,8 @@ #ifndef __GEN_LOCL_H__ #define __GEN_LOCL_H__ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif + #include <assert.h> #include <stdio.h> #include <stdlib.h> @@ -80,9 +79,14 @@ int yyparse(void); int preserve_type(const char *); int seq_type(const char *); +void generate_header_of_codefile(const char *); +void close_codefile(void); + + extern FILE *headerfile, *codefile, *logfile; -extern int dce_fix; +extern int support_ber; extern int rfc1510_bitstring; +extern int one_code_file; extern int error_flag; diff --git a/source4/heimdal/lib/asn1/k5.asn1 b/source4/heimdal/lib/asn1/krb5.asn1 index 9b36498161..8edb0fde69 100644 --- a/source4/heimdal/lib/asn1/k5.asn1 +++ b/source4/heimdal/lib/asn1/krb5.asn1 @@ -13,6 +13,7 @@ NAME-TYPE ::= INTEGER { KRB5_NT_X500_PRINCIPAL(6), -- PKINIT KRB5_NT_SMTP_NAME(7), -- Name in form of SMTP email name KRB5_NT_ENTERPRISE_PRINCIPAL(10), -- Windows 2000 UPN + KRB5_NT_WELLKNOWN(11), -- Wellknown KRB5_NT_ENT_PRINCIPAL_AND_ID(-130), -- Windows 2000 UPN and SID KRB5_NT_MS_PRINCIPAL(-128), -- NT 4 style name KRB5_NT_MS_PRINCIPAL_AND_ID(-129) -- NT style name and SID @@ -64,6 +65,10 @@ PADATA-TYPE ::= INTEGER { KRB5-PADATA-GET-FROM-TYPED-DATA(22), KRB5-PADATA-SAM-ETYPE-INFO(23), KRB5-PADATA-SERVER-REFERRAL(25), + KRB5-PADATA-ALT-PRINC(24), -- (crawdad@fnal.gov) + KRB5-PADATA-SAM-CHALLENGE2(30), -- (kenh@pobox.com) + KRB5-PADATA-SAM-RESPONSE2(31), -- (kenh@pobox.com) + KRB5-PA-EXTRA-TGT(41), -- Reserved extra TGT KRB5-PADATA-TD-KRB-PRINCIPAL(102), -- PrincipalName KRB5-PADATA-PK-TD-TRUSTED-CERTIFIERS(104), -- PKINIT KRB5-PADATA-PK-TD-CERTIFICATE-INDEX(105), -- PKINIT @@ -71,13 +76,30 @@ PADATA-TYPE ::= INTEGER { KRB5-PADATA-TD-REQ-NONCE(107), -- INTEGER KRB5-PADATA-TD-REQ-SEQ(108), -- INTEGER KRB5-PADATA-PA-PAC-REQUEST(128), -- jbrezak@exchange.microsoft.com - KRB5-PADATA-S4U2SELF(129), - KRB5-PADATA-EPAC(130), -- EPAK - KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to - -- tell KDC that is supports + KRB5-PADATA-FOR-USER(129), -- MS-KILE + KRB5-PADATA-FOR-X509-USER(130), -- MS-KILE + KRB5-PADATA-FOR-CHECK-DUPS(131), -- MS-KILE + KRB5-PADATA-AS-CHECKSUM(132), -- MS-KILE + KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to + -- tell KDC that is supports -- the asCheckSum in the -- PK-AS-REP - KRB5-PADATA-CLIENT-CANONICALIZED(133) -- + KRB5-PADATA-CLIENT-CANONICALIZED(133), -- referals + KRB5-PADATA-FX-COOKIE(133), -- krb-wg-preauth-framework + KRB5-PADATA-AUTHENTICATION-SET(134), -- krb-wg-preauth-framework + KRB5-PADATA-AUTH-SET-SELECTED(135), -- krb-wg-preauth-framework + KRB5-PADATA-FX-FAST(136), -- krb-wg-preauth-framework + KRB5-PADATA-FX-ERROR(137), -- krb-wg-preauth-framework + KRB5-PADATA-ENCRYPTED-CHALLENGE(138), -- krb-wg-preauth-framework + KRB5-PADATA-OTP-CHALLENGE(141), -- (gareth.richards@rsa.com) + KRB5-PADATA-OTP-REQUEST(142), -- (gareth.richards@rsa.com) + KBB5-PADATA-OTP-CONFIRM(143), -- (gareth.richards@rsa.com) + KRB5-PADATA-OTP-PIN-CHANGE(144), -- (gareth.richards@rsa.com) + KRB5-PADATA-EPAK-AS-REQ(145), + KRB5-PADATA-EPAK-AS-REP(146), + KRB5-PADATA-PKINIT-KX(147), -- krb-wg-anon + KRB5-PADATA-PKU2U-NAME(148), -- zhu-pku2u + KRB5-PADATA-SUPPORTED-ETYPES(165) -- MS-KILE } AUTHDATA-TYPE ::= INTEGER { @@ -174,6 +196,8 @@ Principal ::= SEQUENCE { realm[1] Realm } +Principals ::= SEQUENCE OF Principal + HostAddress ::= SEQUENCE { addr-type[0] krb5int32, address[1] OCTET STRING @@ -387,7 +411,7 @@ PA-ENC-TS-ENC ::= SEQUENCE { -- draft-brezak-win2k-krb-authz-01 PA-PAC-REQUEST ::= SEQUENCE { - include-pac[0] BOOLEAN -- Indicates whether a PAC + include-pac[0] BOOLEAN -- Indicates whether a PAC -- should be included or not } @@ -618,21 +642,19 @@ PA-S4U2Self ::= SEQUENCE { auth[3] GeneralString } -KRB5SignedPathPrincipals ::= SEQUENCE OF Principal - -- never encoded on the wire, just used to checksum over KRB5SignedPathData ::= SEQUENCE { encticket[0] EncTicketPart, - delegated[1] KRB5SignedPathPrincipals OPTIONAL + delegated[1] Principals OPTIONAL } KRB5SignedPath ::= SEQUENCE { -- DERcoded KRB5SignedPathData - -- krbtgt key (etype), KeyUsage = XXX + -- krbtgt key (etype), KeyUsage = XXX etype[0] ENCTYPE, cksum[1] Checksum, -- srvs delegated though - delegated[2] KRB5SignedPathPrincipals OPTIONAL + delegated[2] Principals OPTIONAL } PA-ClientCanonicalizedNames ::= SEQUENCE{ @@ -666,6 +688,63 @@ PA-ServerReferralData ::= SEQUENCE { ... } +FastOptions ::= BIT STRING { + reserved(0), + hide-client-names(1), + kdc-follow--referrals(16) +} + +KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + padata [1] SEQUENCE OF PA-DATA, + req-body [2] KDC-REQ-BODY, + ... +} + +KrbFastArmor ::= SEQUENCE { + armor-type [0] krb5int32, + armor-value [1] OCTET STRING, + ... +} + +KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + req-checksum [1] Checksum, + enc-fast-req [2] EncryptedData -- KrbFastReq -- +} + +PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... +} + +KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] krb5int32, + crealm [2] Realm, + cname [3] PrincipalName, + checksum [4] Checksum, + ticket-checksum [5] Checksum, + ... +} + +KrbFastResponse ::= SEQUENCE { + padata [0] SEQUENCE OF PA-DATA, + rep-key [1] EncryptionKey OPTIONAL, + finished [2] KrbFastFinished OPTIONAL, + ... +} + +KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + ... +} + +PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... +} + END -- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1 diff --git a/source4/heimdal/lib/asn1/krb5.opt b/source4/heimdal/lib/asn1/krb5.opt new file mode 100644 index 0000000000..1d6d5e8989 --- /dev/null +++ b/source4/heimdal/lib/asn1/krb5.opt @@ -0,0 +1,6 @@ +--encode-rfc1510-bit-string +--sequence=Principals +--sequence=AuthorizationData +--sequence=METHOD-DATA +--sequence=ETYPE-INFO +--sequence=ETYPE-INFO2 diff --git a/source4/heimdal/lib/asn1/kx509.asn1 b/source4/heimdal/lib/asn1/kx509.asn1 index 820abc8106..14ebf50ecd 100644 --- a/source4/heimdal/lib/asn1/kx509.asn1 +++ b/source4/heimdal/lib/asn1/kx509.asn1 @@ -3,6 +3,17 @@ KX509 DEFINITIONS ::= BEGIN +KX509-ERROR-CODE ::= INTEGER { + KX509-STATUS-GOOD(0), + KX509-STATUS-CLIENT-BAD(1), + KX509-STATUS-CLIENT-FIX(2), + KX509-STATUS-CLIENT-TEMP(3), + KX509-STATUS-SERVER-BAD(4), + KX509-STATUS-SERVER-TEMP(5), + -- 6 is used internally in the umich client, avoid that + KX509-STATUS-SERVER-KEY(7) +} + Kx509Request ::= SEQUENCE { authenticator OCTET STRING, pk-hash OCTET STRING, diff --git a/source4/heimdal/lib/asn1/lex.l b/source4/heimdal/lib/asn1/lex.l index 1198ef16a6..7bd442bc50 100644 --- a/source4/heimdal/lib/asn1/lex.l +++ b/source4/heimdal/lib/asn1/lex.l @@ -46,7 +46,7 @@ #endif #undef ECHO #include "symbol.h" -#include "parse.h" +#include "asn1parse.h" #include "lex.h" #include "gen_locl.h" @@ -216,7 +216,7 @@ WITH { return kw_WITH; } char *p = buf; int f = 0; int skip_ws = 0; - + while((c = input()) != EOF) { if(isspace(c) && skip_ws) { if(c == '\n') @@ -224,7 +224,7 @@ WITH { return kw_WITH; } continue; } skip_ws = 0; - + if(c == '"') { if(f) { *p++ = '"'; diff --git a/source4/heimdal/lib/asn1/main.c b/source4/heimdal/lib/asn1/main.c index 6a97634310..115c82a9c7 100644 --- a/source4/heimdal/lib/asn1/main.c +++ b/source4/heimdal/lib/asn1/main.c @@ -62,15 +62,20 @@ seq_type(const char *p) return 0; } -int dce_fix; +int support_ber; int rfc1510_bitstring; +int one_code_file; +char *option_file; int version_flag; int help_flag; struct getargs args[] = { { "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring }, - { "decode-dce-ber", 0, arg_flag, &dce_fix }, + { "decode-dce-ber", 0, arg_flag, &support_ber }, + { "support-ber", 0, arg_flag, &support_ber }, { "preserve-binary", 0, arg_strings, &preserve }, { "sequence", 0, arg_strings, &seq }, + { "one-code-file", 0, arg_flag, &one_code_file }, + { "option-file", 0, arg_string, &option_file }, { "version", 0, arg_flag, &version_flag }, { "help", 0, arg_flag, &help_flag } }; @@ -92,6 +97,8 @@ main(int argc, char **argv) const char *file; const char *name = NULL; int optidx = 0; + char **arg = NULL; + size_t len = 0, i; setprogname(argv[0]); if(getarg(args, num_args, argc, argv, &optidx)) @@ -121,7 +128,58 @@ main(int argc, char **argv) name = argv[optidx + 1]; } + /* + * Parse extra options file + */ + if (option_file) { + char buf[1024]; + FILE *opt; + + opt = fopen(option_file, "r"); + if (opt == NULL) { + perror("open"); + exit(1); + } + + arg = calloc(2, sizeof(arg[0])); + arg[0] = option_file; + arg[1] = NULL; + len = 1; + + while (fgets(buf, sizeof(buf), opt) != NULL) { + buf[strcspn(buf, "\n\r")] = '\0'; + + arg = realloc(arg, (len + 2) * sizeof(arg[0])); + if (argv == NULL) { + perror("malloc"); + exit(1); + } + arg[len] = strdup(buf); + if (arg[len] == NULL) { + perror("strdup"); + exit(1); + } + arg[len + 1] = NULL; + len++; + } + fclose(opt); + + optidx = 0; + if(getarg(args, num_args, len, arg, &optidx)) + usage(1); + + if (len != optidx) { + fprintf(stderr, "extra args"); + exit(1); + } + } + + init_generate (file, name); + + if (one_code_file) + generate_header_of_codefile(name); + initsym (); ret = yyparse (); if(ret != 0 || error_flag != 0) @@ -129,5 +187,15 @@ main(int argc, char **argv) close_generate (); if (argc != optidx) fclose(yyin); + + if (one_code_file) + close_codefile(); + + if (arg) { + for (i = 1; i < len; i++) + free(arg[i]); + free(arg); + } + return 0; } diff --git a/source4/heimdal/lib/asn1/parse.y b/source4/heimdal/lib/asn1/parse.y deleted file mode 100644 index aca4a062b8..0000000000 --- a/source4/heimdal/lib/asn1/parse.y +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -%{ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "symbol.h" -#include "lex.h" -#include "gen_locl.h" -#include "der.h" - -RCSID("$Id$"); - -static Type *new_type (Typetype t); -static struct constraint_spec *new_constraint_spec(enum ctype); -static Type *new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype); -void yyerror (const char *); -static struct objid *new_objid(const char *label, int value); -static void add_oid_to_tail(struct objid *, struct objid *); -static void fix_labels(Symbol *s); - -struct string_list { - char *string; - struct string_list *next; -}; - -%} - -%union { - int constant; - struct value *value; - struct range *range; - char *name; - Type *type; - Member *member; - struct objid *objid; - char *defval; - struct string_list *sl; - struct tagtype tag; - struct memhead *members; - struct constraint_spec *constraint_spec; -} - -%token kw_ABSENT -%token kw_ABSTRACT_SYNTAX -%token kw_ALL -%token kw_APPLICATION -%token kw_AUTOMATIC -%token kw_BEGIN -%token kw_BIT -%token kw_BMPString -%token kw_BOOLEAN -%token kw_BY -%token kw_CHARACTER -%token kw_CHOICE -%token kw_CLASS -%token kw_COMPONENT -%token kw_COMPONENTS -%token kw_CONSTRAINED -%token kw_CONTAINING -%token kw_DEFAULT -%token kw_DEFINITIONS -%token kw_EMBEDDED -%token kw_ENCODED -%token kw_END -%token kw_ENUMERATED -%token kw_EXCEPT -%token kw_EXPLICIT -%token kw_EXPORTS -%token kw_EXTENSIBILITY -%token kw_EXTERNAL -%token kw_FALSE -%token kw_FROM -%token kw_GeneralString -%token kw_GeneralizedTime -%token kw_GraphicString -%token kw_IA5String -%token kw_IDENTIFIER -%token kw_IMPLICIT -%token kw_IMPLIED -%token kw_IMPORTS -%token kw_INCLUDES -%token kw_INSTANCE -%token kw_INTEGER -%token kw_INTERSECTION -%token kw_ISO646String -%token kw_MAX -%token kw_MIN -%token kw_MINUS_INFINITY -%token kw_NULL -%token kw_NumericString -%token kw_OBJECT -%token kw_OCTET -%token kw_OF -%token kw_OPTIONAL -%token kw_ObjectDescriptor -%token kw_PATTERN -%token kw_PDV -%token kw_PLUS_INFINITY -%token kw_PRESENT -%token kw_PRIVATE -%token kw_PrintableString -%token kw_REAL -%token kw_RELATIVE_OID -%token kw_SEQUENCE -%token kw_SET -%token kw_SIZE -%token kw_STRING -%token kw_SYNTAX -%token kw_T61String -%token kw_TAGS -%token kw_TRUE -%token kw_TYPE_IDENTIFIER -%token kw_TeletexString -%token kw_UNION -%token kw_UNIQUE -%token kw_UNIVERSAL -%token kw_UTCTime -%token kw_UTF8String -%token kw_UniversalString -%token kw_VideotexString -%token kw_VisibleString -%token kw_WITH - -%token RANGE -%token EEQUAL -%token ELLIPSIS - -%token <name> IDENTIFIER referencename -%token <name> STRING - -%token <constant> NUMBER -%type <constant> SignedNumber -%type <constant> Class tagenv - -%type <value> Value -%type <value> BuiltinValue -%type <value> IntegerValue -%type <value> BooleanValue -%type <value> ObjectIdentifierValue -%type <value> CharacterStringValue -%type <value> NullValue -%type <value> DefinedValue -%type <value> ReferencedValue -%type <value> Valuereference - -%type <type> Type -%type <type> BuiltinType -%type <type> BitStringType -%type <type> BooleanType -%type <type> ChoiceType -%type <type> ConstrainedType -%type <type> EnumeratedType -%type <type> IntegerType -%type <type> NullType -%type <type> OctetStringType -%type <type> SequenceType -%type <type> SequenceOfType -%type <type> SetType -%type <type> SetOfType -%type <type> TaggedType -%type <type> ReferencedType -%type <type> DefinedType -%type <type> UsefulType -%type <type> ObjectIdentifierType -%type <type> CharacterStringType -%type <type> RestrictedCharactedStringType - -%type <tag> Tag - -%type <member> ComponentType -%type <member> NamedBit -%type <member> NamedNumber -%type <member> NamedType -%type <members> ComponentTypeList -%type <members> Enumerations -%type <members> NamedBitList -%type <members> NamedNumberList - -%type <objid> objid objid_list objid_element objid_opt -%type <range> range size - -%type <sl> referencenames - -%type <constraint_spec> Constraint -%type <constraint_spec> ConstraintSpec -%type <constraint_spec> GeneralConstraint -%type <constraint_spec> ContentsConstraint -%type <constraint_spec> UserDefinedConstraint - - - -%start ModuleDefinition - -%% - -ModuleDefinition: IDENTIFIER objid_opt kw_DEFINITIONS TagDefault ExtensionDefault - EEQUAL kw_BEGIN ModuleBody kw_END - { - checkundefined(); - } - ; - -TagDefault : kw_EXPLICIT kw_TAGS - | kw_IMPLICIT kw_TAGS - { error_message("implicit tagging is not supported"); } - | kw_AUTOMATIC kw_TAGS - { error_message("automatic tagging is not supported"); } - | /* empty */ - ; - -ExtensionDefault: kw_EXTENSIBILITY kw_IMPLIED - { error_message("no extensibility options supported"); } - | /* empty */ - ; - -ModuleBody : /* Exports */ Imports AssignmentList - | /* empty */ - ; - -Imports : kw_IMPORTS SymbolsImported ';' - | /* empty */ - ; - -SymbolsImported : SymbolsFromModuleList - | /* empty */ - ; - -SymbolsFromModuleList: SymbolsFromModule - | SymbolsFromModuleList SymbolsFromModule - ; - -SymbolsFromModule: referencenames kw_FROM IDENTIFIER objid_opt - { - struct string_list *sl; - for(sl = $1; sl != NULL; sl = sl->next) { - Symbol *s = addsym(sl->string); - s->stype = Stype; - } - add_import($3); - } - ; - -AssignmentList : Assignment - | Assignment AssignmentList - ; - -Assignment : TypeAssignment - | ValueAssignment - ; - -referencenames : IDENTIFIER ',' referencenames - { - $$ = emalloc(sizeof(*$$)); - $$->string = $1; - $$->next = $3; - } - | IDENTIFIER - { - $$ = emalloc(sizeof(*$$)); - $$->string = $1; - $$->next = NULL; - } - ; - -TypeAssignment : IDENTIFIER EEQUAL Type - { - Symbol *s = addsym ($1); - s->stype = Stype; - s->type = $3; - fix_labels(s); - generate_type (s); - } - ; - -Type : BuiltinType - | ReferencedType - | ConstrainedType - ; - -BuiltinType : BitStringType - | BooleanType - | CharacterStringType - | ChoiceType - | EnumeratedType - | IntegerType - | NullType - | ObjectIdentifierType - | OctetStringType - | SequenceType - | SequenceOfType - | SetType - | SetOfType - | TaggedType - ; - -BooleanType : kw_BOOLEAN - { - $$ = new_tag(ASN1_C_UNIV, UT_Boolean, - TE_EXPLICIT, new_type(TBoolean)); - } - ; - -range : '(' Value RANGE Value ')' - { - if($2->type != integervalue) - error_message("Non-integer used in first part of range"); - if($2->type != integervalue) - error_message("Non-integer in second part of range"); - $$ = ecalloc(1, sizeof(*$$)); - $$->min = $2->u.integervalue; - $$->max = $4->u.integervalue; - } - | '(' Value RANGE kw_MAX ')' - { - if($2->type != integervalue) - error_message("Non-integer in first part of range"); - $$ = ecalloc(1, sizeof(*$$)); - $$->min = $2->u.integervalue; - $$->max = $2->u.integervalue - 1; - } - | '(' kw_MIN RANGE Value ')' - { - if($4->type != integervalue) - error_message("Non-integer in second part of range"); - $$ = ecalloc(1, sizeof(*$$)); - $$->min = $4->u.integervalue + 2; - $$->max = $4->u.integervalue; - } - | '(' Value ')' - { - if($2->type != integervalue) - error_message("Non-integer used in limit"); - $$ = ecalloc(1, sizeof(*$$)); - $$->min = $2->u.integervalue; - $$->max = $2->u.integervalue; - } - ; - - -IntegerType : kw_INTEGER - { - $$ = new_tag(ASN1_C_UNIV, UT_Integer, - TE_EXPLICIT, new_type(TInteger)); - } - | kw_INTEGER range - { - $$ = new_type(TInteger); - $$->range = $2; - $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$); - } - | kw_INTEGER '{' NamedNumberList '}' - { - $$ = new_type(TInteger); - $$->members = $3; - $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$); - } - ; - -NamedNumberList : NamedNumber - { - $$ = emalloc(sizeof(*$$)); - ASN1_TAILQ_INIT($$); - ASN1_TAILQ_INSERT_HEAD($$, $1, members); - } - | NamedNumberList ',' NamedNumber - { - ASN1_TAILQ_INSERT_TAIL($1, $3, members); - $$ = $1; - } - | NamedNumberList ',' ELLIPSIS - { $$ = $1; } /* XXX used for Enumerations */ - ; - -NamedNumber : IDENTIFIER '(' SignedNumber ')' - { - $$ = emalloc(sizeof(*$$)); - $$->name = $1; - $$->gen_name = estrdup($1); - output_name ($$->gen_name); - $$->val = $3; - $$->optional = 0; - $$->ellipsis = 0; - $$->type = NULL; - } - ; - -EnumeratedType : kw_ENUMERATED '{' Enumerations '}' - { - $$ = new_type(TInteger); - $$->members = $3; - $$ = new_tag(ASN1_C_UNIV, UT_Enumerated, TE_EXPLICIT, $$); - } - ; - -Enumerations : NamedNumberList /* XXX */ - ; - -BitStringType : kw_BIT kw_STRING - { - $$ = new_type(TBitString); - $$->members = emalloc(sizeof(*$$->members)); - ASN1_TAILQ_INIT($$->members); - $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); - } - | kw_BIT kw_STRING '{' NamedBitList '}' - { - $$ = new_type(TBitString); - $$->members = $4; - $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); - } - ; - -ObjectIdentifierType: kw_OBJECT kw_IDENTIFIER - { - $$ = new_tag(ASN1_C_UNIV, UT_OID, - TE_EXPLICIT, new_type(TOID)); - } - ; -OctetStringType : kw_OCTET kw_STRING size - { - Type *t = new_type(TOctetString); - t->range = $3; - $$ = new_tag(ASN1_C_UNIV, UT_OctetString, - TE_EXPLICIT, t); - } - ; - -NullType : kw_NULL - { - $$ = new_tag(ASN1_C_UNIV, UT_Null, - TE_EXPLICIT, new_type(TNull)); - } - ; - -size : - { $$ = NULL; } - | kw_SIZE range - { $$ = $2; } - ; - - -SequenceType : kw_SEQUENCE '{' /* ComponentTypeLists */ ComponentTypeList '}' - { - $$ = new_type(TSequence); - $$->members = $3; - $$ = new_tag(ASN1_C_UNIV, UT_Sequence, TE_EXPLICIT, $$); - } - | kw_SEQUENCE '{' '}' - { - $$ = new_type(TSequence); - $$->members = NULL; - $$ = new_tag(ASN1_C_UNIV, UT_Sequence, TE_EXPLICIT, $$); - } - ; - -SequenceOfType : kw_SEQUENCE size kw_OF Type - { - $$ = new_type(TSequenceOf); - $$->range = $2; - $$->subtype = $4; - $$ = new_tag(ASN1_C_UNIV, UT_Sequence, TE_EXPLICIT, $$); - } - ; - -SetType : kw_SET '{' /* ComponentTypeLists */ ComponentTypeList '}' - { - $$ = new_type(TSet); - $$->members = $3; - $$ = new_tag(ASN1_C_UNIV, UT_Set, TE_EXPLICIT, $$); - } - | kw_SET '{' '}' - { - $$ = new_type(TSet); - $$->members = NULL; - $$ = new_tag(ASN1_C_UNIV, UT_Set, TE_EXPLICIT, $$); - } - ; - -SetOfType : kw_SET kw_OF Type - { - $$ = new_type(TSetOf); - $$->subtype = $3; - $$ = new_tag(ASN1_C_UNIV, UT_Set, TE_EXPLICIT, $$); - } - ; - -ChoiceType : kw_CHOICE '{' /* AlternativeTypeLists */ ComponentTypeList '}' - { - $$ = new_type(TChoice); - $$->members = $3; - } - ; - -ReferencedType : DefinedType - | UsefulType - ; - -DefinedType : IDENTIFIER - { - Symbol *s = addsym($1); - $$ = new_type(TType); - if(s->stype != Stype && s->stype != SUndefined) - error_message ("%s is not a type\n", $1); - else - $$->symbol = s; - } - ; - -UsefulType : kw_GeneralizedTime - { - $$ = new_tag(ASN1_C_UNIV, UT_GeneralizedTime, - TE_EXPLICIT, new_type(TGeneralizedTime)); - } - | kw_UTCTime - { - $$ = new_tag(ASN1_C_UNIV, UT_UTCTime, - TE_EXPLICIT, new_type(TUTCTime)); - } - ; - -ConstrainedType : Type Constraint - { - /* if (Constraint.type == contentConstrant) { - assert(Constraint.u.constraint.type == octetstring|bitstring-w/o-NamedBitList); // remember to check type reference too - if (Constraint.u.constraint.type) { - assert((Constraint.u.constraint.type.length % 8) == 0); - } - } - if (Constraint.u.constraint.encoding) { - type == der-oid|ber-oid - } - */ - } - ; - - -Constraint : '(' ConstraintSpec ')' - { - $$ = $2; - } - ; - -ConstraintSpec : GeneralConstraint - ; - -GeneralConstraint: ContentsConstraint - | UserDefinedConstraint - ; - -ContentsConstraint: kw_CONTAINING Type - { - $$ = new_constraint_spec(CT_CONTENTS); - $$->u.content.type = $2; - $$->u.content.encoding = NULL; - } - | kw_ENCODED kw_BY Value - { - if ($3->type != objectidentifiervalue) - error_message("Non-OID used in ENCODED BY constraint"); - $$ = new_constraint_spec(CT_CONTENTS); - $$->u.content.type = NULL; - $$->u.content.encoding = $3; - } - | kw_CONTAINING Type kw_ENCODED kw_BY Value - { - if ($5->type != objectidentifiervalue) - error_message("Non-OID used in ENCODED BY constraint"); - $$ = new_constraint_spec(CT_CONTENTS); - $$->u.content.type = $2; - $$->u.content.encoding = $5; - } - ; - -UserDefinedConstraint: kw_CONSTRAINED kw_BY '{' '}' - { - $$ = new_constraint_spec(CT_USER); - } - ; - -TaggedType : Tag tagenv Type - { - $$ = new_type(TTag); - $$->tag = $1; - $$->tag.tagenv = $2; - if($3->type == TTag && $2 == TE_IMPLICIT) { - $$->subtype = $3->subtype; - free($3); - } else - $$->subtype = $3; - } - ; - -Tag : '[' Class NUMBER ']' - { - $$.tagclass = $2; - $$.tagvalue = $3; - $$.tagenv = TE_EXPLICIT; - } - ; - -Class : /* */ - { - $$ = ASN1_C_CONTEXT; - } - | kw_UNIVERSAL - { - $$ = ASN1_C_UNIV; - } - | kw_APPLICATION - { - $$ = ASN1_C_APPL; - } - | kw_PRIVATE - { - $$ = ASN1_C_PRIVATE; - } - ; - -tagenv : /* */ - { - $$ = TE_EXPLICIT; - } - | kw_EXPLICIT - { - $$ = TE_EXPLICIT; - } - | kw_IMPLICIT - { - $$ = TE_IMPLICIT; - } - ; - - -ValueAssignment : IDENTIFIER Type EEQUAL Value - { - Symbol *s; - s = addsym ($1); - - s->stype = SValue; - s->value = $4; - generate_constant (s); - } - ; - -CharacterStringType: RestrictedCharactedStringType - ; - -RestrictedCharactedStringType: kw_GeneralString - { - $$ = new_tag(ASN1_C_UNIV, UT_GeneralString, - TE_EXPLICIT, new_type(TGeneralString)); - } - | kw_UTF8String - { - $$ = new_tag(ASN1_C_UNIV, UT_UTF8String, - TE_EXPLICIT, new_type(TUTF8String)); - } - | kw_PrintableString - { - $$ = new_tag(ASN1_C_UNIV, UT_PrintableString, - TE_EXPLICIT, new_type(TPrintableString)); - } - | kw_VisibleString - { - $$ = new_tag(ASN1_C_UNIV, UT_VisibleString, - TE_EXPLICIT, new_type(TVisibleString)); - } - | kw_IA5String - { - $$ = new_tag(ASN1_C_UNIV, UT_IA5String, - TE_EXPLICIT, new_type(TIA5String)); - } - | kw_BMPString - { - $$ = new_tag(ASN1_C_UNIV, UT_BMPString, - TE_EXPLICIT, new_type(TBMPString)); - } - | kw_UniversalString - { - $$ = new_tag(ASN1_C_UNIV, UT_UniversalString, - TE_EXPLICIT, new_type(TUniversalString)); - } - - ; - -ComponentTypeList: ComponentType - { - $$ = emalloc(sizeof(*$$)); - ASN1_TAILQ_INIT($$); - ASN1_TAILQ_INSERT_HEAD($$, $1, members); - } - | ComponentTypeList ',' ComponentType - { - ASN1_TAILQ_INSERT_TAIL($1, $3, members); - $$ = $1; - } - | ComponentTypeList ',' ELLIPSIS - { - struct member *m = ecalloc(1, sizeof(*m)); - m->name = estrdup("..."); - m->gen_name = estrdup("asn1_ellipsis"); - m->ellipsis = 1; - ASN1_TAILQ_INSERT_TAIL($1, m, members); - $$ = $1; - } - ; - -NamedType : IDENTIFIER Type - { - $$ = emalloc(sizeof(*$$)); - $$->name = $1; - $$->gen_name = estrdup($1); - output_name ($$->gen_name); - $$->type = $2; - $$->ellipsis = 0; - } - ; - -ComponentType : NamedType - { - $$ = $1; - $$->optional = 0; - $$->defval = NULL; - } - | NamedType kw_OPTIONAL - { - $$ = $1; - $$->optional = 1; - $$->defval = NULL; - } - | NamedType kw_DEFAULT Value - { - $$ = $1; - $$->optional = 0; - $$->defval = $3; - } - ; - -NamedBitList : NamedBit - { - $$ = emalloc(sizeof(*$$)); - ASN1_TAILQ_INIT($$); - ASN1_TAILQ_INSERT_HEAD($$, $1, members); - } - | NamedBitList ',' NamedBit - { - ASN1_TAILQ_INSERT_TAIL($1, $3, members); - $$ = $1; - } - ; - -NamedBit : IDENTIFIER '(' NUMBER ')' - { - $$ = emalloc(sizeof(*$$)); - $$->name = $1; - $$->gen_name = estrdup($1); - output_name ($$->gen_name); - $$->val = $3; - $$->optional = 0; - $$->ellipsis = 0; - $$->type = NULL; - } - ; - -objid_opt : objid - | /* empty */ { $$ = NULL; } - ; - -objid : '{' objid_list '}' - { - $$ = $2; - } - ; - -objid_list : /* empty */ - { - $$ = NULL; - } - | objid_element objid_list - { - if ($2) { - $$ = $2; - add_oid_to_tail($2, $1); - } else { - $$ = $1; - } - } - ; - -objid_element : IDENTIFIER '(' NUMBER ')' - { - $$ = new_objid($1, $3); - } - | IDENTIFIER - { - Symbol *s = addsym($1); - if(s->stype != SValue || - s->value->type != objectidentifiervalue) { - error_message("%s is not an object identifier\n", - s->name); - exit(1); - } - $$ = s->value->u.objectidentifiervalue; - } - | NUMBER - { - $$ = new_objid(NULL, $1); - } - ; - -Value : BuiltinValue - | ReferencedValue - ; - -BuiltinValue : BooleanValue - | CharacterStringValue - | IntegerValue - | ObjectIdentifierValue - | NullValue - ; - -ReferencedValue : DefinedValue - ; - -DefinedValue : Valuereference - ; - -Valuereference : IDENTIFIER - { - Symbol *s = addsym($1); - if(s->stype != SValue) - error_message ("%s is not a value\n", - s->name); - else - $$ = s->value; - } - ; - -CharacterStringValue: STRING - { - $$ = emalloc(sizeof(*$$)); - $$->type = stringvalue; - $$->u.stringvalue = $1; - } - ; - -BooleanValue : kw_TRUE - { - $$ = emalloc(sizeof(*$$)); - $$->type = booleanvalue; - $$->u.booleanvalue = 0; - } - | kw_FALSE - { - $$ = emalloc(sizeof(*$$)); - $$->type = booleanvalue; - $$->u.booleanvalue = 0; - } - ; - -IntegerValue : SignedNumber - { - $$ = emalloc(sizeof(*$$)); - $$->type = integervalue; - $$->u.integervalue = $1; - } - ; - -SignedNumber : NUMBER - ; - -NullValue : kw_NULL - { - } - ; - -ObjectIdentifierValue: objid - { - $$ = emalloc(sizeof(*$$)); - $$->type = objectidentifiervalue; - $$->u.objectidentifiervalue = $1; - } - ; - -%% - -void -yyerror (const char *s) -{ - error_message ("%s\n", s); -} - -static Type * -new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype) -{ - Type *t; - if(oldtype->type == TTag && oldtype->tag.tagenv == TE_IMPLICIT) { - t = oldtype; - oldtype = oldtype->subtype; /* XXX */ - } else - t = new_type (TTag); - - t->tag.tagclass = tagclass; - t->tag.tagvalue = tagvalue; - t->tag.tagenv = tagenv; - t->subtype = oldtype; - return t; -} - -static struct objid * -new_objid(const char *label, int value) -{ - struct objid *s; - s = emalloc(sizeof(*s)); - s->label = label; - s->value = value; - s->next = NULL; - return s; -} - -static void -add_oid_to_tail(struct objid *head, struct objid *tail) -{ - struct objid *o; - o = head; - while (o->next) - o = o->next; - o->next = tail; -} - -static Type * -new_type (Typetype tt) -{ - Type *t = ecalloc(1, sizeof(*t)); - t->type = tt; - return t; -} - -static struct constraint_spec * -new_constraint_spec(enum ctype ct) -{ - struct constraint_spec *c = ecalloc(1, sizeof(*c)); - c->ctype = ct; - return c; -} - -static void fix_labels2(Type *t, const char *prefix); -static void fix_labels1(struct memhead *members, const char *prefix) -{ - Member *m; - - if(members == NULL) - return; - ASN1_TAILQ_FOREACH(m, members, members) { - asprintf(&m->label, "%s_%s", prefix, m->gen_name); - if (m->label == NULL) - errx(1, "malloc"); - if(m->type != NULL) - fix_labels2(m->type, m->label); - } -} - -static void fix_labels2(Type *t, const char *prefix) -{ - for(; t; t = t->subtype) - fix_labels1(t->members, prefix); -} - -static void -fix_labels(Symbol *s) -{ - char *p; - asprintf(&p, "choice_%s", s->gen_name); - if (p == NULL) - errx(1, "malloc"); - fix_labels2(s->type, p); - free(p); -} diff --git a/source4/heimdal/lib/asn1/pkcs12.asn1 b/source4/heimdal/lib/asn1/pkcs12.asn1 index 4d6454a08f..8b604c68d7 100644 --- a/source4/heimdal/lib/asn1/pkcs12.asn1 +++ b/source4/heimdal/lib/asn1/pkcs12.asn1 @@ -50,7 +50,7 @@ PKCS12-AuthenticatedSafe ::= SEQUENCE OF ContentInfo PKCS12-Attribute ::= SEQUENCE { attrId OBJECT IDENTIFIER, - attrValues -- SET OF -- heim_any_set + attrValues -- SET OF -- heim_any_set } PKCS12-Attributes ::= SET OF PKCS12-Attribute diff --git a/source4/heimdal/lib/asn1/pkcs8.asn1 b/source4/heimdal/lib/asn1/pkcs8.asn1 index 203d91eef8..45a7d715df 100644 --- a/source4/heimdal/lib/asn1/pkcs8.asn1 +++ b/source4/heimdal/lib/asn1/pkcs8.asn1 @@ -24,7 +24,7 @@ PKCS8EncryptedData ::= OCTET STRING PKCS8EncryptedPrivateKeyInfo ::= SEQUENCE { encryptionAlgorithm AlgorithmIdentifier, - encryptedData PKCS8EncryptedData + encryptedData PKCS8EncryptedData } END diff --git a/source4/heimdal/lib/asn1/pkinit.asn1 b/source4/heimdal/lib/asn1/pkinit.asn1 index 758af6f86e..f36ebf0b32 100644 --- a/source4/heimdal/lib/asn1/pkinit.asn1 +++ b/source4/heimdal/lib/asn1/pkinit.asn1 @@ -27,11 +27,11 @@ id-pkinit-san OBJECT IDENTIFIER ::= x509-sanan(2) } id-pkinit-ms-eku OBJECT IDENTIFIER ::= - { iso(1) org(3) dod(6) internet(1) private(4) + { iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) microsoft(311) 20 2 2 } id-pkinit-ms-san OBJECT IDENTIFIER ::= - { iso(1) org(3) dod(6) internet(1) private(4) + { iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) microsoft(311) 20 2 3 } MS-UPN-SAN ::= UTF8String @@ -152,19 +152,18 @@ TrustedCA-Win2k ::= CHOICE { issuerAndSerial [2] IssuerAndSerialNumber } -PA-PK-AS-REQ-Win2k ::= SEQUENCE { - signed-auth-pack [0] IMPLICIT OCTET STRING, - trusted-certifiers [2] SEQUENCE OF TrustedCA-Win2k OPTIONAL, - kdc-cert [3] IMPLICIT OCTET STRING OPTIONAL, +PA-PK-AS-REQ-Win2k ::= SEQUENCE { + signed-auth-pack [0] IMPLICIT OCTET STRING, + trusted-certifiers [2] SEQUENCE OF TrustedCA-Win2k OPTIONAL, + kdc-cert [3] IMPLICIT OCTET STRING OPTIONAL, encryption-cert [4] IMPLICIT OCTET STRING OPTIONAL } PA-PK-AS-REP-Win2k ::= CHOICE { - dhSignedData [0] IMPLICIT OCTET STRING, + dhSignedData [0] IMPLICIT OCTET STRING, encKeyPack [1] IMPLICIT OCTET STRING } - KDCDHKeyInfo-Win2k ::= SEQUENCE { nonce [0] INTEGER (-2147483648..2147483647), subjectPublicKey [2] BIT STRING @@ -176,12 +175,18 @@ ReplyKeyPack-Win2k ::= SEQUENCE { ... } -PkinitSP80056AOtherInfo ::= SEQUENCE { - algorithmID AlgorithmIdentifier, - partyUInfo [0] OCTET STRING, - partyVInfo [1] OCTET STRING, - suppPubInfo [2] OCTET STRING OPTIONAL, - suppPrivInfo [3] OCTET STRING OPTIONAL +PA-PK-AS-REP-BTMM ::= SEQUENCE { + dhSignedData [0] heim_any OPTIONAL, + encKeyPack [1] heim_any OPTIONAL +} + + +PkinitSP80056AOtherInfo ::= SEQUENCE { + algorithmID AlgorithmIdentifier, + partyUInfo [0] OCTET STRING, + partyVInfo [1] OCTET STRING, + suppPubInfo [2] OCTET STRING OPTIONAL, + suppPrivInfo [3] OCTET STRING OPTIONAL } PkinitSuppPubInfo ::= SEQUENCE { diff --git a/source4/heimdal/lib/asn1/rfc2459.asn1 b/source4/heimdal/lib/asn1/rfc2459.asn1 index 8e24f0740b..51cac55cc0 100644 --- a/source4/heimdal/lib/asn1/rfc2459.asn1 +++ b/source4/heimdal/lib/asn1/rfc2459.asn1 @@ -6,7 +6,7 @@ RFC2459 DEFINITIONS ::= BEGIN IMPORTS heim_any FROM heim; Version ::= INTEGER { - rfc3280_version_1(0), + rfc3280_version_1(0), rfc3280_version_2(1), rfc3280_version_3(2) } @@ -29,7 +29,7 @@ id-pkcs2-md2 OBJECT IDENTIFIER ::= { id-pkcs-2 2 } id-pkcs2-md4 OBJECT IDENTIFIER ::= { id-pkcs-2 4 } id-pkcs2-md5 OBJECT IDENTIFIER ::= { id-pkcs-2 5 } -id-rsa-digestAlgorithm OBJECT IDENTIFIER ::= +id-rsa-digestAlgorithm OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 2 } id-rsa-digest-md2 OBJECT IDENTIFIER ::= { id-rsa-digestAlgorithm 2 } @@ -54,7 +54,7 @@ id-secsig-sha-1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) id-nistAlgorithm OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) 4 } - + id-nist-aes-algs OBJECT IDENTIFIER ::= { id-nistAlgorithm 1 } id-aes-128-cbc OBJECT IDENTIFIER ::= { id-nist-aes-algs 2 } @@ -72,9 +72,42 @@ id-dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) ansi-x942(10046) number-type(2) 1 } +-- ECC + +id-ecPublicKey OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } + +id-ecDH OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) schemes(1) + ecdh(12) } + +id-ecMQV OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) schemes(1) + ecmqv(13) } + +id-ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 2 } + +id-ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } + +-- some EC group ids + +id-ec-group-secp256r1 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) + prime(1) 7 } + +id-ec-group-secp160r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 8 } + +id-ec-group-secp160r2 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 30 } + +-- DSA + id-x9-57 OBJECT IDENTIFIER ::= { - iso(1) member-body(2) us(840) ansi-x942(10046) - 4 } + iso(1) member-body(2) us(840) ansi-x942(10046) 4 } id-dsa OBJECT IDENTIFIER ::= { id-x9-57 1 } id-dsa-with-sha1 OBJECT IDENTIFIER ::= { id-x9-57 3 } @@ -256,8 +289,8 @@ KeyIdentifier ::= OCTET STRING AuthorityKeyIdentifier ::= SEQUENCE { keyIdentifier [0] IMPLICIT OCTET STRING OPTIONAL, - authorityCertIssuer [1] IMPLICIT -- GeneralName -- - SEQUENCE -- SIZE (1..MAX) -- OF GeneralName OPTIONAL, + authorityCertIssuer [1] IMPLICIT -- GeneralName -- + SEQUENCE -- SIZE (1..MAX) -- OF GeneralName OPTIONAL, authorityCertSerialNumber [2] IMPLICIT INTEGER OPTIONAL } @@ -269,7 +302,7 @@ id-x509-ce-basicConstraints OBJECT IDENTIFIER ::= { id-x509-ce 19 } BasicConstraints ::= SEQUENCE { cA BOOLEAN OPTIONAL -- DEFAULT FALSE --, - pathLenConstraint INTEGER (0..4294967295) OPTIONAL + pathLenConstraint INTEGER (0..4294967295) OPTIONAL } id-x509-ce-nameConstraints OBJECT IDENTIFIER ::= { id-x509-ce 30 } @@ -350,6 +383,21 @@ DSAParams ::= SEQUENCE { g INTEGER } +-- draft-ietf-pkix-ecc-subpubkeyinfo-11 + +ECPoint ::= OCTET STRING + +ECParameters ::= CHOICE { + namedCurve OBJECT IDENTIFIER + -- implicitCurve NULL + -- specifiedCurve SpecifiedECDomain +} + +ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} + -- really pkcs1 RSAPublicKey ::= SEQUENCE { @@ -382,7 +430,7 @@ DigestInfo ::= SEQUENCE { -- szOID_CERTIFICATE_TEMPLATE "1.3.6.1.4.1.311.21.7" is Encoded as: --- TemplateVersion ::= INTEGER (0..4294967295) +-- TemplateVersion ::= INTEGER (0..4294967295) -- CertificateTemplate ::= SEQUENCE { -- templateID OBJECT IDENTIFIER, @@ -393,7 +441,7 @@ DigestInfo ::= SEQUENCE { -- -- CRL --- +-- TBSCRLCertList ::= SEQUENCE { version Version OPTIONAL, -- if present, MUST be v2 @@ -489,16 +537,16 @@ id-uspkicommon-piv-interim OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 6 9 1 } --- Netscape extentions -id-netscape OBJECT IDENTIFIER ::= +id-netscape OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730) } id-netscape-cert-comment OBJECT IDENTIFIER ::= { id-netscape 1 13 } --- MS extentions -id-ms-cert-enroll-domaincontroller OBJECT IDENTIFIER ::= +id-ms-cert-enroll-domaincontroller OBJECT IDENTIFIER ::= { 1 3 6 1 4 1 311 20 2 } -id-ms-client-authentication OBJECT IDENTIFIER ::= +id-ms-client-authentication OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7 3 2 } -- DER:1e:20:00:44:00:6f:00:6d:00:61:00:69:00:6e:00:43:00:6f:00:6e:00:74:00:72:00:6f:00:6c:00:6c:00:65:00:72 diff --git a/source4/heimdal/lib/asn1/test.asn1 b/source4/heimdal/lib/asn1/test.asn1 index d07bba6185..f6237b85b8 100644 --- a/source4/heimdal/lib/asn1/test.asn1 +++ b/source4/heimdal/lib/asn1/test.asn1 @@ -20,12 +20,12 @@ TESTSeq ::= SEQUENCE { TESTChoice1 ::= CHOICE { i1[1] INTEGER (-2147483648..2147483647), i2[2] INTEGER (-2147483648..2147483647), - ... + ... } TESTChoice2 ::= CHOICE { i1[1] INTEGER (-2147483648..2147483647), - ... + ... } TESTInteger ::= INTEGER (-2147483648..2147483647) @@ -35,7 +35,7 @@ TESTInteger3 ::= [5] IMPLICIT TESTInteger2 TESTImplicit ::= SEQUENCE { ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), - ti2[1] IMPLICIT SEQUENCE { + ti2[1] IMPLICIT SEQUENCE { foo[127] INTEGER (-2147483648..2147483647) }, ti3[2] IMPLICIT [5] IMPLICIT [4] IMPLICIT INTEGER (-2147483648..2147483647) @@ -59,19 +59,19 @@ TESTAlloc ::= SEQUENCE { TESTCONTAINING ::= OCTET STRING ( CONTAINING INTEGER ) -TESTENCODEDBY ::= OCTET STRING ( ENCODED BY +TESTENCODEDBY ::= OCTET STRING ( ENCODED BY { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } ) -TESTDer OBJECT IDENTIFIER ::= { +TESTDer OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } -TESTCONTAININGENCODEDBY ::= OCTET STRING ( CONTAINING INTEGER ENCODED BY +TESTCONTAININGENCODEDBY ::= OCTET STRING ( CONTAINING INTEGER ENCODED BY { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } ) -TESTCONTAININGENCODEDBY2 ::= OCTET STRING ( +TESTCONTAININGENCODEDBY2 ::= OCTET STRING ( CONTAINING INTEGER ENCODED BY TESTDer ) diff --git a/source4/heimdal/lib/com_err/com_err.c b/source4/heimdal/lib/com_err/com_err.c index 89c8ab2c89..a43d1e3e6c 100644 --- a/source4/heimdal/lib/com_err/com_err.c +++ b/source4/heimdal/lib/com_err/com_err.c @@ -31,10 +31,9 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H + #include <config.h> -RCSID("$Id$"); -#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/source4/heimdal/lib/com_err/compile_et.c b/source4/heimdal/lib/com_err/compile_et.c index 239617d1de..a28e51f8da 100644 --- a/source4/heimdal/lib/com_err/compile_et.c +++ b/source4/heimdal/lib/com_err/compile_et.c @@ -35,8 +35,6 @@ #include "compile_et.h" #include <getarg.h> -RCSID("$Id$"); - #include <roken.h> #include <err.h> #include "parse.h" diff --git a/source4/heimdal/lib/com_err/compile_et.h b/source4/heimdal/lib/com_err/compile_et.h index 430405d9d5..b0b8e21da1 100644 --- a/source4/heimdal/lib/com_err/compile_et.h +++ b/source4/heimdal/lib/com_err/compile_et.h @@ -36,9 +36,7 @@ #ifndef __COMPILE_ET_H__ #define __COMPILE_ET_H__ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include <err.h> #include <stdio.h> diff --git a/source4/heimdal/lib/com_err/error.c b/source4/heimdal/lib/com_err/error.c index d64225a758..6b12c00c7a 100644 --- a/source4/heimdal/lib/com_err/error.c +++ b/source4/heimdal/lib/com_err/error.c @@ -31,10 +31,9 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H + #include <config.h> -RCSID("$Id$"); -#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/source4/heimdal/lib/com_err/lex.l b/source4/heimdal/lib/com_err/lex.l index 84356405dd..b68814b21c 100644 --- a/source4/heimdal/lib/com_err/lex.l +++ b/source4/heimdal/lib/com_err/lex.l @@ -44,8 +44,6 @@ #include "parse.h" #include "lex.h" -RCSID("$Id$"); - static unsigned lineno = 1; static int getstring(void); diff --git a/source4/heimdal/lib/com_err/parse.y b/source4/heimdal/lib/com_err/parse.y index 99dddbe1e1..d64681d902 100644 --- a/source4/heimdal/lib/com_err/parse.y +++ b/source4/heimdal/lib/com_err/parse.y @@ -35,8 +35,6 @@ #include "compile_et.h" #include "lex.h" -RCSID("$Id$"); - void yyerror (char *s); static long name2number(const char *str); diff --git a/source4/heimdal/lib/gssapi/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi/gssapi.h index f8b599a664..9fe2bb8b46 100644 --- a/source4/heimdal/lib/gssapi/gssapi/gssapi.h +++ b/source4/heimdal/lib/gssapi/gssapi/gssapi.h @@ -53,6 +53,10 @@ #endif #endif +#ifndef GSSAPI_DEPRECATED +#define GSSAPI_DEPRECATED __attribute__((deprecated)) +#endif + /* * Now define the three implementation-dependent types. */ @@ -102,6 +106,11 @@ typedef struct gss_buffer_set_desc_struct { gss_buffer_desc *elements; } gss_buffer_set_desc, *gss_buffer_set_t; +typedef struct gss_iov_buffer_desc_struct { + OM_uint32 type; + gss_buffer_desc buffer; +} gss_iov_buffer_desc, *gss_iov_buffer_t; + /* * For now, define a QOP-type as an OM_uint32 */ @@ -178,6 +187,7 @@ typedef OM_uint32 gss_qop_t; #define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0) #define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0) #define GSS_C_EMPTY_BUFFER {0, NULL} +#define GSS_C_NO_IOV_BUFFER ((gss_iov_buffer_t)0) /* * Some alternate names for a couple of the above @@ -206,6 +216,27 @@ typedef OM_uint32 gss_qop_t; */ #define GSS_C_INDEFINITE 0xfffffffful +/* + * Type of gss_wrap_iov()/gss_unwrap_iov(). + */ + +#define GSS_IOV_BUFFER_TYPE_EMPTY 0 +#define GSS_IOV_BUFFER_TYPE_DATA 1 +#define GSS_IOV_BUFFER_TYPE_HEADER 2 +#define GSS_IOV_BUFFER_TYPE_MECH_PARAMS 3 + +#define GSS_IOV_BUFFER_TYPE_TRAILER 7 +#define GSS_IOV_BUFFER_TYPE_PADDING 9 +#define GSS_IOV_BUFFER_TYPE_STREAM 10 +#define GSS_IOV_BUFFER_TYPE_SIGN_ONLY 11 + +#define GSS_IOV_BUFFER_TYPE_FLAG_MASK 0xffff0000 +#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE 0x00010000 +#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED 0x00020000 + +#define GSS_IOV_BUFFER_TYPE(_t) ((_t) & ~GSS_IOV_BUFFER_TYPE_FLAG_MASK) +#define GSS_IOV_BUFFER_FLAGS(_t) ((_t) & GSS_IOV_BUFFER_TYPE_FLAG_MASK) + #ifdef __cplusplus extern "C" { #endif @@ -311,12 +342,6 @@ extern GSSAPI_LIB_VARIABLE gss_OID GSS_C_NT_EXPORT_NAME; extern GSSAPI_LIB_VARIABLE gss_OID GSS_SASL_DIGEST_MD5_MECHANISM; -/* - * NTLM mechanism - */ - -extern GSSAPI_LIB_VARIABLE gss_OID GSS_NTLM_MECHANISM; - /* Major status codes */ #define GSS_S_COMPLETE 0 @@ -744,6 +769,75 @@ gss_pseudo_random ); /* + * AEAD support + */ + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_wrap_iov(OM_uint32 * /* minor_status */, + gss_ctx_id_t /* context_handle */, + int /* conf_req_flag */, + gss_qop_t /* qop_req */, + int * /* conf_state */, + gss_iov_buffer_desc * /*iov */, + int /* iov_count */); + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_unwrap_iov(OM_uint32 * /* minor_status */, + gss_ctx_id_t /* context_handle */, + int * /* conf_state */, + gss_qop_t * /* qop_state */, + gss_iov_buffer_desc * /* iov */, + int /* iov_count */); + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_wrap_iov_length(OM_uint32 * /* minor_status */, + gss_ctx_id_t /* context_handle */, + int /* conf_req_flag */, + gss_qop_t /* qop_req */, + int * /* conf_state */, + gss_iov_buffer_desc * /* iov */, + int /* iov_count */); + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_release_iov_buffer(OM_uint32 * /* minor_status */, + gss_iov_buffer_desc * /* iov */, + int /* iov_count */); + + +OM_uint32 +gss_store_cred(OM_uint32 * /* minor_status */, + gss_cred_id_t /* input_cred_handle */, + gss_cred_usage_t /* cred_usage */, + const gss_OID /* desired_mech */, + OM_uint32 /* overwrite_cred */, + OM_uint32 /* default_cred */, + gss_OID_set * /* elements_stored */, + gss_cred_usage_t * /* cred_usage_stored */); + + +/* + * Query functions + */ + +typedef struct { + size_t header; /**< size of header */ + size_t trailer; /**< size of trailer */ + size_t max_msg_size; /**< maximum message size */ + size_t buffers; /**< extra GSS_IOV_BUFFER_TYPE_EMPTY buffer to pass */ + size_t blocksize; /**< Specificed optimal size of messages, also + is the maximum padding size + (GSS_IOV_BUFFER_TYPE_PADDING) */ +} gss_context_stream_sizes; + +extern gss_OID GSSAPI_LIB_VARIABLE GSS_C_ATTR_STREAM_SIZES; + + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_context_query_attributes(OM_uint32 * /* minor_status */, + gss_OID /* attribute */, + void * /*data*/, + size_t /* len */); +/* * The following routines are obsolete variants of gss_get_mic, * gss_verify_mic, gss_wrap and gss_unwrap. They should be * provided by GSSAPI V2 implementations for backwards @@ -754,7 +848,7 @@ gss_pseudo_random * obsolete versions of these routines and their current forms. */ -OM_uint32 GSSAPI_LIB_FUNCTION gss_sign +OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_sign (OM_uint32 * /*minor_status*/, gss_ctx_id_t /*context_handle*/, int /*qop_req*/, @@ -762,7 +856,7 @@ OM_uint32 GSSAPI_LIB_FUNCTION gss_sign gss_buffer_t /*message_token*/ ); -OM_uint32 GSSAPI_LIB_FUNCTION gss_verify +OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_verify (OM_uint32 * /*minor_status*/, gss_ctx_id_t /*context_handle*/, gss_buffer_t /*message_buffer*/, @@ -770,7 +864,7 @@ OM_uint32 GSSAPI_LIB_FUNCTION gss_verify int * /*qop_state*/ ); -OM_uint32 GSSAPI_LIB_FUNCTION gss_seal +OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_seal (OM_uint32 * /*minor_status*/, gss_ctx_id_t /*context_handle*/, int /*conf_req_flag*/, @@ -780,7 +874,7 @@ OM_uint32 GSSAPI_LIB_FUNCTION gss_seal gss_buffer_t /*output_message_buffer*/ ); -OM_uint32 GSSAPI_LIB_FUNCTION gss_unseal +OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_unseal (OM_uint32 * /*minor_status*/, gss_ctx_id_t /*context_handle*/, gss_buffer_t /*input_message_buffer*/, @@ -809,7 +903,4 @@ gss_decapsulate_token(gss_buffer_t /* input_token */, } #endif -#include <gssapi/gssapi_krb5.h> -#include <gssapi/gssapi_spnego.h> - #endif /* GSSAPI_GSSAPI_H_ */ diff --git a/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h b/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h index a821f73d2a..0baccf5098 100644 --- a/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h +++ b/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h @@ -36,7 +36,7 @@ #ifndef GSSAPI_KRB5_H_ #define GSSAPI_KRB5_H_ -#include <gssapi/gssapi.h> +#include <gssapi.h> #ifdef __cplusplus extern "C" { diff --git a/source4/heimdal/lib/gssapi/gssapi_mech.h b/source4/heimdal/lib/gssapi/gssapi_mech.h index b360de13fc..6470df30a0 100644 --- a/source4/heimdal/lib/gssapi/gssapi_mech.h +++ b/source4/heimdal/lib/gssapi/gssapi_mech.h @@ -307,7 +307,45 @@ typedef OM_uint32 _gss_pseudo_random( gss_buffer_t prf_out ); -#define GMI_VERSION 1 +typedef OM_uint32 +_gss_wrap_iov_t(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count); + +typedef OM_uint32 +_gss_unwrap_iov_t(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count); + +typedef OM_uint32 +_gss_wrap_iov_length_t(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count); + +typedef OM_uint32 +_gss_store_cred_t(OM_uint32 *minor_status, + gss_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored); + + + +#define GMI_VERSION 2 typedef struct gssapi_mech_interface_desc { unsigned gm_version; @@ -347,6 +385,10 @@ typedef struct gssapi_mech_interface_desc { _gss_set_sec_context_option *gm_set_sec_context_option; _gss_set_cred_option *gm_set_cred_option; _gss_pseudo_random *gm_pseudo_random; + _gss_wrap_iov_t *gm_wrap_iov; + _gss_unwrap_iov_t *gm_unwrap_iov; + _gss_wrap_iov_length_t *gm_wrap_iov_length; + _gss_store_cred_t *gm_store_cred; } gssapi_mech_interface_desc, *gssapi_mech_interface; gssapi_mech_interface diff --git a/source4/heimdal/lib/gssapi/krb5/8003.c b/source4/heimdal/lib/gssapi/krb5/8003.c index 119d49a0c5..f5181cc311 100644 --- a/source4/heimdal/lib/gssapi/krb5/8003.c +++ b/source4/heimdal/lib/gssapi/krb5/8003.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c index 626afa9384..e0944852a7 100644 --- a/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/accept_sec_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -74,12 +74,10 @@ _gsskrb5_register_acceptor_identity (const char *identity) } void -_gsskrb5i_is_cfx(gsskrb5_ctx ctx, int *is_cfx) +_gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) { + krb5_error_code ret; krb5_keyblock *key; - int acceptor = (ctx->more_flags & LOCAL) == 0; - - *is_cfx = 0; if (acceptor) { if (ctx->auth_context->local_subkey) @@ -108,12 +106,16 @@ _gsskrb5i_is_cfx(gsskrb5_ctx ctx, int *is_cfx) case ETYPE_ARCFOUR_HMAC_MD5_56: break; default : - *is_cfx = 1; + ctx->more_flags |= IS_CFX; + if ((acceptor && ctx->auth_context->local_subkey) || (!acceptor && ctx->auth_context->remote_subkey)) ctx->more_flags |= ACCEPTOR_SUBKEY; break; } + if (ctx->crypto) + krb5_crypto_destroy(context, ctx->crypto); + ret = krb5_crypto_init(context, key, 0, &ctx->crypto); } @@ -136,7 +138,8 @@ gsskrb5_accept_delegated_token kret = krb5_cc_default (context, &ccache); } else { *delegated_cred_handle = NULL; - kret = krb5_cc_gen_new (context, &krb5_mcc_ops, &ccache); + kret = krb5_cc_new_unique (context, krb5_cc_type_memory, + NULL, &ccache); } if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; @@ -210,7 +213,8 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status, ctx->auth_context, &seq_number); - _gsskrb5i_is_cfx(ctx, &is_cfx); + _gsskrb5i_is_cfx(context, ctx, 1); + is_cfx = (ctx->more_flags & IS_CFX); ret = _gssapi_msg_order_create(minor_status, &ctx->order, @@ -381,7 +385,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, server, in, &out); krb5_rd_req_in_ctx_free(context, in); - if (kret == KRB5KRB_AP_ERR_SKEW) { + if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) { /* * No reply in non-MUTUAL mode, but we don't know that its * non-MUTUAL mode yet, thats inside the 8003 checksum, so @@ -526,7 +530,8 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, krb5_data outbuf; int use_subkey = 0; - _gsskrb5i_is_cfx(ctx, &is_cfx); + _gsskrb5i_is_cfx(context, ctx, 1); + is_cfx = (ctx->more_flags & IS_CFX); if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { use_subkey = 1; diff --git a/source4/heimdal/lib/gssapi/krb5/acquire_cred.c b/source4/heimdal/lib/gssapi/krb5/acquire_cred.c index be680840f5..bfab5667be 100644 --- a/source4/heimdal/lib/gssapi/krb5/acquire_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/acquire_cred.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -187,7 +187,8 @@ static OM_uint32 acquire_initiator_cred krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; - kret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache); + kret = krb5_cc_new_unique(context, krb5_cc_type_memory, + NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); diff --git a/source4/heimdal/lib/gssapi/krb5/add_cred.c b/source4/heimdal/lib/gssapi/krb5/add_cred.c index d6fd8f6f15..aa96a45e45 100644 --- a/source4/heimdal/lib/gssapi/krb5/add_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/add_cred.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -168,8 +168,8 @@ OM_uint32 _gsskrb5_add_cred ( } if (strcmp(type, "MEMORY") == 0) { - ret = krb5_cc_gen_new(context, &krb5_mcc_ops, - &handle->ccache); + ret = krb5_cc_new_unique(context, type, + NULL, &handle->ccache); if (ret) { *minor_status = ret; goto failure; diff --git a/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c b/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c index ff0afdc059..fa115d964a 100644 --- a/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c +++ b/source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" #include <roken.h> diff --git a/source4/heimdal/lib/gssapi/krb5/aeap.c b/source4/heimdal/lib/gssapi/krb5/aeap.c new file mode 100644 index 0000000000..7dab7877d7 --- /dev/null +++ b/source4/heimdal/lib/gssapi/krb5/aeap.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#include <roken.h> + +static OM_uint32 +iov_allocate(OM_uint32 *minor_status, gss_iov_buffer_desc *iov, int iov_count) +{ + unsigned int i; + + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_FLAGS(iov[i].type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE){ + void *ptr = malloc(iov[i].buffer.length); + if (ptr == NULL) + abort(); + if (iov[i].buffer.value) + memcpy(ptr, iov[i].buffer.value, iov[i].buffer.length); + iov[i].buffer.value = ptr; + iov[i].type |= GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED; + } + } + return GSS_S_COMPLETE; +} + +static OM_uint32 +iov_map(OM_uint32 *minor_status, + const gss_iov_buffer_desc *iov, + int iov_count, + krb5_crypto_iov *data) +{ + unsigned int i; + + for (i = 0; i < iov_count; i++) { + switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + data[i].flags = KRB5_CRYPTO_TYPE_PADDING; + break; + case GSS_IOV_BUFFER_TYPE_STREAM: + abort(); + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + data[i].data.data = iov[i].buffer.value; + data[i].data.length = iov[i].buffer.length; + } + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_LIB_FUNCTION +_gk_wrap_iov(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; + krb5_context context; + OM_uint32 major_status, junk; + krb5_crypto_iov *data; + krb5_error_code ret; + unsigned usage; + + GSSAPI_KRB5_INIT (&context); + + major_status = iov_allocate(minor_status, iov, iov_count); + if (major_status != GSS_S_COMPLETE) + return major_status; + + data = calloc(iov_count, sizeof(data[0])); + if (data == NULL) { + gss_release_iov_buffer(&junk, iov, iov_count); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = iov_map(minor_status, iov, iov_count, data); + if (major_status != GSS_S_COMPLETE) { + gss_release_iov_buffer(&junk, iov, iov_count); + free(data); + return major_status; + } + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } + + ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, + data, iov_count, NULL); + free(data); + if (ret) { + gss_release_iov_buffer(&junk, iov, iov_count); + *minor_status = ret; + return GSS_S_FAILURE; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_LIB_FUNCTION +_gk_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; + krb5_context context; + krb5_error_code ret; + OM_uint32 major_status, junk; + krb5_crypto_iov *data; + unsigned usage; + + GSSAPI_KRB5_INIT (&context); + + major_status = iov_allocate(minor_status, iov, iov_count); + if (major_status != GSS_S_COMPLETE) + return major_status; + + data = calloc(iov_count, sizeof(data[0])); + if (data == NULL) { + gss_release_iov_buffer(&junk, iov, iov_count); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = iov_map(minor_status, iov, iov_count, data); + if (major_status != GSS_S_COMPLETE) { + gss_release_iov_buffer(&junk, iov, iov_count); + free(data); + return major_status; + } + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } + + ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, + data, iov_count, NULL); + free(data); + if (ret) { + *minor_status = ret; + gss_release_iov_buffer(&junk, iov, iov_count); + return GSS_S_FAILURE; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_LIB_FUNCTION +_gk_wrap_iov_length(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; + krb5_context context; + unsigned int i; + size_t size; + size_t *padding = NULL; + + GSSAPI_KRB5_INIT (&context); + *minor_status = 0; + + for (size = 0, i = 0; i < iov_count; i++) { + switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + break; + case GSS_IOV_BUFFER_TYPE_DATA: + size += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + iov[i].buffer.length = + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER); + size += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + iov[i].buffer.length = + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER); + size += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + if (padding != NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + padding = &iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_STREAM: + size += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + if (padding) { + size_t pad = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_PADDING); + if (pad > 1) { + *padding = pad - (size % pad); + if (*padding == pad) + *padding = 0; + } else + *padding = 0; + } + + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c index 7288b58493..b48cfebcf1 100644 --- a/source4/heimdal/lib/gssapi/krb5/arcfour.c +++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/canonicalize_name.c b/source4/heimdal/lib/gssapi/krb5/canonicalize_name.c index fa2258ce82..3a206b1be1 100644 --- a/source4/heimdal/lib/gssapi/krb5/canonicalize_name.c +++ b/source4/heimdal/lib/gssapi/krb5/canonicalize_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/cfx.c b/source4/heimdal/lib/gssapi/krb5/cfx.c index d029f55ce4..7ae26e2e7a 100755 --- a/source4/heimdal/lib/gssapi/krb5/cfx.c +++ b/source4/heimdal/lib/gssapi/krb5/cfx.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -101,49 +101,47 @@ _gsskrb5cfx_wrap_length_cfx(const gsskrb5_ctx context_handle, return 0; } -krb5_error_code -_gsskrb5cfx_max_wrap_length_cfx(krb5_context context, - krb5_crypto crypto, +OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, int conf_req_flag, - size_t input_length, - OM_uint32 *output_length) + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) { krb5_error_code ret; - *output_length = 0; + *max_input_size = 0; /* 16-byte header is always first */ - if (input_length < 16) + if (req_output_size < 16) return 0; - input_length -= 16; + req_output_size -= 16; if (conf_req_flag) { size_t wrapped_size, sz; - wrapped_size = input_length + 1; + wrapped_size = req_output_size + 1; do { wrapped_size--; sz = krb5_get_wrapped_length(context, - crypto, wrapped_size); - } while (wrapped_size && sz > input_length); - if (wrapped_size == 0) { - *output_length = 0; + ctx->crypto, wrapped_size); + } while (wrapped_size && sz > req_output_size); + if (wrapped_size == 0) return 0; - } /* inner header */ - if (wrapped_size < 16) { - *output_length = 0; + if (wrapped_size < 16) return 0; - } + wrapped_size -= 16; - *output_length = wrapped_size; + *max_input_size = wrapped_size; } else { krb5_cksumtype type; size_t cksumsize; - ret = krb5_crypto_get_checksum_type(context, crypto, &type); + ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type); if (ret) return ret; @@ -151,48 +149,16 @@ _gsskrb5cfx_max_wrap_length_cfx(krb5_context context, if (ret) return ret; - if (input_length < cksumsize) + if (req_output_size < cksumsize) return 0; /* Checksum is concatenated with data */ - *output_length = input_length - cksumsize; + *max_input_size = req_output_size - cksumsize; } return 0; } - -OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, - const gsskrb5_ctx context_handle, - krb5_context context, - int conf_req_flag, - gss_qop_t qop_req, - OM_uint32 req_output_size, - OM_uint32 *max_input_size, - krb5_keyblock *key) -{ - krb5_error_code ret; - krb5_crypto crypto; - - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret != 0) { - *minor_status = ret; - return GSS_S_FAILURE; - } - - ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag, - req_output_size, max_input_size); - if (ret != 0) { - *minor_status = ret; - krb5_crypto_destroy(context, crypto); - return GSS_S_FAILURE; - } - - krb5_crypto_destroy(context, crypto); - - return GSS_S_COMPLETE; -} - /* * Rotate "rrc" bytes to the front or back */ @@ -238,16 +204,14 @@ rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) } OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, - const gsskrb5_ctx context_handle, + const gsskrb5_ctx ctx, krb5_context context, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, int *conf_state, - gss_buffer_t output_message_buffer, - krb5_keyblock *key) + gss_buffer_t output_message_buffer) { - krb5_crypto crypto; gss_cfx_wrap_token token; krb5_error_code ret; unsigned usage; @@ -257,19 +221,12 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, int32_t seq_number; u_char *p; - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret != 0) { - *minor_status = ret; - return GSS_S_FAILURE; - } - - ret = _gsskrb5cfx_wrap_length_cfx(context_handle, context, - crypto, conf_req_flag, + ret = _gsskrb5cfx_wrap_length_cfx(ctx, context, + ctx->crypto, conf_req_flag, input_message_buffer->length, &wrapped_len, &cksumsize, &padlength); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -280,7 +237,6 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, output_message_buffer->value = malloc(output_message_buffer->length); if (output_message_buffer->value == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -290,9 +246,9 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, token->TOK_ID[1] = 0x04; token->Flags = 0; token->Filler = 0xFF; - if ((context_handle->more_flags & LOCAL) == 0) + if ((ctx->more_flags & LOCAL) == 0) token->Flags |= CFXSentByAcceptor; - if (context_handle->more_flags & ACCEPTOR_SUBKEY) + if (ctx->more_flags & ACCEPTOR_SUBKEY) token->Flags |= CFXAcceptorSubkey; if (conf_req_flag) { /* @@ -329,16 +285,16 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, token->RRC[0] = 0; token->RRC[1] = 0; - HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); krb5_auth_con_getlocalseqnumber(context, - context_handle->auth_context, + ctx->auth_context, &seq_number); _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); krb5_auth_con_setlocalseqnumber(context, - context_handle->auth_context, + ctx->auth_context, ++seq_number); - HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); /* * If confidentiality is requested, the token header is @@ -349,7 +305,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, * calculated over the plaintext concatenated with the * token header. */ - if (context_handle->more_flags & LOCAL) { + if (ctx->more_flags & LOCAL) { usage = KRB5_KU_USAGE_INITIATOR_SEAL; } else { usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; @@ -370,14 +326,13 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, memcpy(p + input_message_buffer->length + padlength, token, sizeof(*token)); - ret = krb5_encrypt(context, crypto, + ret = krb5_encrypt(context, ctx->crypto, usage, p, input_message_buffer->length + padlength + sizeof(*token), &cipher); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_FAILURE; } @@ -389,14 +344,13 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, * this is really ugly, but needed against windows * for DCERPC, as windows rotates by EC+RRC. */ - if (IS_DCE_STYLE(context_handle)) { + if (IS_DCE_STYLE(ctx)) { ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE); } else { ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); } if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_FAILURE; } @@ -409,21 +363,19 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, buf = malloc(input_message_buffer->length + sizeof(*token)); if (buf == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_FAILURE; } memcpy(buf, input_message_buffer->value, input_message_buffer->length); memcpy(buf + input_message_buffer->length, token, sizeof(*token)); - ret = krb5_create_checksum(context, crypto, + ret = krb5_create_checksum(context, ctx->crypto, usage, 0, buf, input_message_buffer->length + sizeof(*token), &cksum); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); free(buf); return GSS_S_FAILURE; @@ -446,7 +398,6 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, input_message_buffer->length + cksum.checksum.length, rrc, FALSE); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); free_Checksum(&cksum); return GSS_S_FAILURE; @@ -454,8 +405,6 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, free_Checksum(&cksum); } - krb5_crypto_destroy(context, crypto); - if (conf_state != NULL) { *conf_state = conf_req_flag; } @@ -465,15 +414,13 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, } OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, - const gsskrb5_ctx context_handle, + const gsskrb5_ctx ctx, krb5_context context, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, - gss_qop_t *qop_state, - krb5_keyblock *key) + gss_qop_t *qop_state) { - krb5_crypto crypto; gss_cfx_wrap_token token; u_char token_flags; krb5_error_code ret; @@ -503,11 +450,11 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); if (token_flags & CFXSentByAcceptor) { - if ((context_handle->more_flags & LOCAL) == 0) + if ((ctx->more_flags & LOCAL) == 0) return GSS_S_DEFECTIVE_TOKEN; } - if (context_handle->more_flags & ACCEPTOR_SUBKEY) { + if (ctx->more_flags & ACCEPTOR_SUBKEY) { if ((token_flags & CFXAcceptorSubkey) == 0) return GSS_S_DEFECTIVE_TOKEN; } else { @@ -537,26 +484,21 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, return GSS_S_UNSEQ_TOKEN; } - HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); if (ret != 0) { *minor_status = 0; - HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); _gsskrb5_release_buffer(minor_status, output_message_buffer); return ret; } - HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); /* * Decrypt and/or verify checksum */ - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret != 0) { - *minor_status = ret; - return GSS_S_FAILURE; - } - if (context_handle->more_flags & LOCAL) { + if (ctx->more_flags & LOCAL) { usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; } else { usage = KRB5_KU_USAGE_INITIATOR_SEAL; @@ -571,27 +513,24 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, * this is really ugly, but needed against windows * for DCERPC, as windows rotates by EC+RRC. */ - if (IS_DCE_STYLE(context_handle)) { + if (IS_DCE_STYLE(ctx)) { *minor_status = rrc_rotate(p, len, rrc+ec, TRUE); } else { *minor_status = rrc_rotate(p, len, rrc, TRUE); } if (*minor_status != 0) { - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } - ret = krb5_decrypt(context, crypto, usage, + ret = krb5_decrypt(context, ctx->crypto, usage, p, len, &data); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); return GSS_S_BAD_MIC; } /* Check that there is room for the pad and token header */ if (data.length < ec + sizeof(*token)) { - krb5_crypto_destroy(context, crypto); krb5_data_free(&data); return GSS_S_DEFECTIVE_TOKEN; } @@ -604,7 +543,6 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, /* Check the integrity of the header */ if (memcmp(p, token, sizeof(*token)) != 0) { - krb5_crypto_destroy(context, crypto); krb5_data_free(&data); return GSS_S_BAD_MIC; } @@ -617,16 +555,15 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, /* Rotate by RRC; bogus to do this in-place XXX */ *minor_status = rrc_rotate(p, len, rrc, TRUE); if (*minor_status != 0) { - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } /* Determine checksum type */ ret = krb5_crypto_get_checksum_type(context, - crypto, &cksum.cksumtype); + ctx->crypto, + &cksum.cksumtype); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -635,7 +572,6 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, /* Check we have at least as much data as the checksum */ if (len < cksum.checksum.length) { *minor_status = ERANGE; - krb5_crypto_destroy(context, crypto); return GSS_S_BAD_MIC; } @@ -647,7 +583,6 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, output_message_buffer->value = malloc(len + sizeof(*token)); if (output_message_buffer->value == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -664,21 +599,18 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, token->RRC[0] = 0; token->RRC[1] = 0; - ret = krb5_verify_checksum(context, crypto, + ret = krb5_verify_checksum(context, ctx->crypto, usage, output_message_buffer->value, len + sizeof(*token), &cksum); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_BAD_MIC; } } - krb5_crypto_destroy(context, crypto); - if (qop_state != NULL) { *qop_state = GSS_C_QOP_DEFAULT; } @@ -688,14 +620,12 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, } OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, - const gsskrb5_ctx context_handle, + const gsskrb5_ctx ctx, krb5_context context, gss_qop_t qop_req, const gss_buffer_t message_buffer, - gss_buffer_t message_token, - krb5_keyblock *key) + gss_buffer_t message_token) { - krb5_crypto crypto; gss_cfx_mic_token token; krb5_error_code ret; unsigned usage; @@ -704,17 +634,10 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, size_t len; int32_t seq_number; - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret != 0) { - *minor_status = ret; - return GSS_S_FAILURE; - } - len = message_buffer->length + sizeof(*token); buf = malloc(len); if (buf == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } @@ -724,38 +647,36 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, token->TOK_ID[0] = 0x04; token->TOK_ID[1] = 0x04; token->Flags = 0; - if ((context_handle->more_flags & LOCAL) == 0) + if ((ctx->more_flags & LOCAL) == 0) token->Flags |= CFXSentByAcceptor; - if (context_handle->more_flags & ACCEPTOR_SUBKEY) + if (ctx->more_flags & ACCEPTOR_SUBKEY) token->Flags |= CFXAcceptorSubkey; memset(token->Filler, 0xFF, 5); - HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); krb5_auth_con_getlocalseqnumber(context, - context_handle->auth_context, + ctx->auth_context, &seq_number); _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); krb5_auth_con_setlocalseqnumber(context, - context_handle->auth_context, + ctx->auth_context, ++seq_number); - HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); - if (context_handle->more_flags & LOCAL) { + if (ctx->more_flags & LOCAL) { usage = KRB5_KU_USAGE_INITIATOR_SIGN; } else { usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; } - ret = krb5_create_checksum(context, crypto, + ret = krb5_create_checksum(context, ctx->crypto, usage, 0, buf, len, &cksum); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); free(buf); return GSS_S_FAILURE; } - krb5_crypto_destroy(context, crypto); /* Determine MIC length */ message_token->length = sizeof(*token) + cksum.checksum.length; @@ -780,14 +701,12 @@ OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, } OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, - const gsskrb5_ctx context_handle, + const gsskrb5_ctx ctx, krb5_context context, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, - gss_qop_t *qop_state, - krb5_keyblock *key) + gss_qop_t *qop_state) { - krb5_crypto crypto; gss_cfx_mic_token token; u_char token_flags; krb5_error_code ret; @@ -814,10 +733,10 @@ OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey); if (token_flags & CFXSentByAcceptor) { - if ((context_handle->more_flags & LOCAL) == 0) + if ((ctx->more_flags & LOCAL) == 0) return GSS_S_DEFECTIVE_TOKEN; } - if (context_handle->more_flags & ACCEPTOR_SUBKEY) { + if (ctx->more_flags & ACCEPTOR_SUBKEY) { if ((token_flags & CFXAcceptorSubkey) == 0) return GSS_S_DEFECTIVE_TOKEN; } else { @@ -839,36 +758,29 @@ OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, return GSS_S_UNSEQ_TOKEN; } - HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); if (ret != 0) { *minor_status = 0; - HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return ret; } - HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); /* * Verify checksum */ - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret != 0) { - *minor_status = ret; - return GSS_S_FAILURE; - } - - ret = krb5_crypto_get_checksum_type(context, crypto, + ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &cksum.cksumtype); if (ret != 0) { *minor_status = ret; - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } cksum.checksum.data = p + sizeof(*token); cksum.checksum.length = token_buffer->length - sizeof(*token); - if (context_handle->more_flags & LOCAL) { + if (ctx->more_flags & LOCAL) { usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; } else { usage = KRB5_KU_USAGE_INITIATOR_SIGN; @@ -877,18 +789,16 @@ OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, buf = malloc(message_buffer->length + sizeof(*token)); if (buf == NULL) { *minor_status = ENOMEM; - krb5_crypto_destroy(context, crypto); return GSS_S_FAILURE; } memcpy(buf, message_buffer->value, message_buffer->length); memcpy(buf + message_buffer->length, token, sizeof(*token)); - ret = krb5_verify_checksum(context, crypto, + ret = krb5_verify_checksum(context, ctx->crypto, usage, buf, sizeof(*token) + message_buffer->length, &cksum); - krb5_crypto_destroy(context, crypto); if (ret != 0) { *minor_status = ret; free(buf); diff --git a/source4/heimdal/lib/gssapi/krb5/compare_name.c b/source4/heimdal/lib/gssapi/krb5/compare_name.c index d92f3ef405..fbb0f0218e 100644 --- a/source4/heimdal/lib/gssapi/krb5/compare_name.c +++ b/source4/heimdal/lib/gssapi/krb5/compare_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/compat.c b/source4/heimdal/lib/gssapi/krb5/compat.c index ee0d07d983..012602c074 100644 --- a/source4/heimdal/lib/gssapi/krb5/compat.c +++ b/source4/heimdal/lib/gssapi/krb5/compat.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/context_time.c b/source4/heimdal/lib/gssapi/krb5/context_time.c index 3854b68782..3230389938 100644 --- a/source4/heimdal/lib/gssapi/krb5/context_time.c +++ b/source4/heimdal/lib/gssapi/krb5/context_time.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/copy_ccache.c b/source4/heimdal/lib/gssapi/krb5/copy_ccache.c index 8961642671..40a8fab1b7 100644 --- a/source4/heimdal/lib/gssapi/krb5/copy_ccache.c +++ b/source4/heimdal/lib/gssapi/krb5/copy_ccache.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c index 22386fa737..a2a5de9fe7 100644 --- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/source4/heimdal/lib/gssapi/krb5/decapsulate.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c b/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c index 5ccfe9d015..ea0831815a 100644 --- a/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/delete_sec_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -74,6 +74,8 @@ _gsskrb5_delete_sec_context(OM_uint32 * minor_status, if (ctx->service_keyblock) krb5_free_keyblock (context, ctx->service_keyblock); krb5_data_free(&ctx->fwd_data); + if (ctx->crypto) + krb5_crypto_destroy(context, ctx->crypto); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); diff --git a/source4/heimdal/lib/gssapi/krb5/display_name.c b/source4/heimdal/lib/gssapi/krb5/display_name.c index d1834ebaf8..0b37731510 100644 --- a/source4/heimdal/lib/gssapi/krb5/display_name.c +++ b/source4/heimdal/lib/gssapi/krb5/display_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/display_status.c b/source4/heimdal/lib/gssapi/krb5/display_status.c index 18622610d5..4136c25e53 100644 --- a/source4/heimdal/lib/gssapi/krb5/display_status.c +++ b/source4/heimdal/lib/gssapi/krb5/display_status.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/duplicate_name.c b/source4/heimdal/lib/gssapi/krb5/duplicate_name.c index 6c281f43de..2b5e5c0ef4 100644 --- a/source4/heimdal/lib/gssapi/krb5/duplicate_name.c +++ b/source4/heimdal/lib/gssapi/krb5/duplicate_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/encapsulate.c b/source4/heimdal/lib/gssapi/krb5/encapsulate.c index 19c6ec8ca7..838a34d7db 100644 --- a/source4/heimdal/lib/gssapi/krb5/encapsulate.c +++ b/source4/heimdal/lib/gssapi/krb5/encapsulate.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/export_name.c b/source4/heimdal/lib/gssapi/krb5/export_name.c index b28777ea2e..bad73611dc 100644 --- a/source4/heimdal/lib/gssapi/krb5/export_name.c +++ b/source4/heimdal/lib/gssapi/krb5/export_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/export_sec_context.c b/source4/heimdal/lib/gssapi/krb5/export_sec_context.c index 842921fe50..305d5c334e 100644 --- a/source4/heimdal/lib/gssapi/krb5/export_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/export_sec_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/external.c b/source4/heimdal/lib/gssapi/krb5/external.c index 4efa61fd70..1c28f7c141 100644 --- a/source4/heimdal/lib/gssapi/krb5/external.c +++ b/source4/heimdal/lib/gssapi/krb5/external.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" #include <gssapi_mech.h> RCSID("$Id$"); @@ -469,7 +469,10 @@ static gssapi_mech_interface_desc krb5_mech = { _gsskrb5_inquire_cred_by_oid, _gsskrb5_set_sec_context_option, _gsskrb5_set_cred_option, - _gsskrb5_pseudo_random + _gsskrb5_pseudo_random, + _gk_wrap_iov, + _gk_unwrap_iov, + _gk_wrap_iov_length }; gssapi_mech_interface diff --git a/source4/heimdal/lib/gssapi/krb5/get_mic.c b/source4/heimdal/lib/gssapi/krb5/get_mic.c index 199c414ef4..66aaba44d6 100644 --- a/source4/heimdal/lib/gssapi/krb5/get_mic.c +++ b/source4/heimdal/lib/gssapi/krb5/get_mic.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -284,6 +284,10 @@ OM_uint32 _gsskrb5_get_mic GSSAPI_KRB5_INIT (&context); + if (ctx->more_flags & IS_CFX) + return _gssapi_mic_cfx (minor_status, ctx, context, qop_req, + message_buffer, message_token); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -308,8 +312,7 @@ OM_uint32 _gsskrb5_get_mic message_buffer, message_token, key); break; default : - ret = _gssapi_mic_cfx (minor_status, ctx, context, qop_req, - message_buffer, message_token, key); + abort(); break; } krb5_free_keyblock (context, key); diff --git a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h index 6db842395f..aadb80db0d 100644 --- a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h +++ b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h @@ -36,14 +36,13 @@ #ifndef GSSKRB5_LOCL_H #define GSSKRB5_LOCL_H -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include <krb5_locl.h> #include <gkrb5_err.h> #include <gssapi.h> #include <gssapi_mech.h> +#include <gssapi_krb5.h> #include <assert.h> #include "cfx.h" @@ -54,7 +53,7 @@ struct gss_msg_order; -typedef struct { +typedef struct gsskrb5_ctx { struct krb5_auth_context_data *auth_context; krb5_principal source, target; #define IS_DCE_STYLE(ctx) (((ctx)->flags & GSS_C_DCE_STYLE) != 0) @@ -64,7 +63,8 @@ typedef struct { COMPAT_OLD_DES3_SELECTED = 8, ACCEPTOR_SUBKEY = 16, RETRIED = 32, - CLOSE_CCACHE = 64 + CLOSE_CCACHE = 64, + IS_CFX = 128 } more_flags; enum gss_ctx_id_t_state { /* initiator states */ @@ -85,6 +85,7 @@ typedef struct { struct gss_msg_order *order; krb5_keyblock *service_keyblock; krb5_data fwd_data; + krb5_crypto crypto; } *gsskrb5_ctx; typedef struct { @@ -119,7 +120,7 @@ struct gssapi_thr_context { * Prototypes */ -#include <krb5/gsskrb5-private.h> +#include <gsskrb5-private.h> #define GSSAPI_KRB5_INIT(ctx) do { \ krb5_error_code kret_gss_init; \ diff --git a/source4/heimdal/lib/gssapi/krb5/import_name.c b/source4/heimdal/lib/gssapi/krb5/import_name.c index 2f6b002f30..8f5387fe2b 100644 --- a/source4/heimdal/lib/gssapi/krb5/import_name.c +++ b/source4/heimdal/lib/gssapi/krb5/import_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/import_sec_context.c b/source4/heimdal/lib/gssapi/krb5/import_sec_context.c index e1e8e551b4..ba1a977d2d 100644 --- a/source4/heimdal/lib/gssapi/krb5/import_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/import_sec_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/indicate_mechs.c b/source4/heimdal/lib/gssapi/krb5/indicate_mechs.c index 05b9447746..3702106e79 100644 --- a/source4/heimdal/lib/gssapi/krb5/indicate_mechs.c +++ b/source4/heimdal/lib/gssapi/krb5/indicate_mechs.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/init.c b/source4/heimdal/lib/gssapi/krb5/init.c index 6c1c5949e0..b28e6a4c12 100644 --- a/source4/heimdal/lib/gssapi/krb5/init.c +++ b/source4/heimdal/lib/gssapi/krb5/init.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c index dfa0e935e6..4b632bd95a 100644 --- a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c +++ b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -131,6 +131,7 @@ _gsskrb5_create_ctx( krb5_data_zero(&ctx->fwd_data); ctx->lifetime = GSS_C_INDEFINITE; ctx->order = NULL; + ctx->crypto = NULL; HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); kret = krb5_auth_con_init (context, &ctx->auth_context); @@ -257,7 +258,8 @@ gsskrb5_initiator_ready( krb5_auth_getremoteseqnumber (context, ctx->auth_context, &seq_number); - _gsskrb5i_is_cfx(ctx, &is_cfx); + _gsskrb5i_is_cfx(context, ctx, 0); + is_cfx = (ctx->more_flags & IS_CFX); ret = _gssapi_msg_order_create(minor_status, &ctx->order, @@ -552,8 +554,10 @@ init_auth_restart flags |= GSS_C_REPLAY_FLAG; if (req_flags & GSS_C_SEQUENCE_FLAG) flags |= GSS_C_SEQUENCE_FLAG; +#if 0 if (req_flags & GSS_C_ANON_FLAG) ; /* XXX */ +#endif if (req_flags & GSS_C_DCE_STYLE) { /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; @@ -686,7 +690,6 @@ repl_mutual krb5_error_code kret; krb5_data indata; krb5_ap_rep_enc_part *repl; - int is_cfx = 0; output_token->length = 0; output_token->value = NULL; @@ -759,20 +762,6 @@ repl_mutual krb5_free_ap_rep_enc_part (context, repl); - _gsskrb5i_is_cfx(ctx, &is_cfx); - if (is_cfx) { - krb5_keyblock *key = NULL; - - kret = krb5_auth_con_getremotesubkey(context, - ctx->auth_context, - &key); - if (kret == 0 && key != NULL) { - ctx->more_flags |= ACCEPTOR_SUBKEY; - krb5_free_keyblock (context, key); - } - } - - *minor_status = 0; if (time_rec) { ret = _gsskrb5_lifetime_left(minor_status, diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_context.c b/source4/heimdal/lib/gssapi/krb5/inquire_context.c index e0aeb032ce..188a6135a4 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_context.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_cred.c b/source4/heimdal/lib/gssapi/krb5/inquire_cred.c index bb75978adb..27e3014923 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_cred.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c index cdf05d7934..1fd9733940 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c index 2bcc17683b..5a35202a6a 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c b/source4/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c index 4fd730deab..5d54bd6508 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c b/source4/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c index a9d6495c7b..9eba7b7f4d 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c b/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c index 8d40706294..f8ef2a3aa4 100644 --- a/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c +++ b/source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -242,7 +242,7 @@ static OM_uint32 inquire_sec_context_has_updated_spnego * mechanism. */ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - _gsskrb5i_is_cfx(context_handle, &is_updated); + is_updated = (context_handle->more_flags & IS_CFX); if (is_updated == 0) { krb5_keyblock *acceptor_subkey; @@ -282,7 +282,7 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status, HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - _gsskrb5i_is_cfx(context_handle, &is_cfx); + is_cfx = (context_handle->more_flags & IS_CFX); sp = krb5_storage_emem(); if (sp == NULL) { @@ -445,6 +445,7 @@ get_service_keyblock HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); if (ctx->service_keyblock == NULL) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + krb5_storage_free(sp); _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context"); *minor_status = EINVAL; return GSS_S_FAILURE; diff --git a/source4/heimdal/lib/gssapi/krb5/prf.c b/source4/heimdal/lib/gssapi/krb5/prf.c index 9cbe603435..9fd13f51bd 100644 --- a/source4/heimdal/lib/gssapi/krb5/prf.c +++ b/source4/heimdal/lib/gssapi/krb5/prf.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/process_context_token.c b/source4/heimdal/lib/gssapi/krb5/process_context_token.c index 6892d3ca60..3229b36292 100644 --- a/source4/heimdal/lib/gssapi/krb5/process_context_token.c +++ b/source4/heimdal/lib/gssapi/krb5/process_context_token.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -44,15 +44,12 @@ OM_uint32 _gsskrb5_process_context_token ( krb5_context context; OM_uint32 ret = GSS_S_FAILURE; gss_buffer_desc empty_buffer; - gss_qop_t qop_state; empty_buffer.length = 0; empty_buffer.value = NULL; GSSAPI_KRB5_INIT (&context); - qop_state = GSS_C_QOP_DEFAULT; - ret = _gsskrb5_verify_mic_internal(minor_status, (gsskrb5_ctx)context_handle, context, diff --git a/source4/heimdal/lib/gssapi/krb5/release_buffer.c b/source4/heimdal/lib/gssapi/krb5/release_buffer.c index a0f37c06f4..18e0279939 100644 --- a/source4/heimdal/lib/gssapi/krb5/release_buffer.c +++ b/source4/heimdal/lib/gssapi/krb5/release_buffer.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/release_cred.c b/source4/heimdal/lib/gssapi/krb5/release_cred.c index 5a0ec829d2..62674a1d53 100644 --- a/source4/heimdal/lib/gssapi/krb5/release_cred.c +++ b/source4/heimdal/lib/gssapi/krb5/release_cred.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -61,8 +61,6 @@ OM_uint32 _gsskrb5_release_cred if (cred->keytab != NULL) krb5_kt_close(context, cred->keytab); if (cred->ccache != NULL) { - const krb5_cc_ops *ops; - ops = krb5_cc_get_ops(context, cred->ccache); if (cred->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) krb5_cc_destroy(context, cred->ccache); else diff --git a/source4/heimdal/lib/gssapi/krb5/release_name.c b/source4/heimdal/lib/gssapi/krb5/release_name.c index d39c705433..5491052c59 100644 --- a/source4/heimdal/lib/gssapi/krb5/release_name.c +++ b/source4/heimdal/lib/gssapi/krb5/release_name.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/sequence.c b/source4/heimdal/lib/gssapi/krb5/sequence.c index 61164ffec1..6391d44429 100644 --- a/source4/heimdal/lib/gssapi/krb5/sequence.c +++ b/source4/heimdal/lib/gssapi/krb5/sequence.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/set_cred_option.c b/source4/heimdal/lib/gssapi/krb5/set_cred_option.c index e47e6fdb6c..2a2390f8d1 100644 --- a/source4/heimdal/lib/gssapi/krb5/set_cred_option.c +++ b/source4/heimdal/lib/gssapi/krb5/set_cred_option.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c b/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c index 6591ab04dd..460cfe942a 100644 --- a/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c +++ b/source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c @@ -34,7 +34,7 @@ * glue routine for _gsskrb5_inquire_sec_context_by_oid */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c index f34f72542e..0e87cb88b7 100644 --- a/source4/heimdal/lib/gssapi/krb5/unwrap.c +++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -393,11 +393,16 @@ OM_uint32 _gsskrb5_unwrap output_message_buffer->value = NULL; output_message_buffer->length = 0; + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; GSSAPI_KRB5_INIT (&context); - if (qop_state != NULL) - *qop_state = GSS_C_QOP_DEFAULT; + if (ctx->more_flags & IS_CFX) + return _gssapi_unwrap_cfx (minor_status, ctx, context, + input_message_buffer, output_message_buffer, + conf_state, qop_state); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -427,9 +432,7 @@ OM_uint32 _gsskrb5_unwrap conf_state, qop_state, key); break; default : - ret = _gssapi_unwrap_cfx (minor_status, ctx, context, - input_message_buffer, output_message_buffer, - conf_state, qop_state, key); + abort(); break; } krb5_free_keyblock (context, key); diff --git a/source4/heimdal/lib/gssapi/krb5/verify_mic.c b/source4/heimdal/lib/gssapi/krb5/verify_mic.c index 1832d35b5a..6eb7ae4b08 100644 --- a/source4/heimdal/lib/gssapi/krb5/verify_mic.c +++ b/source4/heimdal/lib/gssapi/krb5/verify_mic.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -266,7 +266,7 @@ retry: OM_uint32 _gsskrb5_verify_mic_internal (OM_uint32 * minor_status, - const gsskrb5_ctx context_handle, + const gsskrb5_ctx ctx, krb5_context context, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, @@ -278,9 +278,14 @@ _gsskrb5_verify_mic_internal OM_uint32 ret; krb5_keytype keytype; - HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - ret = _gsskrb5i_get_token_key(context_handle, context, &key); - HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (ctx->more_flags & IS_CFX) + return _gssapi_verify_mic_cfx (minor_status, ctx, + context, message_buffer, token_buffer, + qop_state); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); if (ret) { *minor_status = ret; return GSS_S_FAILURE; @@ -289,28 +294,24 @@ _gsskrb5_verify_mic_internal krb5_enctype_to_keytype (context, key->keytype, &keytype); switch (keytype) { case KEYTYPE_DES : - ret = verify_mic_des (minor_status, context_handle, context, + ret = verify_mic_des (minor_status, ctx, context, message_buffer, token_buffer, qop_state, key, type); break; case KEYTYPE_DES3 : - ret = verify_mic_des3 (minor_status, context_handle, context, + ret = verify_mic_des3 (minor_status, ctx, context, message_buffer, token_buffer, qop_state, key, type); break; case KEYTYPE_ARCFOUR : case KEYTYPE_ARCFOUR_56 : - ret = _gssapi_verify_mic_arcfour (minor_status, context_handle, + ret = _gssapi_verify_mic_arcfour (minor_status, ctx, context, message_buffer, token_buffer, qop_state, key, type); break; default : - ret = _gssapi_verify_mic_cfx (minor_status, context_handle, - context, - message_buffer, token_buffer, qop_state, - key); - break; + abort(); } krb5_free_keyblock (context, key); diff --git a/source4/heimdal/lib/gssapi/krb5/wrap.c b/source4/heimdal/lib/gssapi/krb5/wrap.c index ad21bcb57b..b9f4c237c7 100644 --- a/source4/heimdal/lib/gssapi/krb5/wrap.c +++ b/source4/heimdal/lib/gssapi/krb5/wrap.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "krb5/gsskrb5_locl.h" +#include "gsskrb5_locl.h" RCSID("$Id$"); @@ -154,6 +154,11 @@ _gsskrb5_wrap_size_limit ( GSSAPI_KRB5_INIT (&context); + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_size_cfx(minor_status, ctx, context, + conf_req_flag, qop_req, + req_output_size, max_input_size); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -177,9 +182,7 @@ _gsskrb5_wrap_size_limit ( ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); break; default : - ret = _gssapi_wrap_size_cfx(minor_status, ctx, context, - conf_req_flag, qop_req, - req_output_size, max_input_size, key); + abort(); break; } krb5_free_keyblock (context, key); @@ -530,8 +533,16 @@ OM_uint32 _gsskrb5_wrap krb5_keytype keytype; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + output_message_buffer->value = NULL; + output_message_buffer->length = 0; + GSSAPI_KRB5_INIT (&context); + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer); + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); ret = _gsskrb5i_get_token_key(ctx, context, &key); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); @@ -559,9 +570,7 @@ OM_uint32 _gsskrb5_wrap output_message_buffer, key); break; default : - ret = _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, - qop_req, input_message_buffer, conf_state, - output_message_buffer, key); + abort(); break; } krb5_free_keyblock (context, key); diff --git a/source4/heimdal/lib/gssapi/mech/context.c b/source4/heimdal/lib/gssapi/mech/context.c index a06a1e9e37..b032d8aa0e 100644 --- a/source4/heimdal/lib/gssapi/mech/context.c +++ b/source4/heimdal/lib/gssapi/mech/context.c @@ -1,4 +1,4 @@ -#include "mech/mech_locl.h" +#include "mech_locl.h" #include "heim_threads.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c index 50011a9b0d..134511f34b 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c +++ b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c @@ -260,7 +260,8 @@ OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status, if (mech_ret_flags & GSS_C_DELEG_FLAG) { if (!delegated_cred_handle) { m->gm_release_cred(minor_status, &delegated_mc); - *ret_flags &= ~GSS_C_DELEG_FLAG; + if (ret_flags) + *ret_flags &= ~GSS_C_DELEG_FLAG; } else if (delegated_mc) { struct _gss_cred *dcred; struct _gss_mechanism_cred *dmc; diff --git a/source4/heimdal/lib/gssapi/mech/gss_acquire_cred.c b/source4/heimdal/lib/gssapi/mech/gss_acquire_cred.c index b21b3f62e8..a8ebe644ab 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_acquire_cred.c +++ b/source4/heimdal/lib/gssapi/mech/gss_acquire_cred.c @@ -51,7 +51,7 @@ gss_acquire_cred(OM_uint32 *minor_status, *minor_status = 0; if (output_cred_handle) - *output_cred_handle = GSS_C_NO_CREDENTIAL; + return GSS_S_CALL_INACCESSIBLE_READ; if (actual_mechs) *actual_mechs = GSS_C_NO_OID_SET; if (time_rec) diff --git a/source4/heimdal/lib/gssapi/mech/gss_aeap.c b/source4/heimdal/lib/gssapi/mech/gss_aeap.c new file mode 100644 index 0000000000..cbe0cd1460 --- /dev/null +++ b/source4/heimdal/lib/gssapi/mech/gss_aeap.c @@ -0,0 +1,184 @@ +/* + * AEAD support + */ + +#include "mech_locl.h" +RCSID("$Id$"); + +/** + * Encrypts or sign the data. + * + * The maximum packet size is gss_context_stream_sizes.max_msg_size. + * + * The caller needs provide the folloing buffers: + * + * - HEADER (of size gss_context_stream_sizes.header) + * SIGN_ONLY (optional, zero or more) + * DATA + * SIGN_ONLY (optional, zero or more) + * PADDING (of size gss_context_stream_sizes.blocksize) + * TRAILER (of size gss_context_stream_sizes.trailer) + * + * - on DCE-RPC mode, the caller can skip PADDING and TRAILER if the + * DATA elements is padded to a block bountry. + * + * To generate gss_wrap() compatible packets, use: HEADER | DATA | PADDING | TRAILER + * + * The input sizes of HEADER, PADDING and TRAILER can be fetched using gss_wrap_iov_length() or + * gss_context_query_attributes(). + * + * @ingroup gssapi + */ + + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_wrap_iov(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (minor_status) + *minor_status = 0; + if (conf_state) + *conf_state = 0; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + m = ctx->gc_mech; + + if (m->gm_wrap_iov == NULL) { + if (minor_status) + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + return (m->gm_wrap_iov)(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, conf_state, + iov, iov_count); +} + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (minor_status) + *minor_status = 0; + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + m = ctx->gc_mech; + + if (m->gm_unwrap_iov == NULL) { + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + return (m->gm_unwrap_iov)(minor_status, ctx->gc_ctx, + conf_state, qop_state, + iov, iov_count); +} + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_wrap_iov_length(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (minor_status) + *minor_status = 0; + if (conf_state) + *conf_state = 0; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + m = ctx->gc_mech; + + if (m->gm_wrap_iov_length == NULL) { + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + return (m->gm_wrap_iov_length)(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, conf_state, + iov, iov_count); +} + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_release_iov_buffer(OM_uint32 *minor_status, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 junk; + size_t i; + + if (minor_status) + *minor_status = 0; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + for (i = 0; i < iov_count; i++) { + if (iov[i].type & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED) + continue; + gss_release_buffer(&junk, &iov[i].buffer); + } + return GSS_S_COMPLETE; +} + +/** + * Query the context for parameters. + * + * SSPI equivalent if this function is QueryContextAttributes. + * + * - GSS_C_ATTR_STREAM_SIZES data is a gss_context_stream_sizes. + */ + +static gss_OID_desc gss_c_attr_stream_sizes_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")}; + +gss_OID GSSAPI_LIB_VARIABLE GSS_C_ATTR_STREAM_SIZES = + &gss_c_attr_stream_sizes_desc; + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_context_query_attributes(OM_uint32 *minor_status, + gss_OID attribute, + void *data, + size_t len) +{ + *minor_status = 0; + + if (gss_oid_equal(GSS_C_ATTR_STREAM_SIZES, attribute)) { + memset(data, 0, len); + return GSS_S_COMPLETE; + } + + return GSS_S_FAILURE; +} diff --git a/source4/heimdal/lib/gssapi/mech/gss_canonicalize_name.c b/source4/heimdal/lib/gssapi/mech/gss_canonicalize_name.c index 91a08fb2bc..db976f2453 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_canonicalize_name.c +++ b/source4/heimdal/lib/gssapi/mech/gss_canonicalize_name.c @@ -29,6 +29,30 @@ #include "mech_locl.h" RCSID("$Id$"); +/** + * gss_canonicalize_name takes a Internal Name (IN) and converts in into a + * mechanism specific Mechanism Name (MN). + * + * The input name may multiple name, or generic name types. + * + * If the input_name if of the GSS_C_NT_USER_NAME, and the Kerberos + * mechanism is specified, the resulting MN type is a + * GSS_KRB5_NT_PRINCIPAL_NAME. + * + * For more information about @ref internalVSmechname. + * + * @param minor_status minor status code. + * @param input_name name to covert, unchanged by gss_canonicalize_name(). + * @param mech_type the type to convert Name too. + * @param output_name the resulting type, release with + * gss_release_name(), independent of input_name. + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ + OM_uint32 GSSAPI_LIB_FUNCTION gss_canonicalize_name(OM_uint32 *minor_status, const gss_name_t input_name, diff --git a/source4/heimdal/lib/gssapi/mech/gss_get_mic.c b/source4/heimdal/lib/gssapi/mech/gss_get_mic.c index 9cd5060fc9..3a0f3fb757 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_get_mic.c +++ b/source4/heimdal/lib/gssapi/mech/gss_get_mic.c @@ -37,7 +37,7 @@ gss_get_mic(OM_uint32 *minor_status, gss_buffer_t message_token) { struct _gss_context *ctx = (struct _gss_context *) context_handle; - gssapi_mech_interface m = ctx->gc_mech; + gssapi_mech_interface m; _mg_buffer_zero(message_token); if (ctx == NULL) { @@ -45,6 +45,8 @@ gss_get_mic(OM_uint32 *minor_status, return GSS_S_NO_CONTEXT; } + m = ctx->gc_mech; + return (m->gm_get_mic(minor_status, ctx->gc_ctx, qop_req, message_buffer, message_token)); } diff --git a/source4/heimdal/lib/gssapi/mech/gss_import_name.c b/source4/heimdal/lib/gssapi/mech/gss_import_name.c index 040e228410..c1dffdc614 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_import_name.c +++ b/source4/heimdal/lib/gssapi/mech/gss_import_name.c @@ -145,9 +145,12 @@ gss_import_name(OM_uint32 *minor_status, const gss_OID input_name_type, gss_name_t *output_name) { + struct _gss_mechanism_name *mn; gss_OID name_type = input_name_type; - OM_uint32 major_status; + OM_uint32 major_status, ms; struct _gss_name *name; + struct _gss_mech_switch *m; + gss_name_t rname; *output_name = GSS_C_NO_NAME; @@ -156,6 +159,8 @@ gss_import_name(OM_uint32 *minor_status, return (GSS_S_BAD_NAME); } + _gss_load_mech(); + /* * Use GSS_NT_USER_NAME as default name type. */ @@ -172,29 +177,15 @@ gss_import_name(OM_uint32 *minor_status, input_name_buffer, output_name); } - /* - * Only allow certain name types. This is pretty bogus - we - * should figure out the list of supported name types using - * gss_inquire_names_for_mech. - */ - if (!gss_oid_equal(name_type, GSS_C_NT_USER_NAME) - && !gss_oid_equal(name_type, GSS_C_NT_MACHINE_UID_NAME) - && !gss_oid_equal(name_type, GSS_C_NT_STRING_UID_NAME) - && !gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE_X) - && !gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE) - && !gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS) - && !gss_oid_equal(name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) { - *minor_status = 0; - return (GSS_S_BAD_NAMETYPE); - } *minor_status = 0; - name = malloc(sizeof(struct _gss_name)); + name = calloc(1, sizeof(struct _gss_name)); if (!name) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } - memset(name, 0, sizeof(struct _gss_name)); + + SLIST_INIT(&name->gn_mn); major_status = _gss_copy_oid(minor_status, name_type, &name->gn_type); @@ -205,14 +196,62 @@ gss_import_name(OM_uint32 *minor_status, major_status = _gss_copy_buffer(minor_status, input_name_buffer, &name->gn_value); - if (major_status) { - gss_name_t rname = (gss_name_t)name; - gss_release_name(minor_status, &rname); - return (GSS_S_FAILURE); + if (major_status) + goto out; + + /* + * Walk over the mechs and import the name into a mech name + * for those supported this nametype. + */ + + SLIST_FOREACH(m, &_gss_mechs, gm_link) { + int present = 0; + + major_status = gss_test_oid_set_member(minor_status, + name_type, m->gm_name_types, &present); + + if (major_status || present == 0) + continue; + + mn = malloc(sizeof(struct _gss_mechanism_name)); + if (!mn) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto out; + } + + major_status = (*m->gm_mech.gm_import_name)(minor_status, + &name->gn_value, + (name->gn_type.elements + ? &name->gn_type : GSS_C_NO_OID), + &mn->gmn_name); + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(&m->gm_mech, major_status, *minor_status); + free(mn); + goto out; + } + + mn->gmn_mech = &m->gm_mech; + mn->gmn_mech_oid = &m->gm_mech_oid; + SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); } - SLIST_INIT(&name->gn_mn); + /* + * If we can't find a mn for the name, bail out already here. + */ + + mn = SLIST_FIRST(&name->gn_mn); + if (!mn) { + *minor_status = 0; + major_status = GSS_S_NAME_NOT_MN; + goto out; + } *output_name = (gss_name_t) name; return (GSS_S_COMPLETE); + + out: + rname = (gss_name_t)name; + gss_release_name(&ms, &rname); + return major_status; } diff --git a/source4/heimdal/lib/gssapi/mech/gss_krb5.c b/source4/heimdal/lib/gssapi/mech/gss_krb5.c index 5318f6cdba..5d883c45c2 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_krb5.c +++ b/source4/heimdal/lib/gssapi/mech/gss_krb5.c @@ -278,7 +278,7 @@ gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, || *context_handle == GSS_C_NO_CONTEXT || version != 1) { - ret = EINVAL; + *minor_status = EINVAL; return GSS_S_FAILURE; } @@ -715,7 +715,7 @@ gsskrb5_extract_key(OM_uint32 *minor_status, krb5_storage *sp = NULL; if (context_handle == GSS_C_NO_CONTEXT) { - ret = EINVAL; + *minor_status = EINVAL; return GSS_S_FAILURE; } diff --git a/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c b/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c index fc2e8816c5..3321819d28 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c +++ b/source4/heimdal/lib/gssapi/mech/gss_mech_switch.c @@ -186,6 +186,15 @@ add_builtin(gssapi_mech_interface mech) gss_add_oid_set_member(&minor_status, &m->gm_mech.gm_mech_oid, &_gss_mech_oids); + /* pick up the oid sets of names */ + + if (m->gm_mech.gm_inquire_names_for_mech) { + (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status, + &m->gm_mech.gm_mech_oid, &m->gm_name_types); + } else { + gss_create_empty_oid_set(&minor_status, &m->gm_name_types); + } + SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); return 0; } @@ -221,9 +230,7 @@ _gss_load_mech(void) add_builtin(__gss_krb5_initialize()); add_builtin(__gss_spnego_initialize()); -#ifndef HEIMDAL_SMALLER add_builtin(__gss_ntlm_initialize()); -#endif #ifdef HAVE_DLOPEN fp = fopen(_PATH_GSS_MECH, "r"); @@ -308,6 +315,9 @@ _gss_load_mech(void) OPTSYM(set_sec_context_option); OPTSYM(set_cred_option); OPTSYM(pseudo_random); + OPTSYM(wrap_iov); + OPTSYM(unwrap_iov); + OPTSYM(wrap_iov_length); SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); continue; diff --git a/source4/heimdal/lib/gssapi/mech/gss_pseudo_random.c b/source4/heimdal/lib/gssapi/mech/gss_pseudo_random.c index b907f94038..771efcb434 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_pseudo_random.c +++ b/source4/heimdal/lib/gssapi/mech/gss_pseudo_random.c @@ -45,7 +45,7 @@ gss_pseudo_random(OM_uint32 *minor_status, gss_buffer_t prf_out) { struct _gss_context *ctx = (struct _gss_context *) context; - gssapi_mech_interface m = ctx->gc_mech; + gssapi_mech_interface m; OM_uint32 major_status; _mg_buffer_zero(prf_out); @@ -56,6 +56,8 @@ gss_pseudo_random(OM_uint32 *minor_status, return GSS_S_NO_CONTEXT; } + m = ctx->gc_mech; + if (m->gm_pseudo_random == NULL) return GSS_S_UNAVAILABLE; diff --git a/source4/heimdal/lib/gssapi/mech/gss_verify_mic.c b/source4/heimdal/lib/gssapi/mech/gss_verify_mic.c index 1a411729c6..60ef3bff85 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_verify_mic.c +++ b/source4/heimdal/lib/gssapi/mech/gss_verify_mic.c @@ -37,7 +37,7 @@ gss_verify_mic(OM_uint32 *minor_status, gss_qop_t *qop_state) { struct _gss_context *ctx = (struct _gss_context *) context_handle; - gssapi_mech_interface m = ctx->gc_mech; + gssapi_mech_interface m; if (qop_state) *qop_state = 0; @@ -46,6 +46,8 @@ gss_verify_mic(OM_uint32 *minor_status, return GSS_S_NO_CONTEXT; } + m = ctx->gc_mech; + return (m->gm_verify_mic(minor_status, ctx->gc_ctx, message_buffer, token_buffer, qop_state)); } diff --git a/source4/heimdal/lib/gssapi/mech/gss_wrap.c b/source4/heimdal/lib/gssapi/mech/gss_wrap.c index b3363d3f20..9476d01ddd 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_wrap.c +++ b/source4/heimdal/lib/gssapi/mech/gss_wrap.c @@ -39,7 +39,7 @@ gss_wrap(OM_uint32 *minor_status, gss_buffer_t output_message_buffer) { struct _gss_context *ctx = (struct _gss_context *) context_handle; - gssapi_mech_interface m = ctx->gc_mech; + gssapi_mech_interface m; if (conf_state) *conf_state = 0; @@ -49,6 +49,8 @@ gss_wrap(OM_uint32 *minor_status, return GSS_S_NO_CONTEXT; } + m = ctx->gc_mech; + return (m->gm_wrap(minor_status, ctx->gc_ctx, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer)); diff --git a/source4/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c b/source4/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c index 15b86a9367..a5a80b21d7 100644 --- a/source4/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c +++ b/source4/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c @@ -38,7 +38,7 @@ gss_wrap_size_limit(OM_uint32 *minor_status, OM_uint32 *max_input_size) { struct _gss_context *ctx = (struct _gss_context *) context_handle; - gssapi_mech_interface m = ctx->gc_mech; + gssapi_mech_interface m; *max_input_size = 0; if (ctx == NULL) { @@ -46,6 +46,8 @@ gss_wrap_size_limit(OM_uint32 *minor_status, return GSS_S_NO_CONTEXT; } + m = ctx->gc_mech; + return (m->gm_wrap_size_limit(minor_status, ctx->gc_ctx, conf_req_flag, qop_req, req_output_size, max_input_size)); } diff --git a/source4/heimdal/lib/gssapi/mech/mech_locl.h b/source4/heimdal/lib/gssapi/mech/mech_locl.h index 42c069eb2d..17721fd3ce 100644 --- a/source4/heimdal/lib/gssapi/mech/mech_locl.h +++ b/source4/heimdal/lib/gssapi/mech/mech_locl.h @@ -53,6 +53,7 @@ #include <gssapi.h> #include <gssapi_mech.h> +#include <gssapi_krb5.h> #include "mechqueue.h" diff --git a/source4/heimdal/lib/gssapi/mech/mech_switch.h b/source4/heimdal/lib/gssapi/mech/mech_switch.h index e83a4c8a5a..56e3b7dea7 100644 --- a/source4/heimdal/lib/gssapi/mech/mech_switch.h +++ b/source4/heimdal/lib/gssapi/mech/mech_switch.h @@ -32,6 +32,7 @@ struct _gss_mech_switch { SLIST_ENTRY(_gss_mech_switch) gm_link; gss_OID_desc gm_mech_oid; + gss_OID_set gm_name_types; void *gm_so; gssapi_mech_interface_desc gm_mech; }; diff --git a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c index cabd806fbf..158126d99f 100644 --- a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c +++ b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "spnego/spnego_locl.h" +#include "spnego_locl.h" RCSID("$Id$"); @@ -494,7 +494,7 @@ acceptor_complete(OM_uint32 * minor_status, *get_mic = 1; } - if (verify_mic || get_mic) { + if (verify_mic || *get_mic) { int eret; size_t buf_len; @@ -512,7 +512,7 @@ acceptor_complete(OM_uint32 * minor_status, if (verify_mic) { ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic); if (ret) { - if (get_mic) + if (*get_mic) send_reject (minor_status, output_token); if (buf.value) free(buf.value); diff --git a/source4/heimdal/lib/gssapi/spnego/compat.c b/source4/heimdal/lib/gssapi/spnego/compat.c index 67d9b202a7..ee25b59435 100644 --- a/source4/heimdal/lib/gssapi/spnego/compat.c +++ b/source4/heimdal/lib/gssapi/spnego/compat.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "spnego/spnego_locl.h" +#include "spnego_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/spnego/context_stubs.c b/source4/heimdal/lib/gssapi/spnego/context_stubs.c index 5bc1a48656..1998c44edf 100644 --- a/source4/heimdal/lib/gssapi/spnego/context_stubs.c +++ b/source4/heimdal/lib/gssapi/spnego/context_stubs.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "spnego/spnego_locl.h" +#include "spnego_locl.h" RCSID("$Id$"); @@ -62,6 +62,7 @@ spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs) return ret; } } + gss_release_oid_set(&junk, &m); return ret; } @@ -598,7 +599,7 @@ out: gss_release_oid_set(&junk, &mechs); - return GSS_S_COMPLETE; + return ret; } OM_uint32 _gss_spnego_inquire_mechs_for_name ( @@ -642,128 +643,6 @@ OM_uint32 _gss_spnego_duplicate_name ( return gss_duplicate_name(minor_status, src_name, dest_name); } -OM_uint32 _gss_spnego_sign - (OM_uint32 * minor_status, - gss_ctx_id_t context_handle, - int qop_req, - gss_buffer_t message_buffer, - gss_buffer_t message_token - ) -{ - gssspnego_ctx ctx; - - *minor_status = 0; - - if (context_handle == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - ctx = (gssspnego_ctx)context_handle; - - if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - return gss_sign(minor_status, - ctx->negotiated_ctx_id, - qop_req, - message_buffer, - message_token); -} - -OM_uint32 _gss_spnego_verify - (OM_uint32 * minor_status, - gss_ctx_id_t context_handle, - gss_buffer_t message_buffer, - gss_buffer_t token_buffer, - int * qop_state - ) -{ - gssspnego_ctx ctx; - - *minor_status = 0; - - if (context_handle == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - ctx = (gssspnego_ctx)context_handle; - - if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - return gss_verify(minor_status, - ctx->negotiated_ctx_id, - message_buffer, - token_buffer, - qop_state); -} - -OM_uint32 _gss_spnego_seal - (OM_uint32 * minor_status, - gss_ctx_id_t context_handle, - int conf_req_flag, - int qop_req, - gss_buffer_t input_message_buffer, - int * conf_state, - gss_buffer_t output_message_buffer - ) -{ - gssspnego_ctx ctx; - - *minor_status = 0; - - if (context_handle == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - ctx = (gssspnego_ctx)context_handle; - - if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - return gss_seal(minor_status, - ctx->negotiated_ctx_id, - conf_req_flag, - qop_req, - input_message_buffer, - conf_state, - output_message_buffer); -} - -OM_uint32 _gss_spnego_unseal - (OM_uint32 * minor_status, - gss_ctx_id_t context_handle, - gss_buffer_t input_message_buffer, - gss_buffer_t output_message_buffer, - int * conf_state, - int * qop_state - ) -{ - gssspnego_ctx ctx; - - *minor_status = 0; - - if (context_handle == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - ctx = (gssspnego_ctx)context_handle; - - if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { - return GSS_S_NO_CONTEXT; - } - - return gss_unseal(minor_status, - ctx->negotiated_ctx_id, - input_message_buffer, - output_message_buffer, - conf_state, - qop_state); -} - #if 0 OM_uint32 _gss_spnego_unwrap_ex (OM_uint32 * minor_status, diff --git a/source4/heimdal/lib/gssapi/spnego/cred_stubs.c b/source4/heimdal/lib/gssapi/spnego/cred_stubs.c index f6b3fecaa0..a3a984e22c 100644 --- a/source4/heimdal/lib/gssapi/spnego/cred_stubs.c +++ b/source4/heimdal/lib/gssapi/spnego/cred_stubs.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "spnego/spnego_locl.h" +#include "spnego_locl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/gssapi/spnego/external.c b/source4/heimdal/lib/gssapi/spnego/external.c index 02404237a7..2dc809bbba 100644 --- a/source4/heimdal/lib/gssapi/spnego/external.c +++ b/source4/heimdal/lib/gssapi/spnego/external.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. */ -#include "spnego/spnego_locl.h" +#include "spnego_locl.h" #include <gssapi_mech.h> RCSID("$Id$"); @@ -71,7 +71,7 @@ static gssapi_mech_interface_desc spnego_mech = { _gss_spnego_inquire_cred_by_mech, _gss_spnego_export_sec_context, _gss_spnego_import_sec_context, - _gss_spnego_inquire_names_for_mech, + NULL /* _gss_spnego_inquire_names_for_mech */, _gss_spnego_inquire_mechs_for_name, _gss_spnego_canonicalize_name, _gss_spnego_duplicate_name, diff --git a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c index 7a5814413b..ac32432d55 100644 --- a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c +++ b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -#include "spnego/spnego_locl.h" +#include "spnego_locl.h" RCSID("$Id$"); @@ -392,8 +392,7 @@ spnego_reply ) { OM_uint32 ret, minor; - NegTokenResp resp; - size_t len, taglen; + NegotiationToken resp; gss_OID_desc mech; int require_mic; size_t buf_len; @@ -414,27 +413,23 @@ spnego_reply mech_buf.value = NULL; mech_buf.length = 0; - ret = der_match_tag_and_length(input_token->value, input_token->length, - ASN1_C_CONTEXT, CONS, 1, &len, &taglen); + ret = decode_NegotiationToken(input_token->value, input_token->length, + &resp, NULL); if (ret) - return ret; + return ret; - if (len > input_token->length - taglen) - return ASN1_OVERRUN; - - ret = decode_NegTokenResp((const unsigned char *)input_token->value+taglen, - len, &resp, NULL); - if (ret) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; + if (resp.element != choice_NegotiationToken_negTokenResp) { + free_NegotiationToken(&resp); + *minor_status = 0; + return GSS_S_BAD_MECH; } - if (resp.negResult == NULL - || *(resp.negResult) == reject - /* || resp.supportedMech == NULL */ + if (resp.u.negTokenResp.negResult == NULL + || *(resp.u.negTokenResp.negResult) == reject + /* || resp.u.negTokenResp.supportedMech == NULL */ ) { - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); return GSS_S_BAD_MECH; } @@ -445,16 +440,16 @@ spnego_reply HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - if (resp.supportedMech) { + if (resp.u.negTokenResp.supportedMech) { if (ctx->oidlen) { - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return GSS_S_BAD_MECH; } ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1, sizeof(ctx->oidbuf), - resp.supportedMech, + resp.u.negTokenResp.supportedMech, &ctx->oidlen); /* Avoid recursively embedded SPNEGO */ if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length && @@ -462,7 +457,7 @@ spnego_reply GSS_SPNEGO_MECHANISM->elements, ctx->oidlen) == 0)) { - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return GSS_S_BAD_MECH; } @@ -478,19 +473,19 @@ spnego_reply ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; } } else if (ctx->oidlen == 0) { - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return GSS_S_BAD_MECH; } /* if a token (of non zero length), or no context, pass to underlaying mech */ - if ((resp.responseToken != NULL && resp.responseToken->length) || + if ((resp.u.negTokenResp.responseToken != NULL && resp.u.negTokenResp.responseToken->length) || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { gss_buffer_desc mech_input_token; - if (resp.responseToken) { - mech_input_token.length = resp.responseToken->length; - mech_input_token.value = resp.responseToken->data; + if (resp.u.negTokenResp.responseToken) { + mech_input_token.length = resp.u.negTokenResp.responseToken->length; + mech_input_token.value = resp.u.negTokenResp.responseToken->data; } else { mech_input_token.length = 0; mech_input_token.value = NULL; @@ -518,7 +513,7 @@ spnego_reply &ctx->mech_time_rec); if (GSS_ERROR(ret)) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); gss_mg_collect_error(&mech, ret, minor); *minor_status = minor; return ret; @@ -526,12 +521,12 @@ spnego_reply if (ret == GSS_S_COMPLETE) { ctx->open = 1; } - } else if (*(resp.negResult) == accept_completed) { + } else if (*(resp.u.negTokenResp.negResult) == accept_completed) { if (ctx->maybe_open) ctx->open = 1; } - if (*(resp.negResult) == request_mic) { + if (*(resp.u.negTokenResp.negResult) == request_mic) { ctx->require_mic = 1; } @@ -540,14 +535,14 @@ spnego_reply * Verify the mechListMIC if one was provided or CFX was * used and a non-preferred mechanism was selected */ - if (resp.mechListMIC != NULL) { + if (resp.u.negTokenResp.mechListMIC != NULL) { require_mic = 1; } else { ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic); if (ret) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); gss_release_buffer(&minor, &mech_output_token); return ret; } @@ -561,7 +556,7 @@ spnego_reply &ctx->initiator_mech_types, &buf_len, ret); if (ret) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); gss_release_buffer(&minor, &mech_output_token); *minor_status = ret; return GSS_S_FAILURE; @@ -569,15 +564,15 @@ spnego_reply if (mech_buf.length != buf_len) abort(); - if (resp.mechListMIC == NULL) { + if (resp.u.negTokenResp.mechListMIC == NULL) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); free(mech_buf.value); - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); *minor_status = 0; return GSS_S_DEFECTIVE_TOKEN; } - mic_buf.length = resp.mechListMIC->length; - mic_buf.value = resp.mechListMIC->data; + mic_buf.length = resp.u.negTokenResp.mechListMIC->length; + mic_buf.value = resp.u.negTokenResp.mechListMIC->data; if (mech_output_token.length == 0) { ret = gss_verify_mic(minor_status, @@ -589,7 +584,7 @@ spnego_reply HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); free(mech_buf.value); gss_release_buffer(&minor, &mech_output_token); - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); return GSS_S_DEFECTIVE_TOKEN; } ctx->verified_mic = 1; @@ -604,7 +599,7 @@ spnego_reply if (mech_buf.value != NULL) free(mech_buf.value); - free_NegTokenResp(&resp); + free_NegotiationToken(&resp); gss_release_buffer(&minor, &mech_output_token); if (actual_mech_type) diff --git a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h index 8344e750ae..44fa8b117d 100644 --- a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h +++ b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h @@ -35,9 +35,7 @@ #ifndef SPNEGO_LOCL_H #define SPNEGO_LOCL_H -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -50,8 +48,9 @@ #include <pthread.h> #endif -#include <gssapi/gssapi_spnego.h> #include <gssapi.h> +#include <gssapi_krb5.h> +#include <gssapi_spnego.h> #include <assert.h> #include <stdlib.h> #include <string.h> @@ -67,7 +66,7 @@ #include <gssapi_mech.h> #include "spnego_asn1.h" -#include "mech/utils.h" +#include "utils.h" #include <der.h> #include <roken.h> @@ -109,6 +108,6 @@ typedef struct { extern gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc; extern gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc; -#include <spnego/spnego-private.h> +#include <spnego-private.h> #endif /* SPNEGO_LOCL_H */ diff --git a/source4/heimdal/lib/hcrypto/bn.c b/source4/heimdal/lib/hcrypto/bn.c index b91a65a7bf..179595ae5c 100644 --- a/source4/heimdal/lib/hcrypto/bn.c +++ b/source4/heimdal/lib/hcrypto/bn.c @@ -443,3 +443,91 @@ BN_GENCB_call(BN_GENCB *cb, int a, int b) return 1; return cb->cb.cb_2(a, b, cb); } + +/* + * + */ + +struct BN_CTX { + struct { + BIGNUM **val; + size_t used; + size_t len; + } bn; + struct { + size_t *val; + size_t used; + size_t len; + } stack; +}; + +BN_CTX * +BN_CTX_new(void) +{ + struct BN_CTX *c; + c = calloc(1, sizeof(*c)); + return c; +} + +void +BN_CTX_free(BN_CTX *c) +{ + size_t i; + for (i = 0; i < c->bn.len; i++) + BN_free(c->bn.val[i]); + free(c->bn.val); + free(c->stack.val); +} + +BIGNUM * +BN_CTX_get(BN_CTX *c) +{ + if (c->bn.used == c->bn.len) { + void *ptr; + size_t i; + c->bn.len += 16; + ptr = realloc(c->bn.val, c->bn.len * sizeof(c->bn.val[0])); + if (ptr == NULL) + return NULL; + c->bn.val = ptr; + for (i = c->bn.used; i < c->bn.len; i++) { + c->bn.val[i] = BN_new(); + if (c->bn.val[i] == NULL) { + c->bn.len = i; + return NULL; + } + } + } + return c->bn.val[c->bn.used++]; +} + +void +BN_CTX_start(BN_CTX *c) +{ + if (c->stack.used == c->stack.len) { + void *ptr; + c->stack.len += 16; + ptr = realloc(c->stack.val, c->stack.len * sizeof(c->stack.val[0])); + if (ptr == NULL) + abort(); + c->stack.val = ptr; + } + c->stack.val[c->stack.used++] = c->bn.used; +} + +void +BN_CTX_end(BN_CTX *c) +{ + const size_t prev = c->stack.val[c->stack.used - 1]; + size_t i; + + if (c->stack.used == 0) + abort(); + + for (i = prev; i < c->bn.used; i++) + BN_clear(c->bn.val[i]); + + c->stack.used--; + c->bn.used = prev; +} + diff --git a/source4/heimdal/lib/hcrypto/bn.h b/source4/heimdal/lib/hcrypto/bn.h index aac770b5a8..2fa25ac1a0 100644 --- a/source4/heimdal/lib/hcrypto/bn.h +++ b/source4/heimdal/lib/hcrypto/bn.h @@ -62,16 +62,21 @@ #define BN_set_negative hc_BN_set_negative #define BN_set_word hc_BN_set_word #define BN_uadd hc_BN_uadd +#define BN_CTX_new hc_BN_CTX_new +#define BN_CTX_free hc_BN_CTX_free +#define BN_CTX_get hc_BN_CTX_get +#define BN_CTX_start hc_BN_CTX_start +#define BN_CTX_end hc_BN_CTX_end /* * */ -typedef void BIGNUM; +typedef struct BIGNUM BIGNUM; typedef struct BN_GENCB BN_GENCB; -typedef void BN_CTX; -typedef void BN_MONT_CTX; -typedef void BN_BLINDING; +typedef struct BN_CTX BN_CTX; +typedef struct BN_MONT_CTX BN_MONT_CTX; +typedef struct BN_BLINDING BN_BLINDING; struct BN_GENCB { unsigned int ver; @@ -118,4 +123,10 @@ int BN_rand(BIGNUM *, int, int, int); void BN_GENCB_set(BN_GENCB *, int (*)(int, int, BN_GENCB *), void *); int BN_GENCB_call(BN_GENCB *, int, int); +BN_CTX *BN_CTX_new(void); +void BN_CTX_free(BN_CTX *); +BIGNUM *BN_CTX_get(BN_CTX *); +void BN_CTX_start(BN_CTX *); +void BN_CTX_end(BN_CTX *); + #endif diff --git a/source4/heimdal/lib/hcrypto/evp-aes-cts.c b/source4/heimdal/lib/hcrypto/evp-aes-cts.c index 685dcac18b..66f87982c0 100644 --- a/source4/heimdal/lib/hcrypto/evp-aes-cts.c +++ b/source4/heimdal/lib/hcrypto/evp-aes-cts.c @@ -31,11 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif - -RCSID("$Id$"); #define HC_DEPRECATED diff --git a/source4/heimdal/lib/hcrypto/evp.c b/source4/heimdal/lib/hcrypto/evp.c index 517ca2a2bc..ac6cac972a 100644 --- a/source4/heimdal/lib/hcrypto/evp.c +++ b/source4/heimdal/lib/hcrypto/evp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -35,8 +35,6 @@ #include <config.h> #endif -RCSID("$Id$"); - #define HC_DEPRECATED #define HC_DEPRECATED_CRYPTO @@ -512,13 +510,6 @@ EVP_md_null(void) return &null; } -#if 0 -int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); -int EVP_DigestFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s); -int EVP_SignFinal(EVP_MD_CTX *, void *, size_t *, EVP_PKEY *); -int EVP_VerifyFinal(EVP_MD_CTX *, const void *, size_t, EVP_PKEY *); -#endif - /** * Return the block size of the cipher. * @@ -1650,6 +1641,11 @@ EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, void *key) /** * Perform a operation on a ctx * + * @param ctx context to perform operation on. + * @param type type of operation. + * @param arg argument to operation. + * @param data addition data to operation. + * @return 1 for success, 0 for failure. * * @ingroup hcrypto_core diff --git a/source4/heimdal/lib/hcrypto/rand-unix.c b/source4/heimdal/lib/hcrypto/rand-unix.c index 0c2185776c..07d81eb620 100644 --- a/source4/heimdal/lib/hcrypto/rand-unix.c +++ b/source4/heimdal/lib/hcrypto/rand-unix.c @@ -40,11 +40,15 @@ RCSID("$Id$"); #include <stdio.h> #include <stdlib.h> #include <rand.h> +#include <heim_threads.h> #include <roken.h> #include "randi.h" +static int random_fd = -1; +static HEIMDAL_MUTEX random_mutex = HEIMDAL_MUTEX_INITIALIZER; + /* * Unix /dev/random */ @@ -88,31 +92,47 @@ unix_seed(const void *indata, int size) } + static int unix_bytes(unsigned char *outdata, int size) { ssize_t count; - int fd; + int once = 0; if (size <= 0) return 0; - fd = get_device_fd(O_RDONLY); - if (fd < 0) - return 0; + HEIMDAL_MUTEX_lock(&random_mutex); + if (random_fd == -1) { + retry: + random_fd = get_device_fd(O_RDONLY); + if (random_fd < 0) { + HEIMDAL_MUTEX_unlock(&random_mutex); + return 0; + } + } while (size > 0) { - count = read (fd, outdata, size); - if (count < 0 && errno == EINTR) - continue; - else if (count <= 0) { - close(fd); + HEIMDAL_MUTEX_unlock(&random_mutex); + count = read (random_fd, outdata, size); + HEIMDAL_MUTEX_lock(&random_mutex); + if (random_fd < 0) { + if (errno == EINTR) + continue; + else if (errno == EBADF && once++ == 0) { + close(random_fd); + random_fd = -1; + goto retry; + } + return 0; + } else if (count <= 0) { + HEIMDAL_MUTEX_unlock(&random_mutex); return 0; } outdata += count; size -= count; } - close(fd); + HEIMDAL_MUTEX_unlock(&random_mutex); return 1; } diff --git a/source4/heimdal/lib/hcrypto/rand.c b/source4/heimdal/lib/hcrypto/rand.c index b8ac2155d1..a61c9cdfb2 100644 --- a/source4/heimdal/lib/hcrypto/rand.c +++ b/source4/heimdal/lib/hcrypto/rand.c @@ -62,7 +62,11 @@ init_method(void) { if (selected_meth != NULL) return; +#ifdef __APPLE__ + selected_meth = &hc_rand_unix_method; +#else selected_meth = &hc_rand_fortuna_method; +#endif } /** diff --git a/source4/heimdal/lib/hdb/dbinfo.c b/source4/heimdal/lib/hdb/dbinfo.c index 2121577bb1..7e2961c614 100644 --- a/source4/heimdal/lib/hdb/dbinfo.c +++ b/source4/heimdal/lib/hdb/dbinfo.c @@ -228,10 +228,12 @@ hdb_free_dbinfo(krb5_context context, struct hdb_dbinfo **dbp) for(di = *dbp; di != NULL; di = ndi) { ndi = di->next; + free (di->label); free (di->realm); free (di->dbname); - if (di->mkey_file) - free (di->mkey_file); + free (di->mkey_file); + free (di->acl_file); + free (di->log_file); free(di); } *dbp = NULL; diff --git a/source4/heimdal/lib/hdb/ext.c b/source4/heimdal/lib/hdb/ext.c index f792b85c09..9053fd6633 100644 --- a/source4/heimdal/lib/hdb/ext.c +++ b/source4/heimdal/lib/hdb/ext.c @@ -235,6 +235,20 @@ hdb_entry_get_pkinit_hash(const hdb_entry *entry, const HDB_Ext_PKINIT_hash **a) } krb5_error_code +hdb_entry_get_pkinit_cert(const hdb_entry *entry, const HDB_Ext_PKINIT_cert **a) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert); + if (ext) + *a = &ext->data.u.pkinit_cert; + else + *a = NULL; + + return 0; +} + +krb5_error_code hdb_entry_get_pw_change_time(const hdb_entry *entry, time_t *t) { const HDB_extension *ext; diff --git a/source4/heimdal/lib/hdb/hdb.asn1 b/source4/heimdal/lib/hdb/hdb.asn1 index 5cddf8f1d0..c2abd4af73 100644 --- a/source4/heimdal/lib/hdb/hdb.asn1 +++ b/source4/heimdal/lib/hdb/hdb.asn1 @@ -13,7 +13,8 @@ hdb-afs3-salt INTEGER ::= 10 Salt ::= SEQUENCE { type[0] INTEGER (0..4294967295), - salt[1] OCTET STRING + salt[1] OCTET STRING, + opaque[2] OCTET STRING OPTIONAL } Key ::= SEQUENCE { @@ -64,6 +65,10 @@ HDB-Ext-PKINIT-hash ::= SEQUENCE OF SEQUENCE { digest[1] OCTET STRING } +HDB-Ext-PKINIT-cert ::= SEQUENCE OF SEQUENCE { + cert[0] OCTET STRING +} + HDB-Ext-Constrained-delegation-acl ::= SEQUENCE OF Principal -- hdb-ext-referrals ::= PA-SERVER-REFERRAL-DATA @@ -94,6 +99,7 @@ HDB-extension ::= SEQUENCE { password[5] HDB-Ext-Password, aliases[6] HDB-Ext-Aliases, last-pw-change[7] KerberosTime, + pkinit-cert[8] HDB-Ext-PKINIT-cert, ... }, ... @@ -101,6 +107,10 @@ HDB-extension ::= SEQUENCE { HDB-extensions ::= SEQUENCE OF HDB-extension +hdb_keyset ::= SEQUENCE { + kvno[1] INTEGER (0..4294967295), + keys[0] SEQUENCE OF Key +} hdb_entry ::= SEQUENCE { principal[0] Principal OPTIONAL, -- this is optional only diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c index ad2c35a43a..e55b0bed03 100644 --- a/source4/heimdal/lib/hdb/hdb.c +++ b/source4/heimdal/lib/hdb/hdb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -31,11 +31,6 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "krb5.h" #include "krb5_locl.h" #include "hdb_locl.h" RCSID("$Id$"); @@ -44,24 +39,49 @@ RCSID("$Id$"); #include <dlfcn.h> #endif +/*! @mainpage Heimdal database backend library + * + * @section intro Introduction + * + * Heimdal libhdb library provides the backend support for Heimdal kdc + * and kadmind. Its here where plugins for diffrent database engines + * can be pluged in and extend support for here Heimdal get the + * principal and policy data from. + * + * Example of Heimdal backend are: + * - Berkeley DB 1.85 + * - Berkeley DB 3.0 + * - Berkeley DB 4.0 + * - New Berkeley DB + * - LDAP + * + * + * The project web page: http://www.h5l.org/ + * + */ + + + static struct hdb_method methods[] = { #if HAVE_DB1 || HAVE_DB3 - {HDB_INTERFACE_VERSION, "db:", hdb_db_create}, + { HDB_INTERFACE_VERSION, "db:", hdb_db_create}, #endif #if HAVE_NDBM - {HDB_INTERFACE_VERSION, "ndbm:", hdb_ndbm_create}, + { HDB_INTERFACE_VERSION, "ndbm:", hdb_ndbm_create}, #endif #if defined(OPENLDAP) && !defined(OPENLDAP_MODULE) - {HDB_INTERFACE_VERSION, "ldap:", hdb_ldap_create}, - {HDB_INTERFACE_VERSION, "ldapi:", hdb_ldapi_create}, + { HDB_INTERFACE_VERSION, "ldap:", hdb_ldap_create}, + { HDB_INTERFACE_VERSION, "ldapi:", hdb_ldapi_create}, #endif {0, NULL, NULL} }; #if HAVE_DB1 || HAVE_DB3 -static struct hdb_method dbmetod = {"", hdb_db_create }; +static struct hdb_method dbmetod = + { HDB_INTERFACE_VERSION, "", hdb_db_create }; #elif defined(HAVE_NDBM) -static struct hdb_method dbmetod = {"", hdb_ndbm_create }; +static struct hdb_method dbmetod = + { HDB_INTERFACE_VERSION, "", hdb_ndbm_create }; #endif @@ -265,9 +285,10 @@ find_dynamic_method (krb5_context context, len = p - filename; *rest = filename + len + 1; - prefix = strndup(filename, len); + prefix = malloc(len + 1); if (prefix == NULL) krb5_errx(context, 1, "out of memory"); + strlcpy(prefix, filename, len + 1); if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1) krb5_errx(context, 1, "out of memory"); @@ -390,6 +411,14 @@ hdb_list_builtin(krb5_context context, char **list) return 0; } +/** + * Create a handle for a Kerberos database + * + * Create a handle for a Kerberos database backend specified by a + * filename. Doesn't create a file if its doesn't exists, you have to + * use O_CREAT to tell the backend to create the file. + */ + krb5_error_code hdb_create(krb5_context context, HDB **db, const char *filename) { diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h index 53b1defc96..ce219153b3 100644 --- a/source4/heimdal/lib/hdb/hdb.h +++ b/source4/heimdal/lib/hdb/hdb.h @@ -66,65 +66,122 @@ typedef struct hdb_entry_ex { } hdb_entry_ex; +/** + * HDB backend function pointer structure + * + * The HDB structure is what the KDC and kadmind framework uses to + * query the backend database when talking about principals. + */ + typedef struct HDB{ void *hdb_db; - void *hdb_dbc; + void *hdb_dbc; /** don't use, only for DB3 */ char *hdb_name; int hdb_master_key_set; hdb_master_key hdb_master_key; int hdb_openp; - krb5_error_code (*hdb_open)(krb5_context, - struct HDB*, - int, - mode_t); - krb5_error_code (*hdb_close)(krb5_context, - struct HDB*); - void (*hdb_free)(krb5_context, - struct HDB*, - hdb_entry_ex*); - krb5_error_code (*hdb_fetch)(krb5_context, - struct HDB*, - krb5_const_principal, - unsigned, - hdb_entry_ex*); - krb5_error_code (*hdb_store)(krb5_context, - struct HDB*, - unsigned, + /** + * Open (or create) the a Kerberos database. + * + * Open (or create) the a Kerberos database that was resolved with + * hdb_create(). The third and fourth flag to the function are the + * same as open(), thus passing O_CREAT will create the data base + * if it doesn't exists. + * + * Then done the caller should call hdb_close(), and to release + * all resources hdb_destroy(). + */ + krb5_error_code (*hdb_open)(krb5_context, struct HDB*, int, mode_t); + /** + * Close the database for transaction + * + * Closes the database for further transactions, wont release any + * permanant resources. the database can be ->hdb_open-ed again. + */ + krb5_error_code (*hdb_close)(krb5_context, struct HDB*); + /** + * Free an entry after use. + */ + void (*hdb_free)(krb5_context, struct HDB*, hdb_entry_ex*); + /** + * Fetch an entry from the backend + * + * Fetch an entry from the backend, flags are what type of entry + * should be fetch: client, server, krbtgt. + */ + krb5_error_code (*hdb_fetch)(krb5_context, struct HDB*, + krb5_const_principal, unsigned, hdb_entry_ex*); - krb5_error_code (*hdb_remove)(krb5_context, - struct HDB*, + /** + * Store an entry to database + */ + krb5_error_code (*hdb_store)(krb5_context, struct HDB*, + unsigned, hdb_entry_ex*); + /** + * Remove an entry from the database. + */ + krb5_error_code (*hdb_remove)(krb5_context, struct HDB*, krb5_const_principal); - krb5_error_code (*hdb_firstkey)(krb5_context, - struct HDB*, - unsigned, - hdb_entry_ex*); - krb5_error_code (*hdb_nextkey)(krb5_context, - struct HDB*, - unsigned, - hdb_entry_ex*); - krb5_error_code (*hdb_lock)(krb5_context, - struct HDB*, - int operation); - krb5_error_code (*hdb_unlock)(krb5_context, - struct HDB*); - krb5_error_code (*hdb_rename)(krb5_context, - struct HDB*, - const char*); - krb5_error_code (*hdb__get)(krb5_context, - struct HDB*, - krb5_data, - krb5_data*); - krb5_error_code (*hdb__put)(krb5_context, - struct HDB*, - int, - krb5_data, - krb5_data); - krb5_error_code (*hdb__del)(krb5_context, - struct HDB*, - krb5_data); - krb5_error_code (*hdb_destroy)(krb5_context, - struct HDB*); + /** + * As part of iteration, fetch one entry + */ + krb5_error_code (*hdb_firstkey)(krb5_context, struct HDB*, + unsigned, hdb_entry_ex*); + /** + * As part of iteration, fetch next entry + */ + krb5_error_code (*hdb_nextkey)(krb5_context, struct HDB*, + unsigned, hdb_entry_ex*); + /** + * Lock database + * + * A lock can only be held by one consumers. Transaction can still + * happen on the database while the lock is held, so the entry is + * only useful for syncroning creation of the database and renaming of the database. + */ + krb5_error_code (*hdb_lock)(krb5_context, struct HDB*, int); + /** + * Unlock database + */ + krb5_error_code (*hdb_unlock)(krb5_context, struct HDB*); + /** + * Rename the data base. + */ + krb5_error_code (*hdb_rename)(krb5_context, struct HDB*, const char*); + /** + * Get an hdb_entry from a classical DB backend + * + * If the database is a classical DB (ie BDB, NDBM, GDBM, etc) + * backend, this function will take a principal key (krb5_data) + * and return all data related to principal in the return + * krb5_data. The returned encoded entry is of type hdb_entry or + * hdb_entry_alias. + */ + krb5_error_code (*hdb__get)(krb5_context, struct HDB*, + krb5_data, krb5_data*); + /** + * Store an hdb_entry from a classical DB backend + * + * Same discussion as in @ref HDB::hdb__get + */ + krb5_error_code (*hdb__put)(krb5_context, struct HDB*, int, + krb5_data, krb5_data); + /** + * Delete and hdb_entry from a classical DB backend + * + * Same discussion as in @ref HDB::hdb__get + */ + krb5_error_code (*hdb__del)(krb5_context, struct HDB*, krb5_data); + /** + * Destroy the handle to the database. + * + * Destroy the handle to the database, deallocate all memory and + * related resources. Does not remove any permanent data. Its the + * logical reverse of hdb_create() function that is the entry + * point for the module. + */ + krb5_error_code (*hdb_destroy)(krb5_context, struct HDB*); }HDB; #define HDB_INTERFACE_VERSION 4 diff --git a/source4/heimdal/lib/hdb/keys.c b/source4/heimdal/lib/hdb/keys.c index b9f294e2eb..50fe7d7fda 100644 --- a/source4/heimdal/lib/hdb/keys.c +++ b/source4/heimdal/lib/hdb/keys.c @@ -1,3 +1,4 @@ + /* * Copyright (c) 1997 - 2001, 2003 - 2004 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). @@ -172,8 +173,8 @@ parse_key_set(krb5_context context, const char *key, if(salt->salttype == KRB5_PW_SALT) ret = krb5_get_pw_salt(context, principal, salt); else if(salt->salttype == KRB5_AFS3_SALT) { - krb5_realm *realm = krb5_princ_realm(context, principal); - salt->saltvalue.data = strdup(*realm); + krb5_const_realm realm = krb5_principal_get_realm(context, principal); + salt->saltvalue.data = strdup(realm); if(salt->saltvalue.data == NULL) { krb5_set_error_message(context, ENOMEM, "out of memory while " @@ -181,7 +182,7 @@ parse_key_set(krb5_context context, const char *key, return ENOMEM; } strlwr(salt->saltvalue.data); - salt->saltvalue.length = strlen(*realm); + salt->saltvalue.length = strlen(realm); } } @@ -217,7 +218,7 @@ add_enctype_to_key_set(Key **key_set, size_t *nkeyset, key.key.keyvalue.data = NULL; if (salt) { - key.salt = malloc(sizeof(*key.salt)); + key.salt = calloc(1, sizeof(*key.salt)); if (key.salt == NULL) { free_Key(&key); return ENOMEM; @@ -259,7 +260,6 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, Key *k, *key_set; int i, j; char *default_keytypes[] = { - "des:pw-salt", "aes256-cts-hmac-sha1-96:pw-salt", "des3-cbc-sha1:pw-salt", "arcfour-hmac-md5:pw-salt", @@ -271,9 +271,6 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, if (ktypes == NULL) ktypes = default_keytypes; - if (ktypes == NULL) - abort(); - *ret_key_set = key_set = NULL; *nkeyset = 0; diff --git a/source4/heimdal/lib/hdb/keytab.c b/source4/heimdal/lib/hdb/keytab.c index a890ba62cd..97989a9764 100644 --- a/source4/heimdal/lib/hdb/keytab.c +++ b/source4/heimdal/lib/hdb/keytab.c @@ -59,7 +59,7 @@ hdb_resolve(krb5_context context, const char *name, krb5_keytab id) return ENOMEM; } db = name; - mkey = strrchr(name, ':'); + mkey = strchr(name, ':'); if(mkey == NULL || mkey[1] == '\0') { if(*name == '\0') d->dbname = NULL; @@ -147,7 +147,7 @@ find_db (krb5_context context, const krb5_config_binding *top_bind = NULL; const krb5_config_binding *default_binding = NULL; const krb5_config_binding *db; - krb5_realm *prealm = krb5_princ_realm(context, rk_UNCONST(principal)); + krb5_const_realm realm = krb5_principal_get_realm(context, principal); *dbname = *mkey = NULL; @@ -169,7 +169,7 @@ find_db (krb5_context context, krb5_warnx(context, "WARNING: using the first encountered"); } else default_binding = db; - } else if (strcmp (*prealm, p) == 0) { + } else if (strcmp (realm, p) == 0) { set_config (context, db, dbname, mkey); break; } @@ -263,6 +263,7 @@ krb5_kt_ops hdb_kt_ops = { hdb_resolve, hdb_get_name, hdb_close, + NULL, /* destroy */ hdb_get_entry, NULL, /* start_seq_get */ NULL, /* next_entry */ diff --git a/source4/heimdal/lib/hdb/mkey.c b/source4/heimdal/lib/hdb/mkey.c index ce1aa9aff1..1520c4f7e9 100644 --- a/source4/heimdal/lib/hdb/mkey.c +++ b/source4/heimdal/lib/hdb/mkey.c @@ -169,23 +169,24 @@ read_master_mit(krb5_context context, const char *filename, return errno; } krb5_storage_set_flags(sp, KRB5_STORAGE_HOST_BYTEORDER); -#if 0 /* could possibly use ret_keyblock here, but do it with more checks for now */ - ret = krb5_ret_keyblock(sp, &key); -#else - ret = krb5_ret_int16(sp, &enctype); - if((htons(enctype) & 0xff00) == 0x3000) { - ret = HEIM_ERR_BAD_MKEY; - krb5_set_error_message(context, ret, "unknown keytype in %s: %#x, expected %#x", - filename, htons(enctype), 0x3000); - goto out; + { + ret = krb5_ret_int16(sp, &enctype); + if (ret) + goto out; + if((htons(enctype) & 0xff00) == 0x3000) { + ret = HEIM_ERR_BAD_MKEY; + krb5_set_error_message(context, ret, "unknown keytype in %s: " + "%#x, expected %#x", + filename, htons(enctype), 0x3000); + goto out; + } + key.keytype = enctype; + ret = krb5_ret_data(sp, &key.keyvalue); + if(ret) + goto out; } - key.keytype = enctype; - ret = krb5_ret_data(sp, &key.keyvalue); - if(ret) - goto out; -#endif ret = hdb_process_master_key(context, 0, &key, 0, mkey); krb5_free_keyblock_contents(context, &key); out: diff --git a/source4/heimdal/lib/hdb/ndbm.c b/source4/heimdal/lib/hdb/ndbm.c index e71125c61f..1e9df81652 100644 --- a/source4/heimdal/lib/hdb/ndbm.c +++ b/source4/heimdal/lib/hdb/ndbm.c @@ -53,9 +53,7 @@ struct ndbm_db { static krb5_error_code NDBM_destroy(krb5_context context, HDB *db) { - krb5_error_code ret; - - ret = hdb_clear_master_key (context, db); + hdb_clear_master_key (context, db); free(db->hdb_name); free(db); return 0; diff --git a/source4/heimdal/lib/hx509/ca.c b/source4/heimdal/lib/hx509/ca.c index cbd58ebd01..624d74289d 100644 --- a/source4/heimdal/lib/hx509/ca.c +++ b/source4/heimdal/lib/hx509/ca.c @@ -33,7 +33,6 @@ #include "hx_locl.h" #include <pkinit_asn1.h> -RCSID("$Id$"); /** * @page page_ca Hx509 CA functions @@ -672,7 +671,7 @@ hx509_ca_tbs_add_san_pkinit(hx509_context context, ret = hx509_ca_tbs_add_san_otherName(context, tbs, - oid_id_pkinit_san(), + &asn1_oid_id_pkinit_san, &os); free(os.data); out: @@ -736,7 +735,7 @@ hx509_ca_tbs_add_san_ms_upn(hx509_context context, hx509_ca_tbs tbs, const char *principal) { - return add_utf8_san(context, tbs, oid_id_pkinit_ms_san(), principal); + return add_utf8_san(context, tbs, &asn1_oid_id_pkinit_ms_san, principal); } /** @@ -757,7 +756,7 @@ hx509_ca_tbs_add_san_jid(hx509_context context, hx509_ca_tbs tbs, const char *jid) { - return add_utf8_san(context, tbs, oid_id_pkix_on_xmppAddr(), jid); + return add_utf8_san(context, tbs, &asn1_oid_id_pkix_on_xmppAddr, jid); } @@ -926,7 +925,7 @@ build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject) return ENOMEM; } /* prefix with CN=<ts>,...*/ - ret = _hx509_name_modify(context, subject, 1, oid_id_at_commonName(), tstr); + ret = _hx509_name_modify(context, subject, 1, &asn1_oid_id_at_commonName, tstr); free(tstr); if (ret) free_Name(subject); @@ -1110,7 +1109,7 @@ ca_sign(hx509_context context, data.length = 34; ret = add_extension(context, tbsc, 0, - oid_id_ms_cert_enroll_domaincontroller(), + &asn1_oid_id_ms_cert_enroll_domaincontroller, &data); if (ret) goto out; @@ -1129,7 +1128,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 1, - oid_id_x509_ce_keyUsage(), &data); + &asn1_oid_id_x509_ce_keyUsage, &data); free(data.data); if (ret) goto out; @@ -1146,7 +1145,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_extKeyUsage(), &data); + &asn1_oid_id_x509_ce_extKeyUsage, &data); free(data.data); if (ret) goto out; @@ -1163,7 +1162,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_subjectAltName(), + &asn1_oid_id_x509_ce_subjectAltName, &data); free(data.data); if (ret) @@ -1181,7 +1180,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_authorityKeyIdentifier(), + &asn1_oid_id_x509_ce_authorityKeyIdentifier, &data); free(data.data); if (ret) @@ -1214,7 +1213,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_subjectKeyIdentifier(), + &asn1_oid_id_x509_ce_subjectKeyIdentifier, &data); free(data.data); if (ret) @@ -1247,7 +1246,7 @@ ca_sign(hx509_context context, _hx509_abort("internal ASN.1 encoder error"); /* Critical if this is a CA */ ret = add_extension(context, tbsc, tbs->flags.ca, - oid_id_x509_ce_basicConstraints(), + &asn1_oid_id_x509_ce_basicConstraints, &data); free(data.data); if (ret) @@ -1271,7 +1270,7 @@ ca_sign(hx509_context context, *info.pCPathLenConstraint = tbs->pathLenConstraint; } - ret = der_copy_oid(oid_id_pkix_ppl_inheritAll(), + ret = der_copy_oid(&asn1_oid_id_pkix_ppl_inheritAll, &info.proxyPolicy.policyLanguage); if (ret) { free_ProxyCertInfo(&info); @@ -1289,7 +1288,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_pkix_pe_proxyCertInfo(), + &asn1_oid_id_pkix_pe_proxyCertInfo, &data); free(data.data); if (ret) @@ -1307,7 +1306,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, FALSE, - oid_id_x509_ce_cRLDistributionPoints(), + &asn1_oid_id_x509_ce_cRLDistributionPoints, &data); free(data.data); if (ret) @@ -1399,8 +1398,7 @@ get_AuthorityKeyIdentifier(hx509_context context, */ ret = copy_Name(&certificate->tbsCertificate.subject, &name); - if (ai->authorityCertSerialNumber == NULL) { - ret = ENOMEM; + if (ret) { hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } diff --git a/source4/heimdal/lib/hx509/cert.c b/source4/heimdal/lib/hx509/cert.c index 121847faaa..cd9ae01fac 100644 --- a/source4/heimdal/lib/hx509/cert.c +++ b/source4/heimdal/lib/hx509/cert.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); #include "crypto-headers.h" #include <rtbl.h> @@ -59,6 +58,7 @@ struct hx509_verify_ctx_data { #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16 +#define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32 time_t time_now; unsigned int max_depth; #define HX509_VERIFY_MAX_DEPTH 30 @@ -432,6 +432,7 @@ hx509_verify_destroy_ctx(hx509_verify_ctx ctx) * Set the trust anchors in the verification context, makes an * reference to the keyset, so the consumer can free the keyset * independent of the destruction of the verification context (ctx). + * If there already is a keyset attached, it's released. * * @param ctx a verification context * @param set a keyset containing the trust anchors. @@ -442,6 +443,8 @@ hx509_verify_destroy_ctx(hx509_verify_ctx ctx) void hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set) { + if (ctx->trust_anchors) + hx509_certs_free(&ctx->trust_anchors); ctx->trust_anchors = _hx509_certs_ref(set); } @@ -569,6 +572,16 @@ hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean) ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; } +void +hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx, + int boolean) +{ + if (boolean) + ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; + else + ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; +} + static const Extension * find_extension(const Certificate *cert, const heim_oid *oid, int *idx) { @@ -594,7 +607,7 @@ find_extension_auth_key_id(const Certificate *subject, memset(ai, 0, sizeof(*ai)); - e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i); + e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i); if (e == NULL) return HX509_EXTENSION_NOT_FOUND; @@ -613,7 +626,7 @@ _hx509_find_extension_subject_key_id(const Certificate *issuer, memset(si, 0, sizeof(*si)); - e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i); + e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i); if (e == NULL) return HX509_EXTENSION_NOT_FOUND; @@ -632,7 +645,7 @@ find_extension_name_constraints(const Certificate *subject, memset(nc, 0, sizeof(*nc)); - e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i); + e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i); if (e == NULL) return HX509_EXTENSION_NOT_FOUND; @@ -650,7 +663,7 @@ find_extension_subject_alt_name(const Certificate *cert, int *i, memset(sa, 0, sizeof(*sa)); - e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i); + e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i); if (e == NULL) return HX509_EXTENSION_NOT_FOUND; @@ -668,7 +681,7 @@ find_extension_eku(const Certificate *cert, ExtKeyUsage *eku) memset(eku, 0, sizeof(*eku)); - e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i); + e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i); if (e == NULL) return HX509_EXTENSION_NOT_FOUND; @@ -748,8 +761,7 @@ hx509_cert_find_subjectAltName_otherName(hx509_context context, ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa); i++; if (ret == HX509_EXTENSION_NOT_FOUND) { - ret = 0; - break; + return 0; } else if (ret != 0) { hx509_set_error_string(context, 0, ret, "Error searching for SAN"); hx509_free_octet_string_list(list); @@ -773,7 +785,6 @@ hx509_cert_find_subjectAltName_otherName(hx509_context context, } free_GeneralNames(&sa); } - return 0; } @@ -790,7 +801,7 @@ check_key_usage(hx509_context context, const Certificate *cert, if (_hx509_cert_get_version(cert) < 3) return 0; - e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i); + e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); if (e == NULL) { if (req_present) { hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, @@ -847,7 +858,7 @@ check_basic_constraints(hx509_context context, const Certificate *cert, if (_hx509_cert_get_version(cert) < 3) return 0; - e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i); + e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i); if (e == NULL) { switch(type) { case PROXY_CERT: @@ -1134,7 +1145,7 @@ is_proxy_cert(hx509_context context, if (rinfo) memset(rinfo, 0, sizeof(*rinfo)); - e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i); + e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i); if (e == NULL) { hx509_clear_error_string(context); return HX509_EXTENSION_NOT_FOUND; @@ -1472,7 +1483,9 @@ hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *s * @param context a hx509 context. * @param p a hx509 certificate object. * @param alg AlgorithmIdentifier, should be freed with - * free_AlgorithmIdentifier(). + * free_AlgorithmIdentifier(). The algorithmidentifier is + * typicly rsaEncryption, or id-ecPublicKey, or some other + * public key mechanism. * * @return An hx509 error code, see hx509_get_error_string(). * @@ -2003,7 +2016,7 @@ hx509_verify_path(hx509_context context, free_ProxyCertInfo(&info); j = 0; - if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) { + if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) { ret = HX509_PROXY_CERT_INVALID; hx509_set_error_string(context, 0, ret, "Proxy certificate have explicity " @@ -2012,7 +2025,7 @@ hx509_verify_path(hx509_context context, } j = 0; - if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) { + if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) { ret = HX509_PROXY_CERT_INVALID; hx509_set_error_string(context, 0, ret, "Proxy certificate have explicity " @@ -2053,7 +2066,7 @@ hx509_verify_path(hx509_context context, if (proxy_issuer.u.rdnSequence.len < 2 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type, - oid_id_at_commonName())) + &asn1_oid_id_at_commonName)) { ret = HX509_PROXY_CERT_NAME_WRONG; hx509_set_error_string(context, 0, ret, @@ -2263,6 +2276,24 @@ hx509_verify_path(hx509_context context, "Failed to verify signature of certificate"); goto out; } + /* + * Verify that the sigature algorithm "best-before" date is + * before the creation date of the certificate, do this for + * trust anchors too, since any trust anchor that is created + * after a algorithm is known to be bad deserved to be invalid. + * + * Skip the leaf certificate for now... + */ + + if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) { + time_t notBefore = + _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); + ret = _hx509_signature_best_before(context, + &c->signatureAlgorithm, + notBefore); + if (ret) + goto out; + } } out: @@ -2329,6 +2360,7 @@ hx509_verify_hostname(hx509_context context, /* XXX krb5_socklen_t */ int sa_size) { GeneralNames san; + const Name *name; int ret, i, j; if (sa && sa_size <= 0) @@ -2339,11 +2371,10 @@ hx509_verify_hostname(hx509_context context, i = 0; do { ret = find_extension_subject_alt_name(cert->data, &i, &san); - if (ret == HX509_EXTENSION_NOT_FOUND) { - ret = 0; - break; - } else if (ret != 0) + if (ret == HX509_EXTENSION_NOT_FOUND) break; + else if (ret != 0) + return HX509_PARSING_NAME_FAILED; for (j = 0; j < san.len; j++) { switch (san.val[j].element) { @@ -2360,31 +2391,31 @@ hx509_verify_hostname(hx509_context context, free_GeneralNames(&san); } while (1); - { - const Name *name = &cert->data->tbsCertificate.subject; - - /* match if first component is a CN= */ - if (name->u.rdnSequence.len > 0 - && name->u.rdnSequence.val[0].len == 1 - && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type, - oid_id_at_commonName()) == 0) - { - DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value; - - switch (ds->element) { - case choice_DirectoryString_printableString: - if (strcasecmp(ds->u.printableString, hostname) == 0) - return 0; - break; - case choice_DirectoryString_ia5String: - if (strcasecmp(ds->u.ia5String, hostname) == 0) + name = &cert->data->tbsCertificate.subject; + + /* Find first CN= in the name, and try to match the hostname on that */ + for (ret = 0, i = name->u.rdnSequence.len - 1; ret == 0 && i >= 0; i--) { + for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) { + AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j]; + + if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) { + DirectoryString *ds = &n->value; + switch (ds->element) { + case choice_DirectoryString_printableString: + if (strcasecmp(ds->u.printableString, hostname) == 0) + return 0; + break; + case choice_DirectoryString_ia5String: + if (strcasecmp(ds->u.ia5String, hostname) == 0) return 0; - break; - case choice_DirectoryString_utf8String: - if (strcasecmp(ds->u.utf8String, hostname) == 0) - return 0; - default: - break; + break; + case choice_DirectoryString_utf8String: + if (strcasecmp(ds->u.utf8String, hostname) == 0) + return 0; + default: + break; + } + ret = HX509_NAME_CONSTRAINT_ERROR; } } } @@ -2495,7 +2526,7 @@ hx509_cert_get_friendly_name(hx509_cert cert) if (cert->friendlyname) return cert->friendlyname; - a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName()); + a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName); if (a == NULL) { hx509_name name; @@ -2746,7 +2777,7 @@ hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr) int hx509_query_match_cmp_func(hx509_query *q, - int (*func)(void *, hx509_cert), + int (*func)(hx509_context, hx509_cert, void *), void *ctx) { if (func) @@ -2869,7 +2900,7 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) { hx509_cert_attribute a; - a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId()); + a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId); if (a == NULL) return 0; if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0) @@ -2891,7 +2922,7 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert return 0; } if (q->match & HX509_QUERY_MATCH_FUNCTION) { - ret = (*q->cmp_func)(q->cmp_func_ctx, cert); + ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx); if (ret != 0) return 0; } @@ -3163,7 +3194,7 @@ _hx509_cert_get_keyusage(hx509_context context, if (_hx509_cert_get_version(cert) < 3) return 0; - e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i); + e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); if (e == NULL) return HX509_KU_CERT_MISSING; @@ -3348,6 +3379,46 @@ _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env) } } + { + Certificate *c = _hx509_get_cert(cert); + heim_octet_string os, sig; + hx509_env envhash = NULL; + char *buf; + + os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = + c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_create_signature(context, + NULL, + hx509_signature_sha1(), + &os, + NULL, + &sig); + if (ret != 0) + goto out; + + ret = hex_encode(sig.data, sig.length, &buf); + der_free_octet_string(&sig); + if (ret < 0) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, + "Out of memory"); + goto out; + } + + ret = hx509_env_add(context, &envhash, "sha1", buf); + free(buf); + if (ret) + goto out; + + ret = hx509_env_add_binding(context, &envcert, "hash", envhash); + if (ret) { + hx509_env_free(&envhash); + goto out; + } + } + ret = hx509_env_add_binding(context, env, "certificate", envcert); if (ret) goto out; diff --git a/source4/heimdal/lib/hx509/cms.c b/source4/heimdal/lib/hx509/cms.c index ba1800ddf2..4766c34655 100644 --- a/source4/heimdal/lib/hx509/cms.c +++ b/source4/heimdal/lib/hx509/cms.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_cms CMS/PKCS7 message functions. @@ -474,6 +473,9 @@ hx509_cms_unenvelope(hx509_context context, if (ret) goto out; + if (flags & HX509_CMS_UE_ALLOW_WEAK) + hx509_crypto_allow_weak(crypto); + if (params) { ret = hx509_crypto_set_params(context, crypto, params, &ivec); if (ret) { @@ -527,7 +529,9 @@ out: * used to RSA. * * @param context A hx509 context. - * @param flags flags to control the behavior, no flags today + * @param flags flags to control the behavior. + * - HX509_CMS_EV_NO_KU_CHECK - Dont check KU on certificate + * - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo * @param cert Certificate to encrypt the EnvelopedData encryption key * with. * @param data pointer the data to encrypt. @@ -565,16 +569,21 @@ hx509_cms_envelope_1(hx509_context context, memset(content, 0, sizeof(*content)); if (encryption_type == NULL) - encryption_type = oid_id_aes_256_cbc(); + encryption_type = &asn1_oid_id_aes_256_cbc; - ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE); - if (ret) - goto out; + if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) { + ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE); + if (ret) + goto out; + } ret = hx509_crypto_init(context, NULL, encryption_type, &crypto); if (ret) goto out; + if (flags & HX509_CMS_EV_ALLOW_WEAK) + hx509_crypto_allow_weak(crypto); + ret = hx509_crypto_set_random_key(crypto, &key); if (ret) { hx509_set_error_string(context, 0, ret, @@ -738,12 +747,16 @@ find_attribute(const CMSAttributes *attr, const heim_oid *oid) * Decode SignedData and verify that the signature is correct. * * @param context A hx509 context. - * @param ctx a hx509 version context - * @param data + * @param ctx a hx509 verify context. + * @param flags to control the behaivor of the function. + * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage + * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch + * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below. + * @param data pointer to CMS SignedData encoded data. * @param length length of the data that data point to. - * @param signedContent + * @param signedContent external data used for signature. * @param pool certificate pool to build certificates paths. - * @param contentType free with der_free_oid() + * @param contentType free with der_free_oid(). * @param content the output of the function, free with * der_free_octet_string(). * @param signer_certs list of the cerficates used to sign this @@ -755,6 +768,7 @@ find_attribute(const CMSAttributes *attr, const heim_oid *oid) int hx509_cms_verify_signed(hx509_context context, hx509_verify_ctx ctx, + unsigned int flags, const void *data, size_t length, const heim_octet_string *signedContent, @@ -797,8 +811,15 @@ hx509_cms_verify_signed(hx509_context context, "Both external and internal SignedData"); goto out; } + if (sd.encapContentInfo.eContent) - signedContent = sd.encapContentInfo.eContent; + ret = der_copy_octet_string(sd.encapContentInfo.eContent, content); + else + ret = der_copy_octet_string(signedContent, content); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc: out of memory"); + goto out; + } ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer", 0, NULL, &certs); @@ -823,7 +844,7 @@ hx509_cms_verify_signed(hx509_context context, } for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) { - heim_octet_string *signed_data; + heim_octet_string signed_data; const heim_oid *match_oid; heim_oid decode_oid; @@ -841,8 +862,22 @@ hx509_cms_verify_signed(hx509_context context, ret = find_CMSIdentifier(context, &signer_info->sid, certs, _hx509_verify_get_time(ctx), &cert, HX509_QUERY_KU_DIGITALSIGNATURE); - if (ret) - continue; + if (ret) { + /** + * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal + * search for matching certificates by not considering + * KeyUsage bits on the certificates. + */ + if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0) + continue; + + ret = find_CMSIdentifier(context, &signer_info->sid, certs, + _hx509_verify_get_time(ctx), &cert, + 0); + if (ret) + continue; + + } if (signer_info->signedAttrs) { const Attribute *attr; @@ -854,7 +889,7 @@ hx509_cms_verify_signed(hx509_context context, sa.len = signer_info->signedAttrs->len; /* verify that sigature exists */ - attr = find_attribute(&sa, oid_id_pkcs9_messageDigest()); + attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest); if (attr == NULL) { ret = HX509_CRYPTO_SIGNATURE_MISSING; hx509_set_error_string(context, 0, ret, @@ -885,7 +920,7 @@ hx509_cms_verify_signed(hx509_context context, ret = _hx509_verify_signature(context, NULL, &signer_info->digestAlgorithm, - signedContent, + content, &os); der_free_octet_string(&os); if (ret) { @@ -898,9 +933,9 @@ hx509_cms_verify_signed(hx509_context context, * Fetch content oid inside signedAttrs or set it to * id-pkcs7-data. */ - attr = find_attribute(&sa, oid_id_pkcs9_contentType()); + attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType); if (attr == NULL) { - match_oid = oid_id_pkcs7_data(); + match_oid = &asn1_oid_id_pkcs7_data; } else { if (attr->value.len != 1) { ret = HX509_CMS_DATA_OID_MISMATCH; @@ -922,36 +957,36 @@ hx509_cms_verify_signed(hx509_context context, match_oid = &decode_oid; } - ALLOC(signed_data, 1); - if (signed_data == NULL) { - if (match_oid == &decode_oid) - der_free_oid(&decode_oid); - ret = ENOMEM; - hx509_clear_error_string(context); - goto next_sigature; - } - ASN1_MALLOC_ENCODE(CMSAttributes, - signed_data->data, - signed_data->length, + signed_data.data, + signed_data.length, &sa, &size, ret); if (ret) { if (match_oid == &decode_oid) der_free_oid(&decode_oid); - free(signed_data); hx509_clear_error_string(context); goto next_sigature; } - if (size != signed_data->length) + if (size != signed_data.length) _hx509_abort("internal ASN.1 encoder error"); } else { - signed_data = rk_UNCONST(signedContent); - match_oid = oid_id_pkcs7_data(); + signed_data.data = content->data; + signed_data.length = content->length; + match_oid = &asn1_oid_id_pkcs7_data; } - if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) { + /** + * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow + * encapContentInfo mismatch with the oid in signedAttributes + * (or if no signedAttributes where use, pkcs7-data oid). + * This is only needed to work with broken CMS implementations + * that doesn't follow CMS signedAttributes rules. + */ + + if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) && + (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) { ret = HX509_CMS_DATA_OID_MISMATCH; hx509_set_error_string(context, 0, ret, "Oid in message mismatch from the expected"); @@ -963,23 +998,28 @@ hx509_cms_verify_signed(hx509_context context, ret = hx509_verify_signature(context, cert, &signer_info->signatureAlgorithm, - signed_data, + &signed_data, &signer_info->signature); if (ret) hx509_set_error_string(context, HX509_ERROR_APPEND, ret, - "Failed to verify sigature in " + "Failed to verify signature in " "CMS SignedData"); } - if (signed_data != signedContent) { - der_free_octet_string(signed_data); - free(signed_data); - } + if (signer_info->signedAttrs) + free(signed_data.data); if (ret) goto next_sigature; - ret = hx509_verify_path(context, ctx, cert, certs); - if (ret) - goto next_sigature; + /** + * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the + * signing certificates and leave that up to the caller. + */ + + if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) { + ret = hx509_verify_path(context, ctx, cert, certs); + if (ret) + goto next_sigature; + } ret = hx509_certs_add(context, *signer_certs, cert); if (ret) @@ -992,7 +1032,18 @@ hx509_cms_verify_signed(hx509_context context, hx509_cert_free(cert); cert = NULL; } - if (found_valid_sig == 0) { + /** + * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty + * SignerInfo (no signatures). If SignedData have no signatures, + * the function will return 0 with signer_certs set to NULL. Zero + * signers is allowed by the standard, but since its only useful + * in corner cases, it make into a flag that the caller have to + * turn on. + */ + if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) { + if (*signer_certs) + hx509_certs_free(signer_certs); + } else if (found_valid_sig == 0) { if (ret == 0) { ret = HX509_CMS_SIGNER_NOT_FOUND; hx509_set_error_string(context, 0, ret, @@ -1007,20 +1058,13 @@ hx509_cms_verify_signed(hx509_context context, goto out; } - content->data = malloc(signedContent->length); - if (content->data == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - content->length = signedContent->length; - memcpy(content->data, signedContent->data, content->length); - out: free_SignedData(&sd); if (certs) hx509_certs_free(&certs); if (ret) { + if (content->data) + der_free_octet_string(content); if (*signer_certs) hx509_certs_free(signer_certs); der_free_oid(contentType); @@ -1097,26 +1141,55 @@ hx509_cms_create_signed_1(hx509_context context, hx509_certs pool, heim_octet_string *signed_data) { - AlgorithmIdentifier digest; - hx509_name name; - SignerInfo *signer_info; - heim_octet_string buf, content, sigdata = { 0, NULL }; + hx509_certs certs; + int ret = 0; + + signed_data->data = NULL; + signed_data->length = 0; + + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs); + if (ret) + return ret; + ret = hx509_certs_add(context, certs, cert); + if (ret) + goto out; + + ret = hx509_cms_create_signed(context, flags, eContentType, data, length, + digest_alg, certs, peer, anchors, pool, + signed_data); + + out: + hx509_certs_free(&certs); + return ret; +} + +struct sigctx { SignedData sd; - int ret; + const AlgorithmIdentifier *digest_alg; + const heim_oid *eContentType; + heim_octet_string content; + hx509_peer_info peer; + int cmsidflag; + hx509_certs certs; + hx509_certs anchors; + hx509_certs pool; +}; + +static int +sig_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + heim_octet_string buf, sigdata = { 0, NULL }; + SignerInfo *signer_info = NULL; + AlgorithmIdentifier digest; size_t size; + void *ptr; + int ret; + SignedData *sd = &sigctx->sd; hx509_path path; - int cmsidflag = CMS_ID_SKI; - memset(&sd, 0, sizeof(sd)); - memset(&name, 0, sizeof(name)); - memset(&path, 0, sizeof(path)); memset(&digest, 0, sizeof(digest)); - - content.data = rk_UNCONST(data); - content.length = length; - - if (flags & HX509_CMS_SIGATURE_ID_NAME) - cmsidflag = CMS_ID_NAME; + memset(&path, 0, sizeof(path)); if (_hx509_cert_private_key(cert) == NULL) { hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, @@ -1124,55 +1197,37 @@ hx509_cms_create_signed_1(hx509_context context, return HX509_PRIVATE_KEY_MISSING; } - if (digest_alg == NULL) { - ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, - _hx509_cert_private_key(cert), peer, &digest); - } else { - ret = copy_AlgorithmIdentifier(digest_alg, &digest); + if (sigctx->digest_alg) { + ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest); if (ret) hx509_clear_error_string(context); + } else { + ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, + _hx509_cert_private_key(cert), + sigctx->peer, &digest); } if (ret) goto out; - sd.version = CMSVersion_v3; - - if (eContentType == NULL) - eContentType = oid_id_pkcs7_data(); - - der_copy_oid(eContentType, &sd.encapContentInfo.eContentType); - - /* */ - if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) { - ALLOC(sd.encapContentInfo.eContent, 1); - if (sd.encapContentInfo.eContent == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - - sd.encapContentInfo.eContent->data = malloc(length); - if (sd.encapContentInfo.eContent->data == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - memcpy(sd.encapContentInfo.eContent->data, data, length); - sd.encapContentInfo.eContent->length = length; - } + /* + * Allocate on more signerInfo and do the signature processing + */ - ALLOC_SEQ(&sd.signerInfos, 1); - if (sd.signerInfos.val == NULL) { - hx509_clear_error_string(context); + ptr = realloc(sd->signerInfos.val, + (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0])); + if (ptr == NULL) { ret = ENOMEM; goto out; } + sd->signerInfos.val = ptr; - signer_info = &sd.signerInfos.val[0]; + signer_info = &sd->signerInfos.val[sd->signerInfos.len]; + + memset(signer_info, 0, sizeof(*signer_info)); signer_info->version = 1; - ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid); + ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid); if (ret) { hx509_clear_error_string(context); goto out; @@ -1181,7 +1236,6 @@ hx509_cms_create_signed_1(hx509_context context, signer_info->signedAttrs = NULL; signer_info->unsignedAttrs = NULL; - ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); if (ret) { hx509_clear_error_string(context); @@ -1192,7 +1246,7 @@ hx509_cms_create_signed_1(hx509_context context, * If it isn't pkcs7-data send signedAttributes */ - if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { + if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) { CMSAttributes sa; heim_octet_string sig; @@ -1205,7 +1259,7 @@ hx509_cms_create_signed_1(hx509_context context, ret = _hx509_create_signature(context, NULL, &digest, - &content, + &sigctx->content, NULL, &sig); if (ret) @@ -1227,9 +1281,10 @@ hx509_cms_create_signed_1(hx509_context context, ret = add_one_attribute(&signer_info->signedAttrs->val, &signer_info->signedAttrs->len, - oid_id_pkcs9_messageDigest(), + &asn1_oid_id_pkcs9_messageDigest, &buf); if (ret) { + free(buf.data); hx509_clear_error_string(context); goto out; } @@ -1238,7 +1293,7 @@ hx509_cms_create_signed_1(hx509_context context, ASN1_MALLOC_ENCODE(ContentType, buf.data, buf.length, - eContentType, + sigctx->eContentType, &size, ret); if (ret) @@ -1248,9 +1303,10 @@ hx509_cms_create_signed_1(hx509_context context, ret = add_one_attribute(&signer_info->signedAttrs->val, &signer_info->signedAttrs->len, - oid_id_pkcs9_contentType(), + &asn1_oid_id_pkcs9_contentType, &buf); if (ret) { + free(buf.data); hx509_clear_error_string(context); goto out; } @@ -1271,16 +1327,15 @@ hx509_cms_create_signed_1(hx509_context context, if (size != sigdata.length) _hx509_abort("internal ASN.1 encoder error"); } else { - sigdata.data = content.data; - sigdata.length = content.length; + sigdata.data = sigctx->content.data; + sigdata.length = sigctx->content.length; } - { AlgorithmIdentifier sigalg; ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, - _hx509_cert_private_key(cert), peer, + _hx509_cert_private_key(cert), sigctx->peer, &sigalg); if (ret) goto out; @@ -1296,54 +1351,165 @@ hx509_cms_create_signed_1(hx509_context context, goto out; } - ALLOC_SEQ(&sd.digestAlgorithms, 1); - if (sd.digestAlgorithms.val == NULL) { - ret = ENOMEM; - hx509_clear_error_string(context); - goto out; - } - - ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]); - if (ret) { - hx509_clear_error_string(context); - goto out; - } + sigctx->sd.signerInfos.len++; + signer_info = NULL; /* * Provide best effort path */ - if (pool) { - _hx509_calculate_path(context, - HX509_CALCULATE_PATH_NO_ANCHOR, - time(NULL), - anchors, - 0, - cert, - pool, - &path); - } else - _hx509_path_append(context, &path, cert); + if (sigctx->certs) { + unsigned int i; + + if (sigctx->pool) { + _hx509_calculate_path(context, + HX509_CALCULATE_PATH_NO_ANCHOR, + time(NULL), + sigctx->anchors, + 0, + cert, + sigctx->pool, + &path); + } else + _hx509_path_append(context, &path, cert); + + for (i = 0; i < path.len; i++) { + /* XXX remove dups */ + ret = hx509_certs_add(context, sigctx->certs, path.val[i]); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + } + + out: + if (signer_info) + free_SignerInfo(signer_info); + if (sigdata.data != sigctx->content.data) + der_free_octet_string(&sigdata); + _hx509_path_free(&path); + free_AlgorithmIdentifier(&digest); + + return ret; +} + +static int +cert_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + const unsigned int i = sigctx->sd.certificates->len; + void *ptr; + int ret; + + ptr = realloc(sigctx->sd.certificates->val, + (i + 1) * sizeof(sigctx->sd.certificates->val[0])); + if (ptr == NULL) + return ENOMEM; + sigctx->sd.certificates->val = ptr; + + ret = hx509_cert_binary(context, cert, + &sigctx->sd.certificates->val[i]); + if (ret == 0) + sigctx->sd.certificates->len++; + + return ret; +} + +int +hx509_cms_create_signed(hx509_context context, + int flags, + const heim_oid *eContentType, + const void *data, size_t length, + const AlgorithmIdentifier *digest_alg, + hx509_certs certs, + hx509_peer_info peer, + hx509_certs anchors, + hx509_certs pool, + heim_octet_string *signed_data) +{ + unsigned int i; + hx509_name name; + int ret; + size_t size; + struct sigctx sigctx; + + memset(&sigctx, 0, sizeof(sigctx)); + memset(&name, 0, sizeof(name)); + + if (eContentType == NULL) + eContentType = &asn1_oid_id_pkcs7_data; + + sigctx.digest_alg = digest_alg; + sigctx.content.data = rk_UNCONST(data); + sigctx.content.length = length; + sigctx.eContentType = eContentType; + sigctx.peer = peer; + /** + * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name + * and serial number if possible. Otherwise subject key identifier + * will preferred. + */ + if (flags & HX509_CMS_SIGNATURE_ID_NAME) + sigctx.cmsidflag = CMS_ID_NAME; + else + sigctx.cmsidflag = CMS_ID_SKI; + + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs); + if (ret) + return ret; + + sigctx.anchors = anchors; + sigctx.pool = pool; + sigctx.sd.version = CMSVersion_v3; - if (path.len) { - int i; + der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); - ALLOC(sd.certificates, 1); - if (sd.certificates == NULL) { + /** + * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures. + */ + if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) { + ALLOC(sigctx.sd.encapContentInfo.eContent, 1); + if (sigctx.sd.encapContentInfo.eContent == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } - ALLOC_SEQ(sd.certificates, path.len); - if (sd.certificates->val == NULL) { + + sigctx.sd.encapContentInfo.eContent->data = malloc(length); + if (sigctx.sd.encapContentInfo.eContent->data == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } + memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length); + sigctx.sd.encapContentInfo.eContent->length = length; + } - for (i = 0; i < path.len; i++) { - ret = hx509_cert_binary(context, path.val[i], - &sd.certificates->val[i]); + /** + * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no + * signatures). + */ + if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) { + ret = hx509_certs_iter(context, certs, sig_process, &sigctx); + if (ret) + goto out; + } + + if (sigctx.sd.signerInfos.len) { + ALLOC_SEQ(&sigctx.sd.digestAlgorithms, sigctx.sd.signerInfos.len); + if (sigctx.sd.digestAlgorithms.val == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + /* XXX remove dups */ + for (i = 0; i < sigctx.sd.signerInfos.len; i++) { + AlgorithmIdentifier *di = + &sigctx.sd.signerInfos.val[i].digestAlgorithm; + ret = copy_AlgorithmIdentifier(di, + &sigctx.sd.digestAlgorithms.val[i]); if (ret) { hx509_clear_error_string(context); goto out; @@ -1351,9 +1517,22 @@ hx509_cms_create_signed_1(hx509_context context, } } + if (sigctx.certs) { + ALLOC(sigctx.sd.certificates, 1); + if (sigctx.sd.certificates == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + ret = hx509_certs_iter(context, sigctx.certs, cert_process, &sigctx); + if (ret) + goto out; + } + ASN1_MALLOC_ENCODE(SignedData, signed_data->data, signed_data->length, - &sd, &size, ret); + &sigctx.sd, &size, ret); if (ret) { hx509_clear_error_string(context); goto out; @@ -1362,11 +1541,8 @@ hx509_cms_create_signed_1(hx509_context context, _hx509_abort("internal ASN.1 encoder error"); out: - if (sigdata.data != content.data) - der_free_octet_string(&sigdata); - free_AlgorithmIdentifier(&digest); - _hx509_path_free(&path); - free_SignedData(&sd); + hx509_certs_free(&sigctx.certs); + free_SignedData(&sigctx.sd); return ret; } diff --git a/source4/heimdal/lib/hx509/collector.c b/source4/heimdal/lib/hx509/collector.c index b59052bb4e..ab36fe2dc8 100644 --- a/source4/heimdal/lib/hx509/collector.c +++ b/source4/heimdal/lib/hx509/collector.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct private_key { AlgorithmIdentifier alg; @@ -144,7 +143,7 @@ _hx509_collector_private_key_add(hx509_context context, if (private_key) { key->private_key = private_key; } else { - ret = _hx509_parse_private_key(context, &alg->algorithm, + ret = _hx509_parse_private_key(context, alg, key_data->data, key_data->length, &key->private_key); if (ret) @@ -306,7 +305,7 @@ _hx509_collector_collect_private_keys(hx509_context context, c->val.data[i]->private_key = NULL; } } - (*keys)[nkeys++] = NULL; + (*keys)[nkeys] = NULL; return 0; } diff --git a/source4/heimdal/lib/hx509/crypto.c b/source4/heimdal/lib/hx509/crypto.c index 4a8ec8f756..8063100717 100644 --- a/source4/heimdal/lib/hx509/crypto.c +++ b/source4/heimdal/lib/hx509/crypto.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct hx509_crypto; @@ -50,40 +49,21 @@ struct hx509_generate_private_context { struct hx509_private_key_ops { const char *pemtype; - const heim_oid *(*key_oid)(void); + const heim_oid *key_oid; + int (*available)(const hx509_private_key, + const AlgorithmIdentifier *); int (*get_spki)(hx509_context, const hx509_private_key, SubjectPublicKeyInfo *); int (*export)(hx509_context context, const hx509_private_key, heim_octet_string *); - int (*import)(hx509_context, - const void *data, - size_t len, - hx509_private_key private_key); + int (*import)(hx509_context, const AlgorithmIdentifier *, + const void *, size_t, hx509_private_key); int (*generate_private_key)(hx509_context, struct hx509_generate_private_context *, hx509_private_key); BIGNUM *(*get_internal)(hx509_context, hx509_private_key, const char *); - int (*handle_alg)(const hx509_private_key, - const AlgorithmIdentifier *, - enum crypto_op_type); - int (*sign)(hx509_context context, - const hx509_private_key, - const AlgorithmIdentifier *, - const heim_octet_string *, - AlgorithmIdentifier *, - heim_octet_string *); -#if 0 - const AlgorithmIdentifier *(*preferred_sig_alg) - (const hx509_private_key, - const hx509_peer_info); - int (*unwrap)(hx509_context context, - const hx509_private_key, - const AlgorithmIdentifier *, - const heim_octet_string *, - heim_octet_string *); -#endif }; struct hx509_private_key { @@ -93,8 +73,10 @@ struct hx509_private_key { union { RSA *rsa; void *keydata; +#ifdef HAVE_OPENSSL + EC_KEY *ecdsa; +#endif } private_key; - /* new crypto layer */ hx509_private_key_ops *ops; }; @@ -104,10 +86,10 @@ struct hx509_private_key { struct signature_alg { const char *name; - const heim_oid *(*sig_oid)(void); - const AlgorithmIdentifier *(*sig_alg)(void); - const heim_oid *(*key_oid)(void); - const heim_oid *(*digest_oid)(void); + const heim_oid *sig_oid; + const AlgorithmIdentifier *sig_alg; + const heim_oid *key_oid; + const AlgorithmIdentifier *digest_alg; int flags; #define PROVIDE_CONF 1 #define REQUIRE_SIGNER 2 @@ -118,7 +100,7 @@ struct signature_alg { #define RA_RSA_USES_DIGEST_INFO 0x1000000 - + time_t best_before; /* refuse signature made after best before date */ int (*verify_signature)(hx509_context context, const struct signature_alg *, const Certificate *, @@ -132,6 +114,116 @@ struct signature_alg { const heim_octet_string *, AlgorithmIdentifier *, heim_octet_string *); + int digest_size; +}; + +static const struct signature_alg * +find_sig_alg(const heim_oid *oid); + +/* + * + */ + +static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") }; + +static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 }; +const AlgorithmIdentifier _hx509_signature_sha512_data = { + { 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 }; +const AlgorithmIdentifier _hx509_signature_sha384_data = { + { 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_sha256_data = { + { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; +const AlgorithmIdentifier _hx509_signature_sha1_data = { + { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; +const AlgorithmIdentifier _hx509_signature_md5_data = { + { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 }; +const AlgorithmIdentifier _hx509_signature_md2_data = { + { 6, rk_UNCONST(md2_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_ecPublicKey = { + { 6, rk_UNCONST(ecPublicKey) }, NULL +}; + +static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = { + { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL +}; + +static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = { + { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL +}; + +static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = { + { 7, rk_UNCONST(rsa_with_sha512_oid) }, NULL +}; + +static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = { + { 7, rk_UNCONST(rsa_with_sha384_oid) }, NULL +}; + +static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = { + { 7, rk_UNCONST(rsa_with_sha256_oid) }, NULL +}; + +static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = { + { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL +}; + +static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = { + { 7, rk_UNCONST(rsa_with_md5_oid) }, NULL +}; + +static const unsigned rsa_with_md2_oid[] ={ 1, 2, 840, 113549, 1, 1, 2 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_md2_data = { + { 7, rk_UNCONST(rsa_with_md2_oid) }, NULL +}; + +static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 }; +const AlgorithmIdentifier _hx509_signature_rsa_data = { + { 7, rk_UNCONST(rsa_oid) }, NULL +}; + +static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 }; +const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = { + { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL +}; + +static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 }; +const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = { + { 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL +}; + +static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 }; +const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = { + { 9, rk_UNCONST(aes128_cbc_oid) }, NULL +}; + +static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 }; +const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = { + { 9, rk_UNCONST(aes256_cbc_oid) }, NULL }; /* @@ -184,6 +276,265 @@ set_digest_alg(DigestAlgorithmIdentifier *id, return 0; } +#ifdef HAVE_OPENSSL + +static int +heim_oid2ecnid(heim_oid *oid) +{ + /* + * Now map to openssl OID fun + */ + + if (der_heim_oid_cmp(oid, &asn1_oid_id_ec_group_secp256r1) == 0) + return NID_X9_62_prime256v1; + else if (der_heim_oid_cmp(oid, &asn1_oid_id_ec_group_secp160r1) == 0) + return NID_secp160r1; + else if (der_heim_oid_cmp(oid, &asn1_oid_id_ec_group_secp160r2) == 0) + return NID_secp160r2; + + return -1; +} + +static int +parse_ECParameters(hx509_context context, + heim_octet_string *parameters, int *nid) +{ + ECParameters ecparam; + size_t size; + int ret; + + if (parameters == NULL) { + ret = HX509_PARSING_KEY_FAILED; + hx509_set_error_string(context, 0, ret, + "EC parameters missing"); + return ret; + } + + ret = decode_ECParameters(parameters->data, parameters->length, + &ecparam, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode EC parameters"); + return ret; + } + + if (ecparam.element != choice_ECParameters_namedCurve) { + free_ECParameters(&ecparam); + hx509_set_error_string(context, 0, ret, + "EC parameters is not a named curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + *nid = heim_oid2ecnid(&ecparam.u.namedCurve); + free_ECParameters(&ecparam); + if (*nid == -1) { + hx509_set_error_string(context, 0, ret, + "Failed to find matcing NID for EC curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + return 0; +} + + +/* + * + */ + +static int +ecdsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + const SubjectPublicKeyInfo *spi; + heim_octet_string digest; + int ret; + EC_KEY *key = NULL; + int groupnid; + EC_GROUP *group; + const unsigned char *p; + long len; + + digest_alg = sig_alg->digest_alg; + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &digest); + if (ret) + return ret; + + /* set up EC KEY */ + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + if (der_heim_oid_cmp(&spi->algorithm.algorithm, &asn1_oid_id_ecPublicKey) != 0) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + +#ifdef HAVE_OPENSSL + /* + * Find the group id + */ + + ret = parse_ECParameters(context, spi->algorithm.parameters, &groupnid); + if (ret) { + der_free_octet_string(&digest); + return ret; + } + + /* + * Create group, key, parse key + */ + + key = EC_KEY_new(); + group = EC_GROUP_new_by_curve_name(groupnid); + EC_KEY_set_group(key, group); + EC_GROUP_free(group); + + p = spi->subjectPublicKey.data; + len = spi->subjectPublicKey.length / 8; + + if (o2i_ECPublicKey(&key, &p, len) == NULL) { + EC_KEY_free(key); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } +#else + key = SubjectPublicKeyInfo2EC_KEY(spi); +#endif + + ret = ECDSA_verify(-1, digest.data, digest.length, + sig->data, sig->length, key); + der_free_octet_string(&digest); + EC_KEY_free(key); + if (ret != 1) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + return ret; + } + + return 0; +} + +static int +ecdsa_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + heim_octet_string indata; + const heim_oid *sig_oid; + unsigned int siglen; + int ret; + + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig_oid = sig_alg->sig_oid; + digest_alg = sig_alg->digest_alg; + + if (signatureAlgorithm) { + ret = set_digest_alg(signatureAlgorithm, sig_oid, "\x05\x00", 2); + if (ret) { + hx509_clear_error_string(context); + goto error; + } + } + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &indata); + if (ret) { + if (signatureAlgorithm) + free_AlgorithmIdentifier(signatureAlgorithm); + goto error; + } + + sig->length = ECDSA_size(signer->private_key.ecdsa); + sig->data = malloc(sig->length); + if (sig->data == NULL) { + der_free_octet_string(&indata); + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto error; + } + + siglen = sig->length; + + ret = ECDSA_sign(-1, indata.data, indata.length, + sig->data, &siglen, signer->private_key.ecdsa); + der_free_octet_string(&indata); + if (ret != 1) { + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + hx509_set_error_string(context, 0, ret, + "ECDSA sign failed: %d", ret); + goto error; + } + if (siglen > sig->length) + _hx509_abort("ECDSA signature prelen longer the output len"); + + sig->length = siglen; + + return 0; + error: + if (signatureAlgorithm) + free_AlgorithmIdentifier(signatureAlgorithm); + return ret; +} + +static int +ecdsa_available(const hx509_private_key signer, + const AlgorithmIdentifier *sig_alg) +{ + const struct signature_alg *sig; + const EC_GROUP *group; + BN_CTX *bnctx = NULL; + BIGNUM *order = NULL; + int ret = 0; + + if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig = find_sig_alg(&sig_alg->algorithm); + + if (sig == NULL || sig->digest_size == 0) + return 0; + + group = EC_KEY_get0_group(signer->private_key.ecdsa); + if (group == NULL) + return 0; + + bnctx = BN_CTX_new(); + order = BN_new(); + if (order == NULL) + goto err; + + if (EC_GROUP_get_order(group, order, bnctx) != 1) + goto err; + + if (BN_num_bytes(order) > sig->digest_size) + ret = 1; + err: + if (bnctx) + BN_CTX_free(bnctx); + if (order) + BN_clear_free(order); + + return ret; +} + + +#endif /* HAVE_OPENSSL */ + /* * */ @@ -268,9 +619,9 @@ rsa_verify_signature(hx509_context context, goto out; } - if (sig_alg->digest_oid && + if (sig_alg->digest_alg && der_heim_oid_cmp(&di.digestAlgorithm.algorithm, - (*sig_alg->digest_oid)()) != 0) + &sig_alg->digest_alg->algorithm) != 0) { ret = HX509_CRYPTO_OID_MISMATCH; hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch"); @@ -324,24 +675,27 @@ rsa_create_signature(hx509_context context, size_t size; int ret; + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) != 0) + return HX509_ALG_NOT_SUPP; + if (alg) sig_oid = &alg->algorithm; else sig_oid = signer->signature_alg; - if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha256WithRSAEncryption()) == 0) { + if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_sha256WithRSAEncryption) == 0) { digest_alg = hx509_signature_sha256(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha1WithRSAEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_sha1WithRSAEncryption) == 0) { digest_alg = hx509_signature_sha1(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_md5WithRSAEncryption) == 0) { digest_alg = hx509_signature_md5(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_md5WithRSAEncryption) == 0) { digest_alg = hx509_signature_md5(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_dsa_with_sha1()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_dsa_with_sha1) == 0) { digest_alg = hx509_signature_sha1(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_rsaEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) { digest_alg = hx509_signature_sha1(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_heim_rsa_pkcs1_x509()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_heim_rsa_pkcs1_x509) == 0) { digest_alg = NULL; } else return HX509_ALG_NOT_SUPP; @@ -413,6 +767,7 @@ rsa_create_signature(hx509_context context, static int rsa_private_key_import(hx509_context context, + const AlgorithmIdentifier *keyai, const void *data, size_t len, hx509_private_key private_key) @@ -426,7 +781,7 @@ rsa_private_key_import(hx509_context context, "Failed to parse RSA key"); return HX509_PARSING_KEY_FAILED; } - private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + private_key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption; return 0; } @@ -449,7 +804,7 @@ rsa_private_key2SPKI(hx509_context context, } spki->subjectPublicKey.length = len * 8; - ret = set_digest_alg(&spki->algorithm,oid_id_pkcs1_rsaEncryption(), + ret = set_digest_alg(&spki->algorithm, &asn1_oid_id_pkcs1_rsaEncryption, "\x05\x00", 2); if (ret) { hx509_set_error_string(context, 0, ret, "malloc - out of memory"); @@ -503,7 +858,7 @@ rsa_generate_private_key(hx509_context context, "Failed to generate RSA key"); return HX509_PARSING_KEY_FAILED; } - private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + private_key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption; return 0; } @@ -543,7 +898,9 @@ rsa_private_key_export(hx509_context context, } static BIGNUM * -rsa_get_internal(hx509_context context, hx509_private_key key, const char *type) +rsa_get_internal(hx509_context context, + hx509_private_key key, + const char *type) { if (strcasecmp(type, "rsa-modulus") == 0) { return BN_dup(key->private_key.rsa->n); @@ -557,7 +914,8 @@ rsa_get_internal(hx509_context context, hx509_private_key key, const char *type) static hx509_private_key_ops rsa_private_key_ops = { "RSA PRIVATE KEY", - oid_id_pkcs1_rsaEncryption, + &asn1_oid_id_pkcs1_rsaEncryption, + NULL, rsa_private_key2SPKI, rsa_private_key_export, rsa_private_key_import, @@ -565,6 +923,104 @@ static hx509_private_key_ops rsa_private_key_ops = { rsa_get_internal }; +#ifdef HAVE_OPENSSL + +static int +ecdsa_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + memset(spki, 0, sizeof(*spki)); + return ENOMEM; +} + +static int +ecdsa_private_key_export(hx509_context context, + const hx509_private_key key, + heim_octet_string *data) +{ + return ENOMEM; +} + +static int +ecdsa_private_key_import(hx509_context context, + const AlgorithmIdentifier *keyai, + const void *data, + size_t len, + hx509_private_key private_key) +{ + const unsigned char *p = data; + EC_KEY **pkey = NULL; + + if (keyai->parameters) { + EC_GROUP *group; + int groupnid; + EC_KEY *key; + int ret; + + ret = parse_ECParameters(context, keyai->parameters, &groupnid); + if (ret) + return ret; + + key = EC_KEY_new(); + if (key == NULL) + return ENOMEM; + + group = EC_GROUP_new_by_curve_name(groupnid); + if (group == NULL) { + EC_KEY_free(key); + return ENOMEM; + } + EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_set_group(key, group) == 0) { + EC_KEY_free(key); + EC_GROUP_free(group); + return ENOMEM; + } + EC_GROUP_free(group); + pkey = &key; + } + + private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); + if (private_key->private_key.ecdsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse EC private key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = &asn1_oid_id_ecdsa_with_SHA256; + + return 0; +} + +static int +ecdsa_generate_private_key(hx509_context context, + struct hx509_generate_private_context *ctx, + hx509_private_key private_key) +{ + return ENOMEM; +} + +static BIGNUM * +ecdsa_get_internal(hx509_context context, + hx509_private_key key, + const char *type) +{ + return NULL; +} + + +static hx509_private_key_ops ecdsa_private_key_ops = { + "EC PRIVATE KEY", + &asn1_oid_id_ecPublicKey, + ecdsa_available, + ecdsa_private_key2SPKI, + ecdsa_private_key_export, + ecdsa_private_key_import, + ecdsa_generate_private_key, + ecdsa_get_internal +}; + +#endif /* HAVE_OPENSSL */ /* * @@ -668,7 +1124,7 @@ dsa_parse_private_key(hx509_context context, d2i_DSAPrivateKey(NULL, &p, len); if (private_key->private_key.dsa == NULL) return EINVAL; - private_key->signature_alg = oid_id_dsa_with_sha1(); + private_key->signature_alg = &asn1_oid_id_dsa_with_sha1; return 0; /* else */ @@ -724,7 +1180,7 @@ sha256_create_signature(hx509_context context, if (signatureAlgorithm) { int ret; - ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(), + ret = set_digest_alg(signatureAlgorithm, sig_alg->sig_oid, "\x05\x00", 2); if (ret) return ret; @@ -790,7 +1246,7 @@ sha1_create_signature(hx509_context context, if (signatureAlgorithm) { int ret; - ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(), + ret = set_digest_alg(signatureAlgorithm, sig_alg->sig_oid, "\x05\x00", 2); if (ret) return ret; @@ -871,131 +1327,176 @@ md2_verify_signature(hx509_context context, return 0; } +#ifdef HAVE_OPENSSL + +static const struct signature_alg ecdsa_with_sha256_alg = { + "ecdsa-with-sha256", + &asn1_oid_id_ecdsa_with_SHA256, + &_hx509_signature_ecdsa_with_sha256_data, + &asn1_oid_id_ecPublicKey, + &_hx509_signature_sha256_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, + ecdsa_verify_signature, + ecdsa_create_signature, + 32 +}; + +static const struct signature_alg ecdsa_with_sha1_alg = { + "ecdsa-with-sha1", + &asn1_oid_id_ecdsa_with_SHA1, + &_hx509_signature_ecdsa_with_sha1_data, + &asn1_oid_id_ecPublicKey, + &_hx509_signature_sha1_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, + ecdsa_verify_signature, + ecdsa_create_signature, + 20 +}; + +#endif + static const struct signature_alg heim_rsa_pkcs1_x509 = { "rsa-pkcs1-x509", - oid_id_heim_rsa_pkcs1_x509, - hx509_signature_rsa_pkcs1_x509, - oid_id_pkcs1_rsaEncryption, + &asn1_oid_id_heim_rsa_pkcs1_x509, + &_hx509_signature_rsa_pkcs1_x509_data, + &asn1_oid_id_pkcs1_rsaEncryption, NULL, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg pkcs1_rsa_sha1_alg = { "rsa", - oid_id_pkcs1_rsaEncryption, - hx509_signature_rsa_with_sha1, - oid_id_pkcs1_rsaEncryption, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_rsa_with_sha1_data, + &asn1_oid_id_pkcs1_rsaEncryption, NULL, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_sha256_alg = { "rsa-with-sha256", - oid_id_pkcs1_sha256WithRSAEncryption, - hx509_signature_rsa_with_sha256, - oid_id_pkcs1_rsaEncryption, - oid_id_sha256, + &asn1_oid_id_pkcs1_sha256WithRSAEncryption, + &_hx509_signature_rsa_with_sha256_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_sha256_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_sha1_alg = { "rsa-with-sha1", - oid_id_pkcs1_sha1WithRSAEncryption, - hx509_signature_rsa_with_sha1, - oid_id_pkcs1_rsaEncryption, - oid_id_secsig_sha_1, + &asn1_oid_id_pkcs1_sha1WithRSAEncryption, + &_hx509_signature_rsa_with_sha1_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_sha1_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_md5_alg = { "rsa-with-md5", - oid_id_pkcs1_md5WithRSAEncryption, - hx509_signature_rsa_with_md5, - oid_id_pkcs1_rsaEncryption, - oid_id_rsa_digest_md5, + &asn1_oid_id_pkcs1_md5WithRSAEncryption, + &_hx509_signature_rsa_with_md5_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_md5_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 1230739889, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_md2_alg = { "rsa-with-md2", - oid_id_pkcs1_md2WithRSAEncryption, - hx509_signature_rsa_with_md2, - oid_id_pkcs1_rsaEncryption, - oid_id_rsa_digest_md2, + &asn1_oid_id_pkcs1_md2WithRSAEncryption, + &_hx509_signature_rsa_with_md2_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_md2_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 1230739889, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg dsa_sha1_alg = { "dsa-with-sha1", - oid_id_dsa_with_sha1, + &asn1_oid_id_dsa_with_sha1, NULL, - oid_id_dsa, - oid_id_secsig_sha_1, + &asn1_oid_id_dsa, + &_hx509_signature_sha1_data, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + 0, dsa_verify_signature, /* create_signature */ NULL, }; static const struct signature_alg sha256_alg = { "sha-256", - oid_id_sha256, - hx509_signature_sha256, + &asn1_oid_id_sha256, + &_hx509_signature_sha256_data, NULL, NULL, SIG_DIGEST, + 0, sha256_verify_signature, sha256_create_signature }; static const struct signature_alg sha1_alg = { "sha1", - oid_id_secsig_sha_1, - hx509_signature_sha1, + &asn1_oid_id_secsig_sha_1, + &_hx509_signature_sha1_data, NULL, NULL, SIG_DIGEST, + 0, sha1_verify_signature, sha1_create_signature }; static const struct signature_alg md5_alg = { "rsa-md5", - oid_id_rsa_digest_md5, - hx509_signature_md5, + &asn1_oid_id_rsa_digest_md5, + &_hx509_signature_md5_data, NULL, NULL, SIG_DIGEST, + 0, md5_verify_signature }; static const struct signature_alg md2_alg = { "rsa-md2", - oid_id_rsa_digest_md2, - hx509_signature_md2, + &asn1_oid_id_rsa_digest_md2, + &_hx509_signature_md2_data, NULL, NULL, SIG_DIGEST, + 0, md2_verify_signature }; /* * Order matter in this structure, "best" first for each "key - * compatible" type (type is RSA, DSA, none, etc) + * compatible" type (type is ECDSA, RSA, DSA, none, etc) */ static const struct signature_alg *sig_algs[] = { +#ifdef HAVE_OPENSSL + &ecdsa_with_sha256_alg, + &ecdsa_with_sha1_alg, +#endif &rsa_with_sha256_alg, &rsa_with_sha1_alg, &pkcs1_rsa_sha1_alg, @@ -1013,19 +1514,51 @@ static const struct signature_alg *sig_algs[] = { static const struct signature_alg * find_sig_alg(const heim_oid *oid) { - int i; + unsigned int i; for (i = 0; sig_algs[i]; i++) - if (der_heim_oid_cmp((*sig_algs[i]->sig_oid)(), oid) == 0) + if (der_heim_oid_cmp(sig_algs[i]->sig_oid, oid) == 0) return sig_algs[i]; return NULL; } +static const AlgorithmIdentifier * +alg_for_privatekey(const hx509_private_key pk, int type) +{ + const heim_oid *keytype; + unsigned int i; + + if (pk->ops == NULL) + return NULL; + + keytype = pk->ops->key_oid; + + for (i = 0; sig_algs[i]; i++) { + if (sig_algs[i]->key_oid == NULL) + continue; + if (der_heim_oid_cmp(sig_algs[i]->key_oid, keytype) != 0) + continue; + if (pk->ops->available && + pk->ops->available(pk, sig_algs[i]->sig_alg) == 0) + continue; + if (type == HX509_SELECT_PUBLIC_SIG) + return sig_algs[i]->sig_alg; + if (type == HX509_SELECT_DIGEST) + return sig_algs[i]->digest_alg; + + return NULL; + } + return NULL; +} + /* * */ static struct hx509_private_key_ops *private_algs[] = { &rsa_private_key_ops, +#ifdef HAVE_OPENSSL + &ecdsa_private_key_ops, +#endif NULL }; @@ -1036,12 +1569,37 @@ find_private_alg(const heim_oid *oid) for (i = 0; private_algs[i]; i++) { if (private_algs[i]->key_oid == NULL) continue; - if (der_heim_oid_cmp((*private_algs[i]->key_oid)(), oid) == 0) + if (der_heim_oid_cmp(private_algs[i]->key_oid, oid) == 0) return private_algs[i]; } return NULL; } +/* + * Check if the algorithm `alg' have a best before date, and if it + * des, make sure the its before the time `t'. + */ + +int +_hx509_signature_best_before(hx509_context context, + const AlgorithmIdentifier *alg, + time_t t) +{ + const struct signature_alg *md; + + md = find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + if (md->best_before && md->best_before < t) { + hx509_set_error_string(context, 0, HX509_CRYPTO_ALGORITHM_BEST_BEFORE, + "Algorithm %s has passed it best before date", + md->name); + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + } + return 0; +} int _hx509_verify_signature(hx509_context context, @@ -1069,7 +1627,7 @@ _hx509_verify_signature(hx509_context context, const SubjectPublicKeyInfo *spi; spi = &signer->tbsCertificate.subjectPublicKeyInfo; - if (der_heim_oid_cmp(&spi->algorithm.algorithm, (*md->key_oid)()) != 0) { + if (der_heim_oid_cmp(&spi->algorithm.algorithm, md->key_oid) != 0) { hx509_clear_error_string(context); return HX509_SIG_ALG_DONT_MATCH_KEY_ALG; } @@ -1108,13 +1666,6 @@ _hx509_create_signature(hx509_context context, { const struct signature_alg *md; - if (signer && signer->ops && signer->ops->handle_alg && - (*signer->ops->handle_alg)(signer, alg, COT_SIGN)) - { - return (*signer->ops->sign)(context, signer, alg, data, - signatureAlgorithm, sig); - } - md = find_sig_alg(&alg->algorithm); if (md == NULL) { hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED, @@ -1221,7 +1772,7 @@ _hx509_public_encrypt(hx509_context context, ciphertext->length = ret; ciphertext->data = to; - ret = der_copy_oid(oid_id_pkcs1_rsaEncryption(), encryption_oid); + ret = der_copy_oid(&asn1_oid_id_pkcs1_rsaEncryption, encryption_oid); if (ret) { der_free_octet_string(ciphertext); hx509_set_error_string(context, 0, ENOMEM, "out of memory"); @@ -1276,7 +1827,7 @@ _hx509_private_key_private_decrypt(hx509_context context, int _hx509_parse_private_key(hx509_context context, - const heim_oid *key_oid, + const AlgorithmIdentifier *keyai, const void *data, size_t len, hx509_private_key *private_key) @@ -1286,7 +1837,7 @@ _hx509_parse_private_key(hx509_context context, *private_key = NULL; - ops = find_private_alg(key_oid); + ops = find_private_alg(&keyai->algorithm); if (ops == NULL) { hx509_clear_error_string(context); return HX509_SIG_ALG_NO_SUPPORTED; @@ -1298,7 +1849,7 @@ _hx509_parse_private_key(hx509_context context, return ret; } - ret = (*ops->import)(context, data, len, *private_key); + ret = (*ops->import)(context, keyai, data, len, *private_key); if (ret) _hx509_private_key_free(private_key); @@ -1330,7 +1881,7 @@ _hx509_generate_private_key_init(hx509_context context, { *ctx = NULL; - if (der_heim_oid_cmp(oid, oid_id_pkcs1_rsaEncryption()) != 0) { + if (der_heim_oid_cmp(oid, &asn1_oid_id_pkcs1_rsaEncryption) != 0) { hx509_set_error_string(context, 0, EINVAL, "private key not an RSA key"); return EINVAL; @@ -1400,98 +1951,10 @@ _hx509_generate_private_key(hx509_context context, return ret; } - /* * */ -static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") }; - -static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 }; -const AlgorithmIdentifier _hx509_signature_sha512_data = { - { 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 }; -const AlgorithmIdentifier _hx509_signature_sha384_data = { - { 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; -const AlgorithmIdentifier _hx509_signature_sha256_data = { - { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; -const AlgorithmIdentifier _hx509_signature_sha1_data = { - { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; -const AlgorithmIdentifier _hx509_signature_md5_data = { - { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 }; -const AlgorithmIdentifier _hx509_signature_md2_data = { - { 6, rk_UNCONST(md2_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = { - { 7, rk_UNCONST(rsa_with_sha512_oid) }, NULL -}; - -static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = { - { 7, rk_UNCONST(rsa_with_sha384_oid) }, NULL -}; - -static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = { - { 7, rk_UNCONST(rsa_with_sha256_oid) }, NULL -}; - -static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = { - { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL -}; - -static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = { - { 7, rk_UNCONST(rsa_with_md5_oid) }, NULL -}; - -static const unsigned rsa_with_md2_oid[] ={ 1, 2, 840, 113549, 1, 1, 2 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_md2_data = { - { 7, rk_UNCONST(rsa_with_md2_oid) }, NULL -}; - -static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 }; -const AlgorithmIdentifier _hx509_signature_rsa_data = { - { 7, rk_UNCONST(rsa_oid) }, NULL -}; - -static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 }; -const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = { - { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL -}; - -static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 }; -const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = { - { 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL -}; - -static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 }; -const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = { - { 9, rk_UNCONST(aes128_cbc_oid) }, NULL -}; - -static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 }; -const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = { - { 9, rk_UNCONST(aes256_cbc_oid) }, NULL -}; - const AlgorithmIdentifier * hx509_signature_sha512(void) { return &_hx509_signature_sha512_data; } @@ -1517,6 +1980,18 @@ hx509_signature_md2(void) { return &_hx509_signature_md2_data; } const AlgorithmIdentifier * +hx509_signature_ecPublicKey(void) +{ return &_hx509_signature_ecPublicKey; } + +const AlgorithmIdentifier * +hx509_signature_ecdsa_with_sha256(void) +{ return &_hx509_signature_ecdsa_with_sha256_data; } + +const AlgorithmIdentifier * +hx509_signature_ecdsa_with_sha1(void) +{ return &_hx509_signature_ecdsa_with_sha1_data; } + +const AlgorithmIdentifier * hx509_signature_rsa_with_sha512(void) { return &_hx509_signature_rsa_with_sha512_data; } @@ -1565,9 +2040,9 @@ hx509_crypto_aes256_cbc(void) */ const AlgorithmIdentifier * _hx509_crypto_default_sig_alg = - &_hx509_signature_rsa_with_sha1_data; + &_hx509_signature_rsa_with_sha256_data; const AlgorithmIdentifier * _hx509_crypto_default_digest_alg = - &_hx509_signature_sha1_data; + &_hx509_signature_sha256_data; const AlgorithmIdentifier * _hx509_crypto_default_secret_alg = &_hx509_crypto_aes128_cbc_data; @@ -1617,8 +2092,15 @@ _hx509_private_key_free(hx509_private_key *key) if (--(*key)->ref > 0) return 0; - if ((*key)->private_key.rsa) - RSA_free((*key)->private_key.rsa); + if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) { + if ((*key)->private_key.rsa) + RSA_free((*key)->private_key.rsa); +#ifdef HAVE_OPENSSL + } else if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, &asn1_oid_id_ecPublicKey) == 0) { + if ((*key)->private_key.ecdsa) + EC_KEY_free((*key)->private_key.ecdsa); +#endif + } (*key)->private_key.rsa = NULL; free(*key); *key = NULL; @@ -1631,7 +2113,7 @@ _hx509_private_key_assign_rsa(hx509_private_key key, void *ptr) if (key->private_key.rsa) RSA_free(key->private_key.rsa); key->private_key.rsa = ptr; - key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption; key->md = &pkcs1_rsa_sha1_alg; } @@ -1641,7 +2123,7 @@ _hx509_private_key_oid(hx509_context context, heim_oid *data) { int ret; - ret = der_copy_oid((*key->ops->key_oid)(), data); + ret = der_copy_oid(key->ops->key_oid, data); if (ret) hx509_set_error_string(context, 0, ret, "malloc out of memory"); return ret; @@ -1683,7 +2165,9 @@ _hx509_private_key_export(hx509_context context, struct hx509cipher { const char *name; - const heim_oid *(*oid_func)(void); + int flags; +#define CIPHER_WEAK 1 + const heim_oid *oid; const AlgorithmIdentifier *(*ai_func)(void); const EVP_CIPHER *(*evp_func)(void); int (*get_params)(hx509_context, const hx509_crypto, @@ -1694,6 +2178,8 @@ struct hx509cipher { struct hx509_crypto_data { char *name; + int flags; +#define ALLOW_WEAK 1 const struct hx509cipher *cipher; const EVP_CIPHER *c; heim_octet_string key; @@ -1705,15 +2191,10 @@ struct hx509_crypto_data { * */ -static const heim_oid * -oid_private_rc2_40(void) -{ - static unsigned oid_data[] = { 127, 1 }; - static const heim_oid oid = { 2, oid_data }; - - return &oid; -} +static unsigned private_rc2_40_oid_data[] = { 127, 1 }; +static heim_oid asn1_oid_private_rc2_40 = + { 2, private_rc2_40_oid_data }; /* * @@ -1853,7 +2334,8 @@ CMSRC2CBCParam_set(hx509_context context, const heim_octet_string *param, static const struct hx509cipher ciphers[] = { { "rc2-cbc", - oid_id_pkcs3_rc2_cbc, + CIPHER_WEAK, + &asn1_oid_id_pkcs3_rc2_cbc, NULL, EVP_rc2_cbc, CMSRC2CBCParam_get, @@ -1861,7 +2343,8 @@ static const struct hx509cipher ciphers[] = { }, { "rc2-cbc", - oid_id_rsadsi_rc2_cbc, + CIPHER_WEAK, + &asn1_oid_id_rsadsi_rc2_cbc, NULL, EVP_rc2_cbc, CMSRC2CBCParam_get, @@ -1869,7 +2352,8 @@ static const struct hx509cipher ciphers[] = { }, { "rc2-40-cbc", - oid_private_rc2_40, + CIPHER_WEAK, + &asn1_oid_private_rc2_40, NULL, EVP_rc2_40_cbc, CMSRC2CBCParam_get, @@ -1877,7 +2361,8 @@ static const struct hx509cipher ciphers[] = { }, { "des-ede3-cbc", - oid_id_pkcs3_des_ede3_cbc, + 0, + &asn1_oid_id_pkcs3_des_ede3_cbc, NULL, EVP_des_ede3_cbc, CMSCBCParam_get, @@ -1885,7 +2370,8 @@ static const struct hx509cipher ciphers[] = { }, { "des-ede3-cbc", - oid_id_rsadsi_des_ede3_cbc, + 0, + &asn1_oid_id_rsadsi_des_ede3_cbc, hx509_crypto_des_rsdi_ede3_cbc, EVP_des_ede3_cbc, CMSCBCParam_get, @@ -1893,7 +2379,8 @@ static const struct hx509cipher ciphers[] = { }, { "aes-128-cbc", - oid_id_aes_128_cbc, + 0, + &asn1_oid_id_aes_128_cbc, hx509_crypto_aes128_cbc, EVP_aes_128_cbc, CMSCBCParam_get, @@ -1901,7 +2388,8 @@ static const struct hx509cipher ciphers[] = { }, { "aes-192-cbc", - oid_id_aes_192_cbc, + 0, + &asn1_oid_id_aes_192_cbc, NULL, EVP_aes_192_cbc, CMSCBCParam_get, @@ -1909,7 +2397,8 @@ static const struct hx509cipher ciphers[] = { }, { "aes-256-cbc", - oid_id_aes_256_cbc, + 0, + &asn1_oid_id_aes_256_cbc, hx509_crypto_aes256_cbc, EVP_aes_256_cbc, CMSCBCParam_get, @@ -1923,7 +2412,7 @@ find_cipher_by_oid(const heim_oid *oid) int i; for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) - if (der_heim_oid_cmp(oid, (*ciphers[i].oid_func)()) == 0) + if (der_heim_oid_cmp(oid, ciphers[i].oid) == 0) return &ciphers[i]; return NULL; @@ -1950,7 +2439,7 @@ hx509_crypto_enctype_by_name(const char *name) cipher = find_cipher_by_name(name); if (cipher == NULL) return NULL; - return (*cipher->oid_func)(); + return cipher->oid; } int @@ -2015,6 +2504,12 @@ hx509_crypto_set_key_name(hx509_crypto crypto, const char *name) return 0; } +void +hx509_crypto_allow_weak(hx509_crypto crypto) +{ + crypto->flags |= ALLOW_WEAK; +} + int hx509_crypto_set_key_data(hx509_crypto crypto, const void *data, size_t length) { @@ -2111,6 +2606,10 @@ hx509_crypto_encrypt(hx509_crypto crypto, *ciphertext = NULL; + if ((crypto->cipher->flags & CIPHER_WEAK) && + (crypto->flags & ALLOW_WEAK) == 0) + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + assert(EVP_CIPHER_iv_length(crypto->c) == ivec->length); EVP_CIPHER_CTX_init(&evp); @@ -2189,6 +2688,10 @@ hx509_crypto_decrypt(hx509_crypto crypto, clear->data = NULL; clear->length = 0; + if ((crypto->cipher->flags & CIPHER_WEAK) && + (crypto->flags & ALLOW_WEAK) == 0) + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + if (ivec && EVP_CIPHER_iv_length(crypto->c) < ivec->length) return HX509_CRYPTO_INTERNAL_ERROR; @@ -2312,6 +2815,8 @@ PBE_string2key(hx509_context context, if (ret) goto out; + hx509_crypto_allow_weak(c); + ret = hx509_crypto_set_key_data(c, key->data, key->length); if (ret) { hx509_crypto_destroy(c); @@ -2330,33 +2835,33 @@ find_string2key(const heim_oid *oid, const EVP_MD **md, PBE_string2key_func *s2k) { - if (der_heim_oid_cmp(oid, oid_id_pbewithSHAAnd40BitRC2_CBC()) == 0) { + if (der_heim_oid_cmp(oid, &asn1_oid_id_pbewithSHAAnd40BitRC2_CBC) == 0) { *c = EVP_rc2_40_cbc(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_private_rc2_40(); - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC2_CBC()) == 0) { + return &asn1_oid_private_rc2_40; + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd128BitRC2_CBC) == 0) { *c = EVP_rc2_cbc(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_id_pkcs3_rc2_cbc(); + return &asn1_oid_id_pkcs3_rc2_cbc; #if 0 - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd40BitRC4()) == 0) { + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd40BitRC4) == 0) { *c = EVP_rc4_40(); *md = EVP_sha1(); *s2k = PBE_string2key; return NULL; - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC4()) == 0) { + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd128BitRC4) == 0) { *c = EVP_rc4(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_id_pkcs3_rc4(); + return &asn1_oid_id_pkcs3_rc4; #endif - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC()) == 0) { + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC) == 0) { *c = EVP_des_ede3_cbc(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_id_pkcs3_des_ede3_cbc(); + return &asn1_oid_id_pkcs3_des_ede3_cbc; } return NULL; @@ -2467,8 +2972,8 @@ out: */ -int -_hx509_match_keys(hx509_cert c, hx509_private_key private_key) +static int +match_keys_rsa(hx509_cert c, hx509_private_key private_key) { const Certificate *cert; const SubjectPublicKeyInfo *spi; @@ -2523,6 +3028,25 @@ _hx509_match_keys(hx509_cert c, hx509_private_key private_key) return ret == 1; } +static int +match_keys_ec(hx509_cert c, hx509_private_key private_key) +{ + return 1; /* XXX use EC_KEY_check_key */ +} + + +int +_hx509_match_keys(hx509_cert c, hx509_private_key key) +{ + if (der_heim_oid_cmp(key->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) + return match_keys_rsa(c, key); + if (der_heim_oid_cmp(key->ops->key_oid, &asn1_oid_id_ecPublicKey) == 0) + return match_keys_ec(c, key); + return 0; + +} + + static const heim_oid * find_keytype(const hx509_private_key key) { @@ -2534,10 +3058,9 @@ find_keytype(const hx509_private_key key) md = find_sig_alg(key->signature_alg); if (md == NULL) return NULL; - return (*md->key_oid)(); + return md->key_oid; } - int hx509_crypto_select(const hx509_context context, int type, @@ -2545,7 +3068,7 @@ hx509_crypto_select(const hx509_context context, hx509_peer_info peer, AlgorithmIdentifier *selected) { - const AlgorithmIdentifier *def; + const AlgorithmIdentifier *def = NULL; size_t i, j; int ret, bits; @@ -2553,11 +3076,17 @@ hx509_crypto_select(const hx509_context context, if (type == HX509_SELECT_DIGEST) { bits = SIG_DIGEST; - def = _hx509_crypto_default_digest_alg; + if (source) + def = alg_for_privatekey(source, type); + if (def == NULL) + def = _hx509_crypto_default_digest_alg; } else if (type == HX509_SELECT_PUBLIC_SIG) { bits = SIG_PUBLIC_SIG; /* XXX depend on `source´ and `peer´ */ - def = _hx509_crypto_default_sig_alg; + if (source) + def = alg_for_privatekey(source, type); + if (def == NULL) + def = _hx509_crypto_default_sig_alg; } else if (type == HX509_SELECT_SECRET_ENC) { bits = SIG_SECRET; def = _hx509_crypto_default_secret_alg; @@ -2576,11 +3105,11 @@ hx509_crypto_select(const hx509_context context, for (j = 0; sig_algs[j]; j++) { if ((sig_algs[j]->flags & bits) != bits) continue; - if (der_heim_oid_cmp((*sig_algs[j]->sig_oid)(), + if (der_heim_oid_cmp(sig_algs[j]->sig_oid, &peer->val[i].algorithm) != 0) continue; if (keytype && sig_algs[j]->key_oid && - der_heim_oid_cmp(keytype, (*sig_algs[j]->key_oid)())) + der_heim_oid_cmp(keytype, sig_algs[j]->key_oid)) continue; /* found one, use that */ @@ -2648,7 +3177,7 @@ hx509_crypto_available(hx509_context context, if (sig_algs[i]->sig_alg == NULL) continue; if (keytype && sig_algs[i]->key_oid && - der_heim_oid_cmp((*sig_algs[i]->key_oid)(), keytype)) + der_heim_oid_cmp(sig_algs[i]->key_oid, keytype)) continue; /* found one, add that to the list */ @@ -2657,7 +3186,7 @@ hx509_crypto_available(hx509_context context, goto out; *val = ptr; - ret = copy_AlgorithmIdentifier((*sig_algs[i]->sig_alg)(), &(*val)[len]); + ret = copy_AlgorithmIdentifier(sig_algs[i]->sig_alg, &(*val)[len]); if (ret) goto out; len++; @@ -2667,7 +3196,9 @@ hx509_crypto_available(hx509_context context, if (bits & SIG_SECRET) { for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) { - + + if (ciphers[i].flags & CIPHER_WEAK) + continue; if (ciphers[i].ai_func == NULL) continue; diff --git a/source4/heimdal/lib/hx509/env.c b/source4/heimdal/lib/hx509/env.c index 0b0a68ceae..7598aebaae 100644 --- a/source4/heimdal/lib/hx509/env.c +++ b/source4/heimdal/lib/hx509/env.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_env Hx509 enviroment functions diff --git a/source4/heimdal/lib/hx509/error.c b/source4/heimdal/lib/hx509/error.c index 6f25404145..45813efb38 100644 --- a/source4/heimdal/lib/hx509/error.c +++ b/source4/heimdal/lib/hx509/error.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_error Hx509 error reporting functions diff --git a/source4/heimdal/lib/hx509/file.c b/source4/heimdal/lib/hx509/file.c index a364dd2179..ba7a23f471 100644 --- a/source4/heimdal/lib/hx509/file.c +++ b/source4/heimdal/lib/hx509/file.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$ID$"); int _hx509_map_file_os(const char *fn, heim_octet_string *os) diff --git a/source4/heimdal/lib/hx509/hx509.h b/source4/heimdal/lib/hx509/hx509.h index 5e5a2f811b..86aad7ec9c 100644 --- a/source4/heimdal/lib/hx509/hx509.h +++ b/source4/heimdal/lib/hx509/hx509.h @@ -36,8 +36,9 @@ #ifndef HEIMDAL_HX509_H #define HEIMDAL_HX509_H 1 -#include <heim_asn1.h> #include <rfc2459_asn1.h> +#include <stdarg.h> +#include <stdio.h> typedef struct hx509_cert_attribute_data *hx509_cert_attribute; typedef struct hx509_cert_data *hx509_cert; @@ -124,6 +125,17 @@ typedef enum { /* flags to hx509_cms_unenvelope */ #define HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT 0x01 +#define HX509_CMS_UE_ALLOW_WEAK 0x02 + +/* flags to hx509_cms_envelope_1 */ +#define HX509_CMS_EV_NO_KU_CHECK 0x01 +#define HX509_CMS_EV_ALLOW_WEAK 0x02 + +/* flags to hx509_cms_verify_signed */ +#define HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH 0x01 +#define HX509_CMS_VS_NO_KU_CHECK 0x02 +#define HX509_CMS_VS_ALLOW_ZERO_SIGNER 0x04 +#define HX509_CMS_VS_NO_VALIDATE 0x08 /* selectors passed to hx509_crypto_select and hx509_crypto_available */ #define HX509_SELECT_ALL 0 @@ -142,8 +154,9 @@ typedef enum { #define HX509_CA_TEMPLATE_EKU 64 /* flags hx509_cms_create_signed* */ -#define HX509_CMS_SIGATURE_DETACHED 1 -#define HX509_CMS_SIGATURE_ID_NAME 2 +#define HX509_CMS_SIGNATURE_DETACHED 0x01 +#define HX509_CMS_SIGNATURE_ID_NAME 0x02 +#define HX509_CMS_SIGNATURE_NO_SIGNER 0x04 /* hx509_verify_hostname nametype */ typedef enum { diff --git a/source4/heimdal/lib/hx509/hx509_err.et b/source4/heimdal/lib/hx509/hx509_err.et index c1dfaf587e..76bbfaeaba 100644 --- a/source4/heimdal/lib/hx509/hx509_err.et +++ b/source4/heimdal/lib/hx509/hx509_err.et @@ -62,9 +62,10 @@ error_code OID_MISMATCH, "Mismatch bewteen oids" error_code NO_PROMPTER, "No prompter function defined" error_code SIGNATURE_WITHOUT_SIGNER, "Signature require signer, but non available" error_code RSA_PUBLIC_ENCRYPT, "RSA public encyption failed" -error_code RSA_PRIVATE_ENCRYPT, "RSA public encyption failed" -error_code RSA_PUBLIC_DECRYPT, "RSA private decryption failed" +error_code RSA_PRIVATE_ENCRYPT, "RSA private encyption failed" +error_code RSA_PUBLIC_DECRYPT, "RSA public decryption failed" error_code RSA_PRIVATE_DECRYPT, "RSA private decryption failed" +error_code ALGORITHM_BEST_BEFORE, "Algorithm has passed its best before date" # revoke related errors index 96 diff --git a/source4/heimdal/lib/hx509/hx_locl.h b/source4/heimdal/lib/hx509/hx_locl.h index 8de2353f15..2d1c036d53 100644 --- a/source4/heimdal/lib/hx509/hx_locl.h +++ b/source4/heimdal/lib/hx509/hx_locl.h @@ -33,9 +33,7 @@ /* $Id$ */ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include <stdio.h> #include <stdlib.h> @@ -145,7 +143,7 @@ struct hx509_query_data { Name *subject_name; hx509_path *path; char *friendlyname; - int (*cmp_func)(void *, hx509_cert); + int (*cmp_func)(hx509_context, hx509_cert, void *); void *cmp_func_ctx; heim_octet_string *keyhash_sha1; time_t timenow; diff --git a/source4/heimdal/lib/hx509/keyset.c b/source4/heimdal/lib/hx509/keyset.c index b68064b512..c4f035ab87 100644 --- a/source4/heimdal/lib/hx509/keyset.c +++ b/source4/heimdal/lib/hx509/keyset.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_keyset Certificate store operations @@ -481,6 +480,10 @@ hx509_certs_find(hx509_context context, hx509_certs_end_seq(context, certs, cursor); if (ret) return ret; + /** + * Return HX509_CERT_NOT_FOUND if no certificate in certs matched + * the query. + */ if (c == NULL) { hx509_clear_error_string(context); return HX509_CERT_NOT_FOUND; @@ -489,6 +492,77 @@ hx509_certs_find(hx509_context context, return 0; } +/** + * Filter certificate matching the query. + * + * @param context a hx509 context. + * @param certs certificate store to search. + * @param q query allocated with @ref hx509_query functions. + * @param result the filtered certificate store, caller must free with + * hx509_certs_free(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +int +hx509_certs_filter(hx509_context context, + hx509_certs certs, + const hx509_query *q, + hx509_certs *result) +{ + hx509_cursor cursor; + hx509_cert c; + int ret, found = 0; + + _hx509_query_statistic(context, 0, q); + + ret = hx509_certs_init(context, "MEMORY:filter-certs", 0, + NULL, result); + if (ret) + return ret; + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) { + hx509_certs_free(result); + return ret; + } + + c = NULL; + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + if (_hx509_query_match_cert(context, q, c)) { + hx509_certs_add(context, *result, c); + found = 1; + } + hx509_cert_free(c); + } + + hx509_certs_end_seq(context, certs, cursor); + if (ret) { + hx509_certs_free(result); + return ret; + } + + /** + * Return HX509_CERT_NOT_FOUND if no certificate in certs matched + * the query. + */ + if (!found) { + hx509_certs_free(result); + hx509_clear_error_string(context); + return HX509_CERT_NOT_FOUND; + } + + return 0; +} + + static int certs_merge_func(hx509_context context, void *ctx, hx509_cert c) { diff --git a/source4/heimdal/lib/hx509/ks_dir.c b/source4/heimdal/lib/hx509/ks_dir.c index 76c0c42633..a627fc65a2 100644 --- a/source4/heimdal/lib/hx509/ks_dir.c +++ b/source4/heimdal/lib/hx509/ks_dir.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); #include <dirent.h> /* @@ -71,7 +70,7 @@ dir_init(hx509_context context, return ENOENT; } - if ((sb.st_mode & S_IFDIR) == 0) { + if (!S_ISDIR(sb.st_mode)) { hx509_set_error_string(context, 0, ENOTDIR, "%s is not a directory", residue); return ENOTDIR; diff --git a/source4/heimdal/lib/hx509/ks_file.c b/source4/heimdal/lib/hx509/ks_file.c index ca0171f8b9..74808f7607 100644 --- a/source4/heimdal/lib/hx509/ks_file.c +++ b/source4/heimdal/lib/hx509/ks_file.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); typedef enum { USE_PEM, USE_DER } outformat; @@ -50,7 +49,8 @@ static int parse_certificate(hx509_context context, const char *fn, struct hx509_collector *c, const hx509_pem_header *headers, - const void *data, size_t len) + const void *data, size_t len, + const AlgorithmIdentifier *ai) { hx509_cert cert; int ret; @@ -130,10 +130,40 @@ out: } static int -parse_rsa_private_key(hx509_context context, const char *fn, +parse_pkcs8_private_key(hx509_context context, const char *fn, + struct hx509_collector *c, + const hx509_pem_header *headers, + const void *data, size_t length, + const AlgorithmIdentifier *ai) +{ + PKCS8PrivateKeyInfo ki; + heim_octet_string keydata; + + int ret; + + ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL); + if (ret) + return ret; + + keydata.data = rk_UNCONST(data); + keydata.length = length; + + ret = _hx509_collector_private_key_add(context, + c, + &ki.privateKeyAlgorithm, + NULL, + &ki.privateKey, + &keydata); + free_PKCS8PrivateKeyInfo(&ki); + return ret; +} + +static int +parse_pem_private_key(hx509_context context, const char *fn, struct hx509_collector *c, const hx509_pem_header *headers, - const void *data, size_t len) + const void *data, size_t len, + const AlgorithmIdentifier *ai) { int ret = 0; const char *enc; @@ -159,7 +189,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, if (strcmp(enc, "4,ENCRYPTED") != 0) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "RSA key encrypted in unknown method %s " + "Private key encrypted in unknown method %s " "in file", enc, fn); hx509_clear_error_string(context); @@ -169,7 +199,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, dek = hx509_pem_find_header(headers, "DEK-Info"); if (dek == NULL) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "Encrypted RSA missing DEK-Info"); + "Encrypted private key missing DEK-Info"); return HX509_PARSING_KEY_FAILED; } @@ -201,7 +231,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, if (cipher == NULL) { free(ivdata); hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, - "RSA key encrypted with " + "Private key encrypted with " "unsupported cipher: %s", type); free(type); @@ -218,7 +248,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) { free(ivdata); hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "Salt have wrong length in RSA key file"); + "Salt have wrong length in " + "private key file"); return HX509_PARSING_KEY_FAILED; } @@ -231,9 +262,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, password = pw->val[i]; passwordlen = strlen(password); - ret = try_decrypt(context, c, hx509_signature_rsa(), - cipher, ivdata, password, passwordlen, - data, len); + ret = try_decrypt(context, c, ai, cipher, ivdata, + password, passwordlen, data, len); if (ret == 0) { decrypted = 1; break; @@ -253,9 +283,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, ret = hx509_lock_prompt(lock, &prompt); if (ret == 0) - ret = try_decrypt(context, c, hx509_signature_rsa(), - cipher, ivdata, password, strlen(password), - data, len); + ret = try_decrypt(context, c, ai, cipher, ivdata, password, + strlen(password), data, len); /* XXX add password to lock password collection ? */ memset(password, 0, sizeof(password)); } @@ -267,12 +296,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, keydata.data = rk_UNCONST(data); keydata.length = len; - ret = _hx509_collector_private_key_add(context, - c, - hx509_signature_rsa(), - NULL, - &keydata, - NULL); + ret = _hx509_collector_private_key_add(context, c, ai, NULL, + &keydata, NULL); } return ret; @@ -282,10 +307,14 @@ parse_rsa_private_key(hx509_context context, const char *fn, struct pem_formats { const char *name; int (*func)(hx509_context, const char *, struct hx509_collector *, - const hx509_pem_header *, const void *, size_t); + const hx509_pem_header *, const void *, size_t, + const AlgorithmIdentifier *); + const AlgorithmIdentifier *(*ai)(void); } formats[] = { - { "CERTIFICATE", parse_certificate }, - { "RSA PRIVATE KEY", parse_rsa_private_key } + { "CERTIFICATE", parse_certificate, NULL }, + { "PRIVATE KEY", parse_pkcs8_private_key, NULL }, + { "RSA PRIVATE KEY", parse_pem_private_key, hx509_signature_rsa }, + { "EC PRIVATE KEY", parse_pem_private_key, hx509_signature_ecPublicKey } }; @@ -305,9 +334,18 @@ pem_func(hx509_context context, const char *type, for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) { const char *q = formats[j].name; if (strcasecmp(type, q) == 0) { - ret = (*formats[j].func)(context, NULL, pem_ctx->c, header, data, len); - if (ret == 0) - break; + const AlgorithmIdentifier *ai = NULL; + if (formats[j].ai != NULL) + ai = (*formats[j].ai)(); + + ret = (*formats[j].func)(context, NULL, pem_ctx->c, + header, data, len, ai); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed parseing PEM format %s", type); + return ret; + } + break; } } if (j == sizeof(formats)/sizeof(formats[0])) { @@ -409,13 +447,19 @@ file_init_common(hx509_context context, } for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { - ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length); + const AlgorithmIdentifier *ai = NULL; + if (formats[i].ai != NULL) + ai = (*formats[i].ai)(); + + ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length, ai); if (ret == 0) break; } rk_xfree(ptr); - if (ret) + if (ret) { + hx509_clear_error_string(context); goto out; + } } } diff --git a/source4/heimdal/lib/hx509/ks_keychain.c b/source4/heimdal/lib/hx509/ks_keychain.c index 2dc0721563..01d0c55d1c 100644 --- a/source4/heimdal/lib/hx509/ks_keychain.c +++ b/source4/heimdal/lib/hx509/ks_keychain.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); #ifdef HAVE_FRAMEWORK_SECURITY @@ -119,6 +118,8 @@ kc_rsa_private_encrypt(int flen, CSSM_DATA sig, in; int fret = 0; + if (padding != RSA_PKCS1_PADDING) + return -1; cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); if(cret) abort(); @@ -157,7 +158,62 @@ static int kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA * rsa, int padding) { - return -1; + struct kc_rsa *kc = RSA_get_app_data(rsa); + + CSSM_RETURN cret; + OSStatus ret; + const CSSM_ACCESS_CREDENTIALS *creds; + SecKeyRef privKeyRef = (SecKeyRef)kc->item; + CSSM_CSP_HANDLE cspHandle; + const CSSM_KEY *cssmKey; + CSSM_CC_HANDLE handle = 0; + CSSM_DATA out, in, rem; + int fret = 0; + CSSM_SIZE outlen = 0; + char remdata[1024]; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); + if(cret) abort(); + + cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); + if(cret) abort(); + + ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, + kSecCredentialTypeDefault, &creds); + if(ret) abort(); + + + ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, + CSSM_ALGID_RSA, + creds, + cssmKey, + CSSM_PADDING_PKCS1, + &handle); + if(ret) abort(); + + in.Data = (uint8 *)from; + in.Length = flen; + + out.Data = (uint8 *)to; + out.Length = kc->keysize; + + rem.Data = (uint8 *)remdata; + rem.Length = sizeof(remdata); + + cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); + if(cret) { + /* cssmErrorString(cret); */ + fret = -1; + } else + fret = out.Length; + + if(handle) + CSSM_DeleteContext(handle); + + return fret; } static int @@ -504,8 +560,7 @@ keychain_iter_end(hx509_context context, struct iter *iter = cursor; if (iter->certs) { - int ret; - ret = hx509_certs_end_seq(context, iter->certs, iter->cursor); + hx509_certs_end_seq(context, iter->certs, iter->cursor); hx509_certs_free(&iter->certs); } else { CFRelease(iter->searchRef); diff --git a/source4/heimdal/lib/hx509/ks_mem.c b/source4/heimdal/lib/hx509/ks_mem.c index bf952fbeee..299a3932c9 100644 --- a/source4/heimdal/lib/hx509/ks_mem.c +++ b/source4/heimdal/lib/hx509/ks_mem.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("Id$"); /* * Should use two hash/tree certificates intead of a array. Criteria diff --git a/source4/heimdal/lib/hx509/ks_null.c b/source4/heimdal/lib/hx509/ks_null.c index fae631fb3f..136d2d4345 100644 --- a/source4/heimdal/lib/hx509/ks_null.c +++ b/source4/heimdal/lib/hx509/ks_null.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); static int diff --git a/source4/heimdal/lib/hx509/ks_p11.c b/source4/heimdal/lib/hx509/ks_p11.c index 652cdc2210..52697f834b 100644 --- a/source4/heimdal/lib/hx509/ks_p11.c +++ b/source4/heimdal/lib/hx509/ks_p11.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); #ifdef HAVE_DLFCN_H #include <dlfcn.h> #endif @@ -332,7 +331,7 @@ p11_init_slot(hx509_context context, } asprintf(&slot->name, "%.*s", - i, slot_info.slotDescription); + (int)i, slot_info.slotDescription); if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) return 0; @@ -711,7 +710,7 @@ collect_cert(hx509_context context, _hx509_set_cert_attribute(context, cert, - oid_id_pkcs_9_at_localKeyId(), + &asn1_oid_id_pkcs_9_at_localKeyId, &data); } @@ -945,11 +944,7 @@ p11_release_module(struct p11_module *p) if (p->slot[i].flags & P11_SESSION_IN_USE) _hx509_abort("pkcs11 module release while session in use"); if (p->slot[i].flags & P11_SESSION) { - int ret; - - ret = P11FUNC(p, CloseSession, (p->slot[i].session)); - if (ret != CKR_OK) - ; + P11FUNC(p, CloseSession, (p->slot[i].session)); } if (p->slot[i].name) diff --git a/source4/heimdal/lib/hx509/ks_p12.c b/source4/heimdal/lib/hx509/ks_p12.c index b59bd215f0..c17ce3f6ac 100644 --- a/source4/heimdal/lib/hx509/ks_p12.c +++ b/source4/heimdal/lib/hx509/ks_p12.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct ks_pkcs12 { hx509_certs certs; @@ -45,7 +44,7 @@ typedef int (*collector_func)(hx509_context, const PKCS12_Attributes *); struct type { - const heim_oid * (*oid)(void); + const heim_oid *oid; collector_func func; }; @@ -77,7 +76,7 @@ keyBag_parser(hx509_context context, const heim_octet_string *os = NULL; int ret; - attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId()); + attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId); if (attr) os = &attr->attrValues; @@ -140,7 +139,7 @@ certBag_parser(hx509_context context, if (ret) return ret; - if (der_heim_oid_cmp(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType)) { + if (der_heim_oid_cmp(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType)) { free_PKCS12_CertBag(&cb); return 0; } @@ -166,13 +165,13 @@ certBag_parser(hx509_context context, { const PKCS12_Attribute *attr; - const heim_oid * (*oids[])(void) = { - oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName + const heim_oid *oids[] = { + &asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName }; int i; - for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { - const heim_oid *oid = (*(oids[i]))(); + for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { + const heim_oid *oid = oids[i]; attr = find_attribute(attrs, oid); if (attr) _hx509_set_cert_attribute(context, cert, oid, @@ -248,7 +247,7 @@ encryptedData_parser(hx509_context context, if (ret) return ret; - if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) ret = parse_safe_content(context, c, content.data, content.length); der_free_octet_string(&content); @@ -285,7 +284,7 @@ envelopedData_parser(hx509_context context, return ret; } - if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) ret = parse_safe_content(context, c, content.data, content.length); der_free_octet_string(&content); @@ -296,12 +295,12 @@ envelopedData_parser(hx509_context context, struct type bagtypes[] = { - { oid_id_pkcs12_keyBag, keyBag_parser }, - { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, - { oid_id_pkcs12_certBag, certBag_parser }, - { oid_id_pkcs7_data, safeContent_parser }, - { oid_id_pkcs7_encryptedData, encryptedData_parser }, - { oid_id_pkcs7_envelopedData, envelopedData_parser } + { &asn1_oid_id_pkcs12_keyBag, keyBag_parser }, + { &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, + { &asn1_oid_id_pkcs12_certBag, certBag_parser }, + { &asn1_oid_id_pkcs7_data, safeContent_parser }, + { &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser }, + { &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser } }; static void @@ -314,7 +313,7 @@ parse_pkcs12_type(hx509_context context, int i; for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++) - if (der_heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0) + if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0) (*bagtypes[i].func)(context, c, data, length, attrs); } @@ -376,7 +375,7 @@ p12_init(hx509_context context, goto out; } - if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) { + if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) { free_PKCS12_PFX(&pfx); ret = EINVAL; hx509_set_error_string(context, 0, ret, @@ -506,7 +505,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) free(os.data); if (ret) goto out; - ret = der_copy_oid(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType); + ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType); if (ret) { free_PKCS12_CertBag(&cb); goto out; @@ -517,7 +516,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (ret) goto out; - ret = addBag(context, as, oid_id_pkcs12_certBag(), os.data, os.length); + ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length); if (_hx509_cert_private_key_exportable(c)) { hx509_private_key key = _hx509_cert_private_key(c); @@ -541,7 +540,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) free_PKCS8PrivateKeyInfo(&pki); return ret; } - /* set attribute, oid_id_pkcs_9_at_localKeyId() */ + /* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */ ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length, &pki, &size, ret); @@ -549,7 +548,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (ret) return ret; - ret = addBag(context, as, oid_id_pkcs12_keyBag(), os.data, os.length); + ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length); if (ret) return ret; } @@ -598,7 +597,7 @@ p12_store(hx509_context context, if (ret) goto out; - ret = der_copy_oid(oid_id_pkcs7_data(), &pfx.authSafe.contentType); + ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType); if (ret) goto out; diff --git a/source4/heimdal/lib/hx509/lock.c b/source4/heimdal/lib/hx509/lock.c index e2ceedecb8..219a301928 100644 --- a/source4/heimdal/lib/hx509/lock.c +++ b/source4/heimdal/lib/hx509/lock.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_lock Locking and unlocking certificates and encrypted data. diff --git a/source4/heimdal/lib/hx509/name.c b/source4/heimdal/lib/hx509/name.c index 069eed6062..b8f48d5236 100644 --- a/source4/heimdal/lib/hx509/name.c +++ b/source4/heimdal/lib/hx509/name.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2009 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,6 @@ #include "hx_locl.h" #include <wind.h> -RCSID("$Id$"); /** * @page page_name PKIX/X.509 Names @@ -63,20 +62,20 @@ RCSID("$Id$"); static const struct { const char *n; - const heim_oid *(*o)(void); + const heim_oid *o; wind_profile_flags flags; } no[] = { - { "C", oid_id_at_countryName }, - { "CN", oid_id_at_commonName }, - { "DC", oid_id_domainComponent }, - { "L", oid_id_at_localityName }, - { "O", oid_id_at_organizationName }, - { "OU", oid_id_at_organizationalUnitName }, - { "S", oid_id_at_stateOrProvinceName }, - { "STREET", oid_id_at_streetAddress }, - { "UID", oid_id_Userid }, - { "emailAddress", oid_id_pkcs9_emailAddress }, - { "serialNumber", oid_id_at_serialNumber } + { "C", &asn1_oid_id_at_countryName }, + { "CN", &asn1_oid_id_at_commonName }, + { "DC", &asn1_oid_id_domainComponent }, + { "L", &asn1_oid_id_at_localityName }, + { "O", &asn1_oid_id_at_organizationName }, + { "OU", &asn1_oid_id_at_organizationalUnitName }, + { "S", &asn1_oid_id_at_stateOrProvinceName }, + { "STREET", &asn1_oid_id_at_streetAddress }, + { "UID", &asn1_oid_id_Userid }, + { "emailAddress", &asn1_oid_id_pkcs9_emailAddress }, + { "serialNumber", &asn1_oid_id_at_serialNumber } }; static char * @@ -145,7 +144,7 @@ oidtostring(const heim_oid *type) size_t i; for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { - if (der_heim_oid_cmp((*no[i].o)(), type) == 0) + if (der_heim_oid_cmp(no[i].o, type) == 0) return strdup(no[i].n); } if (der_print_heim_oid(type, '.', &s) != 0) @@ -163,7 +162,7 @@ stringtooid(const char *name, size_t len, heim_oid *oid) for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { if (strncasecmp(no[i].n, name, len) == 0) - return der_copy_oid((*no[i].o)(), oid); + return der_copy_oid(no[i].o, oid); } s = malloc(len + 1); if (s == NULL) @@ -197,7 +196,7 @@ int _hx509_Name_to_string(const Name *n, char **str) { size_t total_len = 0; - int i, j; + int i, j, ret; *str = strdup(""); if (*str == NULL) @@ -224,15 +223,20 @@ _hx509_Name_to_string(const Name *n, char **str) ss = ds->u.utf8String; break; case choice_DirectoryString_bmpString: { - uint16_t *bmp = ds->u.bmpString.data; + const uint16_t *bmp = ds->u.bmpString.data; size_t bmplen = ds->u.bmpString.length; size_t k; - ss = malloc(bmplen + 1); + ret = wind_ucs2utf8_length(bmp, bmplen, &k); + if (ret) + return ret; + + ss = malloc(k + 1); if (ss == NULL) _hx509_abort("allocation failure"); /* XXX */ - for (k = 0; k < bmplen; k++) - ss[k] = bmp[k] & 0xff; /* XXX */ + ret = wind_ucs2utf8(bmp, bmplen, ss, NULL); + if (ret) + return ret; ss[k] = '\0'; break; } @@ -244,15 +248,20 @@ _hx509_Name_to_string(const Name *n, char **str) ss[ds->u.teletexString.length] = '\0'; break; case choice_DirectoryString_universalString: { - uint32_t *uni = ds->u.universalString.data; + const uint32_t *uni = ds->u.universalString.data; size_t unilen = ds->u.universalString.length; size_t k; - ss = malloc(unilen + 1); + ret = wind_ucs4utf8_length(uni, unilen, &k); + if (ret) + return ret; + + ss = malloc(k + 1); if (ss == NULL) _hx509_abort("allocation failure"); /* XXX */ - for (k = 0; k < unilen; k++) - ss[k] = uni[k] & 0xff; /* XXX */ + ret = wind_ucs4utf8(uni, unilen, ss, NULL); + if (ret) + return ret; ss[k] = '\0'; break; } @@ -344,8 +353,10 @@ dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) if (name == NULL) return ENOMEM; ret = wind_utf8ucs4(ds->u.utf8String, name, &len); - if (ret) + if (ret) { + free(name); return ret; + } break; default: _hx509_abort("unknown directory type: %d", ds->element); diff --git a/source4/heimdal/lib/hx509/peer.c b/source4/heimdal/lib/hx509/peer.c index f5841e497b..c796e19173 100644 --- a/source4/heimdal/lib/hx509/peer.c +++ b/source4/heimdal/lib/hx509/peer.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_peer Hx509 crypto selecting functions @@ -121,6 +120,39 @@ hx509_peer_info_set_cert(hx509_peer_info peer, } /** + * Add an additional algorithm that the peer supports. + * + * @param context A hx509 context. + * @param peer the peer to set the new algorithms for + * @param val an AlgorithmsIdentier to add + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_peer + */ + +int +hx509_peer_info_add_cms_alg(hx509_context context, + hx509_peer_info peer, + const AlgorithmIdentifier *val) +{ + void *ptr; + int ret; + + ptr = realloc(peer->val, sizeof(peer->val[0]) * (peer->len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + ret = copy_AlgorithmIdentifier(val, &peer->val[peer->len]); + if (ret == 0) + peer->len += 1; + else + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; +} + +/** * Set the algorithms that the peer supports. * * @param context A hx509 context. diff --git a/source4/heimdal/lib/hx509/print.c b/source4/heimdal/lib/hx509/print.c index 38d103905f..ddafb7f46e 100644 --- a/source4/heimdal/lib/hx509/print.c +++ b/source4/heimdal/lib/hx509/print.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_print Hx509 printing functions @@ -547,14 +546,14 @@ check_CRLDistributionPoints(hx509_validate_ctx ctx, struct { const char *name; - const heim_oid *(*oid)(void); + const heim_oid *oid; int (*func)(hx509_validate_ctx, heim_any *); -} check_altname[] = { - { "pk-init", oid_id_pkinit_san, check_pkinit_san }, - { "jabber", oid_id_pkix_on_xmppAddr, check_utf8_string_san }, - { "dns-srv", oid_id_pkix_on_dnsSRV, check_altnull }, - { "card-id", oid_id_uspkicommon_card_id, check_altnull }, - { "Microsoft NT-PRINCIPAL-NAME", oid_id_pkinit_ms_san, check_utf8_string_san } +} altname_types[] = { + { "pk-init", &asn1_oid_id_pkinit_san, check_pkinit_san }, + { "jabber", &asn1_oid_id_pkix_on_xmppAddr, check_utf8_string_san }, + { "dns-srv", &asn1_oid_id_pkix_on_dnsSRV, check_altnull }, + { "card-id", &asn1_oid_id_uspkicommon_card_id, check_altnull }, + { "Microsoft NT-PRINCIPAL-NAME", &asn1_oid_id_pkinit_ms_san, check_utf8_string_san } }; static int @@ -597,17 +596,17 @@ check_altName(hx509_validate_ctx ctx, validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%sAltName otherName ", name); - for (j = 0; j < sizeof(check_altname)/sizeof(check_altname[0]); j++) { - if (der_heim_oid_cmp((*check_altname[j].oid)(), + for (j = 0; j < sizeof(altname_types)/sizeof(altname_types[0]); j++) { + if (der_heim_oid_cmp(altname_types[j].oid, &gn.val[i].u.otherName.type_id) != 0) continue; validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ", - check_altname[j].name); - (*check_altname[j].func)(ctx, &gn.val[i].u.otherName.value); + altname_types[j].name); + (*altname_types[j].func)(ctx, &gn.val[i].u.otherName.value); break; } - if (j == sizeof(check_altname)/sizeof(check_altname[0])) { + if (j == sizeof(altname_types)/sizeof(altname_types[0])) { hx509_oid_print(&gn.val[i].u.otherName.type_id, validate_vprint, ctx); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown"); @@ -751,14 +750,14 @@ check_authorityInfoAccess(hx509_validate_ctx ctx, struct { const char *name; - const heim_oid *(*oid)(void); + const heim_oid *oid; int (*func)(hx509_validate_ctx ctx, struct cert_status *status, enum critical_flag cf, const Extension *); enum critical_flag cf; } check_extension[] = { -#define ext(name, checkname) #name, &oid_id_x509_ce_##name, check_##checkname +#define ext(name, checkname) #name, &asn1_oid_id_x509_ce_##name, check_##checkname { ext(subjectDirectoryAttributes, Null), M_N_C }, { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C }, { ext(keyUsage, Null), S_C }, @@ -782,13 +781,13 @@ struct { { ext(freshestCRL, Null), M_N_C }, { ext(inhibitAnyPolicy, Null), M_C }, #undef ext -#define ext(name, checkname) #name, &oid_id_pkix_pe_##name, check_##checkname +#define ext(name, checkname) #name, &asn1_oid_id_pkix_pe_##name, check_##checkname { ext(proxyCertInfo, proxyCertInfo), M_C }, { ext(authorityInfoAccess, authorityInfoAccess), M_C }, #undef ext - { "US Fed PKI - PIV Interim", oid_id_uspkicommon_piv_interim, + { "US Fed PKI - PIV Interim", &asn1_oid_id_uspkicommon_piv_interim, check_Null, D_C }, - { "Netscape cert comment", oid_id_netscape_cert_comment, + { "Netscape cert comment", &asn1_oid_id_netscape_cert_comment, check_Null, D_C }, { NULL } }; @@ -949,7 +948,7 @@ hx509_validate_cert(hx509_context context, for (i = 0; i < t->extensions->len; i++) { for (j = 0; check_extension[j].name; j++) - if (der_heim_oid_cmp((*check_extension[j].oid)(), + if (der_heim_oid_cmp(check_extension[j].oid, &t->extensions->val[i].extnID) == 0) break; if (check_extension[j].name == NULL) { diff --git a/source4/heimdal/lib/hx509/req.c b/source4/heimdal/lib/hx509/req.c index 9836777143..0d174e0cec 100644 --- a/source4/heimdal/lib/hx509/req.c +++ b/source4/heimdal/lib/hx509/req.c @@ -33,7 +33,6 @@ #include "hx_locl.h" #include <pkcs10_asn1.h> -RCSID("$Id$"); struct hx509_request_data { hx509_name name; diff --git a/source4/heimdal/lib/hx509/revoke.c b/source4/heimdal/lib/hx509/revoke.c index 3f35b0d190..adb31164c1 100644 --- a/source4/heimdal/lib/hx509/revoke.c +++ b/source4/heimdal/lib/hx509/revoke.c @@ -50,7 +50,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct revoke_crl { char *path; @@ -235,7 +234,7 @@ verify_ocsp(hx509_context context, } ret = hx509_cert_check_eku(context, signer, - oid_id_pkix_kp_OCSPSigning(), 0); + &asn1_oid_id_pkix_kp_OCSPSigning, 0); if (ret) goto out; } @@ -295,7 +294,7 @@ parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic) } ret = der_heim_oid_cmp(&resp.responseBytes->responseType, - oid_id_pkix_ocsp_basic()); + &asn1_oid_id_pkix_ocsp_basic); if (ret != 0) { free_OCSPResponse(&resp); return HX509_REVOKE_WRONG_DATA; @@ -1011,8 +1010,7 @@ hx509_ocsp_request(hx509_context context, goto out; } es->len = 1; - - ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID); + ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); if (ret) { free_OCSPRequest(&req); return ret; diff --git a/source4/heimdal/lib/hx509/sel-gram.y b/source4/heimdal/lib/hx509/sel-gram.y index e529479724..7f7c9980e0 100644 --- a/source4/heimdal/lib/hx509/sel-gram.y +++ b/source4/heimdal/lib/hx509/sel-gram.y @@ -39,7 +39,6 @@ #include <stdlib.h> #include <hx_locl.h> -RCSID("$Id$"); %} diff --git a/source4/heimdal/lib/hx509/test_name.c b/source4/heimdal/lib/hx509/test_name.c index da83e52786..2cdcdf85f6 100644 --- a/source4/heimdal/lib/hx509/test_name.c +++ b/source4/heimdal/lib/hx509/test_name.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); static int test_name(hx509_context context, const char *name) diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c index bd0a9846e4..0ecda99348 100644 --- a/source4/heimdal/lib/krb5/acache.c +++ b/source4/heimdal/lib/krb5/acache.c @@ -37,12 +37,8 @@ #include <dlfcn.h> #endif -RCSID("$Id$"); - -/* XXX should we fetch these for each open ? */ static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER; static cc_initialize_func init_func; - #ifdef HAVE_DLOPEN static void *cc_handle; #endif @@ -135,7 +131,7 @@ init_ccapi(krb5_context context) #else HEIMDAL_MUTEX_unlock(&acc_mutex); krb5_set_error_message(context, KRB5_CC_NOSUPP, - N_("no support for shared object", "file, error")); + N_("no support for shared object", "")); return KRB5_CC_NOSUPP; #endif } @@ -342,6 +338,7 @@ make_ccred_from_cred(krb5_context context, addr->length = incred->addresses.val[i].address.length; addr->data = malloc(addr->length); if (addr->data == NULL) { + free(addr); ret = ENOMEM; goto fail; } @@ -490,16 +487,23 @@ acc_resolve(krb5_context context, krb5_ccache *id, const char *res) error = (*a->context->func->open_ccache)(a->context, res, &a->ccache); if (error == ccNoError) { + cc_time_t offset; error = get_cc_name(a); if (error != ccNoError) { acc_close(context, *id); *id = NULL; return translate_cc_error(context, error); } + + error = (*a->ccache->func->get_kdc_time_offset)(a->ccache, + cc_credentials_v5, + &offset); + if (error == 0) + context->kdc_sec_offset = offset; + } else if (error == ccErrCCacheNotFound) { a->ccache = NULL; a->cache_name = NULL; - error = 0; } else { *id = NULL; return translate_cc_error(context, error); @@ -572,6 +576,11 @@ acc_initialize(krb5_context context, name); } + if (error == 0 && context->kdc_sec_offset) + error = (*a->ccache->func->set_kdc_time_offset)(a->ccache, + cc_credentials_v5, + context->kdc_sec_offset); + return translate_cc_error(context, error); } @@ -946,8 +955,10 @@ acc_move(krb5_context context, krb5_ccache from, krb5_ccache to) return translate_cc_error(context, error); } - error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache); + + acc_destroy(context, from); + return translate_cc_error(context, error); } diff --git a/source4/heimdal/lib/krb5/add_et_list.c b/source4/heimdal/lib/krb5/add_et_list.c index f08c0fe718..ccffd93b2c 100644 --- a/source4/heimdal/lib/krb5/add_et_list.c +++ b/source4/heimdal/lib/krb5/add_et_list.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Add a specified list of error messages to the et list in context. * Call func (probably a comerr-generated function) with a pointer to diff --git a/source4/heimdal/lib/krb5/addr_families.c b/source4/heimdal/lib/krb5/addr_families.c index 9e2fb3d63a..f88fb2276a 100644 --- a/source4/heimdal/lib/krb5/addr_families.c +++ b/source4/heimdal/lib/krb5/addr_families.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct addr_operations { int af; krb5_address_type atype; @@ -678,6 +676,9 @@ addrport_print_addr (const krb5_address *addr, char *str, size_t len) krb5_storage *sp; sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address)); + if (sp == NULL) + return ENOMEM; + /* for totally obscure reasons, these are not in network byteorder */ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); @@ -1142,10 +1143,12 @@ krb5_parse_address(krb5_context context, for (a = ai, i = 0; a != NULL; a = a->ai_next) { if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i])) continue; - if(krb5_address_search(context, &addresses->val[i], addresses)) + if(krb5_address_search(context, &addresses->val[i], addresses)) { + krb5_free_address(context, &addresses->val[i]); continue; - addresses->len = i; + } i++; + addresses->len = i; } freeaddrinfo (ai); return 0; @@ -1454,7 +1457,6 @@ krb5_make_addrport (krb5_context context, *p++ = (2 >> 24) & 0xFF; memcpy (p, &port, 2); - p += 2; return 0; } diff --git a/source4/heimdal/lib/krb5/appdefault.c b/source4/heimdal/lib/krb5/appdefault.c index d49fc4997a..383e82dad4 100644 --- a/source4/heimdal/lib/krb5/appdefault.c +++ b/source4/heimdal/lib/krb5/appdefault.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - void KRB5_LIB_FUNCTION krb5_appdefault_boolean(krb5_context context, const char *appname, krb5_const_realm realm, const char *option, diff --git a/source4/heimdal/lib/krb5/asn1_glue.c b/source4/heimdal/lib/krb5/asn1_glue.c index cb86c324fb..59c0fbd64b 100644 --- a/source4/heimdal/lib/krb5/asn1_glue.c +++ b/source4/heimdal/lib/krb5/asn1_glue.c @@ -37,8 +37,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION _krb5_principal2principalname (PrincipalName *p, const krb5_principal from) @@ -52,13 +50,23 @@ _krb5_principalname2krb5_principal (krb5_context context, const PrincipalName from, const Realm realm) { - krb5_principal p = malloc(sizeof(*p)); + krb5_error_code ret; + krb5_principal p; + + p = malloc(sizeof(*p)); if (p == NULL) return ENOMEM; - copy_PrincipalName(&from, &p->name); + ret = copy_PrincipalName(&from, &p->name); + if (ret) { + free(p); + return ret; + } p->realm = strdup(realm); - if (p->realm == NULL) + if (p->realm == NULL) { + free_PrincipalName(&p->name); + free(p); return ENOMEM; + } *principal = p; return 0; } diff --git a/source4/heimdal/lib/krb5/auth_context.c b/source4/heimdal/lib/krb5/auth_context.c index 66eccbbc07..bfc183d168 100644 --- a/source4/heimdal/lib/krb5/auth_context.c +++ b/source4/heimdal/lib/krb5/auth_context.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_auth_con_init(krb5_context context, krb5_auth_context *auth_context) diff --git a/source4/heimdal/lib/krb5/build_ap_req.c b/source4/heimdal/lib/krb5/build_ap_req.c index 92c03cb782..1550239faf 100644 --- a/source4/heimdal/lib/krb5/build_ap_req.c +++ b/source4/heimdal/lib/krb5/build_ap_req.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_build_ap_req (krb5_context context, krb5_enctype enctype, diff --git a/source4/heimdal/lib/krb5/build_auth.c b/source4/heimdal/lib/krb5/build_auth.c index bbf4f274af..bf77fd4e77 100644 --- a/source4/heimdal/lib/krb5/build_auth.c +++ b/source4/heimdal/lib/krb5/build_auth.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code make_etypelist(krb5_context context, krb5_authdata **auth_data) @@ -81,12 +79,14 @@ make_etypelist(krb5_context context, ALLOC(*auth_data, 1); if (*auth_data == NULL) { + free(buf); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } ALLOC_SEQ(*auth_data, 1); if ((*auth_data)->val == NULL) { + free(*auth_data); free(buf); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; diff --git a/source4/heimdal/lib/krb5/cache.c b/source4/heimdal/lib/krb5/cache.c index 80b755cd27..12097470d5 100644 --- a/source4/heimdal/lib/krb5/cache.c +++ b/source4/heimdal/lib/krb5/cache.c @@ -33,7 +33,70 @@ #include "krb5_locl.h" -RCSID("$Id$"); +/** + * @page krb5_ccache_intro The credential cache functions + * @section section_krb5_ccache Kerberos credential caches + * + * krb5_ccache structure holds a Kerberos credential cache. + * + * Heimdal support the follow types of credential caches: + * + * - SCC + * Store the credential in a database + * - FILE + * Store the credential in memory + * - MEMORY + * Store the credential in memory + * - API + * A credential cache server based solution for Mac OS X + * - KCM + * A credential cache server based solution for all platforms + * + * @subsection Example + * + * This is a minimalistic version of klist: +@code +#include <krb5.h> + +int +main (int argc, char **argv) +{ + krb5_context context; + krb5_cc_cursor cursor; + krb5_error_code ret; + krb5_ccache id; + krb5_creds creds; + + if (krb5_init_context (&context) != 0) + errx(1, "krb5_context"); + + ret = krb5_cc_default (context, &id); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_default"); + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); + + while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){ + char *principal; + + krb5_unparse_name_short(context, creds.server, &principal); + printf("principal: %s\\n", principal); + free(principal); + krb5_free_cred_contents (context, &creds); + } + ret = krb5_cc_end_seq_get(context, id, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_end_seq_get"); + + krb5_cc_close(context, id); + + krb5_free_context(context); + return 0; +} +* @endcode +*/ /** * Add a new ccache type with operations `ops', overwriting any @@ -176,23 +239,6 @@ krb5_cc_resolve(krb5_context context, } /** - * Generate a new ccache of type `ops' in `id'. - * - * @return Return an error code or 0, see krb5_get_error_message(). - * - * @ingroup krb5_ccache - */ - - -krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_gen_new(krb5_context context, - const krb5_cc_ops *ops, - krb5_ccache *id) -{ - return krb5_cc_new_unique(context, ops->prefix, NULL, id); -} - -/** * Generates a new unique ccache of `type` in `id'. If `type' is NULL, * the library chooses the default credential cache type. The supplied * `hint' (that can be NULL) is a string that the credential cache @@ -221,7 +267,12 @@ krb5_cc_new_unique(krb5_context context, const char *type, ret = _krb5_cc_allocate(context, ops, id); if (ret) return ret; - return (*id)->ops->gen_new(context, id); + ret = (*id)->ops->gen_new(context, id); + if (ret) { + free(*id); + *id = NULL; + } + return ret; } /** @@ -676,7 +727,7 @@ krb5_cc_get_principal(krb5_context context, /** * Start iterating over `id', `cursor' is initialized to the - * beginning. + * beginning. Caller must free the cursor with krb5_cc_end_seq_get(). * * @return Return an error code or 0, see krb5_get_error_message(). * @@ -712,32 +763,6 @@ krb5_cc_next_cred (krb5_context context, } /** - * Like krb5_cc_next_cred, but allow for selective retrieval - * - * @ingroup krb5_ccache - */ - - -krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_next_cred_match(krb5_context context, - const krb5_ccache id, - krb5_cc_cursor * cursor, - krb5_creds * creds, - krb5_flags whichfields, - const krb5_creds * mcreds) -{ - krb5_error_code ret; - while (1) { - ret = krb5_cc_next_cred(context, id, cursor, creds); - if (ret) - return ret; - if (mcreds == NULL || krb5_compare_creds(context, whichfields, mcreds, creds)) - return 0; - krb5_free_cred_contents(context, creds); - } -} - -/** * Destroy the cursor `cursor'. * * @ingroup krb5_ccache @@ -806,25 +831,37 @@ krb5_cc_get_flags(krb5_context context, } /** - * Copy the contents of `from' to `to'. + * Copy the contents of `from' to `to' if the given match function + * return true. + * + * @param context A Kerberos 5 context. + * @param from the cache to copy data from. + * @param to the cache to copy data to. + * @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied. + * @param matchctx context passed to match function. + * @param matched set to true if there was a credential that matched, may be NULL. + * + * @return Return an error code or 0, see krb5_get_error_message(). * * @ingroup krb5_ccache */ - krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_copy_cache_match(krb5_context context, - const krb5_ccache from, - krb5_ccache to, - krb5_flags whichfields, - const krb5_creds * mcreds, - unsigned int *matched) +krb5_cc_copy_match_f(krb5_context context, + const krb5_ccache from, + krb5_ccache to, + krb5_boolean (*match)(krb5_context, void *, const krb5_creds *), + void *matchctx, + unsigned int *matched) { krb5_error_code ret; krb5_cc_cursor cursor; krb5_creds cred; krb5_principal princ; + if (matched) + *matched = 0; + ret = krb5_cc_get_principal(context, from, &princ); if (ret) return ret; @@ -838,24 +875,26 @@ krb5_cc_copy_cache_match(krb5_context context, krb5_free_principal(context, princ); return ret; } - if (matched) - *matched = 0; - while (ret == 0 && - krb5_cc_next_cred_match(context, from, &cursor, &cred, - whichfields, mcreds) == 0) { - if (matched) - (*matched)++; - ret = krb5_cc_store_cred(context, to, &cred); - krb5_free_cred_contents(context, &cred); + + while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) { + if (match == NULL || (*match)(context, matchctx, &cred) == 0) { + if (matched) + (*matched)++; + ret = krb5_cc_store_cred(context, to, &cred); + if (ret) + break; + } + krb5_free_cred_contents(context, &cred); } krb5_cc_end_seq_get(context, from, &cursor); krb5_free_principal(context, princ); + if (ret == KRB5_CC_END) + ret = 0; return ret; } - /** - * Just like krb5_cc_copy_cache_match, but copy everything. + * Just like krb5_cc_copy_match_f(), but copy everything. * * @ingroup @krb5_ccache */ @@ -865,21 +904,7 @@ krb5_cc_copy_cache(krb5_context context, const krb5_ccache from, krb5_ccache to) { - return krb5_cc_copy_cache_match(context, from, to, 0, NULL, NULL); -} - -/** - * MIT compat glue - * - * @ingroup krb5_ccache - */ - -krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_copy_creds(krb5_context context, - const krb5_ccache from, - krb5_ccache to) -{ - return krb5_cc_copy_cache(context, from, to); + return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL); } /** @@ -1057,10 +1082,14 @@ krb5_cc_cache_end_seq_get (krb5_context context, } /** - * Search for a matching credential cache of type `type' that have the + * Search for a matching credential cache that have the * `principal' as the default principal. On success, `id' needs to be * freed with krb5_cc_close() or krb5_cc_destroy(). * + * @param context A Kerberos 5 context + * @param client The principal to search for + * @param id the returned credential cache + * * @return On failure, error code is returned and `id' is set to NULL. * * @ingroup krb5_ccache @@ -1082,7 +1111,7 @@ krb5_cc_cache_match (krb5_context context, if (ret) return ret; - while ((ret = krb5_cccol_cursor_next (context, cursor, &cache)) == 0) { + while (krb5_cccol_cursor_next (context, cursor, &cache) == 0 && cache != NULL) { krb5_principal principal; ret = krb5_cc_get_principal(context, cache, &principal); @@ -1107,7 +1136,7 @@ krb5_cc_cache_match (krb5_context context, krb5_unparse_name(context, client, &str); krb5_set_error_message(context, KRB5_CC_NOTFOUND, - N_("Principal %s not found in a " + N_("Principal %s not found in any " "credential cache", ""), str ? str : "<out of memory>"); if (str) @@ -1178,7 +1207,7 @@ build_conf_principals(krb5_context context, krb5_ccache id, } ret = krb5_make_principal(context, &cred->server, - krb5_principal_get_realm(context, client), + KRB5_REALM_NAME, KRB5_CONF_NAME, name, pname, NULL); free(pname); if (ret) { @@ -1224,7 +1253,7 @@ krb5_is_config_principal(krb5_context context, * @param principal configuration for a specific principal, if * NULL, global for the whole cache. * @param name name under which the configuraion is stored. - * @param data data to store + * @param data data to store, if NULL, configure is removed. * * @ingroup krb5_ccache */ @@ -1246,15 +1275,17 @@ krb5_cc_set_config(krb5_context context, krb5_ccache id, if (ret && ret != KRB5_CC_NOTFOUND) goto out; - /* not that anyone care when this expire */ - cred.times.authtime = time(NULL); - cred.times.endtime = cred.times.authtime + 3600 * 24 * 30; - - ret = krb5_data_copy(&cred.ticket, data->data, data->length); - if (ret) - goto out; - - ret = krb5_cc_store_cred(context, id, &cred); + if (data) { + /* not that anyone care when this expire */ + cred.times.authtime = time(NULL); + cred.times.endtime = cred.times.authtime + 3600 * 24 * 30; + + ret = krb5_data_copy(&cred.ticket, data->data, data->length); + if (ret) + goto out; + + ret = krb5_cc_store_cred(context, id, &cred); + } out: krb5_free_cred_contents (context, &cred); @@ -1345,6 +1376,8 @@ krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor) * @param cache the returned cursor, pointer is set to NULL on failure * and a cache on success. The returned cache needs to be freed * with krb5_cc_close() or destroyed with krb5_cc_destroy(). + * MIT Kerberos behavies slightly diffrent and sets cache to NULL + * when all caches are iterated over and return 0. * * @return Return 0 or and error, KRB5_CC_END is returned at the end * of iteration. See krb5_get_error_message(). @@ -1446,7 +1479,7 @@ krb5_cc_last_change_time(krb5_context context, * and mtime is 0, there was no credentials in the caches. * * @param context A Kerberos 5 context - * @param id The credential cache to probe + * @param type The credential cache to probe, if NULL, all type are traversed. * @param mtime the last modification time, set to 0 on error. * @return Return 0 or and error. See krb5_get_error_message(). @@ -1470,7 +1503,7 @@ krb5_cccol_last_change_time(krb5_context context, if (ret) return ret; - while ((ret = krb5_cccol_cursor_next (context, cursor, &id)) == 0) { + while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) { if (type && strcmp(krb5_cc_get_type(context, id), type) != 0) continue; @@ -1487,3 +1520,106 @@ krb5_cccol_last_change_time(krb5_context context, return 0; } +/** + * Return a friendly name on credential cache. Free the result with krb5_xfree(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_get_friendly_name(krb5_context context, + krb5_ccache id, + char **name) +{ + krb5_error_code ret; + krb5_data data; + + ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data); + if (ret) { + krb5_principal principal; + ret = krb5_cc_get_principal(context, id, &principal); + if (ret) + return ret; + ret = krb5_unparse_name(context, principal, name); + krb5_free_principal(context, principal); + } else { + ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data); + krb5_data_free(&data); + if (ret <= 0) { + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + } else + ret = 0; + } + + return ret; +} + +/** + * Set the friendly name on credential cache. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_set_friendly_name(krb5_context context, + krb5_ccache id, + const char *name) +{ + krb5_data data; + + data.data = rk_UNCONST(name); + data.length = strlen(name); + + return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data); +} + +/** + * Get the lifetime of the initial ticket in the cache + * + * Get the lifetime of the initial ticket in the cache, if the initial + * ticket was not found, the error code KRB5_CC_END is returned. + * + * @param context A Kerberos 5 context. + * @param id a credential cache + * @param t the relative lifetime of the initial ticket + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t) +{ + krb5_cc_cursor cursor; + krb5_error_code ret; + krb5_creds cred; + time_t now; + + *t = 0; + now = time(NULL); + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) + return ret; + + while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) { + if (cred.flags.b.initial) { + if (now < cred.times.endtime) + *t = cred.times.endtime - now; + krb5_free_cred_contents(context, &cred); + goto out; + } + krb5_free_cred_contents(context, &cred); + } + + out: + krb5_cc_end_seq_get(context, id, &cursor); + + return ret; +} diff --git a/source4/heimdal/lib/krb5/changepw.c b/source4/heimdal/lib/krb5/changepw.c index 91ed9c5ba0..207b86b488 100644 --- a/source4/heimdal/lib/krb5/changepw.c +++ b/source4/heimdal/lib/krb5/changepw.c @@ -31,9 +31,9 @@ * SUCH DAMAGE. */ -#include <krb5_locl.h> +#define KRB5_DEPRECATED -RCSID("$Id$"); +#include <krb5_locl.h> #undef __attribute__ #define __attribute__(X) @@ -82,7 +82,6 @@ chgpw_send_request (krb5_context context, krb5_data passwd_data; size_t len; u_char header[6]; - u_char *p; struct iovec iov[3]; struct msghdr msghdr; @@ -118,13 +117,12 @@ chgpw_send_request (krb5_context context, goto out2; len = 6 + ap_req_data.length + krb_priv_data.length; - p = header; - *p++ = (len >> 8) & 0xFF; - *p++ = (len >> 0) & 0xFF; - *p++ = 0; - *p++ = 1; - *p++ = (ap_req_data.length >> 8) & 0xFF; - *p++ = (ap_req_data.length >> 0) & 0xFF; + header[0] = (len >> 8) & 0xFF; + header[1] = (len >> 0) & 0xFF; + header[2] = 0; + header[3] = 1; + header[4] = (ap_req_data.length >> 8) & 0xFF; + header[5] = (ap_req_data.length >> 0) & 0xFF; memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = NULL; @@ -231,7 +229,7 @@ setpw_send_request (krb5_context context, *p++ = 0xff; *p++ = 0x80; *p++ = (ap_req_data.length >> 8) & 0xFF; - *p++ = (ap_req_data.length >> 0) & 0xFF; + *p = (ap_req_data.length >> 0) & 0xFF; memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = NULL; @@ -693,7 +691,7 @@ krb5_change_password (krb5_context context, int *result_code, krb5_data *result_code_string, krb5_data *result_string) - __attribute__((deprecated)) + KRB5_DEPRECATED { struct kpwd_proc *p = find_chpw_proto("change password"); @@ -711,7 +709,7 @@ krb5_change_password (krb5_context context, #endif /* HEIMDAL_SMALLER */ /** - * Change passwrod using creds. + * Change password using creds. * * @param context a Keberos context * @param creds The initial kadmin/passwd for the principal or an admin principal @@ -767,8 +765,6 @@ krb5_set_password(krb5_context context, return ret; } -#ifndef HEIMDAL_SMALLER - /* * */ @@ -834,8 +830,6 @@ krb5_set_password_using_ccache(krb5_context context, return ret; } -#endif /* !HEIMDAL_SMALLER */ - /* * */ diff --git a/source4/heimdal/lib/krb5/codec.c b/source4/heimdal/lib/krb5/codec.c index bd0dcc5371..ebda3e51f7 100644 --- a/source4/heimdal/lib/krb5/codec.c +++ b/source4/heimdal/lib/krb5/codec.c @@ -31,12 +31,9 @@ * SUCH DAMAGE. */ -#include "krb5_locl.h" - -#undef __attribute__ -#define __attribute__(x) +#define KRB5_DEPRECATED -RCSID("$Id$"); +#include "krb5_locl.h" #ifndef HEIMDAL_SMALLER @@ -46,7 +43,7 @@ krb5_decode_EncTicketPart (krb5_context context, size_t length, EncTicketPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncTicketPart(data, length, t, len); } @@ -57,7 +54,7 @@ krb5_encode_EncTicketPart (krb5_context context, size_t length, EncTicketPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncTicketPart(data, length, t, len); } @@ -68,7 +65,7 @@ krb5_decode_EncASRepPart (krb5_context context, size_t length, EncASRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncASRepPart(data, length, t, len); } @@ -79,7 +76,7 @@ krb5_encode_EncASRepPart (krb5_context context, size_t length, EncASRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncASRepPart(data, length, t, len); } @@ -90,7 +87,7 @@ krb5_decode_EncTGSRepPart (krb5_context context, size_t length, EncTGSRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncTGSRepPart(data, length, t, len); } @@ -101,7 +98,7 @@ krb5_encode_EncTGSRepPart (krb5_context context, size_t length, EncTGSRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncTGSRepPart(data, length, t, len); } @@ -112,7 +109,7 @@ krb5_decode_EncAPRepPart (krb5_context context, size_t length, EncAPRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncAPRepPart(data, length, t, len); } @@ -123,7 +120,7 @@ krb5_encode_EncAPRepPart (krb5_context context, size_t length, EncAPRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncAPRepPart(data, length, t, len); } @@ -134,7 +131,7 @@ krb5_decode_Authenticator (krb5_context context, size_t length, Authenticator *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_Authenticator(data, length, t, len); } @@ -145,7 +142,7 @@ krb5_encode_Authenticator (krb5_context context, size_t length, Authenticator *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_Authenticator(data, length, t, len); } @@ -156,7 +153,7 @@ krb5_decode_EncKrbCredPart (krb5_context context, size_t length, EncKrbCredPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncKrbCredPart(data, length, t, len); } @@ -167,7 +164,7 @@ krb5_encode_EncKrbCredPart (krb5_context context, size_t length, EncKrbCredPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncKrbCredPart (data, length, t, len); } @@ -178,7 +175,7 @@ krb5_decode_ETYPE_INFO (krb5_context context, size_t length, ETYPE_INFO *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_ETYPE_INFO(data, length, t, len); } @@ -189,7 +186,7 @@ krb5_encode_ETYPE_INFO (krb5_context context, size_t length, ETYPE_INFO *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_ETYPE_INFO (data, length, t, len); } @@ -200,7 +197,7 @@ krb5_decode_ETYPE_INFO2 (krb5_context context, size_t length, ETYPE_INFO2 *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_ETYPE_INFO2(data, length, t, len); } @@ -211,7 +208,7 @@ krb5_encode_ETYPE_INFO2 (krb5_context context, size_t length, ETYPE_INFO2 *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_ETYPE_INFO2 (data, length, t, len); } diff --git a/source4/heimdal/lib/krb5/config_file.c b/source4/heimdal/lib/krb5/config_file.c index 75c48a001b..ee226c78a2 100644 --- a/source4/heimdal/lib/krb5/config_file.c +++ b/source4/heimdal/lib/krb5/config_file.c @@ -32,9 +32,6 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); - -#ifndef HAVE_NETINFO /* Gaah! I want a portable funopen */ struct fileptr { @@ -302,21 +299,65 @@ krb5_config_parse_string_multi(krb5_context context, return 0; } +/** + * Parse a configuration file and add the result into res. This + * interface can be used to parse several configuration files into one + * resulting krb5_config_section by calling it repeatably. + * + * @param context a Kerberos 5 context. + * @param fname a file name to a Kerberos configuration file + * @param res the returned result, must be free with krb5_free_config_files(). + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_config_parse_file_multi (krb5_context context, const char *fname, krb5_config_section **res) { const char *str; + char *newfname = NULL; unsigned lineno = 0; krb5_error_code ret; struct fileptr f; + + /** + * If the fname starts with "~/" parse configuration file in the + * current users home directory. The behavior can be disabled and + * enabled by calling krb5_set_home_dir_access(). + */ + if (_krb5_homedir_access(context) && fname[0] == '~' && fname[1] == '/') { + const char *home = NULL; + + if(!issuid()) + home = getenv("HOME"); + + if (home == NULL) { + struct passwd *pw = getpwuid(getuid()); + if(pw != NULL) + home = pw->pw_dir; + } + if (home) { + asprintf(&newfname, "%s%s", home, &fname[1]); + if (newfname == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + fname = newfname; + } + } + f.f = fopen(fname, "r"); f.s = NULL; if(f.f == NULL) { ret = errno; krb5_set_error_message (context, ret, "open %s: %s", fname, strerror(ret)); + if (newfname) + free(newfname); return ret; } @@ -324,8 +365,12 @@ krb5_config_parse_file_multi (krb5_context context, fclose(f.f); if (ret) { krb5_set_error_message (context, ret, "%s:%u: %s", fname, lineno, str); + if (newfname) + free(newfname); return ret; } + if (newfname) + free(newfname); return 0; } @@ -338,8 +383,6 @@ krb5_config_parse_file (krb5_context context, return krb5_config_parse_file_multi(context, fname, res); } -#endif /* !HAVE_NETINFO */ - static void free_binding (krb5_context context, krb5_config_binding *b) { diff --git a/source4/heimdal/lib/krb5/config_file_netinfo.c b/source4/heimdal/lib/krb5/config_file_netinfo.c deleted file mode 100644 index e6993bbb4a..0000000000 --- a/source4/heimdal/lib/krb5/config_file_netinfo.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "krb5_locl.h" -RCSID("$Id$"); - -/* - * Netinfo implementation from Luke Howard <lukeh@xedoc.com.au> - */ - -#ifdef HAVE_NETINFO -#include <netinfo/ni.h> -static ni_status -ni_proplist2binding(ni_proplist *pl, krb5_config_section **ret) -{ - int i, j; - krb5_config_section **next = NULL; - - for (i = 0; i < pl->ni_proplist_len; i++) { - if (!strcmp(pl->nipl_val[i].nip_name, "name")) - continue; - - for (j = 0; j < pl->nipl_val[i].nip_val.ni_namelist_len; j++) { - krb5_config_binding *b; - - b = malloc(sizeof(*b)); - if (b == NULL) - return NI_FAILED; - - b->next = NULL; - b->type = krb5_config_string; - b->name = ni_name_dup(pl->nipl_val[i].nip_name); - b->u.string = ni_name_dup(pl->nipl_val[i].nip_val.ninl_val[j]); - - if (next == NULL) { - *ret = b; - } else { - *next = b; - } - next = &b->next; - } - } - return NI_OK; -} - -static ni_status -ni_idlist2binding(void *ni, ni_idlist *idlist, krb5_config_section **ret) -{ - int i; - ni_status nis; - krb5_config_section **next; - - for (i = 0; i < idlist->ni_idlist_len; i++) { - ni_proplist pl; - ni_id nid; - ni_idlist children; - krb5_config_binding *b; - ni_index index; - - nid.nii_instance = 0; - nid.nii_object = idlist->ni_idlist_val[i]; - - nis = ni_read(ni, &nid, &pl); - - if (nis != NI_OK) { - return nis; - } - index = ni_proplist_match(pl, "name", NULL); - b = malloc(sizeof(*b)); - if (b == NULL) return NI_FAILED; - - if (i == 0) { - *ret = b; - } else { - *next = b; - } - - b->type = krb5_config_list; - b->name = ni_name_dup(pl.nipl_val[index].nip_val.ninl_val[0]); - b->next = NULL; - b->u.list = NULL; - - /* get the child directories */ - nis = ni_children(ni, &nid, &children); - if (nis == NI_OK) { - nis = ni_idlist2binding(ni, &children, &b->u.list); - if (nis != NI_OK) { - return nis; - } - } - - nis = ni_proplist2binding(&pl, b->u.list == NULL ? &b->u.list : &b->u.list->next); - ni_proplist_free(&pl); - if (nis != NI_OK) { - return nis; - } - next = &b->next; - } - ni_idlist_free(idlist); - return NI_OK; -} - -krb5_error_code KRB5_LIB_FUNCTION -krb5_config_parse_file (krb5_context context, - const char *fname, - krb5_config_section **res) -{ - void *ni = NULL, *lastni = NULL; - int i; - ni_status nis; - ni_id nid; - ni_idlist children; - - krb5_config_section *s; - int ret; - - s = NULL; - - for (i = 0; i < 256; i++) { - if (i == 0) { - nis = ni_open(NULL, ".", &ni); - } else { - if (lastni != NULL) ni_free(lastni); - lastni = ni; - nis = ni_open(lastni, "..", &ni); - } - if (nis != NI_OK) - break; - nis = ni_pathsearch(ni, &nid, "/locations/kerberos"); - if (nis == NI_OK) { - nis = ni_children(ni, &nid, &children); - if (nis != NI_OK) - break; - nis = ni_idlist2binding(ni, &children, &s); - break; - } - } - - if (ni != NULL) ni_free(ni); - if (ni != lastni && lastni != NULL) ni_free(lastni); - - ret = (nis == NI_OK) ? 0 : -1; - if (ret == 0) { - *res = s; - } else { - *res = NULL; - } - return ret; -} -#endif /* HAVE_NETINFO */ diff --git a/source4/heimdal/lib/krb5/constants.c b/source4/heimdal/lib/krb5/constants.c index b41fb3f663..a3b3d09f41 100644 --- a/source4/heimdal/lib/krb5/constants.c +++ b/source4/heimdal/lib/krb5/constants.c @@ -33,11 +33,16 @@ #include "krb5_locl.h" -RCSID("$Id$"); - KRB5_LIB_VARIABLE const char *krb5_config_file = #ifdef __APPLE__ +"~/Library/Preferences/edu.mit.Kerberos:" "/Library/Preferences/edu.mit.Kerberos:" #endif SYSCONFDIR "/krb5.conf:/etc/krb5.conf"; KRB5_LIB_VARIABLE const char *krb5_defkeyname = KEYTAB_DEFAULT; + +KRB5_LIB_VARIABLE const char *krb5_cc_type_api = "API"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_file = "FILE"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_memory = "MEMORY"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_kcm = "KCM"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_scc = "SCC"; diff --git a/source4/heimdal/lib/krb5/context.c b/source4/heimdal/lib/krb5/context.c index 127dfa117d..fe94135030 100644 --- a/source4/heimdal/lib/krb5/context.c +++ b/source4/heimdal/lib/krb5/context.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <com_err.h> -RCSID("$Id$"); - #define INIT_FIELD(C, T, E, D, F) \ (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \ "libdefaults", F, NULL) @@ -243,9 +241,7 @@ cc_ops_register(krb5_context context) krb5_cc_register(context, &krb5_acc_ops, TRUE); krb5_cc_register(context, &krb5_fcc_ops, TRUE); krb5_cc_register(context, &krb5_mcc_ops, TRUE); -#ifdef HAVE_SQLITE krb5_cc_register(context, &krb5_scc_ops, TRUE); -#endif #ifdef HAVE_KCM krb5_cc_register(context, &krb5_kcm_ops, TRUE); #endif @@ -310,6 +306,8 @@ krb5_init_context(krb5_context *context) } HEIMDAL_MUTEX_init(p->mutex); + p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; + ret = krb5_get_default_config_files(&files); if(ret) goto out; @@ -336,7 +334,7 @@ out: * Make a copy for the Kerberos 5 context, allocated krb5_contex shoud * be freed with krb5_free_context(). * - * @param in the Kerberos context to copy + * @param context the Kerberos context to copy * @param out the copy of the Kerberos, set to NULL error. * * @return Returns 0 to indicate success. Otherwise an kerberos et @@ -453,10 +451,10 @@ krb5_free_context(krb5_context context) krb5_set_extra_addresses(context, NULL); krb5_set_ignore_addresses(context, NULL); krb5_set_send_to_kdc_func(context, NULL, NULL); - if (context->mutex != NULL) { - HEIMDAL_MUTEX_destroy(context->mutex); - free(context->mutex); - } + + HEIMDAL_MUTEX_destroy(context->mutex); + free(context->mutex); + memset(context, 0, sizeof(*context)); free(context); } @@ -552,7 +550,7 @@ krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp) krb5_free_config_files(pp); return ENOMEM; } - l = strsep_copy(&p, ":", fn, l + 1); + (void)strsep_copy(&p, ":", fn, l + 1); ret = add_file(&pp, &len, fn); if (ret) { krb5_free_config_files(pp); @@ -641,7 +639,8 @@ krb5_get_default_config_files(char ***pfilenames) /** * Free a list of configuration files. * - * @param filenames list to be freed. + * @param filenames list, terminated with a NULL pointer, to be + * freed. NULL is an valid argument. * * @return Returns 0 to indicate success. Otherwise an kerberos et * error code is returned, see krb5_get_error_message(). @@ -653,7 +652,7 @@ void KRB5_LIB_FUNCTION krb5_free_config_files(char **filenames) { char **p; - for(p = filenames; *p != NULL; p++) + for(p = filenames; p && *p != NULL; p++) free(*p); free(filenames); } @@ -1226,3 +1225,115 @@ krb5_set_max_time_skew (krb5_context context, time_t t) { context->max_skew = t; } + +/** + * Init encryption types in len, val with etypes. + * + * @param context Kerberos 5 context. + * @param len output length of val. + * @param val output array of enctypes. + * @param etypes etypes to set val and len to, if NULL, use default enctypes. + + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_etype (krb5_context context, + unsigned *len, + krb5_enctype **val, + const krb5_enctype *etypes) +{ + unsigned int i; + krb5_error_code ret; + krb5_enctype *tmp = NULL; + + ret = 0; + if (etypes == NULL) { + ret = krb5_get_default_in_tkt_etypes(context, &tmp); + if (ret) + return ret; + etypes = tmp; + } + + for (i = 0; etypes[i]; ++i) + ; + *len = i; + *val = malloc(i * sizeof(**val)); + if (i != 0 && *val == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto cleanup; + } + memmove (*val, + etypes, + i * sizeof(*tmp)); +cleanup: + if (tmp != NULL) + free (tmp); + return ret; +} + +/* + * Allow homedir accces + */ + +static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER; +static krb5_boolean allow_homedir = TRUE; + +krb5_boolean +_krb5_homedir_access(krb5_context context) +{ + krb5_boolean allow; + + /* is never allowed for root */ + if (geteuid() == 0) + return FALSE; + + if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0) + return FALSE; + + HEIMDAL_MUTEX_lock(&homedir_mutex); + allow = allow_homedir; + HEIMDAL_MUTEX_unlock(&homedir_mutex); + return allow; +} + +/** + * Enable and disable home directory access on either the global state + * or the krb5_context state. By calling krb5_set_home_dir_access() + * with context set to NULL, the global state is configured otherwise + * the state for the krb5_context is modified. + * + * For home directory access to be allowed, both the global state and + * the krb5_context state have to be allowed. + * + * Administrator (root user), never uses the home directory. + * + * @param context a Kerberos 5 context or NULL + * @param allow allow if TRUE home directory + * @return the old value + * + */ + +krb5_boolean +krb5_set_home_dir_access(krb5_context context, krb5_boolean allow) +{ + krb5_boolean old; + if (context) { + old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE; + if (allow) + context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; + else + context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS; + } else { + HEIMDAL_MUTEX_lock(&homedir_mutex); + old = allow_homedir; + allow_homedir = allow; + HEIMDAL_MUTEX_unlock(&homedir_mutex); + } + + return old; +} diff --git a/source4/heimdal/lib/krb5/convert_creds.c b/source4/heimdal/lib/krb5/convert_creds.c index fc81d96bec..35454bf983 100644 --- a/source4/heimdal/lib/krb5/convert_creds.c +++ b/source4/heimdal/lib/krb5/convert_creds.c @@ -32,10 +32,10 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); - #include "krb5-v4compat.h" +#ifndef HEIMDAL_SMALLER + static krb5_error_code check_ticket_flags(TicketFlags f) { @@ -204,3 +204,5 @@ krb524_convert_creds_kdc_ccache(krb5_context context, krb5_free_creds (context, v5_creds); return ret; } + +#endif diff --git a/source4/heimdal/lib/krb5/copy_host_realm.c b/source4/heimdal/lib/krb5/copy_host_realm.c index 37e27110b6..7f19ddd3de 100644 --- a/source4/heimdal/lib/krb5/copy_host_realm.c +++ b/source4/heimdal/lib/krb5/copy_host_realm.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Copy the list of realms from `from' to `to'. * diff --git a/source4/heimdal/lib/krb5/crc.c b/source4/heimdal/lib/krb5/crc.c index a900cabbba..eab946541d 100644 --- a/source4/heimdal/lib/krb5/crc.c +++ b/source4/heimdal/lib/krb5/crc.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - static u_long table[256]; #define CRC_GEN 0xEDB88320L diff --git a/source4/heimdal/lib/krb5/creds.c b/source4/heimdal/lib/krb5/creds.c index 087a4850eb..26c0dfbecb 100644 --- a/source4/heimdal/lib/krb5/creds.c +++ b/source4/heimdal/lib/krb5/creds.c @@ -33,23 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - -#undef __attribute__ -#define __attribute__(X) - -#ifndef HEIMDAL_SMALLER - -/* keep this for compatibility with older code */ -krb5_error_code KRB5_LIB_FUNCTION -krb5_free_creds_contents (krb5_context context, krb5_creds *c) - __attribute__((deprecated)) -{ - return krb5_free_cred_contents (context, c); -} - -#endif /* HEIMDAL_SMALLER */ - /** * Free content of krb5_creds. * @@ -235,9 +218,7 @@ krb5_compare_creds(krb5_context context, krb5_flags whichfields, } if (match && (whichfields & KRB5_TC_MATCH_KEYTYPE)) - match = krb5_enctypes_compatible_keys(context, - mcreds->session.keytype, - creds->session.keytype); + match = mcreds->session.keytype == creds->session.keytype; if (match && (whichfields & KRB5_TC_MATCH_FLAGS_EXACT)) match = mcreds->flags.i == creds->flags.i; diff --git a/source4/heimdal/lib/krb5/crypto.c b/source4/heimdal/lib/krb5/crypto.c index bc6512cf1a..9fd2117345 100644 --- a/source4/heimdal/lib/krb5/crypto.c +++ b/source4/heimdal/lib/krb5/crypto.c @@ -31,13 +31,11 @@ * SUCH DAMAGE. */ +#define KRB5_DEPRECATED + #include "krb5_locl.h" -RCSID("$Id$"); #include <pkinit_asn1.h> -#undef __attribute__ -#define __attribute__(X) - #define WEAK_ENCTYPES 1 #ifndef HEIMDAL_SMALLER @@ -164,6 +162,9 @@ static krb5_error_code hmac(krb5_context context, static void free_key_data(krb5_context, struct key_data *, struct encryption_type *); +static void free_key_schedule(krb5_context, + struct key_data *, + struct encryption_type *); static krb5_error_code usage2arcfour (krb5_context, unsigned *); static void xor (DES_cblock *, const unsigned char *); @@ -1158,7 +1159,16 @@ _key_schedule(krb5_context context, { krb5_error_code ret; struct encryption_type *et = _find_enctype(key->key->keytype); - struct key_type *kt = et->keytype; + struct key_type *kt; + + if (et == NULL) { + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + key->key->keytype); + return KRB5_PROG_ETYPE_NOSUPP; + } + + kt = et->keytype; if(kt->schedule == NULL) return 0; @@ -1841,14 +1851,25 @@ verify_checksum(krb5_context context, return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */ } keyed_checksum = (ct->flags & F_KEYED) != 0; - if(keyed_checksum && crypto == NULL) { - krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, - N_("Checksum type %s is keyed but no " - "crypto context (key) was passed in", ""), - ct->name); - return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ - } if(keyed_checksum) { + struct checksum_type *kct; + if (crypto == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("Checksum type %s is keyed but no " + "crypto context (key) was passed in", ""), + ct->name); + return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ + } + kct = crypto->et->keyed_checksum; + if (kct != NULL && kct->type != ct->type) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("Checksum type %s is keyed, but " + "the key type %s passed didnt have that checksum " + "type as the keyed type", ""), + ct->name, crypto->et->name); + return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ + } + ret = get_checksum_key(context, crypto, usage, ct, &dkey); if (ret) return ret; @@ -2348,10 +2369,11 @@ AES_PRF(krb5_context context, { const EVP_CIPHER *c = (*crypto->et->keytype->evp)(); EVP_CIPHER_CTX ctx; - /* XXX blksz 1 for cts, so we can't use that */ + EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */ EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1); - EVP_Cipher(&ctx, out->data, result.checksum.data, 16); + EVP_Cipher(&ctx, out->data, result.checksum.data, + crypto->et->blocksize); EVP_CIPHER_CTX_cleanup(&ctx); } @@ -2737,17 +2759,6 @@ krb5_cksumtype_valid(krb5_context context, } -/* if two enctypes have compatible keys */ -krb5_boolean KRB5_LIB_FUNCTION -krb5_enctypes_compatible_keys(krb5_context context, - krb5_enctype etype1, - krb5_enctype etype2) -{ - struct encryption_type *e1 = _find_enctype(etype1); - struct encryption_type *e2 = _find_enctype(etype2); - return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; -} - static krb5_boolean derived_crypto(krb5_context context, krb5_crypto crypto) @@ -3147,10 +3158,10 @@ find_iv(krb5_crypto_iov *data, int num_data, int type) * Kerberos encrypted data look like this: * * 1. KRB5_CRYPTO_TYPE_HEADER - * 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in - * any order, however the receiver have to aware of the - * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used headers and - * trailers. + * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...] + * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver + * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is + * commonly used headers and trailers. * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1 * 4. KRB5_CRYPTO_TYPE_TRAILER */ @@ -3160,17 +3171,23 @@ krb5_encrypt_iov_ivec(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + int num_data, void *ivec) { size_t headersz, trailersz, len; - size_t i, sz, block_sz, pad_sz; + int i; + size_t sz, block_sz, pad_sz; Checksum cksum; unsigned char *p, *q; krb5_error_code ret; struct key_data *dkey; const struct encryption_type *et = crypto->et; - krb5_crypto_iov *tiv, *piv, *hiv; + krb5_crypto_iov *tiv, *piv, *hiv, *div; + + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } if(!derived_crypto(context, crypto)) { krb5_clear_error_message(context); @@ -3180,18 +3197,16 @@ krb5_encrypt_iov_ivec(krb5_context context, headersz = et->confoundersize; trailersz = CHECKSUMSIZE(et->keyed_checksum); - for (len = 0, i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER && - data[i].flags == KRB5_CRYPTO_TYPE_DATA) { - len += data[i].data.length; - } - } + div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA); + if (div == NULL) + return KRB5_CRYPTO_INTERNAL; + + len = div->data.length; sz = headersz + len; block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ pad_sz = block_sz - sz; - trailersz += pad_sz; /* header */ @@ -3278,13 +3293,9 @@ krb5_encrypt_iov_ivec(krb5_context context, /* XXX replace with EVP_Cipher */ - len = hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_PADDING) - continue; - len += data[i].data.length; - } + len = hiv->data.length + div->data.length; + if (piv) + len += piv->data.length; p = q = malloc(len); if(p == NULL) @@ -3292,13 +3303,9 @@ krb5_encrypt_iov_ivec(krb5_context context, memcpy(q, hiv->data.data, hiv->data.length); q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_PADDING) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; - } + memcpy(q, div->data.data, div->data.length); + q += div->data.length; + memset(q, 0, pad_sz); ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); if(ret) { @@ -3319,16 +3326,15 @@ krb5_encrypt_iov_ivec(krb5_context context, /* now copy data back to buffers */ q = p; + memcpy(hiv->data.data, q, hiv->data.length); q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_PADDING) - continue; - memcpy(data[i].data.data, q, data[i].data.length); - q += data[i].data.length; - } + memcpy(div->data.data, q, div->data.length); + q += div->data.length; + + if (piv) + memcpy(piv->data.data, q, pad_sz); free(p); return ret; @@ -3348,7 +3354,7 @@ krb5_encrypt_iov_ivec(krb5_context context, * @ingroup krb5_crypto * * 1. KRB5_CRYPTO_TYPE_HEADER - * 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in + * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in * any order, however the receiver have to aware of the * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted * protocol headers and trailers. The output data will be of same @@ -3360,17 +3366,23 @@ krb5_decrypt_iov_ivec(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + unsigned int num_data, void *ivec) { + unsigned int i; size_t headersz, trailersz, len; - size_t i, sz, block_sz, pad_sz; + size_t sz, block_sz, pad_sz; Checksum cksum; unsigned char *p, *q; krb5_error_code ret; struct key_data *dkey; struct encryption_type *et = crypto->et; - krb5_crypto_iov *tiv, *hiv; + krb5_crypto_iov *tiv, *hiv, *div; + + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } if(!derived_crypto(context, crypto)) { krb5_clear_error_message(context); @@ -3380,9 +3392,13 @@ krb5_decrypt_iov_ivec(krb5_context context, headersz = et->confoundersize; trailersz = CHECKSUMSIZE(et->keyed_checksum); - for (len = 0, i = 0; i < num_data; i++) - if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) + for (len = 0, i = 0; i < num_data; i++) { + if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) { + if (len != 0) + return KRB5_CRYPTO_INTERNAL; len += data[i].data.length; + } + } sz = headersz + len; block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ @@ -3404,7 +3420,9 @@ krb5_decrypt_iov_ivec(krb5_context context, return KRB5_BAD_MSIZE; tiv->data.length = trailersz; - /* body */ + div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA); + if (div == NULL) + return KRB5_CRYPTO_INTERNAL; /* XXX replace with EVP_Cipher */ @@ -3421,12 +3439,7 @@ krb5_decrypt_iov_ivec(krb5_context context, memcpy(q, hiv->data.data, hiv->data.length); q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; - } + memcpy(q, div->data.data, div->data.length); ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); if(ret) { @@ -3445,24 +3458,12 @@ krb5_decrypt_iov_ivec(krb5_context context, return ret; } - /* XXX now copy data back to buffers */ - q = p; - memcpy(hiv->data.data, q, hiv->data.length); - q += hiv->data.length; - len -= hiv->data.length; - - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - if (len < data[i].data.length) - data[i].data.length = len; - memcpy(data[i].data.data, q, data[i].data.length); - q += data[i].data.length; - len -= data[i].data.length; - } + /* copy data back to buffers */ + memcpy(hiv->data.data, p, hiv->data.length); + memcpy(div->data.data, p + hiv->data.length, len - hiv->data.length); free(p); - if (len) - krb5_abortx(context, "data still in the buffer"); + + /* check signature */ len = hiv->data.length; for (i = 0; i < num_data; i++) { @@ -3506,7 +3507,7 @@ krb5_decrypt_iov_ivec(krb5_context context, * @param usage Key usage for this buffer * @param data array of buffers to process * @param num_data length of array - * @param result output data + * @param type output data * * @return Return an error code or 0. * @ingroup krb5_crypto @@ -3517,16 +3518,21 @@ krb5_create_checksum_iov(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + unsigned int num_data, krb5_cksumtype *type) { Checksum cksum; krb5_crypto_iov *civ; krb5_error_code ret; - unsigned int i; + int i; size_t len; char *p, *q; + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } + if(!derived_crypto(context, crypto)) { krb5_clear_error_message(context); return KRB5_CRYPTO_INTERNAL; @@ -3765,18 +3771,6 @@ krb5_generate_random_block(void *buf, size_t len) krb5_abortx(NULL, "Failed to generate random block"); } -static void -DES3_postproc(krb5_context context, - unsigned char *k, size_t len, struct key_data *key) -{ - DES3_random_to_key(context, key->key, k, len); - - if (key->schedule) { - krb5_free_data(context, key->schedule); - key->schedule = NULL; - } -} - static krb5_error_code derive_key(krb5_context context, struct encryption_type *et, @@ -3784,7 +3778,7 @@ derive_key(krb5_context context, const void *constant, size_t len) { - unsigned char *k; + unsigned char *k = NULL; unsigned int nblocks = 0, i; krb5_error_code ret = 0; struct key_type *kt = et->keytype; @@ -3796,15 +3790,16 @@ derive_key(krb5_context context, nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8); k = malloc(nblocks * et->blocksize); if(k == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } ret = _krb5_n_fold(constant, len, k, et->blocksize); if (ret) { - free(k); krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - return ret; + goto out; } + for(i = 0; i < nblocks; i++) { if(i > 0) memcpy(k + i * et->blocksize, @@ -3819,30 +3814,31 @@ derive_key(krb5_context context, size_t res_len = (kt->bits + 7) / 8; if(len != 0 && c == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } memcpy(c, constant, len); (*et->encrypt)(context, key, c, len, 1, 0, NULL); k = malloc(res_len); if(res_len != 0 && k == NULL) { free(c); - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } ret = _krb5_n_fold(c, len, k, res_len); + free(c); if (ret) { - free(k); krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - return ret; + goto out; } - free(c); } /* XXX keytype dependent post-processing */ switch(kt->type) { case KEYTYPE_DES3: - DES3_postproc(context, k, nblocks * et->blocksize, key); + DES3_random_to_key(context, key->key, k, nblocks * et->blocksize); break; case KEYTYPE_AES128: case KEYTYPE_AES256: @@ -3855,12 +3851,15 @@ derive_key(krb5_context context, kt->type); break; } + out: if (key->schedule) { - krb5_free_data(context, key->schedule); + free_key_schedule(context, key, et); key->schedule = NULL; } - memset(k, 0, nblocks * et->blocksize); - free(k); + if (k) { + memset(k, 0, nblocks * et->blocksize); + free(k); + } return ret; } @@ -3983,15 +3982,24 @@ krb5_crypto_init(krb5_context context, } static void +free_key_schedule(krb5_context context, + struct key_data *key, + struct encryption_type *et) +{ + if (et->keytype->cleanup) + (*et->keytype->cleanup)(context, key); + memset(key->schedule->data, 0, key->schedule->length); + krb5_free_data(context, key->schedule); +} + +static void free_key_data(krb5_context context, struct key_data *key, struct encryption_type *et) { krb5_free_keyblock(context, key->key); if(key->schedule) { - if (et->keytype->cleanup) - (*et->keytype->cleanup)(context, key); - memset(key->schedule->data, 0, key->schedule->length); - krb5_free_data(context, key->schedule); + free_key_schedule(context, key, et); + key->schedule = NULL; } } @@ -4154,7 +4162,7 @@ krb5_string_to_key_derived(krb5_context context, return ret; } kd.schedule = NULL; - DES3_postproc (context, tmp, keylen, &kd); /* XXX */ + DES3_random_to_key(context, kd.key, tmp, keylen); memset(tmp, 0, keylen); free(tmp); ret = derive_key(context, @@ -4263,6 +4271,23 @@ krb5_crypto_overhead (krb5_context context, krb5_crypto crypto) return crypto_overhead (context, crypto); } +/** + * Converts the random bytestring to a protocol key according to + * Kerberos crypto frame work. It may be assumed that all the bits of + * the input string are equally random, even though the entropy + * present in the random source may be limited. + * + * @param context Kerberos 5 context + * @param type the enctype resulting key will be of + * @param data input random data to convert to a key + * @param data size of input random data, at least krb5_enctype_keysize() long + * @param data key, output key, free with krb5_free_keyblock_contents() + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_random_to_key(krb5_context context, krb5_enctype type, @@ -4312,7 +4337,7 @@ _krb5_pk_octetstring2key(krb5_context context, size_t keylen, offset; void *keydata; unsigned char counter; - unsigned char shaoutput[20]; + unsigned char shaoutput[SHA_DIGEST_LENGTH]; if(et == NULL) { krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, @@ -4463,9 +4488,9 @@ _krb5_pk_kdf(krb5_context context, size_t keylen, offset; uint32_t counter; unsigned char *keydata; - unsigned char shaoutput[20]; + unsigned char shaoutput[SHA_DIGEST_LENGTH]; - if (der_heim_oid_cmp(oid_id_pkinit_kdf_ah_sha1(), &ai->algorithm) != 0) { + if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) != 0) { krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, N_("KDF not supported", "")); return KRB5_PROG_ETYPE_NOSUPP; @@ -4572,118 +4597,131 @@ krb5_crypto_prf(krb5_context context, return (*et->prf)(context, crypto, input, output); } -#ifndef HEIMDAL_SMALLER +static krb5_error_code +krb5_crypto_prfplus(krb5_context context, + const krb5_crypto crypto, + const krb5_data *input, + size_t length, + krb5_data *output) +{ + krb5_error_code ret; + krb5_data input2; + unsigned char i = 1; + unsigned char *p; -static struct key_type *keytypes[] = { - &keytype_null, - &keytype_des, - &keytype_des3_derived, -#ifdef DES3_OLD_ENCTYPE - &keytype_des3, -#endif - &keytype_aes128, - &keytype_aes256, - &keytype_arcfour -}; + krb5_data_zero(&input2); + krb5_data_zero(output); -static int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]); + krb5_clear_error_message(context); + ret = krb5_data_alloc(output, length); + if (ret) goto out; + ret = krb5_data_alloc(&input2, input->length + 1); + if (ret) goto out; -static struct key_type * -_find_keytype(krb5_keytype type) -{ - int i; - for(i = 0; i < num_keytypes; i++) - if(keytypes[i]->type == type) - return keytypes[i]; - return NULL; -} + krb5_clear_error_message(context); -/* - * First take the configured list of etypes for `keytype' if available, - * else, do `krb5_keytype_to_enctypes'. - */ + memcpy(((unsigned char *)input2.data) + 1, input->data, input->length); -krb5_error_code KRB5_LIB_FUNCTION -krb5_keytype_to_enctypes_default (krb5_context context, - krb5_keytype keytype, - unsigned *len, - krb5_enctype **val) - __attribute__((deprecated)) -{ - unsigned int i, n; - krb5_enctype *ret; + p = output->data; - if (keytype != KEYTYPE_DES || context->etypes_des == NULL) - return krb5_keytype_to_enctypes (context, keytype, len, val); + while (length) { + krb5_data block; - for (n = 0; context->etypes_des[n]; ++n) - ; - ret = malloc (n * sizeof(*ret)); - if (ret == NULL && n != 0) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - for (i = 0; i < n; ++i) - ret[i] = context->etypes_des[i]; - *len = n; - *val = ret; - return 0; -} + ((unsigned char *)input2.data)[0] = i++; -krb5_error_code KRB5_LIB_FUNCTION -krb5_keytype_to_string(krb5_context context, - krb5_keytype keytype, - char **string) - __attribute__((deprecated)) -{ - struct key_type *kt = _find_keytype(keytype); - if(kt == NULL) { - krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, - "key type %d not supported", keytype); - return KRB5_PROG_KEYTYPE_NOSUPP; - } - *string = strdup(kt->name); - if(*string == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = krb5_crypto_prf(context, crypto, &input2, &block); + if (ret) + goto out; + + if (block.length < length) { + memcpy(p, block.data, block.length); + length -= block.length; + } else { + memcpy(p, block.data, length); + length = 0; + } + p += block.length; + krb5_data_free(&block); } + + out: + krb5_data_free(&input2); + if (ret) + krb5_data_free(output); return 0; } +/** + * The FX-CF2 key derivation function, used in FAST and preauth framework. + * + * @param context Kerberos 5 context + * @param crypto1 first key to combine + * @param crypto2 second key to combine + * @param pepper1 factor to combine with first key to garante uniqueness + * @param pepper1 factor to combine with second key to garante uniqueness + * @param enctype the encryption type of the resulting key + * @param res allocated key, free with krb5_free_keyblock_contents() + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ krb5_error_code KRB5_LIB_FUNCTION -krb5_string_to_keytype(krb5_context context, - const char *string, - krb5_keytype *keytype) - __attribute__((deprecated)) +krb5_crypto_fx_cf2(krb5_context context, + const krb5_crypto crypto1, + const krb5_crypto crypto2, + krb5_data *pepper1, + krb5_data *pepper2, + krb5_enctype enctype, + krb5_keyblock *res) { - char *end; - int i; + krb5_error_code ret; + krb5_data os1, os2; + size_t i, keysize; - for(i = 0; i < num_keytypes; i++) - if(strcasecmp(keytypes[i]->name, string) == 0){ - *keytype = keytypes[i]->type; - return 0; - } + memset(res, 0, sizeof(*res)); - /* check if the enctype is a number */ - *keytype = strtol(string, &end, 0); - if(*end == '\0' && *keytype != 0) { - if (krb5_enctype_valid(context, *keytype) == 0) - return 0; + ret = krb5_enctype_keysize(context, enctype, &keysize); + if (ret) + return ret; + + ret = krb5_data_alloc(&res->keyvalue, keysize); + if (ret) + goto out; + ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1); + if (ret) + goto out; + ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2); + if (ret) + goto out; + + res->keytype = enctype; + { + unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data; + for (i = 0; i < keysize; i++) + p3[i] = p1[i] ^ p2[i]; } + out: + if (ret) + krb5_data_free(&res->keyvalue); + krb5_data_free(&os1); + krb5_data_free(&os2); - krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, - "key type %s not supported", string); - return KRB5_PROG_KEYTYPE_NOSUPP; + return ret; } + + +#ifndef HEIMDAL_SMALLER + krb5_error_code KRB5_LIB_FUNCTION krb5_keytype_to_enctypes (krb5_context context, krb5_keytype keytype, unsigned *len, krb5_enctype **val) + KRB5_DEPRECATED { int i; unsigned n = 0; @@ -4691,18 +4729,26 @@ krb5_keytype_to_enctypes (krb5_context context, for (i = num_etypes - 1; i >= 0; --i) { if (etypes[i]->keytype->type == keytype - && !(etypes[i]->flags & F_PSEUDO)) + && !(etypes[i]->flags & F_PSEUDO) + && krb5_enctype_valid(context, etypes[i]->type) == 0) ++n; } + if (n == 0) { + krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, + "Keytype have no mapping"); + return KRB5_PROG_KEYTYPE_NOSUPP; + } + ret = malloc(n * sizeof(*ret)); if (ret == NULL && n != 0) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } n = 0; for (i = num_etypes - 1; i >= 0; --i) { if (etypes[i]->keytype->type == keytype - && !(etypes[i]->flags & F_PSEUDO)) + && !(etypes[i]->flags & F_PSEUDO) + && krb5_enctype_valid(context, etypes[i]->type) == 0) ret[n++] = etypes[i]->type; } *len = n; @@ -4710,4 +4756,16 @@ krb5_keytype_to_enctypes (krb5_context context, return 0; } +/* if two enctypes have compatible keys */ +krb5_boolean KRB5_LIB_FUNCTION +krb5_enctypes_compatible_keys(krb5_context context, + krb5_enctype etype1, + krb5_enctype etype2) + KRB5_DEPRECATED +{ + struct encryption_type *e1 = _find_enctype(etype1); + struct encryption_type *e2 = _find_enctype(etype2); + return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; +} + #endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/data.c b/source4/heimdal/lib/krb5/data.c index d6099c3c6c..993d6058bf 100644 --- a/source4/heimdal/lib/krb5/data.c +++ b/source4/heimdal/lib/krb5/data.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Reset the (potentially uninitalized) krb5_data structure. * @@ -52,7 +50,9 @@ krb5_data_zero(krb5_data *p) /** * Free the content of krb5_data structure, its ok to free a zeroed - * structure. When done, the structure will be zeroed. + * structure (with memset() or krb5_data_zero()). When done, the + * structure will be zeroed. The same function is called + * krb5_free_data_contents() in MIT Kerberos. * * @param p krb5_data to free. * @@ -68,21 +68,6 @@ krb5_data_free(krb5_data *p) } /** - * Same as krb5_data_free(). - * - * @param context Kerberos 5 context. - * @param data krb5_data to free. - * - * @ingroup krb5 - */ - -void KRB5_LIB_FUNCTION -krb5_free_data_contents(krb5_context context, krb5_data *data) -{ - krb5_data_free(data); -} - -/** * Free krb5_data (and its content). * * @param context Kerberos 5 context. diff --git a/source4/heimdal/lib/krb5/eai_to_heim_errno.c b/source4/heimdal/lib/krb5/eai_to_heim_errno.c index 594f998e26..499150f469 100644 --- a/source4/heimdal/lib/krb5/eai_to_heim_errno.c +++ b/source4/heimdal/lib/krb5/eai_to_heim_errno.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - /** * Convert the getaddrinfo() error code to a Kerberos et error code. * diff --git a/source4/heimdal/lib/krb5/error_string.c b/source4/heimdal/lib/krb5/error_string.c index 6374fa17ae..829c080a55 100644 --- a/source4/heimdal/lib/krb5/error_string.c +++ b/source4/heimdal/lib/krb5/error_string.c @@ -33,10 +33,8 @@ #include "krb5_locl.h" -RCSID("$Id$"); - #undef __attribute__ -#define __attribute__(X) +#define __attribute__(x) /** * Clears the error message from the Kerberos 5 context. @@ -172,6 +170,9 @@ krb5_get_error_message(krb5_context context, krb5_error_code code) } HEIMDAL_MUTEX_unlock(context->mutex); + if (code == 0) + return strdup("Success"); + cstr = krb5_get_err_text(context, code); if (cstr) return strdup(cstr); @@ -198,80 +199,3 @@ krb5_free_error_message(krb5_context context, const char *msg) { free(rk_UNCONST(msg)); } - -#ifndef HEIMDAL_SMALLER - -/** - * Free the error message returned by krb5_get_error_string(), - * deprecated, use krb5_free_error_message(). - * - * @param context Kerberos context - * @param msg error message to free - * - * @ingroup krb5_deprecated - */ - -void KRB5_LIB_FUNCTION -krb5_free_error_string(krb5_context context, char *str) - __attribute__((deprecated)) -{ - krb5_free_error_message(context, str); -} - -/** - * Set the error message returned by krb5_get_error_string(), - * deprecated, use krb5_set_error_message(). - * - * @param context Kerberos context - * @param msg error message to free - * - * @ingroup krb5_deprecated - */ - -krb5_error_code KRB5_LIB_FUNCTION -krb5_set_error_string(krb5_context context, const char *fmt, ...) - __attribute__((format (printf, 2, 3))) __attribute__((deprecated)) -{ - va_list ap; - - va_start(ap, fmt); - krb5_vset_error_message (context, 0, fmt, ap); - va_end(ap); - return 0; -} - -/** - * Set the error message returned by krb5_get_error_string(), - * deprecated, use krb5_set_error_message(). - * - * @param context Kerberos context - * @param msg error message to free - * - * @ingroup krb5_deprecated - */ - -krb5_error_code KRB5_LIB_FUNCTION -krb5_vset_error_string(krb5_context context, const char *fmt, va_list args) - __attribute__ ((format (printf, 2, 0))) __attribute__((deprecated)) -{ - krb5_vset_error_message(context, 0, fmt, args); - return 0; -} - -/** - * Clar the error message returned by krb5_get_error_string(), - * deprecated, use krb5_clear_error_message(). - * - * @param context Kerberos context - * - * @ingroup krb5_deprecated - */ - -void KRB5_LIB_FUNCTION -krb5_clear_error_string(krb5_context context) - __attribute__((deprecated)) -{ - krb5_clear_error_message(context); -} - -#endif /* !HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/expand_hostname.c b/source4/heimdal/lib/krb5/expand_hostname.c index a712d9c83a..67988d0d7b 100644 --- a/source4/heimdal/lib/krb5/expand_hostname.c +++ b/source4/heimdal/lib/krb5/expand_hostname.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - static krb5_error_code copy_hostname(krb5_context context, const char *orig_hostname, @@ -50,9 +48,19 @@ copy_hostname(krb5_context context, return 0; } -/* - * Try to make `orig_hostname' into a more canonical one in the newly - * allocated space returned in `new_hostname'. +/** + * krb5_expand_hostname() tries to make orig_hostname into a more + * canonical one in the newly allocated space returned in + * new_hostname. + + * @param context a Keberos context + * @param orig_hostname hostname to canonicalise. + * @param new_hostname output hostname, caller must free hostname with + * krb5_xfree(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support */ krb5_error_code KRB5_LIB_FUNCTION @@ -114,9 +122,22 @@ vanilla_hostname (krb5_context context, return 0; } -/* - * expand `hostname' to a name we believe to be a hostname in newly - * allocated space in `host' and return realms in `realms'. +/** + * krb5_expand_hostname_realms() expands orig_hostname to a name we + * believe to be a hostname in newly allocated space in new_hostname + * and return the realms new_hostname is believed to belong to in + * realms. + * + * @param context a Keberos context + * @param orig_hostname hostname to canonicalise. + * @param new_hostname output hostname, caller must free hostname with + * krb5_xfree(). + * @param realms output possible realms, is an array that is terminated + * with NULL. Caller must free with krb5_free_host_realm(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/fcache.c b/source4/heimdal/lib/krb5/fcache.c index b745c67e11..f8e74f1ddc 100644 --- a/source4/heimdal/lib/krb5/fcache.c +++ b/source4/heimdal/lib/krb5/fcache.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - typedef struct krb5_fcache{ char *filename; int version; @@ -233,8 +231,8 @@ scrub_file (int fd) * hardlink) */ -static krb5_error_code -erase_file(krb5_context context, const char *filename) +krb5_error_code +_krb5_erase_file(krb5_context context, const char *filename) { int fd; struct stat sb1, sb2; @@ -453,7 +451,7 @@ static krb5_error_code fcc_destroy(krb5_context context, krb5_ccache id) { - erase_file(context, FILENAME(id)); + _krb5_erase_file(context, FILENAME(id)); return 0; } @@ -740,8 +738,10 @@ fcc_remove_cred(krb5_context context, { krb5_error_code ret; krb5_ccache copy, newfile; + char *newname; + int fd; - ret = krb5_cc_gen_new(context, &krb5_mcc_ops, ©); + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, ©); if (ret) return ret; @@ -757,8 +757,24 @@ fcc_remove_cred(krb5_context context, return ret; } - ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &newfile); + asprintf(&newname, "FILE:%s.XXXXXX", FILENAME(id)); + if (newname == NULL) { + krb5_cc_destroy(context, copy); + return ret; + } + + fd = mkstemp(&newname[5]); + if (fd < 0) { + ret = errno; + krb5_cc_destroy(context, copy); + return ret; + } + close(fd); + + ret = krb5_cc_resolve(context, newname, &newfile); if (ret) { + unlink(&newname[5]); + free(newname); krb5_cc_destroy(context, copy); return ret; } @@ -766,11 +782,18 @@ fcc_remove_cred(krb5_context context, ret = krb5_cc_copy_cache(context, copy, newfile); krb5_cc_destroy(context, copy); if (ret) { + free(newname); krb5_cc_destroy(context, newfile); return ret; } - return krb5_cc_move(context, newfile, id); + ret = rename(&newname[5], FILENAME(id)); + if (ret) + ret = errno; + free(newname); + krb5_cc_close(context, newfile); + + return ret; } static krb5_error_code @@ -822,12 +845,13 @@ fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) iter->first = 0; fn = krb5_cc_default_name(context); - if (strncasecmp(fn, "FILE:", 5) != 0) { + if (fn == NULL || strncasecmp(fn, "FILE:", 5) != 0) { ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_FILE, &expandedfn); if (ret) return ret; + fn = expandedfn; } ret = krb5_cc_resolve(context, fn, id); if (expandedfn) @@ -900,10 +924,10 @@ fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) fcc_unlock(context, fd1); close(fd1); - erase_file(context, FILENAME(from)); + _krb5_erase_file(context, FILENAME(from)); if (ret) { - erase_file(context, FILENAME(to)); + _krb5_erase_file(context, FILENAME(to)); return ret; } } @@ -913,10 +937,14 @@ fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) krb5_storage *sp; int fd; ret = init_fcc (context, to, &sp, &fd); - krb5_storage_free(sp); + if (sp) + krb5_storage_free(sp); fcc_unlock(context, fd); close(fd); } + + fcc_destroy(context, from); + return ret; } diff --git a/source4/heimdal/lib/krb5/free.c b/source4/heimdal/lib/krb5/free.c index da1eb1de1c..7f4374374b 100644 --- a/source4/heimdal/lib/krb5/free.c +++ b/source4/heimdal/lib/krb5/free.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_free_kdc_rep(krb5_context context, krb5_kdc_rep *rep) { diff --git a/source4/heimdal/lib/krb5/free_host_realm.c b/source4/heimdal/lib/krb5/free_host_realm.c index 581b61a15b..f6e9f6e247 100644 --- a/source4/heimdal/lib/krb5/free_host_realm.c +++ b/source4/heimdal/lib/krb5/free_host_realm.c @@ -33,10 +33,15 @@ #include "krb5_locl.h" -RCSID("$Id$"); - -/* +/** * Free all memory allocated by `realmlist' + * + * @param context A Kerberos 5 context. + * @param realmlist realmlist to free, NULL is ok + * + * @return a Kerberos error code, always 0. + * + * @ingroup krb5_support */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/generate_seq_number.c b/source4/heimdal/lib/krb5/generate_seq_number.c index 99745b8305..2764f1a914 100644 --- a/source4/heimdal/lib/krb5/generate_seq_number.c +++ b/source4/heimdal/lib/krb5/generate_seq_number.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_generate_seq_number(krb5_context context, const krb5_keyblock *key, diff --git a/source4/heimdal/lib/krb5/generate_subkey.c b/source4/heimdal/lib/krb5/generate_subkey.c index 4ab4b9bf6c..efb6cce288 100644 --- a/source4/heimdal/lib/krb5/generate_subkey.c +++ b/source4/heimdal/lib/krb5/generate_subkey.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_generate_subkey(krb5_context context, const krb5_keyblock *key, diff --git a/source4/heimdal/lib/krb5/get_addrs.c b/source4/heimdal/lib/krb5/get_addrs.c index ce16785319..8f366fa148 100644 --- a/source4/heimdal/lib/krb5/get_addrs.c +++ b/source4/heimdal/lib/krb5/get_addrs.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id: get_addrs.c 23815 2008-09-13 09:21:03Z lha $"); - #ifdef __osf__ /* hate */ struct rtentry; @@ -43,9 +41,7 @@ struct mbuf; #ifdef HAVE_NET_IF_H #include <net/if.h> #endif -#ifdef HAVE_IFADDR_H #include <ifaddrs.h> -#endif static krb5_error_code gethostname_fallback (krb5_context context, krb5_addresses *res) @@ -106,8 +102,6 @@ find_all_addresses (krb5_context context, krb5_addresses *res, int flags) unsigned int num, idx; krb5_addresses ignore_addresses; - res->val = NULL; - if (getifaddrs(&ifa0) == -1) { ret = errno; krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret)); @@ -232,13 +226,14 @@ get_addrs_int (krb5_context context, krb5_addresses *res, int flags) { krb5_error_code ret = -1; + res->len = 0; + res->val = NULL; + if (flags & SCAN_INTERFACES) { ret = find_all_addresses (context, res, flags); if(ret || res->len == 0) ret = gethostname_fallback (context, res); } else { - res->len = 0; - res->val = NULL; ret = 0; } diff --git a/source4/heimdal/lib/krb5/get_cred.c b/source4/heimdal/lib/krb5/get_cred.c index 97e0022ee1..e609bcadcc 100644 --- a/source4/heimdal/lib/krb5/get_cred.c +++ b/source4/heimdal/lib/krb5/get_cred.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - /* * Take the `body' and encode it into `padata' using the credentials * in `creds'. @@ -375,17 +373,18 @@ decrypt_tkt_with_subkey (krb5_context context, if (ret) return ret; - ret = krb5_decode_EncASRepPart(context, - data.data, + ret = decode_EncASRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + if (ret) + ret = decode_EncTGSRepPart(data.data, data.length, &dec_rep->enc_part, &size); if (ret) - ret = krb5_decode_EncTGSRepPart(context, - data.data, - data.length, - &dec_rep->enc_part, - &size); + krb5_set_error_message(context, ret, + N_("Failed to decode encpart in ticket", "")); krb5_data_free (&data); return ret; } @@ -477,7 +476,7 @@ get_cred_kdc(krb5_context context, if (len != size) krb5_abortx(context, "internal asn1 error"); - ret = krb5_padata_add(context, &padata, KRB5_PADATA_S4U2SELF, buf, len); + ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); if (ret) goto out; } @@ -561,7 +560,7 @@ get_cred_kdc(krb5_context context, } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); - } else if(resp.data && ((char*)resp.data)[0] == 4) { + } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_message(context); } else { @@ -1217,6 +1216,10 @@ krb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt) { if (opt->self) krb5_free_principal(context, opt->self); + if (opt->ticket) { + free_Ticket(opt->ticket); + free(opt->ticket); + } memset(opt, 0, sizeof(*opt)); free(opt); } diff --git a/source4/heimdal/lib/krb5/get_default_principal.c b/source4/heimdal/lib/krb5/get_default_principal.c index c804ab9e56..82d0642934 100644 --- a/source4/heimdal/lib/krb5/get_default_principal.c +++ b/source4/heimdal/lib/krb5/get_default_principal.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* * Try to find out what's a reasonable default principal. */ diff --git a/source4/heimdal/lib/krb5/get_default_realm.c b/source4/heimdal/lib/krb5/get_default_realm.c index a2518bbab7..f09df264c1 100644 --- a/source4/heimdal/lib/krb5/get_default_realm.c +++ b/source4/heimdal/lib/krb5/get_default_realm.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* * Return a NULL-terminated list of default realms in `realms'. * Free this memory with krb5_free_host_realm. diff --git a/source4/heimdal/lib/krb5/get_for_creds.c b/source4/heimdal/lib/krb5/get_for_creds.c index a7072a0136..19e48173df 100644 --- a/source4/heimdal/lib/krb5/get_for_creds.c +++ b/source4/heimdal/lib/krb5/get_for_creds.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code add_addrs(krb5_context context, krb5_addresses *addr, diff --git a/source4/heimdal/lib/krb5/get_host_realm.c b/source4/heimdal/lib/krb5/get_host_realm.c index 2ea075f6c5..7d7fef6e1c 100644 --- a/source4/heimdal/lib/krb5/get_host_realm.c +++ b/source4/heimdal/lib/krb5/get_host_realm.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <resolve.h> -RCSID("$Id$"); - /* To automagically find the correct realm of a host (without * [domain_realm] in krb5.conf) add a text record for your domain with * the name of your realm, like this: @@ -51,14 +49,14 @@ RCSID("$Id$"); */ static int -copy_txt_to_realms (struct resource_record *head, +copy_txt_to_realms (struct rk_resource_record *head, krb5_realm **realms) { - struct resource_record *rr; + struct rk_resource_record *rr; unsigned int n, i; for(n = 0, rr = head; rr; rr = rr->next) - if (rr->type == T_TXT) + if (rr->type == rk_ns_t_txt) ++n; if (n == 0) @@ -72,7 +70,7 @@ copy_txt_to_realms (struct resource_record *head, (*realms)[i] = NULL; for (i = 0, rr = head; rr; rr = rr->next) { - if (rr->type == T_TXT) { + if (rr->type == rk_ns_t_txt) { char *tmp; tmp = strdup(rr->u.txt); @@ -96,7 +94,7 @@ dns_find_realm(krb5_context context, { static const char *default_labels[] = { "_kerberos", NULL }; char dom[MAXHOSTNAMELEN]; - struct dns_reply *r; + struct rk_dns_reply *r; const char **labels; char **config_labels; int i, ret; @@ -116,10 +114,10 @@ dns_find_realm(krb5_context context, krb5_config_free_strings(config_labels); return -1; } - r = dns_lookup(dom, "TXT"); + r = rk_dns_lookup(dom, "TXT"); if(r != NULL) { ret = copy_txt_to_realms (r->head, realms); - dns_free_data(r); + rk_dns_free_data(r); if(ret == 0) { if (config_labels) krb5_config_free_strings(config_labels); diff --git a/source4/heimdal/lib/krb5/get_in_tkt.c b/source4/heimdal/lib/krb5/get_in_tkt.c index cc49e16030..84b1ffb71f 100644 --- a/source4/heimdal/lib/krb5/get_in_tkt.c +++ b/source4/heimdal/lib/krb5/get_in_tkt.c @@ -31,529 +31,11 @@ * SUCH DAMAGE. */ -#include "krb5_locl.h" - -RCSID("$Id$"); - -krb5_error_code KRB5_LIB_FUNCTION -krb5_init_etype (krb5_context context, - unsigned *len, - krb5_enctype **val, - const krb5_enctype *etypes) -{ - unsigned int i; - krb5_error_code ret; - krb5_enctype *tmp = NULL; - - ret = 0; - if (etypes == NULL) { - ret = krb5_get_default_in_tkt_etypes(context, - &tmp); - if (ret) - return ret; - etypes = tmp; - } - - for (i = 0; etypes[i]; ++i) - ; - *len = i; - *val = malloc(i * sizeof(**val)); - if (i != 0 && *val == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto cleanup; - } - memmove (*val, - etypes, - i * sizeof(*tmp)); -cleanup: - if (tmp != NULL) - free (tmp); - return ret; -} - -static krb5_error_code -check_server_referral(krb5_context context, - krb5_kdc_rep *rep, - unsigned flags, - krb5_const_principal requested, - krb5_const_principal returned, - const krb5_keyblock const * key) -{ - krb5_error_code ret; - PA_ServerReferralData ref; - krb5_crypto session; - EncryptedData ed; - size_t len; - krb5_data data; - PA_DATA *pa; - int i = 0, cmp; - - if (rep->kdc_rep.padata == NULL) - goto noreferral; - - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, - KRB5_PADATA_SERVER_REFERRAL, &i); - if (pa == NULL) - goto noreferral; - - memset(&ed, 0, sizeof(ed)); - memset(&ref, 0, sizeof(ref)); - - ret = decode_EncryptedData(pa->padata_value.data, - pa->padata_value.length, - &ed, &len); - if (ret) - return ret; - if (len != pa->padata_value.length) { - free_EncryptedData(&ed); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Referral EncryptedData wrong for realm %s", - "realm"), requested->realm); - return KRB5KRB_AP_ERR_MODIFIED; - } - - ret = krb5_crypto_init(context, key, 0, &session); - if (ret) { - free_EncryptedData(&ed); - return ret; - } - - ret = krb5_decrypt_EncryptedData(context, session, - KRB5_KU_PA_SERVER_REFERRAL, - &ed, &data); - free_EncryptedData(&ed); - krb5_crypto_destroy(context, session); - if (ret) - return ret; - - ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len); - if (ret) { - krb5_data_free(&data); - return ret; - } - krb5_data_free(&data); - - if (strcmp(requested->realm, returned->realm) != 0) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("server ref realm mismatch, " - "requested realm %s got back %s", ""), - requested->realm, returned->realm); - return KRB5KRB_AP_ERR_MODIFIED; - } - - if (returned->name.name_string.len == 2 && - strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0) - { - const char *realm = returned->name.name_string.val[1]; - - if (ref.referred_realm == NULL - || strcmp(*ref.referred_realm, realm) != 0) - { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("tgt returned with wrong ref", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - } else if (krb5_principal_compare(context, returned, requested) == 0) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("req princ no same as returned", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - - if (ref.requested_principal_name) { - cmp = _krb5_principal_compare_PrincipalName(context, - requested, - ref.requested_principal_name); - if (!cmp) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("referred principal not same " - "as requested", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - } else if (flags & EXTRACT_TICKET_AS_REQ) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Requested principal missing on AS-REQ", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - - free_PA_ServerReferralData(&ref); - - return ret; -noreferral: - if (krb5_principal_compare(context, requested, returned) == FALSE) { - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Not same server principal returned " - "as requested", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - return 0; -} - - -/* - * Verify referral data - */ - - -static krb5_error_code -check_client_referral(krb5_context context, - krb5_kdc_rep *rep, - krb5_const_principal requested, - krb5_const_principal mapped, - krb5_keyblock const * key) -{ - krb5_error_code ret; - PA_ClientCanonicalized canon; - krb5_crypto crypto; - krb5_data data; - PA_DATA *pa; - size_t len; - int i = 0; - - if (rep->kdc_rep.padata == NULL) - goto noreferral; - - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, - KRB5_PADATA_CLIENT_CANONICALIZED, &i); - if (pa == NULL) - goto noreferral; - - ret = decode_PA_ClientCanonicalized(pa->padata_value.data, - pa->padata_value.length, - &canon, &len); - if (ret) { - krb5_set_error_message(context, ret, - N_("Failed to decode ClientCanonicalized " - "from realm %s", ""), requested->realm); - return ret; - } - - ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, - &canon.names, &len, ret); - if (ret) { - free_PA_ClientCanonicalized(&canon); - return ret; - } - if (data.length != len) - krb5_abortx(context, "internal asn.1 error"); - - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret) { - free(data.data); - free_PA_ClientCanonicalized(&canon); - return ret; - } - - ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES, - data.data, data.length, - &canon.canon_checksum); - krb5_crypto_destroy(context, crypto); - free(data.data); - if (ret) { - krb5_set_error_message(context, ret, - N_("Failed to verify client canonicalized " - "data from realm %s", ""), - requested->realm); - free_PA_ClientCanonicalized(&canon); - return ret; - } - - if (!_krb5_principal_compare_PrincipalName(context, - requested, - &canon.names.requested_name)) - { - free_PA_ClientCanonicalized(&canon); - krb5_set_error_message(context, KRB5_PRINC_NOMATCH, - N_("Requested name doesn't match" - " in client referral", "")); - return KRB5_PRINC_NOMATCH; - } - if (!_krb5_principal_compare_PrincipalName(context, - mapped, - &canon.names.mapped_name)) - { - free_PA_ClientCanonicalized(&canon); - krb5_set_error_message(context, KRB5_PRINC_NOMATCH, - N_("Mapped name doesn't match" - " in client referral", "")); - return KRB5_PRINC_NOMATCH; - } - - return 0; - -noreferral: - if (krb5_principal_compare(context, requested, mapped) == FALSE) { - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Not same client principal returned " - "as requested", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - return 0; -} - - +#define KRB5_DEPRECATED -static krb5_error_code -decrypt_tkt (krb5_context context, - krb5_keyblock *key, - krb5_key_usage usage, - krb5_const_pointer decrypt_arg, - krb5_kdc_rep *dec_rep) -{ - krb5_error_code ret; - krb5_data data; - size_t size; - krb5_crypto crypto; - - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret) - return ret; - - ret = krb5_decrypt_EncryptedData (context, - crypto, - usage, - &dec_rep->kdc_rep.enc_part, - &data); - krb5_crypto_destroy(context, crypto); - - if (ret) - return ret; - - ret = krb5_decode_EncASRepPart(context, - data.data, - data.length, - &dec_rep->enc_part, - &size); - if (ret) - ret = krb5_decode_EncTGSRepPart(context, - data.data, - data.length, - &dec_rep->enc_part, - &size); - krb5_data_free (&data); - if (ret) - return ret; - return 0; -} - -int -_krb5_extract_ticket(krb5_context context, - krb5_kdc_rep *rep, - krb5_creds *creds, - krb5_keyblock *key, - krb5_const_pointer keyseed, - krb5_key_usage key_usage, - krb5_addresses *addrs, - unsigned nonce, - unsigned flags, - krb5_decrypt_proc decrypt_proc, - krb5_const_pointer decryptarg) -{ - krb5_error_code ret; - krb5_principal tmp_principal; - size_t len; - time_t tmp_time; - krb5_timestamp sec_now; - - /* decrypt */ - - if (decrypt_proc == NULL) - decrypt_proc = decrypt_tkt; - - ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); - if (ret) - goto out; - - /* save session key */ - - creds->session.keyvalue.length = 0; - creds->session.keyvalue.data = NULL; - creds->session.keytype = rep->enc_part.key.keytype; - ret = krb5_data_copy (&creds->session.keyvalue, - rep->enc_part.key.keyvalue.data, - rep->enc_part.key.keyvalue.length); - if (ret) { - krb5_clear_error_message(context); - goto out; - } - - /* - * HACK: - * this is really a ugly hack, to support using the Netbios Domain Name - * as realm against windows KDC's, they always return the full realm - * based on the DNS Name. - */ - flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; - flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; - - /* compare client and save */ - ret = _krb5_principalname2krb5_principal (context, - &tmp_principal, - rep->kdc_rep.cname, - rep->kdc_rep.crealm); - if (ret) - goto out; - - /* check client referral and save principal */ - /* anonymous here ? */ - if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { - ret = check_client_referral(context, rep, - creds->client, - tmp_principal, - &creds->session); - if (ret) { - krb5_free_principal (context, tmp_principal); - goto out; - } - } - krb5_free_principal (context, creds->client); - creds->client = tmp_principal; - - /* check server referral and save principal */ - ret = _krb5_principalname2krb5_principal (context, - &tmp_principal, - rep->kdc_rep.ticket.sname, - rep->kdc_rep.ticket.realm); - if (ret) - goto out; - if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ - ret = check_server_referral(context, - rep, - flags, - creds->server, - tmp_principal, - &creds->session); - if (ret) { - krb5_free_principal (context, tmp_principal); - goto out; - } - } - krb5_free_principal(context, creds->server); - creds->server = tmp_principal; - - /* verify names */ - if(flags & EXTRACT_TICKET_MATCH_REALM){ - const char *srealm = krb5_principal_get_realm(context, creds->server); - const char *crealm = krb5_principal_get_realm(context, creds->client); - - if (strcmp(rep->enc_part.srealm, srealm) != 0 || - strcmp(rep->enc_part.srealm, crealm) != 0) - { - ret = KRB5KRB_AP_ERR_MODIFIED; - krb5_clear_error_message(context); - goto out; - } - } - - /* compare nonces */ - - if (nonce != rep->enc_part.nonce) { - ret = KRB5KRB_AP_ERR_MODIFIED; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto out; - } - - /* set kdc-offset */ - - krb5_timeofday (context, &sec_now); - if (rep->enc_part.flags.initial - && context->kdc_sec_offset == 0 - && krb5_config_get_bool (context, NULL, - "libdefaults", - "kdc_timesync", - NULL)) { - context->kdc_sec_offset = rep->enc_part.authtime - sec_now; - krb5_timeofday (context, &sec_now); - } - - /* check all times */ - - if (rep->enc_part.starttime) { - tmp_time = *rep->enc_part.starttime; - } else - tmp_time = rep->enc_part.authtime; - - if (creds->times.starttime == 0 - && abs(tmp_time - sec_now) > context->max_skew) { - ret = KRB5KRB_AP_ERR_SKEW; - krb5_set_error_message (context, ret, - N_("time skew (%d) larger than max (%d)", ""), - abs(tmp_time - sec_now), - (int)context->max_skew); - goto out; - } - - if (creds->times.starttime != 0 - && tmp_time != creds->times.starttime) { - krb5_clear_error_message (context); - ret = KRB5KRB_AP_ERR_MODIFIED; - goto out; - } - - creds->times.starttime = tmp_time; - - if (rep->enc_part.renew_till) { - tmp_time = *rep->enc_part.renew_till; - } else - tmp_time = 0; - - if (creds->times.renew_till != 0 - && tmp_time > creds->times.renew_till) { - krb5_clear_error_message (context); - ret = KRB5KRB_AP_ERR_MODIFIED; - goto out; - } - - creds->times.renew_till = tmp_time; - - creds->times.authtime = rep->enc_part.authtime; - - if (creds->times.endtime != 0 - && rep->enc_part.endtime > creds->times.endtime) { - krb5_clear_error_message (context); - ret = KRB5KRB_AP_ERR_MODIFIED; - goto out; - } - - creds->times.endtime = rep->enc_part.endtime; - - if(rep->enc_part.caddr) - krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); - else if(addrs) - krb5_copy_addresses (context, addrs, &creds->addresses); - else { - creds->addresses.len = 0; - creds->addresses.val = NULL; - } - creds->flags.b = rep->enc_part.flags; - - creds->authdata.len = 0; - creds->authdata.val = NULL; - - /* extract ticket */ - ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, - &rep->kdc_rep.ticket, &len, ret); - if(ret) - goto out; - if (creds->ticket.length != len) - krb5_abortx(context, "internal error in ASN.1 encoder"); - creds->second_ticket.length = 0; - creds->second_ticket.data = NULL; - - -out: - memset (rep->enc_part.key.keyvalue.data, 0, - rep->enc_part.key.keyvalue.length); - return ret; -} +#include "krb5_locl.h" +#ifndef HEIMDAL_SMALLER static krb5_error_code make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, @@ -626,6 +108,8 @@ add_padata(krb5_context context, if(salt == NULL) { /* default to standard salt */ ret = krb5_get_pw_salt (context, client, &salt2); + if (ret) + return ret; salt = &salt2; } if (!enctypes) { @@ -861,11 +345,10 @@ set_ptypes(krb5_context context, *preauth = &preauth2; ALLOC_SEQ(*preauth, 1); (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP; - krb5_decode_ETYPE_INFO(context, - md.val[i].padata_value.data, - md.val[i].padata_value.length, - &(*preauth)->val[0].info, - NULL); + decode_ETYPE_INFO(md.val[i].padata_value.data, + md.val[i].padata_value.length, + &(*preauth)->val[0].info, + NULL); break; default: break; @@ -891,6 +374,7 @@ krb5_get_in_cred(krb5_context context, krb5_const_pointer decryptarg, krb5_creds *creds, krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED { krb5_error_code ret; AS_REQ a; @@ -1055,6 +539,7 @@ krb5_get_in_tkt(krb5_context context, krb5_creds *creds, krb5_ccache ccache, krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED { krb5_error_code ret; @@ -1076,3 +561,5 @@ krb5_get_in_tkt(krb5_context context, ret = krb5_cc_store_cred (context, ccache, creds); return ret; } + +#endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/get_port.c b/source4/heimdal/lib/krb5/get_port.c index c9869eb450..5d0361b816 100644 --- a/source4/heimdal/lib/krb5/get_port.c +++ b/source4/heimdal/lib/krb5/get_port.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - int KRB5_LIB_FUNCTION krb5_getportbyname (krb5_context context, const char *service, diff --git a/source4/heimdal/lib/krb5/heim_err.et b/source4/heimdal/lib/krb5/heim_err.et index 547a14e04c..2e8a0d18d8 100644 --- a/source4/heimdal/lib/krb5/heim_err.et +++ b/source4/heimdal/lib/krb5/heim_err.et @@ -17,6 +17,8 @@ error_code OPNOTSUPP, "Operation not supported" error_code EOF, "End of file" error_code BAD_MKEY, "Failed to get the master key" error_code SERVICE_NOMATCH, "Unacceptable service used" +error_code NOT_SEEKABLE, "File descriptor not seekable" +error_code TOO_BIG, "Offset too large" index 64 prefix HEIM_PKINIT diff --git a/source4/heimdal/lib/krb5/init_creds.c b/source4/heimdal/lib/krb5/init_creds.c index 89ea3004ed..b1bd94d3b9 100644 --- a/source4/heimdal/lib/krb5/init_creds.c +++ b/source4/heimdal/lib/krb5/init_creds.c @@ -36,14 +36,19 @@ #undef __attribute__ #define __attribute__(x) -RCSID("$Id$"); +/** + * @page krb5_init_creds_intro The initial credential handing functions + * @section section_krb5_init_creds Initial credential + * + * Functions to get initial credentials: @ref krb5_credential . + */ -void KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) - __attribute__((deprecated)) -{ - memset (opt, 0, sizeof(*opt)); -} +/** + * Allocate a new krb5_get_init_creds_opt structure, free with + * krb5_get_init_creds_opt_free(). + * + * @ingroup krb5_credential + */ krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_opt_alloc(krb5_context context, @@ -71,67 +76,11 @@ krb5_get_init_creds_opt_alloc(krb5_context context, return 0; } -krb5_error_code -_krb5_get_init_creds_opt_copy(krb5_context context, - const krb5_get_init_creds_opt *in, - krb5_get_init_creds_opt **out) -{ - krb5_get_init_creds_opt *opt; - - *out = NULL; - opt = calloc(1, sizeof(*opt)); - if (opt == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - if (in) - *opt = *in; - if(opt->opt_private == NULL) { - opt->opt_private = calloc(1, sizeof(*opt->opt_private)); - if (opt->opt_private == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - free(opt); - return ENOMEM; - } - opt->opt_private->refcount = 1; - } else - opt->opt_private->refcount++; - *out = opt; - return 0; -} - -void KRB5_LIB_FUNCTION -_krb5_get_init_creds_opt_free_krb5_error(krb5_get_init_creds_opt *opt) -{ - if (opt->opt_private == NULL || opt->opt_private->error == NULL) - return; - free_KRB_ERROR(opt->opt_private->error); - free(opt->opt_private->error); - opt->opt_private->error = NULL; -} - -void KRB5_LIB_FUNCTION -_krb5_get_init_creds_opt_set_krb5_error(krb5_context context, - krb5_get_init_creds_opt *opt, - const KRB_ERROR *error) -{ - krb5_error_code ret; - - if (opt->opt_private == NULL) - return; - - _krb5_get_init_creds_opt_free_krb5_error(opt); - - opt->opt_private->error = malloc(sizeof(*opt->opt_private->error)); - if (opt->opt_private->error == NULL) - return; - ret = copy_KRB_ERROR(error, opt->opt_private->error); - if (ret) { - free(opt->opt_private->error); - opt->opt_private->error = NULL; - } -} - +/** + * Free krb5_get_init_creds_opt structure. + * + * @ingroup krb5_credential + */ void KRB5_LIB_FUNCTION krb5_get_init_creds_opt_free(krb5_context context, @@ -142,7 +91,6 @@ krb5_get_init_creds_opt_free(krb5_context context, if (opt->opt_private->refcount < 1) /* abort ? */ return; if (--opt->opt_private->refcount == 0) { - _krb5_get_init_creds_opt_free_krb5_error(opt); _krb5_get_init_creds_opt_free_pkinit(opt); free(opt->opt_private); } @@ -369,35 +317,6 @@ krb5_get_init_creds_opt_set_pac_request(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_get_error(krb5_context context, - krb5_get_init_creds_opt *opt, - KRB_ERROR **error) -{ - krb5_error_code ret; - - *error = NULL; - - ret = require_ext_opt(context, opt, "init_creds_opt_get_error"); - if (ret) - return ret; - - if (opt->opt_private->error == NULL) - return 0; - - *error = malloc(sizeof(**error)); - if (*error == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - - ret = copy_KRB_ERROR(opt->opt_private->error, *error); - if (ret) - krb5_clear_error_message(context); - - return 0; -} - -krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_opt_set_addressless(krb5_context context, krb5_get_init_creds_opt *opt, krb5_boolean addressless) @@ -445,3 +364,54 @@ krb5_get_init_creds_opt_set_win2k(krb5_context context, return 0; } + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_init_creds_opt_set_process_last_req(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_gic_process_last_req func, + void *ctx) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k"); + if (ret) + return ret; + + opt->opt_private->lr.func = func; + opt->opt_private->lr.ctx = ctx; + + return 0; +} + + +#ifndef HEIMDAL_SMALLER + +void KRB5_LIB_FUNCTION +krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) + KRB5_DEPRECATED +{ + memset (opt, 0, sizeof(*opt)); +} + +/** + * Deprecated: use the new krb5_init_creds_init() and + * krb5_init_creds_get_error(). + * + * @ingroup krb5_deprecated + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_init_creds_opt_get_error(krb5_context context, + krb5_get_init_creds_opt *opt, + KRB_ERROR **error) + KRB5_DEPRECATED +{ + *error = calloc(1, sizeof(**error)); + if (*error == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } + + return 0; +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c index 0b75522e9d..0435ab5d3b 100644 --- a/source4/heimdal/lib/krb5/init_creds_pw.c +++ b/source4/heimdal/lib/krb5/init_creds_pw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,15 +33,13 @@ #include "krb5_locl.h" -RCSID("$Id$"); - typedef struct krb5_get_init_creds_ctx { KDCOptions flags; krb5_creds cred; krb5_addresses *addrs; krb5_enctype *etypes; krb5_preauthtype *pre_auth_types; - const char *in_tkt_service; + char *in_tkt_service; unsigned nonce; unsigned pk_nonce; @@ -49,13 +47,26 @@ typedef struct krb5_get_init_creds_ctx { AS_REQ as_req; int pa_counter; - const char *password; - krb5_s2k_proc key_proc; + /* password and keytab_data is freed on completion */ + char *password; + krb5_keytab_key_proc_args *keytab_data; + + krb5_pointer *keyseed; + krb5_s2k_proc keyproc; krb5_get_init_creds_tristate req_pac; krb5_pk_init_ctx pk_init_ctx; int ic_flags; + + METHOD_DATA md; + KRB_ERROR error; + AS_REP as_rep; + EncKDCRepPart enc_part; + + krb5_prompter_fct prompter; + void *prompter_data; + } krb5_get_init_creds_ctx; static krb5_error_code @@ -74,7 +85,7 @@ default_s2k_func(krb5_context context, krb5_enctype type, opaque = *s2kparms; else krb5_data_zero(&opaque); - + *key = malloc(sizeof(**key)); if (*key == NULL) return ENOMEM; @@ -88,14 +99,24 @@ default_s2k_func(krb5_context context, krb5_enctype type, } static void -free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx) +free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) { if (ctx->etypes) free(ctx->etypes); if (ctx->pre_auth_types) free (ctx->pre_auth_types); + if (ctx->in_tkt_service) + free(ctx->in_tkt_service); + if (ctx->keytab_data) + free(ctx->keytab_data); + krb5_data_free(&ctx->req_buffer); + krb5_free_cred_contents(context, &ctx->cred); + free_METHOD_DATA(&ctx->md); + free_AS_REP(&ctx->as_rep); + free_EncKDCRepPart(&ctx->enc_part); + free_KRB_ERROR(&ctx->error); free_AS_REQ(&ctx->as_req); - memset(&ctx->as_req, 0, sizeof(ctx->as_req)); + memset(ctx, 0, sizeof(*ctx)); } static int @@ -127,11 +148,9 @@ init_cred (krb5_context context, krb5_creds *cred, krb5_principal client, krb5_deltat start_time, - const char *in_tkt_service, krb5_get_init_creds_opt *options) { krb5_error_code ret; - krb5_const_realm client_realm; int tmp; krb5_timestamp now; @@ -148,8 +167,6 @@ init_cred (krb5_context context, goto out; } - client_realm = krb5_principal_get_realm (context, cred->client); - if (start_time) cred->times.starttime = now + start_time; @@ -164,18 +181,6 @@ init_cred (krb5_context context, cred->times.renew_till = now + options->renew_life; } - if (in_tkt_service) { - ret = krb5_parse_name (context, in_tkt_service, &cred->server); - if (ret) - goto out; - krb5_principal_set_realm (context, cred->server, client_realm); - } else { - ret = krb5_make_principal(context, &cred->server, - client_realm, KRB5_TGS_NAME, client_realm, - NULL); - if (ret) - goto out; - } return 0; out: @@ -195,28 +200,71 @@ report_expiration (krb5_context context, time_t now) { char *p; - + asprintf (&p, "%s%s", str, ctime(&now)); (*prompter) (context, data, NULL, p, 0, NULL); free (p); } /* - * Parse the last_req data and show it to the user if it's interesting + * Check the context, and in the case there is a expiration warning, + * use the prompter to print the warning. + * + * @param context A Kerberos 5 context. + * @param options An GIC options structure + * @param ctx The krb5_init_creds_context check for expiration. */ -static void -print_expire (krb5_context context, - krb5_const_realm realm, - krb5_kdc_rep *rep, - krb5_prompter_fct prompter, - krb5_data *data) +static krb5_error_code +process_last_request(krb5_context context, + krb5_get_init_creds_opt *options, + krb5_init_creds_context ctx) { - int i; - LastReq *lr = &rep->enc_part.last_req; + krb5_const_realm realm; + LastReq *lr; + krb5_boolean reported = FALSE; krb5_timestamp sec; time_t t; - krb5_boolean reported = FALSE; + size_t i; + + /* + * First check if there is a API consumer. + */ + + realm = krb5_principal_get_realm (context, ctx->cred.client); + lr = &ctx->enc_part.last_req; + + if (options && options->opt_private && options->opt_private->lr.func) { + krb5_last_req_entry **lre; + + lre = calloc(lr->len + 1, sizeof(**lre)); + if (lre == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + for (i = 0; i < lr->len; i++) { + lre[i] = calloc(1, sizeof(*lre[i])); + if (lre[i] == NULL) + break; + lre[i]->lr_type = lr->val[i].lr_type; + lre[i]->value = lr->val[i].lr_value; + } + + (*options->opt_private->lr.func)(context, lre, + options->opt_private->lr.ctx); + + for (i = 0; i < lr->len; i++) + free(lre[i]); + free(lre); + } + + /* + * Now check if we should prompt the user + */ + + if (ctx->prompter == NULL) + return 0; krb5_timeofday (context, &sec); @@ -229,13 +277,15 @@ print_expire (krb5_context context, if (lr->val[i].lr_value <= t) { switch (abs(lr->val[i].lr_type)) { case LR_PW_EXPTIME : - report_expiration(context, prompter, data, + report_expiration(context, ctx->prompter, + ctx->prompter_data, "Your password will expire at ", lr->val[i].lr_value); reported = TRUE; break; case LR_ACCT_EXPTIME : - report_expiration(context, prompter, data, + report_expiration(context, ctx->prompter, + ctx->prompter_data, "Your account will expire at ", lr->val[i].lr_value); reported = TRUE; @@ -245,12 +295,14 @@ print_expire (krb5_context context, } if (!reported - && rep->enc_part.key_expiration - && *rep->enc_part.key_expiration <= t) { - report_expiration(context, prompter, data, + && ctx->enc_part.key_expiration + && *ctx->enc_part.key_expiration <= t) { + report_expiration(context, ctx->prompter, + ctx->prompter_data, "Your password/account will expire at ", - *rep->enc_part.key_expiration); + *ctx->enc_part.key_expiration); } + return 0; } static krb5_addresses no_addrs = { 0, NULL }; @@ -259,11 +311,10 @@ static krb5_error_code get_init_creds_common(krb5_context context, krb5_principal client, krb5_deltat start_time, - const char *in_tkt_service, krb5_get_init_creds_opt *options, - krb5_get_init_creds_ctx *ctx) + krb5_init_creds_context ctx) { - krb5_get_init_creds_opt default_opt; + krb5_get_init_creds_opt *default_opt = NULL; krb5_error_code ret; krb5_enctype *etypes; krb5_preauthtype *pre_auth_types; @@ -271,37 +322,51 @@ get_init_creds_common(krb5_context context, memset(ctx, 0, sizeof(*ctx)); if (options == NULL) { - krb5_get_init_creds_opt_init (&default_opt); - options = &default_opt; - } else { - _krb5_get_init_creds_opt_free_krb5_error(options); + const char *realm = krb5_principal_get_realm(context, client); + + krb5_get_init_creds_opt_alloc (context, &default_opt); + options = default_opt; + krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options); } if (options->opt_private) { - ctx->password = options->opt_private->password; - ctx->key_proc = options->opt_private->key_proc; + if (options->opt_private->password) { + ret = krb5_init_creds_set_password(context, ctx, + options->opt_private->password); + if (ret) + goto out; + } + + ctx->keyproc = options->opt_private->key_proc; ctx->req_pac = options->opt_private->req_pac; ctx->pk_init_ctx = options->opt_private->pk_init_ctx; ctx->ic_flags = options->opt_private->flags; } else ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET; - if (ctx->key_proc == NULL) - ctx->key_proc = default_s2k_func; + if (ctx->keyproc == NULL) + ctx->keyproc = default_s2k_func; - if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) + /* Enterprise name implicitly turns on canonicalize */ + if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) || + krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL) ctx->flags.canonicalize = 1; ctx->pre_auth_types = NULL; ctx->addrs = NULL; ctx->etypes = NULL; ctx->pre_auth_types = NULL; - ctx->in_tkt_service = in_tkt_service; - ret = init_cred (context, &ctx->cred, client, start_time, - in_tkt_service, options); - if (ret) + ret = init_cred(context, &ctx->cred, client, start_time, options); + if (ret) { + if (default_opt) + krb5_get_init_creds_opt_free(context, default_opt); return ret; + } + + ret = krb5_init_creds_set_service(context, ctx, NULL); + if (ret) + goto out; if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE) ctx->flags.forwardable = options->forwardable; @@ -336,8 +401,9 @@ get_init_creds_common(krb5_context context, etypes = malloc((options->etype_list_length + 1) * sizeof(krb5_enctype)); if (etypes == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } memcpy (etypes, options->etype_list, options->etype_list_length * sizeof(krb5_enctype)); @@ -348,19 +414,24 @@ get_init_creds_common(krb5_context context, pre_auth_types = malloc((options->preauth_list_length + 1) * sizeof(krb5_preauthtype)); if (pre_auth_types == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } memcpy (pre_auth_types, options->preauth_list, options->preauth_list_length * sizeof(krb5_preauthtype)); pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE; ctx->pre_auth_types = pre_auth_types; } - if (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT) - ; /* XXX */ if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) ctx->flags.request_anonymous = options->anonymous; + if (default_opt) + krb5_get_init_creds_opt_free(context, default_opt); return 0; + out: + if (default_opt) + krb5_get_init_creds_opt_free(context, default_opt); + return ret; } static krb5_error_code @@ -382,18 +453,20 @@ change_password (krb5_context context, krb5_data result_code_string; krb5_data result_string; char *p; - krb5_get_init_creds_opt options; + krb5_get_init_creds_opt *options; memset (&cpw_cred, 0, sizeof(cpw_cred)); - krb5_get_init_creds_opt_init (&options); - krb5_get_init_creds_opt_set_tkt_life (&options, 60); - krb5_get_init_creds_opt_set_forwardable (&options, FALSE); - krb5_get_init_creds_opt_set_proxiable (&options, FALSE); + ret = krb5_get_init_creds_opt_alloc(context, &options); + if (ret) + return ret; + krb5_get_init_creds_opt_set_tkt_life (options, 60); + krb5_get_init_creds_opt_set_forwardable (options, FALSE); + krb5_get_init_creds_opt_set_proxiable (options, FALSE); if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) - krb5_get_init_creds_opt_set_preauth_list (&options, + krb5_get_init_creds_opt_set_preauth_list (options, old_options->preauth_list, - old_options->preauth_list_length); + old_options->preauth_list_length); krb5_data_zero (&result_code_string); krb5_data_zero (&result_string); @@ -406,7 +479,8 @@ change_password (krb5_context context, data, 0, "kadmin/changepw", - &options); + options); + krb5_get_init_creds_opt_free(context, options); if (ret) goto out; @@ -455,7 +529,9 @@ change_password (krb5_context context, (int)result_string.length, result_string.length > 0 ? (char*)result_string.data : ""); - ret = (*prompter) (context, data, NULL, p, 0, NULL); + /* return the result */ + (*prompter) (context, data, NULL, p, 0, NULL); + free (p); if (result_code == 0) { strlcpy (newpw, buf1, newpw_sz); @@ -475,6 +551,7 @@ out: return ret; } + krb5_error_code KRB5_LIB_FUNCTION krb5_keyblock_key_proc (krb5_context context, krb5_keytype type, @@ -485,68 +562,17 @@ krb5_keyblock_key_proc (krb5_context context, return krb5_copy_keyblock (context, keyseed, key); } -krb5_error_code KRB5_LIB_FUNCTION -krb5_get_init_creds_keytab(krb5_context context, - krb5_creds *creds, - krb5_principal client, - krb5_keytab keytab, - krb5_deltat start_time, - const char *in_tkt_service, - krb5_get_init_creds_opt *options) -{ - krb5_get_init_creds_ctx ctx; - krb5_error_code ret; - krb5_keytab_key_proc_args *a; - - ret = get_init_creds_common(context, client, start_time, - in_tkt_service, options, &ctx); - if (ret) - goto out; - - a = malloc (sizeof(*a)); - if (a == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto out; - } - a->principal = ctx.cred.client; - a->keytab = keytab; - - ret = krb5_get_in_cred (context, - KDCOptions2int(ctx.flags), - ctx.addrs, - ctx.etypes, - ctx.pre_auth_types, - NULL, - krb5_keytab_key_proc, - a, - NULL, - NULL, - &ctx.cred, - NULL); - free (a); - - if (ret == 0 && creds) - *creds = ctx.cred; - else - krb5_free_cred_contents (context, &ctx.cred); - - out: - free_init_creds_ctx(context, &ctx); - return ret; -} - /* * */ static krb5_error_code -init_creds_init_as_req (krb5_context context, - KDCOptions opts, - const krb5_creds *creds, - const krb5_addresses *addrs, - const krb5_enctype *etypes, - AS_REQ *a) +init_as_req (krb5_context context, + KDCOptions opts, + const krb5_creds *creds, + const krb5_addresses *addrs, + const krb5_enctype *etypes, + AS_REQ *a) { krb5_error_code ret; @@ -906,7 +932,7 @@ make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md, krb5_crypto_destroy(context, crypto); if (ret) return ret; - + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); free_EncryptedData(&encdata); if (ret) @@ -924,7 +950,7 @@ static krb5_error_code add_enc_ts_padata(krb5_context context, METHOD_DATA *md, krb5_principal client, - krb5_s2k_proc key_proc, + krb5_s2k_proc keyproc, krb5_const_pointer keyseed, krb5_enctype *enctypes, unsigned netypes, @@ -939,6 +965,8 @@ add_enc_ts_padata(krb5_context context, if(salt == NULL) { /* default to standard salt */ ret = krb5_get_pw_salt (context, client, &salt2); + if (ret) + return ret; salt = &salt2; } if (!enctypes) { @@ -951,8 +979,8 @@ add_enc_ts_padata(krb5_context context, for (i = 0; i < netypes; ++i) { krb5_keyblock *key; - ret = (*key_proc)(context, enctypes[i], keyseed, - *salt, s2kparams, &key); + ret = (*keyproc)(context, enctypes[i], keyseed, + *salt, s2kparams, &key); if (ret) continue; ret = make_pa_enc_timestamp (context, md, enctypes[i], key); @@ -973,28 +1001,28 @@ pa_data_to_md_ts_enc(krb5_context context, struct pa_info_data *ppaid, METHOD_DATA *md) { - if (ctx->key_proc == NULL || ctx->password == NULL) + if (ctx->keyproc == NULL || ctx->keyseed == NULL) return 0; if (ppaid) { add_enc_ts_padata(context, md, client, - ctx->key_proc, ctx->password, + ctx->keyproc, ctx->keyseed, &ppaid->etype, 1, &ppaid->salt, ppaid->s2kparams); } else { krb5_salt salt; - + /* make a v5 salted pa-data */ add_enc_ts_padata(context, md, client, - ctx->key_proc, ctx->password, + ctx->keyproc, ctx->keyseed, a->req_body.etype.val, a->req_body.etype.len, NULL, NULL); - + /* make a v4 salted pa-data */ salt.salttype = KRB5_PW_SALT; krb5_data_zero(&salt.saltvalue); add_enc_ts_padata(context, md, client, - ctx->key_proc, ctx->password, + ctx->keyproc, ctx->keyseed, a->req_body.etype.val, a->req_body.etype.len, &salt, NULL); } @@ -1012,7 +1040,7 @@ pa_data_to_key_plain(krb5_context context, { krb5_error_code ret; - ret = (*ctx->key_proc)(context, etype, ctx->password, + ret = (*ctx->keyproc)(context, etype, ctx->keyseed, salt, s2kparams, key); return ret; } @@ -1058,7 +1086,7 @@ pa_data_add_pac_request(krb5_context context, break; case KRB5_INIT_CREDS_TRISTATE_FALSE: req.include_pac = 0; - } + } ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length, &req, &len, ret); @@ -1111,12 +1139,12 @@ process_pa_data_to_md(krb5_context context, } else if (in_md->len != 0) { struct pa_info_data paid, *ppaid; - + memset(&paid, 0, sizeof(paid)); - + paid.etype = ENCTYPE_NULL; ppaid = process_pa_info(context, creds->client, a, &paid, in_md); - + pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md); if (ppaid) free_paid(context, ppaid); @@ -1137,7 +1165,7 @@ process_pa_data_to_key(krb5_context context, krb5_get_init_creds_ctx *ctx, krb5_creds *creds, AS_REQ *a, - krb5_kdc_rep *rep, + AS_REP *rep, const krb5_krbhst_info *hi, krb5_keyblock **key) { @@ -1148,12 +1176,12 @@ process_pa_data_to_key(krb5_context context, memset(&paid, 0, sizeof(paid)); - etype = rep->kdc_rep.enc_part.etype; + etype = rep->enc_part.etype; - if (rep->kdc_rep.padata) { + if (rep->padata) { paid.etype = etype; ppaid = process_pa_info(context, creds->client, a, &paid, - rep->kdc_rep.padata); + rep->padata); } if (ppaid == NULL) { ret = krb5_get_pw_salt (context, creds->client, &paid.salt); @@ -1164,16 +1192,16 @@ process_pa_data_to_key(krb5_context context, } pa = NULL; - if (rep->kdc_rep.padata) { + if (rep->padata) { int idx = 0; - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, + pa = krb5_find_padata(rep->padata->val, + rep->padata->len, KRB5_PADATA_PK_AS_REP, &idx); if (pa == NULL) { idx = 0; - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, + pa = krb5_find_padata(rep->padata->val, + rep->padata->len, KRB5_PADATA_PK_AS_REP_19, &idx); } @@ -1193,7 +1221,7 @@ process_pa_data_to_key(krb5_context context, ret = EINVAL; krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", "")); #endif - } else if (ctx->password) + } else if (ctx->keyseed) ret = pa_data_to_key_plain(context, creds->client, ctx, paid.salt, paid.s2kparams, etype, key); else { @@ -1205,109 +1233,340 @@ process_pa_data_to_key(krb5_context context, return ret; } -static krb5_error_code -init_cred_loop(krb5_context context, - krb5_get_init_creds_opt *init_cred_opts, - const krb5_prompter_fct prompter, - void *prompter_data, - krb5_get_init_creds_ctx *ctx, - krb5_creds *creds, - krb5_kdc_rep *ret_as_reply) +/** + * Start a new context to get a new initial credential. + * + * @param context A Kerberos 5 context. + * @param client The Kerberos principal to get the credential for, if + * NULL is given, the default principal is used as determined by + * krb5_get_default_principal(). + * @param prompter + * @param prompter_data + * @param start_time the time the ticket should start to be valid or 0 for now. + * @param options a options structure, can be NULL for default options. + * @param rctx A new allocated free with krb5_init_creds_free(). + * + * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_init(krb5_context context, + krb5_principal client, + krb5_prompter_fct prompter, + void *prompter_data, + krb5_deltat start_time, + krb5_get_init_creds_opt *options, + krb5_init_creds_context *rctx) { + krb5_init_creds_context ctx; krb5_error_code ret; - krb5_kdc_rep rep; - METHOD_DATA md; - krb5_data resp; - size_t len; - size_t size; - krb5_krbhst_info *hi = NULL; - krb5_sendto_ctx stctx = NULL; - - memset(&md, 0, sizeof(md)); - memset(&rep, 0, sizeof(rep)); + *rctx = NULL; - _krb5_get_init_creds_opt_free_krb5_error(init_cred_opts); - - if (ret_as_reply) - memset(ret_as_reply, 0, sizeof(*ret_as_reply)); + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } - ret = init_creds_init_as_req(context, ctx->flags, creds, - ctx->addrs, ctx->etypes, &ctx->as_req); - if (ret) + ret = get_init_creds_common(context, client, start_time, options, ctx); + if (ret) { + free(ctx); return ret; - - ret = krb5_sendto_ctx_alloc(context, &stctx); - if (ret) - goto out; - krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + } /* Set a new nonce. */ krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce)); - ctx->nonce &= 0xffffffff; + ctx->nonce &= 0x7fffffff; /* XXX these just needs to be the same when using Windows PK-INIT */ ctx->pk_nonce = ctx->nonce; - /* - * Increase counter when we want other pre-auth types then - * KRB5_PA_ENC_TIMESTAMP. - */ -#define MAX_PA_COUNTER 3 + ctx->prompter = prompter; + ctx->prompter_data = prompter_data; - ctx->pa_counter = 0; - while (ctx->pa_counter < MAX_PA_COUNTER) { + *rctx = ctx; - ctx->pa_counter++; + return ret; +} - if (ctx->as_req.padata) { - free_METHOD_DATA(ctx->as_req.padata); - free(ctx->as_req.padata); - ctx->as_req.padata = NULL; - } +/** + * Sets the service that the is requested. This call is only neede for + * special initial tickets, by default the a krbtgt is fetched in the default realm. + * + * @param context a Kerberos 5 context. + * @param ctx a krb5_init_creds_context context. + * @param service the service given as a string, for example + * "kadmind/admin". If NULL, the default krbtgt in the clients + * realm is set. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ - /* Set a new nonce. */ - ctx->as_req.req_body.nonce = ctx->nonce; +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_service(krb5_context context, + krb5_init_creds_context ctx, + const char *service) +{ + krb5_const_realm client_realm; + krb5_principal principal; + krb5_error_code ret; + + client_realm = krb5_principal_get_realm (context, ctx->cred.client); - /* fill_in_md_data */ - ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx, - &md, &ctx->as_req.padata, - prompter, prompter_data); + if (service) { + ret = krb5_parse_name (context, service, &principal); if (ret) - goto out; + return ret; + krb5_principal_set_realm (context, principal, client_realm); + } else { + ret = krb5_make_principal(context, &principal, + client_realm, KRB5_TGS_NAME, client_realm, + NULL); + if (ret) + return ret; + } + krb5_free_principal(context, ctx->cred.server); + ctx->cred.server = principal; - krb5_data_free(&ctx->req_buffer); + return 0; +} - ASN1_MALLOC_ENCODE(AS_REQ, - ctx->req_buffer.data, ctx->req_buffer.length, - &ctx->as_req, &len, ret); - if (ret) - goto out; - if(len != ctx->req_buffer.length) - krb5_abortx(context, "internal error in ASN.1 encoder"); +/** + * Sets the password that will use for the request. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param password the password to use. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ - ret = krb5_sendto_context (context, stctx, &ctx->req_buffer, - creds->client->realm, &resp); - if (ret) - goto out; +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_password(krb5_context context, + krb5_init_creds_context ctx, + const char *password) +{ + if (ctx->password) + memset(ctx->password, 0, strlen(ctx->password)); + if (password) { + ctx->password = strdup(password); + if (ctx->password == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } + ctx->keyseed = (void *) ctx->password; + } else { + ctx->keyseed = NULL; + ctx->password = NULL; + } + + return 0; +} + +static krb5_error_code +keytab_key_proc(krb5_context context, krb5_enctype enctype, + krb5_const_pointer keyseed, + krb5_salt salt, krb5_data *s2kparms, + krb5_keyblock **key) +{ + krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); + krb5_keytab keytab = args->keytab; + krb5_principal principal = args->principal; + krb5_error_code ret; + krb5_keytab real_keytab; + krb5_keytab_entry entry; + + if(keytab == NULL) + krb5_kt_default(context, &real_keytab); + else + real_keytab = keytab; + + ret = krb5_kt_get_entry (context, real_keytab, principal, + 0, enctype, &entry); + + if (keytab == NULL) + krb5_kt_close (context, real_keytab); + + if (ret) + return ret; + + ret = krb5_copy_keyblock (context, &entry.keyblock, key); + krb5_kt_free_entry(context, &entry); + return ret; +} + + +/** + * Set the keytab to use for authentication. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param keytab the keytab to read the key from. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_keytab(krb5_context context, + krb5_init_creds_context ctx, + krb5_keytab keytab) +{ + krb5_keytab_key_proc_args *a; + + a = malloc(sizeof(*a)); + if (a == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } + + a->principal = ctx->cred.client; + a->keytab = keytab; + + ctx->keytab_data = a; + ctx->keyseed = (void *)a; + ctx->keyproc = keytab_key_proc; + + return 0; +} + +static krb5_error_code +keyblock_key_proc(krb5_context context, krb5_enctype enctype, + krb5_const_pointer keyseed, + krb5_salt salt, krb5_data *s2kparms, + krb5_keyblock **key) +{ + return krb5_copy_keyblock (context, keyseed, key); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_keyblock(krb5_context context, + krb5_init_creds_context ctx, + krb5_keyblock *keyblock) +{ + ctx->keyseed = (void *)keyblock; + ctx->keyproc = keyblock_key_proc; + + return 0; +} + +/** + * The core loop if krb5_get_init_creds() function family. Create the + * packets and have the caller send them off to the KDC. + * + * If the caller want all work been done for them, use + * krb5_init_creds_get() instead. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param in input data from KDC, first round it should be reset by krb5_data_zer(). + * @param out reply to KDC. + * @param hostinfo KDC address info, first round it can be NULL. + * @param flags status of the round, if 1 is set, continue one more round. + * + * @return 0 for success, or an Kerberos 5 error code, see + * krb5_get_error_message(). + * + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_step(krb5_context context, + krb5_init_creds_context ctx, + krb5_data *in, + krb5_data *out, + krb5_krbhst_info *hostinfo, + unsigned int *flags) +{ + krb5_error_code ret; + size_t len; + size_t size; - memset (&rep, 0, sizeof(rep)); - ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size); + krb5_data_zero(out); + + if (ctx->as_req.req_body.cname == NULL) { + ret = init_as_req(context, ctx->flags, &ctx->cred, + ctx->addrs, ctx->etypes, &ctx->as_req); + if (ret) { + free_init_creds_ctx(context, ctx); + return ret; + } + } + +#define MAX_PA_COUNTER 10 + if (ctx->pa_counter > MAX_PA_COUNTER) { + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + N_("Looping %d times while getting " + "initial credentials", ""), + ctx->pa_counter); + return KRB5_GET_IN_TKT_LOOP; + } + ctx->pa_counter++; + + /* Lets process the input packet */ + if (in && in->length) { + krb5_kdc_rep rep; + + memset(&rep, 0, sizeof(rep)); + + ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); if (ret == 0) { - krb5_data_free(&resp); - krb5_clear_error_message(context); - break; + krb5_keyblock *key = NULL; + unsigned eflags = EXTRACT_TICKET_AS_REQ; + + if (ctx->flags.canonicalize) { + eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; + eflags |= EXTRACT_TICKET_MATCH_REALM; + } + if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) + eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + + ret = process_pa_data_to_key(context, ctx, &ctx->cred, + &ctx->as_req, &rep.kdc_rep, hostinfo, &key); + if (ret) { + free_AS_REP(&rep.kdc_rep); + goto out; + } + + ret = _krb5_extract_ticket(context, + &rep, + &ctx->cred, + key, + NULL, + KRB5_KU_AS_REP_ENC_PART, + NULL, + ctx->nonce, + eflags, + NULL, + NULL); + krb5_free_keyblock(context, key); + + *flags = 0; + + if (ret == 0) + ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); + + free_AS_REP(&rep.kdc_rep); + free_EncASRepPart(&rep.enc_part); + + return ret; + } else { /* let's try to parse it as a KRB-ERROR */ - KRB_ERROR error; - ret = krb5_rd_error(context, &resp, &error); - if(ret && resp.data && ((char*)resp.data)[0] == 4) + free_KRB_ERROR(&ctx->error); + + ret = krb5_rd_error(context, in, &ctx->error); + if(ret && in->length && ((char*)in->data)[0] == 4) ret = KRB5KRB_AP_ERR_V4_REPLY; - krb5_data_free(&resp); if (ret) goto out; - ret = krb5_error_from_rd_error(context, &error, creds); + ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); /* * If no preauth was set and KDC requires it, give it one @@ -1315,169 +1574,198 @@ init_cred_loop(krb5_context context, */ if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) { - free_METHOD_DATA(&md); - memset(&md, 0, sizeof(md)); - if (error.e_data) { - ret = decode_METHOD_DATA(error.e_data->data, - error.e_data->length, - &md, + free_METHOD_DATA(&ctx->md); + memset(&ctx->md, 0, sizeof(ctx->md)); + + if (ctx->error.e_data) { + ret = decode_METHOD_DATA(ctx->error.e_data->data, + ctx->error.e_data->length, + &ctx->md, NULL); if (ret) krb5_set_error_message(context, ret, - N_("failed to decode METHOD DATA", "")); + N_("Failed to decode METHOD-DATA", "")); } else { - /* XXX guess what the server want here add add md */ + krb5_set_error_message(context, ret, + N_("Preauth required but no preauth " + "options send by KDC", "")); } - krb5_free_error_contents(context, &error); - if (ret) + } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) { + /* + * Try adapt to timeskrew when we are using pre-auth, and + * if there was a time skew, try again. + */ + krb5_set_real_time(context, ctx->error.stime, -1); + if (context->kdc_sec_offset) + ret = 0; + } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { + /* client referal to a new realm */ + if (ctx->error.crealm) { + krb5_set_error_message(context, ret, + N_("Got a client referral, not but no realm", "")); goto out; - } else { - _krb5_get_init_creds_opt_set_krb5_error(context, - init_cred_opts, - &error); - if (ret_as_reply) - rep.error = error; - else - krb5_free_error_contents(context, &error); - goto out; + } + ret = krb5_principal_set_realm(context, + ctx->cred.client, + *ctx->error.crealm); } + if (ret) + goto out; } } - { - krb5_keyblock *key = NULL; - unsigned flags = EXTRACT_TICKET_AS_REQ; + if (ctx->as_req.padata) { + free_METHOD_DATA(ctx->as_req.padata); + free(ctx->as_req.padata); + ctx->as_req.padata = NULL; + } - if (ctx->flags.request_anonymous) - flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; - if (ctx->flags.canonicalize) { - flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; - flags |= EXTRACT_TICKET_MATCH_REALM; - } - if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) - flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + /* Set a new nonce. */ + ctx->as_req.req_body.nonce = ctx->nonce; + + /* fill_in_md_data */ + ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx, + &ctx->md, &ctx->as_req.padata, + ctx->prompter, ctx->prompter_data); + if (ret) + goto out; - ret = process_pa_data_to_key(context, ctx, creds, - &ctx->as_req, &rep, hi, &key); - if (ret) - goto out; - - ret = _krb5_extract_ticket(context, - &rep, - creds, - key, - NULL, - KRB5_KU_AS_REP_ENC_PART, - NULL, - ctx->nonce, - flags, - NULL, - NULL); - krb5_free_keyblock(context, key); - } -out: - if (stctx) - krb5_sendto_ctx_free(context, stctx); krb5_data_free(&ctx->req_buffer); - free_METHOD_DATA(&md); - memset(&md, 0, sizeof(md)); - if (ret == 0 && ret_as_reply) - *ret_as_reply = rep; - else - krb5_free_kdc_rep (context, &rep); + ASN1_MALLOC_ENCODE(AS_REQ, + ctx->req_buffer.data, ctx->req_buffer.length, + &ctx->as_req, &len, ret); + if (ret) + goto out; + if(len != ctx->req_buffer.length) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + out->data = ctx->req_buffer.data; + out->length = ctx->req_buffer.length; + + *flags = 1; + + return 0; + out: return ret; } +/** + * Extract the newly acquired credentials from krb5_init_creds_context + * context. + * + * @param context A Kerberos 5 context. + * @param ctx + * @param cred credentials, free with krb5_free_cred_contents(). + * + * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message(). + */ + krb5_error_code KRB5_LIB_FUNCTION -krb5_get_init_creds(krb5_context context, - krb5_creds *creds, - krb5_principal client, - krb5_prompter_fct prompter, - void *data, - krb5_deltat start_time, - const char *in_tkt_service, - krb5_get_init_creds_opt *options) +krb5_init_creds_get_creds(krb5_context context, + krb5_init_creds_context ctx, + krb5_creds *cred) { - krb5_get_init_creds_ctx ctx; - krb5_kdc_rep kdc_reply; - krb5_error_code ret; - char buf[BUFSIZ]; - int done; + return krb5_copy_creds_contents(context, &ctx->cred, cred); +} + +/** + * Get the last error from the transaction. + * + * @return Returns 0 or an error code + * + * @ingroup krb5_credential + */ - memset(&kdc_reply, 0, sizeof(kdc_reply)); +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_get_error(krb5_context context, + krb5_init_creds_context ctx, + KRB_ERROR *error) +{ + krb5_error_code ret; - ret = get_init_creds_common(context, client, start_time, - in_tkt_service, options, &ctx); + ret = copy_KRB_ERROR(&ctx->error, error); if (ret) - goto out; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - done = 0; - while(!done) { - memset(&kdc_reply, 0, sizeof(kdc_reply)); - - ret = init_cred_loop(context, - options, - prompter, - data, - &ctx, - &ctx.cred, - &kdc_reply); - - switch (ret) { - case 0 : - done = 1; - break; - case KRB5KDC_ERR_KEY_EXPIRED : - /* try to avoid recursion */ + return ret; +} - /* don't try to change password where then where none */ - if (prompter == NULL || ctx.password == NULL) - goto out; +/** + * Free the krb5_init_creds_context allocated by krb5_init_creds_init(). + * + * @param context A Kerberos 5 context. + * @param ctx The krb5_init_creds_context to free. + * + * @ingroup krb5_credential + */ - krb5_clear_error_message (context); +void KRB5_LIB_FUNCTION +krb5_init_creds_free(krb5_context context, + krb5_init_creds_context ctx) +{ + free_init_creds_ctx(context, ctx); + free(ctx); +} - if (ctx.in_tkt_service != NULL - && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0) - goto out; +/** + * Get new credentials as setup by the krb5_init_creds_context. + * + * @param context A Kerberos 5 context. + * @param ctx The krb5_init_creds_context to process. + * + * @ingroup krb5_credential + */ - ret = change_password (context, - client, - ctx.password, - buf, - sizeof(buf), - prompter, - data, - options); - if (ret) - goto out; - ctx.password = buf; +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_sendto_ctx stctx = NULL; + krb5_krbhst_info *hostinfo = NULL; + krb5_error_code ret; + krb5_data in, out; + unsigned int flags = 0; + + krb5_data_zero(&in); + krb5_data_zero(&out); + + ret = krb5_sendto_ctx_alloc(context, &stctx); + if (ret) + goto out; + krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + + while (1) { + flags = 0; + ret = krb5_init_creds_step(context, ctx, &in, &out, hostinfo, &flags); + krb5_data_free(&in); + if (ret) + goto out; + + if ((flags & 1) == 0) break; - default: + + ret = krb5_sendto_context (context, stctx, &out, + ctx->cred.client->realm, &in); + if (ret) goto out; - } - } - if (prompter) - print_expire (context, - krb5_principal_get_realm (context, ctx.cred.client), - &kdc_reply, - prompter, - data); + } out: - memset (buf, 0, sizeof(buf)); - free_init_creds_ctx(context, &ctx); - krb5_free_kdc_rep (context, &kdc_reply); - if (ret == 0) - *creds = ctx.cred; - else - krb5_free_cred_contents (context, &ctx.cred); + if (stctx) + krb5_sendto_ctx_free(context, stctx); return ret; } +/** + * Get new credentials using password. + * + * @ingroup krb5_credential + */ + + krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, @@ -1487,29 +1775,23 @@ krb5_get_init_creds_password(krb5_context context, void *data, krb5_deltat start_time, const char *in_tkt_service, - krb5_get_init_creds_opt *in_options) + krb5_get_init_creds_opt *options) { - krb5_get_init_creds_opt *options; + krb5_init_creds_context ctx; char buf[BUFSIZ]; krb5_error_code ret; + int chpw = 0; - if (in_options == NULL) { - const char *realm = krb5_principal_get_realm(context, client); - ret = krb5_get_init_creds_opt_alloc(context, &options); - if (ret == 0) - krb5_get_init_creds_opt_set_default_flags(context, - NULL, - realm, - options); - } else - ret = _krb5_get_init_creds_opt_copy(context, in_options, &options); + again: + ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx); if (ret) - return ret; + goto out; - if (password == NULL && - options->opt_private->password == NULL && - options->opt_private->pk_init_ctx == NULL) - { + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + if (prompter != NULL && ctx->password == NULL && password == NULL) { krb5_prompt prompt; krb5_data password_data; char *p, *q; @@ -1528,40 +1810,67 @@ krb5_get_init_creds_password(krb5_context context, free (q); if (ret) { memset (buf, 0, sizeof(buf)); - krb5_get_init_creds_opt_free(context, options); ret = KRB5_LIBOS_PWDINTR; krb5_clear_error_message (context); - return ret; + goto out; } password = password_data.data; } - if (options->opt_private->password == NULL) { - ret = krb5_get_init_creds_opt_set_pa_password(context, options, - password, NULL); - if (ret) { - krb5_get_init_creds_opt_free(context, options); - memset(buf, 0, sizeof(buf)); - return ret; - } + if (password) { + ret = krb5_init_creds_set_password(context, ctx, password); + if (ret) + goto out; } - ret = krb5_get_init_creds(context, creds, client, prompter, - data, start_time, in_tkt_service, options); - krb5_get_init_creds_opt_free(context, options); + ret = krb5_init_creds_get(context, ctx); + + if (ret == 0) + process_last_request(context, options, ctx); + + + if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) { + char buf[1024]; + + /* try to avoid recursion */ + if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0) + goto out; + + /* don't try to change password where then where none */ + if (prompter == NULL) + goto out; + + ret = change_password (context, + client, + ctx->password, + buf, + sizeof(buf), + prompter, + data, + options); + if (ret) + goto out; + chpw = 1; + krb5_init_creds_free(context, ctx); + goto again; + } + + out: + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + memset(buf, 0, sizeof(buf)); return ret; } -static krb5_error_code -init_creds_keyblock_key_proc (krb5_context context, - krb5_enctype type, - krb5_salt salt, - krb5_const_pointer keyseed, - krb5_keyblock **key) -{ - return krb5_copy_keyblock (context, keyseed, key); -} +/** + * Get new credentials using keyblock. + * + * @ingroup krb5_credential + */ krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_keyblock(krb5_context context, @@ -1572,33 +1881,80 @@ krb5_get_init_creds_keyblock(krb5_context context, const char *in_tkt_service, krb5_get_init_creds_opt *options) { - struct krb5_get_init_creds_ctx ctx; + krb5_init_creds_context ctx; krb5_error_code ret; - ret = get_init_creds_common(context, client, start_time, - in_tkt_service, options, &ctx); + memset(creds, 0, sizeof(*creds)); + + ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); if (ret) goto out; - ret = krb5_get_in_cred (context, - KDCOptions2int(ctx.flags), - ctx.addrs, - ctx.etypes, - ctx.pre_auth_types, - NULL, - init_creds_keyblock_key_proc, - keyblock, - NULL, - NULL, - &ctx.cred, - NULL); - - if (ret == 0 && creds) - *creds = ctx.cred; - else - krb5_free_cred_contents (context, &ctx.cred); + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + ret = krb5_init_creds_set_keyblock(context, ctx, keyblock); + if (ret) + goto out; + + ret = krb5_init_creds_get(context, ctx); + + if (ret == 0) + process_last_request(context, options, ctx); + + out: + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + + return ret; +} + +/** + * Get new credentials using keytab. + * + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_init_creds_keytab(krb5_context context, + krb5_creds *creds, + krb5_principal client, + krb5_keytab keytab, + krb5_deltat start_time, + const char *in_tkt_service, + krb5_get_init_creds_opt *options) +{ + krb5_init_creds_context ctx; + krb5_error_code ret; + + memset(creds, 0, sizeof(*creds)); + + ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); + if (ret) + goto out; + + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + ret = krb5_init_creds_set_keytab(context, ctx, keytab); + if (ret) + goto out; + + ret = krb5_init_creds_get(context, ctx); + if (ret == 0) + process_last_request(context, options, ctx); out: - free_init_creds_ctx(context, &ctx); + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + return ret; } diff --git a/source4/heimdal/lib/krb5/kcm.c b/source4/heimdal/lib/krb5/kcm.c index 8a8f1efc11..f034341972 100644 --- a/source4/heimdal/lib/krb5/kcm.c +++ b/source4/heimdal/lib/krb5/kcm.c @@ -43,17 +43,24 @@ #include "kcm.h" -RCSID("$Id$"); - typedef struct krb5_kcmcache { char *name; struct sockaddr_un path; char *door_path; } krb5_kcmcache; +typedef struct krb5_kcm_cursor { + unsigned long offset; + unsigned long length; + kcmuuid_t *uuids; +} *krb5_kcm_cursor; + + #define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data) #define CACHENAME(X) (KCMCACHE(X)->name) -#define KCMCURSOR(C) (*(uint32_t *)(C)) +#define KCMCURSOR(C) ((krb5_kcm_cursor)(C)) + +#ifdef HAVE_DOOR_CREATE static krb5_error_code try_door(krb5_context context, @@ -61,7 +68,6 @@ try_door(krb5_context context, krb5_data *request_data, krb5_data *response_data) { -#ifdef HAVE_DOOR_CREATE door_arg_t arg; int fd; int ret; @@ -91,10 +97,8 @@ try_door(krb5_context context, return ret; return 0; -#else - return KRB5_CC_IO; -#endif } +#endif /* HAVE_DOOR_CREATE */ static krb5_error_code try_unix_socket(krb5_context context, @@ -143,9 +147,11 @@ kcm_send_request(krb5_context context, ret = KRB5_CC_NOSUPP; for (i = 0; i < context->max_retries; i++) { +#ifdef HAVE_DOOR_CREATE ret = try_door(context, k, &request_data, response_data); if (ret == 0 && response_data->length != 0) break; +#endif ret = try_unix_socket(context, k, &request_data, response_data); if (ret == 0 && response_data->length != 0) break; @@ -207,7 +213,8 @@ kcm_alloc(krb5_context context, const char *name, krb5_ccache *id) k = malloc(sizeof(*k)); if (k == NULL) { - krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", "")); + krb5_set_error_message(context, KRB5_CC_NOMEM, + N_("malloc: out of memory", "")); return KRB5_CC_NOMEM; } @@ -309,8 +316,6 @@ kcm_free(krb5_context context, krb5_ccache *id) memset(k, 0, sizeof(*k)); krb5_data_free(&(*id)->data); } - - *id = NULL; } static const char * @@ -609,10 +614,10 @@ kcm_get_first (krb5_context context, krb5_cc_cursor *cursor) { krb5_error_code ret; + krb5_kcm_cursor c; krb5_kcmcache *k = KCMCACHE(id); krb5_storage *request, *response; krb5_data response_data; - int32_t tmp; ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request); if (ret) @@ -625,27 +630,56 @@ kcm_get_first (krb5_context context, } ret = kcm_call(context, k, request, &response, &response_data); - if (ret) { - krb5_storage_free(request); + krb5_storage_free(request); + if (ret) + return ret; + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); return ret; } - ret = krb5_ret_int32(response, &tmp); - if (ret || tmp < 0) - ret = KRB5_CC_IO; + while (1) { + ssize_t sret; + kcmuuid_t uuid; + void *ptr; + + sret = krb5_storage_read(response, &uuid, sizeof(uuid)); + if (sret == 0) { + ret = 0; + break; + } else if (sret != sizeof(uuid)) { + ret = EINVAL; + break; + } + + ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1)); + if (ptr == NULL) { + free(c->uuids); + free(c); + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + c->uuids = ptr; + + memcpy(&c->uuids[c->length], &uuid, sizeof(uuid)); + c->length += 1; + } - krb5_storage_free(request); krb5_storage_free(response); krb5_data_free(&response_data); - if (ret) + if (ret) { + free(c->uuids); + free(c); return ret; + } - *cursor = malloc(sizeof(tmp)); - if (*cursor == NULL) - return KRB5_CC_NOMEM; - - KCMCURSOR(*cursor) = tmp; + *cursor = c; return 0; } @@ -666,8 +700,15 @@ kcm_get_next (krb5_context context, { krb5_error_code ret; krb5_kcmcache *k = KCMCACHE(id); + krb5_kcm_cursor c = KCMCURSOR(*cursor); krb5_storage *request, *response; krb5_data response_data; + ssize_t sret; + + again: + + if (c->offset >= c->length) + return KRB5_CC_END; ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request); if (ret) @@ -679,23 +720,26 @@ kcm_get_next (krb5_context context, return ret; } - ret = krb5_store_int32(request, KCMCURSOR(*cursor)); - if (ret) { + sret = krb5_storage_write(request, + &c->uuids[c->offset], + sizeof(c->uuids[c->offset])); + c->offset++; + if (sret != sizeof(c->uuids[c->offset])) { krb5_storage_free(request); - return ret; + krb5_clear_error_message(context); + return ENOMEM; } ret = kcm_call(context, k, request, &response, &response_data); - if (ret) { - krb5_storage_free(request); - return ret; + krb5_storage_free(request); + if (ret == KRB5_CC_END) { + goto again; } ret = krb5_ret_creds(response, creds); if (ret) ret = KRB5_CC_IO; - krb5_storage_free(request); krb5_storage_free(response); krb5_data_free(&response_data); @@ -717,6 +761,7 @@ kcm_end_get (krb5_context context, { krb5_error_code ret; krb5_kcmcache *k = KCMCACHE(id); + krb5_kcm_cursor c = KCMCURSOR(*cursor); krb5_storage *request; ret = kcm_storage_request(context, KCM_OP_END_GET, &request); @@ -729,22 +774,14 @@ kcm_end_get (krb5_context context, return ret; } - ret = krb5_store_int32(request, KCMCURSOR(*cursor)); - if (ret) { - krb5_storage_free(request); - return ret; - } - ret = kcm_call(context, k, request, NULL, NULL); - if (ret) { - krb5_storage_free(request); + krb5_storage_free(request); + if (ret) return ret; - } - krb5_storage_free(request); + free(c->uuids); + free(c); - KCMCURSOR(*cursor) = 0; - free(*cursor); *cursor = NULL; return ret; diff --git a/source4/heimdal/lib/krb5/keyblock.c b/source4/heimdal/lib/krb5/keyblock.c index aa6353d7c8..57ed7875fc 100644 --- a/source4/heimdal/lib/krb5/keyblock.c +++ b/source4/heimdal/lib/krb5/keyblock.c @@ -33,7 +33,13 @@ #include "krb5_locl.h" -RCSID("$Id$"); +/** + * Zero out a keyblock + * + * @param keyblock keyblock to zero out + * + * @ingroup krb5_crypto + */ void KRB5_LIB_FUNCTION krb5_keyblock_zero(krb5_keyblock *keyblock) @@ -42,6 +48,15 @@ krb5_keyblock_zero(krb5_keyblock *keyblock) krb5_data_zero(&keyblock->keyvalue); } +/** + * Free a keyblock's content, also zero out the content of the keyblock. + * + * @param context a Kerberos 5 context + * @param keyblock keyblock content to free, NULL is valid argument + * + * @ingroup krb5_crypto + */ + void KRB5_LIB_FUNCTION krb5_free_keyblock_contents(krb5_context context, krb5_keyblock *keyblock) @@ -54,6 +69,16 @@ krb5_free_keyblock_contents(krb5_context context, } } +/** + * Free a keyblock, also zero out the content of the keyblock, uses + * krb5_free_keyblock_contents() to free the content. + * + * @param context a Kerberos 5 context + * @param keyblock keyblock to free, NULL is valid argument + * + * @ingroup krb5_crypto + */ + void KRB5_LIB_FUNCTION krb5_free_keyblock(krb5_context context, krb5_keyblock *keyblock) @@ -64,6 +89,19 @@ krb5_free_keyblock(krb5_context context, } } +/** + * Copy a keyblock, free the output keyblock with + * krb5_free_keyblock_contents(). + * + * @param context a Kerberos 5 context + * @param inblock the key to copy + * @param to the output key. + * + * @param 0 on success or a Kerberos 5 error code + * + * @ingroup krb5_crypto + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_copy_keyblock_contents (krb5_context context, const krb5_keyblock *inblock, @@ -72,31 +110,62 @@ krb5_copy_keyblock_contents (krb5_context context, return copy_EncryptionKey(inblock, to); } +/** + * Copy a keyblock, free the output keyblock with + * krb5_free_keyblock(). + * + * @param context a Kerberos 5 context + * @param inblock the key to copy + * @param to the output key. + * + * @param 0 on success or a Kerberos 5 error code + * + * @ingroup krb5_crypto + */ + + krb5_error_code KRB5_LIB_FUNCTION krb5_copy_keyblock (krb5_context context, const krb5_keyblock *inblock, krb5_keyblock **to) { + krb5_error_code ret; krb5_keyblock *k; + + *to = NULL; - k = malloc (sizeof(*k)); + k = calloc (1, sizeof(*k)); if (k == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } + + ret = krb5_copy_keyblock_contents (context, inblock, k); + if (ret) { + free(k); + return ret; + } *to = k; - return krb5_copy_keyblock_contents (context, inblock, k); + return 0; } +/** + * Get encryption type of a keyblock. + * + * @ingroup krb5_crypto + */ + krb5_enctype krb5_keyblock_get_enctype(const krb5_keyblock *block) { return block->keytype; } -/* +/** * Fill in `key' with key data of type `enctype' from `data' of length - * `size'. Key should be freed using krb5_free_keyblock_contents. + * `size'. Key should be freed using krb5_free_keyblock_contents(). + * + * @ingroup krb5_crypto */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/keytab.c b/source4/heimdal/lib/krb5/keytab.c index aa7c77ce46..fcc74e847e 100644 --- a/source4/heimdal/lib/krb5/keytab.c +++ b/source4/heimdal/lib/krb5/keytab.c @@ -33,11 +33,114 @@ #include "krb5_locl.h" -RCSID("$Id$"); +/** + * @page krb5_keytab_intro The keytab handing functions + * @section section_krb5_keytab Kerberos Keytabs + * + * See the library functions here: @ref krb5_keytab + * + * Keytabs are long term key storage for servers, their equvalment of + * password files. + * + * Normally the only function that useful for server are to specify + * what keytab to use to other core functions like krb5_rd_req() + * krb5_kt_resolve(), and krb5_kt_close(). + * + * @subsection krb5_keytab_names Keytab names + * + * A keytab name is on the form type:residual. The residual part is + * specific to each keytab-type. + * + * When a keytab-name is resolved, the type is matched with an internal + * list of keytab types. If there is no matching keytab type, + * the default keytab is used. The current default type is FILE. + * + * The default value can be changed in the configuration file + * /etc/krb5.conf by setting the variable + * [defaults]default_keytab_name. + * + * The keytab types that are implemented in Heimdal are: + * - file + * store the keytab in a file, the type's name is FILE . The + * residual part is a filename. For compatibility with other + * Kerberos implemtation WRFILE and JAVA14 is also accepted. WRFILE + * has the same format as FILE. JAVA14 have a format that is + * compatible with older versions of MIT kerberos and SUN's Java + * based installation. They store a truncted kvno, so when the knvo + * excess 255, they are truncted in this format. + * + * - keytab + * store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ), + * the type's name is AFSKEYFILE. The residual part is a filename. + * + * - krb4 + * the keytab is a Kerberos 4 srvtab that is on-the-fly converted to + * a keytab. The type's name is krb4 The residual part is a + * filename. + * + * - memory + * The keytab is stored in a memory segment. This allows sensitive + * and/or temporary data not to be stored on disk. The type's name + * is MEMORY. Each MEMORY keytab is referenced counted by and + * opened by the residual name, so two handles can point to the + * same memory area. When the last user closes the entry, it + * disappears. + * + * + * @subsection krb5_keytab_example Keytab example + * + * This is a minimalistic version of ktutil. + * + * @code +int +main (int argc, char **argv) +{ + krb5_context context; + krb5_keytab keytab; + krb5_kt_cursor cursor; + krb5_keytab_entry entry; + krb5_error_code ret; + char *principal; -/* - * Register a new keytab in `ops' - * Return 0 or an error. + if (krb5_init_context (&context) != 0) + errx(1, "krb5_context"); + + ret = krb5_kt_default (context, &keytab); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_default"); + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_start_seq_get"); + while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){ + krb5_unparse_name_short(context, entry.principal, &principal); + printf("principal: %s\n", principal); + free(principal); + krb5_kt_free_entry(context, &entry); + } + ret = krb5_kt_end_seq_get(context, keytab, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_end_seq_get"); + ret = krb5_kt_close(context, keytab); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_close"); + krb5_free_context(context); + return 0; +} + * @endcode + * + */ + + +/** + * Register a new keytab backend. + * + * @param context a Keberos context. + * @param ops a backend to register. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -55,7 +158,8 @@ krb5_kt_register(krb5_context context, tmp = realloc(context->kt_types, (context->num_kt_types + 1) * sizeof(*context->kt_types)); if(tmp == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); return ENOMEM; } memcpy(&tmp[context->num_kt_types], ops, @@ -65,12 +169,20 @@ krb5_kt_register(krb5_context context, return 0; } -/* +/** * Resolve the keytab name (of the form `type:residual') in `name' * into a keytab in `id'. - * Return 0 or an error + * + * @param context a Keberos context. + * @param name name to resolve + * @param id resulting keytab, free with krb5_kt_close(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ + krb5_error_code KRB5_LIB_FUNCTION krb5_kt_resolve(krb5_context context, const char *name, @@ -120,9 +232,16 @@ krb5_kt_resolve(krb5_context context, return ret; } -/* +/** * copy the name of the default keytab into `name'. - * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. + * + * @param context a Keberos context. + * @param name buffer where the name will be written + * @param namesize length of name + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -135,9 +254,16 @@ krb5_kt_default_name(krb5_context context, char *name, size_t namesize) return 0; } -/* - * copy the name of the default modify keytab into `name'. - * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. +/** + * Copy the name of the default modify keytab into `name'. + * + * @param context a Keberos context. + * @param name buffer where the name will be written + * @param namesize length of name + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -166,9 +292,15 @@ krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize) return 0; } -/* +/** * Set `id' to the default keytab. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param id the new default keytab. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -177,10 +309,20 @@ krb5_kt_default(krb5_context context, krb5_keytab *id) return krb5_kt_resolve (context, context->default_keytab, id); } -/* +/** * Read the key identified by `(principal, vno, enctype)' from the * keytab in `keyprocarg' (the default if == NULL) into `*key'. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param keyprocarg + * @param principal + * @param vno + * @param enctype + * @param key + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -212,9 +354,18 @@ krb5_kt_read_service_key(krb5_context context, return ret; } -/* +/** * Return the type of the `keytab' in the string `prefix of length * `prefixsize'. + * + * @param context a Keberos context. + * @param keytab the keytab to get the prefix for + * @param prefix prefix buffer + * @param prefixsize length of prefix buffer + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -227,9 +378,17 @@ krb5_kt_get_type(krb5_context context, return 0; } -/* +/** * Retrieve the name of the keytab `keytab' into `name', `namesize' - * Return 0 or an error. + * + * @param context a Keberos context. + * @param keytab the keytab to get the name for. + * @param name name buffer. + * @param namesize size of name buffer. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -241,10 +400,18 @@ krb5_kt_get_name(krb5_context context, return (*keytab->get_name)(context, keytab, name, namesize); } -/* +/** * Retrieve the full name of the keytab `keytab' and store the name in - * `str'. `str' needs to be freed by the caller using free(3). - * Returns 0 or an error. On error, *str is set to NULL. + * `str'. + * + * @param context a Keberos context. + * @param keytab keytab to get name for. + * @param str the name of the keytab name, usee krb5_xfree() to free + * the string. On error, *str is set to NULL. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -275,9 +442,16 @@ krb5_kt_get_full_name(krb5_context context, return 0; } -/* +/** * Finish using the keytab in `id'. All resources will be released, - * even on errors. Return 0 or an error. + * even on errors. + * + * @param context a Keberos context. + * @param id keytab to close. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -292,10 +466,61 @@ krb5_kt_close(krb5_context context, return ret; } +/** + * Destroy (remove) the keytab in `id'. All resources will be released, + * even on errors, does the equvalment of krb5_kt_close() on the resources. + * + * @param context a Keberos context. + * @param id keytab to destroy. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_kt_destroy(krb5_context context, + krb5_keytab id) +{ + krb5_error_code ret; + + ret = (*id->destroy)(context, id); + krb5_kt_close(context, id); + return ret; +} + /* + * Match any aliases in keytab `entry' with `principal'. + */ + +static krb5_boolean +compare_aliseses(krb5_context context, + krb5_keytab_entry *entry, + krb5_const_principal principal) +{ + unsigned int i; + if (entry->aliases == NULL) + return FALSE; + for (i = 0; i < entry->aliases->len; i++) + if (krb5_principal_compare(context, &entry->aliases->val[i], principal)) + return TRUE; + return FALSE; +} + +/** * Compare `entry' against `principal, vno, enctype'. * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. * Return TRUE if they compare the same, FALSE otherwise. + * + * @param context a Keberos context. + * @param entry an entry to match with. + * @param principal principal to match, NULL matches all principals. + * @param vno key version to match, 0 matches all key version numbers. + * @param enctype encryption type to match, 0 matches all encryption types. + * + * @return Return TRUE or match, FALSE if not matched. + * + * @ingroup krb5_keytab */ krb5_boolean KRB5_LIB_FUNCTION @@ -306,7 +531,8 @@ krb5_kt_compare(krb5_context context, krb5_enctype enctype) { if(principal != NULL && - !krb5_principal_compare(context, entry->principal, principal)) + !(krb5_principal_compare(context, entry->principal, principal) || + compare_aliseses(context, entry, principal))) return FALSE; if(vno && vno != entry->vno) return FALSE; @@ -315,11 +541,53 @@ krb5_kt_compare(krb5_context context, return TRUE; } -/* +krb5_error_code +_krb5_kt_principal_not_found(krb5_context context, + krb5_error_code ret, + krb5_keytab id, + krb5_const_principal principal, + krb5_enctype enctype, + int kvno) +{ + char princ[256], kvno_str[25], *kt_name; + char *enctype_str = NULL; + + krb5_unparse_name_fixed (context, principal, princ, sizeof(princ)); + krb5_kt_get_full_name (context, id, &kt_name); + krb5_enctype_to_string(context, enctype, &enctype_str); + + if (kvno) + snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno); + else + kvno_str[0] = '\0'; + + krb5_set_error_message (context, ret, + N_("Failed to find %s%s in keytab %s (%s)", + "principal, kvno, keytab file, enctype"), + princ, + kvno_str, + kt_name ? kt_name : "unknown keytab", + enctype_str ? enctype_str : "unknown enctype"); + free(kt_name); + free(enctype_str); + return ret; +} + + +/** * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' - * from the keytab `id'. - * kvno == 0 is a wildcard and gives the keytab with the highest vno. - * Return 0 or an error. + * from the keytab `id'. Matching is done like krb5_kt_compare(). + * + * @param context a Keberos context. + * @param id a keytab. + * @param principal principal to match, NULL matches all principals. + * @param kvno key version to match, 0 matches all key version numbers. + * @param enctype encryption type to match, 0 matches all encryption types. + * @param entry the returned entry, free with krb5_kt_free_entry(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -365,37 +633,23 @@ krb5_kt_get_entry(krb5_context context, krb5_kt_free_entry(context, &tmp); } krb5_kt_end_seq_get (context, id, &cursor); - if (entry->vno) { - return 0; - } else { - char princ[256], kvno_str[25], *kt_name; - char *enctype_str = NULL; - - krb5_unparse_name_fixed (context, principal, princ, sizeof(princ)); - krb5_kt_get_full_name (context, id, &kt_name); - krb5_enctype_to_string(context, enctype, &enctype_str); - - if (kvno) - snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno); - else - kvno_str[0] = '\0'; - - krb5_set_error_message (context, KRB5_KT_NOTFOUND, - N_("Failed to find %s%s in keytab %s (%s)", - "principal, kvno, keytab file, enctype"), - princ, - kvno_str, - kt_name ? kt_name : "unknown keytab", - enctype_str ? enctype_str : "unknown enctype"); - free(kt_name); - free(enctype_str); - return KRB5_KT_NOTFOUND; - } + if (entry->vno == 0) + return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND, + id, principal, enctype, kvno); + return 0; } -/* +/** * Copy the contents of `in' into `out'. - * Return 0 or an error. */ + * + * @param context a Keberos context. + * @param in the keytab entry to copy. + * @param out the copy of the keytab entry, free with krb5_kt_free_entry(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ krb5_error_code KRB5_LIB_FUNCTION krb5_kt_copy_entry_contents(krb5_context context, @@ -422,8 +676,15 @@ fail: return ret; } -/* +/** * Free the contents of `entry'. + * + * @param context a Keberos context. + * @param entry the entry to free + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -436,9 +697,16 @@ krb5_kt_free_entry(krb5_context context, return 0; } -/* +/** * Set `cursor' to point at the beginning of `id'. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param id a keytab. + * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -456,10 +724,18 @@ krb5_kt_start_seq_get(krb5_context context, return (*id->start_seq_get)(context, id, cursor); } -/* - * Get the next entry from `id' pointed to by `cursor' and advance the - * `cursor'. - * Return 0 or an error. +/** + * Get the next entry from keytab, advance the cursor. On last entry + * the function will return KRB5_KT_END. + * + * @param context a Keberos context. + * @param id a keytab. + * @param entry the returned entry, free with krb5_kt_free_entry(). + * @param cursor the cursor of the iteration. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -478,8 +754,16 @@ krb5_kt_next_entry(krb5_context context, return (*id->next_entry)(context, id, entry, cursor); } -/* +/** * Release all resources associated with `cursor'. + * + * @param context a Keberos context. + * @param id a keytab. + * @param cursor the cursor to free. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -496,9 +780,16 @@ krb5_kt_end_seq_get(krb5_context context, return (*id->end_seq_get)(context, id, cursor); } -/* +/** * Add the entry in `entry' to the keytab `id'. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param id a keytab. + * @param entry the entry to add + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -516,9 +807,17 @@ krb5_kt_add_entry(krb5_context context, return (*id->add)(context, id,entry); } -/* - * Remove the entry `entry' from the keytab `id'. - * Return 0 or an error. +/** + * Remove an entry from the keytab, matching is done using + * krb5_kt_compare(). + + * @param context a Keberos context. + * @param id a keytab. + * @param entry the entry to remove + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/keytab_any.c b/source4/heimdal/lib/krb5/keytab_any.c index 7a2d9b9f70..02de8c8028 100644 --- a/source4/heimdal/lib/krb5/keytab_any.c +++ b/source4/heimdal/lib/krb5/keytab_any.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct any_data { krb5_keytab kt; char *name; @@ -253,6 +251,7 @@ const krb5_kt_ops krb5_any_ops = { any_resolve, any_get_name, any_close, + NULL, /* destroy */ NULL, /* get */ any_start_seq_get, any_next_entry, diff --git a/source4/heimdal/lib/krb5/keytab_file.c b/source4/heimdal/lib/krb5/keytab_file.c index f494cac253..819366443f 100644 --- a/source4/heimdal/lib/krb5/keytab_file.c +++ b/source4/heimdal/lib/krb5/keytab_file.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - #define KRB5_KT_VNO_1 1 #define KRB5_KT_VNO_2 2 #define KRB5_KT_VNO KRB5_KT_VNO_2 @@ -332,6 +330,14 @@ fkt_close(krb5_context context, krb5_keytab id) } static krb5_error_code +fkt_destroy(krb5_context context, krb5_keytab id) +{ + struct fkt_data *d = id->data; + _krb5_erase_file(context, d->filename); + return 0; +} + +static krb5_error_code fkt_get_name(krb5_context context, krb5_keytab id, char *name, @@ -445,6 +451,7 @@ fkt_next_entry_int(krb5_context context, int ret; int8_t tmp8; int32_t tmp32; + uint32_t utmp32; off_t pos, curpos; pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); @@ -459,8 +466,8 @@ loop: ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal); if (ret) goto out; - ret = krb5_ret_int32(cursor->sp, &tmp32); - entry->timestamp = tmp32; + ret = krb5_ret_uint32(cursor->sp, &utmp32); + entry->timestamp = utmp32; if (ret) goto out; ret = krb5_ret_int8(cursor->sp, &tmp8); @@ -476,10 +483,19 @@ loop: curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); if(len + 4 + pos - curpos >= 4) { ret = krb5_ret_int32(cursor->sp, &tmp32); - if (ret == 0 && tmp32 != 0) { + if (ret == 0 && tmp32 != 0) entry->vno = tmp32; - } } + /* there might be a flags field here */ + if(len + 4 + pos - curpos >= 8) { + ret = krb5_ret_uint32(cursor->sp, &utmp32); + if (ret == 0) + entry->flags = tmp32; + } else + entry->flags = 0; + + entry->aliases = NULL; + if(start) *start = pos; if(end) *end = pos + 4 + len; out: @@ -653,6 +669,15 @@ fkt_add_entry(krb5_context context, krb5_storage_free(emem); goto out; } + ret = krb5_store_uint32 (emem, entry->flags); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed storing extended kvno " + "in keytab %s", ""), + d->filename); + krb5_storage_free(emem); + goto out; + } } ret = krb5_storage_to_data(emem, &keytab); @@ -744,6 +769,7 @@ const krb5_kt_ops krb5_fkt_ops = { fkt_resolve, fkt_get_name, fkt_close, + fkt_destroy, NULL, /* get */ fkt_start_seq_get, fkt_next_entry, @@ -757,6 +783,7 @@ const krb5_kt_ops krb5_wrfkt_ops = { fkt_resolve, fkt_get_name, fkt_close, + fkt_destroy, NULL, /* get */ fkt_start_seq_get, fkt_next_entry, @@ -770,6 +797,7 @@ const krb5_kt_ops krb5_javakt_ops = { fkt_resolve_java14, fkt_get_name, fkt_close, + fkt_destroy, NULL, /* get */ fkt_start_seq_get, fkt_next_entry, diff --git a/source4/heimdal/lib/krb5/keytab_keyfile.c b/source4/heimdal/lib/krb5/keytab_keyfile.c index 71d3d89d58..54666c7d44 100644 --- a/source4/heimdal/lib/krb5/keytab_keyfile.c +++ b/source4/heimdal/lib/krb5/keytab_keyfile.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - #ifndef HEIMDAL_SMALLER /* afs keyfile operations --------------------------------------- */ @@ -275,6 +273,8 @@ akf_next_entry(krb5_context context, ret = 0; entry->timestamp = time(NULL); + entry->flags = 0; + entry->aliases = NULL; out: krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET); @@ -440,6 +440,7 @@ const krb5_kt_ops krb5_akf_ops = { akf_resolve, akf_get_name, akf_close, + NULL, /* destroy */ NULL, /* get */ akf_start_seq_get, akf_next_entry, diff --git a/source4/heimdal/lib/krb5/keytab_memory.c b/source4/heimdal/lib/krb5/keytab_memory.c index defd10d67c..73ffa1c67d 100644 --- a/source4/heimdal/lib/krb5/keytab_memory.c +++ b/source4/heimdal/lib/krb5/keytab_memory.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* memory operations -------------------------------------------- */ struct mkt_data { @@ -228,6 +226,7 @@ const krb5_kt_ops krb5_mkt_ops = { mkt_resolve, mkt_get_name, mkt_close, + NULL, /* destroy */ NULL, /* get */ mkt_start_seq_get, mkt_next_entry, diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h index 0ba4e7b54a..13dafacf21 100644 --- a/source4/heimdal/lib/krb5/krb5.h +++ b/source4/heimdal/lib/krb5/krb5.h @@ -51,6 +51,10 @@ #define KRB5KDC_ERR_KEY_EXP KRB5KDC_ERR_KEY_EXPIRED #endif +#ifndef KRB5_DEPRECATED +#define KRB5_DEPRECATED __attribute__((deprecated)) +#endif + /* simple constants */ #ifndef TRUE @@ -92,6 +96,8 @@ typedef Checksum krb5_checksum; typedef ENCTYPE krb5_enctype; +typedef struct krb5_get_init_creds_ctx *krb5_init_creds_context; + typedef heim_octet_string krb5_data; /* PKINIT related forward declarations */ @@ -219,6 +225,8 @@ typedef enum krb5_key_usage { /* Keyusage for the server referral in a TGS req */ KRB5_KU_SAM_ENC_NONCE_SAD = 27, /* Encryption of the SAM-NONCE-OR-SAD field */ + KRB5_KU_PA_PKINIT_KX = 44, + /* Encryption type of the kdc session contribution in pk-init */ KRB5_KU_DIGEST_ENCRYPT = -18, /* Encryption key usage used in the digest encryption field */ KRB5_KU_DIGEST_OPAQUE = -19, @@ -272,13 +280,13 @@ typedef HostAddress krb5_address; typedef HostAddresses krb5_addresses; typedef enum krb5_keytype { - KEYTYPE_NULL = 0, - KEYTYPE_DES = 1, - KEYTYPE_DES3 = 7, - KEYTYPE_AES128 = 17, - KEYTYPE_AES256 = 18, - KEYTYPE_ARCFOUR = 23, - KEYTYPE_ARCFOUR_56 = 24 + KEYTYPE_NULL = ETYPE_NULL, + KEYTYPE_DES = ETYPE_DES_CBC_CRC, + KEYTYPE_DES3 = ETYPE_OLD_DES3_CBC_SHA1, + KEYTYPE_AES128 = ETYPE_AES128_CTS_HMAC_SHA1_96, + KEYTYPE_AES256 = ETYPE_AES256_CTS_HMAC_SHA1_96, + KEYTYPE_ARCFOUR = ETYPE_ARCFOUR_HMAC_MD5, + KEYTYPE_ARCFOUR_56 = ETYPE_ARCFOUR_HMAC_MD5_56 } krb5_keytype; typedef EncryptionKey krb5_keyblock; @@ -317,6 +325,7 @@ typedef const char *krb5_const_realm; /* stupid language */ typedef Principal krb5_principal_data; typedef struct Principal *krb5_principal; typedef const struct Principal *krb5_const_principal; +typedef struct Principals *krb5_principals; typedef time_t krb5_deltat; typedef time_t krb5_timestamp; @@ -478,6 +487,8 @@ typedef struct krb5_keytab_entry { krb5_kvno vno; krb5_keyblock keyblock; uint32_t timestamp; + uint32_t flags; + krb5_principals aliases; } krb5_keytab_entry; typedef struct krb5_kt_cursor { @@ -497,6 +508,7 @@ struct krb5_keytab_data { krb5_error_code (*resolve)(krb5_context, const char*, krb5_keytab); krb5_error_code (*get_name)(krb5_context, krb5_keytab, char*, size_t); krb5_error_code (*close)(krb5_context, krb5_keytab); + krb5_error_code (*destroy)(krb5_context, krb5_keytab); krb5_error_code (*get)(krb5_context, krb5_keytab, krb5_const_principal, krb5_kvno, krb5_enctype, krb5_keytab_entry*); krb5_error_code (*start_seq_get)(krb5_context, krb5_keytab, krb5_kt_cursor*); @@ -593,7 +605,8 @@ typedef EncAPRepPart krb5_ap_rep_enc_part; #define KRB5_TGS_NAME_SIZE (6) #define KRB5_TGS_NAME ("krbtgt") - +#define KRB5_WELLKNOWN_NAME ("WELLKNOWN") +#define KRB5_ANON_NAME ("ANONYMOUS") #define KRB5_DIGEST_NAME ("digest") typedef enum { @@ -636,7 +649,7 @@ typedef krb5_error_code (*krb5_s2k_proc)(krb5_context /*context*/, struct _krb5_get_init_creds_opt_private; -typedef struct _krb5_get_init_creds_opt { +struct _krb5_get_init_creds_opt { krb5_flags flags; krb5_deltat tkt_life; krb5_deltat renew_life; @@ -652,7 +665,9 @@ typedef struct _krb5_get_init_creds_opt { int preauth_list_length; krb5_data *salt; struct _krb5_get_init_creds_opt_private *opt_private; -} krb5_get_init_creds_opt; +}; + +typedef struct _krb5_get_init_creds_opt krb5_get_init_creds_opt; #define KRB5_GET_INIT_CREDS_OPT_TKT_LIFE 0x0001 #define KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE 0x0002 @@ -661,7 +676,7 @@ typedef struct _krb5_get_init_creds_opt { #define KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST 0x0010 #define KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST 0x0020 #define KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST 0x0040 -#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080 +#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080 /* no supported */ #define KRB5_GET_INIT_CREDS_OPT_ANONYMOUS 0x0100 #define KRB5_GET_INIT_CREDS_OPT_DISABLE_TRANSITED_CHECK 0x0200 @@ -727,22 +742,22 @@ enum { typedef krb5_error_code (*krb5_send_to_kdc_func)(krb5_context, void *, krb5_krbhst_info *, - time_t timeout, + time_t, const krb5_data *, krb5_data *); -/* flags for krb5_parse_name_flags */ +/** flags for krb5_parse_name_flags */ enum { - KRB5_PRINCIPAL_PARSE_NO_REALM = 1, - KRB5_PRINCIPAL_PARSE_MUST_REALM = 2, - KRB5_PRINCIPAL_PARSE_ENTERPRISE = 4 + KRB5_PRINCIPAL_PARSE_NO_REALM = 1, /**< Require that there are no realm */ + KRB5_PRINCIPAL_PARSE_REQUIRE_REALM = 2, /**< Require a realm present */ + KRB5_PRINCIPAL_PARSE_ENTERPRISE = 4 /**< Parse as a NT-ENTERPRISE name */ }; -/* flags for krb5_unparse_name_flags */ +/** flags for krb5_unparse_name_flags */ enum { - KRB5_PRINCIPAL_UNPARSE_SHORT = 1, - KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2, - KRB5_PRINCIPAL_UNPARSE_DISPLAY = 4 + KRB5_PRINCIPAL_UNPARSE_SHORT = 1, /**< No realm if it is the default realm */ + KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2, /**< No realm */ + KRB5_PRINCIPAL_UNPARSE_DISPLAY = 4 /**< No quoting */ }; typedef struct krb5_sendto_ctx_data *krb5_sendto_ctx; @@ -787,6 +802,20 @@ typedef struct krb5_crypto_iov { } krb5_crypto_iov; +/* Glue for MIT */ + +typedef struct { + int32_t lr_type; + krb5_timestamp value; +} krb5_last_req_entry; + +typedef krb5_error_code +(*krb5_gic_process_last_req)(krb5_context, krb5_last_req_entry **, void *); + +/* + * + */ + #include <krb5-protos.h> /* variables */ @@ -810,5 +839,11 @@ extern KRB5_LIB_VARIABLE const krb5_kt_ops krb4_fkt_ops; extern KRB5_LIB_VARIABLE const krb5_kt_ops krb5_srvtab_fkt_ops; extern KRB5_LIB_VARIABLE const krb5_kt_ops krb5_any_ops; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_api; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_file; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_memory; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_kcm; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_scc; + #endif /* __KRB5_H__ */ diff --git a/source4/heimdal/lib/krb5/krb5_ccapi.h b/source4/heimdal/lib/krb5/krb5_ccapi.h index ec0cb3bc0b..5a7fe6a413 100644 --- a/source4/heimdal/lib/krb5/krb5_ccapi.h +++ b/source4/heimdal/lib/krb5/krb5_ccapi.h @@ -38,6 +38,10 @@ #include <krb5-types.h> + #ifdef __APPLE__ +#pragma pack(push,2) +#endif + enum { cc_credentials_v5 = 2 }; @@ -92,7 +96,7 @@ typedef struct cc_credentials_v5_t cc_credentials_v5_t; typedef struct cc_credentials_t *cc_credentials_t; typedef struct cc_credentials_iterator_t *cc_credentials_iterator_t; typedef struct cc_string_t *cc_string_t; -typedef time_t cc_time_t; +typedef cc_uint32 cc_time_t; typedef struct cc_data { cc_uint32 type; @@ -227,4 +231,9 @@ struct cc_context_t { typedef cc_int32 (*cc_initialize_func)(cc_context_t*, cc_int32, cc_int32 *, char const **); +#ifdef __APPLE__ +#pragma pack(pop) +#endif + + #endif /* KRB5_CCAPI_H */ diff --git a/source4/heimdal/lib/krb5/krb5_err.et b/source4/heimdal/lib/krb5/krb5_err.et index c076992d0b..098e04b959 100644 --- a/source4/heimdal/lib/krb5/krb5_err.et +++ b/source4/heimdal/lib/krb5/krb5_err.et @@ -106,7 +106,13 @@ error_code PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED, "Public key encryption not suppo #error_code ERR_KDC_NOT_FOUND, "IAKERB proxy could not find a KDC" #error_code ERR_KDC_NO_RESPONSE, "IAKERB proxy never reeived a response from a KDC" -# 82-127 are reserved +# 82-93 are reserved + +index 94 +error_code INVALID_HASH_ALG, "Invalid OTP digest algorithm" +error_code INVALID_ITERATION_COUNT, "Invalid OTP iteration count" + +# 97-127 are reserved index 128 prefix diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h index ced722f2d9..2d8bc07de3 100644 --- a/source4/heimdal/lib/krb5/krb5_locl.h +++ b/source4/heimdal/lib/krb5/krb5_locl.h @@ -36,9 +36,7 @@ #ifndef __KRB5_LOCL_H__ #define __KRB5_LOCL_H__ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include <errno.h> #include <ctype.h> @@ -214,11 +212,14 @@ struct _krb5_get_init_creds_opt_private { krb5_get_init_creds_tristate req_pac; /* PKINIT */ krb5_pk_init_ctx pk_init_ctx; - KRB_ERROR *error; krb5_get_init_creds_tristate addressless; int flags; #define KRB5_INIT_CREDS_CANONICALIZE 1 #define KRB5_INIT_CREDS_NO_C_CANON_CHECK 2 + struct { + krb5_gic_process_last_req func; + void *ctx; + } lr; }; typedef struct krb5_context_data { @@ -261,6 +262,7 @@ typedef struct krb5_context_data { int flags; #define KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME 1 #define KRB5_CTX_F_CHECK_PAC 2 +#define KRB5_CTX_F_HOMEDIR_ACCESS 4 struct send_to_kdc *send_to_kdc; } krb5_context_data; @@ -295,6 +297,7 @@ struct krb5_pk_identity { hx509_context hx509ctx; hx509_verify_ctx verify_ctx; hx509_certs certs; + hx509_cert cert; hx509_certs anchors; hx509_certs certpool; hx509_revoke_ctx revokectx; diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c index 7348ac3f00..e9111abec9 100644 --- a/source4/heimdal/lib/krb5/krbhst.c +++ b/source4/heimdal/lib/krb5/krbhst.c @@ -35,8 +35,6 @@ #include <resolve.h> #include "locate_plugin.h" -RCSID("$Id$"); - static int string_to_proto(const char *string) { @@ -61,8 +59,8 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, const char *proto, const char *service, int port) { char domain[1024]; - struct dns_reply *r; - struct resource_record *rr; + struct rk_dns_reply *r; + struct rk_resource_record *rr; int num_srv; int proto_num; int def_port; @@ -87,32 +85,32 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm); - r = dns_lookup(domain, dns_type); + r = rk_dns_lookup(domain, dns_type); if(r == NULL) return KRB5_KDC_UNREACH; for(num_srv = 0, rr = r->head; rr; rr = rr->next) - if(rr->type == T_SRV) + if(rr->type == rk_ns_t_srv) num_srv++; *res = malloc(num_srv * sizeof(**res)); if(*res == NULL) { - dns_free_data(r); + rk_dns_free_data(r); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } - dns_srv_order(r); + rk_dns_srv_order(r); for(num_srv = 0, rr = r->head; rr; rr = rr->next) - if(rr->type == T_SRV) { + if(rr->type == rk_ns_t_srv) { krb5_krbhst_info *hi; size_t len = strlen(rr->u.srv->target); hi = calloc(1, sizeof(*hi) + len); if(hi == NULL) { - dns_free_data(r); + rk_dns_free_data(r); while(--num_srv >= 0) free((*res)[num_srv]); free(*res); @@ -134,7 +132,7 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, *count = num_srv; - dns_free_data(r); + rk_dns_free_data(r); return 0; } @@ -948,7 +946,7 @@ gethostlist(krb5_context context, const char *realm, return ENOMEM; } } - (*hostlist)[nhost++] = NULL; + (*hostlist)[nhost] = NULL; krb5_krbhst_free(context, handle); return 0; } diff --git a/source4/heimdal/lib/krb5/locate_plugin.h b/source4/heimdal/lib/krb5/locate_plugin.h index 529488ddfd..b1b1f0ef23 100644 --- a/source4/heimdal/lib/krb5/locate_plugin.h +++ b/source4/heimdal/lib/krb5/locate_plugin.h @@ -36,9 +36,7 @@ #ifndef HEIMDAL_KRB5_LOCATE_PLUGIN_H #define HEIMDAL_KRB5_LOCATE_PLUGIN_H 1 -#include <krb5.h> - -#define KRB5_PLUGIN_LOCATE "resolve" +#define KRB5_PLUGIN_LOCATE "service_locator" enum locate_service_type { locate_service_kdc = 1, diff --git a/source4/heimdal/lib/krb5/log.c b/source4/heimdal/lib/krb5/log.c index 587cf7ed97..31d267320f 100644 --- a/source4/heimdal/lib/krb5/log.c +++ b/source4/heimdal/lib/krb5/log.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct facility { int min; int max; diff --git a/source4/heimdal/lib/krb5/mcache.c b/source4/heimdal/lib/krb5/mcache.c index 752608069d..78ef68db3d 100644 --- a/source4/heimdal/lib/krb5/mcache.c +++ b/source4/heimdal/lib/krb5/mcache.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - typedef struct krb5_mcache { char *name; unsigned int refcnt; diff --git a/source4/heimdal/lib/krb5/misc.c b/source4/heimdal/lib/krb5/misc.c index 4cee5e22e1..e47383880c 100644 --- a/source4/heimdal/lib/krb5/misc.c +++ b/source4/heimdal/lib/krb5/misc.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION _krb5_s4u2self_to_checksumdata(krb5_context context, const PA_S4U2Self *self, diff --git a/source4/heimdal/lib/krb5/mit_glue.c b/source4/heimdal/lib/krb5/mit_glue.c index f8f13922f5..dab5c6046a 100644 --- a/source4/heimdal/lib/krb5/mit_glue.c +++ b/source4/heimdal/lib/krb5/mit_glue.c @@ -31,8 +31,9 @@ * SUCH DAMAGE. */ +#define KRB5_DEPRECATED + #include "krb5_locl.h" -RCSID("$Id$"); #ifndef HEIMDAL_SMALLER @@ -315,8 +316,9 @@ krb5_c_enctype_compare(krb5_context context, krb5_enctype e1, krb5_enctype e2, krb5_boolean *similar) + KRB5_DEPRECATED { - *similar = krb5_enctypes_compatible_keys(context, e1, e2); + *similar = (e1 == e2); return 0; } @@ -370,4 +372,18 @@ krb5_c_prf(krb5_context context, return ret; } +/** + * MIT compat glue + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_copy_creds(krb5_context context, + const krb5_ccache from, + krb5_ccache to) +{ + return krb5_cc_copy_cache(context, from, to); +} + #endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/mk_error.c b/source4/heimdal/lib/krb5/mk_error.c index 989aa23d75..f623fc495b 100644 --- a/source4/heimdal/lib/krb5/mk_error.c +++ b/source4/heimdal/lib/krb5/mk_error.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_error(krb5_context context, krb5_error_code error_code, diff --git a/source4/heimdal/lib/krb5/mk_priv.c b/source4/heimdal/lib/krb5/mk_priv.c index 86a6b669b1..40f09ae33f 100644 --- a/source4/heimdal/lib/krb5/mk_priv.c +++ b/source4/heimdal/lib/krb5/mk_priv.c @@ -33,9 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_priv(krb5_context context, krb5_auth_context auth_context, diff --git a/source4/heimdal/lib/krb5/mk_rep.c b/source4/heimdal/lib/krb5/mk_rep.c index bba276183a..8eef0ea652 100644 --- a/source4/heimdal/lib/krb5/mk_rep.c +++ b/source4/heimdal/lib/krb5/mk_rep.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_rep(krb5_context context, krb5_auth_context auth_context, diff --git a/source4/heimdal/lib/krb5/mk_req.c b/source4/heimdal/lib/krb5/mk_req.c index 1570637738..c87fa61293 100644 --- a/source4/heimdal/lib/krb5/mk_req.c +++ b/source4/heimdal/lib/krb5/mk_req.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_req_exact(krb5_context context, krb5_auth_context *auth_context, diff --git a/source4/heimdal/lib/krb5/mk_req_ext.c b/source4/heimdal/lib/krb5/mk_req_ext.c index aba804716c..d130272aa1 100644 --- a/source4/heimdal/lib/krb5/mk_req_ext.c +++ b/source4/heimdal/lib/krb5/mk_req_ext.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code _krb5_mk_req_internal(krb5_context context, krb5_auth_context *auth_context, diff --git a/source4/heimdal/lib/krb5/n-fold.c b/source4/heimdal/lib/krb5/n-fold.c index fa45b09f18..0623f6aae1 100644 --- a/source4/heimdal/lib/krb5/n-fold.c +++ b/source4/heimdal/lib/krb5/n-fold.c @@ -32,8 +32,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - static krb5_error_code rr13(unsigned char *buf, size_t len) { @@ -109,8 +107,10 @@ _krb5_n_fold(const void *str, size_t len, void *key, size_t size) unsigned char *tmp = malloc(maxlen); unsigned char *buf = malloc(len); - if (tmp == NULL || buf == NULL) - return ENOMEM; + if (tmp == NULL || buf == NULL) { + ret = ENOMEM; + goto out; + } memcpy(buf, str, len); memset(key, 0, size); @@ -129,9 +129,13 @@ _krb5_n_fold(const void *str, size_t len, void *key, size_t size) } } while(l != 0); out: - memset(buf, 0, len); - free(buf); - memset(tmp, 0, maxlen); - free(tmp); + if (buf) { + memset(buf, 0, len); + free(buf); + } + if (tmp) { + memset(tmp, 0, maxlen); + free(tmp); + } return ret; } diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index 3c55eb3dc3..b66e79960d 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <wind.h> -RCSID("$Id$"); - struct PAC_INFO_BUFFER { uint32_t type; uint32_t buffersize; @@ -613,6 +611,7 @@ verify_logonname(krb5_context context, ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len); free(ucs2); if (ret) { + free(s); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return ret; } diff --git a/source4/heimdal/lib/krb5/padata.c b/source4/heimdal/lib/krb5/padata.c index 022260e709..aa08248ed1 100644 --- a/source4/heimdal/lib/krb5/padata.c +++ b/source4/heimdal/lib/krb5/padata.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - PA_DATA * krb5_find_padata(PA_DATA *val, unsigned len, int type, int *idx) { diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c index de5e90a68e..18b5b5e017 100644 --- a/source4/heimdal/lib/krb5/pkinit.c +++ b/source4/heimdal/lib/krb5/pkinit.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct krb5_dh_moduli { char *name; unsigned long bits; @@ -60,7 +58,13 @@ struct krb5_pk_cert { struct krb5_pk_init_ctx_data { struct krb5_pk_identity *id; - DH *dh; + enum { USE_RSA, USE_DH, USE_ECDH } keyex; + union { + DH *dh; +#ifdef HAVE_OPENSSL + EC_KEY *eckey; +#endif + } u; krb5_data *clientDHNonce; struct krb5_dh_moduli **m; hx509_peer_info peer; @@ -122,6 +126,45 @@ integer_to_BN(krb5_context context, const char *field, const heim_integer *f) return bn; } +static krb5_error_code +select_dh_group(krb5_context context, DH *dh, unsigned long bits, + struct krb5_dh_moduli **moduli) +{ + const struct krb5_dh_moduli *m; + + if (bits == 0) { + m = moduli[1]; /* XXX */ + if (m == NULL) + m = moduli[0]; /* XXX */ + } else { + int i; + for (i = 0; moduli[i] != NULL; i++) { + if (bits < moduli[i]->bits) + break; + } + if (moduli[i] == NULL) { + krb5_set_error_message(context, EINVAL, + N_("Did not find a DH group parameter " + "matching requirement of %lu bits", ""), + bits); + return EINVAL; + } + m = moduli[i]; + } + + dh->p = integer_to_BN(context, "p", &m->p); + if (dh->p == NULL) + return ENOMEM; + dh->g = integer_to_BN(context, "g", &m->g); + if (dh->g == NULL) + return ENOMEM; + dh->q = integer_to_BN(context, "q", &m->q); + if (dh->q == NULL) + return ENOMEM; + + return 0; +} + struct certfind { const char *type; const heim_oid *oid; @@ -139,12 +182,12 @@ find_cert(krb5_context context, struct krb5_pk_identity *id, struct certfind cf[3] = { { "PKINIT EKU" }, { "MS EKU" }, - { "no" } + { "any (or no)" } }; int i, ret; - cf[0].oid = oid_id_pkekuoid(); - cf[1].oid = oid_id_pkinit_ms_eku(); + cf[0].oid = &asn1_oid_id_pkekuoid; + cf[1].oid = &asn1_oid_id_pkinit_ms_eku; cf[2].oid = NULL; for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) { @@ -159,7 +202,7 @@ find_cert(krb5_context context, struct krb5_pk_identity *id, if (ret == 0) break; pk_copy_error(context, id->hx509ctx, ret, - "Failed cert for finding %s OID", cf[i].type); + "Failed finding certificate with %s OID", cf[i].type); } return ret; } @@ -173,37 +216,22 @@ create_signature(krb5_context context, hx509_peer_info peer, krb5_data *sd_data) { - hx509_cert cert = NULL; - hx509_query *q = NULL; - int ret; - - ret = hx509_query_alloc(id->hx509ctx, &q); - if (ret) { - pk_copy_error(context, id->hx509ctx, ret, - "Allocate query to find signing certificate"); - return ret; - } + int ret, flags = 0; - hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); - hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); - - ret = find_cert(context, id, q, &cert); - hx509_query_free(id->hx509ctx, q); - if (ret) - return ret; + if (id->cert == NULL) + flags |= HX509_CMS_SIGNATURE_NO_SIGNER; ret = hx509_cms_create_signed_1(id->hx509ctx, - 0, + flags, eContentType, eContent->data, eContent->length, NULL, - cert, + id->cert, peer, NULL, id->certs, sd_data); - hx509_cert_free(cert); if (ret) { pk_copy_error(context, id->hx509ctx, ret, "Create CMS signedData"); @@ -222,6 +250,9 @@ cert2epi(hx509_context context, void *ctx, hx509_cert c) void *p; int ret; + if (ids->len > 10) + return 0; + memset(&id, 0, sizeof(id)); ret = hx509_cert_get_subject(c, &subject); @@ -319,7 +350,6 @@ static krb5_error_code build_auth_pack(krb5_context context, unsigned nonce, krb5_pk_init_ctx ctx, - DH *dh, const KDC_REQ_BODY *body, AuthPack *a) { @@ -368,12 +398,49 @@ build_auth_pack(krb5_context context, if (ret) return ret; - if (dh) { - DomainParameters dp; - heim_integer dh_pub_key; + if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) { + const char *moduli_file; + unsigned long dh_min_bits; krb5_data dhbuf; size_t size; + krb5_data_zero(&dhbuf); + + + + moduli_file = krb5_config_get_string(context, NULL, + "libdefaults", + "moduli", + NULL); + + dh_min_bits = + krb5_config_get_int_default(context, NULL, 0, + "libdefaults", + "pkinit_dh_min_bits", + NULL); + + ret = _krb5_parse_moduli(context, moduli_file, &ctx->m); + if (ret) + return ret; + + ctx->u.dh = DH_new(); + if (ctx->u.dh == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + + ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m); + if (ret) + return ret; + + if (DH_generate_key(ctx->u.dh) != 1) { + krb5_set_error_message(context, ENOMEM, + N_("pkinit: failed to generate DH key", "")); + return ENOMEM; + } + + if (1 /* support_cached_dh */) { ALLOC(a->clientDHNonce, 1); if (a->clientDHNonce == NULL) { @@ -385,7 +452,7 @@ build_auth_pack(krb5_context context, krb5_clear_error_message(context); return ret; } - memset(a->clientDHNonce->data, 0, a->clientDHNonce->length); + RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length); ret = krb5_copy_data(context, a->clientDHNonce, &ctx->clientDHNonce); if (ret) @@ -395,64 +462,135 @@ build_auth_pack(krb5_context context, ALLOC(a->clientPublicValue, 1); if (a->clientPublicValue == NULL) return ENOMEM; - ret = der_copy_oid(oid_id_dhpublicnumber(), - &a->clientPublicValue->algorithm.algorithm); - if (ret) - return ret; - - memset(&dp, 0, sizeof(dp)); - ret = BN_to_integer(context, dh->p, &dp.p); - if (ret) { - free_DomainParameters(&dp); - return ret; - } - ret = BN_to_integer(context, dh->g, &dp.g); - if (ret) { - free_DomainParameters(&dp); - return ret; - } - ret = BN_to_integer(context, dh->q, &dp.q); - if (ret) { - free_DomainParameters(&dp); - return ret; - } - dp.j = NULL; - dp.validationParms = NULL; + if (ctx->keyex == USE_DH) { + DH *dh = ctx->u.dh; + DomainParameters dp; + heim_integer dh_pub_key; - a->clientPublicValue->algorithm.parameters = - malloc(sizeof(*a->clientPublicValue->algorithm.parameters)); - if (a->clientPublicValue->algorithm.parameters == NULL) { + ret = der_copy_oid(&asn1_oid_id_dhpublicnumber, + &a->clientPublicValue->algorithm.algorithm); + if (ret) + return ret; + + memset(&dp, 0, sizeof(dp)); + + ret = BN_to_integer(context, dh->p, &dp.p); + if (ret) { + free_DomainParameters(&dp); + return ret; + } + ret = BN_to_integer(context, dh->g, &dp.g); + if (ret) { + free_DomainParameters(&dp); + return ret; + } + ret = BN_to_integer(context, dh->q, &dp.q); + if (ret) { + free_DomainParameters(&dp); + return ret; + } + dp.j = NULL; + dp.validationParms = NULL; + + a->clientPublicValue->algorithm.parameters = + malloc(sizeof(*a->clientPublicValue->algorithm.parameters)); + if (a->clientPublicValue->algorithm.parameters == NULL) { + free_DomainParameters(&dp); + return ret; + } + + ASN1_MALLOC_ENCODE(DomainParameters, + a->clientPublicValue->algorithm.parameters->data, + a->clientPublicValue->algorithm.parameters->length, + &dp, &size, ret); free_DomainParameters(&dp); - return ret; - } + if (ret) + return ret; + if (size != a->clientPublicValue->algorithm.parameters->length) + krb5_abortx(context, "Internal ASN1 encoder error"); + + ret = BN_to_integer(context, dh->pub_key, &dh_pub_key); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, + &dh_pub_key, &size, ret); + der_free_heim_integer(&dh_pub_key); + if (ret) + return ret; + if (size != dhbuf.length) + krb5_abortx(context, "asn1 internal error"); + } else if (ctx->keyex == USE_ECDH) { +#ifdef HAVE_OPENSSL + ECParameters ecp; + unsigned char *p; + int len; + + /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */ + + ecp.element = choice_ECParameters_namedCurve; + ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1, + &ecp.u.namedCurve); + if (ret) + return ret; - ASN1_MALLOC_ENCODE(DomainParameters, - a->clientPublicValue->algorithm.parameters->data, - a->clientPublicValue->algorithm.parameters->length, - &dp, &size, ret); - free_DomainParameters(&dp); - if (ret) - return ret; - if (size != a->clientPublicValue->algorithm.parameters->length) - krb5_abortx(context, "Internal ASN1 encoder error"); + ALLOC(a->clientPublicValue->algorithm.parameters, 1); + if (a->clientPublicValue->algorithm.parameters == NULL) { + free_ECParameters(&ecp); + return ENOMEM; + } + ASN1_MALLOC_ENCODE(ECParameters, p, len, &ecp, &size, ret); + free_ECParameters(&ecp); + if (ret) + return ret; + if (size != len) + krb5_abortx(context, "asn1 internal error"); + + a->clientPublicValue->algorithm.parameters->data = p; + a->clientPublicValue->algorithm.parameters->length = size; - ret = BN_to_integer(context, dh->pub_key, &dh_pub_key); - if (ret) - return ret; + /* copy in public key */ - ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, - &dh_pub_key, &size, ret); - der_free_heim_integer(&dh_pub_key); - if (ret) - return ret; - if (size != dhbuf.length) - krb5_abortx(context, "asn1 internal error"); + ret = der_copy_oid(&asn1_oid_id_ecPublicKey, + &a->clientPublicValue->algorithm.algorithm); + if (ret) + return ret; + + ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (ctx->u.eckey == NULL) + return ENOMEM; + + ret = EC_KEY_generate_key(ctx->u.eckey); + if (ret != 1) + return EINVAL; + /* encode onto dhkey */ + + len = i2o_ECPublicKey(ctx->u.eckey, NULL); + if (len <= 0) + abort(); + + dhbuf.data = malloc(len); + if (dhbuf.data == NULL) + abort(); + dhbuf.length = len; + p = dhbuf.data; + + len = i2o_ECPublicKey(ctx->u.eckey, &p); + if (len <= 0) + abort(); + + /* XXX verify that this is right with RFC3279 */ +#else + return EINVAL; +#endif + } else + krb5_abortx(context, "internal error"); a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8; a->clientPublicValue->subjectPublicKey.data = dhbuf.data; } - + { a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes)); if (a->supportedCMSTypes == NULL) @@ -546,13 +684,13 @@ pk_mk_padata(krb5_context context, if (buf.length != size) krb5_abortx(context, "internal ASN1 encoder error"); - oid = oid_id_pkcs7_data(); + oid = &asn1_oid_id_pkcs7_data; } else if (ctx->type == PKINIT_27) { AuthPack ap; memset(&ap, 0, sizeof(ap)); - ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap); + ret = build_auth_pack(context, nonce, ctx, req_body, &ap); if (ret) { free_AuthPack(&ap); goto out; @@ -569,7 +707,7 @@ pk_mk_padata(krb5_context context, if (buf.length != size) krb5_abortx(context, "internal ASN1 encoder error"); - oid = oid_id_pkauthdata(); + oid = &asn1_oid_id_pkauthdata; } else krb5_abortx(context, "internal pkinit error"); @@ -579,7 +717,7 @@ pk_mk_padata(krb5_context context, if (ret) goto out; - ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf); + ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf); krb5_data_free(&sd_buf); if (ret) { krb5_set_error_message(context, ret, @@ -648,8 +786,8 @@ pk_mk_padata(krb5_context context, if (ret) free(buf.data); - if (ret == 0 && ctx->type == PKINIT_WIN2K) - krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); + if (ret == 0) + krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); out: free_ContentInfo(&content_info); @@ -721,14 +859,14 @@ _krb5_pk_mk_padata(krb5_context context, return pk_mk_padata(context, ctx, req_body, nonce, md); } -krb5_error_code KRB5_LIB_FUNCTION -_krb5_pk_verify_sign(krb5_context context, - const void *data, - size_t length, - struct krb5_pk_identity *id, - heim_oid *contentType, - krb5_data *content, - struct krb5_pk_cert **signer) +static krb5_error_code +pk_verify_sign(krb5_context context, + const void *data, + size_t length, + struct krb5_pk_identity *id, + heim_oid *contentType, + krb5_data *content, + struct krb5_pk_cert **signer) { hx509_certs signer_certs; int ret; @@ -737,6 +875,7 @@ _krb5_pk_verify_sign(krb5_context context, ret = hx509_cms_verify_signed(id->hx509ctx, id->verify_ctx, + HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH|HX509_CMS_VS_NO_KU_CHECK, data, length, NULL, @@ -902,7 +1041,7 @@ pk_verify_host(krb5_context context, if (ctx->require_eku) { ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert, - oid_id_pkkdcekuoid(), 0); + &asn1_oid_id_pkkdcekuoid, 0); if (ret) { krb5_set_error_message(context, ret, N_("No PK-INIT KDC EKU in kdc certificate", "")); @@ -915,7 +1054,7 @@ pk_verify_host(krb5_context context, ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx, host->cert, - oid_id_pkinit_san(), + &asn1_oid_id_pkinit_san, &list); if (ret) { krb5_set_error_message(context, ret, @@ -995,16 +1134,20 @@ pk_rd_pa_reply_enckey(krb5_context context, struct krb5_pk_cert *host = NULL; krb5_data content; heim_oid contentType = { 0, NULL }; + int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT; - if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) { + if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) { krb5_set_error_message(context, EINVAL, N_("PKINIT: Invalid content type", "")); return EINVAL; } + if (ctx->type == PKINIT_WIN2K) + flags |= HX509_CMS_UE_ALLOW_WEAK; + ret = hx509_cms_unenvelope(ctx->id->hx509ctx, ctx->id->certs, - HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT, + flags, indata->data, indata->length, NULL, @@ -1042,7 +1185,9 @@ pk_rd_pa_reply_enckey(krb5_context context, heim_octet_string out; ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL); - if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) { + if (ret) + goto out; + if (der_heim_oid_cmp(&type, &asn1_oid_id_pkcs7_signedData)) { ret = EINVAL; /* XXX */ krb5_set_error_message(context, ret, N_("PKINIT: Invalid content type", "")); @@ -1061,13 +1206,13 @@ pk_rd_pa_reply_enckey(krb5_context context, } } - ret = _krb5_pk_verify_sign(context, - content.data, - content.length, - ctx->id, - &contentType, - &content, - &host); + ret = pk_verify_sign(context, + content.data, + content.length, + ctx->id, + &contentType, + &content, + &host); if (ret) goto out; @@ -1079,13 +1224,13 @@ pk_rd_pa_reply_enckey(krb5_context context, #if 0 if (type == PKINIT_WIN2K) { - if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) { + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid"); goto out; } } else { - if (der_heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) { + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid"); goto out; @@ -1131,32 +1276,33 @@ pk_rd_pa_reply_dh(krb5_context context, PA_DATA *pa, krb5_keyblock **key) { - unsigned char *p, *dh_gen_key = NULL; + const unsigned char *p; + unsigned char *dh_gen_key = NULL; struct krb5_pk_cert *host = NULL; BIGNUM *kdc_dh_pubkey = NULL; KDCDHKeyInfo kdc_dh_info; heim_oid contentType = { 0, NULL }; krb5_data content; krb5_error_code ret; - int dh_gen_keylen; + int dh_gen_keylen = 0; size_t size; krb5_data_zero(&content); memset(&kdc_dh_info, 0, sizeof(kdc_dh_info)); - if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) { + if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) { krb5_set_error_message(context, EINVAL, N_("PKINIT: Invalid content type", "")); return EINVAL; } - ret = _krb5_pk_verify_sign(context, - indata->data, - indata->length, - ctx->id, - &contentType, - &content, - &host); + ret = pk_verify_sign(context, + indata->data, + indata->length, + ctx->id, + &contentType, + &content, + &host); if (ret) goto out; @@ -1165,7 +1311,7 @@ pk_rd_pa_reply_dh(krb5_context context, if (ret) goto out; - if (der_heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) { + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_set_error_message(context, ret, N_("pkinit - dh reply contains wrong oid", "")); @@ -1221,7 +1367,7 @@ pk_rd_pa_reply_dh(krb5_context context, p = kdc_dh_info.subjectPublicKey.data; size = (kdc_dh_info.subjectPublicKey.length + 7) / 8; - { + if (ctx->keyex == USE_DH) { DHPublicKey k; ret = decode_DHPublicKey(p, size, &k, NULL); if (ret) { @@ -1237,30 +1383,78 @@ pk_rd_pa_reply_dh(krb5_context context, ret = ENOMEM; goto out; } - } - dh_gen_keylen = DH_size(ctx->dh); - size = BN_num_bytes(ctx->dh->p); - if (size < dh_gen_keylen) - size = dh_gen_keylen; - dh_gen_key = malloc(size); - if (dh_gen_key == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto out; - } - memset(dh_gen_key, 0, size - dh_gen_keylen); + dh_gen_keylen = DH_size(ctx->u.dh); + size = BN_num_bytes(ctx->u.dh->p); + if (size < dh_gen_keylen) + size = dh_gen_keylen; - dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), - kdc_dh_pubkey, ctx->dh); - if (dh_gen_keylen == -1) { - ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, - N_("PKINIT: Can't compute Diffie-Hellman key", "")); - goto out; - } + dh_gen_key = malloc(size); + if (dh_gen_key == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; + } + memset(dh_gen_key, 0, size - dh_gen_keylen); + + dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), + kdc_dh_pubkey, ctx->u.dh); + if (dh_gen_keylen == -1) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't compute Diffie-Hellman key", "")); + goto out; + } + } else { +#ifdef HAVE_OPENSSL + const EC_GROUP *group; + EC_KEY *public = NULL; + + group = EC_KEY_get0_group(ctx->u.eckey); + + public = EC_KEY_new(); + if (public == NULL) { + ret = ENOMEM; + goto out; + } + if (EC_KEY_set_group(public, group) != 1) { + EC_KEY_free(public); + ret = ENOMEM; + goto out; + } + if (o2i_ECPublicKey(&public, &p, size) == NULL) { + EC_KEY_free(public); + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't parse ECDH public key", "")); + goto out; + } + + size = (EC_GROUP_get_degree(group) + 7) / 8; + dh_gen_key = malloc(size); + if (dh_gen_key == NULL) { + EC_KEY_free(public); + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto out; + } + dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, + EC_KEY_get0_public_key(public), ctx->u.eckey, NULL); + EC_KEY_free(public); + if (dh_gen_keylen == -1) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't compute ECDH public key", "")); + goto out; + } +#else + ret = EINVAL; +#endif + } + *key = malloc (sizeof (**key)); if (*key == NULL) { ret = ENOMEM; @@ -1286,7 +1480,7 @@ pk_rd_pa_reply_dh(krb5_context context, if (kdc_dh_pubkey) BN_free(kdc_dh_pubkey); if (dh_gen_key) { - memset(dh_gen_key, 0, DH_size(ctx->dh)); + memset(dh_gen_key, 0, dh_gen_keylen); free(dh_gen_key); } if (host) @@ -1343,12 +1537,42 @@ _krb5_pk_rd_pa_reply(krb5_context context, case choice_PA_PK_AS_REP_encKeyPack: os = rep.u.encKeyPack; break; - default: + default: { + PA_PK_AS_REP_BTMM btmm; free_PA_PK_AS_REP(&rep); - krb5_set_error_message(context, EINVAL, - N_("PKINIT: -27 reply " - "invalid content type", "")); - return EINVAL; + memset(&rep, 0, sizeof(rep)); + + ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data, + pa->padata_value.length, + &btmm, + &size); + if (ret) { + krb5_set_error_message(context, EINVAL, + N_("PKINIT: -27 reply " + "invalid content type", "")); + return EINVAL; + } + + if (btmm.dhSignedData || btmm.encKeyPack == NULL) { + free_PA_PK_AS_REP_BTMM(&btmm); + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("DH mode not supported for BTMM mode", "")); + return ret; + } + + /* + * Transform to IETF style PK-INIT reply so that free works below + */ + + rep.element = choice_PA_PK_AS_REP_encKeyPack; + rep.u.encKeyPack.data = btmm.encKeyPack->data; + rep.u.encKeyPack.length = btmm.encKeyPack->length; + btmm.encKeyPack->data = NULL; + btmm.encKeyPack->length = 0; + free_PA_PK_AS_REP_BTMM(&btmm); + os = rep.u.encKeyPack; + } } ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL); @@ -1484,18 +1708,10 @@ hx_pass_prompter(void *data, const hx509_prompt *prompter) return 0; } - -void KRB5_LIB_FUNCTION -_krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id, - int boolean) -{ - hx509_verify_set_proxy_certificate(id->verify_ctx, boolean); -} - - krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_load_id(krb5_context context, struct krb5_pk_identity **ret_id, + int flags, const char *user_id, const char *anchor_id, char * const *chain_list, @@ -1517,7 +1733,7 @@ _krb5_pk_load_id(krb5_context context, return HEIM_PKINIT_NO_VALID_CA; } - if (user_id == NULL) { + if (user_id == NULL && (flags & 4) == 0) { krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY, N_("PKINIT: No user certificate given", "")); return HEIM_PKINIT_NO_PRIVATE_KEY; @@ -1537,6 +1753,11 @@ _krb5_pk_load_id(krb5_context context, goto out; ret = hx509_lock_init(id->hx509ctx, &lock); + if (ret) { + pk_copy_error(context, id->hx509ctx, ret, "Failed init lock"); + goto out; + } + if (password && password[0]) hx509_lock_add_password(lock, password); @@ -1550,11 +1771,15 @@ _krb5_pk_load_id(krb5_context context, goto out; } - ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs); - if (ret) { - pk_copy_error(context, id->hx509ctx, ret, - "Failed to init cert certs"); - goto out; + if (user_id) { + ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs); + if (ret) { + pk_copy_error(context, id->hx509ctx, ret, + "Failed to init cert certs"); + goto out; + } + } else { + id->certs = NULL; } ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors); @@ -1628,50 +1853,12 @@ _krb5_pk_load_id(krb5_context context, } else *ret_id = id; - hx509_lock_free(lock); + if (lock) + hx509_lock_free(lock); return ret; } -static krb5_error_code -select_dh_group(krb5_context context, DH *dh, unsigned long bits, - struct krb5_dh_moduli **moduli) -{ - const struct krb5_dh_moduli *m; - - if (bits == 0) { - m = moduli[1]; /* XXX */ - if (m == NULL) - m = moduli[0]; /* XXX */ - } else { - int i; - for (i = 0; moduli[i] != NULL; i++) { - if (bits < moduli[i]->bits) - break; - } - if (moduli[i] == NULL) { - krb5_set_error_message(context, EINVAL, - N_("Did not find a DH group parameter " - "matching requirement of %lu bits", ""), - bits); - return EINVAL; - } - m = moduli[i]; - } - - dh->p = integer_to_BN(context, "p", &m->p); - if (dh->p == NULL) - return ENOMEM; - dh->g = integer_to_BN(context, "g", &m->g); - if (dh->g == NULL) - return ENOMEM; - dh->q = integer_to_BN(context, "q", &m->q); - if (dh->q == NULL) - return ENOMEM; - - return 0; -} - /* * */ @@ -1752,8 +1939,10 @@ _krb5_parse_moduli_line(krb5_context context, while (isspace((unsigned char)*p)) p++; - if (*p == '#') + if (*p == '#') { + free(m1); return 0; + } ret = EINVAL; p1 = strsep(&p, " \t"); @@ -1764,7 +1953,7 @@ _krb5_parse_moduli_line(krb5_context context, goto out; } m1->name = strdup(p1); - if (p1 == NULL) { + if (m1->name == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memeory", "")); goto out; @@ -2002,12 +2191,22 @@ _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL) return; ctx = opt->opt_private->pk_init_ctx; - if (ctx->dh) - DH_free(ctx->dh); - ctx->dh = NULL; + switch (ctx->keyex) { + case USE_DH: + DH_free(ctx->u.dh); + break; + case USE_RSA: + break; + case USE_ECDH: +#ifdef HAVE_OPENSSL + EC_KEY_free(ctx->u.eckey); +#endif + break; + } if (ctx->id) { hx509_verify_destroy_ctx(ctx->id->verify_ctx); hx509_certs_free(&ctx->id->certs); + hx509_cert_free(ctx->id->cert); hx509_certs_free(&ctx->id->anchors); hx509_certs_free(&ctx->id->certpool); hx509_context_free(&ctx->id->hx509ctx); @@ -2056,9 +2255,6 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, N_("malloc: out of memory", "")); return ENOMEM; } - opt->opt_private->pk_init_ctx->dh = NULL; - opt->opt_private->pk_init_ctx->id = NULL; - opt->opt_private->pk_init_ctx->clientDHNonce = NULL; opt->opt_private->pk_init_ctx->require_binding = 0; opt->opt_private->pk_init_ctx->require_eku = 1; opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1; @@ -2086,6 +2282,7 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, ret = _krb5_pk_load_id(context, &opt->opt_private->pk_init_ctx->id, + flags, user_id, x509_anchors, pool, @@ -2099,50 +2296,58 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return ret; } - if ((flags & 2) == 0) { - const char *moduli_file; - unsigned long dh_min_bits; - - moduli_file = krb5_config_get_string(context, NULL, - "libdefaults", - "moduli", - NULL); + if (opt->opt_private->pk_init_ctx->id->certs) { + hx509_query *q = NULL; + hx509_cert cert = NULL; + hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx; - dh_min_bits = - krb5_config_get_int_default(context, NULL, 0, - "libdefaults", - "pkinit_dh_min_bits", - NULL); - - ret = _krb5_parse_moduli(context, moduli_file, - &opt->opt_private->pk_init_ctx->m); + ret = hx509_query_alloc(hx509ctx, &q); if (ret) { - _krb5_get_init_creds_opt_free_pkinit(opt); + pk_copy_error(context, hx509ctx, ret, + "Allocate query to find signing certificate"); return ret; } - opt->opt_private->pk_init_ctx->dh = DH_new(); - if (opt->opt_private->pk_init_ctx->dh == NULL) { - _krb5_get_init_creds_opt_free_pkinit(opt); - krb5_set_error_message(context, ENOMEM, - N_("malloc: out of memory", "")); - return ENOMEM; - } - - ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, - dh_min_bits, - opt->opt_private->pk_init_ctx->m); - if (ret) { - _krb5_get_init_creds_opt_free_pkinit(opt); + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + + ret = find_cert(context, opt->opt_private->pk_init_ctx->id, q, &cert); + hx509_query_free(hx509ctx, q); + if (ret) return ret; - } - if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) { - _krb5_get_init_creds_opt_free_pkinit(opt); - krb5_set_error_message(context, ENOMEM, - N_("pkinit: failed to generate DH key", "")); - return ENOMEM; + opt->opt_private->pk_init_ctx->id->cert = cert; + } else + opt->opt_private->pk_init_ctx->id->cert = NULL; + + if ((flags & 2) == 0) { + hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx; + hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert; + + opt->opt_private->pk_init_ctx->keyex = USE_DH; + + /* + * If its a ECDSA certs, lets select ECDSA as the keyex algorithm. + */ + if (cert) { + AlgorithmIdentifier alg; + + ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg); + if (ret == 0) { + if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0) + opt->opt_private->pk_init_ctx->keyex = USE_ECDH; + free_AlgorithmIdentifier(&alg); + } } + + } else { + opt->opt_private->pk_init_ctx->keyex = USE_RSA; + + if (opt->opt_private->pk_init_ctx->id->certs == NULL) { + krb5_set_error_message(context, EINVAL, + N_("No anonymous pkinit support in RSA mode", "")); + return EINVAL; + } } return 0; @@ -2152,3 +2357,122 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return EINVAL; #endif } + +#ifdef PKINIT + +static int +get_ms_san(hx509_context context, hx509_cert cert, char **upn) +{ + hx509_octet_string_list list; + int ret; + + *upn = NULL; + + ret = hx509_cert_find_subjectAltName_otherName(context, + cert, + &asn1_oid_id_pkinit_ms_san, + &list); + if (ret) + return 0; + + if (list.len > 0 && list.val[0].length > 0) + ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, + upn, NULL); + else + ret = 1; + hx509_free_octet_string_list(&list); + + return ret; +} + +static int +find_ms_san(hx509_context context, hx509_cert cert, void *ctx) +{ + char *upn; + int ret; + + ret = get_ms_san(context, cert, &upn); + if (ret == 0) + free(upn); + return ret; +} + + + +#endif + +/* + * Private since it need to be redesigned using krb5_get_init_creds() + */ + +krb5_error_code KRB5_LIB_FUNCTION +_krb5_pk_enterprise_cert(krb5_context context, + const char *user_id, + krb5_const_realm realm, + krb5_principal *principal) +{ +#ifdef PKINIT + krb5_error_code ret; + hx509_context hx509ctx; + hx509_certs certs, result; + hx509_cert cert; + hx509_query *q; + char *name; + + *principal = NULL; + + if (user_id == NULL) + return ENOENT; + + ret = hx509_context_init(&hx509ctx); + if (ret) + return ret; + + ret = hx509_certs_init(hx509ctx, user_id, 0, NULL, &certs); + if (ret) { + pk_copy_error(context, hx509ctx, ret, + "Failed to init cert certs"); + return ret; + } + + ret = hx509_query_alloc(hx509ctx, &q); + if (ret) { + hx509_certs_free(&certs); + return ret; + } + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku); + hx509_query_match_cmp_func(q, find_ms_san, NULL); + + ret = hx509_certs_filter(hx509ctx, certs, q, &result); + hx509_query_free(hx509ctx, q); + hx509_certs_free(&certs); + if (ret) + return ret; + + ret = hx509_get_one_cert(hx509ctx, result, &cert); + hx509_certs_free(&result); + if (ret) + return ret; + + ret = get_ms_san(hx509ctx, cert, &name); + if (ret) + return ret; + + ret = krb5_make_principal(context, principal, realm, name, NULL); + free(name); + hx509_context_free(&hx509ctx); + if (ret) + return ret; + + krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL); + + return ret; +#else + krb5_set_error_message(context, EINVAL, + N_("no support for PKINIT compiled in", "")); + return EINVAL; +#endif +} diff --git a/source4/heimdal/lib/krb5/plugin.c b/source4/heimdal/lib/krb5/plugin.c index a71dd8b6f7..844cb7ab88 100644 --- a/source4/heimdal/lib/krb5/plugin.c +++ b/source4/heimdal/lib/krb5/plugin.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); + #ifdef HAVE_DLFCN_H #include <dlfcn.h> #endif @@ -54,7 +54,13 @@ struct plugin { static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER; static struct plugin *registered = NULL; -static const char *plugin_dir = LIBDIR "/plugin/krb5"; +static const char *sysplugin_dirs[] = { + LIBDIR "/plugin/krb5", +#ifdef __APPLE__ + "/System/Library/KerberosPlugins/KerberosFrameworkPlugins", +#endif + NULL +}; /* * @@ -94,8 +100,11 @@ loadlib(krb5_context context, #ifndef RTLD_LAZY #define RTLD_LAZY 0 #endif +#ifndef RTLD_LOCAL +#define RTLD_LOCAL 0 +#endif - (*e)->dsohandle = dlopen(lib, RTLD_LAZY); + (*e)->dsohandle = dlopen(lib, RTLD_LOCAL|RTLD_LAZY); if ((*e)->dsohandle == NULL) { free(*e); *e = NULL; @@ -173,7 +182,6 @@ _krb5_plugin_find(krb5_context context, struct krb5_plugin *e; struct plugin *p; krb5_error_code ret; - char *sysdirs[2] = { NULL, NULL }; char **dirs = NULL, **di; struct dirent *entry; char *path; @@ -205,10 +213,8 @@ _krb5_plugin_find(krb5_context context, dirs = krb5_config_get_strings(context, NULL, "libdefaults", "plugin_dir", NULL); - if (dirs == NULL) { - sysdirs[0] = rk_UNCONST(plugin_dir); - dirs = sysdirs; - } + if (dirs == NULL) + dirs = rk_UNCONST(sysplugin_dirs); for (di = dirs; *di != NULL; di++) { @@ -218,7 +224,23 @@ _krb5_plugin_find(krb5_context context, rk_cloexec(dirfd(d)); while ((entry = readdir(d)) != NULL) { - asprintf(&path, "%s/%s", *di, entry->d_name); + char *n = entry->d_name; + + /* skip . and .. */ + if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) + continue; + + path = NULL; +#ifdef __APPLE__ + { /* support loading bundles on MacOS */ + size_t len = strlen(n); + if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0) + asprintf(&path, "%s/%s/Contents/MacOS/%.*s", *di, n, (int)(len - 7), n); + } +#endif + if (path == NULL) + asprintf(&path, "%s/%s", *di, n); + if (path == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); @@ -234,7 +256,7 @@ _krb5_plugin_find(krb5_context context, } closedir(d); } - if (dirs != sysdirs) + if (dirs != rk_UNCONST(sysplugin_dirs)) krb5_config_free_strings(dirs); #endif /* HAVE_DLOPEN */ @@ -246,7 +268,7 @@ _krb5_plugin_find(krb5_context context, return 0; out: - if (dirs && dirs != sysdirs) + if (dirs != rk_UNCONST(sysplugin_dirs)) krb5_config_free_strings(dirs); if (d) closedir(d); diff --git a/source4/heimdal/lib/krb5/principal.c b/source4/heimdal/lib/krb5/principal.c index f27355f2d8..50b7bb8813 100644 --- a/source4/heimdal/lib/krb5/principal.c +++ b/source4/heimdal/lib/krb5/principal.c @@ -32,7 +32,7 @@ */ /** - * @page page_principal The principal handing functions. + * @page krb5_principal_intro The principal handing functions. * * A Kerberos principal is a email address looking string that * contains to parts separeted by a @. The later part is the kerbero @@ -57,8 +57,6 @@ host/admin@H5L.ORG #include <fnmatch.h> #include "resolve.h" -RCSID("$Id$"); - #define princ_num_comp(P) ((P)->name.name_string.len) #define princ_type(P) ((P)->name.name_type) #define princ_comp(P) ((P)->name.name_string.val) @@ -78,8 +76,6 @@ RCSID("$Id$"); * @ingroup krb5_principal */ - - void KRB5_LIB_FUNCTION krb5_free_principal(krb5_context context, krb5_principal p) @@ -90,6 +86,18 @@ krb5_free_principal(krb5_context context, } } +/** + * Set the type of the principal + * + * @param context A Kerberos context. + * @param principal principal to set the type for + * @param type the new type + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + void KRB5_LIB_FUNCTION krb5_principal_set_type(krb5_context context, krb5_principal principal, @@ -127,8 +135,10 @@ krb5_principal_get_comp_string(krb5_context context, * * @param context Kerberos 5 context * @param principal principal to query + * * @return number of components in string - * @ingroup krb5 + * + * @ingroup krb5_principal */ unsigned int KRB5_LIB_FUNCTION @@ -162,7 +172,7 @@ krb5_parse_name_flags(krb5_context context, *principal = NULL; -#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM) +#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) if ((flags & RFLAGS) == RFLAGS) { krb5_set_error_message(context, KRB5_ERR_NO_SERVICE, @@ -276,7 +286,7 @@ krb5_parse_name_flags(krb5_context context, memcpy(realm, start, q - start); realm[q - start] = 0; }else{ - if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) { + if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) { ret = KRB5_PARSE_MALFORMED; krb5_set_error_message(context, ret, N_("realm NOT found in principal " @@ -524,22 +534,6 @@ krb5_unparse_name_ext(krb5_context context, #endif -krb5_realm * KRB5_LIB_FUNCTION -krb5_princ_realm(krb5_context context, - krb5_principal principal) -{ - return &princ_realm(principal); -} - - -void KRB5_LIB_FUNCTION -krb5_princ_set_realm(krb5_context context, - krb5_principal principal, - krb5_realm *realm) -{ - princ_realm(principal) = *realm; -} - krb5_error_code KRB5_LIB_FUNCTION krb5_principal_set_realm(krb5_context context, krb5_principal principal, @@ -821,6 +815,7 @@ krb5_principal_match(krb5_context context, return TRUE; } +#if defined(KRB4) || !defined(HEIMDAL_SMALLER) static struct v4_name_convert { const char *from; @@ -835,6 +830,10 @@ static struct v4_name_convert { { NULL, NULL } }; +#endif + +#ifdef KRB4 + /* * return the converted instance name of `name' in `realm'. * look in the configuration file and then in the default set above. @@ -925,6 +924,8 @@ krb5_425_conv_principal_ext2(krb5_context context, if(p){ instance = p; ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); + if (ret) + return ret; if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -938,23 +939,23 @@ krb5_425_conv_principal_ext2(krb5_context context, krb5_boolean passed = FALSE; char *inst = NULL; #ifdef USE_RESOLVER - struct dns_reply *r; + struct rk_dns_reply *r; - r = dns_lookup(instance, "aaaa"); + r = rk_dns_lookup(instance, "aaaa"); if (r) { - if (r->head && r->head->type == T_AAAA) { + if (r->head && r->head->type == rk_ns_t_aaaa) { inst = strdup(r->head->domain); passed = TRUE; } - dns_free_data(r); + rk_dns_free_data(r); } else { - r = dns_lookup(instance, "a"); + r = rk_dns_lookup(instance, "a"); if (r) { - if(r->head && r->head->type == T_A) { + if(r->head && r->head->type == rk_ns_t_a) { inst = strdup(r->head->domain); passed = TRUE; } - dns_free_data(r); + rk_dns_free_data(r); } } #else @@ -998,6 +999,8 @@ krb5_425_conv_principal_ext2(krb5_context context, snprintf(host, sizeof(host), "%s.%s", instance, realm); strlwr(host); ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if (ret) + return ret; if((*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -1025,6 +1028,10 @@ krb5_425_conv_principal_ext2(krb5_context context, for(d = domains; d && *d; d++){ snprintf(host, sizeof(host), "%s.%s", instance, *d); ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if (ret) { + krb5_config_free_strings(domains); + return ret; + } if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; krb5_config_free_strings(domains); @@ -1049,6 +1056,8 @@ krb5_425_conv_principal_ext2(krb5_context context, snprintf(host, sizeof(host), "%s.%s", instance, p); local_host: ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if (ret) + return ret; if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -1075,6 +1084,8 @@ no_host: name = p; ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); + if (ret) + return ret; if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -1084,51 +1095,9 @@ no_host: return HEIM_ERR_V4_PRINC_NO_CONV; } -static krb5_boolean -convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal) -{ - krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx; - return (*func)(conxtext, principal); -} - -krb5_error_code KRB5_LIB_FUNCTION -krb5_425_conv_principal_ext(krb5_context context, - const char *name, - const char *instance, - const char *realm, - krb5_boolean (*func)(krb5_context, krb5_principal), - krb5_boolean resolve, - krb5_principal *principal) -{ - return krb5_425_conv_principal_ext2(context, - name, - instance, - realm, - func ? convert_func : NULL, - func, - resolve, - principal); -} - - - -krb5_error_code KRB5_LIB_FUNCTION -krb5_425_conv_principal(krb5_context context, - const char *name, - const char *instance, - const char *realm, - krb5_principal *princ) -{ - krb5_boolean resolve = krb5_config_get_bool(context, - NULL, - "libdefaults", - "v4_instance_resolve", - NULL); - - return krb5_425_conv_principal_ext(context, name, instance, realm, - NULL, resolve, princ); -} +#endif /* KRB4 */ +#ifndef HEIMDAL_SMALLER static int check_list(const krb5_config_binding *l, const char *name, const char **out) @@ -1186,6 +1155,7 @@ name_convert(krb5_context context, const char *name, const char *realm, return KRB5_NT_UNKNOWN; /* didn't find it in config file, try built-in list */ +#ifdef KRB4 { struct v4_name_convert *q; for(q = default_v4_name_convert; q->from; q++) { @@ -1195,6 +1165,7 @@ name_convert(krb5_context context, const char *name, const char *realm, } } } +#endif return -1; } @@ -1273,6 +1244,8 @@ krb5_524_conv_principal(krb5_context context, return 0; } +#endif /* !HEIMDAL_SMALLER */ + /** * Create a principal for the service running on hostname. If * KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or diff --git a/source4/heimdal/lib/krb5/prog_setup.c b/source4/heimdal/lib/krb5/prog_setup.c index b368573b8d..4c060973d6 100644 --- a/source4/heimdal/lib/krb5/prog_setup.c +++ b/source4/heimdal/lib/krb5/prog_setup.c @@ -35,8 +35,6 @@ #include <getarg.h> #include <err.h> -RCSID("$Id$"); - void KRB5_LIB_FUNCTION krb5_std_usage(int code, struct getargs *args, int num_args) { diff --git a/source4/heimdal/lib/krb5/prompter_posix.c b/source4/heimdal/lib/krb5/prompter_posix.c index 7d63935423..05deaff525 100644 --- a/source4/heimdal/lib/krb5/prompter_posix.c +++ b/source4/heimdal/lib/krb5/prompter_posix.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - int KRB5_LIB_FUNCTION krb5_prompter_posix (krb5_context context, void *data, diff --git a/source4/heimdal/lib/krb5/rd_cred.c b/source4/heimdal/lib/krb5/rd_cred.c index dc51033019..f41edfa2b5 100644 --- a/source4/heimdal/lib/krb5/rd_cred.c +++ b/source4/heimdal/lib/krb5/rd_cred.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code compare_addrs(krb5_context context, krb5_address *a, @@ -149,15 +147,18 @@ krb5_rd_cred(krb5_context context, goto out; } - ret = krb5_decode_EncKrbCredPart (context, - enc_krb_cred_part_data.data, - enc_krb_cred_part_data.length, - &enc_krb_cred_part, - &len); + ret = decode_EncKrbCredPart(enc_krb_cred_part_data.data, + enc_krb_cred_part_data.length, + &enc_krb_cred_part, + &len); if (enc_krb_cred_part_data.data != cred.enc_part.cipher.data) krb5_data_free(&enc_krb_cred_part_data); - if (ret) + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode " + "encrypte credential part", "")); goto out; + } /* check sender address */ diff --git a/source4/heimdal/lib/krb5/rd_error.c b/source4/heimdal/lib/krb5/rd_error.c index 75ae8b1e8a..1561188fad 100644 --- a/source4/heimdal/lib/krb5/rd_error.c +++ b/source4/heimdal/lib/krb5/rd_error.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_rd_error(krb5_context context, const krb5_data *msg, diff --git a/source4/heimdal/lib/krb5/rd_priv.c b/source4/heimdal/lib/krb5/rd_priv.c index 6778ccad88..fb6cfcee4f 100644 --- a/source4/heimdal/lib/krb5/rd_priv.c +++ b/source4/heimdal/lib/krb5/rd_priv.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_rd_priv(krb5_context context, krb5_auth_context auth_context, diff --git a/source4/heimdal/lib/krb5/rd_rep.c b/source4/heimdal/lib/krb5/rd_rep.c index 010726b180..2d5792cd40 100644 --- a/source4/heimdal/lib/krb5/rd_rep.c +++ b/source4/heimdal/lib/krb5/rd_rep.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_rd_rep(krb5_context context, krb5_auth_context auth_context, @@ -48,7 +46,6 @@ krb5_rd_rep(krb5_context context, krb5_crypto crypto; krb5_data_zero (&data); - ret = 0; ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len); if (ret) @@ -82,13 +79,11 @@ krb5_rd_rep(krb5_context context, krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out; } - ret = krb5_decode_EncAPRepPart(context, - data.data, - data.length, - *repl, - &len); - if (ret) + ret = decode_EncAPRepPart(data.data, data.length, *repl, &len); + if (ret) { + krb5_set_error_message(context, ret, N_("Failed to decode EncAPRepPart", "")); return ret; + } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { if ((*repl)->ctime != auth_context->authenticator->ctime || diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c index a416f90c10..784427fe40 100644 --- a/source4/heimdal/lib/krb5/rd_req.c +++ b/source4/heimdal/lib/krb5/rd_req.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code decrypt_tkt_enc_part (krb5_context context, krb5_keyblock *key, @@ -58,8 +56,11 @@ decrypt_tkt_enc_part (krb5_context context, if (ret) return ret; - ret = krb5_decode_EncTicketPart(context, plain.data, plain.length, - decr_part, &len); + ret = decode_EncTicketPart(plain.data, plain.length, decr_part, &len); + if (ret) + krb5_set_error_message(context, ret, + N_("Failed to decode encrypted " + "ticket part", "")); krb5_data_free (&plain); return ret; } @@ -95,8 +96,8 @@ decrypt_authenticator (krb5_context context, if (ret) return ret; - ret = krb5_decode_Authenticator(context, plain.data, plain.length, - authenticator, &len); + ret = decode_Authenticator(plain.data, plain.length, + authenticator, &len); krb5_data_free (&plain); return ret; } @@ -521,10 +522,20 @@ struct krb5_rd_req_out_ctx_data { krb5_keyblock *keyblock; krb5_flags ap_req_options; krb5_ticket *ticket; + krb5_principal server; }; -/* +/** + * Allocate a krb5_rd_req_in_ctx as an input parameter to + * krb5_rd_req_ctx(). The caller should free the context with + * krb5_rd_req_in_ctx_free() when done with the context. + * + * @param context Keberos 5 context. + * @param ctx in ctx to krb5_rd_req_ctx(). + * + * @return Kerberos 5 error code, see krb5_get_error_message(). * + * @ingroup krb5_auth */ krb5_error_code KRB5_LIB_FUNCTION @@ -540,12 +551,26 @@ krb5_rd_req_in_ctx_alloc(krb5_context context, krb5_rd_req_in_ctx *ctx) return 0; } +/** + * Set the keytab that krb5_rd_req_ctx() will use. + * + * @param context Keberos 5 context. + * @param in in ctx to krb5_rd_req_ctx(). + * @param keytab keytab that krb5_rd_req_ctx() will use, only copy the + * pointer, so the caller must free they keytab after + * krb5_rd_req_in_ctx_free() is called. + * + * @return Kerberos 5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_auth + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_rd_req_in_set_keytab(krb5_context context, krb5_rd_req_in_ctx in, krb5_keytab keytab) { - in->keytab = keytab; /* XXX should make copy */ + in->keytab = keytab; return 0; } @@ -558,7 +583,7 @@ krb5_rd_req_in_set_keytab(krb5_context context, * * @return Kerberos 5 error code, see krb5_get_error_message(). * - * @ingroup krb5 + * @ingroup krb5_auth */ krb5_error_code KRB5_LIB_FUNCTION @@ -605,28 +630,50 @@ krb5_rd_req_out_get_keyblock(krb5_context context, return krb5_copy_keyblock(context, out->keyblock, keyblock); } +/** + * Get the principal that was used in the request from the + * client. Might not match whats in the ticket if krb5_rd_req_ctx() + * searched in the keytab for a matching key. + * + * @param context a Kerberos 5 context. + * @param out a krb5_rd_req_out_ctx from krb5_rd_req_ctx(). + * @param principal return principal, free with krb5_free_principal(). + * + * @ingroup krb5_auth + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_req_out_get_server(krb5_context context, + krb5_rd_req_out_ctx out, + krb5_principal *principal) +{ + return krb5_copy_principal(context, out->server, principal); +} + void KRB5_LIB_FUNCTION krb5_rd_req_in_ctx_free(krb5_context context, krb5_rd_req_in_ctx ctx) { free(ctx); } -krb5_error_code KRB5_LIB_FUNCTION -_krb5_rd_req_out_ctx_alloc(krb5_context context, krb5_rd_req_out_ctx *ctx) -{ - *ctx = calloc(1, sizeof(**ctx)); - if (*ctx == NULL) { - krb5_set_error_message(context, ENOMEM, - N_("malloc: out of memory", "")); - return ENOMEM; - } - return 0; -} +/** + * Free the krb5_rd_req_out_ctx. + * + * @param context Keberos 5 context. + * @param ctx krb5_rd_req_out_ctx context to free. + * + * @ingroup krb5_auth + */ void KRB5_LIB_FUNCTION krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx) { - krb5_free_keyblock(context, ctx->keyblock); + if (ctx->ticket) + krb5_free_ticket(context, ctx->ticket); + if (ctx->keyblock) + krb5_free_keyblock(context, ctx->keyblock); + if (ctx->server) + krb5_free_principal(context, ctx->server); free(ctx); } @@ -726,7 +773,6 @@ out: static krb5_error_code get_key_from_keytab(krb5_context context, - krb5_auth_context *auth_context, krb5_ap_req *ap_req, krb5_const_principal server, krb5_keytab keytab, @@ -764,8 +810,28 @@ out: return ret; } -/* +/** + * The core server function that verify application authentication + * requests from clients. + * + * @param context Keberos 5 context. + * @param auth_context the authentication context, can be NULL, then + * default values for the authentication context will used. + * @param inbuf the (AP-REQ) authentication buffer + * + * @param server the server with authenticate as, if NULL the function + * will try to find any avaiable credentintial in the keytab + * that will verify the reply. The function will prefer the + * server the server client specified in the AP-REQ, but if + * there is no mach, it will try all keytab entries for a + * match. This have serious performance issues for larger keytabs. * + * @param inctx control the behavior of the function, if NULL, the + * default behavior is used. + * @param outctx the return outctx, free with krb5_rd_req_out_ctx_free(). + * @return Kerberos 5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_auth */ krb5_error_code KRB5_LIB_FUNCTION @@ -778,12 +844,18 @@ krb5_rd_req_ctx(krb5_context context, { krb5_error_code ret; krb5_ap_req ap_req; - krb5_principal service = NULL; krb5_rd_req_out_ctx o = NULL; + krb5_keytab id = NULL, keytab = NULL; + krb5_principal service = NULL; - ret = _krb5_rd_req_out_ctx_alloc(context, &o); - if (ret) - goto out; + *outctx = NULL; + + o = calloc(1, sizeof(*o)); + if (o == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } if (*auth_context == NULL) { ret = krb5_auth_con_init(context, auth_context); @@ -795,15 +867,14 @@ krb5_rd_req_ctx(krb5_context context, if(ret) goto out; - if(server == NULL){ - ret = _krb5_principalname2krb5_principal(context, - &service, - ap_req.ticket.sname, - ap_req.ticket.realm); - if (ret) - goto out; - server = service; - } + /* Save that principal that was in the request */ + ret = _krb5_principalname2krb5_principal(context, + &o->server, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) + goto out; + if (ap_req.ap_options.use_session_key && (*auth_context)->keyblock == NULL) { ret = KRB5KRB_AP_ERR_NOKEY; @@ -813,49 +884,155 @@ krb5_rd_req_ctx(krb5_context context, goto out; } + if (inctx && inctx->keytab) + id = inctx->keytab; + if((*auth_context)->keyblock){ ret = krb5_copy_keyblock(context, (*auth_context)->keyblock, &o->keyblock); if (ret) goto out; - } else if(inctx->keyblock){ + } else if(inctx && inctx->keyblock){ ret = krb5_copy_keyblock(context, inctx->keyblock, &o->keyblock); if (ret) goto out; } else { - krb5_keytab keytab = NULL; - if (inctx && inctx->keytab) - keytab = inctx->keytab; + if(id == NULL) { + krb5_kt_default(context, &keytab); + id = keytab; + } + if (id == NULL) + goto out; + + if (server == NULL) { + ret = _krb5_principalname2krb5_principal(context, + &service, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) + goto out; + server = service; + } ret = get_key_from_keytab(context, - auth_context, &ap_req, server, - keytab, + id, &o->keyblock); - if(ret) - goto out; + if (ret) { + /* If caller specified a server, fail. */ + if (service == NULL) + goto out; + /* Otherwise, fall back to iterating over the keytab. This + * have serious performace issues for larger keytab. + */ + o->keyblock = NULL; + } } - ret = krb5_verify_ap_req2(context, - auth_context, - &ap_req, - server, - o->keyblock, - 0, - &o->ap_req_options, - &o->ticket, - KRB5_KU_AP_REQ_AUTH); + if (o->keyblock) { + /* + * We got an exact keymatch, use that. + */ - if (ret) - goto out; + ret = krb5_verify_ap_req2(context, + auth_context, + &ap_req, + server, + o->keyblock, + 0, + &o->ap_req_options, + &o->ticket, + KRB5_KU_AP_REQ_AUTH); + + if (ret) + goto out; + + } else { + /* + * Interate over keytab to find a key that can decrypt the request. + */ + + krb5_keytab_entry entry; + krb5_kt_cursor cursor; + int done = 0, kvno = 0; + + memset(&cursor, 0, sizeof(cursor)); + + if (ap_req.ticket.enc_part.kvno) + kvno = *ap_req.ticket.enc_part.kvno; + + ret = krb5_kt_start_seq_get(context, id, &cursor); + if (ret) + goto out; + + done = 0; + while (!done) { + krb5_principal p; + + ret = krb5_kt_next_entry(context, id, &entry, &cursor); + if (ret) { + _krb5_kt_principal_not_found(context, ret, id, o->server, + ap_req.ticket.enc_part.etype, + kvno); + goto out; + } + + if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype || + (kvno && kvno != entry.vno)) { + krb5_kt_free_entry (context, &entry); + continue; + } + + ret = krb5_verify_ap_req2(context, + auth_context, + &ap_req, + server, + &entry.keyblock, + 0, + &o->ap_req_options, + &o->ticket, + KRB5_KU_AP_REQ_AUTH); + if (ret) { + krb5_kt_free_entry (context, &entry); + continue; + } + + /* + * Found a match, save the keyblock for PAC processing, + * and update the service principal in the ticket to match + * whatever is in the keytab. + */ + + ret = krb5_copy_keyblock(context, + &entry.keyblock, + &o->keyblock); + if (ret) { + krb5_kt_free_entry (context, &entry); + goto out; + } + + ret = krb5_copy_principal(context, entry.principal, &p); + if (ret) { + krb5_kt_free_entry (context, &entry); + goto out; + } + krb5_free_principal(context, o->ticket->server); + o->ticket->server = p; + + krb5_kt_free_entry (context, &entry); + + done = 1; + } + krb5_kt_end_seq_get (context, id, &cursor); + } /* If there is a PAC, verify its server signature */ - if (inctx->check_pac) { + if (inctx == NULL || inctx->check_pac) { krb5_pac pac; krb5_data data; @@ -878,17 +1055,23 @@ krb5_rd_req_ctx(krb5_context context, krb5_pac_free(context, pac); if (ret) goto out; - } - ret = 0; + } else + ret = 0; } out: + if (ret || outctx == NULL) { krb5_rd_req_out_ctx_free(context, o); } else *outctx = o; free_AP_REQ(&ap_req); - if(service) + + if (service) krb5_free_principal(context, service); + + if (keytab) + krb5_kt_close(context, keytab); + return ret; } diff --git a/source4/heimdal/lib/krb5/replay.c b/source4/heimdal/lib/krb5/replay.c index 25a6da0262..37556cfbc5 100644 --- a/source4/heimdal/lib/krb5/replay.c +++ b/source4/heimdal/lib/krb5/replay.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <vis.h> -RCSID("$Id$"); - struct krb5_rcache_data { char *name; }; diff --git a/source4/heimdal/lib/krb5/send_to_kdc.c b/source4/heimdal/lib/krb5/send_to_kdc.c index 53c4a69a3f..50b42f2f10 100644 --- a/source4/heimdal/lib/krb5/send_to_kdc.c +++ b/source4/heimdal/lib/krb5/send_to_kdc.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "send_to_kdc_plugin.h" -RCSID("$Id$"); - struct send_to_kdc { krb5_send_to_kdc_func func; void *data; @@ -384,8 +382,8 @@ krb5_sendto (krb5_context context, if (context->send_to_kdc) { struct send_to_kdc *s = context->send_to_kdc; - ret = (*s->func)(context, s->data, - hi, context->kdc_timeout, send_data, receive); + ret = (*s->func)(context, s->data, hi, + context->kdc_timeout, send_data, receive); if (ret == 0 && receive->length != 0) goto out; continue; diff --git a/source4/heimdal/lib/krb5/set_default_realm.c b/source4/heimdal/lib/krb5/set_default_realm.c index 6907b11d10..91201eeb53 100644 --- a/source4/heimdal/lib/krb5/set_default_realm.c +++ b/source4/heimdal/lib/krb5/set_default_realm.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* * Convert the simple string `s' into a NULL-terminated and freshly allocated * list in `list'. Return an error code. diff --git a/source4/heimdal/lib/krb5/store-int.h b/source4/heimdal/lib/krb5/store-int.h index 8489f98453..0b7accb860 100644 --- a/source4/heimdal/lib/krb5/store-int.h +++ b/source4/heimdal/lib/krb5/store-int.h @@ -39,6 +39,7 @@ struct krb5_storage_data { ssize_t (*fetch)(struct krb5_storage_data*, void*, size_t); ssize_t (*store)(struct krb5_storage_data*, const void*, size_t); off_t (*seek)(struct krb5_storage_data*, off_t, int); + int (*trunc)(struct krb5_storage_data*, off_t); void (*free)(struct krb5_storage_data*); krb5_flags flags; int eof_code; diff --git a/source4/heimdal/lib/krb5/store.c b/source4/heimdal/lib/krb5/store.c index 47f9abe1de..2ba83ef0d5 100644 --- a/source4/heimdal/lib/krb5/store.c +++ b/source4/heimdal/lib/krb5/store.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V)) #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE) #define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE) @@ -54,12 +52,36 @@ krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags) sp->flags &= ~flags; } +/** + * Return true or false depending on if the storage flags is set or + * not. NB testing for the flag 0 always return true. + * + * @param sp the storage buffer to check flags on + * @param flags The flags to test for + * + * @return true if all the flags are set, false if not. + * + * @ingroup krb5_storage + */ + krb5_boolean KRB5_LIB_FUNCTION krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags) { return (sp->flags & flags) == flags; } +/** + * Set the new byte order of the storage buffer. + * + * @param sp the storage buffer to set the byte order for. + * @param byteorder the new byte order. + * + * The byte order are: KRB5_STORAGE_BYTEORDER_BE, + * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST. + * + * @ingroup krb5_storage + */ + void KRB5_LIB_FUNCTION krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder) { @@ -67,36 +89,121 @@ krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder) sp->flags |= byteorder; } +/** + * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants. + * + * @ingroup krb5_storage + */ + krb5_flags KRB5_LIB_FUNCTION -krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder) +krb5_storage_get_byteorder(krb5_storage *sp) { return sp->flags & KRB5_STORAGE_BYTEORDER_MASK; } +/** + * Seek to a new offset. + * + * @param sp the storage buffer to seek in. + * @param offset the offset to seek + * @param whence relateive searching, SEEK_CUR from the current + * position, SEEK_END from the end, SEEK_SET absolute from the start. + * + * @return The new current offset + * + * @ingroup krb5_storage + */ + off_t KRB5_LIB_FUNCTION krb5_storage_seek(krb5_storage *sp, off_t offset, int whence) { return (*sp->seek)(sp, offset, whence); } +/** + * Truncate the storage buffer in sp to offset. + * + * @param sp the storage buffer to truncate. + * @param offset the offset to truncate too. + * + * @return An Kerberos 5 error code. + * + * @ingroup krb5_storage + */ + +int KRB5_LIB_FUNCTION +krb5_storage_truncate(krb5_storage *sp, off_t offset) +{ + return (*sp->trunc)(sp, offset); +} + +/** + * Read to the storage buffer. + * + * @param sp the storage buffer to read from + * @param buf the buffer to store the data in + * @param len the length to read + * + * @return The length of data read (can be shorter then len), or negative on error. + * + * @ingroup krb5_storage + */ + krb5_ssize_t KRB5_LIB_FUNCTION krb5_storage_read(krb5_storage *sp, void *buf, size_t len) { return sp->fetch(sp, buf, len); } +/** + * Write to the storage buffer. + * + * @param sp the storage buffer to write to + * @param buf the buffer to write to the storage buffer + * @param len the length to write + * + * @return The length of data written (can be shorter then len), or negative on error. + * + * @ingroup krb5_storage + */ + krb5_ssize_t KRB5_LIB_FUNCTION krb5_storage_write(krb5_storage *sp, const void *buf, size_t len) { return sp->store(sp, buf, len); } +/** + * Set the return code that will be used when end of storage is reached. + * + * @param sp the storage + * @param code the error code to return on end of storage + * + * @ingroup krb5_storage + */ + void KRB5_LIB_FUNCTION krb5_storage_set_eof_code(krb5_storage *sp, int code) { sp->eof_code = code; } +/** + * Get the return code that will be used when end of storage is reached. + * + * @param sp the storage + * + * @return storage error code + * + * @ingroup krb5_storage + */ + +int KRB5_LIB_FUNCTION +krb5_storage_get_eof_code(krb5_storage *sp) +{ + return sp->eof_code; +} + krb5_ssize_t KRB5_LIB_FUNCTION _krb5_put_int(void *buffer, unsigned long value, size_t size) { @@ -121,6 +228,16 @@ _krb5_get_int(void *buffer, unsigned long *value, size_t size) return size; } +/** + * Free a krb5 storage. + * + * @param sp the storage to free. + * + * @return An Kerberos 5 error code. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_storage_free(krb5_storage *sp) { @@ -131,15 +248,29 @@ krb5_storage_free(krb5_storage *sp) return 0; } +/** + * Copy the contnent of storage + * + * @param sp the storage to copy to a data + * @param data the copied data, free with krb5_data_free() + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_storage_to_data(krb5_storage *sp, krb5_data *data) { - off_t pos; - size_t size; + off_t pos, size; krb5_error_code ret; pos = sp->seek(sp, 0, SEEK_CUR); + if (pos < 0) + return HEIM_ERR_NOT_SEEKABLE; size = (size_t)sp->seek(sp, 0, SEEK_END); + if (size > (size_t)-1) + return HEIM_ERR_TOO_BIG; ret = krb5_data_alloc (data, size); if (ret) { sp->seek(sp, pos, SEEK_SET); @@ -170,6 +301,18 @@ krb5_store_int(krb5_storage *sp, return 0; } +/** + * Store a int32 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_int32(krb5_storage *sp, int32_t value) @@ -181,6 +324,18 @@ krb5_store_int32(krb5_storage *sp, return krb5_store_int(sp, value, 4); } +/** + * Store a uint32 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_uint32(krb5_storage *sp, uint32_t value) @@ -232,6 +387,18 @@ krb5_ret_uint32(krb5_storage *sp, return ret; } +/** + * Store a int16 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_int16(krb5_storage *sp, int16_t value) @@ -243,6 +410,18 @@ krb5_store_int16(krb5_storage *sp, return krb5_store_int(sp, value, 2); } +/** + * Store a uint16 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_uint16(krb5_storage *sp, uint16_t value) @@ -281,6 +460,17 @@ krb5_ret_uint16(krb5_storage *sp, return ret; } +/** + * Store a int8 to storage. + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_int8(krb5_storage *sp, int8_t value) @@ -293,6 +483,17 @@ krb5_store_int8(krb5_storage *sp, return 0; } +/** + * Store a uint8 to storage. + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_uint8(krb5_storage *sp, uint8_t value) @@ -326,6 +527,17 @@ krb5_ret_uint8(krb5_storage *sp, return ret; } +/** + * Store a data to the storage. + * + * @param sp the storage buffer to write to + * @param data the buffer to store. + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_data(krb5_storage *sp, krb5_data data) @@ -343,6 +555,17 @@ krb5_store_data(krb5_storage *sp, return 0; } +/** + * Parse a data from the storage. + * + * @param sp the storage buffer to read from + * @param data the parsed data + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_ret_data(krb5_storage *sp, krb5_data *data) @@ -594,6 +817,17 @@ krb5_ret_principal(krb5_storage *sp, return 0; } +/** + * Store a keyblock to the storage. + * + * @param sp the storage buffer to write to + * @param p the keyblock to write + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p) { @@ -612,6 +846,17 @@ krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p) return ret; } +/** + * Read a keyblock from the storage. + * + * @param sp the storage buffer to write to + * @param p the keyblock read from storage, free using krb5_free_keyblock() + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p) { @@ -631,6 +876,17 @@ krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p) return ret; } +/** + * Write a times block to storage. + * + * @param sp the storage buffer to write to + * @param times the times block to write. + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_times(krb5_storage *sp, krb5_times times) { @@ -645,6 +901,17 @@ krb5_store_times(krb5_storage *sp, krb5_times times) return ret; } +/** + * Read a times block from the storage. + * + * @param sp the storage buffer to write to + * @param times the times block read from storage + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_ret_times(krb5_storage *sp, krb5_times *times) { @@ -903,6 +1170,8 @@ krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds) header |= SC_ADDRESSES; ret = krb5_store_int32(sp, header); + if (ret) + return ret; if (creds->client) { ret = krb5_store_principal(sp, creds->client); diff --git a/source4/heimdal/lib/krb5/store_emem.c b/source4/heimdal/lib/krb5/store_emem.c index 8a587600fd..4be89b6564 100644 --- a/source4/heimdal/lib/krb5/store_emem.c +++ b/source4/heimdal/lib/krb5/store_emem.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - typedef struct emem_storage{ unsigned char *base; size_t size; @@ -67,7 +65,7 @@ emem_store(krb5_storage *sp, const void *data, size_t size) sz *= 2; base = realloc(s->base, sz); if(base == NULL) - return 0; + return -1; s->size = sz; s->base = base; s->ptr = (unsigned char*)base + off; @@ -104,6 +102,34 @@ emem_seek(krb5_storage *sp, off_t offset, int whence) return s->ptr - s->base; } +static int +emem_trunc(krb5_storage *sp, off_t offset) +{ + emem_storage *s = (emem_storage*)sp->data; + /* + * If offset is larget then current size, or current size is + * shrunk more then half of the current size, adjust buffer. + */ + if (offset > s->size || (s->size / 2) > offset) { + void *base; + size_t off; + off = s->ptr - s->base; + base = realloc(s->base, offset); + if(base == NULL) + return ENOMEM; + if (offset > s->size) + memset((char *)base + s->size, 0, offset - s->size); + s->size = offset; + s->base = base; + s->ptr = (unsigned char *)base + off; + } + s->len = offset; + if ((s->ptr - s->base) > offset) + s->ptr = s->base + offset; + return 0; +} + + static void emem_free(krb5_storage *sp) { @@ -112,6 +138,21 @@ emem_free(krb5_storage *sp) free(s->base); } +/** + * Create a elastic (allocating) memory storage backend. Memory is + * allocated on demand. Free returned krb5_storage with + * krb5_storage_free(). + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_fd() + * @sa krb5_storage_from_data() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_emem(void) { @@ -142,6 +183,7 @@ krb5_storage_emem(void) sp->fetch = emem_fetch; sp->store = emem_store; sp->seek = emem_seek; + sp->trunc = emem_trunc; sp->free = emem_free; return sp; } diff --git a/source4/heimdal/lib/krb5/store_fd.c b/source4/heimdal/lib/krb5/store_fd.c index fe3c513ee9..38d67ae4d3 100644 --- a/source4/heimdal/lib/krb5/store_fd.c +++ b/source4/heimdal/lib/krb5/store_fd.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - typedef struct fd_storage { int fd; } fd_storage; @@ -60,12 +58,33 @@ fd_seek(krb5_storage * sp, off_t offset, int whence) return lseek(FD(sp), offset, whence); } +static int +fd_trunc(krb5_storage * sp, off_t offset) +{ + if (ftruncate(FD(sp), offset) == -1) + return errno; + return 0; +} + static void fd_free(krb5_storage * sp) { close(FD(sp)); } +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_data() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_fd(int fd) { @@ -93,6 +112,7 @@ krb5_storage_from_fd(int fd) sp->fetch = fd_fetch; sp->store = fd_store; sp->seek = fd_seek; + sp->trunc = fd_trunc; sp->free = fd_free; return sp; } diff --git a/source4/heimdal/lib/krb5/store_mem.c b/source4/heimdal/lib/krb5/store_mem.c index 5c7cd17fba..db1abc1e90 100644 --- a/source4/heimdal/lib/krb5/store_mem.c +++ b/source4/heimdal/lib/krb5/store_mem.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - typedef struct mem_storage{ unsigned char *base; size_t size; @@ -93,6 +91,37 @@ mem_seek(krb5_storage *sp, off_t offset, int whence) return s->ptr - s->base; } +static int +mem_trunc(krb5_storage *sp, off_t offset) +{ + mem_storage *s = (mem_storage*)sp->data; + if(offset > s->size) + return ERANGE; + s->size = offset; + if ((s->ptr - s->base) > offset) + s->ptr = s->base + offset; + return 0; +} + +static int +mem_no_trunc(krb5_storage *sp, off_t offset) +{ + return EINVAL; +} + +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_data() + * @sa krb5_storage_from_fd() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_mem(void *buf, size_t len) { @@ -114,16 +143,43 @@ krb5_storage_from_mem(void *buf, size_t len) sp->fetch = mem_fetch; sp->store = mem_store; sp->seek = mem_seek; + sp->trunc = mem_trunc; sp->free = NULL; return sp; } +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_fd() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_data(krb5_data *data) { return krb5_storage_from_mem(data->data, data->length); } +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_data() + * @sa krb5_storage_from_fd() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_readonly_mem(const void *buf, size_t len) { @@ -145,6 +201,7 @@ krb5_storage_from_readonly_mem(const void *buf, size_t len) sp->fetch = mem_fetch; sp->store = mem_no_store; sp->seek = mem_seek; + sp->trunc = mem_no_trunc; sp->free = NULL; return sp; } diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c index db78626570..86c4924506 100644 --- a/source4/heimdal/lib/krb5/ticket.c +++ b/source4/heimdal/lib/krb5/ticket.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_free_ticket(krb5_context context, krb5_ticket *ticket) @@ -301,3 +299,485 @@ krb5_ticket_get_authorization_data_type(krb5_context context, } return 0; } + +static krb5_error_code +check_server_referral(krb5_context context, + krb5_kdc_rep *rep, + unsigned flags, + krb5_const_principal requested, + krb5_const_principal returned, + krb5_keyblock * key) +{ + krb5_error_code ret; + PA_ServerReferralData ref; + krb5_crypto session; + EncryptedData ed; + size_t len; + krb5_data data; + PA_DATA *pa; + int i = 0, cmp; + + if (rep->kdc_rep.padata == NULL) + goto noreferral; + + pa = krb5_find_padata(rep->kdc_rep.padata->val, + rep->kdc_rep.padata->len, + KRB5_PADATA_SERVER_REFERRAL, &i); + if (pa == NULL) + goto noreferral; + + memset(&ed, 0, sizeof(ed)); + memset(&ref, 0, sizeof(ref)); + + ret = decode_EncryptedData(pa->padata_value.data, + pa->padata_value.length, + &ed, &len); + if (ret) + return ret; + if (len != pa->padata_value.length) { + free_EncryptedData(&ed); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Referral EncryptedData wrong for realm %s", + "realm"), requested->realm); + return KRB5KRB_AP_ERR_MODIFIED; + } + + ret = krb5_crypto_init(context, key, 0, &session); + if (ret) { + free_EncryptedData(&ed); + return ret; + } + + ret = krb5_decrypt_EncryptedData(context, session, + KRB5_KU_PA_SERVER_REFERRAL, + &ed, &data); + free_EncryptedData(&ed); + krb5_crypto_destroy(context, session); + if (ret) + return ret; + + ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len); + if (ret) { + krb5_data_free(&data); + return ret; + } + krb5_data_free(&data); + + if (strcmp(requested->realm, returned->realm) != 0) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("server ref realm mismatch, " + "requested realm %s got back %s", ""), + requested->realm, returned->realm); + return KRB5KRB_AP_ERR_MODIFIED; + } + + if (returned->name.name_string.len == 2 && + strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0) + { + const char *realm = returned->name.name_string.val[1]; + + if (ref.referred_realm == NULL + || strcmp(*ref.referred_realm, realm) != 0) + { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("tgt returned with wrong ref", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + } else if (krb5_principal_compare(context, returned, requested) == 0) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("req princ no same as returned", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + + if (ref.requested_principal_name) { + cmp = _krb5_principal_compare_PrincipalName(context, + requested, + ref.requested_principal_name); + if (!cmp) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("referred principal not same " + "as requested", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + } else if (flags & EXTRACT_TICKET_AS_REQ) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Requested principal missing on AS-REQ", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + + free_PA_ServerReferralData(&ref); + + return ret; +noreferral: + if (krb5_principal_compare(context, requested, returned) == FALSE) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Not same server principal returned " + "as requested", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + return 0; +} + + +/* + * Verify referral data + */ + + +static krb5_error_code +check_client_referral(krb5_context context, + krb5_kdc_rep *rep, + krb5_const_principal requested, + krb5_const_principal mapped, + krb5_keyblock const * key) +{ + krb5_error_code ret; + PA_ClientCanonicalized canon; + krb5_crypto crypto; + krb5_data data; + PA_DATA *pa; + size_t len; + int i = 0; + + if (rep->kdc_rep.padata == NULL) + goto noreferral; + + pa = krb5_find_padata(rep->kdc_rep.padata->val, + rep->kdc_rep.padata->len, + KRB5_PADATA_CLIENT_CANONICALIZED, &i); + if (pa == NULL) + goto noreferral; + + ret = decode_PA_ClientCanonicalized(pa->padata_value.data, + pa->padata_value.length, + &canon, &len); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode ClientCanonicalized " + "from realm %s", ""), requested->realm); + return ret; + } + + ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, + &canon.names, &len, ret); + if (ret) { + free_PA_ClientCanonicalized(&canon); + return ret; + } + if (data.length != len) + krb5_abortx(context, "internal asn.1 error"); + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + free(data.data); + free_PA_ClientCanonicalized(&canon); + return ret; + } + + ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES, + data.data, data.length, + &canon.canon_checksum); + krb5_crypto_destroy(context, crypto); + free(data.data); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to verify client canonicalized " + "data from realm %s", ""), + requested->realm); + free_PA_ClientCanonicalized(&canon); + return ret; + } + + if (!_krb5_principal_compare_PrincipalName(context, + requested, + &canon.names.requested_name)) + { + free_PA_ClientCanonicalized(&canon); + krb5_set_error_message(context, KRB5_PRINC_NOMATCH, + N_("Requested name doesn't match" + " in client referral", "")); + return KRB5_PRINC_NOMATCH; + } + if (!_krb5_principal_compare_PrincipalName(context, + mapped, + &canon.names.mapped_name)) + { + free_PA_ClientCanonicalized(&canon); + krb5_set_error_message(context, KRB5_PRINC_NOMATCH, + N_("Mapped name doesn't match" + " in client referral", "")); + return KRB5_PRINC_NOMATCH; + } + + return 0; + +noreferral: + if (krb5_principal_compare(context, requested, mapped) == FALSE) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Not same client principal returned " + "as requested", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + return 0; +} + + +static krb5_error_code +decrypt_tkt (krb5_context context, + krb5_keyblock *key, + krb5_key_usage usage, + krb5_const_pointer decrypt_arg, + krb5_kdc_rep *dec_rep) +{ + krb5_error_code ret; + krb5_data data; + size_t size; + krb5_crypto crypto; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + return ret; + + ret = krb5_decrypt_EncryptedData (context, + crypto, + usage, + &dec_rep->kdc_rep.enc_part, + &data); + krb5_crypto_destroy(context, crypto); + + if (ret) + return ret; + + ret = decode_EncASRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + if (ret) + ret = decode_EncTGSRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + krb5_data_free (&data); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode encpart in ticket", "")); + return ret; + } + return 0; +} + +int +_krb5_extract_ticket(krb5_context context, + krb5_kdc_rep *rep, + krb5_creds *creds, + krb5_keyblock *key, + krb5_const_pointer keyseed, + krb5_key_usage key_usage, + krb5_addresses *addrs, + unsigned nonce, + unsigned flags, + krb5_decrypt_proc decrypt_proc, + krb5_const_pointer decryptarg) +{ + krb5_error_code ret; + krb5_principal tmp_principal; + size_t len; + time_t tmp_time; + krb5_timestamp sec_now; + + /* decrypt */ + + if (decrypt_proc == NULL) + decrypt_proc = decrypt_tkt; + + ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); + if (ret) + goto out; + + /* save session key */ + + creds->session.keyvalue.length = 0; + creds->session.keyvalue.data = NULL; + creds->session.keytype = rep->enc_part.key.keytype; + ret = krb5_data_copy (&creds->session.keyvalue, + rep->enc_part.key.keyvalue.data, + rep->enc_part.key.keyvalue.length); + if (ret) { + krb5_clear_error_message(context); + goto out; + } + + /* + * HACK: + * this is really a ugly hack, to support using the Netbios Domain Name + * as realm against windows KDC's, they always return the full realm + * based on the DNS Name. + */ + flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; + flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + + /* compare client and save */ + ret = _krb5_principalname2krb5_principal (context, + &tmp_principal, + rep->kdc_rep.cname, + rep->kdc_rep.crealm); + if (ret) + goto out; + + /* check client referral and save principal */ + /* anonymous here ? */ + if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { + ret = check_client_referral(context, rep, + creds->client, + tmp_principal, + &creds->session); + if (ret) { + krb5_free_principal (context, tmp_principal); + goto out; + } + } + krb5_free_principal (context, creds->client); + creds->client = tmp_principal; + + /* check server referral and save principal */ + ret = _krb5_principalname2krb5_principal (context, + &tmp_principal, + rep->kdc_rep.ticket.sname, + rep->kdc_rep.ticket.realm); + if (ret) + goto out; + if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ + ret = check_server_referral(context, + rep, + flags, + creds->server, + tmp_principal, + &creds->session); + if (ret) { + krb5_free_principal (context, tmp_principal); + goto out; + } + } + krb5_free_principal(context, creds->server); + creds->server = tmp_principal; + + /* verify names */ + if(flags & EXTRACT_TICKET_MATCH_REALM){ + const char *srealm = krb5_principal_get_realm(context, creds->server); + const char *crealm = krb5_principal_get_realm(context, creds->client); + + if (strcmp(rep->enc_part.srealm, srealm) != 0 || + strcmp(rep->enc_part.srealm, crealm) != 0) + { + ret = KRB5KRB_AP_ERR_MODIFIED; + krb5_clear_error_message(context); + goto out; + } + } + + /* compare nonces */ + + if (nonce != rep->enc_part.nonce) { + ret = KRB5KRB_AP_ERR_MODIFIED; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; + } + + /* set kdc-offset */ + + krb5_timeofday (context, &sec_now); + if (rep->enc_part.flags.initial + && context->kdc_sec_offset == 0 + && krb5_config_get_bool (context, NULL, + "libdefaults", + "kdc_timesync", + NULL)) { + context->kdc_sec_offset = rep->enc_part.authtime - sec_now; + krb5_timeofday (context, &sec_now); + } + + /* check all times */ + + if (rep->enc_part.starttime) { + tmp_time = *rep->enc_part.starttime; + } else + tmp_time = rep->enc_part.authtime; + + if (creds->times.starttime == 0 + && abs(tmp_time - sec_now) > context->max_skew) { + ret = KRB5KRB_AP_ERR_SKEW; + krb5_set_error_message (context, ret, + N_("time skew (%d) larger than max (%d)", ""), + abs(tmp_time - sec_now), + (int)context->max_skew); + goto out; + } + + if (creds->times.starttime != 0 + && tmp_time != creds->times.starttime) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + creds->times.starttime = tmp_time; + + if (rep->enc_part.renew_till) { + tmp_time = *rep->enc_part.renew_till; + } else + tmp_time = 0; + + if (creds->times.renew_till != 0 + && tmp_time > creds->times.renew_till) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + creds->times.renew_till = tmp_time; + + creds->times.authtime = rep->enc_part.authtime; + + if (creds->times.endtime != 0 + && rep->enc_part.endtime > creds->times.endtime) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + creds->times.endtime = rep->enc_part.endtime; + + if(rep->enc_part.caddr) + krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); + else if(addrs) + krb5_copy_addresses (context, addrs, &creds->addresses); + else { + creds->addresses.len = 0; + creds->addresses.val = NULL; + } + creds->flags.b = rep->enc_part.flags; + + creds->authdata.len = 0; + creds->authdata.val = NULL; + + /* extract ticket */ + ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, + &rep->kdc_rep.ticket, &len, ret); + if(ret) + goto out; + if (creds->ticket.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + creds->second_ticket.length = 0; + creds->second_ticket.data = NULL; + + +out: + memset (rep->enc_part.key.keyvalue.data, 0, + rep->enc_part.key.keyvalue.length); + return ret; +} diff --git a/source4/heimdal/lib/krb5/time.c b/source4/heimdal/lib/krb5/time.c index cd786fedde..ed235783a2 100644 --- a/source4/heimdal/lib/krb5/time.c +++ b/source4/heimdal/lib/krb5/time.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Set the absolute time that the caller knows the kdc has so the * kerberos library can calculate the relative diffrence beteen the diff --git a/source4/heimdal/lib/krb5/transited.c b/source4/heimdal/lib/krb5/transited.c index 7e11d5579a..196ef447ee 100644 --- a/source4/heimdal/lib/krb5/transited.c +++ b/source4/heimdal/lib/krb5/transited.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* this is an attempt at one of the most horrible `compression' schemes that has ever been invented; it's so amazingly brain-dead that words can not describe it, and all this just to save a few diff --git a/source4/heimdal/lib/krb5/v4_glue.c b/source4/heimdal/lib/krb5/v4_glue.c index 6911cb20f8..168268ceab 100644 --- a/source4/heimdal/lib/krb5/v4_glue.c +++ b/source4/heimdal/lib/krb5/v4_glue.c @@ -32,7 +32,6 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); #include "krb5-v4compat.h" @@ -217,14 +216,16 @@ write_v4_cc(krb5_context context, const char *tkfile, ret = write(fd, data.data, data.length); if (ret != data.length) ret = KRB5_CC_IO; + else + ret = 0; - krb5_free_data_contents(context, &data); + krb5_data_free(&data); flock(fd, LOCK_UN); free(path); close(fd); - return 0; + return ret; } /* diff --git a/source4/heimdal/lib/krb5/version.c b/source4/heimdal/lib/krb5/version.c index d43b83e26e..a0e750604e 100644 --- a/source4/heimdal/lib/krb5/version.c +++ b/source4/heimdal/lib/krb5/version.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* this is just to get a version stamp in the library file */ #define heimdal_version __heimdal_version diff --git a/source4/heimdal/lib/krb5/warn.c b/source4/heimdal/lib/krb5/warn.c index a00ae80697..58fb73189e 100644 --- a/source4/heimdal/lib/krb5/warn.c +++ b/source4/heimdal/lib/krb5/warn.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <err.h> -RCSID("$Id$"); - static krb5_error_code _warnerr(krb5_context context, int do_errtext, krb5_error_code code, int level, const char *fmt, va_list ap) __attribute__((__format__(__printf__, 5, 0))); @@ -96,6 +94,18 @@ _warnerr(krb5_context context, int do_errtext, #undef __attribute__ #define __attribute__(X) +/** + * Log a warning to the log, default stderr, include the error from + * the last failure. + * + * @param context A Kerberos 5 context. + * @param code error code of the last error + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_vwarn(krb5_context context, krb5_error_code code, const char *fmt, va_list ap) @@ -104,6 +114,16 @@ krb5_vwarn(krb5_context context, krb5_error_code code, return _warnerr(context, 1, code, 1, fmt, ap); } +/** + * Log a warning to the log, default stderr, include the error from + * the last failure. + * + * @param context A Kerberos 5 context. + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ krb5_error_code KRB5_LIB_FUNCTION krb5_warn(krb5_context context, krb5_error_code code, const char *fmt, ...) @@ -113,6 +133,16 @@ krb5_warn(krb5_context context, krb5_error_code code, const char *fmt, ...) return ret; } +/** + * Log a warning to the log, default stderr. + * + * @param context A Kerberos 5 context. + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_vwarnx(krb5_context context, const char *fmt, va_list ap) __attribute__ ((format (printf, 2, 0))) @@ -120,6 +150,15 @@ krb5_vwarnx(krb5_context context, const char *fmt, va_list ap) return _warnerr(context, 0, 0, 1, fmt, ap); } +/** + * Log a warning to the log, default stderr. + * + * @param context A Kerberos 5 context. + * @param fmt message to print + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_warnx(krb5_context context, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) @@ -128,6 +167,19 @@ krb5_warnx(krb5_context context, const char *fmt, ...) return ret; } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param code error code of the last error + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_verr(krb5_context context, int eval, krb5_error_code code, const char *fmt, va_list ap) @@ -137,6 +189,17 @@ krb5_verr(krb5_context context, int eval, krb5_error_code code, exit(eval); } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ krb5_error_code KRB5_LIB_FUNCTION krb5_err(krb5_context context, int eval, krb5_error_code code, @@ -147,6 +210,17 @@ krb5_err(krb5_context context, int eval, krb5_error_code code, exit(eval); } +/** + * Log a warning to the log, default stderr, and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_verrx(krb5_context context, int eval, const char *fmt, va_list ap) __attribute__ ((noreturn, format (printf, 3, 0))) @@ -155,6 +229,16 @@ krb5_verrx(krb5_context context, int eval, const char *fmt, va_list ap) exit(eval); } +/** + * Log a warning to the log, default stderr, and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param fmt message to print + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_errx(krb5_context context, int eval, const char *fmt, ...) __attribute__ ((noreturn, format (printf, 3, 4))) @@ -163,6 +247,18 @@ krb5_errx(krb5_context context, int eval, const char *fmt, ...) exit(eval); } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then abort. + * + * @param context A Kerberos 5 context + * @param code error code of the last error + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_vabort(krb5_context context, krb5_error_code code, const char *fmt, va_list ap) @@ -172,6 +268,16 @@ krb5_vabort(krb5_context context, krb5_error_code code, abort(); } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then abort. + * + * @param context A Kerberos 5 context + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ krb5_error_code KRB5_LIB_FUNCTION krb5_abort(krb5_context context, krb5_error_code code, const char *fmt, ...) @@ -189,6 +295,16 @@ krb5_vabortx(krb5_context context, const char *fmt, va_list ap) abort(); } +/** + * Log a warning to the log, default stderr, and then abort. + * + * @param context A Kerberos 5 context + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_abortx(krb5_context context, const char *fmt, ...) __attribute__ ((noreturn, format (printf, 2, 3))) @@ -197,6 +313,15 @@ krb5_abortx(krb5_context context, const char *fmt, ...) abort(); } +/** + * Set the default logging facility. + * + * @param context A Kerberos 5 context + * @param fac Facility to use for logging. + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac) { @@ -204,6 +329,14 @@ krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac) return 0; } +/** + * Get the default logging facility. + * + * @param context A Kerberos 5 context + * + * @ingroup krb5_error + */ + krb5_log_facility * KRB5_LIB_FUNCTION krb5_get_warn_dest(krb5_context context) { diff --git a/source4/heimdal/lib/ntlm/ntlm.c b/source4/heimdal/lib/ntlm/ntlm.c index 1002b67cc8..1fe456d022 100644 --- a/source4/heimdal/lib/ntlm/ntlm.c +++ b/source4/heimdal/lib/ntlm/ntlm.c @@ -33,8 +33,6 @@ #include <config.h> -RCSID("$Id$"); - #include <stdio.h> #include <stdlib.h> #include <assert.h> @@ -440,7 +438,8 @@ heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data) CHECK(ret_string(in, 0, &hostname, &data->hostname), 0); out: - krb5_storage_free(in); + if (in) + krb5_storage_free(in); if (ret) heim_ntlm_free_type1(data); @@ -589,7 +588,8 @@ heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2) ret = 0; out: - krb5_storage_free(in); + if (in) + krb5_storage_free(in); if (ret) heim_ntlm_free_type2(type2); @@ -748,7 +748,8 @@ heim_ntlm_decode_type3(const struct ntlm_buf *buf, CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0); out: - krb5_storage_free(in); + if (in) + krb5_storage_free(in); if (ret) heim_ntlm_free_type3(type3); @@ -1041,15 +1042,18 @@ heim_ntlm_build_ntlm1_master(void *key, size_t len, * @param target the name of the target, assumed to be in UTF8. * @param ntlmv2 the ntlmv2 session key * + * @return 0 on success, or an error code on failure. + * * @ingroup ntlm_core */ -void +int heim_ntlm_ntlmv2_key(const void *key, size_t len, const char *username, const char *target, unsigned char ntlmv2[16]) { + int ret; unsigned int hmaclen; HMAC_CTX c; @@ -1058,17 +1062,23 @@ heim_ntlm_ntlmv2_key(const void *key, size_t len, { struct ntlm_buf buf; /* uppercase username and turn it into ucs2-le */ - ascii2ucs2le(username, 1, &buf); + ret = ascii2ucs2le(username, 1, &buf); + if (ret) + goto out; HMAC_Update(&c, buf.data, buf.length); free(buf.data); /* uppercase target and turn into ucs2-le */ - ascii2ucs2le(target, 1, &buf); + ret = ascii2ucs2le(target, 1, &buf); + if (ret) + goto out; HMAC_Update(&c, buf.data, buf.length); free(buf.data); } HMAC_Final(&c, ntlmv2, &hmaclen); + out: HMAC_CTX_cleanup(&c); + return ret; } /* diff --git a/source4/heimdal/lib/roken/base64.c b/source4/heimdal/lib/roken/base64.c index d0096447b3..5e720eb6d4 100644 --- a/source4/heimdal/lib/roken/base64.c +++ b/source4/heimdal/lib/roken/base64.c @@ -31,10 +31,8 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif + #include <stdlib.h> #include <string.h> #include "base64.h" @@ -61,8 +59,10 @@ base64_encode(const void *data, int size, char **str) const unsigned char *q; p = s = (char *) malloc(size * 4 / 3 + 4); - if (p == NULL) + if (p == NULL) { + *str = NULL; return -1; + } q = (const unsigned char *) data; for (i = 0; i < size;) { diff --git a/source4/heimdal/lib/roken/bswap.c b/source4/heimdal/lib/roken/bswap.c index a87345be3f..67d240c231 100644 --- a/source4/heimdal/lib/roken/bswap.c +++ b/source4/heimdal/lib/roken/bswap.c @@ -31,13 +31,9 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include "roken.h" -RCSID("$Id$"); - #ifndef HAVE_BSWAP32 unsigned int ROKEN_LIB_FUNCTION diff --git a/source4/heimdal/lib/roken/cloexec.c b/source4/heimdal/lib/roken/cloexec.c index 7a64233309..c015b1d8fa 100644 --- a/source4/heimdal/lib/roken/cloexec.c +++ b/source4/heimdal/lib/roken/cloexec.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <unistd.h> #include <fcntl.h> diff --git a/source4/heimdal/lib/roken/closefrom.c b/source4/heimdal/lib/roken/closefrom.c index 9198c05e26..7aa0ef7372 100644 --- a/source4/heimdal/lib/roken/closefrom.c +++ b/source4/heimdal/lib/roken/closefrom.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> diff --git a/source4/heimdal/lib/roken/copyhostent.c b/source4/heimdal/lib/roken/copyhostent.c index 58f5a112f2..69c1ba40ff 100644 --- a/source4/heimdal/lib/roken/copyhostent.c +++ b/source4/heimdal/lib/roken/copyhostent.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/dumpdata.c b/source4/heimdal/lib/roken/dumpdata.c index 88a86815ef..c5513c323d 100644 --- a/source4/heimdal/lib/roken/dumpdata.c +++ b/source4/heimdal/lib/roken/dumpdata.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <unistd.h> diff --git a/source4/heimdal/lib/roken/ecalloc.c b/source4/heimdal/lib/roken/ecalloc.c index 6c579e99f3..c8e6504030 100644 --- a/source4/heimdal/lib/roken/ecalloc.c +++ b/source4/heimdal/lib/roken/ecalloc.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdlib.h> #include <err.h> diff --git a/source4/heimdal/lib/roken/emalloc.c b/source4/heimdal/lib/roken/emalloc.c index d033e16a07..c937e6d707 100644 --- a/source4/heimdal/lib/roken/emalloc.c +++ b/source4/heimdal/lib/roken/emalloc.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdlib.h> #include <err.h> diff --git a/source4/heimdal/lib/roken/erealloc.c b/source4/heimdal/lib/roken/erealloc.c index 239d6a0eab..f77c8ec733 100644 --- a/source4/heimdal/lib/roken/erealloc.c +++ b/source4/heimdal/lib/roken/erealloc.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdlib.h> #include <err.h> diff --git a/source4/heimdal/lib/roken/estrdup.c b/source4/heimdal/lib/roken/estrdup.c index fb353d0d85..ab7f26550b 100644 --- a/source4/heimdal/lib/roken/estrdup.c +++ b/source4/heimdal/lib/roken/estrdup.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdlib.h> #include <err.h> diff --git a/source4/heimdal/lib/roken/freeaddrinfo.c b/source4/heimdal/lib/roken/freeaddrinfo.c index 1721d20aaf..434e49e888 100644 --- a/source4/heimdal/lib/roken/freeaddrinfo.c +++ b/source4/heimdal/lib/roken/freeaddrinfo.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/freehostent.c b/source4/heimdal/lib/roken/freehostent.c index 38c27d3380..335504300a 100644 --- a/source4/heimdal/lib/roken/freehostent.c +++ b/source4/heimdal/lib/roken/freehostent.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/gai_strerror.c b/source4/heimdal/lib/roken/gai_strerror.c index 084900a58a..10beac05ea 100644 --- a/source4/heimdal/lib/roken/gai_strerror.c +++ b/source4/heimdal/lib/roken/gai_strerror.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/get_window_size.c b/source4/heimdal/lib/roken/get_window_size.c index 9b200c1159..60fb1764fa 100644 --- a/source4/heimdal/lib/roken/get_window_size.c +++ b/source4/heimdal/lib/roken/get_window_size.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdlib.h> #ifdef HAVE_UNISTD_H diff --git a/source4/heimdal/lib/roken/getaddrinfo.c b/source4/heimdal/lib/roken/getaddrinfo.c index a8fc029c32..8c61299763 100644 --- a/source4/heimdal/lib/roken/getaddrinfo.c +++ b/source4/heimdal/lib/roken/getaddrinfo.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/getarg.c b/source4/heimdal/lib/roken/getarg.c index 3168ccc53d..60b0f645af 100644 --- a/source4/heimdal/lib/roken/getarg.c +++ b/source4/heimdal/lib/roken/getarg.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdio.h> #include <stdlib.h> diff --git a/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c b/source4/heimdal/lib/roken/getdtablesize.c index 0dedbefd2c..a515af3454 100644 --- a/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c +++ b/source4/heimdal/lib/roken/getdtablesize.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -31,69 +31,69 @@ * SUCH DAMAGE. */ -#include "krb5_locl.h" +#include <config.h> -RCSID("$Id$"); +#include "roken.h" -krb5_error_code KRB5_LIB_FUNCTION -krb5_keytab_key_proc (krb5_context context, - krb5_enctype enctype, - krb5_salt salt, - krb5_const_pointer keyseed, - krb5_keyblock **key) -{ - krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); - krb5_keytab keytab = args->keytab; - krb5_principal principal = args->principal; - krb5_error_code ret; - krb5_keytab real_keytab; - krb5_keytab_entry entry; +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#elif defined(HAVE_SYS_TIME_H) +#include <sys/time.h> +#else +#include <time.h> +#endif +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif - if(keytab == NULL) - krb5_kt_default(context, &real_keytab); - else - real_keytab = keytab; +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif - ret = krb5_kt_get_entry (context, real_keytab, principal, - 0, enctype, &entry); +#ifdef HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif - if (keytab == NULL) - krb5_kt_close (context, real_keytab); +int ROKEN_LIB_FUNCTION +getdtablesize(void) +{ + int files = -1; +#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) + files = sysconf(_SC_OPEN_MAX); +#else /* !defined(HAVE_SYSCONF) */ +#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) + struct rlimit res; + if (getrlimit(RLIMIT_NOFILE, &res) == 0) + files = res.rlim_cur; +#else /* !definded(HAVE_GETRLIMIT) */ +#if defined(HAVE_SYSCTL) && defined(CTL_KERN) && defined(KERN_MAXFILES) + int mib[2]; + size_t len; - if (ret) - return ret; + mib[0] = CTL_KERN; + mib[1] = KERN_MAXFILES; + len = sizeof(files); + sysctl(&mib, 2, &files, sizeof(files), NULL, 0); +#endif /* defined(HAVE_SYSCTL) */ +#endif /* !definded(HAVE_GETRLIMIT) */ +#endif /* !defined(HAVE_SYSCONF) */ - ret = krb5_copy_keyblock (context, &entry.keyblock, key); - krb5_kt_free_entry(context, &entry); - return ret; -} - -krb5_error_code KRB5_LIB_FUNCTION -krb5_get_in_tkt_with_keytab (krb5_context context, - krb5_flags options, - krb5_addresses *addrs, - const krb5_enctype *etypes, - const krb5_preauthtype *pre_auth_types, - krb5_keytab keytab, - krb5_ccache ccache, - krb5_creds *creds, - krb5_kdc_rep *ret_as_reply) -{ - krb5_keytab_key_proc_args a; +#ifdef OPEN_MAX + if (files < 0) + files = OPEN_MAX; +#endif - a.principal = creds->client; - a.keytab = keytab; +#ifdef NOFILE + if (files < 0) + files = NOFILE; +#endif - return krb5_get_in_tkt (context, - options, - addrs, - etypes, - pre_auth_types, - krb5_keytab_key_proc, - &a, - NULL, - NULL, - creds, - ccache, - ret_as_reply); + return files; } diff --git a/source4/heimdal/lib/roken/getipnodebyaddr.c b/source4/heimdal/lib/roken/getipnodebyaddr.c index e3c2b50e32..ddaec03a89 100644 --- a/source4/heimdal/lib/roken/getipnodebyaddr.c +++ b/source4/heimdal/lib/roken/getipnodebyaddr.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/getipnodebyname.c b/source4/heimdal/lib/roken/getipnodebyname.c index ec578937b7..16fdbdd24a 100644 --- a/source4/heimdal/lib/roken/getipnodebyname.c +++ b/source4/heimdal/lib/roken/getipnodebyname.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/getnameinfo.c b/source4/heimdal/lib/roken/getnameinfo.c index 865cc09dc8..0621cfeee1 100644 --- a/source4/heimdal/lib/roken/getnameinfo.c +++ b/source4/heimdal/lib/roken/getnameinfo.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/getprogname.c b/source4/heimdal/lib/roken/getprogname.c index b01a3d7e45..933b6dec79 100644 --- a/source4/heimdal/lib/roken/getprogname.c +++ b/source4/heimdal/lib/roken/getprogname.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/h_errno.c b/source4/heimdal/lib/roken/h_errno.c index 0cee02d472..7e49f8008f 100644 --- a/source4/heimdal/lib/roken/h_errno.c +++ b/source4/heimdal/lib/roken/h_errno.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #ifndef HAVE_H_ERRNO int h_errno = -17; /* Some magic number */ diff --git a/source4/heimdal/lib/roken/hex.c b/source4/heimdal/lib/roken/hex.c index 2167172f9f..95488af5c7 100644 --- a/source4/heimdal/lib/roken/hex.c +++ b/source4/heimdal/lib/roken/hex.c @@ -31,10 +31,8 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H + #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" #include <ctype.h> #include "hex.h" @@ -60,12 +58,16 @@ hex_encode(const void *data, size_t size, char **str) char *p; /* check for overflow */ - if (size * 2 < size) + if (size * 2 < size) { + *str = NULL; return -1; + } p = malloc(size * 2 + 1); - if (p == NULL) + if (p == NULL) { + *str = NULL; return -1; + } for (i = 0; i < size; i++) { p[i * 2] = hexchar[(*q >> 4) & 0xf]; diff --git a/source4/heimdal/lib/roken/hostent_find_fqdn.c b/source4/heimdal/lib/roken/hostent_find_fqdn.c index 9376c1da36..b5f2b42f60 100644 --- a/source4/heimdal/lib/roken/hostent_find_fqdn.c +++ b/source4/heimdal/lib/roken/hostent_find_fqdn.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/inet_aton.c b/source4/heimdal/lib/roken/inet_aton.c index c42697c63c..c9b21e00f8 100644 --- a/source4/heimdal/lib/roken/inet_aton.c +++ b/source4/heimdal/lib/roken/inet_aton.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/inet_ntop.c b/source4/heimdal/lib/roken/inet_ntop.c index 5e4e4f9dc7..daf3e926dd 100644 --- a/source4/heimdal/lib/roken/inet_ntop.c +++ b/source4/heimdal/lib/roken/inet_ntop.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/inet_pton.c b/source4/heimdal/lib/roken/inet_pton.c index f2a9af3aa3..ad60824f4a 100644 --- a/source4/heimdal/lib/roken/inet_pton.c +++ b/source4/heimdal/lib/roken/inet_pton.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/issuid.c b/source4/heimdal/lib/roken/issuid.c index 257481cffb..2999e8249c 100644 --- a/source4/heimdal/lib/roken/issuid.c +++ b/source4/heimdal/lib/roken/issuid.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/net_read.c b/source4/heimdal/lib/roken/net_read.c index ae025ffc71..9d055d0068 100644 --- a/source4/heimdal/lib/roken/net_read.c +++ b/source4/heimdal/lib/roken/net_read.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <sys/types.h> #include <unistd.h> diff --git a/source4/heimdal/lib/roken/net_write.c b/source4/heimdal/lib/roken/net_write.c index 11f5b8d7be..515f210973 100644 --- a/source4/heimdal/lib/roken/net_write.c +++ b/source4/heimdal/lib/roken/net_write.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <sys/types.h> #include <unistd.h> diff --git a/source4/heimdal/lib/roken/parse_time.c b/source4/heimdal/lib/roken/parse_time.c index 6065eeb425..b581970bd7 100644 --- a/source4/heimdal/lib/roken/parse_time.c +++ b/source4/heimdal/lib/roken/parse_time.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <parse_units.h> #include "parse_time.h" diff --git a/source4/heimdal/lib/roken/parse_units.c b/source4/heimdal/lib/roken/parse_units.c index 4dbd7b489b..a848298c57 100644 --- a/source4/heimdal/lib/roken/parse_units.c +++ b/source4/heimdal/lib/roken/parse_units.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdio.h> #include <ctype.h> diff --git a/source4/heimdal/lib/roken/resolve.c b/source4/heimdal/lib/roken/resolve.c index f358a5b266..a74e438cf8 100644 --- a/source4/heimdal/lib/roken/resolve.c +++ b/source4/heimdal/lib/roken/resolve.c @@ -31,9 +31,9 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H + #include <config.h> -#endif + #include "roken.h" #ifdef HAVE_ARPA_NAMESER_H #include <arpa/nameser.h> @@ -41,6 +41,9 @@ #ifdef HAVE_RESOLV_H #include <resolv.h> #endif +#ifdef HAVE_DNS_H +#include <dns.h> +#endif #include "resolve.h" #include <assert.h> @@ -78,7 +81,7 @@ static struct stot{ int _resolve_debug = 0; int ROKEN_LIB_FUNCTION -dns_string_to_type(const char *name) +rk_dns_string_to_type(const char *name) { struct stot *p = stot; for(p = stot; p->name; p++) @@ -88,7 +91,7 @@ dns_string_to_type(const char *name) } const char * ROKEN_LIB_FUNCTION -dns_type_to_string(int type) +rk_dns_type_to_string(int type) { struct stot *p = stot; for(p = stot; p->name; p++) @@ -100,7 +103,7 @@ dns_type_to_string(int type) #if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND) static void -dns_free_rr(struct resource_record *rr) +dns_free_rr(struct rk_resource_record *rr) { if(rr->domain) free(rr->domain); @@ -110,13 +113,13 @@ dns_free_rr(struct resource_record *rr) } void ROKEN_LIB_FUNCTION -dns_free_data(struct dns_reply *r) +rk_dns_free_data(struct rk_dns_reply *r) { - struct resource_record *rr; + struct rk_resource_record *rr; if(r->q.domain) free(r->q.domain); for(rr = r->head; rr;){ - struct resource_record *tmp = rr; + struct rk_resource_record *tmp = rr; rr = rr->next; dns_free_rr(tmp); } @@ -125,9 +128,9 @@ dns_free_data(struct dns_reply *r) static int parse_record(const unsigned char *data, const unsigned char *end_data, - const unsigned char **pp, struct resource_record **ret_rr) + const unsigned char **pp, struct rk_resource_record **ret_rr) { - struct resource_record *rr; + struct rk_resource_record *rr; int type, class, ttl; unsigned size; int status; @@ -401,7 +404,7 @@ parse_record(const unsigned char *data, const unsigned char *end_data, #ifndef TEST_RESOLVE static #endif -struct dns_reply* +struct rk_dns_reply* parse_reply(const unsigned char *data, size_t len) { const unsigned char *p; @@ -409,8 +412,8 @@ parse_reply(const unsigned char *data, size_t len) int i; char host[MAXDNAME]; const unsigned char *end_data = data + len; - struct dns_reply *r; - struct resource_record **rr; + struct rk_dns_reply *r; + struct rk_resource_record **rr; r = calloc(1, sizeof(*r)); if (r == NULL) @@ -449,16 +452,16 @@ parse_reply(const unsigned char *data, size_t len) } status = dn_expand(data, end_data, p, host, sizeof(host)); if(status < 0){ - dns_free_data(r); + rk_dns_free_data(r); return NULL; } r->q.domain = strdup(host); if(r->q.domain == NULL) { - dns_free_data(r); + rk_dns_free_data(r); return NULL; } if (p + status + 4 > end_data) { - dns_free_data(r); + rk_dns_free_data(r); return NULL; } p += status; @@ -470,21 +473,21 @@ parse_reply(const unsigned char *data, size_t len) rr = &r->head; for(i = 0; i < r->h.ancount; i++) { if(parse_record(data, end_data, &p, rr) != 0) { - dns_free_data(r); + rk_dns_free_data(r); return NULL; } rr = &(*rr)->next; } for(i = 0; i < r->h.nscount; i++) { if(parse_record(data, end_data, &p, rr) != 0) { - dns_free_data(r); + rk_dns_free_data(r); return NULL; } rr = &(*rr)->next; } for(i = 0; i < r->h.arcount; i++) { if(parse_record(data, end_data, &p, rr) != 0) { - dns_free_data(r); + rk_dns_free_data(r); return NULL; } rr = &(*rr)->next; @@ -501,20 +504,42 @@ parse_reply(const unsigned char *data, size_t len) #endif #endif -static struct dns_reply * +#if defined(HAVE_DNS_SEARCH) +#define resolve_search(h,n,c,t,r,l) \ + ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize)) +#define resolve_free_handle(h) dns_free(h) +#elif defined(HAVE_RES_NSEARCH) +#define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l) +#define resolve_free_handle(h) rk_res_free(h); +#else +#define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l) +#define handle 0 +#define resolve_free_handle(h) +#endif + + +static struct rk_dns_reply * dns_lookup_int(const char *domain, int rr_class, int rr_type) { - struct dns_reply *r; - unsigned char *reply = NULL; + struct rk_dns_reply *r; + void *reply = NULL; int size; int len; -#ifdef HAVE_RES_NSEARCH +#if defined(HAVE_DNS_SEARCH) + struct sockaddr_storage from; + uint32_t fromsize = sizeof(from); + dns_handle_t handle; + + handle = dns_open(NULL); + if (handle == NULL) + return NULL; +#elif defined(HAVE_RES_NSEARCH) struct __res_state state; + struct __res_state *handle = &state; + memset(&state, 0, sizeof(state)); - if(res_ninit(&state)) + if(res_ninit(handle)) return NULL; /* is this the best we can do? */ -#elif defined(HAVE__RES) - u_long old_options = 0; #endif size = 0; @@ -527,45 +552,33 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type) if (size <= len) size = len; if (_resolve_debug) { -#ifdef HAVE_RES_NSEARCH +#if defined(HAVE_DNS_SEARCH) + dns_set_debug(handle, 1); +#elif defined(HAVE_RES_NSEARCH) state.options |= RES_DEBUG; -#elif defined(HAVE__RES) - old_options = _res.options; - _res.options |= RES_DEBUG; #endif fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain, - rr_class, dns_type_to_string(rr_type), size); + rr_class, rk_dns_type_to_string(rr_type), size); } reply = malloc(size); if (reply == NULL) { -#ifdef HAVE_RES_NSEARCH - rk_res_free(&state); -#endif + resolve_free_handle(handle); return NULL; } -#ifdef HAVE_RES_NSEARCH - len = res_nsearch(&state, domain, rr_class, rr_type, reply, size); -#else - len = res_search(domain, rr_class, rr_type, reply, size); -#endif + + len = resolve_search(handle, domain, rr_class, rr_type, reply, size); + if (_resolve_debug) { -#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH) - _res.options = old_options; -#endif fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", - domain, rr_class, dns_type_to_string(rr_type), len); + domain, rr_class, rk_dns_type_to_string(rr_type), len); } - if (len < 0) { -#ifdef HAVE_RES_NSEARCH - rk_res_free(&state); -#endif + if (len <= 0) { + resolve_free_handle(handle); free(reply); return NULL; } } while (size < len && len < rk_DNS_MAX_PACKET_SIZE); -#ifdef HAVE_RES_NSEARCH - rk_res_free(&state); -#endif + resolve_free_handle(handle); len = min(len, size); r = parse_reply(reply, len); @@ -573,25 +586,25 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type) return r; } -struct dns_reply * ROKEN_LIB_FUNCTION -dns_lookup(const char *domain, const char *type_name) +struct rk_dns_reply * ROKEN_LIB_FUNCTION +rk_dns_lookup(const char *domain, const char *type_name) { int type; - type = dns_string_to_type(type_name); + type = rk_dns_string_to_type(type_name); if(type == -1) { if(_resolve_debug) fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", type_name); return NULL; } - return dns_lookup_int(domain, C_IN, type); + return dns_lookup_int(domain, rk_ns_c_in, type); } static int compare_srv(const void *a, const void *b) { - const struct resource_record *const* aa = a, *const* bb = b; + const struct rk_resource_record *const* aa = a, *const* bb = b; if((*aa)->u.srv->priority == (*bb)->u.srv->priority) return ((*aa)->u.srv->weight - (*bb)->u.srv->weight); @@ -604,10 +617,10 @@ compare_srv(const void *a, const void *b) /* try to rearrange the srv-records by the algorithm in RFC2782 */ void ROKEN_LIB_FUNCTION -dns_srv_order(struct dns_reply *r) +rk_dns_srv_order(struct rk_dns_reply *r) { - struct resource_record **srvs, **ss, **headp; - struct resource_record *rr; + struct rk_resource_record **srvs, **ss, **headp; + struct rk_resource_record *rr; int num_srv = 0; #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) @@ -648,7 +661,7 @@ dns_srv_order(struct dns_reply *r) for(ss = srvs; ss < srvs + num_srv; ) { int sum, rnd, count; - struct resource_record **ee, **tt; + struct rk_resource_record **ee, **tt; /* find the last record with the same priority and count the sum of all weights */ for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) { @@ -693,19 +706,19 @@ dns_srv_order(struct dns_reply *r) #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ -struct dns_reply * ROKEN_LIB_FUNCTION -dns_lookup(const char *domain, const char *type_name) +struct rk_dns_reply * ROKEN_LIB_FUNCTION +rk_dns_lookup(const char *domain, const char *type_name) { return NULL; } void ROKEN_LIB_FUNCTION -dns_free_data(struct dns_reply *r) +rk_dns_free_data(struct rk_dns_reply *r) { } void ROKEN_LIB_FUNCTION -dns_srv_order(struct dns_reply *r) +rk_dns_srv_order(struct rk_dns_reply *r) { } diff --git a/source4/heimdal/lib/roken/resolve.h b/source4/heimdal/lib/roken/resolve.h index d181dfa070..91b2afefe7 100644 --- a/source4/heimdal/lib/roken/resolve.h +++ b/source4/heimdal/lib/roken/resolve.h @@ -44,7 +44,11 @@ #endif #endif -typedef enum { +enum { + rk_ns_c_in = 1 +}; + +enum { rk_ns_t_invalid = 0, /* Cookie. */ rk_ns_t_a = 1, /* Host address. */ rk_ns_t_ns = 2, /* Authoritative server. */ @@ -99,99 +103,38 @@ typedef enum { rk_ns_t_any = 255, /* Wildcard match. */ rk_ns_t_zxfr = 256, /* BIND-specific, nonstandard. */ rk_ns_t_max = 65536 -} rk_ns_type; - -/* We use these, but they are not always present in <arpa/nameser.h> */ - -#ifndef C_IN -#define C_IN 1 -#endif - -#ifndef T_A -#define T_A 1 -#endif -#ifndef T_NS -#define T_NS 2 -#endif -#ifndef T_CNAME -#define T_CNAME 5 -#endif -#ifndef T_SOA -#define T_SOA 5 -#endif -#ifndef T_PTR -#define T_PTR 12 -#endif -#ifndef T_MX -#define T_MX 15 -#endif -#ifndef T_TXT -#define T_TXT 16 -#endif -#ifndef T_AFSDB -#define T_AFSDB 18 -#endif -#ifndef T_SIG -#define T_SIG 24 -#endif -#ifndef T_KEY -#define T_KEY 25 -#endif -#ifndef T_AAAA -#define T_AAAA 28 -#endif -#ifndef T_SRV -#define T_SRV 33 -#endif -#ifndef T_NAPTR -#define T_NAPTR 35 -#endif -#ifndef T_CERT -#define T_CERT 37 -#endif -#ifndef T_SSHFP -#define T_SSHFP 44 -#endif +}; #ifndef MAXDNAME #define MAXDNAME 1025 #endif -#define dns_query rk_dns_query #define mx_record rk_mx_record #define srv_record rk_srv_record #define key_record rk_key_record #define sig_record rk_sig_record #define cert_record rk_cert_record #define sshfp_record rk_sshfp_record -#define resource_record rk_resource_record -#define dns_reply rk_dns_reply - -#define dns_lookup rk_dns_lookup -#define dns_free_data rk_dns_free_data -#define dns_string_to_type rk_dns_string_to_type -#define dns_type_to_string rk_dns_type_to_string -#define dns_srv_order rk_dns_srv_order -struct dns_query{ +struct rk_dns_query{ char *domain; unsigned type; unsigned class; }; -struct mx_record{ +struct rk_mx_record{ unsigned preference; char domain[1]; }; -struct srv_record{ +struct rk_srv_record{ unsigned priority; unsigned weight; unsigned port; char target[1]; }; -struct key_record { +struct rk_key_record { unsigned flags; unsigned protocol; unsigned algorithm; @@ -199,7 +142,7 @@ struct key_record { u_char key_data[1]; }; -struct sig_record { +struct rk_sig_record { unsigned type; unsigned algorithm; unsigned labels; @@ -212,7 +155,7 @@ struct sig_record { char sig_data[1]; /* also includes signer */ }; -struct cert_record { +struct rk_cert_record { unsigned type; unsigned tag; unsigned algorithm; @@ -220,14 +163,14 @@ struct cert_record { u_char cert_data[1]; }; -struct sshfp_record { +struct rk_sshfp_record { unsigned algorithm; unsigned type; size_t sshfp_len; u_char sshfp_data[1]; }; -struct ds_record { +struct rk_ds_record { unsigned key_tag; unsigned algorithm; unsigned digest_type; @@ -235,7 +178,7 @@ struct ds_record { u_char digest_data[1]; }; -struct resource_record{ +struct rk_resource_record{ char *domain; unsigned type; unsigned class; @@ -243,23 +186,23 @@ struct resource_record{ unsigned size; union { void *data; - struct mx_record *mx; - struct mx_record *afsdb; /* mx and afsdb are identical */ - struct srv_record *srv; + struct rk_mx_record *mx; + struct rk_mx_record *afsdb; /* mx and afsdb are identical */ + struct rk_srv_record *srv; struct in_addr *a; char *txt; - struct key_record *key; - struct cert_record *cert; - struct sig_record *sig; - struct sshfp_record *sshfp; - struct ds_record *ds; + struct rk_key_record *key; + struct rk_cert_record *cert; + struct rk_sig_record *sig; + struct rk_sshfp_record *sshfp; + struct rk_ds_record *ds; }u; - struct resource_record *next; + struct rk_resource_record *next; }; #define rk_DNS_MAX_PACKET_SIZE 0xffff -struct dns_header { +struct rk_dns_header { unsigned id; unsigned flags; #define rk_DNS_HEADER_RESPONSE_FLAG 1 @@ -277,22 +220,30 @@ struct dns_header { unsigned arcount; }; -struct dns_reply{ - struct dns_header h; - struct dns_query q; - struct resource_record *head; +struct rk_dns_reply{ + struct rk_dns_header h; + struct rk_dns_query q; + struct rk_resource_record *head; }; -struct dns_reply* ROKEN_LIB_FUNCTION - dns_lookup(const char *, const char *); +#ifdef __cplusplus +extern "C" { +#endif + +struct rk_dns_reply* ROKEN_LIB_FUNCTION + rk_dns_lookup(const char *, const char *); void ROKEN_LIB_FUNCTION - dns_free_data(struct dns_reply *); + rk_dns_free_data(struct rk_dns_reply *); int ROKEN_LIB_FUNCTION - dns_string_to_type(const char *name); + rk_dns_string_to_type(const char *name); const char *ROKEN_LIB_FUNCTION - dns_type_to_string(int type); + rk_dns_type_to_string(int type); void ROKEN_LIB_FUNCTION - dns_srv_order(struct dns_reply*); + rk_dns_srv_order(struct rk_dns_reply*); + +#ifdef __cplusplus +} +#endif #endif /* __RESOLVE_H__ */ diff --git a/source4/heimdal/lib/roken/rkpty.c b/source4/heimdal/lib/roken/rkpty.c index ebc3a5d208..bff632f0f1 100644 --- a/source4/heimdal/lib/roken/rkpty.c +++ b/source4/heimdal/lib/roken/rkpty.c @@ -52,6 +52,10 @@ #include <libutil.h> #endif +#ifdef STREAMSPTY +#include <stropts.h> +#endif /* STREAMPTY */ + #include "roken.h" #include <getarg.h> @@ -93,6 +97,39 @@ open_pty(void) if(openpty(&master, &slave, line, 0, 0) == 0) return; #endif /* HAVE_OPENPTY .... */ +#ifdef STREAMSPTY + { + char *clone[] = { + "/dev/ptc", + "/dev/ptmx", + "/dev/ptm", + "/dev/ptym/clone", + NULL + }; + char **q; + + for(q = clone; *q; q++){ + master = open(*q, O_RDWR); + if(master >= 0){ +#ifdef HAVE_GRANTPT + grantpt(master); +#endif +#ifdef HAVE_UNLOCKPT + unlockpt(master); +#endif + strlcpy(line, ptsname(master), sizeof(line)); + slave = open(line, O_RDWR); + if (slave < 0) + errx(1, "failed to open slave when using %s", q); + ioctl(slave, I_PUSH, "ptem"); + ioctl(slave, I_PUSH, "ldterm"); + + return; + } + } + } +#endif /* STREAMSPTY */ + /* more cases, like open /dev/ptmx, etc */ exit(77); @@ -302,7 +339,6 @@ main(int argc, char **argv) parse_configuration(argv[0]); argv += 1; - argc -= 1; open_pty(); diff --git a/source4/heimdal/lib/roken/roken-common.h b/source4/heimdal/lib/roken/roken-common.h index 1d341258fe..1713b6609e 100644 --- a/source4/heimdal/lib/roken/roken-common.h +++ b/source4/heimdal/lib/roken/roken-common.h @@ -267,119 +267,154 @@ SigAction signal(int iSig, SigAction pAction); /* BSD compatible */ #endif #endif +#define simple_execve rk_simple_execve int ROKEN_LIB_FUNCTION simple_execve(const char*, char*const[], char*const[]); +#define simple_execve_timed rk_simple_execve_timed int ROKEN_LIB_FUNCTION simple_execve_timed(const char *, char *const[], char *const [], time_t (*)(void *), void *, time_t); + +#define simple_execvp rk_simple_execvp int ROKEN_LIB_FUNCTION simple_execvp(const char*, char *const[]); +#define simple_execvp_timed rk_simple_execvp_timed int ROKEN_LIB_FUNCTION simple_execvp_timed(const char *, char *const[], time_t (*)(void *), void *, time_t); + +#define simple_execlp rk_simple_execlp int ROKEN_LIB_FUNCTION simple_execlp(const char*, ...); +#define simple_execle rk_simple_execle int ROKEN_LIB_FUNCTION simple_execle(const char*, ...); -int ROKEN_LIB_FUNCTION -simple_execl(const char *file, ...); - +#define wait_for_process rk_wait_for_process int ROKEN_LIB_FUNCTION wait_for_process(pid_t); +#define wait_for_process_timed rk_wait_for_process_timed int ROKEN_LIB_FUNCTION wait_for_process_timed(pid_t, time_t (*)(void *), void *, time_t); +#define pipe_execv rk_pipe_execv int ROKEN_LIB_FUNCTION pipe_execv(FILE**, FILE**, FILE**, const char*, ...); +#define print_version rk_print_version void ROKEN_LIB_FUNCTION print_version(const char *); +#define eread rk_eread ssize_t ROKEN_LIB_FUNCTION eread (int fd, void *buf, size_t nbytes); +#define ewrite rk_ewrite ssize_t ROKEN_LIB_FUNCTION ewrite (int fd, const void *buf, size_t nbytes); struct hostent; +#define hostent_find_fqdn rk_hostent_find_fqdn const char * ROKEN_LIB_FUNCTION hostent_find_fqdn (const struct hostent *); +#define esetenv rk_esetenv void ROKEN_LIB_FUNCTION esetenv(const char *, const char *, int); +#define socket_set_address_and_port rk_socket_set_address_and_port void ROKEN_LIB_FUNCTION socket_set_address_and_port (struct sockaddr *, const void *, int); +#define socket_addr_size rk_socket_addr_size size_t ROKEN_LIB_FUNCTION socket_addr_size (const struct sockaddr *); +#define socket_set_any rk_socket_set_any void ROKEN_LIB_FUNCTION socket_set_any (struct sockaddr *, int); +#define socket_sockaddr_size rk_socket_sockaddr_size size_t ROKEN_LIB_FUNCTION socket_sockaddr_size (const struct sockaddr *); +#define socket_get_address rk_socket_get_address void * ROKEN_LIB_FUNCTION -socket_get_address (struct sockaddr *); +socket_get_address (const struct sockaddr *); +#define socket_get_port rk_socket_get_port int ROKEN_LIB_FUNCTION socket_get_port (const struct sockaddr *); +#define socket_set_port rk_socket_set_port void ROKEN_LIB_FUNCTION socket_set_port (struct sockaddr *, int); +#define socket_set_portrange rk_socket_set_portrange void ROKEN_LIB_FUNCTION socket_set_portrange (int, int, int); +#define socket_set_debug rk_socket_set_debug void ROKEN_LIB_FUNCTION socket_set_debug (int); +#define socket_set_tos rk_socket_set_tos void ROKEN_LIB_FUNCTION socket_set_tos (int, int); +#define socket_set_reuseaddr rk_socket_set_reuseaddr void ROKEN_LIB_FUNCTION socket_set_reuseaddr (int, int); +#define socket_set_ipv6only rk_socket_set_ipv6only void ROKEN_LIB_FUNCTION socket_set_ipv6only (int, int); +#define vstrcollect rk_vstrcollect char ** ROKEN_LIB_FUNCTION vstrcollect(va_list *ap); +#define strcollect rk_strcollect char ** ROKEN_LIB_FUNCTION strcollect(char *first, ...); +#define timevalfix rk_timevalfix void ROKEN_LIB_FUNCTION timevalfix(struct timeval *t1); +#define timevaladd rk_timevaladd void ROKEN_LIB_FUNCTION timevaladd(struct timeval *t1, const struct timeval *t2); +#define timevalsub rk_timevalsub void ROKEN_LIB_FUNCTION timevalsub(struct timeval *t1, const struct timeval *t2); +#define pid_file_write rk_pid_file_write char *ROKEN_LIB_FUNCTION pid_file_write (const char *progname); +#define pid_file_delete rk_pid_file_delete void ROKEN_LIB_FUNCTION pid_file_delete (char **); +#define read_environment rk_read_environment int ROKEN_LIB_FUNCTION read_environment(const char *file, char ***env); +#define free_environment rk_free_environment void ROKEN_LIB_FUNCTION free_environment(char **); +#define warnerr rk_warnerr void ROKEN_LIB_FUNCTION -warnerr(int doerrno, const char *fmt, va_list ap) +rk_warnerr(int doerrno, const char *fmt, va_list ap) __attribute__ ((format (printf, 2, 0))); void * ROKEN_LIB_FUNCTION diff --git a/source4/heimdal/lib/roken/roken.h.in b/source4/heimdal/lib/roken/roken.h.in index d71bee7b46..3fce136875 100644 --- a/source4/heimdal/lib/roken/roken.h.in +++ b/source4/heimdal/lib/roken/roken.h.in @@ -125,9 +125,6 @@ struct sockaddr_dl; #else #include <time.h> #endif -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif #ifdef HAVE_PATHS_H #include <paths.h> @@ -152,82 +149,125 @@ ROKEN_CPP_START #endif #ifndef HAVE_PUTENV +#define putenv rk_putenv int ROKEN_LIB_FUNCTION putenv(const char *); #endif #if !defined(HAVE_SETENV) || defined(NEED_SETENV_PROTO) +#ifndef HAVE_SETENV +#define setenv rk_setenv +#endif int ROKEN_LIB_FUNCTION setenv(const char *, const char *, int); #endif #if !defined(HAVE_UNSETENV) || defined(NEED_UNSETENV_PROTO) +#ifndef HAVE_UNSETENV +#define unsetenv rk_unsetenv +#endif void ROKEN_LIB_FUNCTION unsetenv(const char *); #endif #if !defined(HAVE_GETUSERSHELL) || defined(NEED_GETUSERSHELL_PROTO) +#ifndef HAVE_GETUSERSHELL +#define getusershell rk_getusershell +#define endusershell rk_endusershell +#endif char * ROKEN_LIB_FUNCTION getusershell(void); void ROKEN_LIB_FUNCTION endusershell(void); #endif #if !defined(HAVE_SNPRINTF) || defined(NEED_SNPRINTF_PROTO) -int ROKEN_LIB_FUNCTION snprintf (char *, size_t, const char *, ...) +#ifndef HAVE_SNPRINTF +#define snprintf rk_snprintf +#endif +int ROKEN_LIB_FUNCTION + rk_snprintf (char *, size_t, const char *, ...) __attribute__ ((format (printf, 3, 4))); #endif #if !defined(HAVE_VSNPRINTF) || defined(NEED_VSNPRINTF_PROTO) +#ifndef HAVE_VSNPRINTF +#define vsnprintf rk_vsnprintf +#endif int ROKEN_LIB_FUNCTION - vsnprintf (char *, size_t, const char *, va_list) + rk_vsnprintf (char *, size_t, const char *, va_list) __attribute__((format (printf, 3, 0))); #endif #if !defined(HAVE_ASPRINTF) || defined(NEED_ASPRINTF_PROTO) +#ifndef HAVE_ASPRINTF +#define asprintf rk_asprintf +#endif int ROKEN_LIB_FUNCTION - asprintf (char **, const char *, ...) + rk_asprintf (char **, const char *, ...) __attribute__ ((format (printf, 2, 3))); #endif #if !defined(HAVE_VASPRINTF) || defined(NEED_VASPRINTF_PROTO) +#ifndef HAVE_VASPRINTF +#define vasprintf rk_vasprintf +#endif int ROKEN_LIB_FUNCTION - vasprintf (char **, const char *, va_list) + rk_vasprintf (char **, const char *, va_list) __attribute__((format (printf, 2, 0))); #endif #if !defined(HAVE_ASNPRINTF) || defined(NEED_ASNPRINTF_PROTO) +#ifndef HAVE_ASNPRINTF +#define asnprintf rk_asnprintf +#endif int ROKEN_LIB_FUNCTION - asnprintf (char **, size_t, const char *, ...) + rk_asnprintf (char **, size_t, const char *, ...) __attribute__ ((format (printf, 3, 4))); #endif #if !defined(HAVE_VASNPRINTF) || defined(NEED_VASNPRINTF_PROTO) +#ifndef HAVE_VASNPRINTF +#define vasnprintf rk_vasnprintf +#endif int ROKEN_LIB_FUNCTION vasnprintf (char **, size_t, const char *, va_list) __attribute__((format (printf, 3, 0))); #endif #ifndef HAVE_STRDUP +#define strdup rk_strdup char * ROKEN_LIB_FUNCTION strdup(const char *); #endif #if !defined(HAVE_STRNDUP) || defined(NEED_STRNDUP_PROTO) +#ifndef HAVE_STRNDUP +#define strndup rk_strndup +#endif char * ROKEN_LIB_FUNCTION strndup(const char *, size_t); #endif #ifndef HAVE_STRLWR +#define strlwr rk_strlwr char * ROKEN_LIB_FUNCTION strlwr(char *); #endif #ifndef HAVE_STRNLEN +#define strnlen rk_strnlen size_t ROKEN_LIB_FUNCTION strnlen(const char*, size_t); #endif #if !defined(HAVE_STRSEP) || defined(NEED_STRSEP_PROTO) +#ifndef HAVE_STRSEP +#define strsep rk_strsep +#endif char * ROKEN_LIB_FUNCTION strsep(char**, const char*); #endif #if !defined(HAVE_STRSEP_COPY) || defined(NEED_STRSEP_COPY_PROTO) +#ifndef HAVE_STRSEP_COPY +#define strsep_copy rk_strsep_copy +#endif ssize_t ROKEN_LIB_FUNCTION strsep_copy(const char**, const char*, char*, size_t); #endif #ifndef HAVE_STRCASECMP +#define strcasecmp rk_strcasecmp int ROKEN_LIB_FUNCTION strcasecmp(const char *, const char *); #endif @@ -240,26 +280,34 @@ char * ROKEN_LIB_FUNCTION strtok_r(char *, const char *, char **); #endif #ifndef HAVE_STRUPR +#define strupr rk_strupr char * ROKEN_LIB_FUNCTION strupr(char *); #endif #ifndef HAVE_STRLCPY +#define strlcpy rk_strlcpy size_t ROKEN_LIB_FUNCTION strlcpy (char *, const char *, size_t); #endif #ifndef HAVE_STRLCAT +#define strlcat rk_strlcat size_t ROKEN_LIB_FUNCTION strlcat (char *, const char *, size_t); #endif #ifndef HAVE_GETDTABLESIZE +#define getdtablesize rk_getdtablesize int ROKEN_LIB_FUNCTION getdtablesize(void); #endif #if !defined(HAVE_STRERROR) && !defined(strerror) +#define strerror rk_strerror char * ROKEN_LIB_FUNCTION strerror(int); #endif #if !defined(HAVE_HSTRERROR) || defined(NEED_HSTRERROR_PROTO) +#ifndef HAVE_HSTRERROR +#define hstrerror rk_hstrerror +#endif /* This causes a fatal error under Psoriasis */ #if !(defined(SunOS) && (SunOS >= 50)) const char * ROKEN_LIB_FUNCTION hstrerror(int); @@ -271,20 +319,26 @@ extern int h_errno; #endif #if !defined(HAVE_INET_ATON) || defined(NEED_INET_ATON_PROTO) +#ifndef HAVE_INET_ATON +#define inet_aton rk_inet_aton +#endif int ROKEN_LIB_FUNCTION inet_aton(const char *, struct in_addr *); #endif #ifndef HAVE_INET_NTOP +#define inet_ntop rk_inet_ntop const char * ROKEN_LIB_FUNCTION inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_PTON +#define inet_pton rk_inet_pton int ROKEN_LIB_FUNCTION inet_pton(int, const char *, void *); #endif #if !defined(HAVE_GETCWD) +#define getcwd rk_getcwd char* ROKEN_LIB_FUNCTION getcwd(char *, size_t); #endif @@ -297,91 +351,108 @@ struct passwd * ROKEN_LIB_FUNCTION k_getpwuid (uid_t); const char * ROKEN_LIB_FUNCTION get_default_username (void); #ifndef HAVE_SETEUID +#define seteuid rk_seteuid int ROKEN_LIB_FUNCTION seteuid(uid_t); #endif #ifndef HAVE_SETEGID +#define setegid rk_setegid int ROKEN_LIB_FUNCTION setegid(gid_t); #endif #ifndef HAVE_LSTAT +#define lstat rk_lstat int ROKEN_LIB_FUNCTION lstat(const char *, struct stat *); #endif #if !defined(HAVE_MKSTEMP) || defined(NEED_MKSTEMP_PROTO) +#ifndef HAVE_MKSTEMP +#define mkstemp rk_mkstemp +#endif int ROKEN_LIB_FUNCTION mkstemp(char *); #endif #ifndef HAVE_CGETENT +#define cgetent rk_cgetent +#define cgetstr rk_cgetstr int ROKEN_LIB_FUNCTION cgetent(char **, char **, const char *); int ROKEN_LIB_FUNCTION cgetstr(char *, const char *, char **); #endif #ifndef HAVE_INITGROUPS +#define initgroups rk_initgroups int ROKEN_LIB_FUNCTION initgroups(const char *, gid_t); #endif #ifndef HAVE_FCHOWN +#define fchown rk_fchown int ROKEN_LIB_FUNCTION fchown(int, uid_t, gid_t); #endif #if !defined(HAVE_DAEMON) || defined(NEED_DAEMON_PROTO) -int ROKEN_LIB_FUNCTION daemon(int, int); +#ifndef HAVE_DAEMON +#define daemon rk_daemon #endif - -#ifndef HAVE_INNETGR -int ROKEN_LIB_FUNCTION innetgr(const char *, const char *, - const char *, const char *); +int ROKEN_LIB_FUNCTION daemon(int, int); #endif #ifndef HAVE_CHOWN +#define chown rk_chown int ROKEN_LIB_FUNCTION chown(const char *, uid_t, gid_t); #endif #ifndef HAVE_RCMD +#define rcmd rk_rcmd int ROKEN_LIB_FUNCTION rcmd(char **, unsigned short, const char *, const char *, const char *, int *); #endif #if !defined(HAVE_INNETGR) || defined(NEED_INNETGR_PROTO) +#ifndef HAVE_INNETGR +#define innetgr rk_innetgr +#endif int ROKEN_LIB_FUNCTION innetgr(const char*, const char*, const char*, const char*); #endif #ifndef HAVE_IRUSEROK +#define iruserok rk_iruserok int ROKEN_LIB_FUNCTION iruserok(unsigned, int, const char *, const char *); #endif #if !defined(HAVE_GETHOSTNAME) || defined(NEED_GETHOSTNAME_PROTO) +#ifndef HAVE_GETHOSTNAME +#define gethostname rk_gethostname +#endif int ROKEN_LIB_FUNCTION gethostname(char *, int); #endif #ifndef HAVE_WRITEV +#define writev rk_writev ssize_t ROKEN_LIB_FUNCTION writev(int, const struct iovec *, int); #endif #ifndef HAVE_READV +#define readv rk_readv ssize_t ROKEN_LIB_FUNCTION readv(int, const struct iovec *, int); #endif -#ifndef HAVE_MKSTEMP -int ROKEN_LIB_FUNCTION -mkstemp(char *); -#endif - #ifndef HAVE_PIDFILE +#define pidfile rk_pidfile void ROKEN_LIB_FUNCTION pidfile (const char*); #endif #ifndef HAVE_BSWAP32 +#define bswap32 rk_bswap32 unsigned int ROKEN_LIB_FUNCTION bswap32(unsigned int); #endif #ifndef HAVE_BSWAP16 +#define bswap16 rk_bswap16 unsigned short ROKEN_LIB_FUNCTION bswap16(unsigned short); #endif @@ -399,6 +470,7 @@ unsigned short ROKEN_LIB_FUNCTION bswap16(unsigned short); #define LOCK_UN 8 /* Unlock */ #endif +#define flock rk_flock int flock(int fd, int operation); #endif /* HAVE_FLOCK */ @@ -431,6 +503,7 @@ struct winsize { int ROKEN_LIB_FUNCTION get_window_size(int fd, struct winsize *); #ifndef HAVE_VSYSLOG +#define vsyslog rk_vsyslog void ROKEN_LIB_FUNCTION vsyslog(int, const char *, va_list); #endif @@ -445,21 +518,25 @@ extern int opterr; #endif #ifndef HAVE_GETIPNODEBYNAME +#define getipnodebyname rk_getipnodebyname struct hostent * ROKEN_LIB_FUNCTION getipnodebyname (const char *, int, int, int *); #endif #ifndef HAVE_GETIPNODEBYADDR +#define getipnodebyaddr rk_getipnodebyaddr struct hostent * ROKEN_LIB_FUNCTION getipnodebyaddr (const void *, size_t, int, int *); #endif #ifndef HAVE_FREEHOSTENT +#define freehostent rk_freehostent void ROKEN_LIB_FUNCTION freehostent (struct hostent *); #endif #ifndef HAVE_COPYHOSTENT +#define copyhostent rk_copyhostent struct hostent * ROKEN_LIB_FUNCTION copyhostent (const struct hostent *); #endif @@ -527,6 +604,7 @@ struct addrinfo { #endif #ifndef HAVE_GETADDRINFO +#define getaddrinfo rk_getaddrinfo int ROKEN_LIB_FUNCTION getaddrinfo(const char *, const char *, @@ -535,6 +613,7 @@ getaddrinfo(const char *, #endif #ifndef HAVE_GETNAMEINFO +#define getnameinfo rk_getnameinfo int ROKEN_LIB_FUNCTION getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, @@ -543,11 +622,13 @@ getnameinfo(const struct sockaddr *, socklen_t, #endif #ifndef HAVE_FREEADDRINFO +#define freeaddrinfo rk_freeaddrinfo void ROKEN_LIB_FUNCTION freeaddrinfo(struct addrinfo *); #endif #ifndef HAVE_GAI_STRERROR +#define gai_strerror rk_gai_strerror const char * ROKEN_LIB_FUNCTION gai_strerror(int); #endif @@ -564,25 +645,31 @@ int ROKEN_LIB_FUNCTION roken_getaddrinfo_hostspec2(const char *, int, int, struct addrinfo **); #ifndef HAVE_STRFTIME +#define strftime rk_strftime size_t ROKEN_LIB_FUNCTION strftime (char *, size_t, const char *, const struct tm *); #endif #ifndef HAVE_STRPTIME +#define strptime rk_strptime char * ROKEN_LIB_FUNCTION strptime (const char *, const char *, struct tm *); #endif #ifndef HAVE_EMALLOC +#define emalloc rk_emalloc void * ROKEN_LIB_FUNCTION emalloc (size_t); #endif #ifndef HAVE_ECALLOC +#define ecalloc rk_ecalloc void * ROKEN_LIB_FUNCTION ecalloc(size_t, size_t); #endif #ifndef HAVE_EREALLOC +#define erealloc rk_erealloc void * ROKEN_LIB_FUNCTION erealloc (void *, size_t); #endif #ifndef HAVE_ESTRDUP +#define estrdup rk_estrdup char * ROKEN_LIB_FUNCTION estrdup (const char *); #endif @@ -630,10 +717,12 @@ roken_gethostbyaddr(const void*, size_t, int); #endif #ifndef HAVE_SETPROGNAME +#define setprogname rk_setprogname void ROKEN_LIB_FUNCTION setprogname(const char *); #endif #ifndef HAVE_GETPROGNAME +#define getprogname rk_getprogname const char * ROKEN_LIB_FUNCTION getprogname(void); #endif @@ -645,46 +734,69 @@ void ROKEN_LIB_FUNCTION mini_inetd_addrinfo (struct addrinfo*); void ROKEN_LIB_FUNCTION mini_inetd (int); #ifndef HAVE_LOCALTIME_R +#define localtime_r rk_localtime_r struct tm * ROKEN_LIB_FUNCTION localtime_r(const time_t *, struct tm *); #endif #if !defined(HAVE_STRSVIS) || defined(NEED_STRSVIS_PROTO) +#ifndef HAVE_STRSVIS +#define strsvis rk_strsvis +#endif int ROKEN_LIB_FUNCTION strsvis(char *, const char *, int, const char *); #endif #if !defined(HAVE_STRUNVIS) || defined(NEED_STRUNVIS_PROTO) +#ifndef HAVE_STRUNVIS +#define strunvis rk_strunvis +#endif int ROKEN_LIB_FUNCTION strunvis(char *, const char *); #endif #if !defined(HAVE_STRVIS) || defined(NEED_STRVIS_PROTO) +#ifndef HAVE_STRVIS +#define strvis rk_strvis +#endif int ROKEN_LIB_FUNCTION strvis(char *, const char *, int); #endif #if !defined(HAVE_STRVISX) || defined(NEED_STRVISX_PROTO) +#ifndef HAVE_STRVISX +#define strvisx rk_strvisx +#endif int ROKEN_LIB_FUNCTION strvisx(char *, const char *, size_t, int); #endif #if !defined(HAVE_SVIS) || defined(NEED_SVIS_PROTO) +#ifndef HAVE_SVIS +#define svis rk_svis +#endif char * ROKEN_LIB_FUNCTION svis(char *, int, int, int, const char *); #endif #if !defined(HAVE_UNVIS) || defined(NEED_UNVIS_PROTO) +#ifndef HAVE_UNVIS +#define unvis rk_unvis +#endif int ROKEN_LIB_FUNCTION unvis(char *, int, int *, int); #endif #if !defined(HAVE_VIS) || defined(NEED_VIS_PROTO) +#ifndef HAVE_VIS +#define vis rk_vis +#endif char * ROKEN_LIB_FUNCTION vis(char *, int, int, int); #endif #if !defined(HAVE_CLOSEFROM) +#define closefrom rk_closefrom int ROKEN_LIB_FUNCTION closefrom(int); #endif diff --git a/source4/heimdal/lib/roken/roken_gethostby.c b/source4/heimdal/lib/roken/roken_gethostby.c index 12760456a4..d87a49a04b 100644 --- a/source4/heimdal/lib/roken/roken_gethostby.c +++ b/source4/heimdal/lib/roken/roken_gethostby.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/rtbl.c b/source4/heimdal/lib/roken/rtbl.c index cfb7657091..7d11a487cf 100644 --- a/source4/heimdal/lib/roken/rtbl.c +++ b/source4/heimdal/lib/roken/rtbl.c @@ -31,10 +31,8 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID ("$Id$"); -#endif + #include "roken.h" #include "rtbl.h" diff --git a/source4/heimdal/lib/roken/setprogname.c b/source4/heimdal/lib/roken/setprogname.c index 9beb07afe9..225e6ae092 100644 --- a/source4/heimdal/lib/roken/setprogname.c +++ b/source4/heimdal/lib/roken/setprogname.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" diff --git a/source4/heimdal/lib/roken/signal.c b/source4/heimdal/lib/roken/signal.c index 9141ca2bb1..19a4845435 100644 --- a/source4/heimdal/lib/roken/signal.c +++ b/source4/heimdal/lib/roken/signal.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <signal.h> #include "roken.h" diff --git a/source4/heimdal/lib/roken/simple_exec.c b/source4/heimdal/lib/roken/simple_exec.c index 7060cb8d37..86dde1bad2 100644 --- a/source4/heimdal/lib/roken/simple_exec.c +++ b/source4/heimdal/lib/roken/simple_exec.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdarg.h> #include <stdlib.h> @@ -51,10 +48,6 @@ RCSID("$Id$"); #include "roken.h" -#if !HAVE_DECL_ENVIRON -extern char **environ; -#endif - #define EX_NOEXEC 126 #define EX_NOTFOUND 127 @@ -316,20 +309,3 @@ simple_execle(const char *file, ... /* ,char *const envp[] */) free(argv); return ret; } - -int ROKEN_LIB_FUNCTION -simple_execl(const char *file, ...) -{ - va_list ap; - char **argv; - int ret; - - va_start(ap, file); - argv = vstrcollect(&ap); - va_end(ap); - if(argv == NULL) - return -1; - ret = simple_execve(file, argv, environ); - free(argv); - return ret; -} diff --git a/source4/heimdal/lib/roken/socket.c b/source4/heimdal/lib/roken/socket.c index a373eb7ed2..ab1b7ff344 100644 --- a/source4/heimdal/lib/roken/socket.c +++ b/source4/heimdal/lib/roken/socket.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" #include <err.h> @@ -152,17 +149,17 @@ socket_sockaddr_size (const struct sockaddr *sa) */ void * ROKEN_LIB_FUNCTION -socket_get_address (struct sockaddr *sa) +socket_get_address (const struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET : { - struct sockaddr_in *sin4 = (struct sockaddr_in *)sa; - return &sin4->sin_addr; + const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; + return rk_UNCONST(&sin4->sin_addr); } #ifdef HAVE_IPV6 case AF_INET6 : { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - return &sin6->sin6_addr; + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; + return rk_UNCONST(&sin6->sin6_addr); } #endif default : diff --git a/source4/heimdal/lib/roken/strcollect.c b/source4/heimdal/lib/roken/strcollect.c index a33d52134a..f444d05e25 100644 --- a/source4/heimdal/lib/roken/strcollect.c +++ b/source4/heimdal/lib/roken/strcollect.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdarg.h> #include <stdlib.h> diff --git a/source4/heimdal/lib/roken/strlwr.c b/source4/heimdal/lib/roken/strlwr.c index ea787d8184..1a6634b736 100644 --- a/source4/heimdal/lib/roken/strlwr.c +++ b/source4/heimdal/lib/roken/strlwr.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <string.h> #include <ctype.h> diff --git a/source4/heimdal/lib/roken/strpool.c b/source4/heimdal/lib/roken/strpool.c index aa80996946..dc56892144 100644 --- a/source4/heimdal/lib/roken/strpool.c +++ b/source4/heimdal/lib/roken/strpool.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <stdarg.h> #include <stdlib.h> diff --git a/source4/heimdal/lib/roken/strsep.c b/source4/heimdal/lib/roken/strsep.c index 7a93fb17aa..5cbf8557a5 100644 --- a/source4/heimdal/lib/roken/strsep.c +++ b/source4/heimdal/lib/roken/strsep.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <string.h> diff --git a/source4/heimdal/lib/roken/strsep_copy.c b/source4/heimdal/lib/roken/strsep_copy.c index 61b7d39c57..908e37ca40 100644 --- a/source4/heimdal/lib/roken/strsep_copy.c +++ b/source4/heimdal/lib/roken/strsep_copy.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <string.h> diff --git a/source4/heimdal/lib/roken/strupr.c b/source4/heimdal/lib/roken/strupr.c index d67dd20dd0..db2d987f9f 100644 --- a/source4/heimdal/lib/roken/strupr.c +++ b/source4/heimdal/lib/roken/strupr.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <string.h> #include <ctype.h> diff --git a/source4/heimdal/lib/roken/vis.c b/source4/heimdal/lib/roken/vis.c index 43705e4d50..c8d19a4455 100644 --- a/source4/heimdal/lib/roken/vis.c +++ b/source4/heimdal/lib/roken/vis.c @@ -56,10 +56,7 @@ */ #if 1 -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include "roken.h" #ifndef _DIAGASSERT #define _DIAGASSERT(X) diff --git a/source4/heimdal/lib/roken/xfree.c b/source4/heimdal/lib/roken/xfree.c index 5f6d86ee56..13366ce132 100644 --- a/source4/heimdal/lib/roken/xfree.c +++ b/source4/heimdal/lib/roken/xfree.c @@ -31,10 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -RCSID("$Id$"); -#endif #include <unistd.h> diff --git a/source4/heimdal/lib/vers/print_version.c b/source4/heimdal/lib/vers/print_version.c index 63e016174a..9d102c7dc5 100644 --- a/source4/heimdal/lib/vers/print_version.c +++ b/source4/heimdal/lib/vers/print_version.c @@ -31,18 +31,17 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H + #include <config.h> -RCSID("$Id$"); -#endif + #include "roken.h" -#include "print_version.h" +#include "version.h" -void +void ROKEN_LIB_FUNCTION print_version(const char *progname) { - const char *package_list = VERSIONLIST; + const char *package_list = heimdal_version; if(progname == NULL) progname = getprogname(); diff --git a/source4/heimdal/lib/wind/normalize.c b/source4/heimdal/lib/wind/normalize.c index c7af0e4958..3f71449fac 100644 --- a/source4/heimdal/lib/wind/normalize.c +++ b/source4/heimdal/lib/wind/normalize.c @@ -235,10 +235,9 @@ combine(const uint32_t *in, size_t in_len, int ostarter; unsigned o = 0; int old_cc; - int cc; for (i = 0; i < in_len;) { - while (i < in_len && (cc = _wind_combining_class(in[i])) != 0) { + while (i < in_len && _wind_combining_class(in[i]) != 0) { out[o++] = in[i++]; } if (i < in_len) { @@ -251,6 +250,7 @@ combine(const uint32_t *in, size_t in_len, while (i < in_len) { uint32_t comb; uint32_t v[2]; + int cc; v[0] = out[ostarter]; v[1] = in[i]; diff --git a/source4/heimdal/lib/wind/stringprep.c b/source4/heimdal/lib/wind/stringprep.c index 6e99cfc86b..aa04b3fd1d 100644 --- a/source4/heimdal/lib/wind/stringprep.c +++ b/source4/heimdal/lib/wind/stringprep.c @@ -107,7 +107,7 @@ wind_stringprep(const uint32_t *in, size_t in_len, return ret; } -static struct { +const static struct { const char *name; wind_profile_flags flags; } profiles[] = { diff --git a/source4/heimdal/lib/wind/utf8.c b/source4/heimdal/lib/wind/utf8.c index f563b79107..ed944b4c7d 100644 --- a/source4/heimdal/lib/wind/utf8.c +++ b/source4/heimdal/lib/wind/utf8.c @@ -31,9 +31,7 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include "windlocl.h" RCSID("$Id$"); diff --git a/source4/heimdal/lib/wind/wind_err.et b/source4/heimdal/lib/wind/wind_err.et index f90c252e7d..01c0d0f1c5 100644 --- a/source4/heimdal/lib/wind/wind_err.et +++ b/source4/heimdal/lib/wind/wind_err.et @@ -12,8 +12,8 @@ error_code NONE, "No error" error_code NO_PROFILE, "No such profile" error_code OVERRUN, "Buffer overrun" error_code UNDERUN, "Buffer underrun" -error_code LENGTH_NOT_MOD2, "Lenght not mod2" -error_code LENGTH_NOT_MOD4, "Lenght not mod4" +error_code LENGTH_NOT_MOD2, "Length not mod2" +error_code LENGTH_NOT_MOD4, "Length not mod4" error_code INVALID_UTF8, "Invalid UTF-8 combination in string" error_code INVALID_UTF16, "Invalid UTF-16 combination in string" error_code INVALID_UTF32, "Invalid UTF-32 combination in string" |