From 427af907b41aed7742faf50605e24c880ae6b661 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Feb 2022 07:40:17 +0100 Subject: [PATCH 01/22] s4:sam: Don't use talloc_steal for msg attributes in authsam_make_user_info_dc() This is most likely not a problem for the current callers, but that it is unexpected and will likely cause problems with future changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14993 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit f6fe86924c2ca756083d3628d5dbace0b12d06b0) --- source4/auth/sam.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/source4/auth/sam.c b/source4/auth/sam.c index 93b41be3b210..8b233bab3ad8 100644 --- a/source4/auth/sam.c +++ b/source4/auth/sam.c @@ -454,12 +454,15 @@ _PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx, user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info); NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info); - info->account_name = talloc_steal(info, - ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL)); + str = ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL); + info->account_name = talloc_strdup(info, str); + if (info->account_name == NULL) { + TALLOC_FREE(user_info_dc); + return NT_STATUS_NO_MEMORY; + } - info->user_principal_name = talloc_steal(info, - ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL)); - if (info->user_principal_name == NULL && dns_domain_name != NULL) { + str = ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL); + if (str == NULL && dns_domain_name != NULL) { info->user_principal_name = talloc_asprintf(info, "%s@%s", info->account_name, dns_domain_name); @@ -468,6 +471,12 @@ _PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } info->user_principal_constructed = true; + } else if (str != NULL) { + info->user_principal_name = talloc_strdup(info, str); + if (info->user_principal_name == NULL) { + TALLOC_FREE(user_info_dc); + return NT_STATUS_NO_MEMORY; + } } info->domain_name = talloc_strdup(info, domain_name); -- 2.25.1 From 3ede4a087c41455a86925b0273454303e77c7bb7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 14:15:43 +1300 Subject: [PATCH 02/22] auth: Cope with NULL upn_name in PAC BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher (cherry picked from commit ef95fb439237910b945b8d6a3ad4a140a8d6d1ea) --- auth/auth_sam_reply.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/auth/auth_sam_reply.c b/auth/auth_sam_reply.c index b5b6362dc93b..fda014c87d5c 100644 --- a/auth/auth_sam_reply.c +++ b/auth/auth_sam_reply.c @@ -616,11 +616,13 @@ NTSTATUS make_user_info_dc_pac(TALLOC_CTX *mem_ctx, } if (pac_upn_dns_info != NULL) { - user_info_dc->info->user_principal_name = - talloc_strdup(user_info_dc->info, - pac_upn_dns_info->upn_name); - if (user_info_dc->info->user_principal_name == NULL) { - return NT_STATUS_NO_MEMORY; + if (pac_upn_dns_info->upn_name != NULL) { + user_info_dc->info->user_principal_name = + talloc_strdup(user_info_dc->info, + pac_upn_dns_info->upn_name); + if (user_info_dc->info->user_principal_name == NULL) { + return NT_STATUS_NO_MEMORY; + } } user_info_dc->info->dns_domain_name = -- 2.25.1 From eefa0d127244baabc761e319b48e7eadbf31e1a4 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 15:30:17 +1300 Subject: [PATCH 03/22] third_party/heimdal_build: Add KDC_LIB macro definitions This is an adaptation to Heimdal: commit 7bb00a40eabbed2bc1c268f5244bfb9736d9bebe Author: Luke Howard Date: Tue Jan 4 13:08:35 2022 +1100 kdc: fix Windows build BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher (cherry picked from commit 6d8fec7006e8eadf5967a6f2f5add7d3c2c7bd3e) --- third_party/heimdal_build/wscript_build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/heimdal_build/wscript_build b/third_party/heimdal_build/wscript_build index 7780f9c13246..cf7c2b9a3428 100644 --- a/third_party/heimdal_build/wscript_build +++ b/third_party/heimdal_build/wscript_build @@ -445,7 +445,7 @@ if not bld.CONFIG_SET("USING_SYSTEM_KDC"): includes='../heimdal/kdc', deps='roken krb5 hdb asn1 HEIMDAL_DIGEST_ASN1 HEIMDAL_KX509_ASN1 heimntlm hcrypto com_err wind heimbase gssapi gss_preauth', version_script='kdc/version-script.map') - HEIMDAL_AUTOPROTO('kdc/kdc-protos.h', KDC_SOURCE) + HEIMDAL_AUTOPROTO('kdc/kdc-protos.h', KDC_SOURCE, options='-E KDC_LIB -q -P comment -o') HEIMDAL_AUTOPROTO_PRIVATE('kdc/kdc-private.h', KDC_SOURCE) if not bld.CONFIG_SET("USING_SYSTEM_HEIMNTLM"): -- 2.25.1 From 8eef2f08b6d932228471c28c8f0d54b03747f7cf Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 24 Feb 2022 15:30:17 +1300 Subject: [PATCH 04/22] s4:kdc: Don't pass empty PAC buffers to krb5_pac_add_buffer() Heimdal will no longer allow us to pass a dummy zero-length buffer to krb5_pac_add_buffer(), so we have to pass a buffer of length 1 instead. This is an adaption to Heimdal: commit 190263bb7a56fc775b50a6cd0dc91820d2b2e5eb Author: Jeffrey Altman Date: Wed Jan 19 22:55:33 2022 -0500 assert non-NULL ptrs before calling mem funcs The definitions of memcpy(), memmove(), and memset() state that the behaviour is undefined if any of the pointer arguments are NULL, and some compilers are known to make use of this to optimise away existing NULL checks in the source. Change-Id: I489bc256e3eac7ff41d91becb0b43aba73dbb3f9 Link: https://www.imperialviolet.org/2016/06/26/nonnull.html BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher (cherry picked from commit 9936038fae72fb440864be543e9afd500444d502) --- source4/kdc/pac-glue.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index eac1612ca2b3..dc6db122865f 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -517,9 +517,10 @@ krb5_error_code samba_make_krb5_pac(krb5_context context, krb5_data deleg_data; krb5_error_code ret; #ifdef SAMBA4_USES_HEIMDAL + char null_byte = '\0'; krb5_data null_data = { - .length = 0, - .data = NULL, + .length = 1, + .data = &null_byte, }; #endif -- 2.25.1 From 519964dc463efeb5b0b3dce98c61d030251635b9 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Thu, 24 Feb 2022 15:24:13 +1300 Subject: [PATCH 05/22] third_party/heimdal_build: Determine whether time_t is signed Without this, Heimdal will assume time_t is unsigned, and a wrong assumption will cause 'infinite' ticket lifetimes to be reckoned as from the past, and thus requests will fail with KDC_ERR_NEVER_VALID. This is an adaptation to Heimdal: commit 9ae9902249732237aa1711591604a6adf24963fe Author: Nicolas Williams Date: Tue Feb 15 17:01:00 2022 -0600 cf: Check if time_t is signed BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Tue Mar 1 18:07:50 UTC 2022 on sn-devel-184 (cherry picked from commit 9eb27f296ae2b797803fffbb7f4cb34d8eb06f34) --- buildtools/wafsamba/samba_autoconf.py | 17 +++++++++++++++++ third_party/heimdal_build/wscript_configure | 2 ++ 2 files changed, 19 insertions(+) diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py index 8b4998252302..78927d851937 100644 --- a/buildtools/wafsamba/samba_autoconf.py +++ b/buildtools/wafsamba/samba_autoconf.py @@ -343,6 +343,23 @@ def CHECK_SIZEOF(conf, vars, headers=None, define=None, critical=True): sys.exit(1) return ret +@conf +def CHECK_SIGN(conf, v, headers=None): + '''check the sign of a type''' + define_name = v.upper().replace(' ', '_') + for op, signed in [('<', 'signed'), + ('>', 'unsigned')]: + if CHECK_CODE(conf, + f'static int test_array[1 - 2 * !((({v})-1) {op} 0)];', + define=f'{define_name}_{signed.upper()}', + quote=False, + headers=headers, + local_include=False, + msg=f"Checking if '{v}' is {signed}"): + return True + + return False + @conf def CHECK_VALUEOF(conf, v, headers=None, define=None): '''check the value of a variable/define''' diff --git a/third_party/heimdal_build/wscript_configure b/third_party/heimdal_build/wscript_configure index 023935d98c0d..0021cd328ecf 100644 --- a/third_party/heimdal_build/wscript_configure +++ b/third_party/heimdal_build/wscript_configure @@ -206,3 +206,5 @@ if conf.CONFIG_SET('USING_EMBEDDED_HEIMDAL'): conf.define('HAVE_KRB5_ADDLOG_FUNC_NEED_CONTEXT', 1) else: pass # TODO + +conf.CHECK_SIGN('time_t') -- 2.25.1 From f11bc828b0eed6b119ebef446171d63541237f24 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 16:41:52 +1300 Subject: [PATCH 06/22] third_party/heimdal_build: Define fallthrough macro for switch statements This is an adaptation to Heimdal: commit ddc61136100b32346c4c4efa2bb6ddb5baedfb3e Author: Nicolas Williams Date: Fri Jan 14 16:32:04 2022 -0600 Use fallthrough statement attribute BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Joseph Sutton Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit fccf9859786dfb50b317ea2296c2494997f0ae09) --- third_party/heimdal_build/config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/third_party/heimdal_build/config.h b/third_party/heimdal_build/config.h index d9ba31b3b45e..42b11ace11f5 100644 --- a/third_party/heimdal_build/config.h +++ b/third_party/heimdal_build/config.h @@ -64,4 +64,6 @@ #define HAVE_STRSEP 1 #endif +#define fallthrough FALL_THROUGH + #endif -- 2.25.1 From 2792109ddcab2d43348fd0546650a69312d91fea Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 1 Mar 2022 14:17:54 +1300 Subject: [PATCH 07/22] third_party/heimdal: import lorikeet-heimdal-202203010107 (commit 0e7a12404c388e831fe6933fcc3c86e7eb334825) NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 51569b3152a952d07fddaa3a70d60c920618c704) --- .../heimdal/.github/workflows/build.yml | 67 - third_party/heimdal/.gitignore | 236 ++- third_party/heimdal/Makefile.am | 1 - third_party/heimdal/README.md | 9 +- third_party/heimdal/admin/change.c | 1 - third_party/heimdal/appl/afsutil/afslog.c | 2 +- third_party/heimdal/appl/gssmask/gssmask.c | 2 + third_party/heimdal/appl/kf/kf.c | 4 +- third_party/heimdal/appl/otp/otp.c | 12 +- third_party/heimdal/appl/test/gssapi_server.c | 23 +- third_party/heimdal/appl/test/uu_server.c | 7 + third_party/heimdal/appveyor.yml | 72 +- third_party/heimdal/cf/Makefile.am.common | 19 +- third_party/heimdal/cf/ax_check_sign.m4 | 54 + third_party/heimdal/cf/check-compile-flag.m4 | 53 + third_party/heimdal/cf/db.m4 | 6 +- third_party/heimdal/cf/krb-prog-yacc.m4 | 12 +- third_party/heimdal/cf/roken-frag.m4 | 6 - third_party/heimdal/configure.ac | 38 +- third_party/heimdal/import-lorikeet.sh | 22 +- third_party/heimdal/include/Makefile.am | 33 +- third_party/heimdal/include/bits.c | 51 +- third_party/heimdal/include/config.h.w32 | 37 +- third_party/heimdal/kadmin/add-random-users.c | 2 +- third_party/heimdal/kadmin/add_enctype.c | 4 +- third_party/heimdal/kadmin/ank.c | 40 +- third_party/heimdal/kadmin/cpw.c | 16 +- third_party/heimdal/kadmin/del.c | 12 +- third_party/heimdal/kadmin/ext.c | 2 +- third_party/heimdal/kadmin/get.c | 2 + third_party/heimdal/kadmin/init.c | 202 ++- third_party/heimdal/kadmin/kadm_conn.c | 9 +- third_party/heimdal/kadmin/kadmin.1 | 33 +- third_party/heimdal/kadmin/kadmind.c | 2 + third_party/heimdal/kadmin/load.c | 54 +- third_party/heimdal/kadmin/mod.c | 15 +- third_party/heimdal/kadmin/rpc.c | 4 +- third_party/heimdal/kadmin/server.c | 315 ++-- third_party/heimdal/kadmin/stash.c | 5 +- third_party/heimdal/kcm/cache.c | 10 +- third_party/heimdal/kcm/client.c | 37 + third_party/heimdal/kcm/glue.c | 2 +- third_party/heimdal/kcm/protocol.c | 24 +- third_party/heimdal/kdc/Makefile.am | 14 +- third_party/heimdal/kdc/NTMakefile | 18 +- .../kdc/altsecid_gss_preauth_authorizer.c | 85 +- third_party/heimdal/kdc/bx509d.c | 170 ++- third_party/heimdal/kdc/ca.c | 4 +- .../heimdal/kdc/cjwt_token_validator.c | 9 +- third_party/heimdal/kdc/config.c | 2 +- third_party/heimdal/kdc/connect.c | 19 +- third_party/heimdal/kdc/csr_authorizer.c | 2 +- third_party/heimdal/kdc/default_config.c | 5 +- third_party/heimdal/kdc/digest-service.c | 9 +- third_party/heimdal/kdc/digest.c | 46 +- third_party/heimdal/kdc/fast.c | 35 +- third_party/heimdal/kdc/gss_preauth.c | 78 +- .../kdc/gss_preauth_authorizer_plugin.h | 6 +- third_party/heimdal/kdc/headers.h | 3 +- third_party/heimdal/kdc/hprop.8 | 1 - third_party/heimdal/kdc/hprop.c | 23 +- third_party/heimdal/kdc/hprop.h | 18 +- third_party/heimdal/kdc/hpropd.8 | 3 - third_party/heimdal/kdc/hpropd.c | 11 +- third_party/heimdal/kdc/httpkadmind.c | 73 +- third_party/heimdal/kdc/ipc_csr_authorizer.c | 20 +- third_party/heimdal/kdc/kdc-accessors.h | 349 +++++ third_party/heimdal/kdc/{rx.h => kdc-audit.h} | 68 +- third_party/heimdal/kdc/kdc-plugin.c | 658 +++++++++ third_party/heimdal/kdc/kdc-plugin.h | 136 ++ third_party/heimdal/kdc/kdc-replay.c | 2 + third_party/heimdal/kdc/kdc.h | 168 +-- third_party/heimdal/kdc/kdc_locl.h | 109 +- third_party/heimdal/kdc/kerberos5.c | 691 ++++----- third_party/heimdal/kdc/krb5tgs.c | 946 ++++-------- third_party/heimdal/kdc/kstash.c | 2 + third_party/heimdal/kdc/kx509.c | 130 +- third_party/heimdal/kdc/libkdc-exports.def | 83 +- third_party/heimdal/kdc/log.c | 10 +- third_party/heimdal/kdc/misc.c | 103 +- third_party/heimdal/kdc/mit_dump.c | 6 +- third_party/heimdal/kdc/mssfu.c | 568 ++++++++ .../heimdal/kdc/negotiate_token_validator.c | 2 - third_party/heimdal/kdc/pkinit.c | 30 +- third_party/heimdal/kdc/process.c | 204 ++- third_party/heimdal/kdc/set_dbinfo.c | 2 +- .../heimdal/kdc/simple_csr_authorizer.c | 24 +- third_party/heimdal/kdc/string2key.c | 6 +- third_party/heimdal/kdc/test_kdc_ca.c | 5 +- third_party/heimdal/kdc/token_validator.c | 2 +- third_party/heimdal/kdc/version-script.map | 78 +- third_party/heimdal/kdc/windc.c | 252 ---- third_party/heimdal/kdc/windc_plugin.h | 92 -- third_party/heimdal/kpasswd/kpasswdd.c | 2 + third_party/heimdal/kuser/generate-requests.c | 2 +- third_party/heimdal/kuser/kgetcred.c | 3 + third_party/heimdal/kuser/kimpersonate.c | 27 +- third_party/heimdal/kuser/kinit.c | 34 +- third_party/heimdal/kuser/klist.c | 15 +- third_party/heimdal/kuser/kswitch.c | 5 +- third_party/heimdal/kuser/kuser_locl.h | 4 + third_party/heimdal/lib/asn1/MANUAL.md | 1287 +++++++++++++++++ third_party/heimdal/lib/asn1/Makefile.am | 361 ++--- third_party/heimdal/lib/asn1/NTMakefile | 281 ++-- third_party/heimdal/lib/asn1/README.md | 326 +++-- third_party/heimdal/lib/asn1/asn1-template.h | 75 +- third_party/heimdal/lib/asn1/asn1_compile.1 | 263 +++- third_party/heimdal/lib/asn1/asn1_print.c | 32 +- third_party/heimdal/lib/asn1/asn1parse.y | 141 +- third_party/heimdal/lib/asn1/check-common.h | 3 +- third_party/heimdal/lib/asn1/check-der.c | 2 + third_party/heimdal/lib/asn1/check-gen.c | 144 +- third_party/heimdal/lib/asn1/check-gen.h | 9 + third_party/heimdal/lib/asn1/check-template.c | 13 + third_party/heimdal/lib/asn1/der_copy.c | 103 +- third_party/heimdal/lib/asn1/der_get.c | 92 +- third_party/heimdal/lib/asn1/der_put.c | 68 +- third_party/heimdal/lib/asn1/extra.c | 8 +- third_party/heimdal/lib/asn1/gen.c | 186 ++- third_party/heimdal/lib/asn1/gen_copy.c | 47 +- third_party/heimdal/lib/asn1/gen_decode.c | 6 +- third_party/heimdal/lib/asn1/gen_encode.c | 29 +- third_party/heimdal/lib/asn1/gen_free.c | 55 +- third_party/heimdal/lib/asn1/gen_glue.c | 11 +- third_party/heimdal/lib/asn1/gen_locl.h | 17 +- third_party/heimdal/lib/asn1/gen_template.c | 172 ++- third_party/heimdal/lib/asn1/krb5.asn1 | 46 +- third_party/heimdal/lib/asn1/krb5.opt | 2 + .../heimdal/lib/asn1/libasn1-exports.def | 6 + third_party/heimdal/lib/asn1/main.c | 240 ++- third_party/heimdal/lib/asn1/oid_resolution.c | 75 +- third_party/heimdal/lib/asn1/symbol.h | 5 +- third_party/heimdal/lib/asn1/template.c | 56 +- third_party/heimdal/lib/asn1/test.asn1 | 12 +- third_party/heimdal/lib/asn1/test.opt | 6 + third_party/heimdal/lib/base/array.c | 4 +- third_party/heimdal/lib/base/bsearch.c | 24 +- third_party/heimdal/lib/base/data.c | 9 +- third_party/heimdal/lib/base/db.c | 24 +- third_party/heimdal/lib/base/dict.c | 8 +- third_party/heimdal/lib/base/dll.c | 3 +- third_party/heimdal/lib/base/error.c | 4 +- third_party/heimdal/lib/base/error_string.c | 7 +- third_party/heimdal/lib/base/expand_path.c | 58 +- third_party/heimdal/lib/base/heimbase-svc.h | 8 +- third_party/heimdal/lib/base/heimbase.c | 35 +- third_party/heimdal/lib/base/heimbase.h | 9 +- third_party/heimdal/lib/base/heimbasepriv.h | 3 +- third_party/heimdal/lib/base/log.c | 363 ++++- third_party/heimdal/lib/base/number.c | 22 +- third_party/heimdal/lib/base/plugin.c | 16 +- third_party/heimdal/lib/base/string.c | 6 +- third_party/heimdal/lib/base/test_base.c | 6 +- .../heimdal/lib/base/version-script.map | 7 + third_party/heimdal/lib/com_err/Makefile.am | 2 +- .../heimdal/lib/gss_preauth/pa_client.c | 3 +- .../heimdal/lib/gss_preauth/pa_common.c | 5 - third_party/heimdal/lib/gssapi/Makefile.am | 55 +- third_party/heimdal/lib/gssapi/NTMakefile | 38 +- third_party/heimdal/lib/gssapi/gss-token.c | 11 +- .../heimdal/lib/gssapi/gssapi/gssapi.h | 16 +- .../heimdal/lib/gssapi/gssapi/gssapi_krb5.h | 2 + .../lib/gssapi/krb5/accept_sec_context.c | 140 +- .../heimdal/lib/gssapi/krb5/acquire_cred.c | 52 +- third_party/heimdal/lib/gssapi/krb5/arcfour.c | 13 +- .../heimdal/lib/gssapi/krb5/copy_ccache.c | 5 +- .../lib/gssapi/krb5/export_sec_context.c | 2 +- .../heimdal/lib/gssapi/krb5/external.c | 19 +- .../heimdal/lib/gssapi/krb5/import_name.c | 35 +- .../lib/gssapi/krb5/init_sec_context.c | 41 +- .../heimdal/lib/gssapi/krb5/name_attrs.c | 1171 +++++++++++++++ .../heimdal/lib/gssapi/krb5/store_cred.c | 5 +- .../heimdal/lib/gssapi/krb5/test_kcred.c | 6 +- .../heimdal/lib/gssapi/libgssapi-exports.def | 2 +- .../lib/gssapi/mech/gss_compare_name.c | 10 +- .../heimdal/lib/gssapi/mech/gss_cred.c | 6 +- .../lib/gssapi/mech/gss_export_sec_context.c | 4 + .../heimdal/lib/gssapi/mech/gss_import_name.c | 82 +- .../lib/gssapi/mech/gss_import_sec_context.c | 6 +- .../heimdal/lib/gssapi/mech/gss_krb5.c | 7 +- .../heimdal/lib/gssapi/mech/gss_mech_switch.c | 47 +- .../lib/gssapi/mech/gss_pname_to_uid.c | 4 + .../heimdal/lib/gssapi/mech/mech_locl.h | 11 +- .../lib/gssapi/ntlm/accept_sec_context.c | 2 + third_party/heimdal/lib/gssapi/ntlm/creds.c | 4 - third_party/heimdal/lib/gssapi/ntlm/crypto.c | 5 +- .../lib/gssapi/ntlm/delete_sec_context.c | 6 + .../lib/gssapi/ntlm/init_sec_context.c | 22 +- third_party/heimdal/lib/gssapi/ntlm/kdc.c | 1 + .../heimdal/lib/gssapi/sanon/import_name.c | 25 +- .../lib/gssapi/spnego/accept_sec_context.c | 1 + .../heimdal/lib/gssapi/spnego/negoex_ctx.c | 28 +- third_party/heimdal/lib/gssapi/test_context.c | 168 ++- third_party/heimdal/lib/gssapi/test_kcred.c | 18 +- third_party/heimdal/lib/gssapi/test_names.c | 464 +++++- .../heimdal/lib/gssapi/version-script.map | 2 +- third_party/heimdal/lib/hcrypto/Makefile.am | 27 +- third_party/heimdal/lib/hcrypto/bn.c | 8 +- third_party/heimdal/lib/hcrypto/des.c | 1 + third_party/heimdal/lib/hcrypto/dh-ltm.c | 57 +- third_party/heimdal/lib/hcrypto/dh.c | 2 +- third_party/heimdal/lib/hcrypto/engine.c | 35 +- third_party/heimdal/lib/hcrypto/evp.c | 9 +- third_party/heimdal/lib/hcrypto/hmac.c | 28 +- third_party/heimdal/lib/hcrypto/hmac.h | 2 +- .../lib/hcrypto/libtommath/bn_mp_set_double.c | 2 +- .../libtommath/bn_s_mp_rand_platform.c | 2 +- .../lib/hcrypto/libtommath/demo/test.c | 2 +- .../heimdal/lib/hcrypto/libtommath/etc/tune.c | 2 +- third_party/heimdal/lib/hcrypto/rsa-ltm.c | 7 +- third_party/heimdal/lib/hcrypto/rsa.c | 7 +- third_party/heimdal/lib/hcrypto/test_hmac.c | 6 +- third_party/heimdal/lib/hcrypto/validate.c | 3 +- third_party/heimdal/lib/hdb/Makefile.am | 67 +- third_party/heimdal/lib/hdb/NTMakefile | 12 +- third_party/heimdal/lib/hdb/common.c | 375 +++-- third_party/heimdal/lib/hdb/db.c | 22 +- third_party/heimdal/lib/hdb/db3.c | 22 +- third_party/heimdal/lib/hdb/ext.c | 4 +- third_party/heimdal/lib/hdb/hdb-keytab.c | 22 +- third_party/heimdal/lib/hdb/hdb-ldap.c | 363 ++--- third_party/heimdal/lib/hdb/hdb-mdb.c | 22 +- third_party/heimdal/lib/hdb/hdb-mitdb.c | 89 +- third_party/heimdal/lib/hdb/hdb-sqlite.c | 39 +- third_party/heimdal/lib/hdb/hdb.asn1 | 2 +- third_party/heimdal/lib/hdb/hdb.c | 98 +- third_party/heimdal/lib/hdb/hdb.h | 175 +-- third_party/heimdal/lib/hdb/hdb.opt | 5 + third_party/heimdal/lib/hdb/keys.c | 2 +- third_party/heimdal/lib/hdb/keytab.c | 50 +- .../heimdal/lib/hdb/libhdb-exports.def | 1 - third_party/heimdal/lib/hdb/ndbm.c | 53 +- third_party/heimdal/lib/hdb/print.c | 20 +- .../heimdal/lib/hdb/test_concurrency.c | 58 +- third_party/heimdal/lib/hdb/test_namespace.c | 162 +-- .../heimdal/lib/hdb/version-script.map | 1 - third_party/heimdal/lib/hx509/Makefile.am | 3 +- third_party/heimdal/lib/hx509/ca.c | 21 +- third_party/heimdal/lib/hx509/cert.c | 42 +- third_party/heimdal/lib/hx509/cms.c | 6 +- third_party/heimdal/lib/hx509/collector.c | 3 +- third_party/heimdal/lib/hx509/crypto.c | 4 + third_party/heimdal/lib/hx509/error.c | 66 +- third_party/heimdal/lib/hx509/file.c | 12 +- third_party/heimdal/lib/hx509/hxtool.c | 28 +- third_party/heimdal/lib/hx509/keyset.c | 5 +- third_party/heimdal/lib/hx509/ks_file.c | 29 +- third_party/heimdal/lib/hx509/name.c | 71 +- third_party/heimdal/lib/hx509/print.c | 5 + third_party/heimdal/lib/hx509/req.c | 22 +- third_party/heimdal/lib/hx509/revoke.c | 4 + third_party/heimdal/lib/hx509/sel-gram.y | 4 + third_party/heimdal/lib/hx509/softp11.c | 8 +- third_party/heimdal/lib/ipc/Makefile.am | 4 + third_party/heimdal/lib/ipc/server.c | 15 +- third_party/heimdal/lib/kadm5/ad.c | 2 + third_party/heimdal/lib/kadm5/chpass_s.c | 56 +- third_party/heimdal/lib/kadm5/context_s.c | 16 +- third_party/heimdal/lib/kadm5/create_s.c | 32 +- third_party/heimdal/lib/kadm5/delete_s.c | 8 +- third_party/heimdal/lib/kadm5/ent_setup.c | 78 +- third_party/heimdal/lib/kadm5/get_princs_s.c | 8 +- third_party/heimdal/lib/kadm5/get_s.c | 143 +- third_party/heimdal/lib/kadm5/init_c.c | 12 +- third_party/heimdal/lib/kadm5/init_s.c | 6 +- third_party/heimdal/lib/kadm5/iprop-log.c | 67 +- third_party/heimdal/lib/kadm5/ipropd_common.c | 1 + third_party/heimdal/lib/kadm5/ipropd_master.c | 31 +- third_party/heimdal/lib/kadm5/ipropd_slave.c | 8 +- third_party/heimdal/lib/kadm5/log.c | 172 ++- third_party/heimdal/lib/kadm5/marshall.c | 254 ++-- third_party/heimdal/lib/kadm5/modify_s.c | 12 +- third_party/heimdal/lib/kadm5/prune_s.c | 10 +- third_party/heimdal/lib/kadm5/randkey_c.c | 2 +- third_party/heimdal/lib/kadm5/randkey_s.c | 26 +- third_party/heimdal/lib/kadm5/rename_s.c | 32 +- third_party/heimdal/lib/kadm5/set_keys.c | 2 + third_party/heimdal/lib/kadm5/setkey3_s.c | 28 +- third_party/heimdal/lib/kafs/Makefile.am | 2 + third_party/heimdal/lib/kafs/afskrb5.c | 2 - third_party/heimdal/lib/kafs/afssys.c | 2 + third_party/heimdal/lib/kafs/rxkad_kdf.c | 8 +- third_party/heimdal/lib/krb5/Makefile.am | 4 +- third_party/heimdal/lib/krb5/NTMakefile | 2 + third_party/heimdal/lib/krb5/acache.c | 27 +- third_party/heimdal/lib/krb5/acl.c | 2 +- third_party/heimdal/lib/krb5/addr_families.c | 19 +- third_party/heimdal/lib/krb5/aes-test.c | 22 +- third_party/heimdal/lib/krb5/asn1_glue.c | 94 +- third_party/heimdal/lib/krb5/auth_context.c | 5 +- third_party/heimdal/lib/krb5/cache.c | 25 +- third_party/heimdal/lib/krb5/context.c | 15 +- third_party/heimdal/lib/krb5/crypto-evp.c | 7 +- third_party/heimdal/lib/krb5/crypto.c | 7 +- third_party/heimdal/lib/krb5/data.c | 7 +- third_party/heimdal/lib/krb5/dcache.c | 14 +- third_party/heimdal/lib/krb5/deprecated.c | 10 +- third_party/heimdal/lib/krb5/enomem.c | 2 +- third_party/heimdal/lib/krb5/error_string.c | 19 +- third_party/heimdal/lib/krb5/expand_path.c | 4 +- third_party/heimdal/lib/krb5/fast.c | 13 +- third_party/heimdal/lib/krb5/fcache.c | 15 +- .../heimdal/lib/krb5/generate_subkey.c | 2 +- third_party/heimdal/lib/krb5/get_cred.c | 54 +- third_party/heimdal/lib/krb5/get_in_tkt.c | 2 +- third_party/heimdal/lib/krb5/init_creds_pw.c | 147 +- third_party/heimdal/lib/krb5/kcm.c | 267 +++- third_party/heimdal/lib/krb5/keytab.c | 68 +- third_party/heimdal/lib/krb5/keytab_file.c | 3 +- third_party/heimdal/lib/krb5/keytab_keyfile.c | 2 +- third_party/heimdal/lib/krb5/krb5.conf.5 | 6 - third_party/heimdal/lib/krb5/krb5.h | 116 +- third_party/heimdal/lib/krb5/krb5_locl.h | 2 + third_party/heimdal/lib/krb5/krbhst-test.c | 17 +- third_party/heimdal/lib/krb5/krbhst.c | 24 +- third_party/heimdal/lib/krb5/krcache.c | 31 +- third_party/heimdal/lib/krb5/kx509.c | 62 +- .../heimdal/lib/krb5/libkrb5-exports.def.in | 7 + third_party/heimdal/lib/krb5/mcache.c | 4 +- third_party/heimdal/lib/krb5/mk_cred.c | 15 +- third_party/heimdal/lib/krb5/pac.c | 137 +- third_party/heimdal/lib/krb5/pkinit.c | 21 +- third_party/heimdal/lib/krb5/principal.c | 33 +- third_party/heimdal/lib/krb5/rd_cred.c | 2 +- third_party/heimdal/lib/krb5/rd_req.c | 66 +- third_party/heimdal/lib/krb5/replay.c | 4 +- third_party/heimdal/lib/krb5/salt-arcfour.c | 6 +- third_party/heimdal/lib/krb5/scache.c | 91 +- third_party/heimdal/lib/krb5/send_to_kdc.c | 14 +- third_party/heimdal/lib/krb5/sp800-108-kdf.c | 5 +- third_party/heimdal/lib/krb5/store.c | 24 +- third_party/heimdal/lib/krb5/store_emem.c | 25 +- third_party/heimdal/lib/krb5/store_stdio.c | 2 + third_party/heimdal/lib/krb5/test_alname.c | 2 +- third_party/heimdal/lib/krb5/test_ap-req.c | 1 + third_party/heimdal/lib/krb5/test_cc.c | 10 +- third_party/heimdal/lib/krb5/test_hostname.c | 4 +- third_party/heimdal/lib/krb5/test_rfc3961.c | 1 + third_party/heimdal/lib/krb5/test_set_kvno0.c | 5 +- third_party/heimdal/lib/krb5/ticket.c | 91 +- third_party/heimdal/lib/krb5/transited.c | 19 +- third_party/heimdal/lib/krb5/verify_user.c | 13 +- .../heimdal/lib/krb5/version-script.map | 7 + third_party/heimdal/lib/ntlm/digest.c | 2 +- third_party/heimdal/lib/ntlm/ntlm.c | 75 +- third_party/heimdal/lib/otp/otp_md.c | 4 +- third_party/heimdal/lib/roken/Makefile.am | 6 +- third_party/heimdal/lib/roken/base32-test.c | 3 +- third_party/heimdal/lib/roken/base32.c | 12 +- third_party/heimdal/lib/roken/base64-test.c | 3 +- third_party/heimdal/lib/roken/base64.c | 4 +- third_party/heimdal/lib/roken/copyhostent.c | 3 +- third_party/heimdal/lib/roken/detach.c | 3 +- third_party/heimdal/lib/roken/dirent-test.c | 6 +- third_party/heimdal/lib/roken/environment.c | 15 +- third_party/heimdal/lib/roken/fnmatch.c | 2 +- third_party/heimdal/lib/roken/freeaddrinfo.c | 2 +- third_party/heimdal/lib/roken/freehostent.c | 2 +- third_party/heimdal/lib/roken/getaddrinfo.c | 10 +- third_party/heimdal/lib/roken/getcap.c | 996 ------------- .../heimdal/lib/roken/getipnodebyaddr.c | 2 +- .../heimdal/lib/roken/getipnodebyname.c | 2 +- third_party/heimdal/lib/roken/getnameinfo.c | 8 +- third_party/heimdal/lib/roken/getuserinfo.c | 30 +- third_party/heimdal/lib/roken/hex-test.c | 35 +- third_party/heimdal/lib/roken/hex.c | 28 +- third_party/heimdal/lib/roken/mergesort_r.c | 4 +- third_party/heimdal/lib/roken/ndbm_wrap.c | 2 + third_party/heimdal/lib/roken/net_write.c | 7 +- third_party/heimdal/lib/roken/resolve-test.c | 2 +- third_party/heimdal/lib/roken/roken-common.h | 6 + third_party/heimdal/lib/roken/roken.h.in | 60 +- third_party/heimdal/lib/roken/snprintf.c | 2 +- third_party/heimdal/lib/roken/socket.c | 29 +- third_party/heimdal/lib/roken/strftime.c | 7 +- third_party/heimdal/lib/roken/strptime.c | 2 +- third_party/heimdal/lib/roken/strtoll.c | 3 + third_party/heimdal/lib/roken/strtoull.c | 3 + .../heimdal/lib/roken/test-getuserinfo.c | 3 +- .../heimdal/lib/roken/test-mini_inetd.c | 2 +- third_party/heimdal/lib/roken/timeval.c | 215 ++- .../heimdal/lib/roken/version-script.map | 5 +- third_party/heimdal/lib/roken/vis.c | 17 +- third_party/heimdal/lib/sl/Makefile.am | 2 +- third_party/heimdal/lib/sl/sl.c | 2 + third_party/heimdal/lib/sl/slc-gram.y | 1 + third_party/heimdal/lib/wind/idn-lookup.c | 6 +- third_party/heimdal/lib/wind/utf8.c | 18 +- .../packages/windows/installer/NTMakefile | 33 +- .../windows/installer/heimdal-installer.wxs | 20 +- third_party/heimdal/tests/bin/setup-env.in | 1 + third_party/heimdal/tests/gss/Makefile.am | 2 + third_party/heimdal/tests/gss/check-basic.in | 4 +- .../heimdal/tests/gss/check-context.in | 12 +- .../heimdal/tests/gss/check-gssmask.in | 4 +- third_party/heimdal/tests/gss/check-ntlm.in | 4 +- third_party/heimdal/tests/gss/check-spnego.in | 4 +- third_party/heimdal/tests/gss/krb5.conf.in | 15 + third_party/heimdal/tests/java/check-kinit.in | 2 +- third_party/heimdal/tests/kdc/Makefile.am | 32 +- third_party/heimdal/tests/kdc/check-bx509.in | 5 +- third_party/heimdal/tests/kdc/check-canon.in | 2 +- third_party/heimdal/tests/kdc/check-cc.in | 47 +- .../heimdal/tests/kdc/check-delegation.in | 2 +- third_party/heimdal/tests/kdc/check-des.in | 2 +- third_party/heimdal/tests/kdc/check-digest.in | 2 +- third_party/heimdal/tests/kdc/check-fast.in | 2 +- .../heimdal/tests/kdc/check-hdb-mitdb.in | 2 +- .../heimdal/tests/kdc/check-httpkadmind.in | 2 +- third_party/heimdal/tests/kdc/check-iprop.in | 2 +- third_party/heimdal/tests/kdc/check-kadmin.in | 2 +- third_party/heimdal/tests/kdc/check-kdc.in | 9 +- third_party/heimdal/tests/kdc/check-kinit.in | 2 +- .../heimdal/tests/kdc/check-kpasswdd.in | 2 +- third_party/heimdal/tests/kdc/check-pkinit.in | 4 +- .../heimdal/tests/kdc/check-referral.in | 2 +- third_party/heimdal/tests/kdc/check-tester.in | 3 + third_party/heimdal/tests/kdc/check-uu.in | 2 +- .../heimdal/tests/kdc/krb5-kcm.conf.in | 165 +++ third_party/heimdal/tests/kdc/krb5.conf.in | 3 + third_party/heimdal/tests/ldap/check-ldap.in | 2 +- third_party/heimdal/tests/plugin/Makefile.am | 6 +- third_party/heimdal/tests/plugin/check-pac.in | 6 +- .../heimdal/tests/plugin/kdc_test_plugin.c | 207 +++ third_party/heimdal/tests/plugin/krb5.conf.in | 15 + third_party/heimdal/tests/plugin/windc.c | 161 --- third_party/heimdal/windows/NTMakefile.sdk | 130 ++ third_party/heimdal/windows/NTMakefile.w32 | 7 +- 428 files changed, 14519 insertions(+), 7392 deletions(-) delete mode 100644 third_party/heimdal/.github/workflows/build.yml create mode 100644 third_party/heimdal/cf/ax_check_sign.m4 create mode 100644 third_party/heimdal/cf/check-compile-flag.m4 create mode 100644 third_party/heimdal/kdc/kdc-accessors.h rename third_party/heimdal/kdc/{rx.h => kdc-audit.h} (50%) create mode 100644 third_party/heimdal/kdc/kdc-plugin.c create mode 100644 third_party/heimdal/kdc/kdc-plugin.h create mode 100644 third_party/heimdal/kdc/mssfu.c delete mode 100644 third_party/heimdal/kdc/windc.c delete mode 100644 third_party/heimdal/kdc/windc_plugin.h create mode 100644 third_party/heimdal/lib/asn1/MANUAL.md create mode 100644 third_party/heimdal/lib/asn1/check-gen.h create mode 100644 third_party/heimdal/lib/gssapi/krb5/name_attrs.c create mode 100644 third_party/heimdal/lib/hdb/hdb.opt delete mode 100644 third_party/heimdal/lib/roken/getcap.c create mode 100644 third_party/heimdal/tests/kdc/krb5-kcm.conf.in create mode 100644 third_party/heimdal/tests/plugin/kdc_test_plugin.c delete mode 100644 third_party/heimdal/tests/plugin/windc.c create mode 100644 third_party/heimdal/windows/NTMakefile.sdk diff --git a/third_party/heimdal/.github/workflows/build.yml b/third_party/heimdal/.github/workflows/build.yml deleted file mode 100644 index c9d4d9e79815..000000000000 --- a/third_party/heimdal/.github/workflows/build.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Build - -on: - push: {paths: [src/**, .github/workflows/build.yml]} - pull_request: {paths: [src/**, .github/workflows/build.yml]} - -jobs: - - unix: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - name: [linux-clang, linux-gcc] - include: - - name: linux-clang - os: ubuntu-18.04 - compiler: clang - - name: linux-gcc - os: ubuntu-18.04 - compiler: gcc - steps: - - name: Clone repository - uses: actions/checkout@v1 - - name: Install packages - if: startsWith(matrix.os, 'ubuntu') - run: | - sudo apt-get update -qq - sudo apt-get install -y bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev jq valgrind - # Temporary workaround for: - # https://github.com/actions/virtual-environments/issues/3185 - sudo hostname localhost - - name: Build - env: - CC: ${{ matrix.compiler }} - MAKEVARS: ${{ matrix.makevars }} - CONFIGURE_OPTS: ${{ matrix.configureopts }} - run: | - /bin/sh ./autogen.sh - mkdir build - cd build - ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" - ulimit -c unlimited - make -j4 - make check - make install - - name: Valgrind output - run: | - find . -name \*.log -print0|xargs -0 grep '^==[1-9]' || true - - name: Core dump stacks - run: | - echo "thread apply all bt" > /tmp/x - find . -name core -print | while read core; do gdb -batch -x x `file "$core"|sed -e "s/^[^']*'//" -e "s/[ '].*$//"` "$core"; done - if [ "$(find . -name core -print | wc -l)" -gt 0 ]; then false; fi - - name: Test logs - if: ${{ failure() }} - run: | - find build -name \*.trs|xargs grep -lw FAIL|sed -e 's/trs$/log/'|xargs cat - - name: distclean - run: | - cd build - make distclean - if [ "$(git ls-files -o|grep -v ^build/ | wc -l)" -ne 0 ]; then - echo "Files not removed by make distclean:" - git ls-files -o|grep -v ^build/ - fi - diff --git a/third_party/heimdal/.gitignore b/third_party/heimdal/.gitignore index 2a09f94ac80d..e5b52468af54 100644 --- a/third_party/heimdal/.gitignore +++ b/third_party/heimdal/.gitignore @@ -15,20 +15,17 @@ Makefile Makefile.in rs_state.ini -asn1_*.[cx] tags !/lib/asn1/asn1_gen.c !/lib/asn1/asn1_print.c !/lib/krb5/asn1_glue.c *_asn1.h !/lib/asn1/heim_asn1.h -*_asn1.hx *_asn1-priv.h -*_asn1-priv.hx -*_asn1-template.c -*_asn1-template.x +asn1_*_asn1.c *_asn1_files *_asn1_oids.x +*_asn1_syms.x *_err.[ch] !/lib/com_err/com_err.[ch] *-commands.[ch] @@ -153,6 +150,9 @@ tags /kdc/kdc-tester /kdc/kstash /kdc/string2key +/kdc/test_csr_authorizer +/kdc/test_kdc_ca +/kdc/test_token_validator /kpasswd/kpasswd /kpasswd/kpasswd-generator /kpasswd/kpasswdd @@ -176,13 +176,106 @@ tags /lib/asn1/check-ber /lib/asn1/check-der /lib/asn1/check-gen +/lib/asn1/check-gen-template /lib/asn1/check-template /lib/asn1/check-timegm -/lib/asn1/der-protos.h +/lib/asn1/cms_asn1.json +/lib/asn1/cms_asn1_oids.c +/lib/asn1/cms_asn1_syms.c +/lib/asn1/cms_template_asn1.json +/lib/asn1/cms_template_asn1_oids.c +/lib/asn1/cms_template_asn1_syms.c +/lib/asn1/crmf_asn1.json +/lib/asn1/crmf_asn1_oids.c +/lib/asn1/crmf_asn1_syms.c +/lib/asn1/crmf_template_asn1.json +/lib/asn1/crmf_template_asn1_oids.c +/lib/asn1/crmf_template_asn1_syms.c /lib/asn1/der-private.h +/lib/asn1/der-protos.h +/lib/asn1/digest_asn1.json +/lib/asn1/digest_asn1_oids.c +/lib/asn1/digest_asn1_syms.c +/lib/asn1/digest_template_asn1.json +/lib/asn1/digest_template_asn1_oids.c +/lib/asn1/digest_template_asn1_syms.c +/lib/asn1/krb5_asn1.json +/lib/asn1/krb5_asn1_oids.c +/lib/asn1/krb5_asn1_syms.c +/lib/asn1/krb5_template_asn1.json +/lib/asn1/krb5_template_asn1_oids.c +/lib/asn1/krb5_template_asn1_syms.c +/lib/asn1/kx509_asn1.json +/lib/asn1/kx509_asn1_oids.c +/lib/asn1/kx509_asn1_syms.c +/lib/asn1/kx509_template_asn1.json +/lib/asn1/kx509_template_asn1_oids.c +/lib/asn1/kx509_template_asn1_syms.c /lib/asn1/lex.c +/lib/asn1/ocsp_asn1.json +/lib/asn1/ocsp_asn1_oids.c +/lib/asn1/ocsp_asn1_syms.c +/lib/asn1/ocsp_template_asn1.json +/lib/asn1/ocsp_template_asn1_oids.c +/lib/asn1/ocsp_template_asn1_syms.c +/lib/asn1/pkcs10_asn1.json +/lib/asn1/pkcs10_asn1_oids.c +/lib/asn1/pkcs10_asn1_syms.c +/lib/asn1/pkcs10_template_asn1.json +/lib/asn1/pkcs10_template_asn1_oids.c +/lib/asn1/pkcs10_template_asn1_syms.c +/lib/asn1/pkcs12_asn1.json +/lib/asn1/pkcs12_asn1_oids.c +/lib/asn1/pkcs12_asn1_syms.c +/lib/asn1/pkcs12_template_asn1.json +/lib/asn1/pkcs12_template_asn1_oids.c +/lib/asn1/pkcs12_template_asn1_syms.c +/lib/asn1/pkcs8_asn1.json +/lib/asn1/pkcs8_asn1_oids.c +/lib/asn1/pkcs8_asn1_syms.c +/lib/asn1/pkcs8_template_asn1.json +/lib/asn1/pkcs8_template_asn1_oids.c +/lib/asn1/pkcs8_template_asn1_syms.c +/lib/asn1/pkcs9_asn1.json +/lib/asn1/pkcs9_asn1_oids.c +/lib/asn1/pkcs9_asn1_syms.c +/lib/asn1/pkcs9_template_asn1.json +/lib/asn1/pkcs9_template_asn1_oids.c +/lib/asn1/pkcs9_template_asn1_syms.c +/lib/asn1/pkinit_asn1.json +/lib/asn1/pkinit_asn1_oids.c +/lib/asn1/pkinit_asn1_syms.c +/lib/asn1/pkinit_template_asn1.json +/lib/asn1/pkinit_template_asn1_oids.c +/lib/asn1/pkinit_template_asn1_syms.c +/lib/asn1/rfc2459_asn1.json +/lib/asn1/rfc2459_asn1_oids.c +/lib/asn1/rfc2459_asn1_syms.c +/lib/asn1/rfc2459_template_asn1.json +/lib/asn1/rfc2459_template_asn1_oids.c +/lib/asn1/rfc2459_template_asn1_syms.c +/lib/asn1/rfc4108_asn1.json +/lib/asn1/rfc4108_asn1_oids.c +/lib/asn1/rfc4108_asn1_syms.c +/lib/asn1/rfc4108_template_asn1.json +/lib/asn1/rfc4108_template_asn1_oids.c +/lib/asn1/rfc4108_template_asn1_syms.c +/lib/asn1/test_asn1.json +/lib/asn1/test_asn1_oids.c +/lib/asn1/test_asn1_syms.c +/lib/asn1/test_template_asn1.json +/lib/asn1/test_template_asn1_oids.c +/lib/asn1/test_template_asn1_syms.c +/lib/asn1/x690sample_asn1.json +/lib/asn1/x690sample_asn1_oids.c +/lib/asn1/x690sample_asn1_syms.c +/lib/asn1/x690sample_template_asn1.json +/lib/asn1/x690sample_template_asn1_oids.c +/lib/asn1/x690sample_template_asn1_syms.c /lib/auth/Makefile.in /lib/base/base64.c +/lib/base/heimbase-protos.h +/lib/base/json-journal /lib/base/test_base /lib/base/test_db.json /lib/com_err/compile_et @@ -191,12 +284,31 @@ tags /lib/com_err/parse.h /lib/com_err/snprintf.c /lib/com_err/strlcpy.c -/lib/gssapi/gss +/lib/gssapi/asn1_ContextFlags.c +/lib/gssapi/asn1_GSSAPIContextToken.c +/lib/gssapi/asn1_MechType.c +/lib/gssapi/asn1_MechTypeList.c +/lib/gssapi/asn1_NegHints.c +/lib/gssapi/asn1_NegStateEnum.c +/lib/gssapi/asn1_NegTokenInit.c +/lib/gssapi/asn1_NegTokenInit2.c +/lib/gssapi/asn1_NegTokenResp.c +/lib/gssapi/asn1_NegotiationToken.c +/lib/gssapi/asn1_NegotiationToken2.c +/lib/gssapi/gss-token +/lib/gssapi/gssapi_asn1-template.c +/lib/gssapi/gssapi_asn1.json +/lib/gssapi/gssapi_asn1_oids.c +/lib/gssapi/gssapi_asn1_syms.c /lib/gssapi/gsstool /lib/gssapi/krb5/gsskrb5-private.h /lib/gssapi/ntlm/ntlm-private.h /lib/gssapi/sanon/sanon-private.h /lib/gssapi/spnego/spnego-private.h +/lib/gssapi/spnego_asn1-template.c +/lib/gssapi/spnego_asn1.json +/lib/gssapi/spnego_asn1_oids.c +/lib/gssapi/spnego_asn1_syms.c /lib/gssapi/test_acquire_cred /lib/gssapi/test_add_store_cred /lib/gssapi/test_cfx @@ -239,12 +351,44 @@ tags /lib/hcrypto/test_rsa /lib/hcrypto/unix /lib/hcrypto/libtommath/callgraph.txt -/lib/hdb/hdb-protos.h +/lib/hdb/asn1_Event.c +/lib/hdb/asn1_GENERATION.c +/lib/hdb/asn1_HDBFlags.c +/lib/hdb/asn1_HDB_EncTypeList.c +/lib/hdb/asn1_HDB_EntryOrAlias.c +/lib/hdb/asn1_HDB_Ext_Aliases.c +/lib/hdb/asn1_HDB_Ext_Constrained_delegation_acl.c +/lib/hdb/asn1_HDB_Ext_KeyRotation.c +/lib/hdb/asn1_HDB_Ext_KeySet.c +/lib/hdb/asn1_HDB_Ext_Lan_Manager_OWF.c +/lib/hdb/asn1_HDB_Ext_PKINIT_acl.c +/lib/hdb/asn1_HDB_Ext_PKINIT_cert.c +/lib/hdb/asn1_HDB_Ext_PKINIT_hash.c +/lib/hdb/asn1_HDB_Ext_Password.c +/lib/hdb/asn1_HDB_entry.c +/lib/hdb/asn1_HDB_entry_alias.c +/lib/hdb/asn1_HDB_extension.c +/lib/hdb/asn1_HDB_extensions.c +/lib/hdb/asn1_HDB_keyset.c +/lib/hdb/asn1_Key.c +/lib/hdb/asn1_KeyRotation.c +/lib/hdb/asn1_KeyRotationFlags.c +/lib/hdb/asn1_Keys.c +/lib/hdb/asn1_Salt.c /lib/hdb/hdb-private.h +/lib/hdb/hdb-protos.h +/lib/hdb/hdb_asn1-template.c +/lib/hdb/hdb_asn1.json +/lib/hdb/hdb_asn1_oids.c +/lib/hdb/hdb_asn1_syms.c +/lib/hdb/test_concurrency /lib/hdb/test_dbinfo /lib/hdb/test_hdbkeys -/lib/hdb/test_namespace /lib/hdb/test_mkey +/lib/hdb/test_namespace +/lib/hdb/testhdb-*-shm +/lib/hdb/testhdb-*-wal +/lib/hx509/actual /lib/hx509/PKITS_data/ /lib/hx509/cert-ca.der /lib/hx509/cert-ca.pem @@ -258,6 +402,7 @@ tags /lib/hx509/data/*.srl /lib/hx509/data/*.req /lib/hx509/data/sub-ca-combined.crt +/lib/hx509/expected /lib/hx509/ev.data /lib/hx509/ev.data.out /lib/hx509/hx509-private.h @@ -341,6 +486,7 @@ tags /lib/krb5/test_hostname /lib/krb5/test_keytab /lib/krb5/test_mem +/lib/krb5/test_mkforwardable /lib/krb5/test_pac /lib/krb5/test_pkinit_dh2key /lib/krb5/test_pknistkdf @@ -369,10 +515,10 @@ tags /lib/otp/strlcpy.c /lib/otp/strlwr.c /lib/otp/strncasecmp.c +/lib/roken/base32-test /lib/roken/base64-test /lib/roken/getaddrinfo-test /lib/roken/getifaddrs-test -/lib/roken/glob.h /lib/roken/hex-test /lib/roken/make-roken /lib/roken/make-roken.c @@ -380,10 +526,13 @@ tags /lib/roken/parse_reply-test /lib/roken/parse_time-test /lib/roken/resolve-test +/lib/roken/rkbase32 +/lib/roken/rkbase64 /lib/roken/rkpty +/lib/roken/rkvis /lib/roken/roken.h +/lib/roken/rtbl /lib/roken/snprintf-test -/lib/roken/snprintf-test.trs /lib/roken/strpftime-test /lib/roken/test-auxval /lib/roken/test-detach @@ -415,6 +564,7 @@ tags /lib/wind/normalize_table.h /lib/wind/punycode_examples.c /lib/wind/punycode_examples.h +/lib/wind/__pycache__/ /lib/wind/test-bidi /lib/wind/test-ldap /lib/wind/test-map @@ -453,33 +603,29 @@ tags /tests/gss/check-context /tests/gss/check-gss /tests/gss/check-gssmask +/tests/gss/check-negoex /tests/gss/check-ntlm /tests/gss/check-spnego /tests/gss/current-db.db /tests/gss/foopassword /tests/gss/krb5.conf -/tests/gss/krb5ccfile* -/tests/gss/krb5ccfile2* -/tests/gss/krb5ccfile-ds* +/tests/gss/krb5ccfile +/tests/gss/krb5ccfile-ds +/tests/gss/krb5ccfile2 +/tests/gss/mech +/tests/gss/new_clients_k5.conf /tests/gss/server.keytab /tests/gss/tempfile -/tests/java/KerberosInit$1.class -/tests/java/KerberosInit$TestCallBackHandler.class -/tests/java/KerberosInit.class /tests/java/check-kinit -/tests/java/current-db.db -/tests/java/foopassword -/tests/java/jgssapi_server.class -/tests/java/server.keytab /tests/java/krb5.conf -/tests/kdc/acache.krb5* +/tests/kdc/acache.krb5 /tests/kdc/barpassword -/tests/kdc/ca.crt -/tests/kdc/cache.krb5* -/tests/kdc/cache1.krb5* -/tests/kdc/cache2.krb5* +/tests/kdc/bx509.pem +/tests/kdc/cache.krb5 +/tests/kdc/cc_dir/ /tests/kdc/cdigest-reply /tests/kdc/check-authz +/tests/kdc/check-bx509 /tests/kdc/check-canon /tests/kdc/check-cc /tests/kdc/check-delegation @@ -487,6 +633,7 @@ tags /tests/kdc/check-digest /tests/kdc/check-fast /tests/kdc/check-hdb-mitdb +/tests/kdc/check-httpkadmind /tests/kdc/check-iprop /tests/kdc/check-kadmin /tests/kdc/check-kdc @@ -498,51 +645,62 @@ tags /tests/kdc/check-tester /tests/kdc/check-uu /tests/kdc/current-db.db -/tests/kdc/current.log.save /tests/kdc/current-db.sqlite3 +/tests/kdc/current-db.sqlite3-shm +/tests/kdc/current-db.sqlite3-wal +/tests/kdc/current.log.save +/tests/kdc/email.pem /tests/kdc/foopassword /tests/kdc/foopassword.rkpty +/tests/kdc/icache.krb5 /tests/kdc/iprop-stats +/tests/kdc/iprop-stats2 /tests/kdc/iprop.keytab /tests/kdc/ipropd.dumpfile -/tests/kdc/kdc.crt +/tests/kdc/k.der /tests/kdc/kdc-tester4.json +/tests/kdc/kdc.pid /tests/kdc/krb5-authz.conf /tests/kdc/krb5-authz2.conf +/tests/kdc/krb5-bx509.conf /tests/kdc/krb5-canon.conf /tests/kdc/krb5-canon2.conf +/tests/kdc/krb5-cccol.conf /tests/kdc/krb5-hdb-mitdb.conf +/tests/kdc/krb5-httpkadmind.conf +/tests/kdc/krb5-master2.conf /tests/kdc/krb5-pkinit-win.conf /tests/kdc/krb5-pkinit.conf +/tests/kdc/krb5-pkinit2.conf /tests/kdc/krb5-slave.conf /tests/kdc/krb5-slave2.conf /tests/kdc/krb5-weak.conf /tests/kdc/krb5.conf -/tests/kdc/krb5-cc.conf /tests/kdc/krb5.conf.keys -/tests/kdc/kx509-template.crt -/tests/kdc/kx509.pem /tests/kdc/localname +/tests/kdc/messages.log2 +/tests/kdc/mixed-issuer.pem /tests/kdc/notfoopassword /tests/kdc/o2cache.krb5 /tests/kdc/ocache.krb5 -/tests/kdc/pkinit.crt -/tests/kdc/pkinit2.crt -/tests/kdc/pkinit3.crt -/tests/kdc/pkinit4.crt -/tests/kdc/req-kdc.der -/tests/kdc/req-pkinit.der -/tests/kdc/req-pkinit2.der +/tests/kdc/pkinit-anchor.pem +/tests/kdc/req /tests/kdc/s2digest-reply +/tests/kdc/sdb /tests/kdc/sdigest-init /tests/kdc/sdigest-reply +/tests/kdc/server-issuer.pem /tests/kdc/server.keytab +/tests/kdc/server.pem +/tests/kdc/simple_csr_authz/ /tests/kdc/tempfile /tests/kdc/test-rc-file.rc +/tests/kdc/trivial.pem +/tests/kdc/user-issuer.pem /tests/ldap/check-ldap /tests/ldap/krb5.conf /tests/ldap/slapd-init -/tests/plugin/cache.krb5* +/tests/plugin/cache.krb5 /tests/plugin/check-pac /tests/plugin/current-db.db /tests/plugin/foopassword diff --git a/third_party/heimdal/Makefile.am b/third_party/heimdal/Makefile.am index 7fb69fdf4e08..b9bdcf4995e5 100644 --- a/third_party/heimdal/Makefile.am +++ b/third_party/heimdal/Makefile.am @@ -45,7 +45,6 @@ EXTRA_DIST = \ cf/ChangeLog \ cf/have-pragma-weak.m4 \ cf/have-types.m4 \ - cf/krb-func-getcwd-broken.m4 \ cf/krb-prog-ranlib.m4 \ cf/krb-prog-yacc.m4 \ cf/krb-sys-aix.m4 \ diff --git a/third_party/heimdal/README.md b/third_party/heimdal/README.md index bf9fca2a7be9..5e49fd0e1a4d 100644 --- a/third_party/heimdal/README.md +++ b/third_party/heimdal/README.md @@ -1,4 +1,6 @@ -[![Travis-CI build (Linux, OS X)](https://travis-ci.org/heimdal/heimdal.svg?branch=master)](https://travis-ci.org/heimdal/heimdal#) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/linux.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Alinux) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/osx.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Aosx) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/windows.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Awindows) [![Appveyor-CI build (Windows)](https://ci.appveyor.com/api/projects/status/6j0k0m7kd6jjj4tw/branch/master?svg=true)](https://ci.appveyor.com/project/heimdal/heimdal/branch/master) [![Coverage Status](https://coveralls.io/repos/github/heimdal/heimdal/badge.svg?branch=master)](https://coveralls.io/github/heimdal/heimdal?branch=master) @@ -30,5 +32,8 @@ respectively to subscribe. Build Status ============ -[![Travis-CI build (Linux, OS X)](https://travis-ci.org/heimdal/heimdal.svg?branch=master)](https://travis-ci.org/heimdal/heimdal#) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/linux.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Alinux) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/osx.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Aosx) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/windows.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Awindows) [![Appveyor-CI build (Windows)](https://ci.appveyor.com/api/projects/status/6j0k0m7kd6jjj4tw/branch/master?svg=true)](https://ci.appveyor.com/project/heimdal/heimdal/branch/master) +[![Coverage Status](https://coveralls.io/repos/github/heimdal/heimdal/badge.svg?branch=master)](https://coveralls.io/github/heimdal/heimdal?branch=master) diff --git a/third_party/heimdal/admin/change.c b/third_party/heimdal/admin/change.c index a46d484c18f0..b9d0e830d388 100644 --- a/third_party/heimdal/admin/change.c +++ b/third_party/heimdal/admin/change.c @@ -261,7 +261,6 @@ kt_change(struct change_options *opt, int argc, char **argv) krb5_kt_end_seq_get(context, keytab, &cursor); if (ret == KRB5_KT_END) { - ret = 0; for (i = 0; i < j; i++) { if (verbose_flag) { char *client_name; diff --git a/third_party/heimdal/appl/afsutil/afslog.c b/third_party/heimdal/appl/afsutil/afslog.c index f2ade9425ea8..05078ee8e1fe 100644 --- a/third_party/heimdal/appl/afsutil/afslog.c +++ b/third_party/heimdal/appl/afsutil/afslog.c @@ -118,7 +118,7 @@ expand_cell_name(const char *cell) if(c) return c; } - return cell; + return NULL; } static void diff --git a/third_party/heimdal/appl/gssmask/gssmask.c b/third_party/heimdal/appl/gssmask/gssmask.c index 35c548979a6f..44b59fe5eb90 100644 --- a/third_party/heimdal/appl/gssmask/gssmask.c +++ b/third_party/heimdal/appl/gssmask/gssmask.c @@ -951,7 +951,9 @@ HandleOP(WrapExt) memcpy(p, iov[4].buffer.value, iov[4].buffer.length); p += iov[4].buffer.length; memcpy(p, iov[5].buffer.value, iov[5].buffer.length); +#if 0 /* Would be needed to keep going, but presently unused */ p += iov[5].buffer.length; +#endif gss_release_iov_buffer(NULL, iov, iov_len); diff --git a/third_party/heimdal/appl/kf/kf.c b/third_party/heimdal/appl/kf/kf.c index ecef93965ac1..fd4f174988ea 100644 --- a/third_party/heimdal/appl/kf/kf.c +++ b/third_party/heimdal/appl/kf/kf.c @@ -312,7 +312,9 @@ doit (const char *hostname, int port, const char *svc, continue; } freeaddrinfo (ai); - return proto (s, hostname, svc, message, len); + error = proto(s, hostname, svc, message, len); + close(s); + return error; } warnx ("failed to contact %s", hostname); freeaddrinfo (ai); diff --git a/third_party/heimdal/appl/otp/otp.c b/third_party/heimdal/appl/otp/otp.c index 1ca6a1f61bb8..deb7d303c66b 100644 --- a/third_party/heimdal/appl/otp/otp.c +++ b/third_party/heimdal/appl/otp/otp.c @@ -118,16 +118,22 @@ verify_user_otp(char *username) { OtpContext ctx; char passwd[OTP_MAX_PASSPHRASE + 1]; - char prompt[128], ss[256]; + char ss[256]; + char *prompt = NULL; if (otp_challenge (&ctx, username, ss, sizeof(ss)) != 0) { warnx("no otp challenge found for %s", username); return 1; } - snprintf (prompt, sizeof(prompt), "%s's %s Password: ", username, ss); - if(UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)) + if (asprintf(&prompt, "%s's %s Password: ", username, ss) == -1 || + prompt == NULL) + err(1, "out of memory"); + if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)) { + free(prompt); return 1; + } + free(prompt); return otp_verify_user (&ctx, passwd); } diff --git a/third_party/heimdal/appl/test/gssapi_server.c b/third_party/heimdal/appl/test/gssapi_server.c index 5d2a39dd7c43..baf13ecff5fb 100644 --- a/third_party/heimdal/appl/test/gssapi_server.c +++ b/third_party/heimdal/appl/test/gssapi_server.c @@ -159,6 +159,8 @@ process_it(int sock, input_token, NULL, output_token); + if (GSS_ERROR(maj_stat)) + gss_err(1, min_stat, "gss_wrap"); write_token (sock, output_token); gss_release_buffer (&min_stat, output_token); @@ -184,7 +186,7 @@ proto (int sock, const char *service) gss_name_t client_name; struct gss_channel_bindings_struct input_chan_bindings; gss_cred_id_t delegated_cred_handle = NULL; - krb5_ccache ccache; + krb5_ccache ccache = NULL; u_char init_buf[4]; u_char acct_buf[4]; gss_OID mech_oid; @@ -270,15 +272,21 @@ proto (int sock, const char *service) printf("Using mech: %s\n", mech); if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) { - krb5_context context; + krb5_context context = NULL; printf("Delegated cred found\n"); - maj_stat = krb5_init_context(&context); - maj_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache); - maj_stat = gss_krb5_copy_ccache(&min_stat, - delegated_cred_handle, - ccache); + min_stat = krb5_init_context(&context); + if (min_stat) + gss_err(1, min_stat, "krb5_init_context"); + if (min_stat == 0) + min_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache); + if (min_stat == 0) + maj_stat = gss_krb5_copy_ccache(&min_stat, + delegated_cred_handle, + ccache); + else + maj_stat = GSS_S_FAILURE; if (maj_stat == 0) { krb5_principal p; maj_stat = krb5_cc_get_principal(context, ccache, &p); @@ -293,6 +301,7 @@ proto (int sock, const char *service) } } krb5_cc_close(context, ccache); + krb5_free_context(context); gss_release_cred(&min_stat, &delegated_cred_handle); } diff --git a/third_party/heimdal/appl/test/uu_server.c b/third_party/heimdal/appl/test/uu_server.c index 64a2b1279fae..6e046990b165 100644 --- a/third_party/heimdal/appl/test/uu_server.c +++ b/third_party/heimdal/appl/test/uu_server.c @@ -102,6 +102,8 @@ proto (int sock, const char *service) &in_creds, &out_creds); if(status) krb5_err(context, 1, status, "krb5_get_credentials"); + krb5_cc_close(context, ccache); + ccache = NULL; status = krb5_cc_default(context, &ccache); if(status) @@ -120,6 +122,8 @@ proto (int sock, const char *service) NULL, NULL, NULL); + krb5_cc_close(context, ccache); + ccache = NULL; if (status) krb5_err(context, 1, status, "krb5_sendauth"); @@ -134,6 +138,9 @@ proto (int sock, const char *service) free(str); } + krb5_free_principal(context, in_creds.client); + krb5_free_principal(context, in_creds.server); + krb5_data_zero (&data); krb5_data_zero (&packet); diff --git a/third_party/heimdal/appveyor.yml b/third_party/heimdal/appveyor.yml index bb1e12123e5b..fa56c4c59a66 100644 --- a/third_party/heimdal/appveyor.yml +++ b/third_party/heimdal/appveyor.yml @@ -4,55 +4,51 @@ # users, and is free for public repositories. # +version: '1.0.{build}' + +image: + - Visual Studio 2019 + install: # HACK -- pacman installation in Appveyor seems broken # Taken from https://github.com/johnkerl/miller/blob/master/appveyor.yml - - set PATH=C:\msys64\usr\bin;%PATH% - - bash -lc "curl -Lo pacman-5.2.1-6-x86_64.pkg.tar.xz.sig http://repo.msys2.org/msys/x86_64/pacman-5.2.1-6-x86_64.pkg.tar.xz.sig" - - bash -lc "curl -Lo pacman-5.2.1-6-x86_64.pkg.tar.xz http://repo.msys2.org/msys/x86_64/pacman-5.2.1-6-x86_64.pkg.tar.xz" - - bash -lc "curl -Lo zstd-1.4.4-2-x86_64.pkg.tar.xz.sig http://repo.msys2.org/msys/x86_64/zstd-1.4.4-2-x86_64.pkg.tar.xz.sig" - - bash -lc "curl -Lo zstd-1.4.4-2-x86_64.pkg.tar.xz http://repo.msys2.org/msys/x86_64/zstd-1.4.4-2-x86_64.pkg.tar.xz" - - bash -lc "curl -Lo autoconf-2.69-5-any.pkg.tar.xz.sig http://repo.msys2.org/msys/x86_64/autoconf-2.69-5-any.pkg.tar.xz.sig" - - bash -lc "curl -Lo autoconf-2.69-5-any.pkg.tar.xz http://repo.msys2.org/msys/x86_64/autoconf-2.69-5-any.pkg.tar.xz" - - bash -lc "curl -Lo automake1.16-1.16.2-2-any.pkg.tar.zst.sig http://repo.msys2.org/msys/x86_64/automake1.16-1.16.2-2-any.pkg.tar.zst.sig" - - bash -lc "curl -Lo automake1.16-1.16.2-2-any.pkg.tar.zst http://repo.msys2.org/msys/x86_64/automake1.16-1.16.2-2-any.pkg.tar.zst" - - bash -lc "curl -Lo bison-3.5.4-1-x86_64.pkg.tar.xz.sig http://repo.msys2.org/msys/x86_64/bison-3.5.4-1-x86_64.pkg.tar.xz.sig" - - bash -lc "curl -Lo bison-3.5.4-1-x86_64.pkg.tar.xz http://repo.msys2.org/msys/x86_64/bison-3.5.4-1-x86_64.pkg.tar.xz" - - bash -lc "curl -Lo flex-2.6.4-1-x86_64.pkg.tar.xz.sig http://repo.msys2.org/msys/x86_64/flex-2.6.4-1-x86_64.pkg.tar.xz.sig" - - bash -lc "curl -Lo flex-2.6.4-1-x86_64.pkg.tar.xz http://repo.msys2.org/msys/x86_64/flex-2.6.4-1-x86_64.pkg.tar.xz" - - bash -lc "curl -Lo perl-5.30.2-1-x86_64.pkg.tar.xz.sig http://repo.msys2.org/msys/x86_64/perl-5.30.2-1-x86_64.pkg.tar.xz.sig" - - bash -lc "curl -Lo perl-5.30.2-1-x86_64.pkg.tar.xz http://repo.msys2.org/msys/x86_64/perl-5.30.2-1-x86_64.pkg.tar.xz" - - bash -lc "curl -Lo perl-JSON-4.02-1-any.pkg.tar.zst.sig http://repo.msys2.org/msys/x86_64/perl-JSON-4.02-1-any.pkg.tar.zst.sig" - - bash -lc "curl -Lo perl-JSON-4.02-1-any.pkg.tar.zst http://repo.msys2.org/msys/x86_64/perl-JSON-4.02-1-any.pkg.tar.zst" + # (which is gone) + #- ps: dir 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows' -Recurse + - set "PATH=C:\msys64\usr\bin;%PATH%" + - set "PATH=C:\%MSYS2_DIR%\%MSYSTEM%\bin;C:\%MSYS2_DIR%\usr\bin;%PATH%" + - bash -lc "mkdir -p /var/lib/pacman/sync/" + - bash -lc "pacman-key --init" + - bash -lc "pacman-key --populate msys2" + - bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-1~20211228-1-any.pkg.tar.zst" + - bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-1~20211228-1-any.pkg.tar.zst.sig" + - bash -lc "pacman --noconfirm -U --config <(echo) msys2-keyring-1~20211228-1-any.pkg.tar.zst" + - bash -lc "mkdir -p /var/lib/pacman/sync/" - bash -lc "pacman-key --init" - bash -lc "pacman-key --populate msys2" - - bash -lc "pwd; ls -l" - - bash -lc "pacman-key --verify pacman-5.2.1-6-x86_64.pkg.tar.xz.sig" - - bash -lc "pacman --noconfirm -S zstd || pacman --ask 20 -U file://$PWD/zstd-1.4.4-2-x86_64.pkg.tar.xz" - #- bash -lc "pacman --ask 20 -U file://$PWD/pacman-5.2.1-6-x86_64.pkg.tar.xz" - #- bash -lc "pacman-key --populate zstd" - #- bash -lc "pacman-key --verify zstd-1.4.4-2-x86_64.pkg.tar.xz.sig" - #- bash -lc "pacman --ask 20 -U file://$PWD/zstd-1.4.4-2-x86_64.pkg.tar.xz" - - bash -lc "pacman --noconfirm -S autoconf || pacman --ask 20 -U file://$PWD/autoconf-2.69-5-any.pkg.tar.xz.sig" - - bash -lc "pacman --noconfirm -S automake || pacman --ask 20 -U file://$PWD/automake1.16-1.16.2-2-any.pkg.tar.zst" - - bash -lc "pacman --noconfirm -S flex || pacman --ask 20 -U file://$PWD/flex-2.6.4-1-x86_64.pkg.tar.xz" - - bash -lc "pacman --noconfirm -S bison || pacman --ask 20 -U file://$PWD/bison-3.5.4-1-x86_64.pkg.tar.xz" - - bash -lc "pacman --noconfirm -S perl || pacman --ask 20 -U file://$PWD/perl-5.30.2-1-x86_64.pkg.tar.xz" - - bash -lc "pacman --noconfirm -S perl-JSON || pacman --ask 20 -U file://$PWD/perl-JSON-4.02-1-any.pkg.tar.zst" + - bash -lc "pacman -S --noconfirm --refresh pacman" + - bash -lc "pacman -S --needed --noconfirm pacman-mirrors" + - bash -lc "pacman -S --needed --noconfirm mingw-w64-x86_64-toolchain autoconf automake libtool make patch mingw-w64-x86_64-libtool" + - bash -lc "pacman -S --needed --noconfirm bison flex" + - bash -lc "pacman -S --needed --noconfirm perl perl-JSON" build_script: - - set PSDKDir=C:\Program Files\Microsoft SDKs\Windows\v7.1 - - call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /xp /x64 /Release - - set WIXDIR="c:\Program Files (x86)\Windows Installer XML v3.5" + # build using Windows 10 SDK + - set "WINSDKVER=10.0.22000.0" + - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 %WINSDKVER% + - set "WIXDIR=c:\Program Files (x86)\Windows Installer XML v3.5" # We're not doing any codesigning in the Appveyor build yet. - - SET CODESIGN_PKT=0000000000000000 - - set PATH=%PATH%;C:\Python26;C:\Perl64\bin;C:\tools\cygwin\bin;C:\Program Files (x86)\HTML Help Workshop - - set PATH=%PATH%;C:/msys64/usr/bin - - set PATH=%PATH%;C:\program files (x86)\windows installer xml v3.5\bin;C:\cygwin\bin + - SET "CODESIGN_PKT=0000000000000000" + - set "PATH=%PATH%;C:\Perl64\bin;C:\tools\cygwin\bin;C:\Program Files (x86)\HTML Help Workshop" + - set "PATH=%PATH%;C:/msys64/usr/bin" + - set "PATH=%PATH%;C:\program files (x86)\windows installer xml v3.5\bin;C:\cygwin\bin" + # double check this, should it be x86 or x64? + - set "PATH=%PATH%;%WindowsSdkVerBinPath%\x86" + - set "PATH=C:\Python310-x64;%PATH%" - set dbg__type=Debug - title Heimdal Build %CPU% %dbg__type% - echo PATH=%PATH% - - C:\msys64\usr\bin\bash -lc "cp /c/Windows/System32/msvcr100d.dll /c/projects/heimdal" + # target Windows 10 API + - set APPVER=10.0 # Newer texinfo has no .exe's, so we have to invoke it as # "perl ...\makeinfo ...". See doc/NTMakefile. - nmake /f NTMakefile APPVEYOR=1 MAKEINFO=makeinfo NO_INSTALLERS=1 diff --git a/third_party/heimdal/cf/Makefile.am.common b/third_party/heimdal/cf/Makefile.am.common index 1b134f5b77f6..90921fe46b96 100644 --- a/third_party/heimdal/cf/Makefile.am.common +++ b/third_party/heimdal/cf/Makefile.am.common @@ -12,6 +12,8 @@ endif AM_CFLAGS = $(WFLAGS) +CLANG_FORMAT_STYLE = '{BasedOnStyle: Mozilla, AlwaysBreakAfterReturnType: TopLevelDefinitions, IndentWidth: 4, SortIncludes: false}' + CP = cp ## set build_HEADERZ to headers that should just be installed in build tree @@ -139,22 +141,7 @@ check-local:: test "$$failed" -eq 0 || exit 1; \ fi -SUFFIXES += .x .z .hx - -# It's useful for debugging to format generated sources. The default for all -# clang-format styles is to sort includes, but in many cases in-tree we really -# don't want to do that. -.x.c: - @if [ ! -x "$(CLANG_FORMAT)" ]; then \ - cmp -s $< $@ 2> /dev/null || cp $< $@; \ - else \ - cp $< $@.tmp.c; \ - $(CLANG_FORMAT) -style='{BasedOnStyle: Mozilla, AlwaysBreakAfterReturnType: TopLevelDefinitions, IndentWidth: 4, SortIncludes: false}' -i $@.tmp.c; \ - cmp -s $@.tmp.c $@ 2> /dev/null || mv $@.tmp.c $@; \ - fi - -.hx.h: - @cmp -s $< $@ 2> /dev/null || cp $< $@; +SUFFIXES += .x .z SUFFIXES += .1 .3 .5 .7 .8 .cat1 .cat3 .cat5 .cat7 .cat8 diff --git a/third_party/heimdal/cf/ax_check_sign.m4 b/third_party/heimdal/cf/ax_check_sign.m4 new file mode 100644 index 000000000000..bc2c3f034ce7 --- /dev/null +++ b/third_party/heimdal/cf/ax_check_sign.m4 @@ -0,0 +1,54 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_sign.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_SIGN (TYPE, [ACTION-IF-SIGNED], [ACTION-IF-UNSIGNED], [INCLUDES]) +# +# DESCRIPTION +# +# Checks whether TYPE is signed or not. If no INCLUDES are specified, the +# default includes are used. If ACTION-IF-SIGNED is given, it is +# additional shell code to execute when the type is signed. If +# ACTION-IF-UNSIGNED is given, it is executed when the type is unsigned. +# +# This macro assumes that the type exists. Therefore the existence of the +# type should be checked before calling this macro. For example: +# +# AC_CHECK_HEADERS([wchar.h]) +# AC_CHECK_TYPE([wchar_t],,[ AC_MSG_ERROR([Type wchar_t not found.]) ]) +# AX_CHECK_SIGN([wchar_t], +# [ AC_DEFINE(WCHAR_T_SIGNED, 1, [Define if wchar_t is signed]) ], +# [ AC_DEFINE(WCHAR_T_UNSIGNED, 1, [Define if wchar_t is unsigned]) ], [ +# #ifdef HAVE_WCHAR_H +# #include +# #endif +# ]) +# +# LICENSE +# +# Copyright (c) 2008 Ville Laurikari +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AU_ALIAS([VL_CHECK_SIGN], [AX_CHECK_SIGN]) +AC_DEFUN([AX_CHECK_SIGN], [ + typename=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g"` + AC_CACHE_CHECK([whether $1 is signed], ax_cv_decl_${typename}_signed, [ + AC_TRY_COMPILE([$4], + [ int foo @<:@ 1 - 2 * !((($1) -1) < 0) @:>@ ], + [ eval "ax_cv_decl_${typename}_signed=\"yes\"" ], + [ eval "ax_cv_decl_${typename}_signed=\"no\"" ])]) + symbolname=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g" | tr "a-z" "A-Z"` + if eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"yes\""; then + $2 + elif eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"no\""; then + $3 + fi +])dnl diff --git a/third_party/heimdal/cf/check-compile-flag.m4 b/third_party/heimdal/cf/check-compile-flag.m4 new file mode 100644 index 000000000000..bd753b34d7dc --- /dev/null +++ b/third_party/heimdal/cf/check-compile-flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/third_party/heimdal/cf/db.m4 b/third_party/heimdal/cf/db.m4 index cf5e3a88c997..c0b4510b6297 100644 --- a/third_party/heimdal/cf/db.m4 +++ b/third_party/heimdal/cf/db.m4 @@ -57,9 +57,9 @@ AS_IF([test "x$with_berkeley_db" != xno], db.h \ ])]) -dnl db_create is used by db3 and db4 and db5 +dnl db_create is used by db3 and db4 and db5 and db6 - AC_FIND_FUNC_NO_LIBS(db_create, [$dbheader] db-5 db5 db4 db3 db, [ + AC_FIND_FUNC_NO_LIBS(db_create, [$dbheader] db-6 db-5 db4 db3 db, [ #include #ifdef HAVE_DBHEADER #include <$dbheader/db.h> @@ -83,7 +83,7 @@ dnl db_create is used by db3 and db4 and db5 else DB3LIB="" fi - AC_DEFINE(HAVE_DB3, 1, [define if you have a berkeley db3/4/5 library]) + AC_DEFINE(HAVE_DB3, 1, [define if you have a berkeley db3/4/5/6 library]) fi dnl dbopen is used by db1/db2 diff --git a/third_party/heimdal/cf/krb-prog-yacc.m4 b/third_party/heimdal/cf/krb-prog-yacc.m4 index 380412ec7a0d..4c0afd9b7c33 100644 --- a/third_party/heimdal/cf/krb-prog-yacc.m4 +++ b/third_party/heimdal/cf/krb-prog-yacc.m4 @@ -1,12 +1,18 @@ dnl $Id$ dnl dnl -dnl We prefer byacc or yacc because they do not use `alloca' +dnl OLD: We prefer byacc or yacc because they do not use `alloca' +dnl +dnl CURRENT: We don't mind `alloca', but we do mind `bison -y' because +dnl newer versions of `bison', with `-y' complain about %expect and +dnl anything that yacc didn't document. Because `bison' typically +dnl also installs a `yacc' link that acts like `bison y', we put +dnl `yacc' last in this list. dnl AC_DEFUN([AC_KRB_PROG_YACC], -[AC_CHECK_PROGS(YACC, byacc yacc 'bison -y') +[AC_CHECK_PROGS(YACC, 'bison -d' 'byacc -d' yacc) if test "$YACC" = ""; then - AC_MSG_WARN([yacc not found - some stuff will not build]) + AC_MSG_WARN([byacc and bison not found - some stuff will not build]) fi ]) diff --git a/third_party/heimdal/cf/roken-frag.m4 b/third_party/heimdal/cf/roken-frag.m4 index 1dfcb1860b5a..2c2ef834e7a3 100644 --- a/third_party/heimdal/cf/roken-frag.m4 +++ b/third_party/heimdal/cf/roken-frag.m4 @@ -183,7 +183,6 @@ AC_CHECK_FUNCS([ \ asnprintf \ asprintf \ atexit \ - cgetent \ getauxval \ getconfattr \ getprogname \ @@ -216,11 +215,6 @@ AC_CHECK_FUNCS([ \ vis \ ]) -if test "$ac_cv_func_cgetent" = no; then - AC_LIBOBJ(getcap) -fi -AM_CONDITIONAL(have_cgetent, test "$ac_cv_func_cgetent" = yes) - AC_REQUIRE([AC_FUNC_GETLOGIN]) AC_REQUIRE([AC_FUNC_MMAP]) diff --git a/third_party/heimdal/configure.ac b/third_party/heimdal/configure.ac index 37a2275c283a..8c0b746ba5ce 100644 --- a/third_party/heimdal/configure.ac +++ b/third_party/heimdal/configure.ac @@ -20,6 +20,7 @@ AM_PROG_CC_C_O AC_PROG_CPP AM_PATH_PYTHON AC_CHECK_PROG(CLANG_FORMAT, clang-format, [clang-format], [no]) +test "$CLANG_FORMAT" = no && CLANG_FORMAT=true m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -58,8 +59,8 @@ if ! test -f "$srcdir/lib/asn1/der-protos.h" || AC_KRB_PERL_MOD(JSON) fi -dnl AC_KRB_PROG_YACC -AC_PROG_YACC +AC_KRB_PROG_YACC +dnl AC_PROG_YACC AM_PROG_LEX AS_IF([$LEX --nounput -V > /dev/null 2>&1 && test $? -eq 0], [AC_SUBST([FLEXNOUNPUTARGS], ["--nounput"])], @@ -87,8 +88,6 @@ dnl dnl Helper bits for cross compiling dnl - - AM_CONDITIONAL(CROSS_COMPILE, test "${cross_compiling}" = yes) AC_ARG_WITH(cross-tools, @@ -117,6 +116,14 @@ else fi +AX_CHECK_COMPILE_FLAG([-Wno-error=enum-conversion], + [WFLAGS_ENUM_CONV=-Wno-error=enum-conversion], + [WFLAGS_ENUM_CONV=], [-Werror]) +AX_CHECK_COMPILE_FLAG([-Wno-unused-but-set-variable], + [WFLAGS_UNUSED_BUT_SET_VAR=-Wno-unused-but-set-variable], + [WFLAGS_UNUSED_BUT_SET_VAR=], [-Werror]) + +AC_SUBST([WFLAGS_ENUM_CONV]) AC_SUBST([ASN1_COMPILE]) AC_SUBST([ASN1_COMPILE_DEP]) AC_SUBST([SLC]) @@ -496,6 +503,20 @@ dnl export symbols rk_WIN32_EXPORT(BUILD_KRB5_LIB, KRB5_LIB) rk_WIN32_EXPORT(BUILD_ROKEN_LIB, ROKEN_LIB) rk_WIN32_EXPORT(BUILD_GSSAPI_LIB, GSSAPI_LIB) +rk_WIN32_EXPORT(BUILD_KDC_LIB, KDC_LIB) + +dnl Deal with switch FALLTHROUGH +AH_TOP([ +#if defined(__GNUC__) +#if __GNUC__ >= 7 +# define fallthrough __attribute__((fallthrough)) +#else +# define fallthrough do {} while (0) /* fallthrough */ +#endif +#else +# define fallthrough do {} while (0) /* fallthrough */ +#endif +]) dnl Checks for libraries. @@ -605,6 +626,15 @@ AM_CONDITIONAL(HAVE_KEYUTILS, test "$ac_cv_func_keyctl_get_persistent" = yes) AC_CHECK_SIZEOF([time_t]) +AX_CHECK_SIGN([time_t], + [ AC_DEFINE(TIME_T_SIGNED, 1, [Define if time_t is signed]) ], + [ AC_DEFINE(TIME_T_UNSIGNED, 1, [Define if time_t is unsigned]) ], [ +#ifdef HAVE_TIME_H +#include +#endif +]) + + AC_CHECK_TYPES([int8_t, int16_t, int32_t, int64_t, u_int8_t, u_int16_t, u_int32_t, u_int64_t, uint8_t, uint16_t, uint32_t, uint64_t],,,[ diff --git a/third_party/heimdal/import-lorikeet.sh b/third_party/heimdal/import-lorikeet.sh index 6d36ced6c3fd..45a5888f721b 100755 --- a/third_party/heimdal/import-lorikeet.sh +++ b/third_party/heimdal/import-lorikeet.sh @@ -101,33 +101,33 @@ samba_create() { echo "git clean -d -x -f" git clean -d -x -f echo "git read-tree..." - git read-tree -u --prefix=source4/heimdal-new/ local-heimdal/$lorikeet_branch || bailout $? + git read-tree -u --prefix=third_party/heimdal-new/ local-heimdal/$lorikeet_branch || bailout $? echo "git reset --mixed HEAD" git reset --mixed HEAD echo "swap old -> new" - mv source4/heimdal source4/heimdal-old || bailout $? - rsync -a source4/heimdal-new/ source4/heimdal || bailout $? + mv third_party/heimdal third_party/heimdal-old || bailout $? + rsync -a third_party/heimdal-new/ third_party/heimdal || bailout $? # echo "PS1=\"'import-heimdal shell'>\"" > ../.bashrc.samba_create # bash --rcfile ../.bashrc.samba_create # bailout 255 echo "add changed files to the index" - git add -u source4/heimdal + git add -u third_party/heimdal echo "commit the changed files blindly" - git commit --no-verify -m "s4:heimdal: import $lorikeet_branch (commit $lorikeet_commit)" - echo "cleanup source4/heimdal" - rm -rf source4/heimdal - git checkout source4/heimdal + git commit --no-verify -m "third_party/heimdal: import $lorikeet_branch (commit $lorikeet_commit)" + echo "cleanup third_party/heimdal" + rm -rf third_party/heimdal + git checkout third_party/heimdal echo "try to build samba" build_samba || { echo "" echo "Now build the tree and make it compile." - echo "Missing files can be copied from source4/heimdal-new/" + echo "Missing files can be copied from third_party/heimdal-new/" echo "Also run make test!" } echo "" - echo "Then do a 'git add source4/heimdal' and a 'git commit --amend'" + echo "Then do a 'git add third_party/heimdal' and a 'git commit --amend'" echo "and write a useful commit message..." - echo "Then commit all needed changes outside of source4/heimdal" + echo "Then commit all needed changes outside of third_party/heimdal" echo "maybe splitted into multiple commits." echo "" echo "!!!!!!!!!" diff --git a/third_party/heimdal/include/Makefile.am b/third_party/heimdal/include/Makefile.am index 16dd2250c20c..43ebe7069472 100644 --- a/third_party/heimdal/include/Makefile.am +++ b/third_party/heimdal/include/Makefile.am @@ -36,21 +36,28 @@ CLEANFILES = \ base64.h \ ccache_plugin.h \ cms_asn1.h \ + cms_template_asn1.h \ com_err.h \ com_right.h \ + common_plugin.h \ crmf_asn1.h \ + crmf_template_asn1.h \ db_plugin.h \ der-private.h \ der-protos.h \ der.h \ digest_asn1.h \ + digest_template_asn1.h \ editline.h \ err.h \ getarg.h \ glob.h \ + gss-preauth-protos.h \ + gss-preauth-private.h \ gssapi.h \ gssapi_asn1.h \ gssapi_mech.h \ + gssapi/gssapi_preauth.h \ hdb-private.h \ hdb-protos.h \ hdb.h \ @@ -60,6 +67,8 @@ CLEANFILES = \ heim_asn1.h \ heim_err.h \ heimbase.h \ + heimbase-svc.h \ + heimbase-protos.h \ heimntlm-protos.h \ heimntlm.h \ hex.h \ @@ -79,26 +88,38 @@ CLEANFILES = \ krb5-types.h \ krb5.h \ krb5_asn1.h \ + krb5_template_asn1.h \ krb5_ccapi.h \ krb5_err.h \ krb_err.h \ + kuserok_plugin.h \ kx509_asn1.h \ + kx509_template_asn1.h \ kx509_err.h \ locate_plugin.h \ login-protos.h \ ntlm_err.h \ ocsp_asn1.h \ + ocsp_template_asn1.h \ otp.h \ parse_bytes.h \ parse_time.h \ parse_units.h \ pkcs10_asn1.h \ + pkcs10_template_asn1.h \ pkcs12_asn1.h \ + pkcs12_template_asn1.h \ pkcs8_asn1.h \ + pkcs8_template_asn1.h \ pkcs9_asn1.h \ + pkcs9_template_asn1.h \ pkinit_asn1.h \ + pkinit_template_asn1.h \ resolve.h \ rfc2459_asn1.h \ + rfc2459_template_asn1.h \ + rfc4108_asn1.h \ + rfc4108_template_asn1.h \ roken-common.h \ roken.h \ rtbl.h \ @@ -111,8 +132,16 @@ CLEANFILES = \ vis.h \ wind.h \ wind_err.h \ - windc_plugin.h \ - xdbm.h + kdc-plugin.h \ + kdc-accessors.h \ + kdc-audit.h \ + csr_authorizer_plugin.h \ + gss_preauth_authorizer_plugin.h \ + token_validator_plugin.h \ + xdbm.h \ + x25519_ref10.h \ + x690sample_asn1.h \ + x690sample_template_asn1.h DISTCLEANFILES = \ version.h \ diff --git a/third_party/heimdal/include/bits.c b/third_party/heimdal/include/bits.c index 326b67b7cc90..6abdb15c9113 100644 --- a/third_party/heimdal/include/bits.c +++ b/third_party/heimdal/include/bits.c @@ -46,23 +46,42 @@ RCSID("$Id$"); #include #endif -#define BITSIZE(TYPE) \ -{ \ - int b = 0; TYPE x = 1, zero = 0; const char *pre = "u"; \ - char tmp[128], tmp2[128]; \ - while(x){ x <<= 1; b++; if(x < zero) pre=""; } \ - if(b >= len){ \ - size_t tabs; \ - sprintf(tmp, "%sint%d_t" , pre, len); \ - sprintf(tmp2, "typedef %s %s;", #TYPE, tmp); \ - tabs = 5 - strlen(tmp2) / 8; \ - fprintf(f, "%s", tmp2); \ - while(tabs-- > 0) fprintf(f, "\t"); \ - fprintf(f, "/* %2d bits */\n", b); \ - return; \ - } \ +#ifdef HAVE_SNPRINTF +#define BITSIZE(TYPE) \ +{ \ + int b = 0; TYPE x = 1, zero = 0; const char *pre = "u"; \ + char tmp[128]; \ + while(x){ x <<= 1; b++; if(x < zero) pre=""; } \ + if(b >= len){ \ + size_t tabs; \ + snprintf(tmp, sizeof(tmp), "typedef %s %sint%d_t;", #TYPE, \ + pre, len); \ + tabs = 5 - strlen(tmp) / 8; \ + fprintf(f, "%s", tmp); \ + while(tabs-- > 0) fprintf(f, "\t"); \ + fprintf(f, "/* %2d bits */\n", b); \ + return; \ + } \ } - +#else +#define BITSIZE(TYPE) \ +{ \ + int b = 0; TYPE x = 1, zero = 0; const char *pre = "u"; \ + char tmp[128], tmp2[128]; \ + while(x){ x <<= 1; b++; if(x < zero) pre=""; } \ + if(b >= len){ \ + size_t tabs; \ + sprintf(tmp, "%sint%d_t" , pre, len); \ + sprintf(tmp2, "typedef %s %s;", #TYPE, tmp); \ + tabs = 5 - strlen(tmp2) / 8; \ + fprintf(f, "%s", tmp2); \ + while(tabs-- > 0) \ + fprintf(f, "\t"); \ + fprintf(f, "/* %2d bits */\n", b); \ + return; \ + } \ +} +#endif #ifndef HAVE___ATTRIBUTE__ #define __attribute__(x) #endif diff --git a/third_party/heimdal/include/config.h.w32 b/third_party/heimdal/include/config.h.w32 index 2d03bf264207..5521181d27cc 100644 --- a/third_party/heimdal/include/config.h.w32 +++ b/third_party/heimdal/include/config.h.w32 @@ -32,6 +32,8 @@ #ifndef __CONFIG_H__ #define __CONFIG_H__ +#define fallthrough do {} while(0) /* fallthrough */ + #ifndef RCSID #define RCSID(msg) \ static const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } @@ -122,6 +124,24 @@ static const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } #endif #endif + +#ifdef BUILD_KDC_LIB +#ifndef KDC_LIB +#ifdef _WIN32 +#define KDC_LIB_FUNCTION +#define KDC_LIB_NORETURN_FUNCTION __declspec(noreturn) +#define KDC_LIB_CALL __stdcall +#define KDC_LIB_VARIABLE +#else +#define KDC_LIB_FUNCTION +#define KDC_LIB_NORETURN_FUNCTION +#define KDC_LIB_CALL +#define KDC_LIB_VARIABLE +#endif +#endif +#endif + + /* Feature macros */ @FEATURE_DEFS@ @@ -199,9 +219,6 @@ static const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } /* Define to 1 if you have the `cap_set_proc' function. */ /* #undef HAVE_CAP_SET_PROC */ -/* Define to 1 if you have the `cgetent' function. */ -/* #undef HAVE_CGETENT */ - /* Define if the system defines 'CHAR' type */ #define HAVE_CHAR 1 @@ -793,9 +810,6 @@ static const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } /* Define to 1 if you have the `setstate' function. */ /* #define HAVE_SETSTATE 1 */ -/* Define to 1 if you have the `sgi_getcapabilitybyname' function. */ -/* #undef HAVE_SGI_GETCAPABILITYBYNAME */ - /* Define to 1 if you have the header file. */ /* #undef HAVE_SGTTY_H */ @@ -887,6 +901,17 @@ static const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } /* Define if you have the function `strtok_r'. */ /* #define HAVE_STRTOK_R 1 */ +#if defined(__has_include) +# if __has_include() +# define HAVE_UCRT 1 +# endif +#endif + +#ifdef HAVE_UCRT +#define HAVE_STRTOLL 1 +#define HAVE_STRTOULL 1 +#endif + /* Define to 1 if the system has the type `struct addrinfo'. */ #define HAVE_STRUCT_ADDRINFO 1 diff --git a/third_party/heimdal/kadmin/add-random-users.c b/third_party/heimdal/kadmin/add-random-users.c index b3d6d581d9b3..e2dc303b8dc9 100644 --- a/third_party/heimdal/kadmin/add-random-users.c +++ b/third_party/heimdal/kadmin/add-random-users.c @@ -58,7 +58,7 @@ read_words (const char *filename, char ***ret_w) buf[strcspn(buf, "\r\n")] = '\0'; if (n >= alloc) { alloc = max(alloc + 16, alloc * 2); - w = erealloc (w, alloc * sizeof(char **)); + w = erealloc (w, alloc * sizeof(char *)); } len = strlen(buf); if (wptr + len + 1 >= wend) { diff --git a/third_party/heimdal/kadmin/add_enctype.c b/third_party/heimdal/kadmin/add_enctype.c index 0ababf4f1976..d128ab7f49ef 100644 --- a/third_party/heimdal/kadmin/add_enctype.c +++ b/third_party/heimdal/kadmin/add_enctype.c @@ -46,7 +46,7 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) krb5_error_code ret; const char *princ_name; int i, j; - krb5_key_data *new_key_data; + krb5_key_data *new_key_data = NULL; int n_etypes; krb5_enctype *etypes; @@ -108,7 +108,6 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) /* XXX Should this be an error? The admin can del_enctype... */ krb5_warnx(context, "enctype %d already exists", (int)etypes[j]); - free(new_key_data); goto out; } } @@ -163,6 +162,7 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) if (ret) krb5_warn(context, ret, "kadm5_modify_principal"); out: + free(new_key_data); krb5_free_principal (context, princ_ent); kadm5_free_principal_ent(kadm_handle, &princ); out2: diff --git a/third_party/heimdal/kadmin/ank.c b/third_party/heimdal/kadmin/ank.c index 1e5cd6117dcf..4b89ca6eedd4 100644 --- a/third_party/heimdal/kadmin/ank.c +++ b/third_party/heimdal/kadmin/ank.c @@ -89,6 +89,7 @@ add_one_principal(const char *name, int mask = 0; int default_mask = 0; char pwbuf[1024]; + char *princ_name = NULL; memset(&princ, 0, sizeof(princ)); ret = krb5_parse_name(context, name, &princ_ent); @@ -96,6 +97,14 @@ add_one_principal(const char *name, krb5_warn(context, ret, "krb5_parse_name"); return ret; } + + if (rand_password) { + ret = krb5_unparse_name(context, princ_ent, &princ_name); + if (ret) { + krb5_warn(context, ret, "krb5_parse_name"); + goto out; + } + } princ.principal = princ_ent; mask |= KADM5_PRINCIPAL; @@ -129,7 +138,6 @@ add_one_principal(const char *name, random_password (pwbuf, sizeof(pwbuf)); password = pwbuf; } else if(password == NULL) { - char *princ_name; char *prompt; int aret; @@ -137,7 +145,6 @@ add_one_principal(const char *name, if (ret) goto out; aret = asprintf (&prompt, "%s's Password: ", princ_name); - free (princ_name); if (aret == -1) { ret = ENOMEM; krb5_set_error_message(context, ret, "out of memory"); @@ -205,18 +212,17 @@ add_one_principal(const char *name, kadm5_modify_principal(kadm_handle, &princ, KADM5_PW_EXPIRATION | KADM5_ATTRIBUTES); } else if (rand_password) { - char *princ_name; - - krb5_unparse_name(context, princ_ent, &princ_name); printf ("added %s with password \"%s\"\n", princ_name, password); - free (princ_name); } out: + free(princ_name); kadm5_free_principal_ent(kadm_handle, &princ); /* frees princ_ent */ if(default_ent) kadm5_free_principal_ent (kadm_handle, default_ent); - if (password != NULL) - memset (password, 0, strlen(password)); + if (password != NULL) { + size_t len = strlen(password); + memset_s(password, len, 0, len); + } return ret; } @@ -354,7 +360,6 @@ add_one_namespace(const char *name, { krb5_error_code ret; kadm5_principal_ent_rec princ; - kadm5_principal_ent_rec *default_ent = NULL; krb5_principal princ_ent = NULL; int mask = 0; int default_mask = 0; @@ -391,6 +396,8 @@ add_one_namespace(const char *name, ret = krb5_parse_name(context, name, &princ_ent); if (ret) krb5_warn(context, ret, "krb5_parse_name"); + else + princ.principal = princ_ent; } if (ret != 0) return ret; @@ -449,7 +456,6 @@ add_one_namespace(const char *name, } if (ret == 0) { - princ.principal = princ_ent; mask |= KADM5_PRINCIPAL | KADM5_KVNO; ret = set_entry(context, &princ, &mask, @@ -457,21 +463,21 @@ add_one_namespace(const char *name, "never", "never", attributes, NSPOLICY); } if (ret == 0) - ret = edit_entry(&princ, &mask, default_ent, default_mask); + ret = edit_entry(&princ, &mask, NULL, default_mask); if (ret == 0) ret = kstuple2etypes(&princ, &mask, nkstuple, kstuple); /* XXX Shouldn't need a password for this */ random_password(pwbuf, sizeof(pwbuf)); - ret = kadm5_create_principal_3(kadm_handle, &princ, mask, - nkstuple, kstuple, pwbuf); - if (ret) - krb5_warn(context, ret, "kadm5_create_principal_3"); + if (ret == 0) { + ret = kadm5_create_principal_3(kadm_handle, &princ, mask, + nkstuple, kstuple, pwbuf); + if (ret) + krb5_warn(context, ret, "kadm5_create_principal_3"); + } kadm5_free_principal_ent(kadm_handle, &princ); /* frees princ_ent */ - if (default_ent) - kadm5_free_principal_ent(kadm_handle, default_ent); memset(pwbuf, 0, sizeof(pwbuf)); return ret; } diff --git a/third_party/heimdal/kadmin/cpw.c b/third_party/heimdal/kadmin/cpw.c index d254add4482d..2f3c1c1bcd74 100644 --- a/third_party/heimdal/kadmin/cpw.c +++ b/third_party/heimdal/kadmin/cpw.c @@ -65,17 +65,17 @@ set_random_password (krb5_principal principal, int keepold) { krb5_error_code ret; char pw[128]; + char *princ_name; - random_password (pw, sizeof(pw)); - ret = kadm5_chpass_principal_3(kadm_handle, principal, keepold, 0, NULL, pw); - if (ret == 0) { - char *princ_name; - - krb5_unparse_name(context, principal, &princ_name); + ret = krb5_unparse_name(context, principal, &princ_name); + if (ret) + return ret; + random_password(pw, sizeof(pw)); + ret = kadm5_chpass_principal_3(kadm_handle, principal, keepold, 0, NULL, pw); + if (ret == 0) printf ("%s's password set to \"%s\"\n", princ_name, pw); - free (princ_name); - } + free(princ_name); memset_s(pw, sizeof(pw), 0, sizeof(pw)); return ret; } diff --git a/third_party/heimdal/kadmin/del.c b/third_party/heimdal/kadmin/del.c index 089ee8b0d805..a066f56ea387 100644 --- a/third_party/heimdal/kadmin/del.c +++ b/third_party/heimdal/kadmin/del.c @@ -61,12 +61,15 @@ do_del_ns_entry(krb5_principal nsp, void *data) krb5_principal p = NULL; const char *comp0 = krb5_principal_get_comp_string(context, nsp, 0); const char *comp1 = krb5_principal_get_comp_string(context, nsp, 1); - char *unsp = NULL; if (krb5_principal_get_num_comp(context, nsp) != 2) { - (void) krb5_unparse_name(context, nsp, &unsp); - krb5_warn(context, ret = EINVAL, "Not a valid namespace name %s", - unsp ? unsp : ""); + char *unsp = NULL; + + ret = krb5_unparse_name(context, nsp, &unsp); + krb5_warn(context, ret, + "Not a valid namespace name (component count is not 2): %s", + unsp ? unsp : ""); + free(unsp); return EINVAL; } @@ -80,7 +83,6 @@ do_del_ns_entry(krb5_principal nsp, void *data) if (ret == 0) ret = kadm5_delete_principal(kadm_handle, p); krb5_free_principal(context, p); - free(unsp); return ret; } diff --git a/third_party/heimdal/kadmin/ext.c b/third_party/heimdal/kadmin/ext.c index 01725d96e207..adb2e28518aa 100644 --- a/third_party/heimdal/kadmin/ext.c +++ b/third_party/heimdal/kadmin/ext.c @@ -148,7 +148,7 @@ do_ext_keytab(krb5_principal principal, void *data) } free(unparsed); free(keys); - return 0; + return ret; } int diff --git a/third_party/heimdal/kadmin/get.c b/third_party/heimdal/kadmin/get.c index 35766aa1bfc5..a884e11e96be 100644 --- a/third_party/heimdal/kadmin/get.c +++ b/third_party/heimdal/kadmin/get.c @@ -349,6 +349,7 @@ format_field(struct get_entry_data *data, if (i) strlcat(buf, ",", buf_len); strlcat(buf, str, buf_len); + krb5_xfree(str); } } free_HDB_EncTypeList(&etypes); @@ -632,6 +633,7 @@ list_princs(struct list_options *opt, int argc, char **argv) krb5_warnx(context, "programmer error: sizeof(struct get_options) != sizeof(struct list_options)"); return 0; } + memset(&get_opt, 0, sizeof(get_opt)); get_opt.long_flag = opt->long_flag; get_opt.short_flag = opt->short_flag; get_opt.terse_flag = opt->terse_flag; diff --git a/third_party/heimdal/kadmin/init.c b/third_party/heimdal/kadmin/init.c index 8b025e112f8a..8a3725e3c49c 100644 --- a/third_party/heimdal/kadmin/init.c +++ b/third_party/heimdal/kadmin/init.c @@ -73,7 +73,20 @@ create_random_entry(krb5_principal princ, ent.attributes |= attributes | KRB5_KDB_DISALLOW_ALL_TIX; mask |= KADM5_ATTRIBUTES | KADM5_KEY_DATA; - /* Create the entry with no keys or password */ + /* + * Create the entry with no keys or password. + * + * XXX Note that using kadm5_s_*() here means that `kadmin init` must + * always be local (`kadmin -l init`). This might seem like a very + * obvious thing, but since our KDC daemons support multiple realms + * there is no reason that `init SOME.REALM.EXAMPLE` couldn't be + * remoted. + * + * Granted, one might want all such operations to be local anyways -- + * perhaps for authorization reasons, since we don't really have that + * great a story for authorization in kadmind at this time, especially + * for realm creation. + */ ret = kadm5_s_create_principal_with_key(kadm_handle, &ent, mask); if(ret) { if (ret == KADM5_DUP && (flags & CRE_DUP_OK)) @@ -127,21 +140,21 @@ init(struct init_options *opt, int argc, char **argv) if (!local_flag) { krb5_warnx(context, "init is only available in local (-l) mode"); - return 0; + return 1; } if (opt->realm_max_ticket_life_string) { if (str2deltat (opt->realm_max_ticket_life_string, &max_life) != 0) { krb5_warnx (context, "unable to parse \"%s\"", opt->realm_max_ticket_life_string); - return 0; + return 1; } } if (opt->realm_max_renewable_life_string) { if (str2deltat (opt->realm_max_renewable_life_string, &max_rlife) != 0) { krb5_warnx (context, "unable to parse \"%s\"", opt->realm_max_renewable_life_string); - return 0; + return 1; } } @@ -150,107 +163,164 @@ init(struct init_options *opt, int argc, char **argv) ret = db->hdb_open(context, db, O_RDWR | O_CREAT, 0600); if(ret){ krb5_warn(context, ret, "hdb_open"); - return 0; + return 1; } ret = kadm5_log_reinit(kadm_handle, 0); - if (ret) - krb5_err(context, 1, ret, "Failed iprop log initialization"); - kadm5_log_end(kadm_handle); + if (ret) { + krb5_warn(context, ret, "Failed iprop log initialization"); + return 1; + } + ret = kadm5_log_end(kadm_handle); db->hdb_close(context, db); + if (ret) { + krb5_warn(context, ret, "Failed iprop log initialization"); + return 1; + } + for(i = 0; i < argc; i++){ - krb5_principal princ; + krb5_principal princ = NULL; const char *realm = argv[i]; if (opt->realm_max_ticket_life_string == NULL) { max_life = 0; if(edit_deltat ("Realm max ticket life", &max_life, NULL, 0)) { - return 0; + return 1; } } if (opt->realm_max_renewable_life_string == NULL) { max_rlife = 0; if(edit_deltat("Realm max renewable ticket life", &max_rlife, NULL, 0)) { - return 0; + return 1; } } /* Create `krbtgt/REALM' */ ret = krb5_make_principal(context, &princ, realm, KRB5_TGS_NAME, realm, NULL); - if(ret) - return 0; - - create_random_entry(princ, max_life, max_rlife, 0, 0); + if (ret == 0) + ret = create_random_entry(princ, max_life, max_rlife, 0, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create %s@%s", KRB5_TGS_NAME, + realm); + return 1; + } if (opt->bare_flag) continue; /* Create `kadmin/changepw' */ - krb5_make_principal(context, &princ, realm, - "kadmin", "changepw", NULL); + ret = krb5_make_principal(context, &princ, realm, "kadmin", + "changepw", NULL); /* * The Windows XP (at least) password changing protocol * request the `kadmin/changepw' ticket with `renewable_ok, * renewable, forwardable' and so fails if we disallow * forwardable here. */ - create_random_entry(princ, 5*60, 5*60, - KRB5_KDB_DISALLOW_TGT_BASED| - KRB5_KDB_PWCHANGE_SERVICE| - KRB5_KDB_DISALLOW_POSTDATED| - KRB5_KDB_DISALLOW_RENEWABLE| - KRB5_KDB_DISALLOW_PROXIABLE| - KRB5_KDB_REQUIRES_PRE_AUTH, - 0); + if (ret == 0) + ret = create_random_entry(princ, 5*60, 5*60, + KRB5_KDB_DISALLOW_TGT_BASED| + KRB5_KDB_PWCHANGE_SERVICE| + KRB5_KDB_DISALLOW_POSTDATED| + KRB5_KDB_DISALLOW_RENEWABLE| + KRB5_KDB_DISALLOW_PROXIABLE| + KRB5_KDB_REQUIRES_PRE_AUTH, + 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create kadmin/changepw@%s", + realm); + return 1; + } /* Create `kadmin/admin' */ - krb5_make_principal(context, &princ, realm, - "kadmin", "admin", NULL); - create_random_entry(princ, 60*60, 60*60, KRB5_KDB_REQUIRES_PRE_AUTH, 0); + ret = krb5_make_principal(context, &princ, realm, + "kadmin", "admin", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create kadmin/admin@%s", realm); + return 1; + } /* Create `changepw/kerberos' (for v4 compat) */ - krb5_make_principal(context, &princ, realm, - "changepw", "kerberos", NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_DISALLOW_TGT_BASED| - KRB5_KDB_PWCHANGE_SERVICE, 0); - + ret = krb5_make_principal(context, &princ, realm, + "changepw", "kerberos", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_DISALLOW_TGT_BASED| + KRB5_KDB_PWCHANGE_SERVICE, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create changepw/kerberos@%s", + realm); + return 1; + } /* Create `kadmin/hprop' for database propagation */ - krb5_make_principal(context, &princ, realm, - "kadmin", "hprop", NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_REQUIRES_PRE_AUTH| - KRB5_KDB_DISALLOW_TGT_BASED, 0); + ret = krb5_make_principal(context, &princ, realm, + "kadmin", "hprop", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH| + KRB5_KDB_DISALLOW_TGT_BASED, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create kadmin/hprop@%s", realm); + return 1; + } /* Create `WELLKNOWN/ANONYMOUS' for anonymous as-req */ - krb5_make_principal(context, &princ, realm, - KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_REQUIRES_PRE_AUTH, 0); + ret = krb5_make_principal(context, &princ, realm, KRB5_WELLKNOWN_NAME, + KRB5_ANON_NAME, NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create %s/%s@%s", + KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, realm); + return 1; + } - /* Create `WELLKNOWN/FEDERATED' for GSS preauth */ - krb5_make_principal(context, &princ, realm, - KRB5_WELLKNOWN_NAME, KRB5_FEDERATED_NAME, NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_REQUIRES_PRE_AUTH, 0); - krb5_free_principal(context, princ); + /* Create `WELLKNOWN/FEDERATED' for GSS preauth */ + ret = krb5_make_principal(context, &princ, realm, + KRB5_WELLKNOWN_NAME, KRB5_FEDERATED_NAME, NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH, 0); + krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create %s/%s@%s", + KRB5_WELLKNOWN_NAME, KRB5_FEDERATED_NAME, realm); + return 1; + } - /* Create `WELLKNONW/org.h5l.fast-cookie@WELLKNOWN:ORG.H5L' for FAST cookie */ - krb5_make_principal(context, &princ, KRB5_WELLKNOWN_ORG_H5L_REALM, - KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_REQUIRES_PRE_AUTH| - KRB5_KDB_DISALLOW_TGT_BASED| - KRB5_KDB_DISALLOW_ALL_TIX, CRE_DUP_OK); - krb5_free_principal(context, princ); + /* + * Create `WELLKNONW/org.h5l.fast-cookie@WELLKNOWN:ORG.H5L' for FAST cookie. + * + * There can be only one. + */ + if (i == 0) { + ret = krb5_make_principal(context, &princ, KRB5_WELLKNOWN_ORG_H5L_REALM, + KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH| + KRB5_KDB_DISALLOW_TGT_BASED| + KRB5_KDB_DISALLOW_ALL_TIX, CRE_DUP_OK); + krb5_free_principal(context, princ); + if (ret && ret != KADM5_DUP) { + krb5_warn(context, ret, + "Failed to create %s/org.h5l.fast-cookie@%s", + KRB5_WELLKNOWN_NAME, KRB5_WELLKNOWN_ORG_H5L_REALM); + return 1; + } + } /* Create `default' */ { @@ -259,18 +329,20 @@ init(struct init_options *opt, int argc, char **argv) memset (&ent, 0, sizeof(ent)); mask |= KADM5_PRINCIPAL; - krb5_make_principal(context, &ent.principal, realm, - "default", NULL); mask |= KADM5_MAX_LIFE; - ent.max_life = 24 * 60 * 60; mask |= KADM5_MAX_RLIFE; + mask |= KADM5_ATTRIBUTES; + ent.max_life = 24 * 60 * 60; ent.max_renewable_life = 7 * ent.max_life; ent.attributes = KRB5_KDB_DISALLOW_ALL_TIX; - mask |= KADM5_ATTRIBUTES; - - ret = kadm5_create_principal(kadm_handle, &ent, mask, ""); - if (ret) - krb5_err (context, 1, ret, "kadm5_create_principal"); + ret = krb5_make_principal(context, &ent.principal, realm, + "default", NULL); + if (ret == 0) + ret = kadm5_create_principal(kadm_handle, &ent, mask, ""); + if (ret) { + krb5_warn(context, ret, "Failed to create default@%s", realm); + return 1; + } krb5_free_principal(context, ent.principal); } diff --git a/third_party/heimdal/kadmin/kadm_conn.c b/third_party/heimdal/kadmin/kadm_conn.c index 0817b7c93aa4..0eeaf508da84 100644 --- a/third_party/heimdal/kadmin/kadm_conn.c +++ b/third_party/heimdal/kadmin/kadm_conn.c @@ -261,12 +261,9 @@ start_server(krb5_context contextp, const char *port_str) for(ap = ai; ap; ap = ap->ai_next) i++; tmp = realloc(socks, (num_socks + i) * sizeof(*socks)); - if(tmp == NULL) { - krb5_warnx(contextp, "failed to reallocate %lu bytes", - (unsigned long)(num_socks + i) * sizeof(*socks)); - freeaddrinfo(ai); - continue; - } + if(tmp == NULL) + krb5_err(contextp, 1, errno, "failed to reallocate %lu bytes", + (unsigned long)(num_socks + i) * sizeof(*socks)); socks = tmp; for(ap = ai; ap; ap = ap->ai_next) { krb5_socket_t s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); diff --git a/third_party/heimdal/kadmin/kadmin.1 b/third_party/heimdal/kadmin/kadmin.1 index 401b6a9f6ba0..b0e852931c6b 100644 --- a/third_party/heimdal/kadmin/kadmin.1 +++ b/third_party/heimdal/kadmin/kadmin.1 @@ -166,13 +166,20 @@ and sub-commands rather than having to edit the KDC's configuration file and having to restart the KDC. .Pp -However, there is currently no way to alias namespaces via HDB -entry aliases. -To issue referrals for entire namespaces use the +There are two methods for issuing referrals for entire namespaces +of hostnames. +An alias of the form +.Ar WELLKNOWN/HOSTBASED-NAMESPACE/service/namespace-fqdn@REALM +(see +.Nm add_namespace +below) will cause all requests for host-based principals in the +given namespace to be referred to the given realm. +Alternatively, the KDC will issue referrals for all host-based +service principals whose hostname component matches a .Ar [domain_realm] -section of the KDC's +entry in the KDC's .Ar krb5.conf -file. +file referring to a different realm. .Ed .Pp .Nm add_namespace @@ -182,18 +189,23 @@ file. .Op Fl Fl max-ticket-life= Ns Ar lifetime .Op Fl Fl max-renewable-life= Ns Ar lifetime .Op Fl Fl attributes= Ns Ar attributes -.Ar principal... +.Ar host-based-principal... .Bd -ragged -offset indent Adds a new namespace of virtual host-based or domain-based principals to the database, whose keys will be automatically derived from base keys stored in the namespace record, and which keys will be rotated automatically. -The namespace names should look like -.Ar hostname@REALM +The namespace names are of the same form as host-based principal +names: +.Ar service/hostname@REALM and these will match all host-based or domain-based service names where hostname component of such a principal ends in the labels of the hostname in the namespace name. .Pp +The service name component may be a wild-card (underscore, +.Ar _ ), +in which case it will match any service. +.Pp For example, .Ar bar.baz.example@BAZ.EXAMPLE will match @@ -223,6 +235,11 @@ The default enctypes is as for the .Nm add command. .Pp +Note that namespaces are stored as principals whose names are of the form +.Ar WELLKNOWN/HOSTBASED-NAMESPACE/service/namespace.fqdn@REALM , +with the +.Ar service +.Pp This command has the following alias: .Nm add_ns . .Ed diff --git a/third_party/heimdal/kadmin/kadmind.c b/third_party/heimdal/kadmin/kadmind.c index 10bbea840576..444950623f0b 100644 --- a/third_party/heimdal/kadmin/kadmind.c +++ b/third_party/heimdal/kadmin/kadmind.c @@ -134,6 +134,8 @@ main(int argc, char **argv) argc -= optidx; argv += optidx; + if (argc != 0) + usage(1); if (config_file == NULL) { int aret; diff --git a/third_party/heimdal/kadmin/load.c b/third_party/heimdal/kadmin/load.c index 971c24793c05..f62f8b96dcc0 100644 --- a/third_party/heimdal/kadmin/load.c +++ b/third_party/heimdal/kadmin/load.c @@ -367,7 +367,7 @@ my_fgetln(FILE *f, char **bufp, size_t *szp, size_t *lenp) size_t len; size_t sz = *szp; char *buf = *bufp; - char *p, *n; + char *n; if (!buf) { buf = malloc(sz ? sz : 8192); @@ -378,7 +378,7 @@ my_fgetln(FILE *f, char **bufp, size_t *szp, size_t *lenp) } len = 0; - while ((p = fgets(&buf[len], sz-len, f)) != NULL) { + while (fgets(&buf[len], sz-len, f) != NULL) { len += strlen(&buf[len]); if (buf[len-1] == '\n') break; @@ -418,7 +418,7 @@ doit(const char *filename, int mergep) int lineno; int flags = O_RDWR; struct entry e; - hdb_entry_ex ent; + hdb_entry ent; HDB *db = _kadm5_s_get_db(kadm_handle); f = fopen(filename, "r"); @@ -506,7 +506,7 @@ doit(const char *filename, int mergep) skip_next(p); memset(&ent, 0, sizeof(ent)); - ret2 = krb5_parse_name(context, e.principal, &ent.entry.principal); + ret2 = krb5_parse_name(context, e.principal, &ent.principal); if (ret2) { const char *msg = krb5_get_error_message(context, ret); fprintf(stderr, "%s:%d:%s (%s)\n", @@ -516,92 +516,92 @@ doit(const char *filename, int mergep) continue; } - if (parse_keys(&ent.entry, e.key)) { + if (parse_keys(&ent, e.key)) { fprintf (stderr, "%s:%d:error parsing keys (%s)\n", filename, lineno, e.key); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_event(&ent.entry.created_by, e.created) == -1) { + if (parse_event(&ent.created_by, e.created) == -1) { fprintf (stderr, "%s:%d:error parsing created event (%s)\n", filename, lineno, e.created); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_event_alloc (&ent.entry.modified_by, e.modified) == -1) { + if (parse_event_alloc (&ent.modified_by, e.modified) == -1) { fprintf (stderr, "%s:%d:error parsing event (%s)\n", filename, lineno, e.modified); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_time_string_alloc (&ent.entry.valid_start, e.valid_start) == -1) { + if (parse_time_string_alloc (&ent.valid_start, e.valid_start) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", filename, lineno, e.valid_start); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_time_string_alloc (&ent.entry.valid_end, e.valid_end) == -1) { + if (parse_time_string_alloc (&ent.valid_end, e.valid_end) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", filename, lineno, e.valid_end); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_time_string_alloc (&ent.entry.pw_end, e.pw_end) == -1) { + if (parse_time_string_alloc (&ent.pw_end, e.pw_end) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", filename, lineno, e.pw_end); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_integer_alloc (&ent.entry.max_life, e.max_life) == -1) { + if (parse_integer_alloc (&ent.max_life, e.max_life) == -1) { fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", filename, lineno, e.max_life); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_integer_alloc (&ent.entry.max_renew, e.max_renew) == -1) { + if (parse_integer_alloc (&ent.max_renew, e.max_renew) == -1) { fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", filename, lineno, e.max_renew); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_hdbflags2int (&ent.entry.flags, e.flags) != 1) { + if (parse_hdbflags2int (&ent.flags, e.flags) != 1) { fprintf (stderr, "%s:%d:error parsing flags (%s)\n", filename, lineno, e.flags); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if(parse_generation(e.generation, &ent.entry.generation) == -1) { + if(parse_generation(e.generation, &ent.generation) == -1) { fprintf (stderr, "%s:%d:error parsing generation (%s)\n", filename, lineno, e.generation); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } - if (parse_extensions(&e.extensions, &ent.entry.extensions) == -1) { + if (parse_extensions(&e.extensions, &ent.extensions) == -1) { fprintf (stderr, "%s:%d:error parsing extension (%s)\n", filename, lineno, e.extensions); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); ret = 1; continue; } ret2 = db->hdb_store(context, db, HDB_F_REPLACE, &ent); - hdb_free_entry (context, &ent); + hdb_free_entry (context, db, &ent); if (ret2) { krb5_warn(context, ret2, "db_store"); break; diff --git a/third_party/heimdal/kadmin/mod.c b/third_party/heimdal/kadmin/mod.c index 9541c6efcb41..7c7b2dd7ce44 100644 --- a/third_party/heimdal/kadmin/mod.c +++ b/third_party/heimdal/kadmin/mod.c @@ -123,7 +123,7 @@ static void add_aliases(krb5_context contextp, kadm5_principal_ent_rec *princ, struct getarg_strings *strings) { - krb5_error_code ret; + krb5_error_code ret = 0; HDB_extension ext; krb5_data buf; krb5_principal p; @@ -144,9 +144,16 @@ add_aliases(krb5_context contextp, kadm5_principal_ent_rec *princ, sizeof(ext.data.u.aliases.aliases.val[0])); ext.data.u.aliases.aliases.len = strings->num_strings; - for (i = 0; i < strings->num_strings; i++) { + for (i = 0; ret == 0 && i < strings->num_strings; i++) { ret = krb5_parse_name(contextp, strings->strings[i], &p); - ret = copy_Principal(p, &ext.data.u.aliases.aliases.val[i]); + if (ret) + krb5_err(contextp, 1, ret, "Could not parse alias %s", + strings->strings[i]); + if (ret == 0) + ret = copy_Principal(p, &ext.data.u.aliases.aliases.val[i]); + if (ret) + krb5_err(contextp, 1, ret, "Could not copy parsed alias %s", + strings->strings[i]); krb5_free_principal(contextp, p); } } @@ -224,6 +231,7 @@ add_etypes(krb5_context contextp, if (ret) { krb5_warn(contextp, ret, "Could not parse enctype %s", strings->strings[i]); + free(etypes.val); return ret; } etypes.val[i] = etype; @@ -236,6 +244,7 @@ add_etypes(krb5_context contextp, if (ret || buf.length != size) abort(); add_tl(princ, KRB5_TL_ETYPES, &buf); + free(etypes.val); return 0; } diff --git a/third_party/heimdal/kadmin/rpc.c b/third_party/heimdal/kadmin/rpc.c index 6ddb9dfa8654..1ae10f1af7ca 100644 --- a/third_party/heimdal/kadmin/rpc.c +++ b/third_party/heimdal/kadmin/rpc.c @@ -142,7 +142,7 @@ parse_name(const unsigned char *p, size_t len, /* MECHNAME_LEN */ if (len < 4) return 1; - l = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + l = (unsigned long)p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; len -= 4; p += 4; @@ -972,7 +972,7 @@ process_stream(krb5_context contextp, INSIST(gctx.ctx == NULL); gctx.inprogress = 1; - /* FALLTHROUGH */ + fallthrough; case RPG_CONTINUE_INIT: { gss_name_t src_name = GSS_C_NO_NAME; krb5_data in; diff --git a/third_party/heimdal/kadmin/server.c b/third_party/heimdal/kadmin/server.c index cbe16948c06c..52f20202e7fb 100644 --- a/third_party/heimdal/kadmin/server.c +++ b/third_party/heimdal/kadmin/server.c @@ -42,7 +42,8 @@ static kadm5_ret_t kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, krb5_data *in, krb5_data *out, int readonly) { - kadm5_ret_t ret; + kadm5_ret_t ret = 0; + kadm5_ret_t ret_sp = 0; int32_t cmd, mask, kvno, tmp; kadm5_server_context *contextp = kadm_handlep; char client[128], name[128], name2[128]; @@ -58,19 +59,31 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, char **princs; int n_princs; int keys_ok = 0; + krb5_storage *rsp; /* response goes here */ krb5_storage *sp; int len; - krb5_unparse_name_fixed(contextp->context, contextp->caller, - client, sizeof(client)); + memset(&ent, 0, sizeof(ent)); + memset(&ent_prev, 0, sizeof(ent_prev)); + krb5_data_zero(out); + + rsp = krb5_storage_emem(); + if (rsp == NULL) + return krb5_enomem(contextp->context); sp = krb5_storage_from_data(in); if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; + krb5_storage_free(rsp); + return krb5_enomem(contextp->context); } - krb5_ret_int32(sp, &cmd); + ret = krb5_unparse_name_fixed(contextp->context, contextp->caller, + client, sizeof(client)); + if (ret == 0) + ret = krb5_ret_int32(sp, &cmd); + if (ret) + goto fail; + switch(cmd){ case kadm_get:{ op = "GET"; @@ -121,20 +134,14 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, } ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); - if (ret == 0){ - if (keys_ok) - kadm5_store_principal_ent(sp, &ent); - else - kadm5_store_principal_ent_nokeys(sp, &ent); - kadm5_free_principal_ent(kadm_handlep, &ent); + ret_sp = krb5_store_int32(rsp, ret); + if (ret == 0) { + if (ret_sp == 0 && keys_ok) + ret_sp = kadm5_store_principal_ent(rsp, &ent); + else if (ret_sp == 0) + ret_sp = kadm5_store_principal_ent_nokeys(rsp, &ent); } + kadm5_free_principal_ent(kadm_handlep, &ent); break; } case kadm_delete:{ @@ -144,27 +151,21 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, goto fail; } ret = krb5_ret_principal(sp, &princ); - if (ret) - goto fail; - krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); - krb5_warnx(contextp->context, "%s: %s %s", client, op, name); - ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); - if (ret) - goto fail; + if (ret == 0) + ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + if (ret == 0) { + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); + krb5_warnx(contextp->context, "%s: %s %s (%s)", client, op, name, + ret == 0 ? "granted" : "denied"); + } /* * There's no need to check that the caller has permission to * delete the victim principal's aliases. */ - - ret = kadm5_delete_principal(kadm_handlep, princ); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); + if (ret == 0) + ret = kadm5_delete_principal(kadm_handlep, princ); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_create:{ @@ -209,13 +210,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, ret = kadm5_create_principal(kadm_handlep, &ent, mask, password); kadm5_free_principal_ent(kadm_handlep, &ent); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_modify:{ @@ -262,13 +257,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, } ret = kadm5_modify_principal(kadm_handlep, &ent, mask); kadm5_free_principal_ent(kadm_handlep, &ent); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_prune:{ @@ -293,13 +282,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, goto fail; ret = kadm5_prune_principal(kadm_handlep, princ, kvno); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_rename:{ @@ -342,13 +325,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, goto fail; ret = kadm5_rename_principal(kadm_handlep, princ, princ2); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); + ret_sp = krb5_store_int32(sp, ret); break; } case kadm_chpass:{ @@ -360,18 +337,19 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, goto fail; } ret = krb5_ret_principal(sp, &princ); + if (ret == 0) + ret = krb5_ret_string(sp, &password); + if (ret == 0) + ret = krb5_ret_int32(sp, &keepold); + if (ret == HEIM_ERR_EOF) + ret = 0; + if (ret == 0) { + ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + if (ret == 0) + krb5_warnx(contextp->context, "%s: %s %s", client, op, name); + } if (ret) goto fail; - ret = krb5_ret_string(sp, &password); - if (ret) - goto fail; - - ret = krb5_ret_int32(sp, &keepold); - if (ret && ret != HEIM_ERR_EOF) - goto fail; - - krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); - krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * Change password requests are subject to ACLs unless the principal is @@ -391,13 +369,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL, password); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_chpass_with_key:{ @@ -411,16 +383,16 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, goto fail; } ret = krb5_ret_principal(sp, &princ); - if(ret) - goto fail; - ret = krb5_ret_int32(sp, &n_key_data); + if (ret == 0) + ret = krb5_ret_int32(sp, &n_key_data); + if (ret == 0) { + ret = krb5_ret_int32(sp, &keepold); + if (ret == HEIM_ERR_EOF) + ret = 0; + } if (ret) goto fail; - ret = krb5_ret_int32(sp, &keepold); - if (ret && ret != HEIM_ERR_EOF) - goto fail; - /* n_key_data will be squeezed into an int16_t below. */ if (n_key_data < 0 || n_key_data >= 1 << 16 || (size_t)n_key_data > UINT_MAX/sizeof(*key_data)) { @@ -445,15 +417,16 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, } } - krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); - krb5_warnx(contextp->context, "%s: %s %s", client, op, name); - /* * The change is only allowed if the user is on the CPW ACL, * this it to force password quality check on the user. */ ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); + ret_sp = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + if (ret_sp == 0) + krb5_warnx(contextp->context, "%s: %s %s (%s)", client, op, name, + ret ? "denied" : "granted"); if(ret) { int16_t dummy = n_key_data; @@ -468,13 +441,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, kadm5_free_key_data (contextp, &dummy, key_data); } free (key_data); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_randkey:{ @@ -537,7 +504,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, ret = EOVERFLOW; goto fail; } - + free(ks_tuple); if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) { ret = errno; goto fail; @@ -560,18 +527,12 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, &n_keys); free(ks_tuple); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); - if (ret == 0){ - krb5_store_int32(sp, n_keys); + ret_sp = krb5_store_int32(rsp, ret); + if (ret == 0 && ret_sp == 0){ + ret_sp = krb5_store_int32(rsp, n_keys); for (i = 0; i < n_keys; i++){ - if (ret == 0) - ret = krb5_store_keyblock(sp, new_keys[i]); + if (ret_sp == 0) + ret_sp = krb5_store_keyblock(rsp, new_keys[i]); krb5_free_keyblock_contents(contextp->context, &new_keys[i]); } free(new_keys); @@ -581,15 +542,8 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, case kadm_get_privs:{ uint32_t privs; ret = kadm5_get_privs(kadm_handlep, &privs); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); - if(ret == 0) - krb5_store_uint32(sp, privs); + if (ret == 0) + ret_sp = krb5_store_uint32(sp, privs); break; } case kadm_get_princs:{ @@ -612,62 +566,42 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, } ret = kadm5_get_principals(kadm_handlep, expression, &princs, &n_princs); free(expression); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, ret); - if(ret == 0){ + ret_sp = krb5_store_int32(rsp, ret); + if (ret == 0) { int i; - krb5_store_int32(sp, n_princs); - for(i = 0; i < n_princs; i++) - krb5_store_string(sp, princs[i]); + + ret_sp = krb5_store_int32(sp, n_princs); + for (i = 0; ret_sp == 0 && i < n_princs; i++) + ret_sp = krb5_store_string(sp, princs[i]); kadm5_free_name_list(kadm_handlep, princs, &n_princs); } break; } default: krb5_warnx(contextp->context, "%s: UNKNOWN OP %d", client, cmd); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - if (sp == NULL) { - ret = krb5_enomem(contextp->context); - goto fail; - } - krb5_store_int32(sp, KADM5_FAILURE); + ret_sp = krb5_store_int32(sp, KADM5_FAILURE); break; } - if (password != NULL) { - len = strlen(password); - memset_s(password, len, 0, len); - free(password); - } - krb5_storage_to_data(sp, out); - krb5_storage_free(sp); - if (princ != NULL) - krb5_free_principal(contextp->context, princ); - if (princ2 != NULL) - krb5_free_principal(contextp->context, princ2); - return 0; + fail: if (password != NULL) { len = strlen(password); memset_s(password, len, 0, len); free(password); } - krb5_warn(contextp->context, ret, "%s", op); - if (sp != NULL) { - krb5_storage_seek(sp, 0, SEEK_SET); - krb5_store_int32(sp, ret); - krb5_storage_to_data(sp, out); - krb5_storage_free(sp); - } - if (princ != NULL) - krb5_free_principal(contextp->context, princ); - if (princ2 != NULL) - krb5_free_principal(contextp->context, princ2); + krb5_storage_to_data(rsp, out); + krb5_storage_free(rsp); + krb5_storage_free(sp); + krb5_free_principal(contextp->context, princ); + krb5_free_principal(contextp->context, princ2); + if (ret) + krb5_warn(contextp->context, ret, "%s", op); + if (out->length == 0) + krb5_warn(contextp->context, ret, "%s: reply failed", op); + else if (ret_sp) + krb5_warn(contextp->context, ret, "%s: reply incomplete", op); + if (ret_sp) + return ret_sp; return 0; } @@ -691,6 +625,10 @@ iter_aliases(kadm5_principal_ent_rec *from, if (ctx->done > 0) return 0; + if (from == NULL) { + ctx->done = 1; + return 0; + } if (ctx->done == 0) { if (ctx->alias_idx < ctx->aliases.aliases.len) { @@ -841,7 +779,6 @@ handle_v5(krb5_context contextp, void *kadm_handlep; krb5_boolean initial; krb5_auth_context ac = NULL; - unsigned kadm_version = 1; kadm5_config_params realm_params; @@ -849,35 +786,51 @@ handle_v5(krb5_context contextp, match_appl_version, &kadm_version, NULL, KRB5_RECVAUTH_IGNORE_VERSION, keytab, &ticket); - if (ret) + if (ret) { krb5_err(contextp, 1, ret, "krb5_recvauth"); - - ret = krb5_unparse_name (contextp, ticket->server, &server_name); - if (ret) - krb5_err (contextp, 1, ret, "krb5_unparse_name"); - - if (strncmp (server_name, KADM5_ADMIN_SERVICE, - strlen(KADM5_ADMIN_SERVICE)) != 0) - krb5_errx (contextp, 1, "ticket for strange principal (%s)", - server_name); - - free (server_name); + return; + } + ret = krb5_unparse_name(contextp, ticket->server, &server_name); + if (ret) { + krb5_err(contextp, 1, ret, "krb5_unparse_name"); + krb5_free_ticket(contextp, ticket); + return; + } + if (strncmp(server_name, KADM5_ADMIN_SERVICE, + strlen(KADM5_ADMIN_SERVICE)) != 0) { + krb5_errx(contextp, 1, "ticket for strange principal (%s)", server_name); + krb5_free_ticket(contextp, ticket); + free(server_name); + return; + } + free(server_name); memset(&realm_params, 0, sizeof(realm_params)); if(kadm_version == 1) { krb5_data params; ret = krb5_read_priv_message(contextp, ac, &fd, ¶ms); - if(ret) + if (ret) { krb5_err(contextp, 1, ret, "krb5_read_priv_message"); - _kadm5_unmarshal_params(contextp, ¶ms, &realm_params); + krb5_free_ticket(contextp, ticket); + return; + } + ret = _kadm5_unmarshal_params(contextp, ¶ms, &realm_params); + if (ret) { + krb5_err(contextp, 1, ret, + "Could not read or parse kadm5 parameters"); + krb5_free_ticket(contextp, ticket); + return; + } } initial = ticket->ticket.flags.initial; ret = krb5_unparse_name(contextp, ticket->client, &client); - if (ret) - krb5_err (contextp, 1, ret, "krb5_unparse_name"); - krb5_free_ticket (contextp, ticket); + krb5_free_ticket(contextp, ticket); + if (ret) { + krb5_err(contextp, 1, ret, "krb5_unparse_name"); + return; + } ret = kadm5_s_init_with_password_ctx(contextp, client, NULL, @@ -885,9 +838,11 @@ handle_v5(krb5_context contextp, &realm_params, 0, 0, &kadm_handlep); - if(ret) - krb5_err (contextp, 1, ret, "kadm5_init_with_password_ctx"); - v5_loop (contextp, ac, initial, kadm_handlep, fd, readonly); + if (ret) { + krb5_err(contextp, 1, ret, "kadm5_init_with_password_ctx"); + return; + } + v5_loop(contextp, ac, initial, kadm_handlep, fd, readonly); } krb5_error_code diff --git a/third_party/heimdal/kadmin/stash.c b/third_party/heimdal/kadmin/stash.c index 785de43f872e..c33623038ce4 100644 --- a/third_party/heimdal/kadmin/stash.c +++ b/third_party/heimdal/kadmin/stash.c @@ -106,7 +106,10 @@ stash(struct stash_options *opt, int argc, char **argv) } } ret = krb5_string_to_key_salt(context, enctype, buf, salt, &key); - ret = hdb_add_master_key(context, &key, &mkey); + if (ret == 0) + ret = hdb_add_master_key(context, &key, &mkey); + if (ret) + krb5_warn(context, errno, "setting master key"); krb5_free_keyblock_contents(context, &key); } diff --git a/third_party/heimdal/kcm/cache.c b/third_party/heimdal/kcm/cache.c index 02624dfd1c83..b11812769b67 100644 --- a/third_party/heimdal/kcm/cache.c +++ b/third_party/heimdal/kcm/cache.c @@ -168,9 +168,9 @@ krb5_error_code kcm_debug_ccache(krb5_context context) ncreds++; if (p->client != NULL) - krb5_unparse_name(context, p->client, &cpn); + (void) krb5_unparse_name(context, p->client, &cpn); if (p->server != NULL) - krb5_unparse_name(context, p->server, &spn); + (void) krb5_unparse_name(context, p->server, &spn); kcm_log(7, "cache %08x: name %s refcnt %d flags %04x mode %04o " "uid %d gid %d client %s server %s ncreds %d", @@ -179,10 +179,8 @@ krb5_error_code kcm_debug_ccache(krb5_context context) (spn == NULL) ? "" : spn, ncreds); - if (cpn != NULL) - free(cpn); - if (spn != NULL) - free(spn); + free(cpn); + free(spn); } return 0; diff --git a/third_party/heimdal/kcm/client.c b/third_party/heimdal/kcm/client.c index 09c94b6e8ddd..061d4e972676 100644 --- a/third_party/heimdal/kcm/client.c +++ b/third_party/heimdal/kcm/client.c @@ -46,6 +46,43 @@ kcm_ccache_resolve_client(krb5_context context, const char *estr; ret = kcm_ccache_resolve(context, name, ccache); + if (ret) { + char *uid = NULL; + + /* + * Both MIT and Heimdal are unable to, in krb5_cc_default(), call to + * KCM (or CCAPI, or LSA, or...) to get the user's default ccache name + * in their collection. Instead, the default ccache name is obtained + * in a static way, and for KCM that's "%{UID}". When we + * krb5_cc_switch(), we simply maintain a pointer to the name of the + * ccache that was made the default, but klist can't make use of this + * because krb5_cc_default() can't. + * + * The solution here is to first try resolving the ccache name given by + * the client, and if that fails but the name happens to be what would + * be the library's default KCM ccache name for that user, then try + * resolving it through the default ccache name pointer saved at switch + * time. + */ + if (asprintf(&uid, "%llu", (unsigned long long)client->uid) == -1 || + uid == NULL) + return ENOMEM; + + if (strcmp(name, uid) == 0) { + struct kcm_default_cache *c; + + for (c = default_caches; c != NULL; c = c->next) { + if (kcm_is_same_session(client, c->uid, c->session)) { + if (strcmp(c->name, name) != 0) { + ret = kcm_ccache_resolve(context, c->name, ccache); + break; + } + } + } + } + free(uid); + } + if (ret) { estr = krb5_get_error_message(context, ret); kcm_log(1, "Failed to resolve cache %s: %s", name, estr); diff --git a/third_party/heimdal/kcm/glue.c b/third_party/heimdal/kcm/glue.c index 713af7f8650c..0895f48f051c 100644 --- a/third_party/heimdal/kcm/glue.c +++ b/third_party/heimdal/kcm/glue.c @@ -55,7 +55,7 @@ kcmss_get_name_2(krb5_context context, *name = CACHENAME(id); if (col) *col = NULL; - if (name) + if (sub) *sub = CACHENAME(id); return 0; } diff --git a/third_party/heimdal/kcm/protocol.c b/third_party/heimdal/kcm/protocol.c index c36bbe9c6c67..31f17623d01d 100644 --- a/third_party/heimdal/kcm/protocol.c +++ b/third_party/heimdal/kcm/protocol.c @@ -423,7 +423,7 @@ kcm_op_get_principal(krb5_context context, free(name); kcm_release_ccache(context, ccache); - return 0; + return ret; } /* @@ -1537,13 +1537,6 @@ kcm_op_do_ntlm(krb5_context context, } free(tmpsesskey.data); - if (ret) { - if (type3.lm.data) - free(type3.lm.data); - if (type3.ntlm.data) - free(type3.ntlm.data); - goto error; - } flags |= NTLM_FLAG_SESSIONKEY; #if 0 } else { @@ -1754,6 +1747,7 @@ kcm_dispatch(krb5_context context, krb5_storage *resp_sp = NULL; uint16_t opcode; + krb5_data_zero(resp_data); resp_sp = krb5_storage_emem(); if (resp_sp == NULL) { return ENOMEM; @@ -1803,11 +1797,17 @@ out: krb5_storage_free(req_sp); } - krb5_storage_seek(resp_sp, 0, SEEK_SET); - krb5_store_int32(resp_sp, ret); + if (resp_sp) { + krb5_error_code ret2; - ret = krb5_storage_to_data(resp_sp, resp_data); - krb5_storage_free(resp_sp); + krb5_storage_seek(resp_sp, 0, SEEK_SET); + ret2 = krb5_store_int32(resp_sp, ret); + if (ret2 == 0) + ret2 = krb5_storage_to_data(resp_sp, resp_data); + krb5_storage_free(resp_sp); + if (ret2) + ret = ret2; + } return ret; } diff --git a/third_party/heimdal/kdc/Makefile.am b/third_party/heimdal/kdc/Makefile.am index 54382a842bf4..c7f57251f7c8 100644 --- a/third_party/heimdal/kdc/Makefile.am +++ b/third_party/heimdal/kdc/Makefile.am @@ -2,6 +2,8 @@ include $(top_srcdir)/Makefile.am.common +WFLAGS += $(WFLAGS_ENUM_CONV) + AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_openssl_crypto) -I$(srcdir)/../lib/krb5 lib_LTLIBRARIES = simple_csr_authorizer.la ipc_csr_authorizer.la \ @@ -112,6 +114,8 @@ altsecid_gss_preauth_authorizer_la_LDFLAGS = -module \ $(LIB_openldap) endif +libkdc_la_CPPFLAGS = -DBUILD_KDC_LIB $(AM_CPPFLAGS) + libkdc_la_SOURCES = \ default_config.c \ ca.c \ @@ -123,15 +127,15 @@ libkdc_la_SOURCES = \ krb5tgs.c \ pkinit.c \ pkinit-ec.c \ + mssfu.c \ log.c \ misc.c \ kx509.c \ token_validator.c \ csr_authorizer.c \ process.c \ - windc.c \ - gss_preauth.c \ - rx.h + kdc-plugin.c \ + gss_preauth.c KDC_PROTOS = $(srcdir)/kdc-protos.h $(srcdir)/kdc-private.h @@ -168,7 +172,7 @@ endif $(libkdc_la_OBJECTS): $(srcdir)/version-script.map $(srcdir)/kdc-protos.h: $(libkdc_la_SOURCES) - cd $(srcdir) && perl ../cf/make-proto.pl -q -P comment -o kdc-protos.h $(libkdc_la_SOURCES) || rm -f kdc-protos.h + cd $(srcdir) && perl ../cf/make-proto.pl -E KDC_LIB -q -P comment -o kdc-protos.h $(libkdc_la_SOURCES) || rm -f kdc-protos.h $(srcdir)/kdc-private.h: $(libkdc_la_SOURCES) cd $(srcdir) && perl ../cf/make-proto.pl -q -P comment -p kdc-private.h $(libkdc_la_SOURCES) || rm -f kdc-private.h @@ -240,7 +244,7 @@ include_HEADERS = kdc.h $(srcdir)/kdc-protos.h noinst_HEADERS = $(srcdir)/kdc-private.h krb5dir = $(includedir)/krb5 -krb5_HEADERS = windc_plugin.h token_validator_plugin.h csr_authorizer_plugin.h +krb5_HEADERS = kdc-audit.h kdc-plugin.h kdc-accessors.h token_validator_plugin.h csr_authorizer_plugin.h gss_preauth_authorizer_plugin.h build_HEADERZ = $(krb5_HEADERS) # XXX diff --git a/third_party/heimdal/kdc/NTMakefile b/third_party/heimdal/kdc/NTMakefile index 58eb7577141e..aca65b104ae8 100644 --- a/third_party/heimdal/kdc/NTMakefile +++ b/third_party/heimdal/kdc/NTMakefile @@ -33,7 +33,7 @@ RELDIR=kdc !include ../windows/NTMakefile.w32 -intcflags=-I$(OBJ) -I$(SRC)\lib\gssapi -I$(OBJDIR)\lib\gssapi -I$(OBJDIR)\lib\gss_preauth +intcflags=-I$(OBJ) -I$(SRC)\lib\gssapi -I$(OBJDIR)\lib\gssapi -I$(OBJDIR)\lib\gss_preauth -DBUILD_KDC_LIB BINPROGRAMS=$(BINDIR)\string2key.exe @@ -51,7 +51,9 @@ INCFILES=\ $(INCDIR)\kdc.h \ $(INCDIR)\kdc-protos.h \ $(INCDIR)\kdc-private.h \ - $(INCDIR)\krb5\windc_plugin.h + $(INCDIR)\krb5\kdc-audit.h \ + $(INCDIR)\krb5\kdc-plugin.h \ + $(INCDIR)\krb5\kdc-accessors.h all:: $(INCFILES) $(LIBKDC) $(BINPROGRAMS) $(SBINPROGRAMS) $(LIBEXECPROGRAMS) @@ -103,13 +105,14 @@ LIBKDC_OBJS=\ $(OBJ)\krb5tgs.obj \ $(OBJ)\pkinit.obj \ $(OBJ)\pkinit-ec.obj \ + $(OBJ)\mssfu.obj \ $(OBJ)\log.obj \ $(OBJ)\misc.obj \ $(OBJ)\kx509.obj \ $(OBJ)\token_validator.obj \ $(OBJ)\csr_authorizer.obj \ $(OBJ)\process.obj \ - $(OBJ)\windc.obj \ + $(OBJ)\kdc-plugin.obj \ $(OBJ)\gss_preauth.obj LIBKDC_LIBS=\ @@ -144,18 +147,19 @@ libkdc_la_SOURCES = \ krb5tgs.c \ pkinit.c \ pkinit-ec.c \ + mssfu.c \ log.c \ misc.c \ kx509.c \ token_validator.c \ csr_authorizer.c \ process.c \ - windc.c \ - gss_preauth.c \ - rx.h + kdc-plugin.c \ + gss_preauth.c $(OBJ)\kdc-protos.h: $(libkdc_la_SOURCES) - $(PERL) ..\cf\make-proto.pl -q -P remove -o $@ $(libkdc_la_SOURCES) \ + cd $(SRCDIR) + $(PERL) ..\cf\make-proto.pl -E KDC_LIB -q -P remove -o $@ $(libkdc_la_SOURCES) \ || $(RM) $@ $(OBJ)\kdc-private.h: $(libkdc_la_SOURCES) diff --git a/third_party/heimdal/kdc/altsecid_gss_preauth_authorizer.c b/third_party/heimdal/kdc/altsecid_gss_preauth_authorizer.c index 961ced0db9a6..d48ea584bc8e 100644 --- a/third_party/heimdal/kdc/altsecid_gss_preauth_authorizer.c +++ b/third_party/heimdal/kdc/altsecid_gss_preauth_authorizer.c @@ -272,7 +272,7 @@ ad_lookup(krb5_context context, gss_const_name_t initiator_name, gss_const_OID mech_type, krb5_principal *canon_principal, - krb5_data *requestor_sid) + kdc_data_t *requestor_sid) { krb5_error_code ret; OM_uint32 minor; @@ -286,7 +286,8 @@ ad_lookup(krb5_context context, struct berval **values = NULL; *canon_principal = NULL; - krb5_data_zero(requestor_sid); + if (requestor_sid) + *requestor_sid = NULL; mech_type_str = gss_oid_to_name(mech_type); if (mech_type_str == NULL) { @@ -335,25 +336,29 @@ ad_lookup(krb5_context context, if (m0 == NULL) goto out; + values = ldap_get_values_len(server->ld, m0, "sAMAccountName"); + if (values == NULL || + ldap_count_values_len(values) == 0) + goto out; + + ret = krb5_make_principal(context, canon_principal, realm, + values[0]->bv_val, NULL); + if (ret) + goto out; + if (requestor_sid) { + ldap_value_free_len(values); + values = ldap_get_values_len(server->ld, m0, "objectSid"); if (values == NULL || ldap_count_values_len(values) == 0) goto out; - if (krb5_data_copy(requestor_sid, values[0]->bv_val, values[0]->bv_len) != 0) + *requestor_sid = kdc_data_create(values[0]->bv_val, values[0]->bv_len); + if (*requestor_sid == NULL) goto enomem; - - ldap_value_free_len(values); } - values = ldap_get_values_len(server->ld, m0, "sAMAccountName"); - if (values == NULL || - ldap_count_values_len(values) == 0) - goto out; - - ret = krb5_make_principal(context, canon_principal, realm, - values[0]->bv_val, NULL); goto out; enomem: @@ -361,6 +366,16 @@ enomem: goto out; out: + if (ret) { + krb5_free_principal(context, *canon_principal); + *canon_principal = NULL; + + if (requestor_sid) { + kdc_object_release(*requestor_sid); + *requestor_sid = NULL; + } + } + ldap_value_free_len(values); ldap_msgfree(m); ldap_memfree(basedn); @@ -377,25 +392,27 @@ authorize(void *ctx, gss_const_OID mech_type, OM_uint32 ret_flags, krb5_boolean *authorized, - krb5_principal *mapped_name, - krb5_data *requestor_sid) + krb5_principal *mapped_name) { struct altsecid_gss_preauth_authorizer_context *c = ctx; struct ad_server_tuple *server = NULL; krb5_error_code ret; - krb5_const_realm realm = krb5_principal_get_realm(r->context, r->client->entry.principal); + krb5_context context = kdc_request_get_context((kdc_request_t)r); + const hdb_entry *client = kdc_request_get_client(r); + krb5_const_principal server_princ = kdc_request_get_server_princ(r); + krb5_const_realm realm = krb5_principal_get_realm(context, client->principal); krb5_boolean reconnect_p = FALSE; krb5_boolean is_tgs; + kdc_data_t requestor_sid = NULL; *authorized = FALSE; *mapped_name = NULL; - krb5_data_zero(requestor_sid); - if (!krb5_principal_is_federated(r->context, r->client->entry.principal) || + if (!krb5_principal_is_federated(context, client->principal) || (ret_flags & GSS_C_ANON_FLAG)) return KRB5_PLUGIN_NO_HANDLE; - is_tgs = krb5_principal_is_krbtgt(r->context, r->server_princ); + is_tgs = krb5_principal_is_krbtgt(context, server_princ); HEIM_TAILQ_FOREACH(server, &c->servers, link) { if (strcmp(realm, server->realm) == 0) @@ -405,12 +422,12 @@ authorize(void *ctx, if (server == NULL) { server = calloc(1, sizeof(*server)); if (server == NULL) - return krb5_enomem(r->context); + return krb5_enomem(context); server->realm = strdup(realm); if (server->realm == NULL) { free(server); - return krb5_enomem(r->context); + return krb5_enomem(context); } HEIM_TAILQ_INSERT_HEAD(&c->servers, server, link); @@ -418,14 +435,14 @@ authorize(void *ctx, do { if (server->ld == NULL) { - ret = ad_connect(r->context, realm, server); + ret = ad_connect(context, realm, server); if (ret) return ret; } - ret = ad_lookup(r->context, realm, server, + ret = ad_lookup(context, realm, server, initiator_name, mech_type, - mapped_name, is_tgs ? requestor_sid : NULL); + mapped_name, is_tgs ? &requestor_sid : NULL); if (ret == KRB5KDC_ERR_SVC_UNAVAILABLE) { ldap_unbind_ext_s(server->ld, NULL, NULL); server->ld = NULL; @@ -437,17 +454,29 @@ authorize(void *ctx, *authorized = (ret == 0); } while (reconnect_p); + if (requestor_sid) { + kdc_request_set_attribute((kdc_request_t)r, + HSTR("org.h5l.gss-pa-requestor-sid"), requestor_sid); + kdc_object_release(requestor_sid); + } + return ret; } static KRB5_LIB_CALL krb5_error_code -finalize_pac(void *ctx, astgs_request_t r, krb5_data *requestor_sid) +finalize_pac(void *ctx, astgs_request_t r) { - if (requestor_sid->length == 0) + kdc_data_t requestor_sid; + + requestor_sid = kdc_request_get_attribute((kdc_request_t)r, + HSTR("org.h5l.gss-pa-requestor-sid")); + if (requestor_sid == NULL) return 0; - return krb5_pac_add_buffer(r->context, r->pac, - PAC_REQUESTOR_SID, requestor_sid); + kdc_audit_setkv_object((kdc_request_t)r, "gss_requestor_sid", requestor_sid); + + return kdc_request_add_pac_buffer(r, PAC_REQUESTOR_SID, + kdc_data_get_data(requestor_sid)); } static KRB5_LIB_CALL krb5_error_code @@ -494,8 +523,6 @@ altsecid_gss_preauth_authorizer_get_instance(const char *libname) return krb5_get_instance(libname); if (strcmp(libname, "kdc") == 0) return kdc_get_instance(libname); - if (strcmp(libname, "gssapi") == 0) - return gss_get_instance(libname); return 0; } diff --git a/third_party/heimdal/kdc/bx509d.c b/third_party/heimdal/kdc/bx509d.c index 2f30744bf31d..064c424b7c29 100644 --- a/third_party/heimdal/kdc/bx509d.c +++ b/third_party/heimdal/kdc/bx509d.c @@ -112,6 +112,22 @@ #define heim_pconfig krb5_context #include +#if MHD_VERSION < 0x00097002 || defined(MHD_YES) +/* libmicrohttpd changed these from int valued macros to an enum in 0.9.71 */ +#ifdef MHD_YES +#undef MHD_YES +#undef MHD_NO +#endif +enum MHD_Result { MHD_NO = 0, MHD_YES = 1 }; +#define MHD_YES 1 +#define MHD_NO 0 +typedef int heim_mhd_result; +#else +typedef enum MHD_Result heim_mhd_result; +#endif + +enum k5_creds_kind { K5_CREDS_EPHEMERAL, K5_CREDS_CACHED }; + typedef struct bx509_request_desc { HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; @@ -122,6 +138,7 @@ typedef struct bx509_request_desc { const char *for_cname; const char *target; const char *redir; + enum k5_creds_kind cckind; char *pkix_store; char *ccname; char *freeme1; @@ -485,8 +502,8 @@ bad_reqv(struct bx509_request_desc *r, char *formatted = NULL; char *msg = NULL; - heim_audit_addkv((heim_svc_req_desc)r, 0, "http-status-code", "%d", - http_status_code); + heim_audit_setkv_number((heim_svc_req_desc)r, "http-status-code", + http_status_code); (void) gettimeofday(&r->tv_end, NULL); if (code == ENOMEM) { if (r->context) @@ -511,7 +528,7 @@ bad_reqv(struct bx509_request_desc *r, msg = formatted; formatted = NULL; } - heim_audit_addreason((heim_svc_req_desc)r, "%s", formatted); + heim_audit_addreason((heim_svc_req_desc)r, "%s", msg); audit_trail(r, code); krb5_free_error_message(context, k5msg); @@ -606,10 +623,20 @@ static krb5_error_code good_bx509(struct bx509_request_desc *r) { krb5_error_code ret; + const char *fn; size_t bodylen; void *body; - ret = rk_undumpdata(strchr(r->pkix_store, ':') + 1, &body, &bodylen); + /* + * This `fn' thing is just to quiet linters that think "hey, strchr() can + * return NULL so...", but here we've build `r->pkix_store' and know it has + * a ':'. + */ + if (r->pkix_store == NULL) + return bad_503(r, EINVAL, "Internal error"); /* Quiet warnings */ + fn = strchr(r->pkix_store, ':'); + fn = fn ? fn + 1 : r->pkix_store; + ret = rk_undumpdata(fn, &body, &bodylen); if (ret) return bad_503(r, ret, "Could not recover issued certificate " "from PKIX store"); @@ -621,7 +648,7 @@ good_bx509(struct bx509_request_desc *r) return ret; } -static int +static heim_mhd_result bx509_param_cb(void *d, enum MHD_ValueKind kind, const char *key, @@ -633,53 +660,53 @@ bx509_param_cb(void *d, if (strcmp(key, "eku") == 0 && val) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_eku", "%s", val); - r->ret = der_parse_heim_oid(val, ".", &oid); - if (r->ret == 0) - r->ret = hx509_request_add_eku(r->context->hx509ctx, r->req, &oid); + r->error_code = der_parse_heim_oid(val, ".", &oid); + if (r->error_code == 0) + r->error_code = hx509_request_add_eku(r->context->hx509ctx, r->req, &oid); der_free_oid(&oid); } else if (strcmp(key, "dNSName") == 0 && val) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_dNSName", "%s", val); - r->ret = hx509_request_add_dns_name(r->context->hx509ctx, r->req, val); + r->error_code = hx509_request_add_dns_name(r->context->hx509ctx, r->req, val); } else if (strcmp(key, "rfc822Name") == 0 && val) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_rfc822Name", "%s", val); - r->ret = hx509_request_add_email(r->context->hx509ctx, r->req, val); + r->error_code = hx509_request_add_email(r->context->hx509ctx, r->req, val); } else if (strcmp(key, "xMPPName") == 0 && val) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_xMPPName", "%s", val); - r->ret = hx509_request_add_xmpp_name(r->context->hx509ctx, r->req, + r->error_code = hx509_request_add_xmpp_name(r->context->hx509ctx, r->req, val); } else if (strcmp(key, "krb5PrincipalName") == 0 && val) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_krb5PrincipalName", "%s", val); - r->ret = hx509_request_add_pkinit(r->context->hx509ctx, r->req, + r->error_code = hx509_request_add_pkinit(r->context->hx509ctx, r->req, val); } else if (strcmp(key, "ms-upn") == 0 && val) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_ms_upn", "%s", val); - r->ret = hx509_request_add_ms_upn_name(r->context->hx509ctx, r->req, + r->error_code = hx509_request_add_ms_upn_name(r->context->hx509ctx, r->req, val); } else if (strcmp(key, "registeredID") == 0 && val) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_registered_id", "%s", val); - r->ret = der_parse_heim_oid(val, ".", &oid); - if (r->ret == 0) - r->ret = hx509_request_add_registered(r->context->hx509ctx, r->req, + r->error_code = der_parse_heim_oid(val, ".", &oid); + if (r->error_code == 0) + r->error_code = hx509_request_add_registered(r->context->hx509ctx, r->req, &oid); der_free_oid(&oid); } else if (strcmp(key, "csr") == 0 && val) { - heim_audit_addkv((heim_svc_req_desc)r, 0, "requested_csr", "true"); - r->ret = 0; /* Handled upstairs */ + heim_audit_setkv_bool((heim_svc_req_desc)r, "requested_csr", TRUE); + r->error_code = 0; /* Handled upstairs */ } else if (strcmp(key, "lifetime") == 0 && val) { r->req_life = parse_time(val, "day"); } else { /* Produce error for unknown params */ - heim_audit_addkv((heim_svc_req_desc)r, 0, "requested_unknown", "true"); - krb5_set_error_message(r->context, r->ret = ENOTSUP, + heim_audit_setkv_bool((heim_svc_req_desc)r, "requested_unknown", TRUE); + krb5_set_error_message(r->context, r->error_code = ENOTSUP, "Query parameter %s not supported", key); } - return r->ret == 0 ? MHD_YES : MHD_NO /* Stop iterating */; + return r->error_code == 0 ? MHD_YES : MHD_NO /* Stop iterating */; } static krb5_error_code @@ -693,10 +720,10 @@ authorize_CSR(struct bx509_request_desc *r, if (ret) return bad_req(r, ret, MHD_HTTP_SERVICE_UNAVAILABLE, "Could not parse CSR"); - r->ret = 0; + r->error_code = 0; (void) MHD_get_connection_values(r->connection, MHD_GET_ARGUMENT_KIND, bx509_param_cb, r); - ret = r->ret; + ret = r->error_code; if (ret) return bad_req(r, ret, MHD_HTTP_SERVICE_UNAVAILABLE, "Could not handle query parameters"); @@ -771,6 +798,7 @@ do_CA(struct bx509_request_desc *r, const char *csr) /* Set CSR */ if ((d.data = malloc(strlen(csr2))) == NULL) { krb5_free_principal(r->context, p); + free(csr2); return bad_enomem(r, ENOMEM); } @@ -818,11 +846,9 @@ do_CA(struct bx509_request_desc *r, const char *csr) ret = store_certs(r->context->hx509ctx, r->pkix_store, certs, NULL); hx509_certs_free(&certs); - if (ret) { - (void) unlink(strchr(r->pkix_store, ':') + 1); - return bad_500(r, ret, - "Failed convert issued certificate and chain to PEM"); - } + if (ret) + return bad_500(r, ret, "Failed to convert issued" + " certificate and chain to PEM"); return 0; } @@ -864,7 +890,7 @@ set_req_desc(struct MHD_Connection *connection, r->from = r->frombuf; r->tgt_addresses.len = 0; r->tgt_addresses.val = 0; - r->hcontext = r->context->hcontext; + r->hcontext = r->context ? r->context->hcontext : NULL; r->config = NULL; r->logf = logfac; r->reqtype = url; @@ -880,8 +906,11 @@ set_req_desc(struct MHD_Connection *connection, r->addr = NULL; r->req = NULL; r->req_life = 0; - r->ret = 0; - r->kv = heim_array_create(); + r->error_code = ret; + r->kv = heim_dict_create(10); + r->attributes = heim_dict_create(1); + if (ret == 0 && (r->kv == NULL || r->attributes == NULL)) + r->error_code = ret = ENOMEM; ci = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); if (ci) { @@ -905,10 +934,6 @@ set_req_desc(struct MHD_Connection *connection, } - if (ret == 0 && r->kv == NULL) { - krb5_log_msg(r->context, logfac, 1, NULL, "Out of memory"); - ret = ENOMEM; - } return ret; } @@ -917,12 +942,28 @@ clean_req_desc(struct bx509_request_desc *r) { if (!r) return; - if (r->pkix_store) - (void) unlink(strchr(r->pkix_store, ':') + 1); + if (r->pkix_store) { + const char *fn = strchr(r->pkix_store, ':'); + + /* + * This `fn' thing is just to quiet linters that think "hey, strchr() can + * return NULL so...", but here we've build `r->pkix_store' and know it has + * a ':'. + */ + fn = fn ? fn + 1 : r->pkix_store; + (void) unlink(fn); + } krb5_free_addresses(r->context, &r->tgt_addresses); hx509_request_free(&r->req); heim_release(r->reason); heim_release(r->kv); + if (r->ccname && r->cckind == K5_CREDS_EPHEMERAL) { + const char *fn = r->ccname; + + if (strncmp(fn, "FILE:", sizeof("FILE:") - 1) == 0) + fn += sizeof("FILE:") - 1; + (void) unlink(fn); + } free(r->pkix_store); free(r->freeme1); free(r->ccname); @@ -966,6 +1007,8 @@ bx509(struct bx509_request_desc *r) * '~' and '.' also get encoded, and '@' does not. * * A corresponding decoder is not needed. + * + * XXX Maybe use krb5_cc_default_for()! */ static size_t princ_fs_encode_sz(const char *in) @@ -1045,8 +1088,10 @@ find_ccache(krb5_context context, const char *princ, char **ccname) */ if ((s = princ_fs_encode(princ)) == NULL || asprintf(ccname, "FILE:%s/%s.cc", cache_dir, s) == -1 || - *ccname == NULL) + *ccname == NULL) { + free(s); return ENOMEM; + } free(s); if ((ret = krb5_cc_resolve(context, *ccname, &cc))) { @@ -1067,13 +1112,10 @@ find_ccache(krb5_context context, const char *princ, char **ccname) return ret ? ret : ENOENT; } -enum k5_creds_kind { K5_CREDS_EPHEMERAL, K5_CREDS_CACHED }; - static krb5_error_code get_ccache(struct bx509_request_desc *r, krb5_ccache *cc, int *won) { krb5_error_code ret = 0; - struct stat st1, st2; char *temp_ccname = NULL; const char *fn = NULL; time_t life; @@ -1103,6 +1145,7 @@ get_ccache(struct bx509_request_desc *r, krb5_ccache *cc, int *won) if (ret == 0) fn = temp_ccname + sizeof("FILE:") - 1; if (ret == 0) do { + struct stat st1, st2; /* * Open and flock the temp ccache file. * @@ -1115,6 +1158,8 @@ get_ccache(struct bx509_request_desc *r, krb5_ccache *cc, int *won) fd = -1; } errno = 0; + memset(&st1, 0, sizeof(st1)); + memset(&st2, 0xff, sizeof(st2)); if (ret == 0 && ((fd = open(fn, O_RDWR | O_CREAT, 0600)) == -1 || flock(fd, LOCK_EX) == -1 || @@ -1186,7 +1231,8 @@ do_pkinit(struct bx509_request_desc *r, enum k5_creds_kind kind) ret = krb5_cc_new_unique(r->context, "FILE", NULL, &temp_cc); } - ret = krb5_parse_name(r->context, cname, &p); + if (ret == 0) + ret = krb5_parse_name(r->context, cname, &p); if (ret == 0) crealm = krb5_principal_get_realm(r->context, p); if (ret == 0) @@ -1304,7 +1350,7 @@ k5_do_CA(struct bx509_request_desc *r) if (ret == 0) ret = krb5_parse_name(r->context, cname, &p); if (ret == 0) - hx509_private_key2SPKI(r->context->hx509ctx, key, &spki); + ret = hx509_private_key2SPKI(r->context->hx509ctx, key, &spki); if (ret == 0) hx509_request_set_SubjectPublicKeyInfo(r->context->hx509ctx, req, &spki); @@ -1366,6 +1412,7 @@ k5_get_creds(struct bx509_request_desc *r, enum k5_creds_kind kind) const char *cname = r->for_cname ? r->for_cname : r->cname; /* If we have a live ccache for `cprinc', we're done */ + r->cckind = kind; if (kind == K5_CREDS_CACHED && (ret = find_ccache(r->context, cname, &r->ccname)) == 0) return ret; /* Success */ @@ -1638,8 +1685,7 @@ bnegotiate(struct bx509_request_desc *r) if (ret == 0) { heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "target", "%s", r->target ? r->target : ""); - heim_audit_addkv((heim_svc_req_desc)r, 0, "redir", "%s", - r->redir ? "yes" : "no"); + heim_audit_setkv_bool((heim_svc_req_desc)r, "redir", !!r->redir); ret = validate_token(r); } /* bnegotiate_get_target() and validate_token() call bad_req() */ @@ -1688,7 +1734,8 @@ authorize_TGT_REQ(struct bx509_request_desc *r) return 0; ret = krb5_parse_name(r->context, r->cname, &p); - ret = hx509_request_init(r->context->hx509ctx, &r->req); + if (ret == 0) + ret = hx509_request_init(r->context->hx509ctx, &r->req); if (ret) return bad_500(r, ret, "Out of resources"); heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, @@ -1707,7 +1754,7 @@ authorize_TGT_REQ(struct bx509_request_desc *r) return ret; } -static int +static heim_mhd_result get_tgt_param_cb(void *d, enum MHD_ValueKind kind, const char *key, @@ -1719,15 +1766,15 @@ get_tgt_param_cb(void *d, if (!krb5_config_get_bool_default(r->context, NULL, FALSE, "get-tgt", "allow_addresses", NULL)) { - krb5_set_error_message(r->context, r->ret = ENOTSUP, + krb5_set_error_message(r->context, r->error_code = ENOTSUP, "Query parameter %s not allowed", key); } else { krb5_addresses addresses; - r->ret = _krb5_parse_address_no_lookup(r->context, val, + r->error_code = _krb5_parse_address_no_lookup(r->context, val, &addresses); - if (r->ret == 0) - r->ret = krb5_append_addresses(r->context, &r->tgt_addresses, + if (r->error_code == 0) + r->error_code = krb5_append_addresses(r->context, &r->tgt_addresses, &addresses); krb5_free_addresses(r->context, &addresses); } @@ -1738,11 +1785,11 @@ get_tgt_param_cb(void *d, r->req_life = parse_time(val, "day"); } else { /* Produce error for unknown params */ - heim_audit_addkv((heim_svc_req_desc)r, 0, "requested_unknown", "true"); - krb5_set_error_message(r->context, r->ret = ENOTSUP, + heim_audit_setkv_bool((heim_svc_req_desc)r, "requested_unknown", TRUE); + krb5_set_error_message(r->context, r->error_code = ENOTSUP, "Query parameter %s not supported", key); } - return r->ret == 0 ? MHD_YES : MHD_NO /* Stop iterating */; + return r->error_code == 0 ? MHD_YES : MHD_NO /* Stop iterating */; } /* @@ -1772,13 +1819,14 @@ get_tgt(struct bx509_request_desc *r) if (ret) return ret; - r->ret = 0; + r->error_code = 0; (void) MHD_get_connection_values(r->connection, MHD_GET_ARGUMENT_KIND, get_tgt_param_cb, r); - ret = r->ret; + ret = r->error_code; /* k5_get_creds() calls bad_req() */ - ret = k5_get_creds(r, K5_CREDS_EPHEMERAL); + if (ret == 0) + ret = k5_get_creds(r, K5_CREDS_EPHEMERAL); if (ret) return ret; @@ -1786,10 +1834,8 @@ get_tgt(struct bx509_request_desc *r) if (fn == NULL) return bad_500(r, ret, "Impossible error"); fn++; - if ((errno = rk_undumpdata(fn, &body, &bodylen))) { - (void) unlink(fn); + if ((errno = rk_undumpdata(fn, &body, &bodylen))) return bad_503(r, ret, "Could not get TGT"); - } ret = resp(r, MHD_HTTP_OK, MHD_RESPMEM_MUST_COPY, "application/x-krb5-ccache", body, bodylen, NULL); @@ -1811,7 +1857,7 @@ health(const char *method, struct bx509_request_desc *r) } /* Implements the entirety of this REST service */ -static int +static heim_mhd_result route(void *cls, struct MHD_Connection *connection, const char *url, @@ -2013,6 +2059,8 @@ main(int argc, char **argv) argc -= optidx; argv += optidx; + if (argc != 0) + usage(1); if ((errno = pthread_key_create(&k5ctx, k5_free_context))) err(1, "Could not create thread-specific storage"); diff --git a/third_party/heimdal/kdc/ca.c b/third_party/heimdal/kdc/ca.c index 0d92ca7fc89f..4402c44677fb 100644 --- a/third_party/heimdal/kdc/ca.c +++ b/third_party/heimdal/kdc/ca.c @@ -97,7 +97,7 @@ get_cf(krb5_context context, /* * Build a certifate for `principal' and its CSR. */ -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL kdc_issue_certificate(krb5_context context, const char *app_name, krb5_log_facility *logf, @@ -129,5 +129,5 @@ kdc_issue_certificate(krb5_context context, out); if (ret == EACCES) ret = KRB5KDC_ERR_POLICY; - return (ret == EACCES) ? KRB5KDC_ERR_POLICY : ret; + return ret; } diff --git a/third_party/heimdal/kdc/cjwt_token_validator.c b/third_party/heimdal/kdc/cjwt_token_validator.c index 68fe01594f8e..93742e5ddd55 100644 --- a/third_party/heimdal/kdc/cjwt_token_validator.c +++ b/third_party/heimdal/kdc/cjwt_token_validator.c @@ -107,13 +107,13 @@ get_issuer_pubkeys(krb5_context context, if (!previous->length && !current->length && !next->length) krb5_set_error_message(context, save_ret, "Could not read jwk issuer public key files"); - if (current->length == next->length && + if (current->length && current->length == next->length && memcmp(current->data, next->data, next->length) == 0) { free(next->data); next->data = 0; next->length = 0; } - if (current->length == previous->length && + if (current->length && current->length == previous->length && memcmp(current->data, previous->data, previous->length) == 0) { free(previous->data); previous->data = 0; @@ -255,6 +255,11 @@ validate(void *ctx, tokstr = NULL; switch (ret) { case 0: + if (jwt == NULL) { + krb5_set_error_message(context, EINVAL, "JWT validation failed"); + free(defrealm); + return EPERM; + } if (jwt->header.alg == alg_none) { krb5_set_error_message(context, EINVAL, "JWT signature algorithm " "not supported"); diff --git a/third_party/heimdal/kdc/config.c b/third_party/heimdal/kdc/config.c index 507cb195af3f..e217b9dadfa5 100644 --- a/third_party/heimdal/kdc/config.c +++ b/third_party/heimdal/kdc/config.c @@ -309,7 +309,7 @@ configure(krb5_context context, int argc, char **argv, int *optidx) krb5_enctype_disable(context, ETYPE_DES_PCBC_NONE); } - krb5_kdc_windc_init(context); + krb5_kdc_plugin_init(context); krb5_kdc_pkinit_config(context, config); diff --git a/third_party/heimdal/kdc/connect.c b/third_party/heimdal/kdc/connect.c index 975f24cb269a..ba8c8ad7ba54 100644 --- a/third_party/heimdal/kdc/connect.c +++ b/third_party/heimdal/kdc/connect.c @@ -263,7 +263,8 @@ init_socket(krb5_context context, #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR) { int one = 1; - setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); + (void) setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, + sizeof(one)); } #endif d->type = type; @@ -620,15 +621,22 @@ handle_vanilla_tcp (krb5_context context, krb5_kdc_configuration *config, struct descr *d) { + krb5_error_code ret; krb5_storage *sp; uint32_t len; + if (d->len < 4) + return 0; sp = krb5_storage_from_mem(d->buf, d->len); if (sp == NULL) { kdc_log (context, config, 1, "krb5_storage_from_mem failed"); return -1; } - krb5_ret_uint32(sp, &len); + ret = krb5_ret_uint32(sp, &len); + if (ret) { + kdc_log(context, config, 4, "failed to read request length"); + return -1; + } krb5_storage_free(sp); if(d->len - 4 >= len) { memmove(d->buf, d->buf + 4, d->len - 4); @@ -1064,7 +1072,7 @@ reap_kid(krb5_context context, krb5_kdc_configuration *config, pid_t *pids, int max_kids, int options) { pid_t pid; - char *what; + char *what = "untracked"; int status; int i = 0; /* quiet warnings */ int ret = 0; @@ -1090,7 +1098,6 @@ reap_kid(krb5_context context, krb5_kdc_configuration *config, if (i == max_kids) { /* should not happen */ - what = "untracked"; sev = "warning: "; level = 2; } @@ -1156,7 +1163,7 @@ start_kdc(krb5_context context, #endif #ifdef __APPLE__ - if (do_bonjour > 0) + if (!testing_flag && do_bonjour > 0) bonjour_kid(context, config, argv0, NULL); #endif @@ -1191,7 +1198,7 @@ start_kdc(krb5_context context, #ifdef HAVE_FORK # ifdef __APPLE__ - if (do_bonjour < 0) + if (!testing_flag && do_bonjour < 0) bonjour_kid(context, config, argv0, islive); # endif diff --git a/third_party/heimdal/kdc/csr_authorizer.c b/third_party/heimdal/kdc/csr_authorizer.c index fa20519d73a6..52bc37c42965 100644 --- a/third_party/heimdal/kdc/csr_authorizer.c +++ b/third_party/heimdal/kdc/csr_authorizer.c @@ -65,7 +65,7 @@ static struct heim_plugin_data csr_authorizer_data = { * Invoke a plugin to validate a JWT/SAML/OIDC token and partially-evaluate * access control. */ -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL kdc_authorize_csr(krb5_context context, const char *app, hx509_request csr, diff --git a/third_party/heimdal/kdc/default_config.c b/third_party/heimdal/kdc/default_config.c index 627dc74f4580..01f8f7b54a69 100644 --- a/third_party/heimdal/kdc/default_config.c +++ b/third_party/heimdal/kdc/default_config.c @@ -69,7 +69,7 @@ load_kdc_plugins_once(void *ctx) #endif } -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) { static heim_base_once_t load_kdc_plugins = HEIM_BASE_ONCE_INIT; @@ -93,7 +93,6 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) c->preauth_use_strongest_session_key = FALSE; c->svc_use_strongest_session_key = FALSE; c->use_strongest_server_key = TRUE; - c->autodetect_referrals = TRUE; c->check_ticket_addresses = TRUE; c->warn_ticket_addresses = FALSE; c->allow_null_ticket_addresses = TRUE; @@ -392,7 +391,7 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) return 0; } -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL krb5_kdc_pkinit_config(krb5_context context, krb5_kdc_configuration *config) { #ifdef PKINIT diff --git a/third_party/heimdal/kdc/digest-service.c b/third_party/heimdal/kdc/digest-service.c index 3a4f4c551db6..4ea76dbe7e28 100644 --- a/third_party/heimdal/kdc/digest-service.c +++ b/third_party/heimdal/kdc/digest-service.c @@ -60,7 +60,8 @@ ntlm_service(void *ctx, const heim_idata *req, unsigned char sessionkey[16]; heim_idata rep = { 0, NULL }; krb5_context context = ctx; - hdb_entry_ex *user = NULL; + hdb_entry *user = NULL; + HDB *db = NULL; Key *key = NULL; NTLMReply ntp; size_t size; @@ -113,12 +114,12 @@ ntlm_service(void *ctx, const heim_idata *req, krb5_principal_set_type(context, client, KRB5_NT_NTLM); ret = _kdc_db_fetch(context, config, client, - HDB_F_GET_CLIENT, NULL, NULL, &user); + HDB_F_GET_CLIENT, NULL, &db, &user); krb5_free_principal(context, client); if (ret) goto failed; - ret = hdb_enctype2key(context, &user->entry, NULL, + ret = hdb_enctype2key(context, user, NULL, ETYPE_ARCFOUR_HMAC_MD5, &key); if (ret) { krb5_set_error_message(context, ret, "NTLM missing arcfour key"); @@ -213,7 +214,7 @@ ntlm_service(void *ctx, const heim_idata *req, free_NTLMRequest2(&ntq); if (user) - _kdc_free_ent (context, user); + _kdc_free_ent (context, db, user); } static int help_flag; diff --git a/third_party/heimdal/kdc/digest.c b/third_party/heimdal/kdc/digest.c index a8652891f535..092b4a75a4be 100644 --- a/third_party/heimdal/kdc/digest.c +++ b/third_party/heimdal/kdc/digest.c @@ -57,7 +57,7 @@ const struct units _kdc_digestunits[] = { static krb5_error_code get_digest_key(krb5_context context, krb5_kdc_configuration *config, - hdb_entry_ex *server, + hdb_entry *server, krb5_crypto *crypto) { krb5_error_code ret; @@ -81,12 +81,12 @@ get_digest_key(krb5_context context, static char * get_ntlm_targetname(krb5_context context, - hdb_entry_ex *client) + hdb_entry *client) { char *targetname, *p; targetname = strdup(krb5_principal_get_realm(context, - client->entry.principal)); + client->principal)); if (targetname == NULL) return NULL; @@ -101,7 +101,7 @@ get_ntlm_targetname(krb5_context context, static krb5_error_code fill_targetinfo(krb5_context context, char *targetname, - hdb_entry_ex *client, + hdb_entry *client, krb5_data *data) { struct ntlm_targetinfo ti; @@ -113,7 +113,7 @@ fill_targetinfo(krb5_context context, memset(&ti, 0, sizeof(ti)); ti.domainname = targetname; - p = client->entry.principal; + p = client->principal; str = krb5_principal_get_comp_string(context, p, 0); if (str != NULL && (strcmp("host", str) == 0 || @@ -168,7 +168,7 @@ get_password_entry(krb5_context context, { krb5_principal clientprincipal; krb5_error_code ret; - hdb_entry_ex *user; + hdb_entry *user; HDB *db; /* get username */ @@ -182,7 +182,7 @@ get_password_entry(krb5_context context, if (ret) return ret; - ret = hdb_entry_get_password(context, db, &user->entry, password); + ret = hdb_entry_get_password(context, db, user, password); if (ret || password == NULL) { if (ret == 0) { ret = EINVAL; @@ -190,7 +190,7 @@ get_password_entry(krb5_context context, } memset(user, 0, sizeof(*user)); } - _kdc_free_ent (context, user); + _kdc_free_ent (context, db, user); return ret; } @@ -217,8 +217,10 @@ _kdc_do_digest(krb5_context context, size_t size; krb5_storage *sp = NULL; Checksum res; - hdb_entry_ex *server = NULL, *user = NULL; - hdb_entry_ex *client = NULL; + HDB *serverdb, *userdb; + hdb_entry *server = NULL, *user = NULL; + HDB *clientdb; + hdb_entry *client = NULL; char *client_name = NULL, *password = NULL; krb5_data serverNonce; @@ -292,7 +294,7 @@ _kdc_do_digest(krb5_context context, krb5_clear_error_message(context); ret = _kdc_db_fetch(context, config, principal, - HDB_F_GET_SERVER, NULL, NULL, &server); + HDB_F_GET_SERVER, NULL, &serverdb, &server); if (ret) goto out; @@ -314,12 +316,12 @@ _kdc_do_digest(krb5_context context, } ret = _kdc_db_fetch(context, config, principal, - HDB_F_GET_CLIENT, NULL, NULL, &client); + HDB_F_GET_CLIENT, NULL, &clientdb, &client); krb5_free_principal(context, principal); if (ret) goto out; - if (client->entry.flags.allow_digest == 0) { + if (client->flags.allow_digest == 0) { kdc_log(context, config, 2, "Client %s tried to use digest " "but is not allowed to", @@ -877,7 +879,7 @@ _kdc_do_digest(krb5_context context, goto failed; ret = _kdc_db_fetch(context, config, clientprincipal, - HDB_F_GET_CLIENT, NULL, NULL, &user); + HDB_F_GET_CLIENT, NULL, &userdb, &user); krb5_free_principal(context, clientprincipal); if (ret) { krb5_set_error_message(context, ret, @@ -886,7 +888,7 @@ _kdc_do_digest(krb5_context context, goto failed; } - ret = hdb_enctype2key(context, &user->entry, NULL, + ret = hdb_enctype2key(context, user, NULL, ETYPE_ARCFOUR_HMAC_MD5, &key); if (ret) { krb5_set_error_message(context, ret, @@ -1163,7 +1165,7 @@ _kdc_do_digest(krb5_context context, goto failed; ret = _kdc_db_fetch(context, config, clientprincipal, - HDB_F_GET_CLIENT, NULL, NULL, &user); + HDB_F_GET_CLIENT, NULL, &userdb, &user); krb5_free_principal(context, clientprincipal); if (ret) { krb5_set_error_message(context, ret, "NTLM user %s not in database", @@ -1214,7 +1216,7 @@ _kdc_do_digest(krb5_context context, goto out; } - ret = hdb_enctype2key(context, &user->entry, NULL, + ret = hdb_enctype2key(context, user, NULL, ETYPE_ARCFOUR_HMAC_MD5, &key); if (ret) { krb5_set_error_message(context, ret, "NTLM missing arcfour key"); @@ -1466,6 +1468,10 @@ _kdc_do_digest(krb5_context context, ret = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT, buf.data, buf.length, 0, &rep.innerRep); + if (ret) { + krb5_prepend_error_message(context, ret, "Failed to encrypt digest: "); + goto out; + } ASN1_MALLOC_ENCODE(DigestREP, reply->data, reply->length, &rep, &size, ret); if (ret) { @@ -1490,11 +1496,11 @@ _kdc_do_digest(krb5_context context, if (sp) krb5_storage_free(sp); if (user) - _kdc_free_ent (context, user); + _kdc_free_ent (context, userdb, user); if (server) - _kdc_free_ent (context, server); + _kdc_free_ent (context, serverdb, server); if (client) - _kdc_free_ent (context, client); + _kdc_free_ent (context, clientdb, client); if (password) { memset(password, 0, strlen(password)); free (password); diff --git a/third_party/heimdal/kdc/fast.c b/third_party/heimdal/kdc/fast.c index d4cd650284b8..25cab3096b7f 100644 --- a/third_party/heimdal/kdc/fast.c +++ b/third_party/heimdal/kdc/fast.c @@ -108,7 +108,8 @@ get_fastuser_crypto(astgs_request_t r, krb5_crypto *crypto) { krb5_principal fast_princ; - hdb_entry_ex *fast_user = NULL; + HDB *fast_db; + hdb_entry *fast_user = NULL; Key *cookie_key = NULL; krb5_crypto fast_crypto = NULL; krb5_error_code ret; @@ -122,7 +123,7 @@ get_fastuser_crypto(astgs_request_t r, goto out; ret = _kdc_db_fetch(r->context, r->config, fast_princ, - HDB_F_GET_FAST_COOKIE, NULL, NULL, &fast_user); + HDB_F_GET_FAST_COOKIE, NULL, &fast_db, &fast_user); if (ret) goto out; @@ -130,7 +131,7 @@ get_fastuser_crypto(astgs_request_t r, ret = _kdc_get_preferred_key(r->context, r->config, fast_user, "fast-cookie", &enctype, &cookie_key); else - ret = hdb_enctype2key(r->context, &fast_user->entry, NULL, + ret = hdb_enctype2key(r->context, fast_user, NULL, enctype, &cookie_key); if (ret) goto out; @@ -148,7 +149,7 @@ get_fastuser_crypto(astgs_request_t r, out: if (fast_user) - _kdc_free_ent(r->context, fast_user); + _kdc_free_ent(r->context, fast_db, fast_user); if (fast_crypto) krb5_crypto_destroy(r->context, fast_crypto); krb5_free_principal(r->context, fast_princ); @@ -457,7 +458,7 @@ fast_unwrap_request(astgs_request_t r, krb5_principal armor_server_principal = NULL; char *armor_client_principal_name = NULL; char *armor_server_principal_name = NULL; - PA_FX_FAST_REQUEST fxreq = {0}; + PA_FX_FAST_REQUEST fxreq; krb5_auth_context ac = NULL; krb5_ticket *ticket = NULL; krb5_flags ap_req_options; @@ -466,12 +467,15 @@ fast_unwrap_request(astgs_request_t r, krb5_boolean explicit_armor; krb5_error_code ret; krb5_ap_req ap_req; - KrbFastReq fastreq = {0}; + KrbFastReq fastreq; const PA_DATA *pa; krb5_data data; size_t len; int i = 0; + memset(&fxreq, 0, sizeof(fxreq)); + memset(&fastreq, 0, sizeof(fastreq)); + pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST); if (pa == NULL) { if (tgs_ac && r->fast_asserted) { @@ -548,7 +552,7 @@ fast_unwrap_request(astgs_request_t r, ret = _kdc_db_fetch(r->context, r->config, armor_server_principal, HDB_F_GET_KRBTGT | HDB_F_DELAY_NEW_KEYS, (krb5uint32 *)ap_req.ticket.enc_part.kvno, - NULL, &r->armor_server); + &r->armor_serverdb, &r->armor_server); if(ret == HDB_ERR_NOT_FOUND_HERE) { free_AP_REQ(&ap_req); kdc_log(r->context, r->config, 5, @@ -561,7 +565,7 @@ fast_unwrap_request(astgs_request_t r, goto out; } - ret = hdb_enctype2key(r->context, &r->armor_server->entry, NULL, + ret = hdb_enctype2key(r->context, r->armor_server, NULL, ap_req.ticket.enc_part.etype, &r->armor_key); if (ret) { @@ -591,8 +595,8 @@ fast_unwrap_request(astgs_request_t r, &r->armor_ticket->ticket, armor_server_principal_name); if (ret) { - _kdc_audit_addreason((kdc_request_t)r, - "Armor TGT expired or invalid"); + kdc_audit_addreason((kdc_request_t)r, + "Armor TGT expired or invalid"); goto out; } ticket = r->armor_ticket; @@ -603,8 +607,8 @@ fast_unwrap_request(astgs_request_t r, } krb5_unparse_name(r->context, ticket->client, &armor_client_principal_name); - _kdc_audit_addkv((kdc_request_t)r, 0, "armor_client_name", "%s", - armor_client_principal_name ? armor_client_principal_name : ""); + kdc_audit_addkv((kdc_request_t)r, 0, "armor_client_name", "%s", + armor_client_principal_name ? armor_client_principal_name : ""); if (ac->remote_subkey == NULL) { krb5_auth_con_free(r->context, ac); @@ -833,7 +837,8 @@ _kdc_fast_check_armor_pac(astgs_request_t r) krb5_boolean ad_kdc_issued = FALSE; krb5_pac mspac = NULL; krb5_principal armor_client_principal = NULL; - hdb_entry_ex *armor_client = NULL; + HDB *armor_db; + hdb_entry *armor_client = NULL; char *armor_client_principal_name = NULL; flags = HDB_F_FOR_TGS_REQ; @@ -856,7 +861,7 @@ _kdc_fast_check_armor_pac(astgs_request_t r) ret = _kdc_db_fetch_client(r->context, r->config, flags, armor_client_principal, armor_client_principal_name, - r->req.req_body.realm, NULL, &armor_client); + r->req.req_body.realm, &armor_db, &armor_client); if (ret) goto out; @@ -885,7 +890,7 @@ _kdc_fast_check_armor_pac(astgs_request_t r) out: krb5_xfree(armor_client_principal_name); if (armor_client) - _kdc_free_ent(r->context, armor_client); + _kdc_free_ent(r->context, armor_db, armor_client); krb5_free_principal(r->context, armor_client_principal); krb5_pac_free(r->context, mspac); diff --git a/third_party/heimdal/kdc/gss_preauth.c b/third_party/heimdal/kdc/gss_preauth.c index ce62a29afccc..d8a2a24fd941 100644 --- a/third_party/heimdal/kdc/gss_preauth.c +++ b/third_party/heimdal/kdc/gss_preauth.c @@ -51,7 +51,6 @@ struct gss_client_params { OM_uint32 flags; OM_uint32 lifetime; krb5_checksum req_body_checksum; - krb5_data pac_data; }; static void @@ -66,6 +65,9 @@ pa_gss_display_name(gss_name_t name, gss_buffer_t namebuf, gss_const_buffer_t *namebuf_p); +static void HEIM_CALLCONV +pa_gss_dealloc_client_params(void *ptr); + /* * Create a checksum over KDC-REQ-BODY (without the nonce), used to * assert the request is invariant within the preauth conversation. @@ -132,6 +134,7 @@ pa_gss_decode_context_state(astgs_request_t r, krb5_storage *sp; size_t cksumsize; krb5_data data; + int32_t cksumtype; memset(req_body_checksum, 0, sizeof(*req_body_checksum)); sec_context_token->length = 0; @@ -152,10 +155,12 @@ pa_gss_decode_context_state(astgs_request_t r, if (ret) goto out; - ret = krb5_ret_int32(sp, &req_body_checksum->cksumtype); + ret = krb5_ret_int32(sp, &cksumtype); if (ret) goto out; + req_body_checksum->cksumtype = (CKSUMTYPE)cksumtype; + if (req_body_checksum->cksumtype == CKSUMTYPE_NONE || krb5_checksum_is_keyed(r->context, req_body_checksum->cksumtype)) { ret = KRB5KDC_ERR_SUMTYPE_NOSUPP; @@ -271,7 +276,7 @@ pa_gss_encode_context_state(astgs_request_t r, if (ret) goto out; - ret = krb5_store_int32(sp, req_body_checksum->cksumtype); + ret = krb5_store_int32(sp, (int32_t)req_body_checksum->cksumtype); if (ret) goto out; @@ -421,7 +426,7 @@ _kdc_gss_rd_padata(astgs_request_t r, goto out; } - gcp = calloc(1, sizeof(*gcp)); + gcp = kdc_object_alloc(sizeof(*gcp), "pa-gss-client-params", pa_gss_dealloc_client_params); if (gcp == NULL) { ret = krb5_enomem(r->context); goto out; @@ -471,7 +476,7 @@ out: if (gcp && gcp->major != GSS_S_NO_CONTEXT) *pgcp = gcp; else - _kdc_gss_free_client_param(r, gcp); + kdc_object_release(gcp); return ret; } @@ -498,7 +503,6 @@ struct pa_gss_authorize_plugin_ctx { struct gss_client_params *gcp; krb5_boolean authorized; krb5_principal initiator_princ; - krb5_data pac_data; }; static krb5_error_code KRB5_LIB_CALL @@ -516,8 +520,7 @@ pa_gss_authorize_cb(krb5_context context, pa_gss_authorize_plugin_ctx->gcp->mech_type, pa_gss_authorize_plugin_ctx->gcp->flags, &pa_gss_authorize_plugin_ctx->authorized, - &pa_gss_authorize_plugin_ctx->initiator_princ, - &pa_gss_authorize_plugin_ctx->pac_data); + &pa_gss_authorize_plugin_ctx->initiator_princ); } static const char *plugin_deps[] = { @@ -542,8 +545,7 @@ pa_gss_authorize_plugin(astgs_request_t r, struct gss_client_params *gcp, gss_const_buffer_t display_name, krb5_boolean *authorized, - krb5_principal *initiator_princ, - krb5_data *pac_data) + krb5_principal *initiator_princ) { krb5_error_code ret; struct pa_gss_authorize_plugin_ctx ctx; @@ -552,7 +554,6 @@ pa_gss_authorize_plugin(astgs_request_t r, ctx.gcp = gcp; ctx.authorized = 0; ctx.initiator_princ = NULL; - krb5_data_zero(&ctx.pac_data); krb5_clear_error_message(r->context); ret = _krb5_plugin_run_f(r->context, &gss_preauth_authorizer_data, @@ -573,7 +574,6 @@ pa_gss_authorize_plugin(astgs_request_t r, *authorized = ctx.authorized; *initiator_princ = ctx.initiator_princ; - *pac_data = ctx.pac_data; return ret; } @@ -583,12 +583,11 @@ pa_gss_authorize_default(astgs_request_t r, struct gss_client_params *gcp, gss_const_buffer_t display_name, krb5_boolean *authorized, - krb5_principal *initiator_princ, - krb5_data *pac_data) + krb5_principal *initiator_princ) { krb5_error_code ret; krb5_principal principal; - krb5_const_realm realm = r->server->entry.principal->realm; + krb5_const_realm realm = r->server->principal->realm; int flags = 0, cross_realm_allowed = 0, unauth_anon; /* @@ -684,16 +683,15 @@ _kdc_gss_check_client(astgs_request_t r, { krb5_error_code ret; krb5_principal initiator_princ = NULL; - hdb_entry_ex *initiator = NULL; + hdb_entry *initiator = NULL; krb5_boolean authorized = FALSE; - krb5_data pac_data; + HDB *clientdb = r->clientdb; OM_uint32 minor; gss_buffer_desc display_name = GSS_C_EMPTY_BUFFER; gss_const_buffer_t display_name_p; *client_name = NULL; - krb5_data_zero(&pac_data); pa_gss_display_name(gcp->initiator_name, &display_name, &display_name_p); @@ -702,10 +700,10 @@ _kdc_gss_check_client(astgs_request_t r, * are authorized as the directly corresponding Kerberos principal. */ ret = pa_gss_authorize_plugin(r, gcp, display_name_p, - &authorized, &initiator_princ, &pac_data); + &authorized, &initiator_princ); if (ret == KRB5_PLUGIN_NO_HANDLE) ret = pa_gss_authorize_default(r, gcp, display_name_p, - &authorized, &initiator_princ, &pac_data); + &authorized, &initiator_princ); if (ret == 0 && !authorized) ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; if (ret) @@ -745,15 +743,15 @@ _kdc_gss_check_client(astgs_request_t r, * two principals must match, noting that GSS pre-authentication is * for authentication, not general purpose impersonation. */ - if (krb5_principal_is_federated(r->context, r->client->entry.principal)) { - initiator->entry.flags.force_canonicalize = 1; + if (krb5_principal_is_federated(r->context, r->client->principal)) { + initiator->flags.force_canonicalize = 1; - _kdc_free_ent(r->context, r->client); + _kdc_free_ent(r->context, clientdb, r->client); r->client = initiator; initiator = NULL; } else if (!krb5_principal_compare(r->context, - r->client->entry.principal, - initiator->entry.principal)) { + r->client->principal, + initiator->principal)) { kdc_log(r->context, r->config, 2, "GSS %s initiator %.*s does not match principal %s", gss_oid_to_name(gcp->mech_type), @@ -763,14 +761,10 @@ _kdc_gss_check_client(astgs_request_t r, goto out; } - gcp->pac_data = pac_data; - krb5_data_zero(&pac_data); - out: krb5_free_principal(r->context, initiator_princ); if (initiator) - _kdc_free_ent(r->context, initiator); - krb5_data_free(&pac_data); + _kdc_free_ent(r->context, r->clientdb, initiator); gss_release_buffer(&minor, &display_name); return ret; @@ -864,10 +858,10 @@ _kdc_gss_mk_composite_name_ad(astgs_request_t r, return ret; } -void -_kdc_gss_free_client_param(astgs_request_t r, - gss_client_params *gcp) +static void HEIM_CALLCONV +pa_gss_dealloc_client_params(void *ptr) { + gss_client_params *gcp = ptr; OM_uint32 minor; if (gcp == NULL) @@ -877,9 +871,7 @@ _kdc_gss_free_client_param(astgs_request_t r, gss_release_name(&minor, &gcp->initiator_name); gss_release_buffer(&minor, &gcp->output_token); free_Checksum(&gcp->req_body_checksum); - krb5_data_free(&gcp->pac_data); memset(gcp, 0, sizeof(*gcp)); - free(gcp); } krb5_error_code @@ -1013,11 +1005,6 @@ pa_gss_display_name(gss_name_t name, *namebuf_p = namebuf; } -struct pa_gss_finalize_pac_plugin_ctx { - astgs_request_t r; - krb5_data *pac_data; -}; - static krb5_error_code KRB5_LIB_CALL pa_gss_finalize_pac_cb(krb5_context context, const void *plug, @@ -1025,11 +1012,8 @@ pa_gss_finalize_pac_cb(krb5_context context, void *userctx) { const krb5plugin_gss_preauth_authorizer_ftable *authorizer = plug; - struct pa_gss_finalize_pac_plugin_ctx *pa_gss_finalize_pac_ctx = userctx; - return authorizer->finalize_pac(plugctx, - pa_gss_finalize_pac_ctx->r, - pa_gss_finalize_pac_ctx->pac_data); + return authorizer->finalize_pac(plugctx, userctx); } @@ -1038,14 +1022,10 @@ _kdc_gss_finalize_pac(astgs_request_t r, gss_client_params *gcp) { krb5_error_code ret; - struct pa_gss_finalize_pac_plugin_ctx ctx; - - ctx.r = r; - ctx.pac_data = &gcp->pac_data; krb5_clear_error_message(r->context); ret = _krb5_plugin_run_f(r->context, &gss_preauth_authorizer_data, - 0, &ctx, pa_gss_finalize_pac_cb); + 0, r, pa_gss_finalize_pac_cb); if (ret == KRB5_PLUGIN_NO_HANDLE) ret = 0; diff --git a/third_party/heimdal/kdc/gss_preauth_authorizer_plugin.h b/third_party/heimdal/kdc/gss_preauth_authorizer_plugin.h index 69bd5fc1ae5b..293e59da47ba 100644 --- a/third_party/heimdal/kdc/gss_preauth_authorizer_plugin.h +++ b/third_party/heimdal/kdc/gss_preauth_authorizer_plugin.h @@ -69,11 +69,9 @@ typedef struct krb5plugin_gss_preauth_authorizer_ftable_desc { gss_const_OID, /*mech_type*/ OM_uint32, /*ret_flags*/ krb5_boolean *, /*authorized*/ - krb5_principal *, /*mapped_name*/ - krb5_data *); /*pac_data*/ + krb5_principal *); /*mapped_name*/ krb5_error_code (KRB5_LIB_CALL *finalize_pac)(void *, /*plug_ctx*/ - astgs_request_t, /*r*/ - krb5_data *); /*pac_data*/ + astgs_request_t); /*r*/ } krb5plugin_gss_preauth_authorizer_ftable; #endif /* HEIMDAL_KDC_GSS_PREAUTH_AUTHORIZER_PLUGIN_H */ diff --git a/third_party/heimdal/kdc/headers.h b/third_party/heimdal/kdc/headers.h index 6f4d56ae95cb..ffe49c8bdfd6 100644 --- a/third_party/heimdal/kdc/headers.h +++ b/third_party/heimdal/kdc/headers.h @@ -104,7 +104,8 @@ #include #endif #include -#include +#include +#include #include diff --git a/third_party/heimdal/kdc/hprop.8 b/third_party/heimdal/kdc/hprop.8 index 2746e1d8fccc..acf66bcd6147 100644 --- a/third_party/heimdal/kdc/hprop.8 +++ b/third_party/heimdal/kdc/hprop.8 @@ -50,7 +50,6 @@ .Oc .Op Fl Fl source= Ns Ar heimdal|mit-dump .Oo Fl r Ar string \*(Ba Xo -.Fl Fl v4-realm= Ns Ar string .Xc .Oc .Oo Fl c Ar cell \*(Ba Xo diff --git a/third_party/heimdal/kdc/hprop.c b/third_party/heimdal/kdc/hprop.c index 880a6f746406..c1db11b978ec 100644 --- a/third_party/heimdal/kdc/hprop.c +++ b/third_party/heimdal/kdc/hprop.c @@ -87,28 +87,28 @@ open_socket(krb5_context context, const char *hostname, const char *port) } krb5_error_code -v5_prop(krb5_context context, HDB *db, hdb_entry_ex *entry, void *appdata) +v5_prop(krb5_context context, HDB *db, hdb_entry *entry, void *appdata) { krb5_error_code ret; struct prop_data *pd = appdata; krb5_data data; if(encrypt_flag) { - ret = hdb_seal_keys_mkey(context, &entry->entry, mkey5); + ret = hdb_seal_keys_mkey(context, entry, mkey5); if (ret) { krb5_warn(context, ret, "hdb_seal_keys_mkey"); return ret; } } if(decrypt_flag) { - ret = hdb_unseal_keys_mkey(context, &entry->entry, mkey5); + ret = hdb_unseal_keys_mkey(context, entry, mkey5); if (ret) { krb5_warn(context, ret, "hdb_unseal_keys_mkey"); return ret; } } - ret = hdb_entry2value(context, &entry->entry, &data); + ret = hdb_entry2value(context, entry, &data); if(ret) { krb5_warn(context, ret, "hdb_entry2value"); return ret; @@ -316,9 +316,18 @@ propagate_database (krb5_context context, int type, if (local_realm) { krb5_realm my_realm; - krb5_get_default_realm(context,&my_realm); - krb5_principal_set_realm(context,server,my_realm); - krb5_xfree(my_realm); + ret = krb5_get_default_realm(context,&my_realm); + if (ret == 0) { + ret = krb5_principal_set_realm(context,server,my_realm); + krb5_xfree(my_realm); + } + if (ret) { + failed++; + krb5_warn(context, ret, "unable to obtain default or set realm"); + krb5_free_principal(context, server); + close(fd); + continue; + } } auth_context = NULL; diff --git a/third_party/heimdal/kdc/hprop.h b/third_party/heimdal/kdc/hprop.h index 426bf6ed7fd5..59c39ea47847 100644 --- a/third_party/heimdal/kdc/hprop.h +++ b/third_party/heimdal/kdc/hprop.h @@ -53,23 +53,7 @@ struct prop_data{ #define NEVERDATE ((1U << 31) - 1) #endif -krb5_error_code v5_prop(krb5_context, HDB*, hdb_entry_ex*, void*); +krb5_error_code v5_prop(krb5_context, HDB*, hdb_entry*, void*); int mit_prop_dump(void*, const char*); -struct v4_principal { - char name[64]; - char instance[64]; - DES_cblock key; - int kvno; - int mkvno; - time_t exp_date; - time_t mod_date; - char mod_name[64]; - char mod_instance[64]; - int max_life; -}; - -int v4_prop(void*, struct v4_principal*); -int v4_prop_dump(void *arg, const char*); - #endif /* __HPROP_H__ */ diff --git a/third_party/heimdal/kdc/hpropd.8 b/third_party/heimdal/kdc/hpropd.8 index 31b44e28a59c..9056b05a8d24 100644 --- a/third_party/heimdal/kdc/hpropd.8 +++ b/third_party/heimdal/kdc/hpropd.8 @@ -51,7 +51,6 @@ .Fl Fl keytab= Ns Ar keytab .Xc .Oc -.Op Fl 4 | Fl Fl v4dump .Ek .Sh DESCRIPTION .Nm @@ -83,8 +82,6 @@ print dump to stdout not started from inetd .It Fl k Ar keytab , Fl Fl keytab= Ns Ar keytab keytab to use for authentication -.It Fl 4 , Fl Fl v4dump -create v4 type DB .El .Sh SEE ALSO .Xr hprop 8 diff --git a/third_party/heimdal/kdc/hpropd.c b/third_party/heimdal/kdc/hpropd.c index fd9df08e8d78..fa06a1fd4019 100644 --- a/third_party/heimdal/kdc/hpropd.c +++ b/third_party/heimdal/kdc/hpropd.c @@ -125,6 +125,7 @@ main(int argc, char **argv) krb5_ticket *ticket; char *server; + memset(&ss, 0, sizeof(ss)); sock = STDIN_FILENO; #ifdef SUPPORT_INETD if (inetd_flag == -1) { @@ -146,7 +147,7 @@ main(int argc, char **argv) if (getpeername(sock, sa, &sin_len) < 0) krb5_err(context, 1, errno, "getpeername"); - if (inet_ntop(ss.ss_family, + if (inet_ntop(sa->sa_family, socket_get_address (sa), addr_name, sizeof(addr_name)) == NULL) @@ -225,7 +226,7 @@ main(int argc, char **argv) nprincs = 0; while (1){ krb5_data data; - hdb_entry_ex entry; + hdb_entry entry; if (from_stdin) { ret = krb5_read_message(context, &sock, &data); @@ -254,7 +255,7 @@ main(int argc, char **argv) break; } memset(&entry, 0, sizeof(entry)); - ret = hdb_value2entry(context, &data, &entry.entry); + ret = hdb_value2entry(context, &data, &entry); krb5_data_free(&data); if (ret) krb5_err(context, 1, ret, "hdb_value2entry"); @@ -268,7 +269,7 @@ main(int argc, char **argv) ret = db->hdb_store(context, db, 0, &entry); if (ret == HDB_ERR_EXISTS) { char *s; - ret = krb5_unparse_name(context, entry.entry.principal, &s); + ret = krb5_unparse_name(context, entry.principal, &s); if (ret) s = strdup(unparseable_name); krb5_warnx(context, "Entry exists: %s", s); @@ -278,7 +279,7 @@ main(int argc, char **argv) else nprincs++; } - hdb_free_entry(context, &entry); + hdb_free_entry(context, db, &entry); } if (!print_dump) krb5_log(context, fac, 0, "Received %d principals", nprincs); diff --git a/third_party/heimdal/kdc/httpkadmind.c b/third_party/heimdal/kdc/httpkadmind.c index 3dfb365186af..0e31b4044c3c 100644 --- a/third_party/heimdal/kdc/httpkadmind.c +++ b/third_party/heimdal/kdc/httpkadmind.c @@ -80,6 +80,20 @@ #define heim_pconfig krb5_context #include +#if MHD_VERSION < 0x00097002 || defined(MHD_YES) +/* libmicrohttpd changed these from int valued macros to an enum in 0.9.71 */ +#ifdef MHD_YES +#undef MHD_YES +#undef MHD_NO +#endif +enum MHD_Result { MHD_NO = 0, MHD_YES = 1 }; +#define MHD_YES 1 +#define MHD_NO 0 +typedef int heim_mhd_result; +#else +typedef enum MHD_Result heim_mhd_result; +#endif + #define BODYLEN_IS_STRLEN (~0) /* @@ -565,7 +579,7 @@ redirect_uri_appends(struct redirect_uri *redirect, redirect->len += len; } -static int +static heim_mhd_result make_redirect_uri_param_cb(void *d, enum MHD_ValueKind kind, const char *key, @@ -700,9 +714,10 @@ bad_reqv(kadmin_request_desc r, if (r && r->context) context = r->context; if (r && r->hcontext && r->kv) - heim_audit_addkv((heim_svc_req_desc)r, 0, "http-status-code", "%d", - http_status_code); - (void) gettimeofday(&r->tv_end, NULL); + heim_audit_setkv_number((heim_svc_req_desc)r, "http-status-code", + http_status_code); + if (r) + (void) gettimeofday(&r->tv_end, NULL); if (code == ENOMEM) { if (context) krb5_log_msg(context, logfac, 1, NULL, "Out of memory"); @@ -881,7 +896,7 @@ check_service_name(kadmin_request_desc r, const char *name) return EACCES; } -static int +static heim_mhd_result param_cb(void *d, enum MHD_ValueKind kind, const char *key, @@ -1046,12 +1061,12 @@ param_cb(void *d, #endif } else { /* Produce error for unknown params */ - heim_audit_addkv((heim_svc_req_desc)r, 0, "requested_unknown", "true"); + heim_audit_setkv_bool((heim_svc_req_desc)r, "requested_unknown", TRUE); krb5_set_error_message(r->context, ret = ENOTSUP, "Query parameter %s not supported", key); } - if (ret && !r->ret) - r->ret = ret; + if (ret && !r->error_code) + r->error_code = ret; heim_release(s); return ret ? MHD_NO /* Stop iterating */ : MHD_YES; } @@ -1067,7 +1082,7 @@ authorize_req(kadmin_request_desc r) return bad_enomem(r, ret); (void) MHD_get_connection_values(r->connection, MHD_GET_ARGUMENT_KIND, param_cb, r); - ret = r->ret; + ret = r->error_code; if (ret == EACCES) return bad_403(r, ret, "Not authorized to requested principal(s)"); if (ret) @@ -1189,7 +1204,7 @@ make_kstuple(krb5_context context, if (p->n_key_data < 1) return 0; - *kstuple = calloc(p->n_key_data, sizeof (*kstuple)); + *kstuple = calloc(p->n_key_data, sizeof (**kstuple)); for (i = 0; *kstuple && i < p->n_key_data; i++) { if (p->key_data[i].key_data_kvno == p->kvno) { (*kstuple)[i].ks_enctype = p->key_data[i].key_data_type[0]; @@ -1417,6 +1432,8 @@ get_keysN(kadmin_request_desc r, const char *method) ret = heim_array_append_value(r->service_names, s); heim_release(s); nsvcs = 1; + if (ret) + return bad_503(r, ret, "Out of memory"); } /* FIXME: Make this configurable */ @@ -1528,7 +1545,8 @@ set_req_desc(struct MHD_Connection *connection, r->sname = NULL; r->cname = NULL; r->addr = NULL; - r->kv = heim_array_create(); + r->kv = heim_dict_create(10); + r->attributes = heim_dict_create(1); /* Our fields */ r->connection = connection; r->kadm_handle = NULL; @@ -1570,7 +1588,7 @@ set_req_desc(struct MHD_Connection *connection, if (ret == 0 && r->kv == NULL) { krb5_log_msg(r->context, logfac, 1, NULL, "Out of memory"); - ret = r->ret = ENOMEM; + ret = r->error_code = ENOMEM; } return ret; } @@ -1643,6 +1661,8 @@ get_config(kadmin_request_desc r) ret = get_kadm_handle(r->context, r->realm ? r->realm : realm, 0 /* want_write */, &r->kadm_handle); + if (ret) + return bad_503(r, ret, "Could not access KDC database"); memset(&princ, 0, sizeof(princ)); princ.key_data = NULL; @@ -1665,7 +1685,7 @@ get_config(kadmin_request_desc r) break; } } else { - r->ret = ret; + r->error_code = ret; return bad_404(r, "/get-config"); } } @@ -1725,15 +1745,22 @@ mac_csrf_token(kadmin_request_desc r, krb5_storage *sp) ret = krb5_enomem(r->context); /* HMAC the token body and the client principal name */ if (ret == 0) { - HMAC_Init_ex(ctx, princ.key_data[i].key_data_contents[0], princ.key_data[i].key_data_length[0], EVP_sha256(), NULL); - HMAC_Update(ctx, data.data, data.length); - HMAC_Update(ctx, r->cname, strlen(r->cname)); - HMAC_Final(ctx, mac, &maclen); - krb5_data_free(&data); - data.length = maclen; - data.data = mac; - if (krb5_storage_write(sp, mac, maclen) != maclen) + if (HMAC_Init_ex(ctx, princ.key_data[i].key_data_contents[0], + princ.key_data[i].key_data_length[0], EVP_sha256(), + NULL) == 0) { + HMAC_CTX_cleanup(ctx); ret = krb5_enomem(r->context); + } else { + HMAC_Update(ctx, data.data, data.length); + HMAC_Update(ctx, r->cname, strlen(r->cname)); + HMAC_Final(ctx, mac, &maclen); + HMAC_CTX_cleanup(ctx); + krb5_data_free(&data); + data.length = maclen; + data.data = mac; + if (krb5_storage_write(sp, mac, maclen) != maclen) + ret = krb5_enomem(r->context); + } } krb5_free_principal(r->context, p); if (freeit) @@ -1874,7 +1901,7 @@ health(const char *method, kadmin_request_desc r) } /* Implements the entirety of this REST service */ -static int +static heim_mhd_result route(void *cls, struct MHD_Connection *connection, const char *url, @@ -2100,6 +2127,8 @@ main(int argc, char **argv) argc -= optidx; argv += optidx; + if (argc != 0) + usage(1); if ((errno = pthread_key_create(&k5ctx, k5_free_context))) err(1, "Could not create thread-specific storage"); diff --git a/third_party/heimdal/kdc/ipc_csr_authorizer.c b/third_party/heimdal/kdc/ipc_csr_authorizer.c index fad3919a2a6b..7d77e7f812a4 100644 --- a/third_party/heimdal/kdc/ipc_csr_authorizer.c +++ b/third_party/heimdal/kdc/ipc_csr_authorizer.c @@ -169,6 +169,7 @@ cmd_append(struct rk_strpool **cmd, const char *s0, ...) { va_list ap; const char *arg; + int ret = 0; if ((*cmd = rk_strpoolprintf(*cmd, "%s", s0)) == NULL) return ENOMEM; @@ -177,14 +178,23 @@ cmd_append(struct rk_strpool **cmd, const char *s0, ...) while ((arg = va_arg(ap, const char *))) { char *s; - if ((s = string_encode(arg)) == NULL) - return rk_strpoolfree(*cmd), *cmd = NULL, ENOMEM; + if ((s = string_encode(arg)) == NULL) { + rk_strpoolfree(*cmd); + *cmd = NULL; + ret = ENOMEM; + goto out; + } *cmd = rk_strpoolprintf(*cmd, "%s", s); free(s); - if (*cmd == NULL) - return ENOMEM; + if (*cmd == NULL) { + ret = ENOMEM; + goto out; + } } - return 0; + + out: + va_end(ap); + return ret; } static int diff --git a/third_party/heimdal/kdc/kdc-accessors.h b/third_party/heimdal/kdc/kdc-accessors.h new file mode 100644 index 000000000000..81c03d2f2227 --- /dev/null +++ b/third_party/heimdal/kdc/kdc-accessors.h @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2022, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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. + */ + +#ifndef HEIMDAL_KDC_KDC_ACCESSORS_H +#define HEIMDAL_KDC_KDC_ACCESSORS_H 1 + +/* read-only accessor */ +#ifndef _KDC_REQUEST_GET_ACCESSOR +#define _KDC_REQUEST_GET_ACCESSOR(R, T, f) \ + KDC_LIB_FUNCTION T KDC_LIB_CALL \ + kdc_request_get_ ## f(R); +#endif + +#ifndef _KDC_REQUEST_SET_ACCESSOR +#define _KDC_REQUEST_SET_ACCESSOR(R, T, f) \ + KDC_LIB_FUNCTION void KDC_LIB_CALL \ + kdc_request_set_ ## f(R, T); +#endif + +#ifndef KDC_REQUEST_GET_ACCESSOR +#define KDC_REQUEST_GET_ACCESSOR(T, f) \ + _KDC_REQUEST_GET_ACCESSOR(kdc_request_t, T, f) +#endif + +#ifndef KDC_REQUEST_SET_ACCESSOR +#define KDC_REQUEST_SET_ACCESSOR(T, f) \ + _KDC_REQUEST_SET_ACCESSOR(kdc_request_t, T, f) +#endif + +#ifndef ASTGS_REQUEST_GET_ACCESSOR +#define ASTGS_REQUEST_GET_ACCESSOR(T, f) \ + _KDC_REQUEST_GET_ACCESSOR(astgs_request_t, T, f) +#endif + +#ifndef ASTGS_REQUEST_SET_ACCESSOR +#define ASTGS_REQUEST_SET_ACCESSOR(T, f) \ + _KDC_REQUEST_SET_ACCESSOR(astgs_request_t, T, f) +#endif + +/* get/set accessor for pointer type */ +#ifndef _KDC_REQUEST_GET_ACCESSOR_PTR +#define _KDC_REQUEST_GET_ACCESSOR_PTR(R, T, f) \ + KDC_LIB_FUNCTION const T KDC_LIB_CALL \ + kdc_request_get_ ## f(R); +#endif + +#ifndef _KDC_REQUEST_SET_ACCESSOR_PTR +#define _KDC_REQUEST_SET_ACCESSOR_PTR(R, T, t, f) \ + KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL \ + kdc_request_set_ ## f(R, const T); +#endif + +#ifndef KDC_REQUEST_GET_ACCESSOR_PTR +#define KDC_REQUEST_GET_ACCESSOR_PTR(T, f) \ + _KDC_REQUEST_GET_ACCESSOR_PTR(kdc_request_t, T, f) +#endif + +#ifndef KDC_REQUEST_SET_ACCESSOR_PTR +#define KDC_REQUEST_SET_ACCESSOR_PTR(T, t, f) \ + _KDC_REQUEST_SET_ACCESSOR_PTR(kdc_request_t, T, t, f) +#endif + +#ifndef ASTGS_REQUEST_GET_ACCESSOR_PTR +#define ASTGS_REQUEST_GET_ACCESSOR_PTR(T, f) \ + _KDC_REQUEST_GET_ACCESSOR_PTR(astgs_request_t, T, f) +#endif + +#ifndef ASTGS_REQUEST_SET_ACCESSOR_PTR +#define ASTGS_REQUEST_SET_ACCESSOR_PTR(T, t, f) \ + _KDC_REQUEST_SET_ACCESSOR_PTR(astgs_request_t, T, t, f) +#endif + +/* get/set accessor for struct type */ +#ifndef _KDC_REQUEST_GET_ACCESSOR_STRUCT +#define _KDC_REQUEST_GET_ACCESSOR_STRUCT(R, T, f) \ + KDC_LIB_FUNCTION const T * KDC_LIB_CALL \ + kdc_request_get_ ## f(R); +#endif + +#ifndef _KDC_REQUEST_SET_ACCESSOR_STRUCT +#define _KDC_REQUEST_SET_ACCESSOR_STRUCT(R, T, t, f) \ + KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL \ + kdc_request_set_ ## f(R, const T *); +#endif + +#ifndef KDC_REQUEST_GET_ACCESSOR_STRUCT +#define KDC_REQUEST_GET_ACCESSOR_STRUCT(T, f) \ + _KDC_REQUEST_GET_ACCESSOR_STRUCT(kdc_request_t, T, f) +#endif + +#ifndef KDC_REQUEST_SET_ACCESSOR_STRUCT +#define KDC_REQUEST_SET_ACCESSOR_STRUCT(T, t, f) \ + _KDC_REQUEST_SET_ACCESSOR_STRUCT(kdc_request_t, T, t, f) +#endif + +#ifndef ASTGS_REQUEST_GET_ACCESSOR_STRUCT +#define ASTGS_REQUEST_GET_ACCESSOR_STRUCT(T, f) \ + _KDC_REQUEST_GET_ACCESSOR_STRUCT(astgs_request_t, T, f) +#endif + +#ifndef ASTGS_REQUEST_SET_ACCESSOR_STRUCT +#define ASTGS_REQUEST_SET_ACCESSOR_STRUCT(T, t, f) \ + _KDC_REQUEST_SET_ACCESSOR_STRUCT(astgs_request_t, T, t, f) +#endif + +/* + * krb5_context + * kdc_request_get_context(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR(krb5_context, context) + +/* + * krb5_kdc_configuration * + * kdc_request_get_config(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR(krb5_kdc_configuration *, config) + +/* + * heim_log_facility * + * kdc_request_get_logf(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR(heim_log_facility *, logf) + +/* + * const char * + * kdc_request_get_from(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR_PTR(char *, from) + +/* + * const struct sockaddr * + * kdc_request_get_addr(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR_PTR(struct sockaddr *, addr) + +/* + * krb5_data + * kdc_request_get_request(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR(krb5_data, request) + +/* + * struct timeval + * kdc_request_get_tv_start(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR(struct timeval, tv_start) + +/* + * struct timeval + * kdc_request_get_tv_end(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR(struct timeval, tv_end) + +/* + * krb5_error_code + * kdc_request_get_error_code(kdc_request_t); + */ +KDC_REQUEST_GET_ACCESSOR(krb5_error_code, error_code) + +/* + * void + * kdc_request_set_error_code(kdc_request_t, krb5_error_code); + */ +KDC_REQUEST_SET_ACCESSOR(krb5_error_code, error_code) + +/* + * const KDC_REQ * + * kdc_request_get_req(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_STRUCT(KDC_REQ, req) + +/* + * const KDC_REP * + * kdc_request_get_rep(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_STRUCT(KDC_REP, rep) + +/* + * krb5_error_code + * kdc_request_set_rep(astgs_request_t, const KDC_REP *); + */ + +ASTGS_REQUEST_SET_ACCESSOR_STRUCT(KDC_REP, KDC_REP, rep) + +/* + * const char * + * kdc_request_get_cname(kdc_request_t); + */ + +KDC_REQUEST_GET_ACCESSOR_PTR(char *, cname) + +/* + * krb5_error_code + * kdc_request_set_cname(kdc_request_t, const char *); + */ + +KDC_REQUEST_SET_ACCESSOR_PTR(char *, string_ptr, cname) + +/* + * const Principal * + * kdc_request_get_client_princ(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_PTR(Principal *, client_princ) + +/* + * krb5_error_code + * kdc_request_set_client_princ(astgs_request_t, const Principal *); + */ + +ASTGS_REQUEST_SET_ACCESSOR_PTR(Principal *, Principal_ptr, client_princ) + +/* + * const Principal * + * kdc_request_get_canon_client_princ(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_PTR(Principal *, canon_client_princ) + +/* + * krb5_error_code + * kdc_request_set_canon_client_princ(astgs_request_t, const Principal *); + */ + +ASTGS_REQUEST_SET_ACCESSOR_PTR(Principal *, Principal_ptr, canon_client_princ) + +/* + * const HDB * + * kdc_request_get_clientdb(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_PTR(HDB *, clientdb) + +/* + * const hdb_entry * + * kdc_request_get_client(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_PTR(hdb_entry *, client) + +/* + * See client accessors + */ + +KDC_REQUEST_GET_ACCESSOR_PTR(char *, sname) +KDC_REQUEST_SET_ACCESSOR_PTR(char *, string_ptr, sname) +ASTGS_REQUEST_GET_ACCESSOR_PTR(Principal *, server_princ) +ASTGS_REQUEST_SET_ACCESSOR_PTR(Principal *, Principal_ptr, server_princ) +ASTGS_REQUEST_GET_ACCESSOR_PTR(HDB *, serverdb) +ASTGS_REQUEST_GET_ACCESSOR_PTR(hdb_entry *, server) + +/* + * See client accessors + */ + +ASTGS_REQUEST_GET_ACCESSOR_PTR(Principal *, krbtgt_princ) +ASTGS_REQUEST_SET_ACCESSOR_PTR(Principal *, Principal_ptr, krbtgt_princ) +ASTGS_REQUEST_GET_ACCESSOR_PTR(HDB *, krbtgtdb) +ASTGS_REQUEST_GET_ACCESSOR_PTR(hdb_entry *, krbtgt) + +/* + * krb5_ticket * + * kdc_request_get_ticket(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR(krb5_ticket *, ticket) + +/* + * const krb5_keyblock * + * kdc_request_get_reply_key(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_STRUCT(krb5_keyblock, reply_key) + +/* + * krb5_error_code + * kdc_request_set_reply_key(astgs_request_t, const krb5_keyblock *); + */ + +ASTGS_REQUEST_SET_ACCESSOR_STRUCT(krb5_keyblock, keyblock, reply_key) + +/* + * krb5_const_pac + * kdc_request_get_pac(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR_PTR(struct krb5_pac_data *, pac) + +/* + * krb5_error_code + * kdc_request_set_pac(astgs_request_t, krb5_const_pac); + */ + +ASTGS_REQUEST_SET_ACCESSOR_PTR(struct krb5_pac_data *, pac, pac) + +/* + * uint64_t + * kdc_request_get_pac_attributes(astgs_request_t); + */ + +ASTGS_REQUEST_GET_ACCESSOR(uint64_t, pac_attributes) + +/* + * void + * kdc_request_set_pac_attributes(astgs_request_t, uint64_t); + */ + +ASTGS_REQUEST_SET_ACCESSOR(uint64_t, pac_attributes) + +#endif /* HEIMDAL_KDC_KDC_ACCESSORS_H */ diff --git a/third_party/heimdal/kdc/rx.h b/third_party/heimdal/kdc/kdc-audit.h similarity index 50% rename from third_party/heimdal/kdc/rx.h rename to third_party/heimdal/kdc/kdc-audit.h index f914e93e6efc..4b2203f22679 100644 --- a/third_party/heimdal/kdc/rx.h +++ b/third_party/heimdal/kdc/kdc-audit.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,47 +33,35 @@ /* $Id$ */ -#ifndef __RX_H__ -#define __RX_H__ +#ifndef HEIMDAL_KDC_KDC_AUDIT_H +#define HEIMDAL_KDC_KDC_AUDIT_H 1 -/* header of a RPC packet */ - -enum rx_header_type { - HT_DATA = 1, - HT_ACK = 2, - HT_BUSY = 3, - HT_ABORT = 4, - HT_ACKALL = 5, - HT_CHAL = 6, - HT_RESP = 7, - HT_DEBUG = 8 -}; - -/* For flags in header */ +/* + * KDC auditing + */ -enum rx_header_flag { - HF_CLIENT_INITIATED = 1, - HF_REQ_ACK = 2, - HF_LAST = 4, - HF_MORE = 8 -}; +/* auth event type enumeration, currently for AS only */ +#define KDC_AUTH_EVENT_INVALID 0 /* no event logged */ +#define KDC_AUTH_EVENT_CLIENT_AUTHORIZED 1 /* all authn/authz checks passed */ +#define KDC_AUTH_EVENT_CLIENT_UNKNOWN 2 /* client unknown */ +#define KDC_AUTH_EVENT_CLIENT_LOCKED_OUT 3 /* client locked out */ +#define KDC_AUTH_EVENT_CLIENT_TIME_SKEW 4 /* client time skew */ +#define KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY 5 /* PA failed to validate long term key */ +#define KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY 6 /* PA validated long term key */ +#define KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED 7 /* couldn't map GSS/PKINIT name to principal */ +#define KDC_AUTH_EVENT_PREAUTH_FAILED 8 /* generic PA failure */ +#define KDC_AUTH_EVENT_PREAUTH_SUCCEEDED 9 /* generic (non-long term key) PA success */ -struct rx_header { - uint32_t epoch; - uint32_t connid; /* And channel ID */ - uint32_t callid; - uint32_t seqno; - uint32_t serialno; - u_char type; - u_char flags; - u_char status; - u_char secindex; - uint16_t reserved; /* ??? verifier? */ - uint16_t serviceid; -/* This should be the other way around according to everything but */ -/* tcpdump */ -}; +/* + * Audit keys to be queried using kdc_audit_getkv(). There are other keys + * intended for logging that are not defined below; the constants below are + * there to ease migration from the older auth_status HDB API. + */ -#define RX_HEADER_SIZE 28 +#define KDC_REQUEST_KV_AUTH_EVENT "#auth_event" /* heim_number_t */ +#define KDC_REQUEST_KV_PA_NAME "pa" /* heim_string_t */ +#define KDC_REQUEST_KV_PA_ETYPE "pa-etype" /* heim_number_t */ +#define KDC_REQUEST_KV_GSS_INITIATOR "gss_initiator" /* heim_string_t */ +#define KDC_REQUEST_KV_PKINIT_CLIENT_CERT "pkinit_client_cert" /* heim_string_t */ -#endif /* __RX_H__ */ +#endif /* HEIMDAL_KDC_KDC_AUDIT_H */ diff --git a/third_party/heimdal/kdc/kdc-plugin.c b/third_party/heimdal/kdc/kdc-plugin.c new file mode 100644 index 000000000000..8759893a9560 --- /dev/null +++ b/third_party/heimdal/kdc/kdc-plugin.c @@ -0,0 +1,658 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions (c) 2021, 2022 PADL Software Pty Ltd. + * + * 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" + +static int have_plugin = 0; + +/* + * Pick the first KDC plugin module that we find. + */ + +static const char *kdc_plugin_deps[] = { + "kdc", + "krb5", + "hdb", + NULL +}; + +static struct heim_plugin_data kdc_plugin_data = { + "krb5", + "kdc", + KRB5_PLUGIN_KDC_VERSION_10, + kdc_plugin_deps, + kdc_get_instance +}; + +static krb5_error_code KRB5_LIB_CALL +load(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + have_plugin = 1; + return KRB5_PLUGIN_NO_HANDLE; +} + +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL +krb5_kdc_plugin_init(krb5_context context) +{ + (void)_krb5_plugin_run_f(context, &kdc_plugin_data, 0, NULL, load); + + return 0; +} + +struct generate_uc { + krb5_kdc_configuration *config; + hdb_entry *client; + hdb_entry *server; + const krb5_keyblock *reply_key; + uint64_t pac_attributes; + krb5_pac *pac; +}; + +static krb5_error_code KRB5_LIB_CALL +generate(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const krb5plugin_kdc_ftable *ft = (const krb5plugin_kdc_ftable *)plug; + struct generate_uc *uc = (struct generate_uc *)userctx; + + if (ft->pac_generate == NULL) + return KRB5_PLUGIN_NO_HANDLE; + + return ft->pac_generate((void *)plug, + context, + uc->config, + uc->client, + uc->server, + uc->reply_key, + uc->pac_attributes, + uc->pac); +} + + +krb5_error_code +_kdc_pac_generate(krb5_context context, + krb5_kdc_configuration *config, + hdb_entry *client, + hdb_entry *server, + const krb5_keyblock *reply_key, + uint64_t pac_attributes, + krb5_pac *pac) +{ + krb5_error_code ret = 0; + struct generate_uc uc; + + *pac = NULL; + + if (krb5_config_get_bool_default(context, NULL, FALSE, "realms", + client->principal->realm, + "disable_pac", NULL)) + return 0; + + if (have_plugin) { + uc.config = config; + uc.client = client; + uc.server = server; + uc.reply_key = reply_key; + uc.pac = pac; + uc.pac_attributes = pac_attributes; + + ret = _krb5_plugin_run_f(context, &kdc_plugin_data, + 0, &uc, generate); + if (ret != KRB5_PLUGIN_NO_HANDLE) + return ret; + ret = 0; + } + + if (*pac == NULL) + ret = krb5_pac_init(context, pac); + + return ret; +} + +struct verify_uc { + krb5_kdc_configuration *config; + krb5_principal client_principal; + krb5_principal delegated_proxy_principal; + hdb_entry *client; + hdb_entry *server; + hdb_entry *krbtgt; + krb5_pac *pac; +}; + +static krb5_error_code KRB5_LIB_CALL +verify(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const krb5plugin_kdc_ftable *ft = (const krb5plugin_kdc_ftable *)plug; + struct verify_uc *uc = (struct verify_uc *)userctx; + krb5_error_code ret; + + if (ft->pac_verify == NULL) + return KRB5_PLUGIN_NO_HANDLE; + + ret = ft->pac_verify((void *)plug, + context, + uc->config, + uc->client_principal, + uc->delegated_proxy_principal, + uc->client, uc->server, uc->krbtgt, uc->pac); + return ret; +} + +krb5_error_code +_kdc_pac_verify(krb5_context context, + krb5_kdc_configuration *config, + const krb5_principal client_principal, + const krb5_principal delegated_proxy_principal, + hdb_entry *client, + hdb_entry *server, + hdb_entry *krbtgt, + krb5_pac *pac) +{ + struct verify_uc uc; + + if (!have_plugin) + return KRB5_PLUGIN_NO_HANDLE; + + uc.config = config; + uc.client_principal = client_principal; + uc.delegated_proxy_principal = delegated_proxy_principal; + uc.client = client; + uc.server = server; + uc.krbtgt = krbtgt; + uc.pac = pac; + + return _krb5_plugin_run_f(context, &kdc_plugin_data, + 0, &uc, verify); +} + +static krb5_error_code KRB5_LIB_CALL +check(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const krb5plugin_kdc_ftable *ft = (const krb5plugin_kdc_ftable *)plug; + + if (ft->client_access == NULL) + return KRB5_PLUGIN_NO_HANDLE; + return ft->client_access((void *)plug, userctx); +} + +krb5_error_code +_kdc_check_access(astgs_request_t r) +{ + krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE; + + if (have_plugin) { + ret = _krb5_plugin_run_f(r->context, &kdc_plugin_data, + 0, r, check); + } + + if (ret == KRB5_PLUGIN_NO_HANDLE) + return kdc_check_flags(r, r->req.msg_type == krb_as_req, + r->client, r->server); + return ret; +} + +static krb5_error_code KRB5_LIB_CALL +referral_policy(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const krb5plugin_kdc_ftable *ft = (const krb5plugin_kdc_ftable *)plug; + + if (ft->referral_policy == NULL) + return KRB5_PLUGIN_NO_HANDLE; + return ft->referral_policy((void *)plug, userctx); +} + +krb5_error_code +_kdc_referral_policy(astgs_request_t r) +{ + krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE; + + if (have_plugin) + ret = _krb5_plugin_run_f(r->context, &kdc_plugin_data, 0, r, referral_policy); + + return ret; +} + +static krb5_error_code KRB5_LIB_CALL +finalize_reply(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const krb5plugin_kdc_ftable *ft = (const krb5plugin_kdc_ftable *)plug; + + if (ft->finalize_reply == NULL) + return KRB5_PLUGIN_NO_HANDLE; + return ft->finalize_reply((void *)plug, userctx); +} + +krb5_error_code +_kdc_finalize_reply(astgs_request_t r) +{ + krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE; + + if (have_plugin) + ret = _krb5_plugin_run_f(r->context, &kdc_plugin_data, 0, r, finalize_reply); + + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +static krb5_error_code KRB5_LIB_CALL +audit(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const krb5plugin_kdc_ftable *ft = (const krb5plugin_kdc_ftable *)plug; + + if (ft->audit == NULL) + return KRB5_PLUGIN_NO_HANDLE; + return ft->audit((void *)plug, userctx); +} + +krb5_error_code +_kdc_plugin_audit(astgs_request_t r) +{ + krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE; + + if (have_plugin) + ret = _krb5_plugin_run_f(r->context, &kdc_plugin_data, 0, r, audit); + + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +KDC_LIB_FUNCTION uintptr_t KDC_LIB_CALL +kdc_get_instance(const char *libname) +{ + static const char *instance = "libkdc"; + + if (strcmp(libname, "kdc") == 0) + return (uintptr_t)instance; + else if (strcmp(libname, "hdb") == 0) + return hdb_get_instance(libname); + else if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + + return 0; +} + +/* + * Minimum API surface wrapper for libheimbase object types so it + * may remain a private interface, yet plugins can interact with + * objects. + */ + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_object_alloc(size_t size, const char *name, kdc_type_dealloc dealloc) +{ + return heim_alloc(size, name, dealloc); +} + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_object_retain(kdc_object_t o) +{ + return heim_retain(o); +} + +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_object_release(kdc_object_t o) +{ + heim_release(o); +} + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_bool_create(krb5_boolean v) +{ + return heim_bool_create(v); +} + +KDC_LIB_FUNCTION krb5_boolean KDC_LIB_CALL +kdc_bool_get_value(kdc_object_t o) +{ + return heim_bool_val(o); +} + +struct kdc_array_iterator_trampoline_data { + kdc_array_iterator_t iter; + void *data; +}; + +/* + * Calling convention shim to avoid needing to update all internal + * consumers of heim_array_iterate_f() + */ +static void +_kdc_array_iterator_trampoline(kdc_object_t o, void *data, int *stop) +{ + struct kdc_array_iterator_trampoline_data *t = data; + + t->iter(o, t->data, stop); +} + +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_array_iterate(kdc_array_t a, void *d, kdc_array_iterator_t iter) +{ + struct kdc_array_iterator_trampoline_data t; + + t.iter = iter; + t.data = d; + + heim_array_iterate_f((heim_array_t)a, &t, _kdc_array_iterator_trampoline); +} + +KDC_LIB_FUNCTION size_t KDC_LIB_CALL +kdc_array_get_length(kdc_array_t a) +{ + return heim_array_get_length((heim_array_t)a); +} + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_array_get_value(heim_array_t a, size_t i) +{ + return heim_array_get_value((heim_array_t)a, i); +} + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_array_copy_value(heim_array_t a, size_t i) +{ + return heim_array_copy_value((heim_array_t)a, i); +} + +KDC_LIB_FUNCTION kdc_string_t KDC_LIB_CALL +kdc_string_create(const char *s) +{ + return (kdc_string_t)heim_string_create(s); +} + +KDC_LIB_FUNCTION const char * KDC_LIB_CALL +kdc_string_get_utf8(kdc_string_t s) +{ + return heim_string_get_utf8((heim_string_t)s); +} + +KDC_LIB_FUNCTION kdc_data_t +kdc_data_create(const void *d, size_t len) +{ + return (kdc_data_t)heim_data_create(d, len); +} + +KDC_LIB_FUNCTION const krb5_data * KDC_LIB_CALL +kdc_data_get_data(kdc_data_t d) +{ + return heim_data_get_data((heim_data_t)d); +} + +KDC_LIB_FUNCTION kdc_number_t KDC_LIB_CALL +kdc_number_create(int64_t v) +{ + return (kdc_number_t)heim_number_create(v); +} + +KDC_LIB_FUNCTION int64_t KDC_LIB_CALL +kdc_number_get_value(kdc_number_t n) +{ + return heim_number_get_long((heim_number_t)n); +} + +/* + * Plugin accessors + */ + +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL +kdc_request_add_reply_padata(astgs_request_t r, PA_DATA *md) +{ + heim_assert(r->rep.padata != NULL, "reply padata not allocated"); + return add_METHOD_DATA(r->rep.padata, md); +} + +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL +kdc_request_add_encrypted_padata(astgs_request_t r, PA_DATA *md) +{ + if (r->ek.encrypted_pa_data == NULL) { + r->ek.encrypted_pa_data = calloc(1, sizeof *(r->ek.encrypted_pa_data)); + if (r->ek.encrypted_pa_data == NULL) { + return ENOMEM; + } + } + + return add_METHOD_DATA(r->ek.encrypted_pa_data, md); +} + +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL +kdc_request_add_pac_buffer(astgs_request_t r, + uint32_t pactype, + const krb5_data *d) +{ + krb5_error_code ret; + krb5_pac pac; + + if (r->pac == NULL) { + ret = krb5_pac_init(r->context, &pac); + if (ret) + return ret; + } else + pac = heim_retain(r->pac); + + ret = krb5_pac_add_buffer(r->context, pac, pactype, d); + if (ret == 0 && r->pac == NULL) + r->pac = pac; + else + heim_release(pac); + + return ret; +} + +#undef _KDC_REQUEST_GET_ACCESSOR +#define _KDC_REQUEST_GET_ACCESSOR(R, T, f) \ + KDC_LIB_FUNCTION T KDC_LIB_CALL \ + kdc_request_get_ ## f(R r) \ + { \ + return r->f; \ + } + +#undef _KDC_REQUEST_SET_ACCESSOR +#define _KDC_REQUEST_SET_ACCESSOR(R, T, f) \ + KDC_LIB_FUNCTION void KDC_LIB_CALL \ + kdc_request_set_ ## f(R r, T v) \ + { \ + r->f = v; \ + } + +#undef _KDC_REQUEST_GET_ACCESSOR_PTR +#define _KDC_REQUEST_GET_ACCESSOR_PTR(R, T, f) \ + KDC_LIB_FUNCTION const T KDC_LIB_CALL \ + kdc_request_get_ ## f(R r) \ + { \ + return r->f; \ + } + +#undef _KDC_REQUEST_SET_ACCESSOR_PTR +#define _KDC_REQUEST_SET_ACCESSOR_PTR(R, T, t, f) \ + KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL \ + kdc_request_set_ ## f(R r, const T v) \ + { \ + krb5_error_code ret; \ + T tmp; \ + \ + if (v == r->f) \ + return 0; \ + else if (v) { \ + ret = copy_##t(v, &tmp); \ + if (ret) \ + return ret; \ + } else \ + tmp = NULL; \ + \ + free_##t(r->f); \ + r->f = tmp; \ + \ + return 0; \ + } + +#undef _KDC_REQUEST_GET_ACCESSOR_STRUCT +#define _KDC_REQUEST_GET_ACCESSOR_STRUCT(R, T, f) \ + KDC_LIB_FUNCTION const T * KDC_LIB_CALL \ + kdc_request_get_ ## f(R r) \ + { \ + return &r->f; \ + } + +#undef _KDC_REQUEST_SET_ACCESSOR_STRUCT +#define _KDC_REQUEST_SET_ACCESSOR_STRUCT(R, T, t, f) \ + KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL \ + kdc_request_set_ ## f(R r, const T *v) \ + { \ + krb5_error_code ret; \ + T tmp; \ + \ + if (v == NULL) \ + return EINVAL; \ + else if (v == &r->f) \ + return 0; \ + \ + ret = copy_##t(v, &tmp); \ + if (ret) \ + return ret; \ + \ + free_##t(&r->f); \ + r->f = tmp; \ + \ + return 0; \ + } + +static krb5_error_code +copy_string_ptr(const char *src, char **dst) +{ + *dst = strdup(src); + if (*dst == NULL) + return ENOMEM; + + return 0; +} + +static void +free_string_ptr(char *s) +{ + free(s); +} + +static krb5_error_code +copy_Principal_ptr(krb5_const_principal src, krb5_principal *dst) +{ + krb5_error_code ret; + krb5_principal p; + + *dst = NULL; + + p = calloc(1, sizeof(*p)); + if (p == NULL) + return ENOMEM; + + ret = copy_Principal(src, p); + if (ret == 0) + *dst = p; + else + free(p); + + return ret; +} + +static void +free_Principal_ptr(krb5_principal p) +{ + if (p) { + free_Principal(p); + free(p); + } +} + +static krb5_error_code +copy_pac(const struct krb5_pac_data *src, struct krb5_pac_data **dst) +{ + /* FIXME use heim_copy() when it exists */ + *dst = (krb5_pac)heim_retain((heim_object_t)src); + return 0; +} + +static void +free_pac(struct krb5_pac_data *o) +{ + heim_release(o); +} + +static krb5_error_code +copy_keyblock(const EncryptionKey *src, EncryptionKey *dst) +{ + return copy_EncryptionKey(src, dst); +} + +static void +free_keyblock(EncryptionKey *key) +{ + krb5_free_keyblock_contents(NULL, key); +} + +#undef HEIMDAL_KDC_KDC_ACCESSORS_H +#include "kdc-accessors.h" + +#undef _KDC_REQUEST_GET_ACCESSOR +#undef _KDC_REQUEST_SET_ACCESSOR + +#undef _KDC_REQUEST_GET_ACCESSOR_PTR +#undef _KDC_REQUEST_SET_ACCESSOR_PTR +#define _KDC_REQUEST_SET_ACCESSOR_PTR(R, T, t, f) \ + void \ + _kdc_request_set_ ## f ## _nocopy(R r, T *v) \ + { \ + if (*v != r->f) { \ + free_##t(r->f); \ + r->f = *v; \ + } \ + *v = NULL; \ + } + +#undef _KDC_REQUEST_GET_ACCESSOR_STRUCT +#undef _KDC_REQUEST_SET_ACCESSOR_STRUCT +#define _KDC_REQUEST_SET_ACCESSOR_STRUCT(R, T, t, f) \ + void \ + _kdc_request_set_ ## f ## _nocopy(R r, T *v) \ + { \ + if (v != &r->f) { \ + free_##t(&r->f); \ + r->f = *v; \ + } \ + memset(v, 0, sizeof(*v)); \ + } + +#undef HEIMDAL_KDC_KDC_ACCESSORS_H +#include "kdc-accessors.h" diff --git a/third_party/heimdal/kdc/kdc-plugin.h b/third_party/heimdal/kdc/kdc-plugin.h new file mode 100644 index 000000000000..efe8dd6abe0e --- /dev/null +++ b/third_party/heimdal/kdc/kdc-plugin.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 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. + */ + +/* $Id$ */ + +#ifndef HEIMDAL_KDC_KDC_PLUGIN_H +#define HEIMDAL_KDC_KDC_PLUGIN_H 1 + +#include +#include +#include +#include + +/* + * Allocate a PAC for the given client with krb5_pac_init(), + * and fill its contents in with krb5_pac_add_buffer(). + */ + +typedef krb5_error_code +(KRB5_CALLCONV *krb5plugin_kdc_pac_generate)(void *, + krb5_context, /* context */ + krb5_kdc_configuration *, /* configuration */ + hdb_entry *, /* client */ + hdb_entry *, /* server */ + const krb5_keyblock *, /* pk_replykey */ + uint64_t, /* pac_attributes */ + krb5_pac *); + +/* + * Verify the PAC KDC signatures by fetching the appropriate TGS key + * and calling krb5_pac_verify() with that key. Optionally update the + * PAC buffers on success. + */ + +typedef krb5_error_code +(KRB5_CALLCONV *krb5plugin_kdc_pac_verify)(void *, + krb5_context, /* context */ + krb5_kdc_configuration *, /* configuration */ + const krb5_principal, /* new ticket client */ + const krb5_principal, /* delegation proxy */ + hdb_entry *,/* client */ + hdb_entry *,/* server */ + hdb_entry *,/* krbtgt */ + krb5_pac *); + +/* + * Authorize the client principal's access to the Authentication Service (AS). + * This function is called after any pre-authentication has completed. + */ + +typedef krb5_error_code +(KRB5_CALLCONV *krb5plugin_kdc_client_access)(void *, astgs_request_t); + +/* + * A referral policy plugin can either rewrite the server principal + * by resetting priv->server_princ, or it can disable referral + * processing entirely by returning an error. + * + * The error code from the previous server lookup is available as r->ret. + * + * If the function returns KRB5_PLUGIN_NO_HANDLE, the TGS will continue + * with its default referral handling. + * + * Note well: the plugin should free priv->server_princ is replacing. + */ + +typedef krb5_error_code +(KRB5_CALLCONV *krb5plugin_kdc_referral_policy)(void *, astgs_request_t); + +/* + * Update the AS or TGS reply immediately prior to encoding. + */ + +typedef krb5_error_code +(KRB5_CALLCONV *krb5plugin_kdc_finalize_reply)(void *, astgs_request_t); + +/* + * Audit an AS or TGS request. This function is called after encoding the + * reply (on success), or before encoding the error message. If a HDB audit + * function is also present, it is called after this one. + * + * The request should not be modified by the plugin. + */ + +typedef krb5_error_code +(KRB5_CALLCONV *krb5plugin_kdc_audit)(void *, astgs_request_t); + +/* + * Plugins should carefully check API contract notes for changes + * between plugin API versions. + */ +#define KRB5_PLUGIN_KDC_VERSION_10 10 + +typedef struct krb5plugin_kdc_ftable { + int minor_version; + krb5_error_code (KRB5_CALLCONV *init)(krb5_context, void **); + void (KRB5_CALLCONV *fini)(void *); + krb5plugin_kdc_pac_generate pac_generate; + krb5plugin_kdc_pac_verify pac_verify; + krb5plugin_kdc_client_access client_access; + krb5plugin_kdc_referral_policy referral_policy; + krb5plugin_kdc_finalize_reply finalize_reply; + krb5plugin_kdc_audit audit; +} krb5plugin_kdc_ftable; + +#endif /* HEIMDAL_KDC_KDC_PLUGIN_H */ diff --git a/third_party/heimdal/kdc/kdc-replay.c b/third_party/heimdal/kdc/kdc-replay.c index af4e55c356d9..29190f7837f8 100644 --- a/third_party/heimdal/kdc/kdc-replay.c +++ b/third_party/heimdal/kdc/kdc-replay.c @@ -184,6 +184,8 @@ main(int argc, char **argv) unsigned int tag2; ret = der_get_tag (r.data, r.length, &cl, &ty, &tag2, NULL); + if (ret) + krb5_err(context, 1, ret, "Could not decode replay data"); if (MAKE_TAG(cl, ty, 0) != clty) krb5_errx(context, 1, "class|type mismatch: %d != %d", (int)MAKE_TAG(cl, ty, 0), (int)clty); diff --git a/third_party/heimdal/kdc/kdc.h b/third_party/heimdal/kdc/kdc.h index cbf4f5117382..e3709ada6b0a 100644 --- a/third_party/heimdal/kdc/kdc.h +++ b/third_party/heimdal/kdc/kdc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * * Copyright (c) 2005 Andrew Bartlett @@ -46,120 +46,27 @@ #include #include -#define heim_pcontext krb5_context -#define heim_pconfig krb5_kdc_configuration * -#include - enum krb5_kdc_trpolicy { TRPOLICY_ALWAYS_CHECK, TRPOLICY_ALLOW_PER_PRINCIPAL, TRPOLICY_ALWAYS_HONOUR_REQUEST }; -typedef struct krb5_kdc_configuration { - krb5_boolean require_preauth; /* require preauth for all principals */ - time_t kdc_warn_pwexpire; /* time before expiration to print a warning */ - - struct HDB **db; - int num_db; - - int num_kdc_processes; - - krb5_boolean encode_as_rep_as_tgs_rep; /* bug compatibility */ - - /* - * Windows 2019 (and earlier versions) always sends the salt - * and Samba has testsuites that check this behaviour, so a - * Samba AD DC will set this flag to match the AS-REP packet - * exactly. - */ - krb5_boolean force_include_pa_etype_salt; - - krb5_boolean tgt_use_strongest_session_key; - krb5_boolean preauth_use_strongest_session_key; - krb5_boolean svc_use_strongest_session_key; - krb5_boolean use_strongest_server_key; - - krb5_boolean check_ticket_addresses; - krb5_boolean warn_ticket_addresses; - krb5_boolean allow_null_ticket_addresses; - krb5_boolean allow_anonymous; - krb5_boolean historical_anon_realm; - krb5_boolean strict_nametypes; - enum krb5_kdc_trpolicy trpolicy; - - krb5_boolean require_pac; - krb5_boolean enable_armored_pa_enc_timestamp; - krb5_boolean enable_unarmored_pa_enc_timestamp; - - krb5_boolean autodetect_referrals; - - krb5_boolean enable_pkinit; - krb5_boolean pkinit_princ_in_cert; - const char *pkinit_kdc_identity; - const char *pkinit_kdc_anchors; - const char *pkinit_kdc_friendly_name; - const char *pkinit_kdc_ocsp_file; - char **pkinit_kdc_cert_pool; - char **pkinit_kdc_revoke; - int pkinit_dh_min_bits; - /* XXX Turn these into bit-fields */ - int pkinit_require_binding; - int pkinit_allow_proxy_certs; - int synthetic_clients; - int pkinit_max_life_from_cert_extension; - krb5_timestamp pkinit_max_life_from_cert; - krb5_timestamp pkinit_max_life_bound; - krb5_timestamp synthetic_clients_max_life; - krb5_timestamp synthetic_clients_max_renew; - - krb5_log_facility *logf; - - int enable_digest; - int digests_allowed; - - int enable_gss_preauth; - int enable_gss_auth_data; - gss_OID_set gss_mechanisms_allowed; - gss_OID_set gss_cross_realm_mechanisms_allowed; - - size_t max_datagram_reply_length; - - int enable_kx509; - - const char *app; -} krb5_kdc_configuration; - -#define ASTGS_REQUEST_DESC_COMMON_ELEMENTS \ - HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; \ - \ - KDC_REQ req; \ - \ - KDC_REP rep; \ - EncTicketPart et; \ - EncKDCRepPart ek; \ - \ - /* princ requested by client (AS) or canon princ (TGT) */ \ - krb5_principal client_princ; \ - hdb_entry_ex *client; \ - HDB *clientdb; \ - \ - krb5_principal server_princ; \ - hdb_entry_ex *server; \ - \ - krb5_keyblock reply_key; \ - \ - krb5_pac pac; \ - uint64_t pac_attributes; +struct krb5_kdc_configuration; +typedef struct krb5_kdc_configuration krb5_kdc_configuration; -#ifndef __KDC_LOCL_H__ -struct astgs_request_desc { - ASTGS_REQUEST_DESC_COMMON_ELEMENTS -}; -#endif +/* + * Access to request fields by plugins and other out-of-tree + * consumers should be via the functions in kdc-accessors.h. + */ +struct kdc_request_desc; typedef struct kdc_request_desc *kdc_request_t; + +struct astgs_request_desc; typedef struct astgs_request_desc *astgs_request_t; + +struct kx509_req_context_desc; typedef struct kx509_req_context_desc *kx509_req_context; struct krb5_kdc_service { @@ -170,9 +77,54 @@ struct krb5_kdc_service { krb5_error_code (*process)(kdc_request_t *, int *claim); }; -#include +/* + * The following fields are guaranteed stable within a major + * release of Heimdal and can be manipulated by applications + * that manage KDC requests themselves using libkdc. + * + * Applications can make custom KDC configuration available + * to libkdc by using krb5_set_config(). + */ -#undef heim_pcontext -#undef heim_pconfig +#define KRB5_KDC_CONFIGURATION_COMMON_ELEMENTS \ + krb5_log_facility *logf; \ + struct HDB **db; \ + size_t num_db; \ + const char *app; \ + \ + /* \ + * Windows 2019 (and earlier versions) always sends the salt\ + * and Samba has testsuites that check this behaviour, so a \ + * Samba AD DC will set this flag to match the AS-REP packet\ + * exactly. \ + */ \ + unsigned int force_include_pa_etype_salt : 1; \ + \ + unsigned int tgt_use_strongest_session_key : 1; \ + unsigned int preauth_use_strongest_session_key : 1; \ + unsigned int svc_use_strongest_session_key : 1; \ + unsigned int use_strongest_server_key : 1; \ + \ + unsigned int require_pac : 1; \ + unsigned int enable_armored_pa_enc_timestamp : 1 +#ifndef __KDC_LOCL_H__ +struct krb5_kdc_configuration { + KRB5_KDC_CONFIGURATION_COMMON_ELEMENTS; +}; #endif + +typedef void *kdc_object_t; +typedef struct kdc_array_data *kdc_array_t; +typedef struct kdc_dict_data *kdc_dict_t; +typedef struct kdc_string_data *kdc_string_t; +typedef struct kdc_data_data *kdc_data_t; +typedef struct kdc_number_data *kdc_number_t; + +typedef void (KRB5_CALLCONV *kdc_array_iterator_t)(kdc_object_t, void *, int *); + +typedef void (KRB5_CALLCONV *kdc_type_dealloc)(kdc_object_t); + +#include + +#endif /* __KDC_H__ */ diff --git a/third_party/heimdal/kdc/kdc_locl.h b/third_party/heimdal/kdc/kdc_locl.h index e7b86151def0..8418a91a0a4b 100644 --- a/third_party/heimdal/kdc/kdc_locl.h +++ b/third_party/heimdal/kdc/kdc_locl.h @@ -64,15 +64,95 @@ struct kdc_request_desc { HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; }; -struct as_request_pa_state; struct kdc_patypes; +struct krb5_kdc_configuration { + KRB5_KDC_CONFIGURATION_COMMON_ELEMENTS; + + int num_kdc_processes; + + size_t max_datagram_reply_length; + + time_t kdc_warn_pwexpire; /* time before expiration to print a warning */ + + unsigned int require_preauth : 1; /* require preauth for all principals */ + unsigned int encode_as_rep_as_tgs_rep : 1; /* bug compatibility */ + + unsigned int check_ticket_addresses : 1; + unsigned int warn_ticket_addresses : 1; + unsigned int allow_null_ticket_addresses : 1; + unsigned int allow_anonymous : 1; + unsigned int historical_anon_realm : 1; + unsigned int strict_nametypes : 1; + enum krb5_kdc_trpolicy trpolicy; + + unsigned int enable_unarmored_pa_enc_timestamp : 1; + + unsigned int enable_pkinit : 1; + unsigned int pkinit_princ_in_cert : 1; + const char *pkinit_kdc_identity; + const char *pkinit_kdc_anchors; + const char *pkinit_kdc_friendly_name; + const char *pkinit_kdc_ocsp_file; + char **pkinit_kdc_cert_pool; + char **pkinit_kdc_revoke; + int pkinit_dh_min_bits; + unsigned int pkinit_require_binding : 1; + unsigned int pkinit_allow_proxy_certs : 1; + unsigned int synthetic_clients : 1; + unsigned int pkinit_max_life_from_cert_extension : 1; + krb5_timestamp pkinit_max_life_from_cert; + krb5_timestamp pkinit_max_life_bound; + krb5_timestamp synthetic_clients_max_life; + krb5_timestamp synthetic_clients_max_renew; + + int digests_allowed; + unsigned int enable_digest : 1; + + unsigned int enable_kx509 : 1; + + unsigned int enable_gss_preauth : 1; + unsigned int enable_gss_auth_data : 1; + gss_OID_set gss_mechanisms_allowed; + gss_OID_set gss_cross_realm_mechanisms_allowed; + +}; + struct astgs_request_desc { - ASTGS_REQUEST_DESC_COMMON_ELEMENTS; + HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; + + /* AS-REQ or TGS-REQ */ + KDC_REQ req; + + /* AS-REP or TGS-REP */ + KDC_REP rep; + EncTicketPart et; + EncKDCRepPart ek; + + /* client principal (AS) or TGT/S4U principal (TGS) */ + krb5_principal client_princ; + hdb_entry *client; + HDB *clientdb; + krb5_principal canon_client_princ; + + /* server principal */ + krb5_principal server_princ; + HDB *serverdb; + hdb_entry *server; + + /* presented ticket in TGS-REQ (unused by AS) */ + krb5_principal krbtgt_princ; + hdb_entry *krbtgt; + HDB *krbtgtdb; + krb5_ticket *ticket; + + krb5_keyblock reply_key; + + krb5_pac pac; + uint64_t pac_attributes; /* Only AS */ const struct kdc_patypes *pa_used; - struct as_request_pa_state *pa_state; /* PA methods can affect both the reply key and the session key (pkinit) */ krb5_enctype sessionetype; @@ -89,7 +169,8 @@ struct astgs_request_desc { unsigned int fast_asserted : 1; krb5_crypto armor_crypto; - hdb_entry_ex *armor_server; + hdb_entry *armor_server; + HDB *armor_serverdb; krb5_ticket *armor_ticket; Key *armor_key; @@ -148,4 +229,24 @@ configure(krb5_context context, int argc, char **argv, int *optidx); void bonjour_announce(krb5_context, krb5_kdc_configuration *); #endif +/* no-copy setters */ + +#undef _KDC_REQUEST_GET_ACCESSOR +#undef _KDC_REQUEST_SET_ACCESSOR + +#undef _KDC_REQUEST_GET_ACCESSOR_PTR +#undef _KDC_REQUEST_SET_ACCESSOR_PTR +#define _KDC_REQUEST_SET_ACCESSOR_PTR(R, T, t, f) \ + void \ + _kdc_request_set_ ## f ## _nocopy(R r, T *v); + +#undef _KDC_REQUEST_GET_ACCESSOR_STRUCT +#undef _KDC_REQUEST_SET_ACCESSOR_STRUCT +#define _KDC_REQUEST_SET_ACCESSOR_STRUCT(R, T, t, f) \ + void \ + _kdc_request_set_ ## f ## _nocopy(R r, T *v); + +#undef HEIMDAL_KDC_KDC_ACCESSORS_H +#include "kdc-accessors.h" + #endif /* __KDC_LOCL_H__ */ diff --git a/third_party/heimdal/kdc/kerberos5.c b/third_party/heimdal/kdc/kerberos5.c index ee7e56c5f27d..b30d321f6f14 100644 --- a/third_party/heimdal/kdc/kerberos5.c +++ b/third_party/heimdal/kdc/kerberos5.c @@ -33,44 +33,26 @@ #include "kdc_locl.h" -#define MAX_TIME ((time_t)((1U << 31) - 1)) +#ifdef TIME_T_SIGNED +#if SIZEOF_TIME_T == 4 +#define MAX_TIME ((time_t)INT32_MAX) +#elif SIZEOF_TIME_T == 8 +#define MAX_TIME ((time_t)INT64_MAX) +#else +#error "Unexpected sizeof(time_t)" +#endif +#else + +#if SIZEOF_TIME_T == 4 +#define MAX_TIME ((time_t)UINT32_MAX) +#else +#define MAX_TIME ((time_t)UINT64_MAX) +#endif +#endif #undef __attribute__ #define __attribute__(X) -struct kdc_pa_auth_status { - int auth_status; - const char *auth_details; - void *free_ptr; -}; - -static krb5_error_code -_kdc_audit_auth_status(astgs_request_t r, - struct kdc_pa_auth_status *status, - const char *pa_type) -{ - struct HDB *hdb; - krb5_error_code ret = 0; - - if (r->clientdb) - hdb = r->clientdb; - else - hdb = r->config->db[0]; - - if (hdb && hdb->hdb_auth_status) - ret = hdb->hdb_auth_status(r->context, - hdb, - r->client, - &r->tv_start, - r->addr, - r->cname, - status->auth_status, - status->auth_details, - pa_type); - - return ret; -} - void _kdc_fix_time(time_t **t) { @@ -104,10 +86,10 @@ set_salt_padata(krb5_context context, krb5_kdc_configuration *config, METHOD_DATA *md, Key *key) { - if (key->salt) - return get_pa_etype_info2(context, config, md, key, TRUE); + if (!key->salt) + return 0; - return 0; + return get_pa_etype_info2(context, config, md, key, TRUE); } const PA_DATA* @@ -134,9 +116,9 @@ _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 && - (etype == (krb5_enctype)ETYPE_DES_CBC_CRC - || etype == (krb5_enctype)ETYPE_DES_CBC_MD4 - || etype == (krb5_enctype)ETYPE_DES_CBC_MD5)) + (etype == ETYPE_DES_CBC_CRC + || etype == ETYPE_DES_CBC_MD4 + || etype == ETYPE_DES_CBC_MD5)) return TRUE; return FALSE; } @@ -153,7 +135,7 @@ is_default_salt_p(const krb5_salt *default_salt, const Key *key) return TRUE; if (default_salt->salttype != key->salt->type) return FALSE; - if (krb5_data_cmp(&default_salt->saltvalue, &key->salt->salt)) + if (krb5_data_cmp(&default_salt->saltvalue, &key->salt->salt) != 0) return FALSE; return TRUE; } @@ -170,11 +152,11 @@ is_default_salt_p(const krb5_salt *default_salt, const Key *key) static krb5_boolean is_good_salt_p(const krb5_salt *default_salt, const Key *key) { - if (key->key.keytype != (krb5_enctype)ETYPE_DES_CBC_CRC) - return TRUE; - return is_default_salt_p(default_salt, key); -} + if (key->key.keytype == KRB5_ENCTYPE_DES_CBC_CRC) + return is_default_salt_p(default_salt, key); + return TRUE; +} krb5_boolean _kdc_is_anon_request(const KDC_REQ *req) @@ -217,25 +199,25 @@ _kdc_find_etype(astgs_request_t r, uint32_t flags, krb5_boolean use_strongest_session_key; krb5_boolean is_preauth = flags & KFE_IS_PREAUTH; krb5_boolean is_tgs = flags & KFE_IS_TGS; - hdb_entry_ex *princ; + hdb_entry *princ; krb5_principal request_princ; krb5_error_code ret; krb5_salt def_salt; - krb5_enctype enctype = (krb5_enctype)ETYPE_NULL; + krb5_enctype enctype = ETYPE_NULL; const krb5_enctype *p; Key *key = NULL; size_t i, k, m; if (is_preauth && (flags & KFE_USE_CLIENT) && - r->client->entry.flags.synthetic) + r->client->flags.synthetic) return KRB5KDC_ERR_ETYPE_NOSUPP; - if ((flags & KFE_USE_CLIENT) && !r->client->entry.flags.synthetic) { + if ((flags & KFE_USE_CLIENT) && !r->client->flags.synthetic) { princ = r->client; request_princ = r->client_princ; } else { princ = r->server; - request_princ = r->server->entry.principal; + request_princ = r->server->principal; } use_strongest_session_key = @@ -280,14 +262,14 @@ _kdc_find_etype(astgs_request_t r, uint32_t flags, /* drive the search with local supported enctypes list */ p = krb5_kerberos_enctypes(r->context); for (i = 0; - p[i] != (krb5_enctype)ETYPE_NULL && enctype == (krb5_enctype)ETYPE_NULL; + p[i] != ETYPE_NULL && enctype == ETYPE_NULL; i++) { if (krb5_enctype_valid(r->context, p[i]) != 0 && - !_kdc_is_weak_exception(princ->entry.principal, p[i])) + !_kdc_is_weak_exception(princ->principal, p[i])) continue; /* check that the client supports it too */ - for (k = 0; k < len && enctype == (krb5_enctype)ETYPE_NULL; k++) { + for (k = 0; k < len && enctype == ETYPE_NULL; k++) { if (p[i] != etypes[k]) continue; @@ -304,15 +286,15 @@ _kdc_find_etype(astgs_request_t r, uint32_t flags, /* check target princ support */ key = NULL; - if (!(flags & KFE_USE_CLIENT) && princ->entry.etypes) { + if (!is_preauth && !(flags & KFE_USE_CLIENT) && princ->etypes) { /* * Use the etypes list from the server's HDB entry instead * of deriving it from its long-term keys. This allows an * entry to have just one long-term key but record support * for multiple enctypes. */ - for (m = 0; m < princ->entry.etypes->len; m++) { - if (p[i] == princ->entry.etypes->val[m]) { + for (m = 0; m < princ->etypes->len; m++) { + if (p[i] == princ->etypes->val[m]) { ret = 0; break; } @@ -324,7 +306,7 @@ _kdc_find_etype(astgs_request_t r, uint32_t flags, * PA-ETYPE-INFO* or because we're selecting a session key * enctype. */ - while (hdb_next_enctype2key(r->context, &princ->entry, NULL, + while (hdb_next_enctype2key(r->context, princ, NULL, p[i], &key) == 0) { if (key->key.keyvalue.length == 0) { ret = KRB5KDC_ERR_NULL_KEY; @@ -352,12 +334,12 @@ _kdc_find_etype(astgs_request_t r, uint32_t flags, for(i = 0; ret != 0 && i < len; i++) { if (krb5_enctype_valid(r->context, etypes[i]) != 0 && - !_kdc_is_weak_exception(princ->entry.principal, etypes[i])) + !_kdc_is_weak_exception(princ->principal, etypes[i])) continue; key = NULL; while (ret != 0 && - hdb_next_enctype2key(r->context, &princ->entry, NULL, + hdb_next_enctype2key(r->context, princ, NULL, etypes[i], &key) == 0) { if (key->key.keyvalue.length == 0) { ret = KRB5KDC_ERR_NULL_KEY; @@ -372,14 +354,14 @@ _kdc_find_etype(astgs_request_t r, uint32_t flags, } } - if (enctype == (krb5_enctype)ETYPE_NULL) { + if (ret == 0 && enctype == ETYPE_NULL) { /* * if the service principal is one for which there is a known 1DES * exception and no other enctype matches both the client request and * the service key list, provide a DES-CBC-CRC key. */ if (ret_key == NULL && - _kdc_is_weak_exception(princ->entry.principal, ETYPE_DES_CBC_CRC)) { + _kdc_is_weak_exception(princ->principal, ETYPE_DES_CBC_CRC)) { ret = 0; enctype = ETYPE_DES_CBC_CRC; } else { @@ -498,15 +480,13 @@ _kdc_log_timestamp(astgs_request_t r, const char *type, endtime_str[100], renewtime_str[100]; if (authtime) - _kdc_audit_addkv((kdc_request_t)r, 0, "auth", "%ld", (long)authtime); + kdc_audit_setkv_number((kdc_request_t)r, "auth", authtime); if (starttime && *starttime) - _kdc_audit_addkv((kdc_request_t)r, 0, "start", "%ld", - (long)*starttime); + kdc_audit_setkv_number((kdc_request_t)r, "start", *starttime); if (endtime) - _kdc_audit_addkv((kdc_request_t)r, 0, "end", "%ld", (long)endtime); + kdc_audit_setkv_number((kdc_request_t)r, "end", endtime); if (renew_till && *renew_till) - _kdc_audit_addkv((kdc_request_t)r, 0, "renew", "%ld", - (long)*renew_till); + kdc_audit_setkv_number((kdc_request_t)r, "renew", *renew_till); krb5_format_time(r->context, authtime, authtime_str, sizeof(authtime_str), TRUE); @@ -535,9 +515,7 @@ _kdc_log_timestamp(astgs_request_t r, const char *type, #ifdef PKINIT static krb5_error_code -pa_pkinit_validate(astgs_request_t r, - const PA_DATA *pa, - struct kdc_pa_auth_status *auth_status) +pa_pkinit_validate(astgs_request_t r, const PA_DATA *pa) { pk_client_params *pkp = NULL; char *client_cert = NULL; @@ -548,22 +526,23 @@ pa_pkinit_validate(astgs_request_t r, ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; _kdc_r_log(r, 4, "Failed to decode PKINIT PA-DATA -- %s", r->cname); - auth_status->auth_status = HDB_AUTHSTATUS_PKINIT_FAILURE; goto out; } ret = _kdc_pk_check_client(r, pkp, &client_cert); + if (client_cert) + kdc_audit_addkv((kdc_request_t)r, 0, KDC_REQUEST_KV_PKINIT_CLIENT_CERT, + "%s", client_cert); if (ret) { _kdc_set_e_text(r, "PKINIT certificate not allowed to " "impersonate principal"); - auth_status->auth_status = HDB_AUTHSTATUS_PKINIT_FAILURE; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED); goto out; } - auth_status->auth_details = client_cert; - auth_status->free_ptr = client_cert; r->pa_endtime = _kdc_pk_endtime(pkp); - if (!r->client->entry.flags.synthetic) + if (!r->client->flags.synthetic) r->pa_max_life = _kdc_pk_max_life(pkp); _kdc_r_log(r, 4, "PKINIT pre-authentication succeeded -- %s using %s", @@ -577,10 +556,13 @@ pa_pkinit_validate(astgs_request_t r, ret = _kdc_add_initial_verified_cas(r->context, r->config, pkp, &r->et); - auth_status->auth_status = HDB_AUTHSTATUS_PKINIT_SUCCESS; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_PREAUTH_SUCCEEDED); + out: if (pkp) _kdc_pk_free_client_param(r->context, pkp); + free(client_cert); return ret; } @@ -588,9 +570,7 @@ pa_pkinit_validate(astgs_request_t r, #endif /* PKINIT */ static krb5_error_code -pa_gss_validate(astgs_request_t r, - const PA_DATA *pa, - struct kdc_pa_auth_status *auth_status) +pa_gss_validate(astgs_request_t r, const PA_DATA *pa) { gss_client_params *gcp = NULL; char *client_name = NULL; @@ -603,19 +583,23 @@ pa_gss_validate(astgs_request_t r, if (open) { ret = _kdc_gss_check_client(r, gcp, &client_name); + if (client_name) + kdc_audit_addkv((kdc_request_t)r, 0, KDC_REQUEST_KV_GSS_INITIATOR, + "%s", client_name); if (ret) { _kdc_set_e_text(r, "GSS-API client not allowed to " "impersonate principal"); - auth_status->auth_status = HDB_AUTHSTATUS_GSS_FAILURE; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED); goto out; } - auth_status->auth_details = client_name; - auth_status->free_ptr = client_name; r->pa_endtime = _kdc_gss_endtime(r, gcp); _kdc_r_log(r, 4, "GSS pre-authentication succeeded -- %s using %s", r->cname, client_name); + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_PREAUTH_SUCCEEDED); ret = _kdc_gss_mk_composite_name_ad(r, gcp); if (ret) { @@ -628,19 +612,17 @@ pa_gss_validate(astgs_request_t r, if (ret) { if (ret != KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED) _kdc_set_e_text(r, "Failed to build GSS pre-authentication reply"); - goto out; } - auth_status->auth_status = HDB_AUTHSTATUS_GSS_SUCCESS; - - heim_assert(r->pa_state == NULL, "already have PA state, should be NULL"); - r->pa_state = (struct as_request_pa_state *)gcp; - gcp = NULL; + ret = kdc_request_set_attribute((kdc_request_t)r, + HSTR("org.h5l.pa-gss-client-params"), gcp); + if (ret) + goto out; out: - if (gcp) - _kdc_gss_free_client_param(r, gcp); + kdc_object_release(gcp); + free(client_name); return ret; } @@ -648,28 +630,17 @@ out: static krb5_error_code pa_gss_finalize_pac(astgs_request_t r) { - gss_client_params *gcp = (gss_client_params *)r->pa_state; + gss_client_params *gcp; + + gcp = kdc_request_get_attribute((kdc_request_t)r, HSTR("org.h5l.pa-gss-client-params")); heim_assert(gcp != NULL, "invalid GSS-API client params"); return _kdc_gss_finalize_pac(r, gcp); } -static void -pa_gss_cleanup(astgs_request_t r) -{ - gss_client_params *gcp = (gss_client_params *)r->pa_state; - - if (gcp) { - _kdc_gss_free_client_param(r, gcp); - r->pa_state = NULL; - } -} - static krb5_error_code -pa_enc_chal_validate(astgs_request_t r, - const PA_DATA *pa, - struct kdc_pa_auth_status *auth_status) +pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa) { krb5_data pepper1, pepper2; int invalidPassword = 0; @@ -688,11 +659,12 @@ pa_enc_chal_validate(astgs_request_t r, return ret; } - if (r->client->entry.flags.locked_out) { + if (r->client->flags.locked_out) { ret = KRB5KDC_ERR_CLIENT_REVOKED; kdc_log(r->context, r->config, 0, "Client (%s) is locked out", r->cname); - auth_status->auth_status = HDB_AUTHSTATUS_CLIENT_LOCKED_OUT; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_CLIENT_LOCKED_OUT); return ret; } @@ -716,11 +688,11 @@ pa_enc_chal_validate(astgs_request_t r, kdc_log(r->context, r->config, 5, "FAST armor enctype is: %d", (int)aenctype); - for (i = 0; i < r->client->entry.keys.len; i++) { + for (i = 0; i < r->client->keys.len; i++) { krb5_crypto challengecrypto, longtermcrypto; krb5_keyblock challengekey; - k = &r->client->entry.keys.val[i]; + k = &r->client->keys.val[i]; ret = krb5_crypto_init(r->context, &k->key, 0, &longtermcrypto); if (ret) @@ -813,20 +785,21 @@ pa_enc_chal_validate(astgs_request_t r, if (ret) goto out; - ret = set_salt_padata(r->context, r->config, - r->rep.padata, k); - if (ret) - goto out; + if (ret == 0) + ret = set_salt_padata(r->context, r->config, + r->rep.padata, k); /* * Success */ - auth_status->auth_status = HDB_AUTHSTATUS_CORRECT_PASSWORD; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY); goto out; } if (invalidPassword) { - auth_status->auth_status = HDB_AUTHSTATUS_WRONG_PASSWORD; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY); ret = KRB5KDC_ERR_PREAUTH_FAILED; } else { ret = KRB5KDC_ERR_ETYPE_NOSUPP; @@ -838,9 +811,7 @@ pa_enc_chal_validate(astgs_request_t r, } static krb5_error_code -pa_enc_ts_validate(astgs_request_t r, - const PA_DATA *pa, - struct kdc_pa_auth_status *auth_status) +pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa) { EncryptedData enc_data; krb5_error_code ret; @@ -863,11 +834,12 @@ pa_enc_ts_validate(astgs_request_t r, return ret; } - if (r->client->entry.flags.locked_out) { + if (r->client->flags.locked_out) { ret = KRB5KDC_ERR_CLIENT_REVOKED; kdc_log(r->context, r->config, 0, "Client (%s) is locked out", r->cname); - auth_status->auth_status = HDB_AUTHSTATUS_CLIENT_LOCKED_OUT; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_CLIENT_LOCKED_OUT); return ret; } @@ -882,7 +854,7 @@ pa_enc_ts_validate(astgs_request_t r, goto out; } - ret = hdb_enctype2key(r->context, &r->client->entry, NULL, + ret = hdb_enctype2key(r->context, r->client, NULL, enc_data.etype, &pa_key); if(ret){ char *estr; @@ -935,14 +907,13 @@ pa_enc_ts_validate(astgs_request_t r, _kdc_r_log(r, 2, "Failed to decrypt PA-DATA -- %s " "(enctype %s) error %s", r->cname, str ? str : "unknown enctype", msg); + krb5_xfree(str); krb5_free_error_message(r->context, msg); - - free(auth_status->free_ptr); - auth_status->auth_status = HDB_AUTHSTATUS_WRONG_PASSWORD; - auth_status->auth_details = str ? str : "unknown enctype"; - auth_status->free_ptr = str; - - if(hdb_next_enctype2key(r->context, &r->client->entry, NULL, + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_PA_ETYPE, + pa_key->key.keytype); + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY); + if(hdb_next_enctype2key(r->context, r->client, NULL, enc_data.etype, &pa_key) == 0) goto try_next_key; @@ -952,10 +923,6 @@ pa_enc_ts_validate(astgs_request_t r, goto out; } free_EncryptedData(&enc_data); - free(auth_status->free_ptr); - auth_status->auth_status = HDB_AUTHSTATUS_INVALID; - auth_status->auth_details = NULL; - auth_status->free_ptr = NULL; ret = decode_PA_ENC_TS_ENC(ts_data.data, ts_data.length, &p, @@ -980,7 +947,8 @@ pa_enc_ts_validate(astgs_request_t r, (unsigned)labs(kdc_time - p.patimestamp), r->context->max_skew, r->cname); - auth_status->auth_details = "AP_ERR_SKEW"; + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_CLIENT_TIME_SKEW); /* * The following is needed to make windows clients to @@ -995,10 +963,8 @@ pa_enc_ts_validate(astgs_request_t r, ret = set_salt_padata(r->context, r->config, r->rep.padata, pa_key); - if (ret) - return ret; - - ret = krb5_copy_keyblock_contents(r->context, &pa_key->key, &r->reply_key); + if (ret == 0) + ret = krb5_copy_keyblock_contents(r->context, &pa_key->key, &r->reply_key); if (ret) return ret; @@ -1007,11 +973,11 @@ pa_enc_ts_validate(astgs_request_t r, str = NULL; _kdc_r_log(r, 4, "ENC-TS Pre-authentication succeeded -- %s using %s", r->cname, str ? str : "unknown enctype"); - _kdc_audit_addkv((kdc_request_t)r, 0, "pa-etype", "%d", - (int)pa_key->key.keytype); - auth_status->auth_status = HDB_AUTHSTATUS_CORRECT_PASSWORD; - auth_status->auth_details = str ? str : "unknown enctype"; - auth_status->free_ptr = str; + krb5_xfree(str); + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_PA_ETYPE, + pa_key->key.keytype); + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY); ret = 0; @@ -1029,9 +995,7 @@ struct kdc_patypes { #define PA_SYNTHETIC_OK 4 #define PA_REPLACE_REPLY_KEY 8 /* PA mech replaces reply key */ #define PA_USES_LONG_TERM_KEY 16 /* PA mech uses client's long-term key */ - krb5_error_code (*validate)(astgs_request_t, - const PA_DATA *pa, - struct kdc_pa_auth_status *auth_status); + krb5_error_code (*validate)(astgs_request_t, const PA_DATA *pa); krb5_error_code (*finalize_pac)(astgs_request_t r); void (*cleanup)(astgs_request_t r); }; @@ -1074,7 +1038,7 @@ static const struct kdc_patypes pat[] = { { KRB5_PADATA_GSS , "GSS", PA_ANNOUNCE | PA_SYNTHETIC_OK | PA_REPLACE_REPLY_KEY, - pa_gss_validate, pa_gss_finalize_pac, pa_gss_cleanup + pa_gss_validate, pa_gss_finalize_pac, NULL }, }; @@ -1107,8 +1071,8 @@ log_patypes(astgs_request_t r, METHOD_DATA *padata) str = rk_strpoolcollect(p); kdc_log(r->context, config, 4, "Client sent patypes: %s", str); - _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, - "client-pa", "%s", str); + kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, + "client-pa", "%s", str); free(str); } @@ -1273,25 +1237,29 @@ _kdc_encode_reply(krb5_context context, return ret; } if(rep->msg_type == krb_as_rep) { - krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_AS_REP_ENC_PART, - buf, - len, - ckvno, - &rep->enc_part); - free(buf); - ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret); + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_AS_REP_ENC_PART, + buf, + len, + ckvno, + &rep->enc_part); + free(buf); + if (ret == 0) + ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret); } else { - krb5_encrypt_EncryptedData(context, - crypto, - rk_is_subkey ? KRB5_KU_TGS_REP_ENC_PART_SUB_KEY : KRB5_KU_TGS_REP_ENC_PART_SESSION, - buf, - len, - ckvno, - &rep->enc_part); - free(buf); - ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret); + ret = krb5_encrypt_EncryptedData(context, + crypto, + rk_is_subkey ? + KRB5_KU_TGS_REP_ENC_PART_SUB_KEY : + KRB5_KU_TGS_REP_ENC_PART_SESSION, + buf, + len, + ckvno, + &rep->enc_part); + free(buf); + if (ret == 0) + ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret); } krb5_crypto_destroy(context, crypto); if(ret) { @@ -1315,57 +1283,6 @@ _kdc_encode_reply(krb5_context context, * */ -static krb5_error_code -make_etype_info_entry(krb5_context context, - ETYPE_INFO_ENTRY *ent, - Key *key, - krb5_boolean include_salt) -{ - ent->etype = key->key.keytype; - if (key->salt && include_salt){ -#if 0 - ALLOC(ent->salttype); - - if(key->salt->type == hdb_pw_salt) - *ent->salttype = 0; /* or 1? or NULL? */ - else if(key->salt->type == hdb_afs3_salt) - *ent->salttype = 2; - else { - kdc_log(context, config, 4, "unknown salt-type: %d", - key->salt->type); - return KRB5KRB_ERR_GENERIC; - } - /* according to `the specs', we can't send a salt if - we have AFS3 salted key, but that requires that you - *know* what cell you are using (e.g by assuming - that the cell is the same as the realm in lower - case) */ -#elif 0 - ALLOC(ent->salttype); - *ent->salttype = key->salt->type; -#else - /* - * We shouldn't sent salttype since it is incompatible with the - * specification and it breaks windows clients. The afs - * salting problem is solved by using KRB5-PADATA-AFS3-SALT - * implemented in Heimdal 0.7 and later. - */ - ent->salttype = NULL; -#endif - krb5_copy_data(context, &key->salt->salt, - &ent->salt); - } else { - /* we return no salt type at all, as that should indicate - * the default salt type and make everybody happy. some - * systems (like w2k) dislike being told the salt type - * here. */ - - ent->salttype = NULL; - ent->salt = NULL; - } - return 0; -} - static krb5_error_code get_pa_etype_info(krb5_context context, krb5_kdc_configuration *config, @@ -1373,35 +1290,51 @@ get_pa_etype_info(krb5_context context, krb5_boolean include_salt) { krb5_error_code ret = 0; - ETYPE_INFO pa; - unsigned char *buf; + ETYPE_INFO_ENTRY eie; /* do not free this one */ + ETYPE_INFO ei; + PA_DATA pa; size_t len; + /* + * Code moved here from what used to be make_etype_info_entry() because + * using the ASN.1 compiler-generated SEQUENCE OF add functions makes that + * old function's body and this one's small and clean. + * + * The following comment blocks were there: + * + * According to `the specs', we can't send a salt if we have AFS3 salted + * key, but that requires that you *know* what cell you are using (e.g by + * assuming that the cell is the same as the realm in lower case) + * + * We shouldn't sent salttype since it is incompatible with the + * specification and it breaks windows clients. The afs salting problem + * is solved by using KRB5-PADATA-AFS3-SALT implemented in Heimdal 0.7 and + * later. + * + * We return no salt type at all, as that should indicate the default salt + * type and make everybody happy. some systems (like w2k) dislike being + * told the salt type here. + */ - pa.len = 1; - pa.val = calloc(1, sizeof(pa.val[0])); - if(pa.val == NULL) - return ENOMEM; - - ret = make_etype_info_entry(context, &pa.val[0], ckey, include_salt); - if (ret) { - free_ETYPE_INFO(&pa); - return ret; - } - - ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret); - free_ETYPE_INFO(&pa); - if(ret) - return ret; - ret = realloc_method_data(md); - if(ret) { - free(buf); - return ret; - } - md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO; - md->val[md->len - 1].padata_value.length = len; - md->val[md->len - 1].padata_value.data = buf; - return 0; + pa.padata_type = KRB5_PADATA_ETYPE_INFO; + pa.padata_value.data = NULL; + pa.padata_value.length = 0; + ei.len = 0; + ei.val = NULL; + eie.etype = ckey->key.keytype; + eie.salttype = NULL; + eie.salt = NULL; + if (include_salt && ckey->salt) + eie.salt = &ckey->salt->salt; + ret = add_ETYPE_INFO(&ei, &eie); + if (ret == 0) + ASN1_MALLOC_ENCODE(ETYPE_INFO, pa.padata_value.data, pa.padata_value.length, + &ei, &len, ret); + if (ret == 0) + add_METHOD_DATA(md, &pa); + free_ETYPE_INFO(&ei); + free_PA_DATA(&pa); + return ret; } /* @@ -1642,8 +1575,8 @@ _log_astgs_req(astgs_request_t r, krb5_enctype setype) str = rk_strpoolcollect(s); if (str) - _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, "etypes", "%s", - str); + kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, "etypes", "%s", + str); free(str); ret = krb5_enctype_to_string(r->context, cetype, &cet); @@ -1664,7 +1597,7 @@ _log_astgs_req(astgs_request_t r, krb5_enctype setype) _kdc_r_log(r, 4, "%s", str); free(str); - _kdc_audit_addkv((kdc_request_t)r, 0, "etype", "%d/%d", cetype, setype); + kdc_audit_addkv((kdc_request_t)r, 0, "etype", "%d/%d", cetype, setype); { char fixedstr[128]; @@ -1674,8 +1607,8 @@ _log_astgs_req(astgs_request_t r, krb5_enctype setype) fixedstr, sizeof(fixedstr)); if (result > 0) { _kdc_r_log(r, 4, "Requested flags: %s", fixedstr); - _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, - "flags", "%s", fixedstr); + kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, + "flags", "%s", fixedstr); } } } @@ -1686,30 +1619,28 @@ _log_astgs_req(astgs_request_t r, krb5_enctype setype) * and error code otherwise. */ -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL kdc_check_flags(astgs_request_t r, krb5_boolean is_as_req, - hdb_entry_ex *client_ex, - hdb_entry_ex *server_ex) + hdb_entry *client, + hdb_entry *server) { - if (client_ex != NULL) { - hdb_entry *client = &client_ex->entry; - + if (client != NULL) { /* check client */ if (client->flags.locked_out) { - _kdc_audit_addreason((kdc_request_t)r, "Client is locked out"); + kdc_audit_addreason((kdc_request_t)r, "Client is locked out"); return KRB5KDC_ERR_CLIENT_REVOKED; } if (client->flags.invalid) { - _kdc_audit_addreason((kdc_request_t)r, - "Client has invalid bit set"); + kdc_audit_addreason((kdc_request_t)r, + "Client has invalid bit set"); return KRB5KDC_ERR_POLICY; } if (!client->flags.client) { - _kdc_audit_addreason((kdc_request_t)r, - "Principal may not act as client"); + kdc_audit_addreason((kdc_request_t)r, + "Principal may not act as client"); return KRB5KDC_ERR_POLICY; } @@ -1717,8 +1648,8 @@ kdc_check_flags(astgs_request_t r, char starttime_str[100]; krb5_format_time(r->context, *client->valid_start, starttime_str, sizeof(starttime_str), TRUE); - _kdc_audit_addreason((kdc_request_t)r, "Client not yet valid " - "until %s", starttime_str); + kdc_audit_addreason((kdc_request_t)r, "Client not yet valid " + "until %s", starttime_str); return KRB5KDC_ERR_CLIENT_NOTYET; } @@ -1726,49 +1657,47 @@ kdc_check_flags(astgs_request_t r, char endtime_str[100]; krb5_format_time(r->context, *client->valid_end, endtime_str, sizeof(endtime_str), TRUE); - _kdc_audit_addreason((kdc_request_t)r, "Client expired at %s", - endtime_str); + kdc_audit_addreason((kdc_request_t)r, "Client expired at %s", + endtime_str); return KRB5KDC_ERR_NAME_EXP; } if (client->flags.require_pwchange && - (server_ex == NULL || !server_ex->entry.flags.change_pw)) + (server == NULL || !server->flags.change_pw)) return KRB5KDC_ERR_KEY_EXPIRED; if (client->pw_end && *client->pw_end < kdc_time - && (server_ex == NULL || !server_ex->entry.flags.change_pw)) { + && (server == NULL || !server->flags.change_pw)) { char pwend_str[100]; krb5_format_time(r->context, *client->pw_end, pwend_str, sizeof(pwend_str), TRUE); - _kdc_audit_addreason((kdc_request_t)r, "Client's key has expired " - "at %s", pwend_str); + kdc_audit_addreason((kdc_request_t)r, "Client's key has expired " + "at %s", pwend_str); return KRB5KDC_ERR_KEY_EXPIRED; } } /* check server */ - if (server_ex != NULL) { - hdb_entry *server = &server_ex->entry; - + if (server != NULL) { if (server->flags.locked_out) { - _kdc_audit_addreason((kdc_request_t)r, "Server locked out"); + kdc_audit_addreason((kdc_request_t)r, "Server locked out"); return KRB5KDC_ERR_SERVICE_REVOKED; } if (server->flags.invalid) { - _kdc_audit_addreason((kdc_request_t)r, - "Server has invalid flag set"); + kdc_audit_addreason((kdc_request_t)r, + "Server has invalid flag set"); return KRB5KDC_ERR_POLICY; } if (!server->flags.server) { - _kdc_audit_addreason((kdc_request_t)r, - "Principal may not act as server"); + kdc_audit_addreason((kdc_request_t)r, + "Principal may not act as server"); return KRB5KDC_ERR_POLICY; } if (!is_as_req && server->flags.initial) { - _kdc_audit_addreason((kdc_request_t)r, - "AS-REQ is required for server"); + kdc_audit_addreason((kdc_request_t)r, + "AS-REQ is required for server"); return KRB5KDC_ERR_POLICY; } @@ -1776,8 +1705,8 @@ kdc_check_flags(astgs_request_t r, char starttime_str[100]; krb5_format_time(r->context, *server->valid_start, starttime_str, sizeof(starttime_str), TRUE); - _kdc_audit_addreason((kdc_request_t)r, "Server not yet valid " - "until %s", starttime_str); + kdc_audit_addreason((kdc_request_t)r, "Server not yet valid " + "until %s", starttime_str); return KRB5KDC_ERR_SERVICE_NOTYET; } @@ -1785,8 +1714,8 @@ kdc_check_flags(astgs_request_t r, char endtime_str[100]; krb5_format_time(r->context, *server->valid_end, endtime_str, sizeof(endtime_str), TRUE); - _kdc_audit_addreason((kdc_request_t)r, "Server expired at %s", - endtime_str); + kdc_audit_addreason((kdc_request_t)r, "Server expired at %s", + endtime_str); return KRB5KDC_ERR_SERVICE_EXP; } @@ -1794,8 +1723,8 @@ kdc_check_flags(astgs_request_t r, char pwend_str[100]; krb5_format_time(r->context, *server->pw_end, pwend_str, sizeof(pwend_str), TRUE); - _kdc_audit_addreason((kdc_request_t)r, "Server's key has expired " - "at %s", pwend_str); + kdc_audit_addreason((kdc_request_t)r, "Server's key has expired " + "at %s", pwend_str); return KRB5KDC_ERR_KEY_EXPIRED; } } @@ -1861,8 +1790,8 @@ krb5_error_code _kdc_check_anon_policy(astgs_request_t r) { if (!r->config->allow_anonymous) { - _kdc_audit_addreason((kdc_request_t)r, - "Anonymous tickets denied by local policy"); + kdc_audit_addreason((kdc_request_t)r, + "Anonymous tickets denied by local policy"); return KRB5KDC_ERR_POLICY; } @@ -1914,8 +1843,8 @@ generate_pac(astgs_request_t r, const Key *skey, const Key *tkey, krb5_const_principal canon_princ = NULL; r->pac_attributes = get_pac_attributes(r->context, &r->req); - _kdc_audit_addkv((kdc_request_t)r, 0, "pac_attributes", "%lx", - (long)r->pac_attributes); + kdc_audit_setkv_number((kdc_request_t)r, "pac_attributes", + r->pac_attributes); if (!is_tgs && !(r->pac_attributes & (KRB5_PAC_WAS_REQUESTED | KRB5_PAC_WAS_GIVEN_IMPLICITLY))) return 0; @@ -1928,6 +1857,7 @@ generate_pac(astgs_request_t r, const Key *skey, const Key *tkey, */ ret = _kdc_pac_generate(r->context, + r->config, r->client, r->server, r->pa_used && !pa_used_flag_isset(r, PA_USES_LONG_TERM_KEY) @@ -1942,7 +1872,7 @@ generate_pac(astgs_request_t r, const Key *skey, const Key *tkey, if (r->pac == NULL) return 0; - rodc_id = r->server->entry.kvno >> 16; + rodc_id = r->server->kvno >> 16; /* libkrb5 expects ticket and PAC client names to match */ ret = _krb5_principalname2krb5_principal(r->context, &client, @@ -1956,14 +1886,14 @@ generate_pac(astgs_request_t r, const Key *skey, const Key *tkey, * impersonate any realm. Windows always canonicalizes the realm, * but Heimdal permits aliases between realms.) */ - if (krb5_realm_compare(r->context, client, r->client->entry.principal)) { + if (krb5_realm_compare(r->context, client, r->canon_client_princ)) { char *cpn = NULL; - canon_princ = r->client->entry.principal; + canon_princ = r->canon_client_princ; - krb5_unparse_name(r->context, canon_princ, &cpn); - _kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s", - cpn ? cpn : ""); + (void) krb5_unparse_name(r->context, canon_princ, &cpn); + kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s", + cpn ? cpn : ""); krb5_xfree(cpn); } @@ -2027,8 +1957,8 @@ static int require_preauth_p(astgs_request_t r) { return r->config->require_preauth - || r->client->entry.flags.require_preauth - || r->server->entry.flags.require_preauth; + || r->client->flags.require_preauth + || r->server->flags.require_preauth; } @@ -2099,11 +2029,13 @@ static krb5_error_code get_local_tgs(krb5_context context, krb5_kdc_configuration *config, krb5_const_realm realm, - hdb_entry_ex **krbtgt) + HDB **krbtgtdb, + hdb_entry **krbtgt) { krb5_error_code ret; krb5_principal tgs_name; + *krbtgtdb = NULL; *krbtgt = NULL; ret = krb5_make_principal(context, @@ -2116,7 +2048,7 @@ get_local_tgs(krb5_context context, return ret; ret = _kdc_db_fetch(context, config, tgs_name, - HDB_F_GET_KRBTGT, NULL, NULL, krbtgt); + HDB_F_GET_KRBTGT, NULL, krbtgtdb, krbtgt); krb5_free_principal(context, tgs_name); return ret; @@ -2143,7 +2075,6 @@ _kdc_as_rep(astgs_request_t r) const PA_DATA *pa; krb5_boolean is_tgs; const char *msg; - hdb_entry_ex *krbtgt = NULL; Key *krbtgt_key; memset(rep, 0, sizeof(*rep)); @@ -2227,7 +2158,7 @@ _kdc_as_rep(astgs_request_t r) case HDB_ERR_WRONG_REALM: { char *fixed_client_name = NULL; - ret = krb5_unparse_name(r->context, r->client->entry.principal, + ret = krb5_unparse_name(r->context, r->client->principal, &fixed_client_name); if (ret) { goto out; @@ -2240,26 +2171,26 @@ _kdc_as_rep(astgs_request_t r) r->e_text = NULL; ret = _kdc_fast_mk_error(r, r->rep.padata, r->armor_crypto, &req->req_body, - r->ret = KRB5_KDC_ERR_WRONG_REALM, - r->client->entry.principal, r->server_princ, + r->error_code = KRB5_KDC_ERR_WRONG_REALM, + r->client->principal, r->server_princ, NULL, NULL, r->reply); goto out; } default: { - struct kdc_pa_auth_status auth_status = {HDB_AUTHSTATUS_CLIENT_UNKNOWN, NULL, NULL}; msg = krb5_get_error_message(r->context, ret); kdc_log(r->context, config, 4, "UNKNOWN -- %s: %s", r->cname, msg); krb5_free_error_message(r->context, msg); ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; - _kdc_audit_auth_status(r, &auth_status, NULL); + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_CLIENT_UNKNOWN); goto out; } } ret = _kdc_db_fetch(r->context, config, r->server_princ, HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags | (is_tgs ? HDB_F_GET_KRBTGT : 0), - NULL, NULL, &r->server); + NULL, &r->serverdb, &r->server); switch (ret) { case 0: /* Success */ break; @@ -2313,28 +2244,24 @@ _kdc_as_rep(astgs_request_t r) i = 0; pa = _kdc_find_padata(req, &i, pat[n].type); if (pa) { - struct kdc_pa_auth_status auth_status = {HDB_AUTHSTATUS_INVALID, NULL, NULL}; - - if (r->client->entry.flags.synthetic && + if (r->client->flags.synthetic && !(pat[n].flags & PA_SYNTHETIC_OK)) { kdc_log(r->context, config, 4, "UNKNOWN -- %s", r->cname); - ret = HDB_ERR_NOENTRY; + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; goto out; } - _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_VIS, "pa", "%s", - pat[n].name); - ret = pat[n].validate(r, pa, &auth_status); + kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_VIS, "pa", "%s", + pat[n].name); + ret = pat[n].validate(r, pa); if (ret != 0) { krb5_error_code ret2; Key *ckey = NULL; krb5_boolean default_salt; - if (auth_status.auth_status == HDB_AUTHSTATUS_INVALID) - auth_status.auth_status = HDB_AUTHSTATUS_GENERIC_FAILURE; - _kdc_audit_auth_status(r, - &auth_status, - pat[n].name); - free(auth_status.free_ptr); + if (ret != KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED && + !kdc_audit_getkv((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT)) + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_PREAUTH_FAILED); /* * If there is a client key, send ETYPE_INFO{,2} @@ -2350,17 +2277,14 @@ _kdc_as_rep(astgs_request_t r) } goto out; } + if (!kdc_audit_getkv((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT)) + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_PREAUTH_SUCCEEDED); kdc_log(r->context, config, 4, "%s pre-authentication succeeded -- %s", pat[n].name, r->cname); found_pa = 1; r->pa_used = &pat[n]; - - if (auth_status.auth_status == HDB_AUTHSTATUS_INVALID) - auth_status.auth_status = HDB_AUTHSTATUS_GENERIC_SUCCESS; - - _kdc_audit_auth_status(r, &auth_status, r->pa_used->name); - free(auth_status.free_ptr); r->et.flags.pre_authent = 1; } } @@ -2371,9 +2295,9 @@ _kdc_as_rep(astgs_request_t r) size_t n; krb5_boolean default_salt; - if (r->client->entry.flags.synthetic) { + if (r->client->flags.synthetic) { kdc_log(r->context, config, 4, "UNKNOWN -- %s", r->cname); - ret = HDB_ERR_NOENTRY; + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; goto out; } @@ -2430,6 +2354,8 @@ _kdc_as_rep(astgs_request_t r) goto out; } + r->canon_client_princ = r->client->principal; + /* * Verify flags after the user been required to prove its identity * with in a preauth mech. @@ -2449,14 +2375,8 @@ _kdc_as_rep(astgs_request_t r) r->et.flags.anonymous = 1; } - { - struct kdc_pa_auth_status auth_status - = {HDB_AUTHSTATUS_AUTHORIZATION_SUCCESS, - NULL, - NULL}; - - _kdc_audit_auth_status(r, &auth_status, NULL); - } + kdc_audit_setkv_number((kdc_request_t)r, KDC_REQUEST_KV_AUTH_EVENT, + KDC_AUTH_EVENT_CLIENT_AUTHORIZED); /* * Select the best encryption type for the KDC with out regard to @@ -2474,11 +2394,11 @@ _kdc_as_rep(astgs_request_t r) krbtgt_key = skey; } else { ret = get_local_tgs(r->context, config, r->server_princ->realm, - &krbtgt); + &r->krbtgtdb, &r->krbtgt); if (ret) goto out; - ret = _kdc_get_preferred_key(r->context, config, krbtgt, + ret = _kdc_get_preferred_key(r->context, config, r->krbtgt, r->server_princ->realm, NULL, &krbtgt_key); if (ret) @@ -2501,31 +2421,31 @@ _kdc_as_rep(astgs_request_t r) _kdc_is_anonymous(r->context, r->client_princ)) { Realm anon_realm = KRB5_ANON_REALM; ret = copy_Realm(&anon_realm, &rep->crealm); - } else if (f.canonicalize || r->client->entry.flags.force_canonicalize) - ret = copy_Realm(&r->client->entry.principal->realm, &rep->crealm); + } else if (f.canonicalize || r->client->flags.force_canonicalize) + ret = copy_Realm(&r->canon_client_princ->realm, &rep->crealm); else ret = copy_Realm(&r->client_princ->realm, &rep->crealm); if (ret) goto out; if (r->et.flags.anonymous) ret = _kdc_make_anonymous_principalname(&rep->cname); - else if (f.canonicalize || r->client->entry.flags.force_canonicalize) - ret = _krb5_principal2principalname(&rep->cname, r->client->entry.principal); + else if (f.canonicalize || r->client->flags.force_canonicalize) + ret = _krb5_principal2principalname(&rep->cname, r->canon_client_princ); else ret = _krb5_principal2principalname(&rep->cname, r->client_princ); if (ret) goto out; rep->ticket.tkt_vno = 5; - if (f.canonicalize || r->server->entry.flags.force_canonicalize) - ret = copy_Realm(&r->server->entry.principal->realm, &rep->ticket.realm); + if (f.canonicalize || r->server->flags.force_canonicalize) + ret = copy_Realm(&r->server->principal->realm, &rep->ticket.realm); else ret = copy_Realm(&r->server_princ->realm, &rep->ticket.realm); if (ret) goto out; - if (f.canonicalize || r->server->entry.flags.force_canonicalize) + if (f.canonicalize || r->server->flags.force_canonicalize) _krb5_principal2principalname(&rep->ticket.sname, - r->server->entry.principal); + r->server->principal); else _krb5_principal2principalname(&rep->ticket.sname, r->server_princ); @@ -2540,16 +2460,16 @@ _kdc_as_rep(astgs_request_t r) #undef CNT r->et.flags.initial = 1; - if(r->client->entry.flags.forwardable && r->server->entry.flags.forwardable) + if(r->client->flags.forwardable && r->server->flags.forwardable) r->et.flags.forwardable = f.forwardable; - if(r->client->entry.flags.proxiable && r->server->entry.flags.proxiable) + if(r->client->flags.proxiable && r->server->flags.proxiable) r->et.flags.proxiable = f.proxiable; else if (f.proxiable) { _kdc_set_e_text(r, "Ticket may not be proxiable"); ret = KRB5KDC_ERR_POLICY; goto out; } - if(r->client->entry.flags.postdate && r->server->entry.flags.postdate) + if(r->client->flags.postdate && r->server->flags.postdate) r->et.flags.may_postdate = f.allow_postdate; else if (f.allow_postdate){ _kdc_set_e_text(r, "Ticket may not be postdate"); @@ -2558,12 +2478,12 @@ _kdc_as_rep(astgs_request_t r) } if (b->addresses) - _kdc_audit_addaddrs((kdc_request_t)r, b->addresses, "reqaddrs"); + kdc_audit_addaddrs((kdc_request_t)r, b->addresses, "reqaddrs"); /* check for valid set of addresses */ if (!_kdc_check_addresses(r, b->addresses, r->addr)) { if (r->config->warn_ticket_addresses) { - _kdc_audit_addkv((kdc_request_t)r, 0, "wrongaddr", "yes"); + kdc_audit_setkv_bool((kdc_request_t)r, "wrongaddr", TRUE); } else { _kdc_set_e_text(r, "Request from wrong address"); ret = KRB5KRB_AP_ERR_BADADDR; @@ -2596,24 +2516,26 @@ _kdc_as_rep(astgs_request_t r) /* be careful not overflowing */ /* - * Pre-auth can override r->client->entry.max_life if configured. + * Pre-auth can override r->client->max_life if configured. * * See pre-auth methods, specifically PKINIT, which can get or derive * this from the client's certificate. */ if (r->pa_max_life > 0) - t = start + min(t - start, r->pa_max_life); - else if (r->client->entry.max_life) - t = start + min(t - start, *r->client->entry.max_life); + t = rk_time_add(start, min(rk_time_sub(t, start), r->pa_max_life)); + else if (r->client->max_life && *r->client->max_life) + t = rk_time_add(start, min(rk_time_sub(t, start), + *r->client->max_life)); - if (r->server->entry.max_life) - t = start + min(t - start, *r->server->entry.max_life); + if (r->server->max_life && *r->server->max_life) + t = rk_time_add(start, min(rk_time_sub(t, start), + *r->server->max_life)); /* Pre-auth can bound endtime as well */ if (r->pa_endtime > 0) - t = start + min(t - start, r->pa_endtime); + t = rk_time_add(start, min(rk_time_sub(t, start), r->pa_endtime)); #if 0 - t = min(t, start + realm->max_life); + t = min(t, rk_time_add(start, realm->max_life)); #endif r->et.endtime = t; if(f.renewable_ok && r->et.endtime < *b->till){ @@ -2629,12 +2551,14 @@ _kdc_as_rep(astgs_request_t r) t = *b->rtime; if(t == 0) t = MAX_TIME; - if(r->client->entry.max_renew) - t = start + min(t - start, *r->client->entry.max_renew); - if(r->server->entry.max_renew) - t = start + min(t - start, *r->server->entry.max_renew); + if(r->client->max_renew && *r->client->max_renew) + t = rk_time_add(start, min(rk_time_sub(t, start), + *r->client->max_renew)); + if(r->server->max_renew && *r->server->max_renew) + t = rk_time_add(start, min(rk_time_sub(t, start), + *r->server->max_renew)); #if 0 - t = min(t, start + realm->max_renew); + t = min(t, rk_time_add(start, realm->max_renew)); #endif ALLOC(r->et.renew_till); *r->et.renew_till = t; @@ -2665,16 +2589,16 @@ _kdc_as_rep(astgs_request_t r) goto out; } r->ek.last_req.len = 0; - if (r->client->entry.pw_end + if (r->client->pw_end && (config->kdc_warn_pwexpire == 0 - || kdc_time + config->kdc_warn_pwexpire >= *r->client->entry.pw_end)) { + || kdc_time + config->kdc_warn_pwexpire >= *r->client->pw_end)) { r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_PW_EXPTIME; - r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->entry.pw_end; + r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->pw_end; ++r->ek.last_req.len; } - if (r->client->entry.valid_end) { + if (r->client->valid_end) { r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_ACCT_EXPTIME; - r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->entry.valid_end; + r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->valid_end; ++r->ek.last_req.len; } if (r->ek.last_req.len == 0) { @@ -2683,16 +2607,16 @@ _kdc_as_rep(astgs_request_t r) ++r->ek.last_req.len; } r->ek.nonce = b->nonce; - if (r->client->entry.valid_end || r->client->entry.pw_end) { + if (r->client->valid_end || r->client->pw_end) { ALLOC(r->ek.key_expiration); - if (r->client->entry.valid_end) { - if (r->client->entry.pw_end) - *r->ek.key_expiration = min(*r->client->entry.valid_end, - *r->client->entry.pw_end); + if (r->client->valid_end) { + if (r->client->pw_end) + *r->ek.key_expiration = min(*r->client->valid_end, + *r->client->pw_end); else - *r->ek.key_expiration = *r->client->entry.valid_end; + *r->ek.key_expiration = *r->client->valid_end; } else - *r->ek.key_expiration = *r->client->entry.pw_end; + *r->ek.key_expiration = *r->client->pw_end; } else r->ek.key_expiration = NULL; r->ek.flags = r->et.flags; @@ -2746,7 +2670,7 @@ _kdc_as_rep(astgs_request_t r) generate_pac(r, skey, krbtgt_key, is_tgs); } - if (r->client->entry.flags.synthetic) { + if (r->client->flags.synthetic) { ret = add_synthetic_princ_ad(r); if (ret) goto out; @@ -2803,8 +2727,8 @@ _kdc_as_rep(astgs_request_t r) ret = _kdc_encode_reply(r->context, config, r, req->req_body.nonce, setype, - r->server->entry.kvno, &skey->key, - pa_used_flag_isset(r, PA_REPLACE_REPLY_KEY) ? 0 : r->client->entry.kvno, + r->server->kvno, &skey->key, + pa_used_flag_isset(r, PA_REPLACE_REPLY_KEY) ? 0 : r->client->kvno, 0, r->reply); if (ret) goto out; @@ -2819,6 +2743,9 @@ _kdc_as_rep(astgs_request_t r) } out: + r->error_code = ret; + _kdc_audit_request(r); + /* * In case of a non proxy error, build an error message. */ @@ -2827,7 +2754,7 @@ out: r->rep.padata, r->armor_crypto, &req->req_body, - r->ret = ret, + r->error_code, r->client_princ, r->server_princ, NULL, NULL, @@ -2850,11 +2777,11 @@ out: r->server_princ = NULL; } if (r->client) - _kdc_free_ent(r->context, r->client); + _kdc_free_ent(r->context, r->clientdb, r->client); if (r->server) - _kdc_free_ent(r->context, r->server); - if (krbtgt) - _kdc_free_ent(r->context, krbtgt); + _kdc_free_ent(r->context, r->serverdb, r->server); + if (r->krbtgt) + _kdc_free_ent(r->context, r->krbtgtdb, r->krbtgt); if (r->armor_crypto) { krb5_crypto_destroy(r->context, r->armor_crypto); r->armor_crypto = NULL; @@ -2862,7 +2789,7 @@ out: if (r->armor_ticket) krb5_free_ticket(r->context, r->armor_ticket); if (r->armor_server) - _kdc_free_ent(r->context, r->armor_server); + _kdc_free_ent(r->context, r->armor_serverdb, r->armor_server); krb5_free_keyblock_contents(r->context, &r->reply_key); krb5_free_keyblock_contents(r->context, &r->session_key); krb5_free_keyblock_contents(r->context, &r->strengthen_key); diff --git a/third_party/heimdal/kdc/krb5tgs.c b/third_party/heimdal/kdc/krb5tgs.c index c9878dd6af52..39d42106e01e 100644 --- a/third_party/heimdal/kdc/krb5tgs.c +++ b/third_party/heimdal/kdc/krb5tgs.c @@ -80,10 +80,10 @@ _kdc_check_pac(krb5_context context, krb5_kdc_configuration *config, const krb5_principal client_principal, const krb5_principal delegated_proxy_principal, - hdb_entry_ex *client, - hdb_entry_ex *server, - hdb_entry_ex *krbtgt, - hdb_entry_ex *ticket_server, + hdb_entry *client, + hdb_entry *server, + hdb_entry *krbtgt, + hdb_entry *ticket_server, const EncryptionKey *server_check_key, const EncryptionKey *krbtgt_check_key, EncTicketPart *tkt, @@ -139,7 +139,8 @@ _kdc_check_pac(krb5_context context, } /* Verify the KDC signatures. */ - ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal, + ret = _kdc_pac_verify(context, config, + client_principal, delegated_proxy_principal, client, server, krbtgt, &pac); if (ret == 0) { if (pac == NULL) { @@ -151,8 +152,8 @@ _kdc_check_pac(krb5_context context, * We can't verify the KDC signatures if the ticket was issued by * another realm's KDC. */ - if (krb5_realm_compare(context, server->entry.principal, - ticket_server->entry.principal)) { + if (krb5_realm_compare(context, server->principal, + ticket_server->principal)) { ret = krb5_pac_verify(context, pac, 0, NULL, NULL, krbtgt_check_key); if (ret) { @@ -173,7 +174,7 @@ _kdc_check_pac(krb5_context context, *kdc_issued = signedticket || krb5_principal_is_krbtgt(context, - ticket_server->entry.principal); + ticket_server->principal); *ppac = pac; return 0; @@ -210,35 +211,35 @@ check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b, if(f.validate){ if (!tgt->flags.invalid || tgt->starttime == NULL) { - _kdc_audit_addreason((kdc_request_t)r, - "Bad request to validate ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Bad request to validate ticket"); return KRB5KDC_ERR_BADOPTION; } if(*tgt->starttime > kdc_time){ - _kdc_audit_addreason((kdc_request_t)r, - "Early request to validate ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Early request to validate ticket"); return KRB5KRB_AP_ERR_TKT_NYV; } /* XXX tkt = tgt */ et->flags.invalid = 0; } else if (tgt->flags.invalid) { - _kdc_audit_addreason((kdc_request_t)r, - "Ticket-granting ticket has INVALID flag set"); + kdc_audit_addreason((kdc_request_t)r, + "Ticket-granting ticket has INVALID flag set"); return KRB5KRB_AP_ERR_TKT_INVALID; } if(f.forwardable){ if (!tgt->flags.forwardable) { - _kdc_audit_addreason((kdc_request_t)r, - "Bad request for forwardable ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Bad request for forwardable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.forwardable = 1; } if(f.forwarded){ if (!tgt->flags.forwardable) { - _kdc_audit_addreason((kdc_request_t)r, - "Request to forward non-forwardable ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Request to forward non-forwardable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.forwarded = 1; @@ -249,16 +250,16 @@ check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b, if(f.proxiable){ if (!tgt->flags.proxiable) { - _kdc_audit_addreason((kdc_request_t)r, - "Bad request for proxiable ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Bad request for proxiable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.proxiable = 1; } if(f.proxy){ if (!tgt->flags.proxiable) { - _kdc_audit_addreason((kdc_request_t)r, - "Request to proxy non-proxiable ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Request to proxy non-proxiable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.proxy = 1; @@ -269,16 +270,16 @@ check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b, if(f.allow_postdate){ if (!tgt->flags.may_postdate) { - _kdc_audit_addreason((kdc_request_t)r, - "Bad request for post-datable ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Bad request for post-datable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.may_postdate = 1; } if(f.postdated){ if (!tgt->flags.may_postdate) { - _kdc_audit_addreason((kdc_request_t)r, - "Bad request for postdated ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Bad request for postdated ticket"); return KRB5KDC_ERR_BADOPTION; } if(b->from) @@ -286,15 +287,15 @@ check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b, et->flags.postdated = 1; et->flags.invalid = 1; } else if (b->from && *b->from > kdc_time + r->context->max_skew) { - _kdc_audit_addreason((kdc_request_t)r, - "Ticket cannot be postdated"); + kdc_audit_addreason((kdc_request_t)r, + "Ticket cannot be postdated"); return KRB5KDC_ERR_CANNOT_POSTDATE; } if(f.renewable){ if (!tgt->flags.renewable || tgt->renew_till == NULL) { - _kdc_audit_addreason((kdc_request_t)r, - "Bad request for renewable ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Bad request for renewable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.renewable = 1; @@ -305,8 +306,8 @@ check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b, if(f.renew){ time_t old_life; if (!tgt->flags.renewable || tgt->renew_till == NULL) { - _kdc_audit_addreason((kdc_request_t)r, - "Request to renew non-renewable ticket"); + kdc_audit_addreason((kdc_request_t)r, + "Request to renew non-renewable ticket"); return KRB5KDC_ERR_BADOPTION; } old_life = tgt->endtime; @@ -325,8 +326,8 @@ check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b, */ if (tgt->flags.anonymous && !_kdc_is_anonymous(r->context, tgt_name)) { - _kdc_audit_addreason((kdc_request_t)r, - "Anonymous ticket flag set without " + kdc_audit_addreason((kdc_request_t)r, + "Anonymous ticket flag set without " "anonymous principal"); return KRB5KDC_ERR_BADOPTION; } @@ -342,63 +343,6 @@ check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b, return 0; } -/* - * Determine if constrained delegation is allowed from this client to this server - */ - -static krb5_error_code -check_constrained_delegation(krb5_context context, - krb5_kdc_configuration *config, - HDB *clientdb, - hdb_entry_ex *client, - hdb_entry_ex *server, - krb5_const_principal target) -{ - const HDB_Ext_Constrained_delegation_acl *acl; - krb5_error_code ret; - size_t i; - - /* - * constrained_delegation (S4U2Proxy) only works within - * the same realm. We use the already canonicalized version - * of the principals here, while "target" is the principal - * provided by the client. - */ - if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) { - ret = KRB5KDC_ERR_BADOPTION; - kdc_log(context, config, 4, - "Bad request for constrained delegation"); - return ret; - } - - if (clientdb->hdb_check_constrained_delegation) { - ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target); - if (ret == 0) - return 0; - } else { - /* if client delegates to itself, that ok */ - if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE) - return 0; - - ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl); - if (ret) { - krb5_clear_error_message(context); - return ret; - } - - if (acl) { - for (i = 0; i < acl->len; i++) { - if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE) - return 0; - } - } - ret = KRB5KDC_ERR_BADOPTION; - } - kdc_log(context, config, 4, - "Bad request for constrained delegation"); - return ret; -} - /* * Determine if s4u2self is allowed from this client to this server * @@ -412,13 +356,13 @@ check_constrained_delegation(krb5_context context, * alias of client, then it's safe. */ -static krb5_error_code -check_client_matches_target_service(krb5_context context, - krb5_kdc_configuration *config, - HDB *clientdb, - hdb_entry_ex *client, - hdb_entry_ex *target_server, - krb5_const_principal target_server_principal) +krb5_error_code +_kdc_check_client_matches_target_service(krb5_context context, + krb5_kdc_configuration *config, + HDB *clientdb, + hdb_entry *client, + hdb_entry *target_server, + krb5_const_principal target_server_principal) { krb5_error_code ret; @@ -435,7 +379,7 @@ check_client_matches_target_service(krb5_context context, if (ret == 0) return 0; } else if (krb5_principal_compare(context, - client->entry.principal, + client->principal, target_server_principal) == TRUE) { /* if client does a s4u2self to itself, and there is no plugin, that is ok */ return 0; @@ -587,17 +531,12 @@ fix_transited_encoding(krb5_context context, static krb5_error_code tgs_make_reply(astgs_request_t r, - krb5_principal tgt_name, const EncTicketPart *tgt, const EncryptionKey *serverkey, const EncryptionKey *krbtgtkey, const krb5_keyblock *sessionkey, krb5_kvno kvno, AuthorizationData *auth_data, - hdb_entry_ex *server, - krb5_principal server_principal, - hdb_entry_ex *client, - krb5_principal client_principal, const char *tgt_realm, uint16_t rodc_id, krb5_boolean add_ticket_sig) @@ -611,6 +550,8 @@ tgs_make_reply(astgs_request_t r, krb5_error_code ret; int is_weak = 0; + heim_assert(r->client_princ != NULL, "invalid client name passed to tgs_make_reply"); + rep->pvno = 5; rep->msg_type = krb_tgs_rep; @@ -620,7 +561,7 @@ tgs_make_reply(astgs_request_t r, ALLOC(et->starttime); *et->starttime = kdc_time; - ret = check_tgs_flags(r, b, tgt_name, tgt, et); + ret = check_tgs_flags(r, b, r->client_princ, tgt, et); if(ret) goto out; @@ -646,24 +587,39 @@ tgs_make_reply(astgs_request_t r, ret = fix_transited_encoding(r->context, r->config, !f.disable_transited_check || GLOBAL_FORCE_TRANSITED_CHECK || - PRINCIPAL_FORCE_TRANSITED_CHECK(server) || + PRINCIPAL_FORCE_TRANSITED_CHECK(r->server) || !((GLOBAL_ALLOW_PER_PRINCIPAL && - PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) || + PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(r->server)) || GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), &tgt->transited, et, - krb5_principal_get_realm(r->context, client_principal), - krb5_principal_get_realm(r->context, server->entry.principal), + krb5_principal_get_realm(r->context, r->client_princ), + krb5_principal_get_realm(r->context, r->server->principal), tgt_realm); - if(ret) - goto out; - ret = copy_Realm(&server_principal->realm, &rep->ticket.realm); - if (ret) - goto out; - _krb5_principal2principalname(&rep->ticket.sname, server_principal); - ret = copy_Realm(&tgt_name->realm, &rep->crealm); + { + /* + * RFC 6806 notes that names MUST NOT be changed in the response to a + * TGS request. Hence we ignore the setting of the canonicalize KDC + * option. However, for legacy interoperability we do allow the backend + * to override this by setting the force-canonicalize HDB flag in the + * server entry. + */ + krb5_const_principal rsp; + + if (r->server->flags.force_canonicalize) + rsp = r->server->principal; + else + rsp = r->server_princ; + if (ret == 0) + ret = copy_Realm(&rsp->realm, &rep->ticket.realm); + if (ret == 0) + ret = _krb5_principal2principalname(&rep->ticket.sname, rsp); + } + + if (ret == 0) + ret = copy_Realm(&r->client_princ->realm, &rep->crealm); if (ret) - goto out; + goto out; /* * RFC 8062 states "if the ticket in the TGS request is an anonymous @@ -674,7 +630,7 @@ tgs_make_reply(astgs_request_t r, if (et->flags.anonymous && !tgt->flags.anonymous) _kdc_make_anonymous_principalname(&rep->cname); else - ret = copy_PrincipalName(&tgt_name->name, &rep->cname); + ret = copy_PrincipalName(&r->client_princ->name, &rep->cname); if (ret) goto out; rep->ticket.tkt_vno = 5; @@ -684,10 +640,10 @@ tgs_make_reply(astgs_request_t r, { time_t life; life = et->endtime - *et->starttime; - if(client && client->entry.max_life) - life = min(life, *client->entry.max_life); - if(server->entry.max_life) - life = min(life, *server->entry.max_life); + if(r->client && r->client->max_life) + life = min(life, *r->client->max_life); + if(r->server->max_life) + life = min(life, *r->server->max_life); et->endtime = *et->starttime + life; } if(f.renewable_ok && tgt->flags.renewable && @@ -701,10 +657,10 @@ tgs_make_reply(astgs_request_t r, if(et->renew_till){ time_t renew; renew = *et->renew_till - *et->starttime; - if(client && client->entry.max_renew) - renew = min(renew, *client->entry.max_renew); - if(server->entry.max_renew) - renew = min(renew, *server->entry.max_renew); + if(r->client && r->client->max_renew) + renew = min(renew, *r->client->max_renew); + if(r->server->max_renew) + renew = min(renew, *r->server->max_renew); *et->renew_till = *et->starttime + renew; } @@ -728,12 +684,12 @@ tgs_make_reply(astgs_request_t r, et->flags.pre_authent = tgt->flags.pre_authent; et->flags.hw_authent = tgt->flags.hw_authent; - et->flags.ok_as_delegate = server->entry.flags.ok_as_delegate; + et->flags.ok_as_delegate = r->server->flags.ok_as_delegate; /* See MS-KILE 3.3.5.1 */ - if (!server->entry.flags.forwardable) + if (!r->server->flags.forwardable) et->flags.forwardable = 0; - if (!server->entry.flags.proxiable) + if (!r->server->flags.proxiable) et->flags.proxiable = 0; if (auth_data) { @@ -785,18 +741,18 @@ tgs_make_reply(astgs_request_t r, et->endtime, et->renew_till); if (krb5_enctype_valid(r->context, serverkey->keytype) != 0 - && _kdc_is_weak_exception(server->entry.principal, serverkey->keytype)) + && _kdc_is_weak_exception(r->server->principal, serverkey->keytype)) { krb5_enctype_enable(r->context, serverkey->keytype); is_weak = 1; } - if (r->client_princ) { + if (r->canon_client_princ) { char *cpn; - krb5_unparse_name(r->context, r->client_princ, &cpn); - _kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s", - cpn ? cpn : ""); + (void) krb5_unparse_name(r->context, r->canon_client_princ, &cpn); + kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s", + cpn ? cpn : ""); krb5_xfree(cpn); } @@ -807,8 +763,8 @@ tgs_make_reply(astgs_request_t r, * is implementation dependent. */ if (r->pac && !et->flags.anonymous) { - _kdc_audit_addkv((kdc_request_t)r, 0, "pac_attributes", "%lx", - (long)r->pac_attributes); + kdc_audit_setkv_number((kdc_request_t)r, "pac_attributes", + r->pac_attributes); /* * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES @@ -817,10 +773,10 @@ tgs_make_reply(astgs_request_t r, */ if (_kdc_include_pac_p(r)) { krb5_boolean is_tgs = - krb5_principal_is_krbtgt(r->context, server->entry.principal); + krb5_principal_is_krbtgt(r->context, r->server->principal); - ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, tgt_name, serverkey, - krbtgtkey, rodc_id, NULL, r->client_princ, + ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, r->client_princ, serverkey, + krbtgtkey, rodc_id, NULL, r->canon_client_princ, add_ticket_sig, et, is_tgs ? &r->pac_attributes : NULL); if (ret) @@ -865,7 +821,12 @@ tgs_check_authenticator(krb5_context context, krb5_error_code ret; krb5_crypto crypto; - krb5_auth_con_getauthenticator(context, ac, &auth); + ret = krb5_auth_con_getauthenticator(context, ac, &auth); + if (ret) { + kdc_log(context, config, 2, + "Out of memory checking PA-TGS Authenticator"); + goto out; + } if(auth->cksum == NULL){ kdc_log(context, config, 4, "No authenticator in request"); ret = KRB5KRB_AP_ERR_INAPP_CKSUM; @@ -922,23 +883,7 @@ need_referral(krb5_context context, krb5_kdc_configuration *config, if (server->name.name_string.len == 1) name = server->name.name_string.val[0]; - else if (server->name.name_string.len == 3) { - /* - This is used to give referrals for the - E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN - SPN form, which is used for inter-domain communication in AD - */ - name = server->name.name_string.val[2]; - kdc_log(context, config, 4, "Giving 3 part referral for %s", name); - *realms = malloc(sizeof(char *)*2); - if (*realms == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return FALSE; - } - (*realms)[0] = strdup(name); - (*realms)[1] = NULL; - return TRUE; - } else 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; @@ -978,9 +923,7 @@ validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data) static krb5_error_code tgs_parse_request(astgs_request_t r, const PA_DATA *tgs_req, - hdb_entry_ex **krbtgt, krb5_enctype *krbtgt_etype, - krb5_ticket **ticket, const char *from, const struct sockaddr *from_addr, time_t **csec, @@ -1032,7 +975,7 @@ tgs_parse_request(astgs_request_t r, krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0; ret = _kdc_db_fetch(r->context, config, princ, HDB_F_GET_KRBTGT, - &krbtgt_kvno, NULL, krbtgt); + &krbtgt_kvno, &r->krbtgtdb, &r->krbtgt); if (ret == HDB_ERR_NOT_FOUND_HERE) { /* XXX Factor out this unparsing of the same princ all over */ @@ -1090,12 +1033,12 @@ tgs_parse_request(astgs_request_t r, goto out; } - krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno; + krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : r->krbtgt->kvno; *krbtgt_etype = ap_req.ticket.enc_part.etype; next_kvno: - krbtgt_keys = hdb_kvno2keys(r->context, &(*krbtgt)->entry, krbtgt_kvno_try); - ret = hdb_enctype2key(r->context, &(*krbtgt)->entry, krbtgt_keys, + krbtgt_keys = hdb_kvno2keys(r->context, r->krbtgt, krbtgt_kvno_try); + ret = hdb_enctype2key(r->context, r->krbtgt, krbtgt_keys, ap_req.ticket.enc_part.etype, &tkey); if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) { kvno_search_tries--; @@ -1129,13 +1072,13 @@ next_kvno: &tkey->key, verify_ap_req_flags, &ap_req_options, - ticket, + &r->ticket, KRB5_KU_TGS_REQ_AUTH); - if (*ticket && (*ticket)->ticket.caddr) - _kdc_audit_addaddrs((kdc_request_t)r, (*ticket)->ticket.caddr, "tixaddrs"); + if (r->ticket && r->ticket->ticket.caddr) + kdc_audit_addaddrs((kdc_request_t)r, r->ticket->ticket.caddr, "tixaddrs"); if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR && - *ticket != NULL) { - _kdc_audit_addkv((kdc_request_t)r, 0, "wrongaddr", "yes"); + r->ticket != NULL) { + kdc_audit_setkv_bool((kdc_request_t)r, "wrongaddr", TRUE); ret = 0; } if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) { @@ -1181,8 +1124,7 @@ next_kvno: } } - ret = tgs_check_authenticator(r->context, config, ac, b, - &(*ticket)->ticket.key); + ret = tgs_check_authenticator(r->context, config, ac, b, &r->ticket->ticket.key); if (ret) { krb5_auth_con_free(r->context, ac); goto out; @@ -1267,7 +1209,7 @@ next_kvno: } } - ret = validate_fast_ad(r, (*ticket)->ticket.authorization_data); + ret = validate_fast_ad(r, r->ticket->ticket.authorization_data); if (ret) goto out; @@ -1276,7 +1218,7 @@ next_kvno: * Check for FAST request */ - ret = _kdc_fast_unwrap_request(r, *ticket, ac); + ret = _kdc_fast_unwrap_request(r, r->ticket, ac); if (ret) goto out; @@ -1376,10 +1318,10 @@ _kdc_db_fetch_client(krb5_context context, const char *cpn, const char *krbtgt_realm, HDB **clientdb, - hdb_entry_ex **client_out) + hdb_entry **client_out) { krb5_error_code ret; - hdb_entry_ex *client = NULL; + hdb_entry *client = NULL; *client_out = NULL; @@ -1408,9 +1350,9 @@ _kdc_db_fetch_client(krb5_context context, msg = krb5_get_error_message(context, ret); kdc_log(context, config, 4, "Client not found in database: %s", msg); krb5_free_error_message(context, msg); - } else if (client->entry.flags.invalid || !client->entry.flags.client) { + } else if (client->flags.invalid || !client->flags.client) { kdc_log(context, config, 4, "Client has invalid bit set"); - _kdc_free_ent(context, client); + _kdc_free_ent(context, *clientdb, client); return KRB5KDC_ERR_POLICY; } @@ -1421,29 +1363,25 @@ _kdc_db_fetch_client(krb5_context context, static krb5_error_code tgs_build_reply(astgs_request_t priv, - hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, - krb5_ticket *ticket, AuthorizationData **auth_data, const struct sockaddr *from_addr) { krb5_context context = priv->context; krb5_kdc_configuration *config = priv->config; - KDC_REQ *req = &priv->req; KDC_REQ_BODY *b = &priv->req.req_body; const char *from = priv->from; krb5_error_code ret, ret2; - krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL; krb5_principal krbtgt_out_principal = NULL; krb5_principal user2user_princ = NULL; - char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL; + char *spn = NULL, *cpn = NULL, *krbtgt_out_n = NULL; char *user2user_name = NULL; - hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL; - hdb_entry_ex *user2user_krbtgt = NULL; - HDB *clientdb, *s4u2self_impersonated_clientdb; + HDB *user2user_krbtgtdb; + hdb_entry *user2user_krbtgt = NULL; + HDB *clientdb; HDB *serverdb = NULL; krb5_realm ref_realm = NULL; - EncTicketPart *tgt = &ticket->ticket; + EncTicketPart *tgt = &priv->ticket->ticket; const EncryptionKey *ekey; krb5_keyblock sessionkey; krb5_kvno kvno; @@ -1451,13 +1389,14 @@ tgs_build_reply(astgs_request_t priv, uint16_t rodc_id; krb5_boolean add_ticket_sig = FALSE; const char *tgt_realm = /* Realm of TGT issuer */ - krb5_principal_get_realm(context, krbtgt->entry.principal); + krb5_principal_get_realm(context, priv->krbtgt->principal); const char *our_realm = /* Realm of this KDC */ - krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1); + krb5_principal_get_comp_string(context, priv->krbtgt->principal, 1); char **capath = NULL; size_t num_capath = 0; - hdb_entry_ex *krbtgt_out = NULL; + HDB *krbtgt_outdb; + hdb_entry *krbtgt_out = NULL; PrincipalName *s; Realm r; @@ -1491,13 +1430,14 @@ tgs_build_reply(astgs_request_t priv, goto out; } - _krb5_principalname2krb5_principal(context, &sp, *s, r); - ret = krb5_unparse_name(context, sp, &priv->sname); + _krb5_principalname2krb5_principal(context, &priv->server_princ, *s, r); + ret = krb5_unparse_name(context, priv->server_princ, &priv->sname); if (ret) goto out; spn = priv->sname; - _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm); - ret = krb5_unparse_name(context, cp, &priv->cname); + _krb5_principalname2krb5_principal(context, &priv->client_princ, + tgt->cname, tgt->crealm); + ret = krb5_unparse_name(context, priv->client_princ, &priv->cname); if (ret) goto out; cpn = priv->cname; @@ -1517,21 +1457,20 @@ tgs_build_reply(astgs_request_t priv, */ server_lookup: + if (priv->server) + _kdc_free_ent(context, serverdb, priv->server); priv->server = NULL; - if (server) - _kdc_free_ent(context, server); - server = NULL; - ret = _kdc_db_fetch(context, config, sp, + ret = _kdc_db_fetch(context, config, priv->server_princ, HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags, - NULL, &serverdb, &server); - priv->server = server; + NULL, &serverdb, &priv->server); + priv->serverdb = serverdb; if (ret == HDB_ERR_NOT_FOUND_HERE) { kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn); - _kdc_audit_addreason((kdc_request_t)priv, "Target not found here"); + kdc_audit_addreason((kdc_request_t)priv, "Target not found here"); goto out; } else if (ret == HDB_ERR_WRONG_REALM) { free(ref_realm); - ref_realm = strdup(server->entry.principal->realm); + ref_realm = strdup(priv->server->principal->realm); if (ref_realm == NULL) { ret = krb5_enomem(context); goto out; @@ -1541,15 +1480,15 @@ server_lookup: "Returning a referral to realm %s for " "server %s.", ref_realm, spn); - krb5_free_principal(context, sp); - sp = NULL; - ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, + krb5_free_principal(context, priv->server_princ); + priv->server_princ = NULL; + ret = krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME, ref_realm, NULL); if (ret) goto out; free(priv->sname); priv->sname = NULL; - ret = krb5_unparse_name(context, sp, &priv->sname); + ret = krb5_unparse_name(context, priv->server_princ, &priv->sname); if (ret) goto out; spn = priv->sname; @@ -1560,17 +1499,26 @@ server_lookup: Realm req_rlm; krb5_realm *realms; - if (!config->autodetect_referrals) { - /* noop */ - } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) { + priv->error_code = ret; /* advise policy plugin of failure reason */ + ret2 = _kdc_referral_policy(priv); + if (ret2 == 0) { + krb5_xfree(priv->sname); + priv->sname = NULL; + ret = krb5_unparse_name(context, priv->server_princ, &priv->sname); + if (ret) + goto out; + goto server_lookup; + } else if (ret2 != KRB5_PLUGIN_NO_HANDLE) { + ret = ret2; + } else if ((req_rlm = get_krbtgt_realm(&priv->server_princ->name)) != NULL) { if (capath == NULL) { /* With referalls, hierarchical capaths are always enabled */ ret2 = _krb5_find_capath(context, tgt->crealm, our_realm, req_rlm, TRUE, &capath, &num_capath); if (ret2) { ret = ret2; - _kdc_audit_addreason((kdc_request_t)priv, - "No trusted path from client realm to ours"); + kdc_audit_addreason((kdc_request_t)priv, + "No trusted path from client realm to ours"); goto out; } } @@ -1587,31 +1535,31 @@ server_lookup: goto out; } - krb5_free_principal(context, sp); - sp = NULL; - krb5_make_principal(context, &sp, r, + krb5_free_principal(context, priv->server_princ); + priv->server_princ = NULL; + krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME, ref_realm, NULL); free(priv->sname); priv->sname = NULL; - ret = krb5_unparse_name(context, sp, &priv->sname); + ret = krb5_unparse_name(context, priv->server_princ, &priv->sname); if (ret) goto out; spn = priv->sname; goto server_lookup; } - } else if (need_referral(context, config, &b->kdc_options, sp, &realms)) { - if (strcmp(realms[0], sp->realm) != 0) { + } else if (need_referral(context, config, &b->kdc_options, priv->server_princ, &realms)) { + if (strcmp(realms[0], priv->server_princ->realm) != 0) { kdc_log(context, config, 4, "Returning a referral to realm %s for " "server %s that was not found", realms[0], spn); - krb5_free_principal(context, sp); - sp = NULL; - krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, + krb5_free_principal(context, priv->server_princ); + priv->server_princ = NULL; + krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME, realms[0], NULL); free(priv->sname); priv->sname = NULL; - ret = krb5_unparse_name(context, sp, &priv->sname); + ret = krb5_unparse_name(context, priv->server_princ, &priv->sname); if (ret) { krb5_free_host_realm(context, realms); goto out; @@ -1632,23 +1580,11 @@ server_lookup: krb5_free_error_message(context, msg); if (ret == HDB_ERR_NOENTRY) ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; - _kdc_audit_addreason((kdc_request_t)priv, - "Service principal unknown"); + kdc_audit_addreason((kdc_request_t)priv, + "Service principal unknown"); goto out; } - /* - * RFC 6806 notes that names MUST NOT be changed in the response to - * a TGS request. Hence we ignore the setting of the canonicalize - * KDC option. However, for legacy interoperability we do allow the - * backend to override this by setting the force-canonicalize HDB - * flag in the server entry. - */ - if (server->entry.flags.force_canonicalize) - rsp = server->entry.principal; - else - rsp = sp; - /* * Now refetch the primary krbtgt, and get the current kvno (the * sign check may have been on an old kvno, and the server may @@ -1676,10 +1612,10 @@ server_lookup: } ret = _kdc_db_fetch(context, config, krbtgt_out_principal, - HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out); + HDB_F_GET_KRBTGT, NULL, &krbtgt_outdb, &krbtgt_out); if (ret) { char *ktpn = NULL; - ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn); + ret = krb5_unparse_name(context, priv->krbtgt->principal, &ktpn); kdc_log(context, config, 4, "No such principal %s (needed for authz-data signature keys) " "while processing TGS-REQ for service %s with krbtg %s", @@ -1703,24 +1639,26 @@ server_lookup: krb5uint32 second_kvno = 0; krb5uint32 *kvno_ptr = NULL; size_t i; - hdb_entry_ex *user2user_client = NULL; + HDB *user2user_db; + hdb_entry *user2user_client = NULL; krb5_boolean user2user_kdc_issued = FALSE; + char *tpn; if(b->additional_tickets == NULL || b->additional_tickets->len == 0){ ret = KRB5KDC_ERR_BADOPTION; /* ? */ kdc_log(context, config, 4, "No second ticket present in user-to-user request"); - _kdc_audit_addreason((kdc_request_t)priv, - "No second ticket present in user-to-user request"); + kdc_audit_addreason((kdc_request_t)priv, + "No second ticket present in user-to-user request"); goto out; } t = &b->additional_tickets->val[0]; if(!get_krbtgt_realm(&t->sname)){ kdc_log(context, config, 4, "Additional ticket is not a ticket-granting ticket"); - _kdc_audit_addreason((kdc_request_t)priv, - "Additional ticket is not a ticket-granting ticket"); + kdc_audit_addreason((kdc_request_t)priv, + "Additional ticket is not a ticket-granting ticket"); ret = KRB5KDC_ERR_POLICY; goto out; } @@ -1737,36 +1675,41 @@ server_lookup: } ret = _kdc_db_fetch(context, config, p, HDB_F_GET_KRBTGT, kvno_ptr, - NULL, &user2user_krbtgt); + &user2user_krbtgtdb, &user2user_krbtgt); krb5_free_principal(context, p); if(ret){ if (ret == HDB_ERR_NOENTRY) ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; - _kdc_audit_addreason((kdc_request_t)priv, - "User-to-user service principal (TGS) unknown"); + kdc_audit_addreason((kdc_request_t)priv, + "User-to-user service principal (TGS) unknown"); + krb5_xfree(tpn); goto out; } - ret = hdb_enctype2key(context, &user2user_krbtgt->entry, NULL, + ret = hdb_enctype2key(context, user2user_krbtgt, NULL, t->enc_part.etype, &uukey); if(ret){ ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ - _kdc_audit_addreason((kdc_request_t)priv, - "User-to-user enctype not supported"); + kdc_audit_addreason((kdc_request_t)priv, + "User-to-user enctype not supported"); + krb5_xfree(tpn); goto out; } ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0); if(ret) { - _kdc_audit_addreason((kdc_request_t)priv, - "User-to-user TGT decrypt failure"); + kdc_audit_addreason((kdc_request_t)priv, + "User-to-user TGT decrypt failure"); + krb5_xfree(tpn); goto out; } ret = _kdc_verify_flags(context, config, &adtkt, tpn); if (ret) { - _kdc_audit_addreason((kdc_request_t)priv, - "User-to-user TGT expired or invalid"); + kdc_audit_addreason((kdc_request_t)priv, + "User-to-user TGT expired or invalid"); + krb5_xfree(tpn); goto out; } + krb5_xfree(tpn); /* Fetch the name from the TGT. */ ret = _krb5_principalname2krb5_principal(context, &user2user_princ, @@ -1786,7 +1729,7 @@ server_lookup: */ ret = _kdc_db_fetch(context, config, user2user_princ, HDB_F_GET_CLIENT | flags, - NULL, NULL, &user2user_client); + NULL, &user2user_db, &user2user_client); if (ret == HDB_ERR_NOENTRY) ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; if (ret) @@ -1807,7 +1750,7 @@ server_lookup: user2user_client, NULL); if (ret) { - _kdc_free_ent(context, user2user_client); + _kdc_free_ent(context, user2user_db, user2user_client); goto out; } @@ -1815,14 +1758,14 @@ server_lookup: * Also check that the account is the same one specified in the * request. */ - ret = check_client_matches_target_service(context, - config, - serverdb, - server, - user2user_client, - user2user_princ); + ret = _kdc_check_client_matches_target_service(context, + config, + serverdb, + priv->server, + user2user_client, + user2user_princ); if (ret) { - _kdc_free_ent(context, user2user_client); + _kdc_free_ent(context, user2user_db, user2user_client); goto out; } @@ -1831,7 +1774,7 @@ server_lookup: user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt, &uukey->key, &priv->ticket_key->key, &adtkt, &user2user_kdc_issued, &user2user_pac, NULL, NULL); - _kdc_free_ent(context, user2user_client); + _kdc_free_ent(context, user2user_db, user2user_client); if (ret) { const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, @@ -1860,8 +1803,8 @@ server_lookup: "Addition ticket have not matching etypes"); krb5_clear_error_message(context); ret = KRB5KDC_ERR_ETYPE_NOSUPP; - _kdc_audit_addreason((kdc_request_t)priv, - "No matching enctypes for 2nd ticket"); + kdc_audit_addreason((kdc_request_t)priv, + "No matching enctypes for 2nd ticket"); goto out; } etype = b->etype.val[i]; @@ -1869,28 +1812,28 @@ server_lookup: } else { Key *skey; - ret = _kdc_find_etype(priv, krb5_principal_is_krbtgt(context, sp) + ret = _kdc_find_etype(priv, krb5_principal_is_krbtgt(context, priv->server_princ) ? KFE_IS_TGS : 0, b->etype.val, b->etype.len, &etype, NULL, NULL); if(ret) { kdc_log(context, config, 4, "Server (%s) has no support for etypes", spn); - _kdc_audit_addreason((kdc_request_t)priv, - "Enctype not supported"); + kdc_audit_addreason((kdc_request_t)priv, + "Enctype not supported"); goto out; } - ret = _kdc_get_preferred_key(context, config, server, spn, + ret = _kdc_get_preferred_key(context, config, priv->server, spn, NULL, &skey); if(ret) { kdc_log(context, config, 4, "Server (%s) has no supported etypes", spn); - _kdc_audit_addreason((kdc_request_t)priv, - "Enctype not supported"); + kdc_audit_addreason((kdc_request_t)priv, + "Enctype not supported"); goto out; } ekey = &skey->key; - kvno = server->entry.kvno; + kvno = priv->server->kvno; } ret = krb5_generate_random_keyblock(context, etype, &sessionkey); @@ -1911,17 +1854,17 @@ server_lookup: * the DB to possibly correct the case of the realm (Samba4 does * this) before the strcmp() */ - if (strcmp(krb5_principal_get_realm(context, server->entry.principal), - krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) { + if (strcmp(krb5_principal_get_realm(context, priv->server->principal), + krb5_principal_get_realm(context, krbtgt_out->principal)) != 0) { char *ktpn; - ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn); + ret = krb5_unparse_name(context, krbtgt_out->principal, &ktpn); kdc_log(context, config, 4, "Request with wrong krbtgt: %s", (ret == 0) ? ktpn : ""); if(ret == 0) free(ktpn); ret = KRB5KRB_AP_ERR_NOT_US; - _kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT"); + kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT"); goto out; } @@ -1930,38 +1873,39 @@ server_lookup: if (ret) { kdc_log(context, config, 4, "Failed to find key for krbtgt PAC signature"); - _kdc_audit_addreason((kdc_request_t)priv, - "Failed to find key for krbtgt PAC signature"); + kdc_audit_addreason((kdc_request_t)priv, + "Failed to find key for krbtgt PAC signature"); goto out; } - ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL, + ret = hdb_enctype2key(context, krbtgt_out, NULL, tkey_sign->key.keytype, &tkey_sign); if(ret) { kdc_log(context, config, 4, "Failed to find key for krbtgt PAC signature"); - _kdc_audit_addreason((kdc_request_t)priv, - "Failed to find key for krbtgt PAC signature"); + kdc_audit_addreason((kdc_request_t)priv, + "Failed to find key for krbtgt PAC signature"); goto out; } - if (_kdc_synthetic_princ_used_p(context, ticket)) + if (_kdc_synthetic_princ_used_p(context, priv->ticket)) flags |= HDB_F_SYNTHETIC_OK; - ret = _kdc_db_fetch_client(context, config, flags, cp, cpn, our_realm, - &clientdb, &client); + ret = _kdc_db_fetch_client(context, config, flags, priv->client_princ, + cpn, our_realm, &clientdb, &priv->client); if (ret) goto out; flags &= ~HDB_F_SYNTHETIC_OK; - priv->client = client; - - heim_assert(priv->client_princ == NULL, "client_princ should be NULL for TGS"); + priv->clientdb = clientdb; - ret = _kdc_check_pac(context, config, cp, NULL, client, server, krbtgt, krbtgt, + ret = _kdc_check_pac(context, config, priv->client_princ, NULL, + priv->client, priv->server, + priv->krbtgt, priv->krbtgt, &priv->ticket_key->key, &priv->ticket_key->key, tgt, - &kdc_issued, &priv->pac, &priv->client_princ, &priv->pac_attributes); + &kdc_issued, &priv->pac, &priv->canon_client_princ, + &priv->pac_attributes); if (ret) { const char *msg = krb5_get_error_message(context, ret); - _kdc_audit_addreason((kdc_request_t)priv, "PAC check failed"); + kdc_audit_addreason((kdc_request_t)priv, "PAC check failed"); kdc_log(context, config, 4, "Verify PAC failed for %s (%s) from %s with %s", spn, cpn, from, msg); @@ -1973,352 +1917,13 @@ server_lookup: * Process request */ - /* by default the tgt principal matches the client principal */ - tp = cp; - tpn = cpn; - - if (client) { - const PA_DATA *sdata; - int i = 0; - - sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER); - if (sdata) { - krb5_crypto crypto; - krb5_data datack; - PA_S4U2Self self; - const char *str; - - ret = decode_PA_S4U2Self(sdata->padata_value.data, - sdata->padata_value.length, - &self, NULL); - if (ret) { - _kdc_audit_addreason((kdc_request_t)priv, - "Failed to decode PA-S4U2Self"); - kdc_log(context, config, 4, "Failed to decode PA-S4U2Self"); - goto out; - } - - if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) { - free_PA_S4U2Self(&self); - _kdc_audit_addreason((kdc_request_t)priv, - "PA-S4U2Self with unkeyed checksum"); - kdc_log(context, config, 4, "Reject PA-S4U2Self with unkeyed checksum"); - ret = KRB5KRB_AP_ERR_INAPP_CKSUM; - goto out; - } - - ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack); - if (ret) - goto out; - - ret = krb5_crypto_init(context, &tgt->key, 0, &crypto); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - free_PA_S4U2Self(&self); - krb5_data_free(&datack); - kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg); - krb5_free_error_message(context, msg); - goto out; - } - - /* Allow HMAC_MD5 checksum with any key type */ - if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) { - struct krb5_crypto_iov iov; - unsigned char csdata[16]; - Checksum cs; - - cs.checksum.length = sizeof(csdata); - cs.checksum.data = &csdata; - - iov.data.data = datack.data; - iov.data.length = datack.length; - iov.flags = KRB5_CRYPTO_TYPE_DATA; - - ret = _krb5_HMAC_MD5_checksum(context, NULL, &crypto->key, - KRB5_KU_OTHER_CKSUM, &iov, 1, - &cs); - if (ret == 0 && - krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0) - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - } - else { - ret = _kdc_verify_checksum(context, - crypto, - KRB5_KU_OTHER_CKSUM, - &datack, - &self.cksum); - } - krb5_data_free(&datack); - krb5_crypto_destroy(context, crypto); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - free_PA_S4U2Self(&self); - _kdc_audit_addreason((kdc_request_t)priv, - "S4U2Self checksum failed"); - kdc_log(context, config, 4, - "krb5_verify_checksum failed for S4U2Self: %s", msg); - krb5_free_error_message(context, msg); - goto out; - } - - ret = _krb5_principalname2krb5_principal(context, - &tp, - self.name, - self.realm); - free_PA_S4U2Self(&self); - if (ret) - goto out; - - ret = krb5_unparse_name(context, tp, &tpn); - if (ret) - goto out; - - /* - * Note no HDB_F_SYNTHETIC_OK -- impersonating non-existent clients - * is probably not desirable! - */ - ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags, - NULL, &s4u2self_impersonated_clientdb, - &s4u2self_impersonated_client); - if (ret) { - const char *msg; - - /* - * If the client belongs to the same realm as our krbtgt, it - * should exist in the local database. - * - */ - - if (ret == HDB_ERR_NOENTRY) - ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; - msg = krb5_get_error_message(context, ret); - _kdc_audit_addreason((kdc_request_t)priv, - "S4U2Self principal to impersonate not found"); - kdc_log(context, config, 2, - "S4U2Self principal to impersonate %s not found in database: %s", - tpn, msg); - krb5_free_error_message(context, msg); - goto out; - } - - /* Ignore require_pwchange and pw_end attributes (as Windows does), - * since S4U2Self is not password authentication. */ - s4u2self_impersonated_client->entry.flags.require_pwchange = FALSE; - free(s4u2self_impersonated_client->entry.pw_end); - s4u2self_impersonated_client->entry.pw_end = NULL; - - ret = kdc_check_flags(priv, FALSE, s4u2self_impersonated_client, priv->server); - if (ret) - goto out; /* kdc_check_flags() calls _kdc_audit_addreason() */ - - /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */ - krb5_pac_free(context, priv->pac); - priv->pac = NULL; - - ret = _kdc_pac_generate(context, - s4u2self_impersonated_client, - server, - NULL, - KRB5_PAC_WAS_GIVEN_IMPLICITLY, - &priv->pac); - if (ret) { - kdc_log(context, config, 4, "PAC generation failed for -- %s", tpn); - goto out; - } - - /* - * Check that service doing the impersonating is - * requesting a ticket to it-self. - */ - ret = check_client_matches_target_service(context, - config, - clientdb, - client, - server, - sp); - if (ret) { - kdc_log(context, config, 4, "S4U2Self: %s is not allowed " - "to impersonate to service " - "(tried for user %s to service %s)", - cpn, tpn, spn); - goto out; - } - - /* - * If the service isn't trusted for authentication to - * delegation or if the impersonate client is disallowed - * forwardable, remove the forwardable flag. - */ - - if (client->entry.flags.trusted_for_delegation && - s4u2self_impersonated_client->entry.flags.forwardable) { - str = "[forwardable]"; - } else { - b->kdc_options.forwardable = 0; - str = ""; - } - kdc_log(context, config, 4, "s4u2self %s impersonating %s to " - "service %s %s", cpn, tpn, spn, str); - } - } - /* - * Constrained delegation + * Services for User: protocol transition and constrained delegation */ - if (client != NULL - && b->additional_tickets != NULL - && b->additional_tickets->len != 0 - && b->kdc_options.cname_in_addl_tkt - && b->kdc_options.enc_tkt_in_skey == 0) - { - hdb_entry_ex *adclient = NULL; - krb5_boolean ad_kdc_issued = FALSE; - Key *clientkey; - Ticket *t; - - /* - * We require that the service's krbtgt has a PAC. - */ - if (priv->pac == NULL) { - ret = KRB5KDC_ERR_BADOPTION; - _kdc_audit_addreason((kdc_request_t)priv, "Missing PAC"); - kdc_log(context, config, 4, - "Constrained delegation without PAC, %s/%s", - cpn, spn); - goto out; - } - - krb5_pac_free(context, priv->pac); - priv->pac = NULL; - - krb5_free_principal(context, priv->client_princ); - priv->client_princ = NULL; - - t = &b->additional_tickets->val[0]; - - ret = hdb_enctype2key(context, &client->entry, - hdb_kvno2keys(context, &client->entry, - t->enc_part.kvno ? * t->enc_part.kvno : 0), - t->enc_part.etype, &clientkey); - if(ret){ - ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ - goto out; - } - - ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0); - if (ret) { - _kdc_audit_addreason((kdc_request_t)priv, - "Failed to decrypt constrained delegation ticket"); - kdc_log(context, config, 4, - "failed to decrypt ticket for " - "constrained delegation from %s to %s ", cpn, spn); - goto out; - } - - ret = _krb5_principalname2krb5_principal(context, - &tp, - adtkt.cname, - adtkt.crealm); - if (ret) - goto out; - - ret = krb5_unparse_name(context, tp, &tpn); - if (ret) - goto out; - - _kdc_audit_addkv((kdc_request_t)priv, 0, "impersonatee", "%s", tpn); - - ret = _krb5_principalname2krb5_principal(context, - &dp, - t->sname, - t->realm); - if (ret) - goto out; - - ret = krb5_unparse_name(context, dp, &dpn); - if (ret) - goto out; - - /* check that ticket is valid */ - if (adtkt.flags.forwardable == 0) { - _kdc_audit_addreason((kdc_request_t)priv, - "Missing forwardable flag on ticket for constrained delegation"); - kdc_log(context, config, 4, - "Missing forwardable flag on ticket for " - "constrained delegation from %s (%s) as %s to %s ", - cpn, dpn, tpn, spn); - ret = KRB5KDC_ERR_BADOPTION; - goto out; - } - - ret = check_constrained_delegation(context, config, clientdb, - client, server, sp); - if (ret) { - _kdc_audit_addreason((kdc_request_t)priv, - "Constrained delegation not allowed"); - kdc_log(context, config, 4, - "constrained delegation from %s (%s) as %s to %s not allowed", - cpn, dpn, tpn, spn); - goto out; - } - - ret = _kdc_verify_flags(context, config, &adtkt, tpn); - if (ret) { - _kdc_audit_addreason((kdc_request_t)priv, - "Constrained delegation ticket expired or invalid"); - goto out; - } - - /* Try lookup the delegated client in DB */ - ret = _kdc_db_fetch_client(context, config, flags, tp, tpn, our_realm, - NULL, &adclient); - if (ret) - goto out; - - if (adclient != NULL) { - ret = kdc_check_flags(priv, FALSE, adclient, priv->server); - if (ret) { - _kdc_free_ent(context, adclient); - goto out; - } - } - - /* - * TODO: pass in t->sname and t->realm and build - * a S4U_DELEGATION_INFO blob to the PAC. - */ - ret = _kdc_check_pac(context, config, tp, dp, adclient, server, krbtgt, client, - &clientkey->key, &priv->ticket_key->key, &adtkt, - &ad_kdc_issued, &priv->pac, &priv->client_princ, &priv->pac_attributes); - if (adclient) - _kdc_free_ent(context, adclient); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - _kdc_audit_addreason((kdc_request_t)priv, - "Constrained delegation ticket PAC check failed"); - kdc_log(context, config, 4, - "Verify delegated PAC failed to %s for client" - "%s (%s) as %s from %s with %s", - spn, cpn, dpn, tpn, from, msg); - krb5_free_error_message(context, msg); - goto out; - } - - if (priv->pac == NULL || !ad_kdc_issued) { - ret = KRB5KDC_ERR_BADOPTION; - kdc_log(context, config, 4, - "Ticket not signed with PAC; service %s failed for " - "for delegation to %s for client %s (%s) from %s; (%s).", - spn, tpn, dpn, cpn, from, priv->pac ? "Ticket unsigned" : "No PAC"); - _kdc_audit_addreason((kdc_request_t)priv, - "Constrained delegation ticket not signed"); - goto out; - } - - kdc_log(context, config, 4, "constrained delegation for %s " - "from %s (%s) to %s", tpn, cpn, dpn, spn); - } + ret = _kdc_validate_services_for_user(priv); + if (ret) + goto out; /* * Check flags @@ -2330,9 +1935,9 @@ server_lookup: if((b->kdc_options.validate || b->kdc_options.renew) && !krb5_principal_compare(context, - krbtgt->entry.principal, - server->entry.principal)){ - _kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request"); + priv->krbtgt->principal, + priv->server->principal)){ + kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request"); kdc_log(context, config, 4, "Inconsistent request."); ret = KRB5KDC_ERR_SERVER_NOMATCH; goto out; @@ -2342,12 +1947,12 @@ server_lookup: if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) { if (config->check_ticket_addresses) { ret = KRB5KRB_AP_ERR_BADADDR; - _kdc_audit_addkv((kdc_request_t)priv, 0, "wrongaddr", "yes"); + kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE); kdc_log(context, config, 4, "Request from wrong address"); - _kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address"); + kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address"); goto out; } else if (config->warn_ticket_addresses) { - _kdc_audit_addkv((kdc_request_t)priv, 0, "wrongaddr", "yes"); + kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE); } } @@ -2377,7 +1982,7 @@ server_lookup: NULL, s, &pa.padata_value); krb5_crypto_destroy(context, crypto); if (ret) { - _kdc_audit_addreason((kdc_request_t)priv, "Referral build failed"); + kdc_audit_addreason((kdc_request_t)priv, "Referral build failed"); kdc_log(context, config, 4, "Failed building server referral"); goto out; @@ -2402,7 +2007,7 @@ server_lookup: */ if (kdc_issued && - !krb5_principal_is_krbtgt(context, server->entry.principal)) { + !krb5_principal_is_krbtgt(context, priv->server->principal)) { /* Validate armor TGT before potentially including device claims */ if (priv->armor_ticket) { @@ -2419,54 +2024,35 @@ server_lookup: * read-only-dc identifier, we need to embed it in the PAC KDC signatures. */ - rodc_id = krbtgt_out->entry.kvno >> 16; + rodc_id = krbtgt_out->kvno >> 16; /* * */ ret = tgs_make_reply(priv, - tp, tgt, ekey, &tkey_sign->key, &sessionkey, kvno, *auth_data, - server, - rsp, - client, - cp, tgt_realm, rodc_id, add_ticket_sig); out: free(user2user_name); - if (tpn != cpn) - free(tpn); - free(dpn); free(krbtgt_out_n); _krb5_free_capath(context, capath); krb5_free_keyblock_contents(context, &sessionkey); if(krbtgt_out) - _kdc_free_ent(context, krbtgt_out); - if(server) - _kdc_free_ent(context, server); - if(client) - _kdc_free_ent(context, client); - if(s4u2self_impersonated_client) - _kdc_free_ent(context, s4u2self_impersonated_client); + _kdc_free_ent(context, krbtgt_outdb, krbtgt_out); if(user2user_krbtgt) - _kdc_free_ent(context, user2user_krbtgt); + _kdc_free_ent(context, user2user_krbtgtdb, user2user_krbtgt); krb5_free_principal(context, user2user_princ); - if (tp && tp != cp) - krb5_free_principal(context, tp); - krb5_free_principal(context, cp); - krb5_free_principal(context, dp); - krb5_free_principal(context, sp); krb5_free_principal(context, krbtgt_out_principal); free(ref_realm); @@ -2494,9 +2080,6 @@ _kdc_tgs_rep(astgs_request_t r) krb5_error_code ret; int i = 0; const PA_DATA *tgs_req, *pa; - - hdb_entry_ex *krbtgt = NULL; - krb5_ticket *ticket = NULL; krb5_enctype krbtgt_etype = ETYPE_NULL; time_t *csec = NULL; @@ -2529,9 +2112,7 @@ _kdc_tgs_rep(astgs_request_t r) goto out; } ret = tgs_parse_request(r, tgs_req, - &krbtgt, &krbtgt_etype, - &ticket, from, from_addr, &csec, &cusec, &auth_data); @@ -2557,9 +2138,7 @@ _kdc_tgs_rep(astgs_request_t r) } ret = tgs_build_reply(r, - krbtgt, krbtgt_etype, - ticket, &auth_data, from_addr); if (ret) { @@ -2576,6 +2155,9 @@ _kdc_tgs_rep(astgs_request_t r) } out: + r->error_code = ret; + _kdc_audit_request(r); + if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){ METHOD_DATA error_method = { 0, NULL }; @@ -2584,9 +2166,9 @@ out: &error_method, r->armor_crypto, &req->req_body, - r->ret = ret, - ticket != NULL ? ticket->client : NULL, - ticket != NULL ? ticket->server : NULL, + r->error_code, + r->client_princ ? r->client_princ :(r->ticket != NULL ? r->ticket->client : NULL), + r->server_princ ? r->server_princ :(r->ticket != NULL ? r->ticket->server : NULL), csec, cusec, data); free_METHOD_DATA(&error_method); @@ -2609,9 +2191,9 @@ out: } free_EncryptionKey(&r->et.key); - if (r->client_princ) { - krb5_free_principal(r->context, r->client_princ); - r->client_princ = NULL; + if (r->canon_client_princ) { + krb5_free_principal(r->context, r->canon_client_princ); + r->canon_client_princ = NULL; } if (r->armor_crypto) { krb5_crypto_destroy(r->context, r->armor_crypto); @@ -2620,15 +2202,21 @@ out: if (r->armor_ticket) krb5_free_ticket(r->context, r->armor_ticket); if (r->armor_server) - _kdc_free_ent(r->context, r->armor_server); + _kdc_free_ent(r->context, r->armor_serverdb, r->armor_server); krb5_free_keyblock_contents(r->context, &r->reply_key); krb5_free_keyblock_contents(r->context, &r->strengthen_key); - if (ticket) - krb5_free_ticket(r->context, ticket); - if(krbtgt) - _kdc_free_ent(r->context, krbtgt); - + if (r->ticket) + krb5_free_ticket(r->context, r->ticket); + if (r->krbtgt) + _kdc_free_ent(r->context, r->krbtgtdb, r->krbtgt); + + if (r->client) + _kdc_free_ent(r->context, r->clientdb, r->client); + krb5_free_principal(r->context, r->client_princ); + if (r->server) + _kdc_free_ent(r->context, r->serverdb, r->server); + krb5_free_principal(r->context, r->server_princ); _kdc_free_fast_state(&r->fast); krb5_pac_free(r->context, r->pac); diff --git a/third_party/heimdal/kdc/kstash.c b/third_party/heimdal/kdc/kstash.c index bba2b11d0f0d..6ec1a548aca6 100644 --- a/third_party/heimdal/kdc/kstash.c +++ b/third_party/heimdal/kdc/kstash.c @@ -131,6 +131,8 @@ main(int argc, char **argv) krb5_string_to_key_salt(context, enctype, buf, salt, &key); } ret = hdb_add_master_key(context, &key, &mkey); + if (ret) + krb5_err(context, 1, ret, "hdb_add_master_key"); krb5_free_keyblock_contents(context, &key); diff --git a/third_party/heimdal/kdc/kx509.c b/third_party/heimdal/kdc/kx509.c index bc3ca9deca6b..6efd94e3a12d 100644 --- a/third_party/heimdal/kdc/kx509.c +++ b/third_party/heimdal/kdc/kx509.c @@ -157,9 +157,11 @@ verify_req_hash(krb5_context context, } HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, - key->keyvalue.data, key->keyvalue.length, - EVP_sha1(), NULL); + if (HMAC_Init_ex(&ctx, key->keyvalue.data, key->keyvalue.length, + EVP_sha1(), NULL) == 0) { + HMAC_CTX_cleanup(&ctx); + return krb5_enomem(context); + } if (sizeof(digest) != HMAC_size(&ctx)) krb5_abortx(context, "runtime error, hmac buffer wrong size in kx509"); HMAC_Update(&ctx, version_2_0, sizeof(version_2_0)); @@ -186,14 +188,17 @@ calculate_reply_hash(krb5_context context, krb5_keyblock *key, Kx509Response *rep) { - krb5_error_code ret; + krb5_error_code ret = 0; HMAC_CTX ctx; HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, key->keyvalue.data, key->keyvalue.length, - EVP_sha1(), NULL); - ret = krb5_data_alloc(rep->hash, HMAC_size(&ctx)); + if (HMAC_Init_ex(&ctx, key->keyvalue.data, key->keyvalue.length, + EVP_sha1(), NULL) == 0) + ret = krb5_enomem(context); + + if (ret == 0) + ret = krb5_data_alloc(rep->hash, HMAC_size(&ctx)); if (ret) { HMAC_CTX_cleanup(&ctx); return krb5_enomem(context); @@ -248,7 +253,8 @@ is_local_realm(krb5_context context, { krb5_error_code ret; krb5_principal tgs; - hdb_entry_ex *ent = NULL; + HDB *db; + hdb_entry *ent = NULL; ret = krb5_make_principal(context, &tgs, realm, KRB5_TGS_NAME, realm, NULL); @@ -256,9 +262,9 @@ is_local_realm(krb5_context context, return ret; if (ret == 0) ret = _kdc_db_fetch(context, reqctx->config, tgs, HDB_F_GET_KRBTGT, - NULL, NULL, &ent); + NULL, &db, &ent); if (ent) - _kdc_free_ent(context, ent); + _kdc_free_ent(context, db, ent); krb5_free_principal(context, tgs); if (ret == HDB_ERR_NOENTRY || ret == HDB_ERR_NOT_FOUND_HERE) return KRB5KRB_AP_ERR_NOT_US; @@ -299,8 +305,8 @@ kdc_kx509_verify_service_principal(krb5_context context, KRB5_TGS_NAME) == 0) { const char *r = krb5_principal_get_comp_string(context, sprincipal, 1); if ((ret = is_local_realm(context, reqctx, r))) - _kdc_audit_addreason((kdc_request_t)reqctx, - "Client used wrong krbtgt for kx509"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Client used wrong krbtgt for kx509"); goto out; } @@ -309,8 +315,8 @@ kdc_kx509_verify_service_principal(krb5_context context, if (ret != 0) { ret = errno; kdc_log(context, reqctx->config, 0, "Failed to get local hostname"); - _kdc_audit_addreason((kdc_request_t)reqctx, - "Failed to get local hostname"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Failed to get local hostname"); return ret; } localhost[sizeof(localhost) - 1] = '\0'; @@ -329,8 +335,8 @@ err: goto out; ret = KRB5KDC_ERR_SERVER_NOMATCH; - _kdc_audit_addreason((kdc_request_t)reqctx, "Client used wrong kx509 " - "service principal (expected %s)", expected); + kdc_audit_addreason((kdc_request_t)reqctx, "Client used wrong kx509 " + "service principal (expected %s)", expected); out: krb5_xfree(expected); @@ -394,7 +400,7 @@ mk_error_response(krb5_context context, } va_start(ap, fmt); - _kdc_audit_vaddreason((kdc_request_t)reqctx, fmt, ap); + kdc_audit_vaddreason((kdc_request_t)reqctx, fmt, ap); va_end(ap); } @@ -536,12 +542,13 @@ update_csr(krb5_context context, kx509_req_context reqctx, Extensions *exts) } } if (ret) { + const char *emsg = krb5_get_error_message(context, ret); kdc_log(context, reqctx->config, 1, - "Error handling requested extensions: %s", - krb5_get_error_message(context, ret)); - _kdc_audit_addreason((kdc_request_t)reqctx, - "Error handling requested extensions: %s", - krb5_get_error_message(context, ret)); + "Error handling requested extensions: %s", emsg); + kdc_audit_addreason((kdc_request_t)reqctx, + "Error handling requested extensions: %s", + emsg); + krb5_free_error_message(context, emsg); } return ret; } @@ -574,7 +581,7 @@ get_csr(krb5_context context, kx509_req_context reqctx) */ if (ret == 0) return update_csr(context, reqctx, reqctx->csr_plus.exts); - _kdc_audit_addreason((kdc_request_t)reqctx, "Invalid CSR"); + kdc_audit_addreason((kdc_request_t)reqctx, "Invalid CSR"); return ret; } reqctx->send_chain = 0; @@ -582,8 +589,8 @@ get_csr(krb5_context context, kx509_req_context reqctx) /* Check if proof of possession is required by configuration */ if (!get_bool_param(context, FALSE, reqctx->realm, "require_csr")) { - _kdc_audit_addreason((kdc_request_t)reqctx, - "CSRs required but client did not send one"); + kdc_audit_addreason((kdc_request_t)reqctx, + "CSRs required but client did not send one"); krb5_set_error_message(context, KX509_STATUS_CLIENT_USE_CSR, "CSRs required but kx509 client did not send " "one"); @@ -601,14 +608,14 @@ get_csr(krb5_context context, kx509_req_context reqctx) /* Not an RSAPublicKey or garbage follows it */ if (ret == 0) { ret = KRB5KDC_ERR_NULL_KEY; - _kdc_audit_addreason((kdc_request_t)reqctx, - "Request has garbage after key"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Request has garbage after key"); krb5_set_error_message(context, ret, "Request has garbage after key"); return ret; } - _kdc_audit_addreason((kdc_request_t)reqctx, - "Could not decode CSR or RSA subject public key"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Could not decode CSR or RSA subject public key"); krb5_set_error_message(context, ret, "Could not decode CSR or RSA subject public key"); return ret; @@ -668,7 +675,7 @@ check_authz(krb5_context context, ret = kdc_authorize_csr(context, reqctx->config->app, reqctx->csr, cprincipal); if (ret == 0) { - _kdc_audit_addkv((kdc_request_t)reqctx, 0, "authorized", "true"); + kdc_audit_setkv_bool((kdc_request_t)reqctx, "authorized", TRUE); ret = hx509_request_get_san(reqctx->csr, 0, &san_type, &s); if (ret == 0) { @@ -685,20 +692,19 @@ check_authz(krb5_context context, case HX509_SAN_TYPE_MS_UPN: san_type_s = "ms-UPN"; break; default: san_type_s = "unknown"; break; } - _kdc_audit_addkv((kdc_request_t)reqctx, 0, "san0_type", "%s", - san_type_s); - _kdc_audit_addkv((kdc_request_t)reqctx, 0, "san0", "%s", s); - free(s); + kdc_audit_addkv((kdc_request_t)reqctx, 0, "san0_type", "%s", + san_type_s); + kdc_audit_addkv((kdc_request_t)reqctx, 0, "san0", "%s", s); } + frees(&s); ret = hx509_request_get_eku(reqctx->csr, 0, &s); - if (ret == 0) { - _kdc_audit_addkv((kdc_request_t)reqctx, 0, "eku0", "%s", s); - free(s); - } + if (ret == 0) + kdc_audit_addkv((kdc_request_t)reqctx, 0, "eku0", "%s", s); + free(s); return 0; } if (ret != KRB5_PLUGIN_NO_HANDLE) { - _kdc_audit_addreason((kdc_request_t)reqctx, + kdc_audit_addreason((kdc_request_t)reqctx, "Requested extensions rejected by plugin"); return ret; } @@ -718,27 +724,27 @@ check_authz(krb5_context context, if (ncomp != 2 || strcasecmp(comp1, s) != 0 || strchr(s, '.') == NULL || !check_authz_svc_ok(context, comp0)) { - _kdc_audit_addreason((kdc_request_t)reqctx, - "Requested extensions rejected by " - "default policy (dNSName SAN " - "does not match client)"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Requested extensions rejected by " + "default policy (dNSName SAN " + "does not match client)"); goto eacces; } break; case HX509_SAN_TYPE_PKINIT: if (strcmp(cprinc, s) != 0) { - _kdc_audit_addreason((kdc_request_t)reqctx, - "Requested extensions rejected by " - "default policy (PKINIT SAN " - "does not match client)"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Requested extensions rejected by " + "default policy (PKINIT SAN " + "does not match client)"); goto eacces; } break; default: - _kdc_audit_addreason((kdc_request_t)reqctx, - "Requested extensions rejected by " - "default policy (non-default SAN " - "requested)"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Requested extensions rejected by " + "default policy (non-default SAN " + "requested)"); goto eacces; } } @@ -766,8 +772,8 @@ check_authz(krb5_context context, } der_free_oid(&oid); if (k == sizeof(eku_whitelist)/sizeof(eku_whitelist[0])) { - _kdc_audit_addreason((kdc_request_t)reqctx, - "Requested EKU rejected by default policy"); + kdc_audit_addreason((kdc_request_t)reqctx, + "Requested EKU rejected by default policy"); goto eacces; } } @@ -785,7 +791,8 @@ check_authz(krb5_context context, if (KeyUsage2int(ku) != (KeyUsage2int(ku) & KeyUsage2int(ku_allowed))) goto eacces; - _kdc_audit_addkv((kdc_request_t)reqctx, 0, "authorized", "true"); + kdc_audit_setkv_bool((kdc_request_t)reqctx, "authorized", TRUE); + free(cprinc); return 0; eacces: @@ -794,7 +801,7 @@ eacces: out: /* XXX Display error code */ - _kdc_audit_addreason((kdc_request_t)reqctx, + kdc_audit_addreason((kdc_request_t)reqctx, "Error handling requested extensions"); out2: free(cprinc); @@ -884,7 +891,7 @@ _kdc_do_kx509(kx509_req_context r) * possibly change the error code and message. */ is_probe = 1; - _kdc_audit_addkv((kdc_request_t)r, 0, "probe", "unauthenticated"); + kdc_audit_addkv((kdc_request_t)r, 0, "probe", "unauthenticated"); ret = mk_error_response(r->context, r, 4, 0, "kx509 service is available"); goto out; @@ -933,7 +940,8 @@ _kdc_do_kx509(kx509_req_context r) goto out; } - ret = krb5_unparse_name(r->context, cprincipal, &r->cname); + if (ret == 0) + ret = krb5_unparse_name(r->context, cprincipal, &r->cname); /* Check that the service name is a valid kx509 service name */ if (ret == 0) @@ -966,7 +974,7 @@ _kdc_do_kx509(kx509_req_context r) * possibly change the error code and message. */ is_probe = 1; - _kdc_audit_addkv((kdc_request_t)r, 0, "probe", "authenticated"); + kdc_audit_addkv((kdc_request_t)r, 0, "probe", "authenticated"); ret = mk_error_response(r->context, r, 4, 0, "kx509 authenticated probe request"); goto out; @@ -1041,14 +1049,14 @@ _kdc_do_kx509(kx509_req_context r) ret = encode_reply(r->context, r, &rep); if (ret) /* Can't send an error message either in this case, surely */ - _kdc_audit_addreason((kdc_request_t)r, "Could not encode response"); + kdc_audit_addreason((kdc_request_t)r, "Could not encode response"); out: hx509_certs_free(&certs); if (ret == 0 && !is_probe) - _kdc_audit_addkv((kdc_request_t)r, 0, "cert_issued", "true"); + kdc_audit_setkv_bool((kdc_request_t)r, "cert_issued", TRUE); else - _kdc_audit_addkv((kdc_request_t)r, 0, "cert_issued", "false"); + kdc_audit_setkv_bool((kdc_request_t)r, "cert_issued", FALSE); if (r->ac) krb5_auth_con_free(r->context, r->ac); if (ticket) diff --git a/third_party/heimdal/kdc/libkdc-exports.def b/third_party/heimdal/kdc/libkdc-exports.def index a4ed75bfb6a5..3cc929e6025b 100644 --- a/third_party/heimdal/kdc/libkdc-exports.def +++ b/third_party/heimdal/kdc/libkdc-exports.def @@ -6,8 +6,9 @@ EXPORTS kdc_log_msg kdc_log_msg_va kdc_openlog + kdc_check_flags kdc_validate_token - krb5_kdc_windc_init + krb5_kdc_plugin_init krb5_kdc_get_config krb5_kdc_pkinit_config krb5_kdc_set_dbinfo @@ -16,8 +17,80 @@ EXPORTS krb5_kdc_save_request krb5_kdc_update_time krb5_kdc_pk_initialize - _kdc_audit_addkv - _kdc_audit_addreason - _kdc_audit_vaddkv - _kdc_audit_vaddreason + kdc_request_set_attribute + kdc_request_get_attribute + kdc_request_copy_attribute + kdc_request_delete_attribute + kdc_request_add_encrypted_padata + kdc_request_add_pac_buffer + kdc_request_add_reply_padata + kdc_request_get_addr + kdc_request_get_canon_client_princ + kdc_request_get_client + kdc_request_get_clientdb + kdc_request_get_client_princ + kdc_request_get_context + kdc_request_get_config + kdc_request_get_cname + kdc_request_get_error_code + kdc_request_get_from + kdc_request_get_krbtgt + kdc_request_get_krbtgtdb + kdc_request_get_krbtgt_princ + kdc_request_get_pac + kdc_request_get_pac_attributes + kdc_request_get_rep + kdc_request_get_reply_key + kdc_request_get_req + kdc_request_get_request + kdc_request_get_server + kdc_request_get_serverdb + kdc_request_get_server_princ + kdc_request_get_sname + kdc_request_get_ticket + kdc_request_get_tv_end + kdc_request_get_tv_start + kdc_request_set_canon_client_princ + kdc_request_set_client_princ + kdc_request_set_cname + kdc_request_set_error_code + kdc_request_set_krbtgt_princ + kdc_request_set_pac + kdc_request_set_pac_attributes + kdc_request_set_rep + kdc_request_set_reply_key + kdc_request_set_server_princ + kdc_request_set_sname + kdc_audit_addkv + kdc_audit_addkv_number + kdc_audit_addkv_object + kdc_audit_addkv_timediff + kdc_audit_addaddrs + kdc_audit_addreason + kdc_audit_getkv + kdc_audit_setkv_bool + kdc_audit_setkv_number + kdc_audit_setkv_object + kdc_audit_vaddkv + kdc_audit_vaddreason _kdc_audit_trail + + kdc_object_alloc + kdc_object_retain + kdc_object_release + kdc_bool_create + kdc_bool_get_value + kdc_array_iterate + kdc_array_get_length + kdc_array_get_value + kdc_array_copy_value + kdc_string_create + kdc_string_get_utf8 + kdc_data_create + kdc_data_get_data + kdc_number_create + kdc_number_get_value + + ; needed for digest-service + _kdc_db_fetch + _kdc_free_ent diff --git a/third_party/heimdal/kdc/log.c b/third_party/heimdal/kdc/log.c index 895f1c9c6e4b..bfb0f54ff899 100644 --- a/third_party/heimdal/kdc/log.c +++ b/third_party/heimdal/kdc/log.c @@ -35,7 +35,7 @@ #include "kdc_locl.h" -void +KDC_LIB_FUNCTION void KDC_LIB_CALL kdc_openlog(krb5_context context, const char *service, krb5_kdc_configuration *config) @@ -63,7 +63,7 @@ kdc_openlog(krb5_context context, #undef __attribute__ #define __attribute__(X) -char* +KDC_LIB_FUNCTION char * KDC_LIB_CALL kdc_log_msg_va(krb5_context context, krb5_kdc_configuration *config, int level, const char *fmt, va_list ap) @@ -74,7 +74,7 @@ kdc_log_msg_va(krb5_context context, return msg; } -char* +KDC_LIB_FUNCTION char * KDC_LIB_CALL kdc_log_msg(krb5_context context, krb5_kdc_configuration *config, int level, const char *fmt, ...) @@ -88,7 +88,7 @@ kdc_log_msg(krb5_context context, return s; } -void +KDC_LIB_FUNCTION void KDC_LIB_CALL kdc_vlog(krb5_context context, krb5_kdc_configuration *config, int level, const char *fmt, va_list ap) @@ -97,7 +97,7 @@ kdc_vlog(krb5_context context, free(kdc_log_msg_va(context, config, level, fmt, ap)); } -void +KDC_LIB_FUNCTION void KDC_LIB_CALL kdc_log(krb5_context context, krb5_kdc_configuration *config, int level, const char *fmt, ...) diff --git a/third_party/heimdal/kdc/misc.c b/third_party/heimdal/kdc/misc.c index e6a5c5c2340d..b48503d26a0e 100644 --- a/third_party/heimdal/kdc/misc.c +++ b/third_party/heimdal/kdc/misc.c @@ -60,18 +60,18 @@ synthesize_hdb_close(krb5_context context, struct HDB *db) } /* - * Synthesize an HDB entry suitable for PKINIT and only PKINIT. + * Synthesize an HDB entry suitable for PKINIT and GSS preauth. */ static krb5_error_code synthesize_client(krb5_context context, krb5_kdc_configuration *config, krb5_const_principal princ, HDB **db, - hdb_entry_ex **h) + hdb_entry **h) { static HDB null_db; krb5_error_code ret; - hdb_entry_ex *e; + hdb_entry *e; /* Hope this works! */ null_db.hdb_destroy = synthesize_hdb_close; @@ -81,57 +81,57 @@ synthesize_client(krb5_context context, ret = (e = calloc(1, sizeof(*e))) ? 0 : krb5_enomem(context); if (ret == 0) { - e->entry.flags.client = 1; - e->entry.flags.immutable = 1; - e->entry.flags.virtual = 1; - e->entry.flags.synthetic = 1; - e->entry.flags.do_not_store = 1; - e->entry.kvno = 1; - e->entry.keys.len = 0; - e->entry.keys.val = NULL; - e->entry.created_by.time = time(NULL); - e->entry.modified_by = NULL; - e->entry.valid_start = NULL; - e->entry.valid_end = NULL; - e->entry.pw_end = NULL; - e->entry.etypes = NULL; - e->entry.generation = NULL; - e->entry.extensions = NULL; + e->flags.client = 1; + e->flags.immutable = 1; + e->flags.virtual = 1; + e->flags.synthetic = 1; + e->flags.do_not_store = 1; + e->kvno = 1; + e->keys.len = 0; + e->keys.val = NULL; + e->created_by.time = time(NULL); + e->modified_by = NULL; + e->valid_start = NULL; + e->valid_end = NULL; + e->pw_end = NULL; + e->etypes = NULL; + e->generation = NULL; + e->extensions = NULL; } if (ret == 0) - ret = (e->entry.max_renew = calloc(1, sizeof(*e->entry.max_renew))) ? + ret = (e->max_renew = calloc(1, sizeof(*e->max_renew))) ? 0 : krb5_enomem(context); if (ret == 0) - ret = (e->entry.max_life = calloc(1, sizeof(*e->entry.max_life))) ? + ret = (e->max_life = calloc(1, sizeof(*e->max_life))) ? 0 : krb5_enomem(context); if (ret == 0) - ret = krb5_copy_principal(context, princ, &e->entry.principal); + ret = krb5_copy_principal(context, princ, &e->principal); if (ret == 0) - ret = krb5_copy_principal(context, princ, &e->entry.created_by.principal); + ret = krb5_copy_principal(context, princ, &e->created_by.principal); if (ret == 0) { /* * We can't check OCSP in the TGS path, so we can't let tickets for * synthetic principals live very long. */ - *(e->entry.max_renew) = config->synthetic_clients_max_renew; - *(e->entry.max_life) = config->synthetic_clients_max_life; + *(e->max_renew) = config->synthetic_clients_max_renew; + *(e->max_life) = config->synthetic_clients_max_life; *h = e; - } else { - hdb_free_entry(context, e); + } else if (e) { + hdb_free_entry(context, &null_db, e); } return ret; } -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL _kdc_db_fetch(krb5_context context, krb5_kdc_configuration *config, krb5_const_principal principal, unsigned flags, krb5uint32 *kvno_ptr, HDB **db, - hdb_entry_ex **h) + hdb_entry **h) { - hdb_entry_ex *ent = NULL; + hdb_entry *ent = NULL; krb5_error_code ret = HDB_ERR_NOENTRY; int i; unsigned kvno = 0; @@ -245,10 +245,10 @@ out: return ret; } -void -_kdc_free_ent(krb5_context context, hdb_entry_ex *ent) +KDC_LIB_FUNCTION void KDC_LIB_CALL +_kdc_free_ent(krb5_context context, HDB *db, hdb_entry *ent) { - hdb_free_entry (context, ent); + hdb_free_entry (context, db, ent); free (ent); } @@ -260,7 +260,7 @@ _kdc_free_ent(krb5_context context, hdb_entry_ex *ent) krb5_error_code _kdc_get_preferred_key(krb5_context context, krb5_kdc_configuration *config, - hdb_entry_ex *h, + hdb_entry *h, const char *name, krb5_enctype *enctype, Key **key) @@ -271,11 +271,11 @@ _kdc_get_preferred_key(krb5_context context, if (config->use_strongest_server_key) { const krb5_enctype *p = krb5_kerberos_enctypes(context); - for (i = 0; p[i] != (krb5_enctype)ETYPE_NULL; i++) { + for (i = 0; p[i] != ETYPE_NULL; i++) { if (krb5_enctype_valid(context, p[i]) != 0 && - !_kdc_is_weak_exception(h->entry.principal, p[i])) + !_kdc_is_weak_exception(h->principal, p[i])) continue; - ret = hdb_enctype2key(context, &h->entry, NULL, p[i], key); + ret = hdb_enctype2key(context, h, NULL, p[i], key); if (ret != 0) continue; if (enctype != NULL) @@ -285,12 +285,12 @@ _kdc_get_preferred_key(krb5_context context, } else { *key = NULL; - for (i = 0; i < h->entry.keys.len; i++) { - if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype) != 0 && - !_kdc_is_weak_exception(h->entry.principal, h->entry.keys.val[i].key.keytype)) + for (i = 0; i < h->keys.len; i++) { + if (krb5_enctype_valid(context, h->keys.val[i].key.keytype) != 0 && + !_kdc_is_weak_exception(h->principal, h->keys.val[i].key.keytype)) continue; - ret = hdb_enctype2key(context, &h->entry, NULL, - h->entry.keys.val[i].key.keytype, key); + ret = hdb_enctype2key(context, h, NULL, + h->keys.val[i].key.keytype, key); if (ret != 0) continue; if (enctype != NULL) @@ -336,3 +336,22 @@ _kdc_include_pac_p(astgs_request_t r) { return TRUE; } + +/* + * Notify the HDB backend and KDC plugin of the audited event. + */ + +krb5_error_code +_kdc_audit_request(astgs_request_t r) +{ + krb5_error_code ret; + struct HDB *hdb; + + ret = _kdc_plugin_audit(r); + if (ret == 0 && + (hdb = r->clientdb ? r->clientdb : r->config->db[0]) && + hdb->hdb_audit) + ret = hdb->hdb_audit(r->context, hdb, r->client, (hdb_request_t)r); + + return ret; +} diff --git a/third_party/heimdal/kdc/mit_dump.c b/third_party/heimdal/kdc/mit_dump.c index 3e4b47d7e1b9..32cf5dc65cea 100644 --- a/third_party/heimdal/kdc/mit_dump.c +++ b/third_party/heimdal/kdc/mit_dump.c @@ -146,7 +146,7 @@ mit_prop_dump(void *arg, const char *file) char *line = NULL; int lineno = 0; FILE *f; - struct hdb_entry_ex ent; + hdb_entry ent; struct prop_data *pd = arg; krb5_storage *sp = NULL; krb5_data kdb_ent; @@ -202,14 +202,14 @@ mit_prop_dump(void *arg, const char *file) } ret = krb5_storage_to_data(sp, &kdb_ent); if (ret) break; - ret = _hdb_mdb_value2entry(pd->context, &kdb_ent, 0, &ent.entry); + ret = _hdb_mdb_value2entry(pd->context, &kdb_ent, 0, &ent); krb5_data_free(&kdb_ent); if (ret) { warnx("line: %d: failed to store; ignoring", lineno); continue; } ret = v5_prop(pd->context, NULL, &ent, arg); - hdb_free_entry(pd->context, &ent); + hdb_free_entry(pd->context, NULL, &ent); /* XXX */ if (ret) break; } diff --git a/third_party/heimdal/kdc/mssfu.c b/third_party/heimdal/kdc/mssfu.c new file mode 100644 index 000000000000..9e67aad33193 --- /dev/null +++ b/third_party/heimdal/kdc/mssfu.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 1997-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 "kdc_locl.h" + +/* + * [MS-SFU] Kerberos Protocol Extensions: + * Service for User (S4U2Self) and Constrained Delegation Protocol (S4U2Proxy) + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/ + */ + +/* + * Determine if constrained delegation is allowed from this client to this server + */ + +static krb5_error_code +check_constrained_delegation(krb5_context context, + krb5_kdc_configuration *config, + HDB *clientdb, + hdb_entry *client, + hdb_entry *server, + krb5_const_principal target) +{ + const HDB_Ext_Constrained_delegation_acl *acl; + krb5_error_code ret; + size_t i; + + /* + * constrained delegation (S4U2Proxy) only works within + * the same realm. We use the already canonicalized version + * of the principals here, while "target" is the principal + * provided by the client. + */ + if (!krb5_realm_compare(context, client->principal, server->principal)) { + ret = KRB5KDC_ERR_BADOPTION; + kdc_log(context, config, 4, + "Bad request for constrained delegation"); + return ret; + } + + if (clientdb->hdb_check_constrained_delegation) { + ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target); + if (ret == 0) + return 0; + } else { + /* if client delegates to itself, that ok */ + if (krb5_principal_compare(context, client->principal, server->principal) == TRUE) + return 0; + + ret = hdb_entry_get_ConstrainedDelegACL(client, &acl); + if (ret) { + krb5_clear_error_message(context); + return ret; + } + + if (acl) { + for (i = 0; i < acl->len; i++) { + if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE) + return 0; + } + } + ret = KRB5KDC_ERR_BADOPTION; + } + kdc_log(context, config, 4, + "Bad request for constrained delegation"); + return ret; +} + +/* + * Validate a protocol transition (S4U2Self) request. If present and + * successfully validated then the client in the request structure + * will be replaced with the impersonated client. + */ + +static krb5_error_code +validate_protocol_transition(astgs_request_t r) +{ + krb5_error_code ret; + KDC_REQ_BODY *b = &r->req.req_body; + EncTicketPart *ticket = &r->ticket->ticket; + hdb_entry *s4u_client = NULL; + HDB *s4u_clientdb; + int flags = HDB_F_FOR_TGS_REQ; + krb5_principal s4u_client_name = NULL, s4u_canon_client_name = NULL; + krb5_pac s4u_pac = NULL; + const PA_DATA *sdata; + char *s4ucname = NULL; + int i = 0; + krb5_crypto crypto; + krb5_data datack; + PA_S4U2Self self; + const char *str; + + if (r->client == NULL) + return 0; + + sdata = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FOR_USER); + if (sdata == NULL) + return 0; + + memset(&self, 0, sizeof(self)); + + if (b->kdc_options.canonicalize) + flags |= HDB_F_CANON; + + ret = decode_PA_S4U2Self(sdata->padata_value.data, + sdata->padata_value.length, + &self, NULL); + if (ret) { + kdc_audit_addreason((kdc_request_t)r, + "Failed to decode PA-S4U2Self"); + kdc_log(r->context, r->config, 4, "Failed to decode PA-S4U2Self"); + goto out; + } + + if (!krb5_checksum_is_keyed(r->context, self.cksum.cksumtype)) { + kdc_audit_addreason((kdc_request_t)r, + "PA-S4U2Self with unkeyed checksum"); + kdc_log(r->context, r->config, 4, "Reject PA-S4U2Self with unkeyed checksum"); + ret = KRB5KRB_AP_ERR_INAPP_CKSUM; + goto out; + } + + ret = _krb5_s4u2self_to_checksumdata(r->context, &self, &datack); + if (ret) + goto out; + + ret = krb5_crypto_init(r->context, &ticket->key, 0, &crypto); + if (ret) { + const char *msg = krb5_get_error_message(r->context, ret); + krb5_data_free(&datack); + kdc_log(r->context, r->config, 4, "krb5_crypto_init failed: %s", msg); + krb5_free_error_message(r->context, msg); + goto out; + } + + /* Allow HMAC_MD5 checksum with any key type */ + if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) { + struct krb5_crypto_iov iov; + unsigned char csdata[16]; + Checksum cs; + + cs.checksum.length = sizeof(csdata); + cs.checksum.data = &csdata; + + iov.data.data = datack.data; + iov.data.length = datack.length; + iov.flags = KRB5_CRYPTO_TYPE_DATA; + + ret = _krb5_HMAC_MD5_checksum(r->context, NULL, &crypto->key, + KRB5_KU_OTHER_CKSUM, &iov, 1, + &cs); + if (ret == 0 && + krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } else { + ret = _kdc_verify_checksum(r->context, + crypto, + KRB5_KU_OTHER_CKSUM, + &datack, + &self.cksum); + } + krb5_data_free(&datack); + krb5_crypto_destroy(r->context, crypto); + if (ret) { + const char *msg = krb5_get_error_message(r->context, ret); + kdc_audit_addreason((kdc_request_t)r, + "S4U2Self checksum failed"); + kdc_log(r->context, r->config, 4, + "krb5_verify_checksum failed for S4U2Self: %s", msg); + krb5_free_error_message(r->context, msg); + goto out; + } + + ret = _krb5_principalname2krb5_principal(r->context, + &s4u_client_name, + self.name, + self.realm); + if (ret) + goto out; + + ret = krb5_unparse_name(r->context, s4u_client_name, &s4ucname); + if (ret) + goto out; + + /* + * Note no HDB_F_SYNTHETIC_OK -- impersonating non-existent clients + * is probably not desirable! + */ + ret = _kdc_db_fetch(r->context, r->config, s4u_client_name, + HDB_F_GET_CLIENT | flags, NULL, + &s4u_clientdb, &s4u_client); + if (ret) { + const char *msg; + + /* + * If the client belongs to the same realm as our krbtgt, it + * should exist in the local database. + * + */ + if (ret == HDB_ERR_NOENTRY) + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; + msg = krb5_get_error_message(r->context, ret); + kdc_audit_addreason((kdc_request_t)r, + "S4U2Self principal to impersonate not found"); + kdc_log(r->context, r->config, 2, + "S4U2Self principal to impersonate %s not found in database: %s", + s4ucname, msg); + krb5_free_error_message(r->context, msg); + goto out; + } + + /* + * Ignore require_pwchange and pw_end attributes (as Windows does), + * since S4U2Self is not password authentication. + */ + s4u_client->flags.require_pwchange = FALSE; + free(s4u_client->pw_end); + s4u_client->pw_end = NULL; + + ret = kdc_check_flags(r, FALSE, s4u_client, r->server); + if (ret) + goto out; /* kdc_check_flags() calls kdc_audit_addreason() */ + + ret = _kdc_pac_generate(r->context, + r->config, + s4u_client, + r->server, + NULL, + KRB5_PAC_WAS_GIVEN_IMPLICITLY, + &s4u_pac); + if (ret) { + kdc_log(r->context, r->config, 4, "PAC generation failed for -- %s", s4ucname); + goto out; + } + + /* + * Check that service doing the impersonating is + * requesting a ticket to it-self. + */ + ret = _kdc_check_client_matches_target_service(r->context, + r->config, + r->clientdb, + r->client, + r->server, + r->server_princ); + if (ret) { + kdc_log(r->context, r->config, 4, "S4U2Self: %s is not allowed " + "to impersonate to service " + "(tried for user %s to service %s)", + r->cname, s4ucname, r->sname); + goto out; + } + + ret = krb5_copy_principal(r->context, s4u_client->principal, + &s4u_canon_client_name); + if (ret) + goto out; + + /* + * If the service isn't trusted for authentication to + * delegation or if the impersonate client is disallowed + * forwardable, remove the forwardable flag. + */ + if (r->client->flags.trusted_for_delegation && + s4u_client->flags.forwardable) { + str = "[forwardable]"; + } else { + b->kdc_options.forwardable = 0; + str = ""; + } + kdc_log(r->context, r->config, 4, "s4u2self %s impersonating %s to " + "service %s %s", r->cname, s4ucname, r->sname, str); + + /* + * Replace all client information in the request with the + * impersonated client. (The audit entry containing the original + * client name will have been created before this point.) + */ + _kdc_request_set_cname_nocopy((kdc_request_t)r, &s4ucname); + _kdc_request_set_client_princ_nocopy(r, &s4u_client_name); + + _kdc_free_ent(r->context, r->clientdb, r->client); + r->client = s4u_client; + s4u_client = NULL; + r->clientdb = s4u_clientdb; + s4u_clientdb = NULL; + + _kdc_request_set_canon_client_princ_nocopy(r, &s4u_canon_client_name); + _kdc_request_set_pac_nocopy(r, &s4u_pac); + +out: + if (s4u_client) + _kdc_free_ent(r->context, s4u_clientdb, s4u_client); + krb5_free_principal(r->context, s4u_client_name); + krb5_xfree(s4ucname); + krb5_free_principal(r->context, s4u_canon_client_name); + krb5_pac_free(r->context, s4u_pac); + + free_PA_S4U2Self(&self); + + return ret; +} + +/* + * Validate a constrained delegation (S4U2Proxy) request. If present + * and successfully validated then the client in the request structure + * will be replaced with the client from the evidence ticket. + */ + +static krb5_error_code +validate_constrained_delegation(astgs_request_t r) +{ + krb5_error_code ret; + KDC_REQ_BODY *b = &r->req.req_body; + int flags = HDB_F_FOR_TGS_REQ; + krb5_principal s4u_client_name = NULL, s4u_server_name = NULL; + krb5_principal s4u_canon_client_name = NULL; + krb5_pac s4u_pac = NULL; + uint64_t s4u_pac_attributes; + char *s4ucname = NULL, *s4usname = NULL; + EncTicketPart evidence_tkt; + HDB *s4u_clientdb; + hdb_entry *s4u_client = NULL; + krb5_boolean ad_kdc_issued = FALSE; + Key *clientkey; + Ticket *t; + krb5_const_realm local_realm; + + if (r->client == NULL + || b->additional_tickets == NULL + || b->additional_tickets->len == 0 + || b->kdc_options.cname_in_addl_tkt == 0 + || b->kdc_options.enc_tkt_in_skey) + return 0; + + memset(&evidence_tkt, 0, sizeof(evidence_tkt)); + local_realm = + krb5_principal_get_comp_string(r->context, r->krbtgt->principal, 1); + + /* + * We require that the service's TGT has a PAC; this will have been + * validated prior to this function being called. + */ + if (r->pac == NULL) { + ret = KRB5KDC_ERR_BADOPTION; + kdc_audit_addreason((kdc_request_t)r, "Missing PAC"); + kdc_log(r->context, r->config, 4, + "Constrained delegation without PAC, %s/%s", + r->cname, r->sname); + goto out; + } + + t = &b->additional_tickets->val[0]; + + ret = hdb_enctype2key(r->context, r->client, + hdb_kvno2keys(r->context, r->client, + t->enc_part.kvno ? * t->enc_part.kvno : 0), + t->enc_part.etype, &clientkey); + if (ret) { + ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ + goto out; + } + + ret = krb5_decrypt_ticket(r->context, t, &clientkey->key, &evidence_tkt, 0); + if (ret) { + kdc_audit_addreason((kdc_request_t)r, + "Failed to decrypt constrained delegation ticket"); + kdc_log(r->context, r->config, 4, + "failed to decrypt ticket for " + "constrained delegation from %s to %s ", r->cname, r->sname); + goto out; + } + + ret = _krb5_principalname2krb5_principal(r->context, + &s4u_client_name, + evidence_tkt.cname, + evidence_tkt.crealm); + if (ret) + goto out; + + ret = krb5_unparse_name(r->context, s4u_client_name, &s4ucname); + if (ret) + goto out; + + kdc_audit_addkv((kdc_request_t)r, 0, "impersonatee", "%s", s4ucname); + + ret = _krb5_principalname2krb5_principal(r->context, + &s4u_server_name, + t->sname, + t->realm); + if (ret) + goto out; + + ret = krb5_unparse_name(r->context, s4u_server_name, &s4usname); + if (ret) + goto out; + + /* check that ticket is valid */ + if (evidence_tkt.flags.forwardable == 0) { + kdc_audit_addreason((kdc_request_t)r, + "Missing forwardable flag on ticket for constrained delegation"); + kdc_log(r->context, r->config, 4, + "Missing forwardable flag on ticket for " + "constrained delegation from %s (%s) as %s to %s ", + r->cname, s4usname, s4ucname, r->sname); + ret = KRB5KDC_ERR_BADOPTION; + goto out; + } + + ret = check_constrained_delegation(r->context, r->config, r->clientdb, + r->client, r->server, r->server_princ); + if (ret) { + kdc_audit_addreason((kdc_request_t)r, + "Constrained delegation not allowed"); + kdc_log(r->context, r->config, 4, + "constrained delegation from %s (%s) as %s to %s not allowed", + r->cname, s4usname, s4ucname, r->sname); + goto out; + } + + ret = _kdc_verify_flags(r->context, r->config, &evidence_tkt, s4ucname); + if (ret) { + kdc_audit_addreason((kdc_request_t)r, + "Constrained delegation ticket expired or invalid"); + goto out; + } + + /* Try lookup the delegated client in DB */ + ret = _kdc_db_fetch_client(r->context, r->config, flags, + s4u_client_name, s4ucname, local_realm, + &s4u_clientdb, &s4u_client); + if (ret) + goto out; + + if (s4u_client != NULL) { + ret = kdc_check_flags(r, FALSE, s4u_client, r->server); + if (ret) + goto out; + } + + /* + * TODO: pass in t->sname and t->realm and build + * a S4U_DELEGATION_INFO blob to the PAC. + */ + ret = _kdc_check_pac(r->context, r->config, s4u_client_name, s4u_server_name, + s4u_client, r->server, r->krbtgt, r->client, + &clientkey->key, &r->ticket_key->key, &evidence_tkt, + &ad_kdc_issued, &s4u_pac, + &s4u_canon_client_name, &s4u_pac_attributes); + if (ret) { + const char *msg = krb5_get_error_message(r->context, ret); + kdc_audit_addreason((kdc_request_t)r, + "Constrained delegation ticket PAC check failed"); + kdc_log(r->context, r->config, 4, + "Verify delegated PAC failed to %s for client" + "%s (%s) as %s from %s with %s", + r->sname, r->cname, s4usname, s4ucname, r->from, msg); + krb5_free_error_message(r->context, msg); + goto out; + } + + if (s4u_pac == NULL || !ad_kdc_issued) { + ret = KRB5KDC_ERR_BADOPTION; + kdc_log(r->context, r->config, 4, + "Ticket not signed with PAC; service %s failed for " + "for delegation to %s for client %s (%s) from %s; (%s).", + r->sname, s4ucname, s4usname, r->cname, r->from, + s4u_pac ? "Ticket unsigned" : "No PAC"); + kdc_audit_addreason((kdc_request_t)r, + "Constrained delegation ticket not signed"); + goto out; + } + + /* + * If the evidence ticket PAC didn't include PAC_UPN_DNS_INFO with + * the canonical client name, but the user is local to our KDC, we + * can insert the canonical client name ourselves. + */ + if (s4u_canon_client_name == NULL && s4u_client != NULL) { + ret = krb5_copy_principal(r->context, s4u_client->principal, + &s4u_canon_client_name); + if (ret) + goto out; + } + + kdc_log(r->context, r->config, 4, "constrained delegation for %s " + "from %s (%s) to %s", s4ucname, r->cname, s4usname, r->sname); + + /* + * Replace all client information in the request with the + * impersonated client. (The audit entry containing the original + * client name will have been created before this point.) + */ + _kdc_request_set_cname_nocopy((kdc_request_t)r, &s4ucname); + _kdc_request_set_client_princ_nocopy(r, &s4u_client_name); + + _kdc_free_ent(r->context, r->clientdb, r->client); + r->client = s4u_client; + s4u_client = NULL; + r->clientdb = s4u_clientdb; + s4u_clientdb = NULL; + + _kdc_request_set_canon_client_princ_nocopy(r, &s4u_canon_client_name); + _kdc_request_set_pac_nocopy(r, &s4u_pac); + + r->pac_attributes = s4u_pac_attributes; + +out: + if (s4u_client) + _kdc_free_ent(r->context, s4u_clientdb, s4u_client); + krb5_free_principal(r->context, s4u_client_name); + krb5_xfree(s4ucname); + krb5_free_principal(r->context, s4u_server_name); + krb5_xfree(s4usname); + krb5_free_principal(r->context, s4u_canon_client_name); + krb5_pac_free(r->context, s4u_pac); + + free_EncTicketPart(&evidence_tkt); + + return ret; +} + +/* + * + */ + +krb5_error_code +_kdc_validate_services_for_user(astgs_request_t r) +{ + krb5_error_code ret; + + ret = validate_protocol_transition(r); + if (ret == 0) + ret = validate_constrained_delegation(r); + + return ret; +} diff --git a/third_party/heimdal/kdc/negotiate_token_validator.c b/third_party/heimdal/kdc/negotiate_token_validator.c index ad5db1e3ca46..20250c6dc897 100644 --- a/third_party/heimdal/kdc/negotiate_token_validator.c +++ b/third_party/heimdal/kdc/negotiate_token_validator.c @@ -304,8 +304,6 @@ negotiate_get_instance(const char *libname) { if (strcmp(libname, "krb5") == 0) return krb5_get_instance(libname); - else if (strcmp(libname, "gssapi") == 0) - return gss_get_instance(libname); return 0; } diff --git a/third_party/heimdal/kdc/pkinit.c b/third_party/heimdal/kdc/pkinit.c index b355e4c8830b..f01178983f3c 100644 --- a/third_party/heimdal/kdc/pkinit.c +++ b/third_party/heimdal/kdc/pkinit.c @@ -231,8 +231,6 @@ generate_dh_keyblock(krb5_context context, memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen); memset(dh_gen_key, 0, size); } - - ret = 0; } else if (client_params->keyex == USE_ECDH) { if (client_params->u.ecdh.public_key == NULL) { ret = KRB5KRB_ERR_GENERIC; @@ -390,7 +388,7 @@ _kdc_pk_rd_padata(astgs_request_t priv, krb5_context context = priv->context; krb5_kdc_configuration *config = priv->config; const KDC_REQ *req = &priv->req; - hdb_entry_ex *client = priv->client; + hdb_entry *client = priv->client; pk_client_params *cp; krb5_error_code ret; heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL }; @@ -433,7 +431,7 @@ _kdc_pk_rd_padata(astgs_request_t priv, } /* Add any registered certificates for this client as trust anchors */ - ret = hdb_entry_get_pkinit_cert(&client->entry, &pc); + ret = hdb_entry_get_pkinit_cert(client, &pc); if (ret == 0 && pc != NULL) { hx509_cert cert; unsigned int i; @@ -469,7 +467,7 @@ _kdc_pk_rd_padata(astgs_request_t priv, type = "PK-INIT-Win2k"; - if (_kdc_is_anonymous(context, client->entry.principal)) { + if (_kdc_is_anonymous(context, client->principal)) { ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; krb5_set_error_message(context, ret, "Anonymous client not supported in RSA mode"); @@ -615,7 +613,7 @@ _kdc_pk_rd_padata(astgs_request_t priv, hx509_certs signer_certs; int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */ - if (_kdc_is_anonymous(context, client->entry.principal) + if (_kdc_is_anonymous(context, client->principal) || (config->historical_anon_realm && _kdc_is_anon_request(req))) flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER; @@ -701,7 +699,7 @@ _kdc_pk_rd_padata(astgs_request_t priv, goto out; } - if (_kdc_is_anonymous(context, client->entry.principal) && + if (_kdc_is_anonymous(context, client->principal) && ap.clientPublicValue == NULL) { free_AuthPack(&ap); ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; @@ -1600,7 +1598,7 @@ match_ms_upn_san(krb5_context context, hx509_context hx509ctx, hx509_cert client_cert, HDB *clientdb, - hdb_entry_ex *client) + hdb_entry *client) { hx509_octet_string_list list; krb5_principal principal = NULL; @@ -1654,7 +1652,7 @@ match_ms_upn_san(krb5_context context, */ strupr(principal->realm); - if (krb5_principal_compare(context, principal, client->entry.principal) == FALSE) + if (krb5_principal_compare(context, principal, client->principal) == FALSE) ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; } @@ -1673,7 +1671,7 @@ _kdc_pk_check_client(astgs_request_t r, { krb5_kdc_configuration *config = r->config; HDB *clientdb = r->clientdb; - hdb_entry_ex *client = r->client; + hdb_entry *client = r->client; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_PKINIT_cert *pc; krb5_error_code ret; @@ -1681,7 +1679,7 @@ _kdc_pk_check_client(astgs_request_t r, size_t i; if (cp->cert == NULL) { - if (!_kdc_is_anonymous(r->context, client->entry.principal) + if (!_kdc_is_anonymous(r->context, client->principal) && !config->historical_anon_realm) return KRB5KDC_ERR_BADOPTION; @@ -1718,7 +1716,7 @@ _kdc_pk_check_client(astgs_request_t r, "Trying to authorize PKINIT subject DN %s", *subject_name); - ret = hdb_entry_get_pkinit_cert(&client->entry, &pc); + ret = hdb_entry_get_pkinit_cert(client, &pc); if (ret == 0 && pc) { hx509_cert cert; size_t j; @@ -1745,7 +1743,7 @@ _kdc_pk_check_client(astgs_request_t r, ret = match_rfc_san(r->context, config, r->context->hx509ctx, cp->cert, - client->entry.principal); + client->principal); if (ret == 0) { kdc_log(r->context, config, 5, "Found matching PKINIT SAN in certificate"); @@ -1763,7 +1761,7 @@ _kdc_pk_check_client(astgs_request_t r, } } - ret = hdb_entry_get_pkinit_acl(&client->entry, &acl); + ret = hdb_entry_get_pkinit_acl(client, &acl); if (ret == 0 && acl != NULL) { /* * Cheat here and compare the generated name with the string @@ -1789,7 +1787,7 @@ _kdc_pk_check_client(astgs_request_t r, krb5_boolean b; b = krb5_principal_compare(r->context, - client->entry.principal, + client->principal, principal_mappings.val[i].principal); if (b == FALSE) continue; @@ -1926,7 +1924,7 @@ load_mappings(krb5_context context, const char *fn) * */ -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL krb5_kdc_pk_initialize(krb5_context context, krb5_kdc_configuration *config, const char *user_id, diff --git a/third_party/heimdal/kdc/process.c b/third_party/heimdal/kdc/process.c index 23a0fe0102d0..cf8ab060ec96 100644 --- a/third_party/heimdal/kdc/process.c +++ b/third_party/heimdal/kdc/process.c @@ -42,15 +42,15 @@ #undef __attribute__ #define __attribute__(x) -void -_kdc_audit_vaddreason(kdc_request_t r, const char *fmt, va_list ap) +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_vaddreason(kdc_request_t r, const char *fmt, va_list ap) __attribute__ ((__format__ (__printf__, 2, 0))) { heim_audit_vaddreason((heim_svc_req_desc)r, fmt, ap); } -void -_kdc_audit_addreason(kdc_request_t r, const char *fmt, ...) +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_addreason(kdc_request_t r, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))) { va_list ap; @@ -66,16 +66,16 @@ _kdc_audit_addreason(kdc_request_t r, const char *fmt, ...) * not a kv-pair. */ -void -_kdc_audit_vaddkv(kdc_request_t r, int flags, const char *k, +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_vaddkv(kdc_request_t r, int flags, const char *k, const char *fmt, va_list ap) __attribute__ ((__format__ (__printf__, 4, 0))) { heim_audit_vaddkv((heim_svc_req_desc)r, flags, k, fmt, ap); } -void -_kdc_audit_addkv(kdc_request_t r, int flags, const char *k, +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_addkv(kdc_request_t r, int flags, const char *k, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 4, 5))) { @@ -86,20 +86,56 @@ _kdc_audit_addkv(kdc_request_t r, int flags, const char *k, va_end(ap); } -void -_kdc_audit_addkv_timediff(kdc_request_t r, const char *k, +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_addkv_timediff(kdc_request_t r, const char *k, const struct timeval *start, const struct timeval *end) { heim_audit_addkv_timediff((heim_svc_req_desc)r,k, start, end); } +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_setkv_bool(kdc_request_t r, const char *k, krb5_boolean v) +{ + heim_audit_setkv_bool((heim_svc_req_desc)r, k, (int)v); +} + +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_addkv_number(kdc_request_t r, const char *k, int64_t v) +{ + heim_audit_addkv_number((heim_svc_req_desc)r, k, v); +} + +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_setkv_number(kdc_request_t r, const char *k, int64_t v) +{ + heim_audit_setkv_number((heim_svc_req_desc)r, k, v); +} + +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_addkv_object(kdc_request_t r, const char *k, kdc_object_t obj) +{ + heim_audit_addkv_object((heim_svc_req_desc)r, k, obj); +} + +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_setkv_object(kdc_request_t r, const char *k, kdc_object_t obj) +{ + heim_audit_setkv_object((heim_svc_req_desc)r, k, obj); +} + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_audit_getkv(kdc_request_t r, const char *k) +{ + return heim_audit_getkv((heim_svc_req_desc)r, k); +} + /* * Add up to 3 key value pairs to record HostAddresses from request body or * PA-TGS ticket or whatever. */ -void -_kdc_audit_addaddrs(kdc_request_t r, HostAddresses *a, const char *key) +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_audit_addaddrs(kdc_request_t r, HostAddresses *a, const char *key) { size_t i; char buf[128]; @@ -109,23 +145,23 @@ _kdc_audit_addaddrs(kdc_request_t r, HostAddresses *a, const char *key) if (snprintf(numkey, sizeof(numkey), "num%s", key) >= sizeof(numkey)) numkey[31] = '\0'; - _kdc_audit_addkv(r, 0, numkey, "%llu", (unsigned long long)a->len); + kdc_audit_addkv(r, 0, numkey, "%llu", (unsigned long long)a->len); } for (i = 0; i < 3 && i < a->len; i++) { if (krb5_print_address(&a->val[i], buf, sizeof(buf), NULL) == 0) - _kdc_audit_addkv(r, 0, key, "%s", buf); + kdc_audit_addkv(r, 0, key, "%s", buf); } } -void +KDC_LIB_FUNCTION void KDC_LIB_CALL _kdc_audit_trail(kdc_request_t r, krb5_error_code ret) { const char *retname = NULL; /* Get a symbolic name for some error codes */ #define CASE(x) case x : retname = #x; break - switch (ret ? ret : r->ret) { + switch (ret ? ret : r->error_code) { CASE(ENOMEM); CASE(EACCES); CASE(HDB_ERR_NOT_FOUND_HERE); @@ -171,7 +207,7 @@ _kdc_audit_trail(kdc_request_t r, krb5_error_code ret) heim_audit_trail((heim_svc_req_desc)r, ret, retname); } -void +KDC_LIB_FUNCTION void KDC_LIB_CALL krb5_kdc_update_time(struct timeval *tv) { if (tv == NULL) @@ -334,8 +370,11 @@ process_request(krb5_context context, r->request.length = len; r->datagram_reply = datagram_reply; r->reply = reply; - r->kv = heim_array_create(); - if (!r->kv) { + r->kv = heim_dict_create(10); + r->attributes = heim_dict_create(1); + if (r->kv == NULL || r->attributes == NULL) { + heim_release(r->kv); + heim_release(r->attributes); free(r); return krb5_enomem(context); } @@ -361,6 +400,7 @@ process_request(krb5_context context, heim_release(r->reason); heim_release(r->kv); + heim_release(r->attributes); free(r); return ret; } @@ -368,6 +408,7 @@ process_request(krb5_context context, heim_release(r->reason); heim_release(r->kv); + heim_release(r->attributes); free(r); return -1; } @@ -377,7 +418,7 @@ process_request(krb5_context context, * sending a reply in `reply'. */ -int +KDC_LIB_FUNCTION int KDC_LIB_CALL krb5_kdc_process_request(krb5_context context, krb5_kdc_configuration *config, unsigned char *buf, @@ -399,7 +440,7 @@ krb5_kdc_process_request(krb5_context context, * This only processes krb5 requests */ -int +KDC_LIB_FUNCTION int KDC_LIB_CALL krb5_kdc_process_krb5_request(krb5_context context, krb5_kdc_configuration *config, unsigned char *buf, @@ -418,7 +459,7 @@ krb5_kdc_process_krb5_request(krb5_context context, * */ -int +KDC_LIB_FUNCTION int KDC_LIB_CALL krb5_kdc_save_request(krb5_context context, const char *fn, const unsigned char *buf, @@ -428,56 +469,109 @@ krb5_kdc_save_request(krb5_context context, { krb5_storage *sp; krb5_address a; - int fd, ret; + int fd = -1; + int ret = 0; uint32_t t; krb5_data d; memset(&a, 0, sizeof(a)); - d.data = rk_UNCONST(buf); + d.data = rk_UNCONST(buf); /* do not free here */ d.length = len; t = _kdc_now.tv_sec; - fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600); - if (fd < 0) { - int saved_errno = errno; - krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn); - return saved_errno; - } - - sp = krb5_storage_from_fd(fd); - close(fd); - if (sp == NULL) { - krb5_set_error_message(context, ENOMEM, "Storage failed to open fd"); - return ENOMEM; - } - - ret = krb5_sockaddr2address(context, sa, &a); - if (ret) - goto out; - - krb5_store_uint32(sp, 1); - krb5_store_uint32(sp, t); - krb5_store_address(sp, a); - krb5_store_data(sp, d); - { + sp = krb5_storage_emem(); + if (sp == NULL) + ret = krb5_enomem(context); + + if (ret == 0) + ret = krb5_sockaddr2address(context, sa, &a); + if (ret == 0) + ret = krb5_store_uint32(sp, 1); + if (ret == 0) + ret = krb5_store_uint32(sp, t); + if (ret == 0) + ret = krb5_store_address(sp, a); + if (ret == 0) + ret = krb5_store_data(sp, d); + d.length = 0; + d.data = NULL; + if (ret == 0) { Der_class cl; Der_type ty; unsigned int tag; ret = der_get_tag (reply->data, reply->length, &cl, &ty, &tag, NULL); if (ret) { - krb5_store_uint32(sp, 0xffffffff); - krb5_store_uint32(sp, 0xffffffff); - } else { - krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0)); - krb5_store_uint32(sp, tag); + ret = krb5_store_uint32(sp, 0xffffffff); + if (ret == 0) + ret = krb5_store_uint32(sp, 0xffffffff); + } else { + ret = krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0)); + if (ret == 0) + ret = krb5_store_uint32(sp, tag); } } - krb5_free_address(context, &a); -out: + if (ret == 0) + ret = krb5_storage_to_data(sp, &d); krb5_storage_free(sp); + sp = NULL; + + /* + * We've got KDC concurrency, so we're going to try to do a single O_APPEND + * write(2). Hopefully we manage to write enough of the header that one + * can skip this request if it fails to write completely. + */ + if (ret == 0) + fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600); + if (fd < 0) + krb5_set_error_message(context, ret = errno, "Failed to open: %s", fn); + if (ret == 0) { + sp = krb5_storage_from_fd(fd); + if (sp == NULL) + krb5_set_error_message(context, ret = ENOMEM, + "Storage failed to open fd"); + } + (void) close(fd); + if (ret == 0) + ret = krb5_store_data(sp, d); + krb5_free_address(context, &a); + /* + * krb5_storage_free() currently always returns 0, but for FDs it sets + * errno to whatever close() set it to if it failed. + */ + errno = 0; + if (ret == 0) + ret = krb5_storage_free(sp); + else + (void) krb5_storage_free(sp); + if (ret == 0 && errno) + ret = errno; + + return ret; +} - return 0; +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL +kdc_request_set_attribute(kdc_request_t r, kdc_object_t key, kdc_object_t value) +{ + return heim_dict_set_value(r->attributes, key, value); +} + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_request_get_attribute(kdc_request_t r, kdc_object_t key) +{ + return heim_dict_get_value(r->attributes, key); +} + +KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL +kdc_request_copy_attribute(kdc_request_t r, kdc_object_t key) +{ + return heim_dict_copy_value(r->attributes, key); +} + +KDC_LIB_FUNCTION void KDC_LIB_CALL +kdc_request_delete_attribute(kdc_request_t r, kdc_object_t key) +{ + heim_dict_delete_key(r->attributes, key); } diff --git a/third_party/heimdal/kdc/set_dbinfo.c b/third_party/heimdal/kdc/set_dbinfo.c index 93ded4ec2ae8..683eaaf7be4c 100644 --- a/third_party/heimdal/kdc/set_dbinfo.c +++ b/third_party/heimdal/kdc/set_dbinfo.c @@ -64,7 +64,7 @@ add_db(krb5_context context, struct krb5_kdc_configuration *c, return 0; } -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL krb5_kdc_set_dbinfo(krb5_context context, struct krb5_kdc_configuration *c) { struct hdb_dbinfo *info, *d; diff --git a/third_party/heimdal/kdc/simple_csr_authorizer.c b/third_party/heimdal/kdc/simple_csr_authorizer.c index 1ae9efd676cb..2300eb53299d 100644 --- a/third_party/heimdal/kdc/simple_csr_authorizer.c +++ b/third_party/heimdal/kdc/simple_csr_authorizer.c @@ -157,6 +157,13 @@ string_encode(const char *in) return s; } +static void +frees(char **s) +{ + free(*s); + *s = NULL; +} + static KRB5_LIB_CALL krb5_error_code authorize(void *ctx, krb5_context context, @@ -228,17 +235,19 @@ authorize(void *ctx, if ((san = string_encode(s)) == NULL || asprintf(&p, "%s/%s/%s-%s", d, princ, prefix, san) == -1 || - p == NULL) + p == NULL) { + free(san); goto enomem; + } ret = stat(p, &st) == -1 ? errno : 0; free(san); free(p); - free(s); - s = NULL; + frees(&s); if (ret) goto skip; ret = hx509_request_authorize_san(csr, i); } + frees(&s); if (ret == HX509_NO_ITEM) ret = 0; if (ret) @@ -251,14 +260,11 @@ authorize(void *ctx, ret = hx509_request_get_eku(csr, i, &s); if (ret) break; - if (asprintf(&p, "%s/%s/eku-%s", d, princ, s) == -1 || p == NULL) { - free(princ); - free(s); - } + if (asprintf(&p, "%s/%s/eku-%s", d, princ, s) == -1 || p == NULL) + goto enomem; ret = stat(p, &st) == -1 ? errno : 0; free(p); - free(s); - s = NULL; + frees(&s); if (ret) goto skip; ret = hx509_request_authorize_eku(csr, i); diff --git a/third_party/heimdal/kdc/string2key.c b/third_party/heimdal/kdc/string2key.c index 1b603dece58d..4b9c62e5a5d0 100644 --- a/third_party/heimdal/kdc/string2key.c +++ b/third_party/heimdal/kdc/string2key.c @@ -128,9 +128,9 @@ main(int argc, char **argv) if(ret) krb5_err(context, 1, ret, "krb5_string_to_enctype"); - if((etype != (krb5_enctype)ETYPE_DES_CBC_CRC && - etype != (krb5_enctype)ETYPE_DES_CBC_MD4 && - etype != (krb5_enctype)ETYPE_DES_CBC_MD5) && + if((etype != ETYPE_DES_CBC_CRC && + etype != ETYPE_DES_CBC_MD4 && + etype != ETYPE_DES_CBC_MD5) && (afs || version4)) { if(!version5) { etype = ETYPE_DES_CBC_CRC; diff --git a/third_party/heimdal/kdc/test_kdc_ca.c b/third_party/heimdal/kdc/test_kdc_ca.c index 12b873c039b7..4d80c96a034a 100644 --- a/third_party/heimdal/kdc/test_kdc_ca.c +++ b/third_party/heimdal/kdc/test_kdc_ca.c @@ -137,8 +137,9 @@ main(int argc, char **argv) if (ret == 0) hx509_request_authorize_san(req, i); } - if (ret == HX509_NO_ITEM) - ret = 0; + if (ret && ret != HX509_NO_ITEM) + krb5_err(context, 1, ret, + "Failed to mark requested extensions authorized"); } else if ((ret = kdc_authorize_csr(context, app_string, req, p))) { krb5_err(context, 1, ret, "Requested certificate extensions rejected by policy"); diff --git a/third_party/heimdal/kdc/token_validator.c b/third_party/heimdal/kdc/token_validator.c index cdb50e47752c..858fdfa7b214 100644 --- a/third_party/heimdal/kdc/token_validator.c +++ b/third_party/heimdal/kdc/token_validator.c @@ -78,7 +78,7 @@ static struct heim_plugin_data token_validator_data = { * Invoke a plugin to validate a JWT/SAML/OIDC token and partially-evaluate * access control. */ -krb5_error_code +KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL kdc_validate_token(krb5_context context, const char *realm, const char *token_kind, diff --git a/third_party/heimdal/kdc/version-script.map b/third_party/heimdal/kdc/version-script.map index 4b27e6943ccc..9067bb6e43f4 100644 --- a/third_party/heimdal/kdc/version-script.map +++ b/third_party/heimdal/kdc/version-script.map @@ -11,7 +11,7 @@ HEIMDAL_KDC_1.0 { kdc_openlog; kdc_check_flags; kdc_validate_token; - krb5_kdc_windc_init; + krb5_kdc_plugin_init; krb5_kdc_get_config; krb5_kdc_pkinit_config; krb5_kdc_set_dbinfo; @@ -20,12 +20,80 @@ HEIMDAL_KDC_1.0 { krb5_kdc_save_request; krb5_kdc_update_time; krb5_kdc_pk_initialize; - _kdc_audit_addkv; - _kdc_audit_addreason; - _kdc_audit_vaddkv; - _kdc_audit_vaddreason; + kdc_request_set_attribute; + kdc_request_get_attribute; + kdc_request_copy_attribute; + kdc_request_delete_attribute; + kdc_request_add_encrypted_padata; + kdc_request_add_pac_buffer; + kdc_request_add_reply_padata; + kdc_request_get_addr; + kdc_request_get_canon_client_princ; + kdc_request_get_client; + kdc_request_get_clientdb; + kdc_request_get_client_princ; + kdc_request_get_context; + kdc_request_get_config; + kdc_request_get_cname; + kdc_request_get_error_code; + kdc_request_get_from; + kdc_request_get_krbtgt; + kdc_request_get_krbtgtdb; + kdc_request_get_krbtgt_princ; + kdc_request_get_pac; + kdc_request_get_pac_attributes; + kdc_request_get_rep; + kdc_request_get_reply_key; + kdc_request_get_req; + kdc_request_get_request; + kdc_request_get_server; + kdc_request_get_serverdb; + kdc_request_get_server_princ; + kdc_request_get_sname; + kdc_request_get_ticket; + kdc_request_get_tv_end; + kdc_request_get_tv_start; + kdc_request_set_canon_client_princ; + kdc_request_set_client_princ; + kdc_request_set_cname; + kdc_request_set_error_code; + kdc_request_set_krbtgt_princ; + kdc_request_set_pac; + kdc_request_set_pac_attributes; + kdc_request_set_rep; + kdc_request_set_reply_key; + kdc_request_set_server_princ; + kdc_request_set_sname; + kdc_audit_addkv; + kdc_audit_addkv_number; + kdc_audit_addkv_object; + kdc_audit_addkv_timediff; + kdc_audit_addaddrs; + kdc_audit_addreason; + kdc_audit_getkv; + kdc_audit_setkv_bool; + kdc_audit_setkv_number; + kdc_audit_setkv_object; + kdc_audit_vaddkv; + kdc_audit_vaddreason; _kdc_audit_trail; + kdc_object_alloc; + kdc_object_retain; + kdc_object_release; + kdc_bool_create; + kdc_bool_get_value; + kdc_array_iterate; + kdc_array_get_length; + kdc_array_get_value; + kdc_array_copy_value; + kdc_string_create; + kdc_string_get_utf8; + kdc_data_create; + kdc_data_get_data; + kdc_number_create; + kdc_number_get_value; + # needed for digest-service _kdc_db_fetch; _kdc_free_ent; diff --git a/third_party/heimdal/kdc/windc.c b/third_party/heimdal/kdc/windc.c deleted file mode 100644 index eb834cd6cfdd..000000000000 --- a/third_party/heimdal/kdc/windc.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "kdc_locl.h" - -static int have_plugin = 0; - -/* - * Pick the first WINDC module that we find. - */ - -static const char *windc_plugin_deps[] = { - "kdc", - "krb5", - "hdb", - NULL -}; - -static struct heim_plugin_data windc_plugin_data = { - "krb5", - "windc", - KRB5_WINDC_PLUGIN_MINOR, - windc_plugin_deps, - kdc_get_instance -}; - -static krb5_error_code KRB5_LIB_CALL -load(krb5_context context, const void *plug, void *plugctx, void *userctx) -{ - have_plugin = 1; - return KRB5_PLUGIN_NO_HANDLE; -} - -krb5_error_code -krb5_kdc_windc_init(krb5_context context) -{ - (void)_krb5_plugin_run_f(context, &windc_plugin_data, 0, NULL, load); - - return 0; -} - -struct generate_uc { - hdb_entry_ex *client; - hdb_entry_ex *server; - const krb5_keyblock *reply_key; - uint64_t pac_attributes; - krb5_pac *pac; -}; - -static krb5_error_code KRB5_LIB_CALL -generate(krb5_context context, const void *plug, void *plugctx, void *userctx) -{ - krb5plugin_windc_ftable *ft = (krb5plugin_windc_ftable *)plug; - struct generate_uc *uc = (struct generate_uc *)userctx; - - if (ft->pac_generate == NULL) - return KRB5_PLUGIN_NO_HANDLE; - - return ft->pac_generate((void *)plug, context, - uc->client, - uc->server, - uc->reply_key, - uc->pac_attributes, - uc->pac); -} - - -krb5_error_code -_kdc_pac_generate(krb5_context context, - hdb_entry_ex *client, - hdb_entry_ex *server, - const krb5_keyblock *reply_key, - uint64_t pac_attributes, - krb5_pac *pac) -{ - krb5_error_code ret = 0; - struct generate_uc uc; - - *pac = NULL; - - if (krb5_config_get_bool_default(context, NULL, FALSE, "realms", - client->entry.principal->realm, - "disable_pac", NULL)) - return 0; - - if (have_plugin) { - uc.client = client; - uc.server = server; - uc.reply_key = reply_key; - uc.pac = pac; - uc.pac_attributes = pac_attributes; - - ret = _krb5_plugin_run_f(context, &windc_plugin_data, - 0, &uc, generate); - if (ret != KRB5_PLUGIN_NO_HANDLE) - return ret; - ret = 0; - } - - if (*pac == NULL) - ret = krb5_pac_init(context, pac); - - return ret; -} - -struct verify_uc { - krb5_principal client_principal; - krb5_principal delegated_proxy_principal; - hdb_entry_ex *client; - hdb_entry_ex *server; - hdb_entry_ex *krbtgt; - krb5_pac *pac; -}; - -static krb5_error_code KRB5_LIB_CALL -verify(krb5_context context, const void *plug, void *plugctx, void *userctx) -{ - krb5plugin_windc_ftable *ft = (krb5plugin_windc_ftable *)plug; - struct verify_uc *uc = (struct verify_uc *)userctx; - krb5_error_code ret; - - if (ft->pac_verify == NULL) - return KRB5_PLUGIN_NO_HANDLE; - - ret = ft->pac_verify((void *)plug, context, - uc->client_principal, - uc->delegated_proxy_principal, - uc->client, uc->server, uc->krbtgt, uc->pac); - return ret; -} - -krb5_error_code -_kdc_pac_verify(krb5_context context, - const krb5_principal client_principal, - const krb5_principal delegated_proxy_principal, - hdb_entry_ex *client, - hdb_entry_ex *server, - hdb_entry_ex *krbtgt, - krb5_pac *pac) -{ - struct verify_uc uc; - - if (!have_plugin) - return KRB5_PLUGIN_NO_HANDLE; - - uc.client_principal = client_principal; - uc.delegated_proxy_principal = delegated_proxy_principal; - uc.client = client; - uc.server = server; - uc.krbtgt = krbtgt; - uc.pac = pac; - - return _krb5_plugin_run_f(context, &windc_plugin_data, - 0, &uc, verify); -} - -static krb5_error_code KRB5_LIB_CALL -check(krb5_context context, const void *plug, void *plugctx, void *userctx) -{ - krb5plugin_windc_ftable *ft = (krb5plugin_windc_ftable *)plug; - - if (ft->client_access == NULL) - return KRB5_PLUGIN_NO_HANDLE; - return ft->client_access((void *)plug, userctx); -} - -krb5_error_code -_kdc_check_access(astgs_request_t r) -{ - krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE; - - if (have_plugin) { - ret = _krb5_plugin_run_f(r->context, &windc_plugin_data, - 0, r, check); - } - - if (ret == KRB5_PLUGIN_NO_HANDLE) - return kdc_check_flags(r, r->req.msg_type == krb_as_req, - r->client, r->server); - return ret; -} - -static krb5_error_code KRB5_LIB_CALL -finalize(krb5_context context, const void *plug, void *plugctx, void *userctx) -{ - krb5plugin_windc_ftable *ft = (krb5plugin_windc_ftable *)plug; - - if (ft->finalize_reply == NULL) - return KRB5_PLUGIN_NO_HANDLE; - return ft->finalize_reply((void *)plug, (astgs_request_t)userctx); -} - -krb5_error_code -_kdc_finalize_reply(astgs_request_t r) -{ - krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE; - - if (have_plugin) - ret = _krb5_plugin_run_f(r->context, &windc_plugin_data, 0, r, finalize); - - if (ret == KRB5_PLUGIN_NO_HANDLE) - ret = 0; - - return ret; -} - -uintptr_t KRB5_CALLCONV -kdc_get_instance(const char *libname) -{ - static const char *instance = "libkdc"; - - if (strcmp(libname, "kdc") == 0) - return (uintptr_t)instance; - else if (strcmp(libname, "hdb") == 0) - return hdb_get_instance(libname); - else if (strcmp(libname, "krb5") == 0) - return krb5_get_instance(libname); - else if (strcmp(libname, "gssapi") == 0) - return gss_get_instance(libname); - - return 0; -} diff --git a/third_party/heimdal/kdc/windc_plugin.h b/third_party/heimdal/kdc/windc_plugin.h deleted file mode 100644 index ae0c6d181ea3..000000000000 --- a/third_party/heimdal/kdc/windc_plugin.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/* $Id$ */ - -#ifndef HEIMDAL_KDC_WINDC_PLUGIN_H -#define HEIMDAL_KDC_WINDC_PLUGIN_H 1 - -#include -#include - -/* - * The PAC generate function should allocate a krb5_pac using - * krb5_pac_init and fill in the PAC structure for the principal using - * krb5_pac_add_buffer. - * - * The PAC verify function should verify the PAC KDC signatures by fetching - * the right KDC key and calling krb5_pac_verify() with that KDC key. - * Optionally, update the PAC buffers upon success. - * - * Check client access function check if the client is authorized. - */ - -struct hdb_entry_ex; - -typedef krb5_error_code -(KRB5_CALLCONV *krb5plugin_windc_pac_generate)(void *, krb5_context, - struct hdb_entry_ex *, /* client */ - struct hdb_entry_ex *, /* server */ - const krb5_keyblock *, /* pk_replykey */ - uint64_t, /* pac_attributes */ - krb5_pac *); - -typedef krb5_error_code -(KRB5_CALLCONV *krb5plugin_windc_pac_verify)(void *, krb5_context, - const krb5_principal, /* new ticket client */ - const krb5_principal, /* delegation proxy */ - struct hdb_entry_ex *,/* client */ - struct hdb_entry_ex *,/* server */ - struct hdb_entry_ex *,/* krbtgt */ - krb5_pac *); - -typedef krb5_error_code -(KRB5_CALLCONV *krb5plugin_windc_client_access)(void *, astgs_request_t); - -typedef krb5_error_code -(KRB5_CALLCONV *krb5plugin_windc_finalize_reply)(void *, astgs_request_t r); - -#define KRB5_WINDC_PLUGIN_MINOR 8 -#define KRB5_WINDC_PLUGING_MINOR KRB5_WINDC_PLUGIN_MINOR - -typedef struct krb5plugin_windc_ftable { - int minor_version; - krb5_error_code (KRB5_CALLCONV *init)(krb5_context, void **); - void (KRB5_CALLCONV *fini)(void *); - krb5plugin_windc_pac_generate pac_generate; - krb5plugin_windc_pac_verify pac_verify; - krb5plugin_windc_client_access client_access; - krb5plugin_windc_finalize_reply finalize_reply; -} krb5plugin_windc_ftable; - -#endif /* HEIMDAL_KDC_WINDC_PLUGIN_H */ diff --git a/third_party/heimdal/kpasswd/kpasswdd.c b/third_party/heimdal/kpasswd/kpasswdd.c index 344688e296e0..e04eebe46e1f 100644 --- a/third_party/heimdal/kpasswd/kpasswdd.c +++ b/third_party/heimdal/kpasswd/kpasswdd.c @@ -406,6 +406,7 @@ change (krb5_auth_context auth_context, krb5_warnx(context, "%s didn't pass password quality check with error: %s", client, str); + break; default: krb5_warnx(context, "kadm5_s_chpass_principal_cond: %s", str); } @@ -772,6 +773,7 @@ doit(krb5_keytab keytab, int port) free(sockets); krb5_free_addresses(context, &addrs); + krb5_kt_close(context, keytab); krb5_free_context(context); return 0; } diff --git a/third_party/heimdal/kuser/generate-requests.c b/third_party/heimdal/kuser/generate-requests.c index 1196c16dc679..2dd71bf7ab8a 100644 --- a/third_party/heimdal/kuser/generate-requests.c +++ b/third_party/heimdal/kuser/generate-requests.c @@ -49,7 +49,7 @@ read_words (const char *filename, char ***ret_w) buf[strcspn(buf, "\r\n")] = '\0'; if (n >= alloc) { alloc += 16; - w = erealloc (w, alloc * sizeof(char **)); + w = erealloc (w, alloc * sizeof(*w)); } w[n++] = estrdup (buf); } diff --git a/third_party/heimdal/kuser/kgetcred.c b/third_party/heimdal/kuser/kgetcred.c index 92eb770990c5..4982f8a796a8 100644 --- a/third_party/heimdal/kuser/kgetcred.c +++ b/third_party/heimdal/kuser/kgetcred.c @@ -283,6 +283,9 @@ main(int argc, char **argv) ret = krb5_sname_to_principal(context, hname, sname, KRB5_NT_SRV_HST, &server2); + if (ret) + krb5_err(context, 1, ret, "krb5_sname_to_principal %s %s", + sname, hname); sname = krb5_principal_get_comp_string(context, server2, 0); hname = krb5_principal_get_comp_string(context, server2, 1); diff --git a/third_party/heimdal/kuser/kimpersonate.c b/third_party/heimdal/kuser/kimpersonate.c index 04a16fb6ade6..35b4295fb36d 100644 --- a/third_party/heimdal/kuser/kimpersonate.c +++ b/third_party/heimdal/kuser/kimpersonate.c @@ -82,9 +82,7 @@ encode_ticket(krb5_context context, et.flags = cred->flags.b; et.key = cred->session; et.crealm = cred->client->realm; - ret = copy_PrincipalName(&cred->client->name, &et.cname); - if (ret) - krb5_err(context, 1, ret, "copy_PrincipalName"); + et.cname = cred->client->name; { krb5_data empty_string; @@ -129,16 +127,11 @@ encode_ticket(krb5_context context, ticket.tkt_vno = 5; ticket.realm = cred->server->realm; - ret = copy_PrincipalName(&cred->server->name, &ticket.sname); - if (ret) - krb5_err(context, 1, ret, "copy_PrincipalName"); - - ASN1_MALLOC_ENCODE(Ticket, buf, len, &ticket, &size, ret); + ticket.sname = cred->server->name; + ASN1_MALLOC_ENCODE(Ticket, cred->ticket.data, cred->ticket.length, &ticket, &size, ret); + free_EncryptedData(&ticket.enc_part); if(ret) krb5_err(context, 1, ret, "encode_Ticket"); - - krb5_data_copy(&cred->ticket, buf, len); - free(buf); } /* @@ -173,12 +166,13 @@ create_krb5_tickets(krb5_context context, krb5_keytab kt) ret = krb5_copy_principal(context, client_principal, &cred.client); + if (ret == 0) + ret = krb5_copy_principal(context, server_principal, &cred.server); if (ret) krb5_err(context, 1, ret, "krb5_copy_principal"); - ret = krb5_copy_principal(context, server_principal, &cred.server); + ret = krb5_generate_random_keyblock(context, session_etype, &cred.session); if (ret) - krb5_err(context, 1, ret, "krb5_copy_principal"); - krb5_generate_random_keyblock(context, session_etype, &cred.session); + krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); cred.times.authtime = time(NULL); cred.times.starttime = time(NULL); @@ -283,13 +277,13 @@ setup_env(krb5_context context, krb5_keytab *kt) krb5_errx(context, 1, "missing client principal"); ret = krb5_parse_name(context, client_principal_str, &client_principal); if (ret) - krb5_err(context, 1, ret, "resolvning client name"); + krb5_err(context, 1, ret, "resolving client name"); if (server_principal_str == NULL) krb5_errx(context, 1, "missing server principal"); ret = krb5_parse_name(context, server_principal_str, &server_principal); if (ret) - krb5_err(context, 1, ret, "resolvning server name"); + krb5_err(context, 1, ret, "resolving server name"); /* If no session-enc-type specified on command line and this is an afs */ /* service ticket, change default of session_enc_type to DES. */ @@ -395,6 +389,7 @@ main(int argc, char **argv) create_krb5_tickets(context, kt); krb5_kt_close(context, kt); + krb5_free_context(context); return 0; } diff --git a/third_party/heimdal/kuser/kinit.c b/third_party/heimdal/kuser/kinit.c index 0b22e7150950..6ac4b45426a9 100644 --- a/third_party/heimdal/kuser/kinit.c +++ b/third_party/heimdal/kuser/kinit.c @@ -34,6 +34,8 @@ */ #include "kuser_locl.h" +#undef HC_DEPRECATED_CRYPTO +#include #ifdef HAVE_FRAMEWORK_SECURITY #include @@ -78,7 +80,7 @@ int pk_enterprise_flag = 0; struct hx509_certs_data *ent_user_id = NULL; char *pk_x509_anchors = NULL; int pk_use_enckey = 0; -int pk_anon_fast_armor = 0; +int pk_anon_fast_armor = -1; char *gss_preauth_mech = NULL; char *gss_preauth_name = NULL; char *kdc_hostname = NULL; @@ -500,7 +502,7 @@ renew_validate(krb5_context context, * no need to check the error here, it's only to be * friendly to the user */ - krb5_get_credentials(context, KRB5_GC_CACHED, cache, &in, &out); + (void) krb5_get_credentials(context, KRB5_GC_CACHED, cache, &in, &out); } flags.i = 0; @@ -828,6 +830,8 @@ get_new_tickets(krb5_context context, if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_pkinit) { + if (pk_anon_fast_armor == -1) + pk_anon_fast_armor = 0; ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, @@ -936,13 +940,22 @@ get_new_tickets(krb5_context context, } } + if (anonymous_flag && pk_anon_fast_armor == -1) + pk_anon_fast_armor = 0; + if (!gss_preauth_mech && anonymous_flag && pk_anon_fast_armor) { + krb5_warnx(context, N_("Ignoring --pk-anon-fast-armor because " + "--anonymous given", "")); + pk_anon_fast_armor = 0; + } + if (fast_armor_cache_string) { krb5_ccache fastid = NULL; - if (pk_anon_fast_armor) + if (pk_anon_fast_armor > 0) krb5_errx(context, 1, N_("cannot specify FAST armor cache with FAST " "anonymous PKINIT option", "")); + pk_anon_fast_armor = 0; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) { @@ -955,6 +968,12 @@ get_new_tickets(krb5_context context, krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); goto out; } + } else if (pk_anon_fast_armor == -1) { + ret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx); + if (ret) { + krb5_warn(context, ret, "_krb5_init_creds_set_fast_anon_pkinit_optimistic"); + goto out; + } } else if (pk_anon_fast_armor) { ret = krb5_init_creds_set_fast_anon_pkinit(context, ctx); if (ret) { @@ -1659,6 +1678,10 @@ main(int argc, char **argv) krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); pk_user_id = NULL; + if (pk_anon_fast_armor > 0) + krb5_warnx(context, N_("Ignoring --pk-anon-fast-armor " + "because --pk-user given", "")); + pk_anon_fast_armor = 0; } else if (argc && argv[0][0] == '@' && (gss_preauth_mech || anonymous_flag)) { const char *instance; @@ -1673,6 +1696,11 @@ main(int argc, char **argv) ret = make_wellknown_name(context, &argv[0][1], instance, &principal); if (ret) krb5_err(context, 1, ret, "make_wellknown_name"); + if (!gss_preauth_mech && pk_anon_fast_armor > 1) { + krb5_warnx(context, N_("Ignoring --pk-anon-fast-armor " + "because --anonymous given", "")); + pk_anon_fast_armor = 0; + } } else if (anonymous_flag && historical_anon_pkinit) { char *realm = argc == 0 ? get_default_realm(context) : argv[0][0] == '@' ? &argv[0][1] : argv[0]; diff --git a/third_party/heimdal/kuser/klist.c b/third_party/heimdal/kuser/klist.c index 5dbabcaad85e..b33c3c28a7aa 100644 --- a/third_party/heimdal/kuser/klist.c +++ b/third_party/heimdal/kuser/klist.c @@ -362,7 +362,6 @@ print_tickets(krb5_context context, if (ret) krb5_err(context, 1, ret, "krb5_cc_end_seq_get"); - print_comma = 0; if(!do_verbose) { rtbl_format(ct, stdout); rtbl_destroy(ct); @@ -523,16 +522,16 @@ static int list_caches(krb5_context context, struct klist_options *opt) { krb5_cccol_cursor cursor; - const char *cdef_name; + const char *cdef_name = krb5_cc_default_name(context); char *def_name; krb5_error_code ret; krb5_ccache id; rtbl_t ct; - cdef_name = krb5_cc_default_name(context); - if (cdef_name == NULL) - krb5_errx(context, 1, "krb5_cc_default_name"); - def_name = strdup(cdef_name); + if ((def_name = krb5_cccol_get_default_ccname(context)) == NULL) + cdef_name = krb5_cc_default_name(context); + if (!def_name && cdef_name && (def_name = strdup(cdef_name)) == NULL) + krb5_err(context, 1, ENOMEM, "Out of memory"); ret = krb5_cccol_cursor_new(context, &cursor); if (ret == KRB5_CC_NOSUPP) { @@ -554,7 +553,7 @@ list_caches(krb5_context context, struct klist_options *opt) if (opt->json_flag) rtbl_set_flags(ct, RTBL_JSON); - while (krb5_cccol_cursor_next(context, cursor, &id) == 0) { + while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) { int expired = 0; char *name; time_t t; @@ -582,7 +581,7 @@ list_caches(krb5_context context, struct klist_options *opt) rtbl_add_column_entry(ct, COL_CACHENAME, fname); if (opt->json_flag) ; - else if (strcmp(fname, def_name) == 0) + else if (def_name && strcmp(fname, def_name) == 0) rtbl_add_column_entry(ct, COL_DEFCACHE, "*"); else rtbl_add_column_entry(ct, COL_DEFCACHE, ""); diff --git a/third_party/heimdal/kuser/kswitch.c b/third_party/heimdal/kuser/kswitch.c index d897a8e74513..3bb3b700dbd1 100644 --- a/third_party/heimdal/kuser/kswitch.c +++ b/third_party/heimdal/kuser/kswitch.c @@ -86,16 +86,17 @@ kswitch(struct kswitch_options *opt, int argc, char **argv) krb5_err(heimtools_context, 1, ret, "krb5_cc_cache_get_first"); while (krb5_cc_cache_next(heimtools_context, cursor, &id) == 0) { - krb5_principal p; + krb5_principal p = NULL; char num[10]; ret = krb5_cc_get_principal(heimtools_context, id, &p); + if (ret == 0) + ret = krb5_unparse_name(heimtools_context, p, &name); if (ret) { krb5_cc_close(heimtools_context, id); continue; } - ret = krb5_unparse_name(heimtools_context, p, &name); krb5_free_principal(heimtools_context, p); snprintf(num, sizeof(num), "%d", (int)(len + 1)); diff --git a/third_party/heimdal/kuser/kuser_locl.h b/third_party/heimdal/kuser/kuser_locl.h index 8218a6f096fd..b1a097a8d6f7 100644 --- a/third_party/heimdal/kuser/kuser_locl.h +++ b/third_party/heimdal/kuser/kuser_locl.h @@ -97,11 +97,15 @@ #ifdef LIBINTL #include +#undef N_ #define N_(x,y) gettext(x) +#undef NP_ #define NP_(x,y) (x) #define getarg_i18n gettext #else +#undef N_ #define N_(x,y) (x) +#undef NP_ #define NP_(x,y) (x) #define getarg_i18n NULL #define bindtextdomain(package, localedir) diff --git a/third_party/heimdal/lib/asn1/MANUAL.md b/third_party/heimdal/lib/asn1/MANUAL.md new file mode 100644 index 000000000000..89c452a031c0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/MANUAL.md @@ -0,0 +1,1287 @@ +# Introduction + +Heimdal is an implementation of PKIX and Kerberos. As such it must handle the +use of [Abstract Syntax Notation One (ASN.1)](https://www.itu.int/rec/T-REC-X.680-X.693-202102-I/en) +by those protocols. ASN.1 is a language for describing the schemata of network +protocol messages. Associated with ASN.1 are the ASN.1 Encoding Rules (ERs) +that specify how to encode such messages. + +In short: + + - ASN.1 is just a _schema description language_ + + - ASN.1 Encoding Rules are specifications for encoding formats for values of + types described by ASN.1 schemas ("modules") + +Similar languages include: + + - [DCE RPC's Interface Description Language (IDL)](https://pubs.opengroup.org/onlinepubs/9629399/chap4.htm#tagcjh_08) + - [Microsoft Interface Description Language (IDL)](https://docs.microsoft.com/en-us/windows/win32/midl/midl-start-page) + (MIDL is derived from the DCE RPC IDL) + - ONC RPC's eXternal Data Representation (XDR) [RFC4506](https://datatracker.ietf.org/doc/html/rfc4506) + - [XML Schema](https://en.wikipedia.org/wiki/XML_schema) + - Various JSON schema languages + - [Protocol Buffers](https://developers.google.com/protocol-buffers) + - and [many, many others](https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats)! + Many are not even listed there. + +Similar encoding rules include: + + - DCE RPC's [NDR](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm) + - ONC RPC's [XDR](https://datatracker.ietf.org/doc/html/rfc4506) + - XML + - FastInfoSet + - JSON + - CBOR + - [Protocol Buffers](https://developers.google.com/protocol-buffers) + - [Flat Buffers](https://google.github.io/flatbuffers/) + - and [many, many others](https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats)! + Many are not even listed there. + +Many such languages are quite old. ASN.1 itself dates to the early 1980s, with +the first specification published in 1984. XDR was first published in 1987. +IDL's lineage dates back to sometime during the 1980s, via the Apollo Domain +operating system. + +ASN.1 is standardized by the International Telecommunications Union (ITU-T), +and has continued evolving over the years, with frequent updates. + +The two most useful and transcending features of ASN.1 are: + + - the ability to formally express what some know as "open types", "typed + holes", or "references"; + + - the ability to add encoding rules over type, which for ASN.1 includes: + + - binary, tag-length-value (TLV) encoding rules + - binary, non-TLV encoding rules + - textual encoding rules using XML and JSON + - an ad-hoc generic text-based ER called GSER + + In principle ASN.1 can add encoding rules that would allow it to + interoperate with many others, such as: CBOR, protocol buffers, flat + buffers, NDR, and others. + + Readers may recognize that some alternatives to ASN.1 have followed a + similar arc. For example, Protocol Buffers was originally a syntax and + encoding, and has become a syntax and set of various encodings (e.g., Flat + Buffers was added later). And XML has FastInfoSet as a binary encoding + alternative to XML's textual encoding. + +As well, ASN.1 has [high-quality, freely-available specifications](https://www.itu.int/rec/T-REC-X.680-X.693-202102-I/en). + +## ASN.1 Example + +For example, this is a `Certificate` as used in TLS and other protocols, taken +from [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280): + + ```ASN.1 + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING + } + + TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL + } + ``` + +and the same `Certificate` taken from a more modern version -from +[RFC5912](https://datatracker.ietf.org/doc/html/rfc5912)- using newer features +of ASN.1: + + ```ASN.1 + Certificate ::= SIGNED{TBSCertificate} + + TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier{SIGNATURE-ALGORITHM, + {SignatureAlgorithms}}, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + ... , + [[2: + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL + ]], + [[3: + extensions [3] Extensions{{CertExtensions}} OPTIONAL + ]], ... + } + ``` + +As you can see, a `Certificate` is a structure containing a to-be-signed +sub-structure, and a signature of that sub-structure, and the sub-structure +has: a version number, a serial number, a signature algorithm, an issuer name, +a validity period, a subject name, a public key for the subject name, "unique +identifiers" for the issuer and subject entities, and "extensions". + +To understand more we'd have to look at the types of those fields of +`TBSCertificate`, but for now we won't do that. The point here is to show that +ASN.1 allows us to describe "types" of data in a way that resembles +"structures", "records", or "classes" in various programming languages. + +To be sure, there are some "noisy" artifacts in the definition of +`TBSCertificate` which mostly have to do with the original encoding rules for +ASN.1. The original encoding rules for ASN.1 were tag-length-value (TLV) +binary encodings, meaning that for every type, the encoding of a value of that +type consisted of a _tag_, a _length_ of the value's encoding, and the _actual +value's encoding_. Over time other encoding rules were added that do not +require tags, such as the octet encoding rules (OER), but also JSON encoding +rules (JER), XML encoding rules (XER), and others. There is almost no need for +tagging directives like `[1] IMPLICIT` when using OER. But in existing +protocols like PKIX and Kerberos that date back to the days when DER was king, +tagging directives are unfortunately commonplace. + +## ASN.1 Crash Course + +This is not a specification. Readers should refer to the ITU-T's X.680 base +specification for ASN.1's syntax. + +A schema is called a "module". + +A module looks like: + +```ASN.1 +-- This is a comment + +-- Here's the name of the module, here given as an "object identifier" or +-- OID: +PKIXAlgs-2009 { iso(1) identified-organization(3) dod(6) + internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) + id-mod-pkix1-algorithms2008-02(56) } + + +-- `DEFINITIONS` is a required keyword +-- `EXPLICIT TAGS` will be explained later +DEFINITIONS EXPLICIT TAGS ::= +BEGIN +-- list exported types, or `ALL`: +EXPORTS ALL; +-- import some types: +IMPORTS PUBLIC-KEY, SIGNATURE-ALGORITHM, ... FROM AlgorithmInformation-2009 + mda-sha224, mda-sha256, ... FROM PKIX1-PSS-OAEP-Algorithms-2009; + +-- type definitions follow: +... + +END +``` + +Type names start with capital upper-case letters. Value names start with +lower-case letters. + +Type definitions are of the form `TypeName ::= TypeDefinition`. + +Value (constant) definitions are of the form `valueName ::= TypeName `. + +There are some "universal" primitive types (e.g., string types, numeric types), +and several "constructed" types (arrays, structures. + +Some useful primitive types include `BOOLEAN`, `INTEGER` and `UTF8String`. + +Structures are either `SEQUENCE { ... }` or `SET { ... }`. The "fields" of +these are known as "members". + +Arrays are either `SEQUENCE OF SomeType` or `SET OF SomeType`. + +A `SEQUENCE`'s elements or members are ordered, while a `SET`'s are not. In +practice this means that for _canonical_ encoding rules a `SET OF` type's +values must be sorted, while a `SET { ... }` type's members need not be sorted +at run-time, but are sorted by _tag_ at compile-time. + +Anonymous types are supported, such as `SET OF SET { a A, b B }` (which is a +set of structures with an `a` field (member) of type `A` and a `b` member of +type `B`). + +The members of structures can be `OPTIONAL` or have a `DEFAULT` value. + +There are also discriminated union types known as `CHOICE`s: `U ::= CHOICE { a +A, b B, c C }` (in this case `U` is either an `A`, a `B`, or a `C`. + +Extensibility is supported. "Extensibility" means: the ability to add new +members to structures, new alternatives to discriminated unions, etc. For +example, `A ::= SEQUENCE { a0 A0, a1 A1, ... }` means that type `A` is a +structure that has two fields and which may have more fields added in future +revisions, therefore decoders _must_ be able to receive and decode encodings of +extended versions of `A`, even encoders produced prior to the extensions being +specified! (Normally a decoder "skips" extensions it doesn't know about, and +the encoding rules need only make it possible to do so.) + +## TLV Encoding Rules + +The TLV encoding rules for ASN.1 are: + + - Basic Encoding Rules (BER) + - Distinguished Encoding Rules (DER), a canonical subset of BER + - Canonical Encoding Rules (CER), another canonical subset of BER + +"Canonical" encoding rules yield just one way to encode any value of any type, +while non-canonical rules possibly yield many ways to encode values of certain +types. For example, JSON is not a canonical data encoding. A canonical form +of JSON would have to specify what interstitial whitespace is allowed, a +canonical representation of strings (which Unicode codepoints must be escaped +and in what way, and which must not), and a canonical representation of decimal +numbers. + +It is important to understand that originally ASN.1 came with TLV encoding +rules, and some considerations around TLV encoding rules leaked into the +language. For example, `A ::= SET { a0 [0] A0, a1 [1] A1 }` is a structure +that has two members `a0` and `a1`, and when encoded those members will be +tagged with a "context-specific" tags `0` and `1`, respectively. + +Tags only have to be specified when needed to disambiguate encodings. +Ambiguities arise only in `CHOICE` types and sometimes in `SEQUENCE`/`SET` +types that have `OPTIONAL`/`DEFAULT`ed members. + +In modern ASN.1 it is possible to specify that a module uses `AUTOMATIC` +tagging so that one need never specify tags explicitly in order to fix +ambiguities. + +Also, there are two types of tags: `IMPLICIT` and `EXPLICIT`. Implicit tags +replace the tags that the tagged type would have otherwise. Explicit tags +treat the encoding of a type's value (including its tag and length) as the +value of the tagged type, thus yielding a tag-length-tag-length-value encoding +-- a TLTLV encoding! + +Thus explicit tagging is more redundant and wasteful than implicit tagging. +But implicit tagging loses metadata that is useful for tools that can decode +TLV encodings without reference to the schema (module) corresponding to the +types of values encoded. + +TLV encodings were probably never justified except by lack of tooling and +belief that codecs for TLV ERs can be hand-coded. But TLV RTs exist, and +because they are widely used, cannot be removed. + +## Other Encoding Rules + +The Packed Encoding Rules (PER) and Octet Encoding Rules (OER) are rules that +resemble XDR, but with a 1-byte word size instead of 4-byte word size, and also +with a 1-byte alignment instead of 4-byte alignment, yielding space-efficient +encodings. + +Hand-coding XDR codecs is quite common and fairly easy. Hand-coding PER and +OER is widely considered difficult because PER and OER try to be quite +space-efficient. + +Hand-coding TLV codecs used to be considered easy, but really, never was. + +But no one should hand-code codecs for any encoding rules. + +Instead, one should use a compiler. This is true for ASN.1, and for all schema +languages. + +## Encoding Rule Specific Syntactic Forms + +Some encoding rules require specific syntactic forms for some aspects of them. + +For example, the JER (JSON Encoding Rules) provide for syntax to select the use +of JSON arrays vs. JSON objects for encoding structure types. + +For example, the TLV encoding rules provide for syntax for specifying +alternative tags for disambiguation. + +## ASN.1 Syntax Specifications + + - The base specification is ITU-T + [X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en). + + - Additional syntax extensions include: + + - [X.681 ASN.1 Information object specification](https://www.itu.int/rec/T-REC-X.681/en) + - [X.682 ASN.1 Constraint specification](https://www.itu.int/rec/T-REC-X.682/en) + - [X.682 ASN.1 Parameterization of ASN.1 specifications](https://www.itu.int/rec/T-REC-X.683/en) + + Together these three specifications make the formal specification of open + types possible. + +## ASN.1 Encoding Rules Specifications + + - The TLV Basic, Distinguished, and Canonical Encoding Rules (BER, DER, CER) + are described in ITU-T [X.690](https://www.itu.int/rec/T-REC-X.690/en). + + - The more flat-buffers/XDR-like Packed Encoding Rules (PER) are described in + ITU-T [X.691](https://www.itu.int/rec/T-REC-X.691/en), and its successor, + the Octet Encoding Rules (OER) are described in + [X.696](https://www.itu.int/rec/T-REC-X.692/en). + + - The XML Encoding Rules (XER) are described in ITU-T + [X.693](https://www.itu.int/rec/T-REC-X.693/en). + + Related is the [X.694 Mapping W3C XML schema definitions into ASN.1](https://www.itu.int/rec/T-REC-X.694/en) + + - The JSON Encoding Rules (JER) are described in ITU-T + [X.697](https://www.itu.int/rec/T-REC-X.697/en). + + - The Generic String Encoding Rules are specified by IETF RFCs + [RFC3641](https://datatracker.ietf.org/doc/html/rfc3641), + [RFC3642](https://datatracker.ietf.org/doc/html/rfc3642), + [RFC4792](https://datatracker.ietf.org/doc/html/rfc4792). + +Additional ERs can be added. + +For example, XDR can clearly encode a very large subset of ASN.1, and with a +few additional conventions, all of ASN.1. + +NDR too can clearly encode a very large subset of ASN.1, and with a few +additional conventions, all of ASN. However, ASN.1 is not sufficiently rich a +_syntax_ to express all of what NDR can express (think of NDR conformant and/or +varying arrays), though with some extensions it could. + +## Commentary + +The text in this section is the personal opinion of the author(s). + + - ASN.1 gets a bad rap because BER/DER/CER are terrible encoding rules, as are + all TLV encoding rules. + + The BER family of encoding rules is a disaster, yes, but ASN.1 itself is + not. On the contrary, ASN.1 is quite rich in features and semantics -as + rich as any competitor- while also being very easy to write and understand + _as a syntax_. + + - ASN.1 also gets a bad rap because its full syntax is not context-free, and + so parsing it can be tricky. + + And yet the Heimdal ASN.1 compiler manages, using LALR(1) `yacc`/`bison`/`byacc` + parser-generators. For the subset of ASN.1 that this compiler handles, + there are no ambiguities. However, we understand that eventually we will + need run into ambiguities. + + For example, `ValueSet` and `ObjectSet` are ambiguous. X.680 says: + + ``` + ValueSet ::= "{" ElementSetSpecs "}" + ``` + + while X.681 says: + + ``` + ObjectSet ::= "{" ObjectSetSpec "}" + ``` + + and the set members can be just the symbolic names of members, in which case + there's no grammatical difference between those two productions. These then + cause a conflict in the `FieldSetting` production, which is used in the + `ObjectDefn` production, which is used in defining an object (which is to be + referenced from some `ObjectSet` or `FieldSetting`). + + This particular conflict can be resolved by one of: + + - limiting the power of object sets by disallowing recursion (object sets + containing objects that have field settings that are object sets ...), + + - or by introducing additional required and disambiguating syntactic + elements that preclude full compliance with ASN.1, + + - or by simply using the same production and type internally to handle + both, the `ValueSet` and `ObjectSet` productions and then internally + resolving the actual type as late as possible by either inspecting the + types of the set members or by inspecting the expected kind of field that + the `ValueSet`-or-`ObjectSet` is setting. + + Clearly, only the last of these is satisfying, but it is more work for the + compiler developer. + + - TLV encodings are bad because they yield unnecessary redundance in + encodings. This is space-inefficient, but also a source of bugs in + hand-coded codecs for TLV encodings. + + EXPLICIT tagging makes this worse by making the encoding a TLTLV encoding + (tag length tag length value). (The inner TLV is the V for the outer TL.) + + - TLV encodings are often described as "self-describing" because one can + usually write a `dumpasn1` style of tool that attempts to decode a TLV + encoding of a value without reference to the value's type definition. + + The use of `IMPLICIT` tagging with BER/DER/CER makes schema-less `dumpasn1` + style tools harder to use, as some type information is lost. E.g., a + primitive type implicitly tagged with a context tag results in a TLV + encoding where -without reference to the schema- the tag denotes no + information about the type of the value encoded. The user is left to figure + out what kind of data that is and to then decode it by hand. For + constructed types (arrays and structures), implicit tagging does not really + lose any metadata about the type that wasn't already lost by BER/DER/CER, so + there is no great loss there. + + However, Heimdal's ASN.1 compiler includes an `asn1_print(1)` utility that + can print DER-encoded values in much more detail than a schema-less + `dumpasn1` style of tool can. This is because `asn1_print(1)` includes + a number of compiled ASN.1 modules, and it can be extended to include more. + + - There is some merit to BER, however. Specifically, an appropriate use of + indeterminate length encoding with BER can yield on-line encoding. Think of + encoding streams of indeterminate size -- this cannot be done with DER or + Flat Buffers, or most encodings, though it can be done with some encodings, + such as BER and NDR (NDR has "pipes" for this). + + Some clues are needed in order to produce an codec that can handle such + on-line behavior. In IDL/NDR that clue comes from the "pipe" type. In + ASN.1 there is no such clue and it would have to be provided separately to + the ASN.1 compiler (e.g., as a command-line option). + + - Protocol Buffers is a TLV encoding. There was no need to make it a TLV + encoding. + + Public opinion seems to prefer Flat Buffers now, which is not a TLV encoding + and which is more comparable to XDR/NDR/PER/OER. + +# Heimdal ASN.1 Compiler + +The Heimdal ASN.1 compiler and library implement a very large subset of the +ASN.1 syntax, meanign large parts of X.680, X.681, X.682, and X.683. + +The compiler currently emits: + + - a JSON representation of ASN.1 modules + - C types corresponding to ASN.1 modules' types + - C functions for DER (and some BER) codecs for ASN.1 modules' types + +We vaguely hope to eventually move to using the JSON representation of ASN.1 +modules to do code generation in a programming language like `jq` rather than +in C. The idea there is to make it much easier to target other programming +languages than C, especially Rust, so that we can start moving Heimdal to Rust +(first after this would be `lib/hx509`, then `lib/krb5`, then `lib/hdb`, then +`lib/gssapi`, then `kdc/`). + +The compiler has two "backends": + + - C code generation + - "template" (byte-code) generation and interpretation + +## Features and Limitations + +Supported encoding rules: + + - DER + - BER decoding (but not encoding) + +As well, the Heimdal ASN.1 compiler can render values as JSON using an ad-hoc +metaschema that is not quite JER-compliant. A sample rendering of a complex +PKIX `Certificate` with all typed holes automatically decoded is shown in +[README.md#features](README.md#features). + +The Heimdal ASN.1 compiler supports open types via X.681/X.682/X.683 syntax. +Specifically: (when using the template backend) the generated codecs can +automatically and recursively decode and encode through "typed holes". + +An "open type", also known as "typed holes" or "references", is a part of a +structure that can contain the encoding of a value of some arbitrary data type, +with a hint of that value's type expressed in some way such as: via an "object +identifier", or an integer, or even a string (e.g., like a URN). + +Open types are widely used as a form of extensibility. + +Historically, open types were never documented formally, but with natural +language (e.g., English) meant only for humans to understand. Documenting open +types with formal syntax allows compilers to support them specially. + +See the the [`asn1_compile(1)` manual page](#Manual-Page-for-asn1_compile) +below and [README.md#features](README.md#features), for more details on +limitations. Excerpt from the manual page: + +``` +The Information Object System support includes automatic codec support +for encoding and decoding through “open types” which are also known as +“typed holes”. See RFC5912 for examples of how to use the ASN.1 Infor- +mation Object System via X.681/X.682/X.683 annotations. See the com- +piler's README files for more information on ASN.1 Information Object +System support. + +Extensions specific to Heimdal are generally not syntactic in nature but +rather command-line options to this program. For example, one can use +command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei- + ther encoded nor decoded; +etc. + +ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + +Size and range constraints on the ‘INTEGER’ type cause the compiler to +generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, +‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which +represents an integer of arbitrary size. + +Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. +``` + +## Easy-to-Use C Types + +The Heimdal ASN.1 compiler generates easy-to-use C types for ASN.1 types. + +Unconstrained `INTEGER` becomes `heim_integer` -- a large integer type. + +Constrained `INTEGER` types become `int`, `unsigned int`, `int64_t`, or +`uint64_t`. + +String types generally become `char *` (C strings, i.e., NUL-terminated) or +`heim_octet_string` (a counted byte string type). + +`SET` and `SEQUENCE` types become `struct` types. + +`SET OF SomeType` and `SEQUENCE OF SomeType` types become `struct` types with a +`size_t len` field counting the number of elements of the array, and a pointer +to `len` consecutive elements of the `SomeType` type. + +`CHOICE` types become a `struct` type with an `enum` discriminant and a +`union`. + +Type names have hyphens turned to underscores. + +Every ASN.1 gets a `typedef`. + +`OPTIONAL` members of `SET`s and `SEQUENCE`s become pointer types (`NULL` +values mean "absent", while non-`NULL` values mean "present"). + +Tags are of no consequence to the C types generated. + +Types definitions to be topographically sorted because of the need to have +forward declarations. + +Forward `typedef` declarations are emmitted. + +Circular type dependencies are allowed provided that `OPTIONAL` members are +used for enough circular references so as to avoid creating types whose values +have infinite size! (Circular type dependencies can be used to build linked +lists, though that is a bit of a silly trick when one can use arrays instead, +though in principle this could be used to do on-line encoding and decoding of +arbitrarily large streams of objects. See the [commentary](#Commentary) +section.) + +Thus `Certificate` becomes: + +```C +typedef struct TBSCertificate { + heim_octet_string _save; /* see below! */ + Version *version; + CertificateSerialNumber serialNumber; + AlgorithmIdentifier signature; + Name issuer; + Validity validity; + Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + heim_bit_string *issuerUniqueID; + heim_bit_string *subjectUniqueID; + Extensions *extensions; +} TBSCertificate; + +typedef struct Certificate { + TBSCertificate tbsCertificate; + AlgorithmIdentifier signatureAlgorithm; + heim_bit_string signatureValue; +} Certificate; +``` + +The `_save` field in `TBSCertificate` is generated when the compiler is invoked +with `--preserve-binary=TBSCertificate`, and the decoder will place the +original encoding of the value of a `TBSCertificate` in the decoded +`TBSCertificate`'s `_save` field. This is very useful for signature +validation: the application need not attempt to re-encode a `TBSCertificate` in +order to validate its signature from the containing `Certificate`! + +Let's compare to the `Certificate` as defined in ASN.1: + +```ASN.1 + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING + } + + TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL + } +``` + +The conversion from ASN.1 to C is quite mechanical and natural. That's what +code-generators do, of course, so it's not surprising. But you can see that +`Certificate` in ASN.1 and C differs only in: + + - in C `SEQUENCE { }` becomes `struct { }` + - in C the type name comes first + - in C we drop the tagging directives (e.g., `[0] EXPLICIT`) + - `DEFAULT` and `OPTIONAL` become pointers + - in C we use `typedef`s to make the type names usable without having to add + `struct` + +## Circular Type Dependencies + +As noted above, circular type dependencies are supported. + +Here's a toy example from [XDR](https://datatracker.ietf.org/doc/html/rfc4506) +-- a linked list: + +```XDR +struct stringentry { + string item<>; + stringentry *next; +}; + +typedef stringentry *stringlist; +``` + +Here is the same example in ASN.1: + +```ASN.1 +Stringentry ::= SEQUENCE { + item UTF8String, + next Stringentry OPTIONAL +} +``` + +which compiles to: + +```C +typedef struct Stringentry Stringentry; +struct Stringentry { + char *item; + Stringentry *next; +}; +``` + +This illustrates that `OPTIONAL` members in ASN.1 are like pointers in XDR. + +Making the `next` member not `OPTIONAL` would cause `Stringentry` to be +infinitely large, and there is no way to declare the equivalent in C anyways +(`struct foo { int a; struct foo b; };` will not compile in C). + +Mutual circular references are allowed too. In the following example `A` +refers to `B` and `B` refers to `A`, but as long as one (or both) of those +references is `OPTIONAL`, then it will be allowed: + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B } +B ::= SEQUENCE { name UTF8String, a A OPTIONAL } +``` + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B OPTIONAL } +B ::= SEQUENCE { name UTF8String, a A } +``` + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B OPTIONAL } +B ::= SEQUENCE { name UTF8String, a A OPTIONAL } +``` + +In the above example values of types `A` and `B` together form a linked list. + +Whereas this is broken and will not compile: + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B } +B ::= SEQUENCE { name UTF8String, a A } -- infinite size! +``` + +## Generated APIs For Any Given Type T + +The C functions generated for ASN.1 types are all of the same form, for any +type `T`: + +```C +int decode_T(const unsigned char *, size_t, TBSCertificate *, size_t *); +int encode_T(unsigned char *, size_t, const TBSCertificate *, size_t *); +size_t length_T(const TBSCertificate *); +int copy_T(const TBSCertificate *, TBSCertificate *); +void free_T(TBSCertificate *); +char * print_T(const TBSCertificate *, int); +``` + +The `decode_T()` functions take a pointer to the encoded data, its length in +bytes, a pointer to a C object of type `T` to decode into, and a pointer into +which the number of bytes consumed will be written. + +The `length_T()` functions take a pointer to a C object of type `T` and return +the number of bytes its encoding would need. + +The `encode_T()` functions take a pointer to enough bytes to encode the value, +the number of bytes found there, a pointer to a C object of type `T` whose +value to encode, and a pointer into which the number of bytes output will be +written. + +> NOTE WELL: The first argument to `encode_T()` functions must point to the +> last byte in the buffer into which the encoder will encode the value. This +> is because the encoder encodes from the end towards the beginning. + +The `print_T()` functions encode the value of a C object of type `T` in JSON +(though not in JER-compliant JSON). A sample printing of a complex PKIX +`Certificate` can be seen in [README.md#features](README.md#features). + +The `copy_T()` functions take a pointer to a source C object of type `T` whose +value they then copy to the destination C object of the same type. The copy +constructor is equivalent to encoding the source value and decoding it onto the +destination. + +The `free_T()` functions take a pointer to a C object of type `T` whose value's +memory resources will be released. Note that the C object _itself_ is not +freed, only its _content_. + +See [sample usage](#Using-the-Generated-APIs). + +These functions are all recursive. + +> NOTE WELL: These functions use the standard C memory allocator. +> When using the Windows statically-linked C run-time, you must link with +> `LIBASN1.LIB` to avoid possibly freeing memory allocated by a different +> allocator. + +## Error Handling + +All codec functions that return errors return them as `int`. + +Error values are: + + - system error codes (use `strerror()` to display them) + +or + + - `ASN1_BAD_TIMEFORMAT` + - `ASN1_MISSING_FIELD` + - `ASN1_MISPLACED_FIELD` + - `ASN1_TYPE_MISMATCH` + - `ASN1_OVERFLOW` + - `ASN1_OVERRUN` + - `ASN1_BAD_ID` + - `ASN1_BAD_LENGTH` + - `ASN1_BAD_FORMAT` + - `ASN1_PARSE_ERROR` + - `ASN1_EXTRA_DATA` + - `ASN1_BAD_CHARACTER` + - `ASN1_MIN_CONSTRAINT` + - `ASN1_MAX_CONSTRAINT` + - `ASN1_EXACT_CONSTRAINT` + - `ASN1_INDEF_OVERRUN` + - `ASN1_INDEF_UNDERRUN` + - `ASN1_GOT_BER` + - `ASN1_INDEF_EXTRA_DATA` + +You can use the `com_err` library to display these errors as strings: + +```C + struct et_list *etl = NULL; + initialize_asn1_error_table_r(&etl); + int ret; + + ... + + ret = decode_T(...); + if (ret) { + const char *error_message; + + if ((error_message = com_right(etl, ret)) == NULL) + error_message = strerror(ret); + + fprintf(stderr, "Failed to decode T: %s\n", + error_message ? error_message : ""); + } +``` + +## Using the Generated APIs + +Value construction is as usual in C. Use the standard C allocator for +allocating values of `OPTIONAL` fields. + +Value destruction is done with the `free_T()` destructors. + +Decoding is just: + +```C + Certificate c; + size_t sz; + int ret; + + ret = decode_Certificate(pointer_to_encoded_bytes, + number_of_encoded_bytes, + &c, &sz); + if (ret == 0) { + if (sz != number_of_encoded_bytes) + warnx("Extra bytes after Certificate!"); + } else { + warnx("Failed to decode certificate!"); + return ret; + } + + /* Now do stuff with the Certificate */ + ... + + /* Now release the memory */ + free_Certificate(&c); +``` + +Encoding involves calling the `length_T()` function to compute the number of +bytes needed for the encoding, then allocating that many bytes, then calling +`encode_T()` to encode into that memory. A convenience macro, +`ASN1_MALLOC_ENCODE()`, does all three operations: + +```C + Certificate c; + size_t num_bytes, sz; + char *bytes = NULL; + int ret; + + /* Build a `Certificate` in `c` */ + ... + + /* Encode `c` */ + ASN1_MALLOC_ENCODE(Certificate, bytes, num_bytes, &c, sz, ret); + if (ret) + errx(1, "Out of memory encoding a Certificate"); + + /* This check isn't really needed -- it never fails */ + if (num_bytes != sz) + errx(1, "ASN.1 encoder internal error"); + + /* Send the `num_bytes` in `bytes` */ + ... + + /* Free the memory allocated by `ASN1_MALLOC_ENCODE()` */ + free(bytes); +``` + +or, the same code w/o the `ASN1_MALLOC_ENCODE()` macro: + +```C + Certificate c; + size_t num_bytes, sz; + char *bytes = NULL; + int ret; + + /* Build a `Certificate` in `c` */ + ... + + /* Encode `c` */ + num_bytes = length_Certificate(&c); + bytes = malloc(num_bytes); + if (bytes == NULL) + errx(1, "Out of memory"); + + /* + * Note that the memory to encode into, passed to encode_Certificate() + * must be a pointer to the _last_ byte of that memory, not the first! + */ + ret = encode_Certificate(bytes + num_bytes - 1, num_bytes, + &c, &sz); + if (ret) + errx(1, "Out of memory encoding a Certificate"); + + /* This check isn't really needed -- it never fails */ + if (num_bytes != sz) + errx(1, "ASN.1 encoder internal error"); + + /* Send the `num_bytes` in `bytes` */ + ... + + /* Free the memory allocated by `ASN1_MALLOC_ENCODE()` */ + free(bytes); +``` + +## Open Types + +The handling of X.681/X.682/X.683 syntax for open types is described at length +in [README-X681.md](README-X681.md). + +## Command-line Usage + +The compiler takes an ASN.1 module file name and outputs a C header and C +source files, as well as various other metadata files: + + - `_asn1.h` + + This file defines all the exported types from the given ASN.1 module as C + types. + + - `_asn1-priv.h` + + This file defines all the non-exported types from the given ASN.1 module as + C types. + + - `_asn1_files` + + This file is needed because the default is to place the code for each type + in a separate C source file, which can help improve the performance of + builds by making it easier to parallelize the building of the ASN.1 module. + + - `asn1_.c` or `asn1__asn1.c` + + If `--one-code-file` is used, then the implementation of the module will be + in a file named `asn1__asn1.c`, otherwise the implementation of each + type in the module will be in `asn1_.c`. + + - `_asn1.json` + + This file contains a JSON description of the module (the schema for this + file is ad-hoc and subject to change w/o notice). + + - `_asn1_oids.c` + + This file is meant to be `#include`d, and contains just calls to a + `DEFINE_OID_WITH_NAME(sym)` macro that the user must define, where `sym` is + the suffix of the name of a variable of type `heim_oid`. The full name of + the variable is `asn1_oid_ ## sym`. + + - `_asn1_syms.c` + + This file is meant to be `#include`d, and contains just calls to these + macros that the user must define: + + - `ASN1_SYM_INTVAL(name, genname, sym, num)` + - `ASN1_SYM_OID(name, genname, sym)` + - `ASN1_SYM_TYPE(name, genname, sym)` + + where `name` is the C string literal name of the value or type as it appears + in the ASN.1 module, `genname` is the C string literal name of the value or + type as generated (e.g., with hyphens replaced by underscores), `sym` is the + symbol or symbol suffix (see above0, and `num` is the numeric value of the + integer value. + +Control over the C types used for ASN.1 `INTEGER` types is done by ASN.1 usage +convention: + + - unconstrained `INTEGER` types, or `INTEGER` types where only the minimum, or + only the maximum value is specified generate `heim_integer` + + - constrained `INTEGER` types whose minimum and maximum fit in `unsigned`'s + range generate `unsigned` + + - constrained `INTEGER` types whose minimum and maximum fit in `int`'s + range generate `int` + + - constrained `INTEGER` types whose minimum and maximum fit in `uin64_t`'s + range generate `uin64_t` + + - constrained `INTEGER` types whose minimum and maximum fit in `in64_t`'s + range generate `in64_t` + + - `INTEGER` types with named members generate a C `struct` with `unsigned int` + bit-field members + + - all other `INTEGER` types generate `heim_integer` + +Various code generation options are provided as command-line options or as +ASN.1 usage conventions: + + - `--type-file=C-HEADER-FILE` -- generate an `#include` directive to include + that header for some useful base types (within Heimdal we use `krb5-types.h` + as that header) + + - `--template` -- use the "template" (byte-coded) backend + + - `--one-code-file` -- causes all the code generated to be placed in one C + source file (mutually exclusive with `--template`) + + - `--support-ber` -- accept non-DER BER when decoding + + - `--preserve-binary=TYPE` -- add a `_save` field to the C struct type for the + ASN.1 `TYPE` where the decoder will save the original encoding of the value + of `TYPE` it decodes (useful for cryptographic signature verification!) + + - `--sequence=TYPE` -- generate `add_TYPE()` and `remove_TYPE()` utility + functions (`TYPE` must be a `SET OF` or `SEQUENCE OF` type) + + - `--decorate=DECORATION` -- add fields to generated C struct types as + described in the `DECORATION` (see the + [manual page](#Manual-Page-for-asn1_compile) below) + + Decoration fields are never encoded or decoded. They are meant to be used + for, e.g., application state keeping. + + - `--no-parse-units` -- normally the compiler generates code to use the + Heimdal `libroken` "units" utility for displaying bit fields; this option + disables this + +See the [manual page for `asn1_compile(1)`](#Manual-Page-for-asn1_compile) for +a full listing of command-line options. + +### Manual Page for `asn1_compile(1)` + +``` +ASN1_COMPILE(1) BSD General Commands Manual ASN1_COMPILE(1) + +NAME + asn1_compile — compile ASN.1 modules + +SYNOPSIS + asn1_compile [--template] [--prefix-enum] [--enum-prefix=PREFIX] + [--encode-rfc1510-bit-string] [--decode-dce-ber] + [--support-ber] [--preserve-binary=TYPE] [--sequence=TYPE] + [--decorate=DECORATION] [--one-code-file] [--gen-name=NAME] + [--option-file=FILE] [--original-order] [--no-parse-units] + [--type-file=C-HEADER-FILE] [--version] [--help] + [FILE.asn1 [NAME]] + +DESCRIPTION + asn1_compile compiles an ASN.1 module into C source code and header + files. + + A fairly large subset of ASN.1 as specified in X.680, and the ASN.1 In‐ + formation Object System as specified in X.681, X.682, and X.683 is sup‐ + ported, with support for the Distinguished Encoding Rules (DER), partial + Basic Encoding Rules (BER) support, and experimental JSON support (encod‐ + ing only at this time). + + See the compiler's README files for details about the C code and inter‐ + faces it generates. + + The Information Object System support includes automatic codec support + for encoding and decoding through “open types” which are also known as + “typed holes”. See RFC 5912 for examples of how to use the ASN.1 Infor‐ + mation Object System via X.681/X.682/X.683 annotations. See the com‐ + piler's README files for more information on ASN.1 Information Object + System support. + + Extensions specific to Heimdal are generally not syntactic in nature but + rather command-line options to this program. For example, one can use + command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei‐ + ther encoded nor decoded; + etc. + + ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + + Size and range constraints on the ‘INTEGER’ type cause the compiler to + generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, + ‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which + represents an integer of arbitrary size. + + Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. + + Options supported: + + --template + Use the “template” backend instead of the “codegen” backend + (which is the default backend). + + The template backend generates “templates” which are akin to + bytecode, and which are interpreted at run-time. + + The codegen backend generates C code for all functions directly, + with no template interpretation. + + The template backend scales better than the codegen backend be‐ + cause as we add support for more encoding rules and more opera‐ + tions (we may add value comparators) the templates stay mostly + the same, thus scaling linearly with size of module. Whereas the + codegen backend scales linear with the product of module size and + number of encoding rules supported. + + --prefix-enum + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --enum-prefix=PREFIX + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --encode-rfc1510-bit-string + Use RFC1510, non-standard handling of “BIT STRING” types. + + --decode-dce-ber + + --support-ber + + --preserve-binary=TYPE + Generate a field named ‘_save’ in the C struct generated for the + named TYPE. This field is used to preserve the original encoding + of the value of the TYPE. + + This is useful for cryptographic applications so that they can + check signatures of encoded values as-received without having to + re-encode those values. + + For example, the TBSCertificate type should have values preserved + so that Certificate validation can check the signatureValue over + the tbsCertificate's value as-received. + + The alternative of encoding a value to check a signature of it is + brittle. For types where non-canonical encodings (such as BER) + are allowed, this alternative is bound to fail. Thus the point + of this option. + + --sequence=TYPE + Generate add/remove functions for the named ASN.1 TYPE which must + be a ‘SET OF’ or ‘SEQUENCE OF’ type. + + --decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given ASN.1 type FIELD-ASN1-TYPE, but do not encode or decode + it. If the fname ends in a question mark, then treat the field + as OPTIONAL. + + This is useful for adding fields to existing types that can be + used for internal bookkeeping but which do not affect interoper‐ + ability because they are neither encoded nor decoded. For exam‐ + ple, one might decorate a request type with state needed during + processing of the request. + + --decorate=ASN1-TYPE:void*:fname + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + type ‘void *’ (but do not encode or decode it. + + The destructor and copy constructor functions generated by this + compiler for ASN1-TYPE will set this field to the ‘NULL’ pointer. + + --decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given external C type FIELD-C-TYPE, declared in the given + header but do not encode or decode this field. If the fname ends + in a question mark, then treat the field as OPTIONAL. + + The header must include double quotes or angle brackets. The + copyfn must be the name of a copy constructor function that takes + a pointer to a source value of the type, and a pointer to a des‐ + tination value of the type, in that order, and which returns zero + on success or else a system error code on failure. The freefn + must be the name of a destructor function that takes a pointer to + a value of the type and which releases resources referenced by + that value, but does not free the value itself (the run-time al‐ + locates this value as needed from the C heap). The freefn should + also reset the value to a pristine state (such as all zeros). + + If the copyfn and freefn are empty strings, then the decoration + field will neither be copied nor freed by the functions generated + for the TYPE. + + --one-code-file + Generate a single source code file. Otherwise a separate code + file will be generated for every type. + + --gen-name=NAME + Use NAME to form the names of the files generated. + + --option-file=FILE + Take additional command-line options from FILE. + + --original-order + Attempt to preserve the original order of type definition in the + ASN.1 module. By default the compiler generates types in a topo‐ + logical sort order. + + --no-parse-units + Do not generate to-int / from-int functions for enumeration + types. + + --type-file=C-HEADER-FILE + Generate an include of the named header file that might be needed + for common type defintions. + + --version + + --help + +NOTES + Currently only the template backend supports automatic encoding and de‐ + coding of open types via the ASN.1 Information Object System and + X.681/X.682/X.683 annotations. + +HEIMDAL February 22, 2021 HEIMDAL +``` + +# Future Directions + +The Heimdal ASN.1 compiler is focused on PKIX and Kerberos, and is almost +feature-complete for dealing with those. It could use additional support for +X.681/X.682/X.683 elements that would allow the compiler to understand +`Certificate ::= SIGNED{TBSCertificate}`, particularly the ability to +automatically validate cryptographic algorithm parameters. However, this is +not that important. + +Another feature that might be nice is the ability of callers to specify smaller +information object sets when decoding values of types like `Certificate`, +mainly to avoid spending CPU cycles and memory allocations on decoding types in +typed holes that are not of interest to the application. + +For testing purposes, a JSON reader to go with the JSON printer might be nice, +and anyways, would make for a generally useful tool. + +Another feature that would be nice would to automatically generate SQL and LDAP +code for HDB based on `lib/hdb/hdb.asn1` (with certain usage conventions and/or +compiler command-line options to make it possible to map schemas usefully). + +For the `hxtool` command, it would be nice if the user could input arbitrary +certificate extensions and `subjectAlternativeName` (SAN) values in JSON + an +ASN.1 module and type reference that `hxtool` could then parse and encode using +the ASN.1 compiler and library. Currently the `hx509` library and its `hxtool` +command must be taught about every SAN type. diff --git a/third_party/heimdal/lib/asn1/Makefile.am b/third_party/heimdal/lib/asn1/Makefile.am index 94d24fc47eb6..eb0308ee13cc 100644 --- a/third_party/heimdal/lib/asn1/Makefile.am +++ b/third_party/heimdal/lib/asn1/Makefile.am @@ -2,9 +2,11 @@ include $(top_srcdir)/Makefile.am.common -YFLAGS = -d -t +WFLAGS += $(WFLAGS_ENUM_CONV) -AM_CPPFLAGS += $(ROKEN_RENAME) +YFLAGS = -o asn1parse.c -t + +AM_CPPFLAGS += $(ROKEN_RENAME) -I$(top_builddir)/include -I$(top_srcdir)/lib/base man_MANS = asn1_print.1 asn1_compile.1 @@ -30,64 +32,64 @@ libasn1template_la_LIBADD = \ @LIB_com_err@ \ $(LIBADD_roken) -BUILT_SOURCES = \ - $(gen_files_rfc2459:.x=.c) \ - $(gen_files_rfc4108:.x=.c) \ - $(gen_files_cms:.x=.c) \ - $(gen_files_krb5:.x=.c) \ - $(gen_files_ocsp:.x=.c) \ - $(gen_files_pkinit:.x=.c) \ - $(gen_files_pkcs8:.x=.c) \ - $(gen_files_pkcs9:.x=.c) \ - $(gen_files_pkcs10:.x=.c) \ - $(gen_files_pkcs12:.x=.c) \ - $(gen_files_digest:.x=.c) \ - $(gen_files_kx509:.x=.c) - -BUILT_TEMPLATE_SOURCES = \ - $(gen_files_rfc2459_template:.x=.c) \ - $(gen_files_rfc4108_template:.x=.c) \ - $(gen_files_cms_template:.x=.c) \ - $(gen_files_krb5_template:.x=.c) \ - $(gen_files_ocsp_template:.x=.c) \ - $(gen_files_pkinit_template:.x=.c) \ - $(gen_files_pkcs8_template:.x=.c) \ - $(gen_files_pkcs9_template:.x=.c) \ - $(gen_files_pkcs10_template:.x=.c) \ - $(gen_files_pkcs12_template:.x=.c) \ - $(gen_files_digest_template:.x=.c) \ - $(gen_files_kx509_template:.x=.c) - -gen_files_krb5 = asn1_krb5_asn1.x -gen_files_krb5_template = asn1_krb5_template_asn1.x -gen_files_cms = asn1_cms_asn1.x -gen_files_cms_template = asn1_cms_template_asn1.x -gen_files_crmf = asn1_crmf_asn1.x -gen_files_crmf_template = asn1_crmf_template_asn1.x -gen_files_rfc2459 = asn1_rfc2459_asn1.x -gen_files_rfc2459_template = asn1_rfc2459_template_asn1.x -gen_files_rfc4108 = asn1_rfc4108_asn1.x -gen_files_rfc4108_template = asn1_rfc4108_template_asn1.x -gen_files_ocsp = asn1_ocsp_asn1.x -gen_files_ocsp_template = asn1_ocsp_template_asn1.x -gen_files_pkinit = asn1_pkinit_asn1.x -gen_files_pkinit_template = asn1_pkinit_template_asn1.x -gen_files_pkcs10 = asn1_pkcs10_asn1.x -gen_files_pkcs10_template = asn1_pkcs10_template_asn1.x -gen_files_pkcs12 = asn1_pkcs12_asn1.x -gen_files_pkcs12_template = asn1_pkcs12_template_asn1.x -gen_files_pkcs8 = asn1_pkcs8_asn1.x -gen_files_pkcs8_template = asn1_pkcs8_template_asn1.x -gen_files_pkcs9 = asn1_pkcs9_asn1.x -gen_files_pkcs9_template = asn1_pkcs9_template_asn1.x -gen_files_test = asn1_test_asn1.x -gen_files_test_template = asn1_test_template_asn1.x -gen_files_digest = asn1_digest_asn1.x -gen_files_digest_template = asn1_digest_template_asn1.x -gen_files_kx509 = asn1_kx509_asn1.x -gen_files_kx509_template = asn1_kx509_template_asn1.x -gen_files_x690sample = asn1_x690sample_asn1.x -gen_files_x690sample_template = asn1_x690sample_template_asn1.x +BUILT_SOURCES = \ + $(gen_files_rfc2459) \ + $(gen_files_rfc4108) \ + $(gen_files_cms) \ + $(gen_files_krb5) \ + $(gen_files_ocsp) \ + $(gen_files_pkinit) \ + $(gen_files_pkcs8) \ + $(gen_files_pkcs9) \ + $(gen_files_pkcs10) \ + $(gen_files_pkcs12) \ + $(gen_files_digest) \ + $(gen_files_kx509) + +BUILT_TEMPLATE_SOURCES = \ + $(gen_files_rfc2459_template) \ + $(gen_files_rfc4108_template) \ + $(gen_files_cms_template) \ + $(gen_files_krb5_template) \ + $(gen_files_ocsp_template) \ + $(gen_files_pkinit_template) \ + $(gen_files_pkcs8_template) \ + $(gen_files_pkcs9_template) \ + $(gen_files_pkcs10_template) \ + $(gen_files_pkcs12_template) \ + $(gen_files_digest_template) \ + $(gen_files_kx509_template) + +gen_files_krb5 = asn1_krb5_asn1.c +gen_files_krb5_template = asn1_krb5_template_asn1.c +gen_files_cms = asn1_cms_asn1.c +gen_files_cms_template = asn1_cms_template_asn1.c +gen_files_crmf = asn1_crmf_asn1.c +gen_files_crmf_template = asn1_crmf_template_asn1.c +gen_files_rfc2459 = asn1_rfc2459_asn1.c +gen_files_rfc2459_template = asn1_rfc2459_template_asn1.c +gen_files_rfc4108 = asn1_rfc4108_asn1.c +gen_files_rfc4108_template = asn1_rfc4108_template_asn1.c +gen_files_ocsp = asn1_ocsp_asn1.c +gen_files_ocsp_template = asn1_ocsp_template_asn1.c +gen_files_pkinit = asn1_pkinit_asn1.c +gen_files_pkinit_template = asn1_pkinit_template_asn1.c +gen_files_pkcs10 = asn1_pkcs10_asn1.c +gen_files_pkcs10_template = asn1_pkcs10_template_asn1.c +gen_files_pkcs12 = asn1_pkcs12_asn1.c +gen_files_pkcs12_template = asn1_pkcs12_template_asn1.c +gen_files_pkcs8 = asn1_pkcs8_asn1.c +gen_files_pkcs8_template = asn1_pkcs8_template_asn1.c +gen_files_pkcs9 = asn1_pkcs9_asn1.c +gen_files_pkcs9_template = asn1_pkcs9_template_asn1.c +gen_files_test = asn1_test_asn1.c +gen_files_test_template = asn1_test_template_asn1.c +gen_files_digest = asn1_digest_asn1.c +gen_files_digest_template = asn1_digest_template_asn1.c +gen_files_kx509 = asn1_kx509_asn1.c +gen_files_kx509_template = asn1_kx509_template_asn1.c +gen_files_x690sample = asn1_x690sample_asn1.c +gen_files_x690sample_template = asn1_x690sample_template_asn1.c oid_resolution.lo: $(BUILT_SOURCES) @@ -100,20 +102,20 @@ check_PROGRAMS = $(TESTS) asn1_gen_SOURCES = asn1_gen.c asn1_print_SOURCES = asn1_print.c -asn1_print_SOURCES += $(gen_files_x690sample_template:.x=.c) +asn1_print_SOURCES += $(gen_files_x690sample_template) asn1_print_CPPFLAGS = -DASN1_PRINT_SUPPORTED check_der_SOURCES = check-der.c check-common.c check-common.h check_template_SOURCES = check-template.c check-common.c check-common.h -nodist_check_template_SOURCES = $(gen_files_test_template:.x=.c) +nodist_check_template_SOURCES = $(gen_files_test_template) check_gen_template_CPPFLAGS = -DASN1_IOS_SUPPORTED dist_check_gen_template_SOURCES = check-gen.c check-common.c check-common.h -nodist_check_gen_template_SOURCES = $(gen_files_test_template:.x=.c) \ - $(gen_files_x690sample_template:.x=.c) +nodist_check_gen_template_SOURCES = $(gen_files_test_template) \ + $(gen_files_x690sample_template) dist_check_gen_SOURCES = check-gen.c check-common.c check-common.h -nodist_check_gen_SOURCES = $(gen_files_test:.x=.c) $(gen_files_x690sample:.x=.c) +nodist_check_gen_SOURCES = $(gen_files_test) $(gen_files_x690sample) build_HEADERZ = asn1-template.h @@ -229,37 +231,37 @@ CLEANFILES = \ $(nodist_check_gen_SOURCES) \ asn1parse.c asn1parse.h lex.c \ asn1_err.c asn1_err.h \ - rfc2459_asn1_files rfc2459_asn1*.h* rfc2459_asn1*.x \ - rfc2459_template_asn1_files rfc2459_template_asn1*.h* rfc2459_template_asn1*.x \ - rfc4108_asn1_files rfc4108_asn1*.h* rfc4108_asn1*.x \ - rfc4108_template_asn1_files rfc4108_template_asn1*.h* rfc4108_template_asn1*.x \ - cms_asn1_files cms_asn1*.h* cms_asn1*.x \ - cms_template_asn1_files cms_template_asn1*.h* cms_template_asn1*.x \ - crmf_asn1_files crmf_asn1*.h* crmf_asn1*.x \ - crmf_template_asn1_files crmf_template_asn1*.h* crmf_template_asn1*.x \ - krb5_asn1_files krb5_asn1*.h* krb5_asn1*.x \ - krb5_template_asn1_files krb5_template_asn1*.h* krb5_template_asn1*.x \ - ocsp_asn1_files ocsp_asn1*.h* ocsp_asn1*.x \ - ocsp_template_asn1_files ocsp_template_asn1*.h* ocsp_template_asn1*.x \ - pkinit_asn1_files pkinit_asn1*.h* pkinit_asn1*.x \ - pkinit_template_asn1_files pkinit_template_asn1*.h* pkinit_template_asn1*.x \ - pkcs8_asn1_files pkcs8_asn1*.h* pkcs8_asn1*.x* \ - pkcs8_template_asn1_files pkcs8_template_asn1*.h* pkcs8_template_asn1*.x* \ - pkcs9_asn1_files pkcs9_asn1*.h* pkcs9_asn1*.x \ - pkcs9_template_asn1_files pkcs9_template_asn1*.h* pkcs9_template_asn1*.x \ - pkcs10_asn1_files pkcs10_asn1*.h* pkcs10_asn1*.x \ - pkcs10_template_asn1_files pkcs10_template_asn1*.h* pkcs10_template_asn1*.x \ - pkcs12_asn1_files pkcs12_asn1*.h* pkcs12_asn1*.x \ - pkcs12_template_asn1_files pkcs12_template_asn1*.h* pkcs12_template_asn1*.x \ - digest_asn1_files digest_asn1*.h* digest_asn1*.x \ - digest_template_asn1_files digest_template_asn1*.h* digest_template_asn1*.x \ - kx509_asn1_files kx509_asn1*.h* kx509_asn1*.x \ - kx509_template_asn1_files kx509_template_asn1*.h* kx509_template_asn1*.x \ - x690sample_asn1_files x690sample_asn1*.h* x690sample_asn1*.x \ - x690sample_template_asn1_files x690sample_template_asn1*.h* x690sample_template_asn1*.x \ - test_asn1_files test_asn1*.h* test_asn1*.x \ - test_template_asn1_files test_template_asn1*.h* test_template_asn1*.x \ - asn1_*.tmp.c asn1_*.x asn1_*.json + rfc2459_asn1_files rfc2459_asn1*.h \ + rfc2459_template_asn1_files rfc2459_template_asn1*.h \ + rfc4108_asn1_files rfc4108_asn1*.h \ + rfc4108_template_asn1_files rfc4108_template_asn1*.h \ + cms_asn1_files cms_asn1*.h \ + cms_template_asn1_files cms_template_asn1* \ + crmf_asn1_files crmf_asn1* \ + crmf_template_asn1_files crmf_template_asn1* \ + krb5_asn1_files krb5_asn1* \ + krb5_template_asn1_files krb5_template_asn1* \ + ocsp_asn1_files ocsp_asn1* \ + ocsp_template_asn1_files ocsp_template_asn1* \ + pkinit_asn1_files pkinit_asn1* \ + pkinit_template_asn1_files pkinit_template_asn1* \ + pkcs8_asn1_files pkcs8_asn1* \ + pkcs8_template_asn1_files pkcs8_template_asn1* \ + pkcs9_asn1_files pkcs9_asn1* \ + pkcs9_template_asn1_files pkcs9_template_asn1* \ + pkcs10_asn1_files pkcs10_asn1* \ + pkcs10_template_asn1_files pkcs10_template_asn1* \ + pkcs12_asn1_files pkcs12_asn1* \ + pkcs12_template_asn1_files pkcs12_template_asn1* \ + digest_asn1_files digest_asn1* \ + digest_template_asn1_files digest_template_asn1* \ + kx509_asn1_files kx509_asn1* \ + kx509_template_asn1_files kx509_template_asn1* \ + x690sample_asn1_files x690sample_asn1* \ + x690sample_template_asn1_files x690sample_template_asn1* \ + test_asn1_files test_asn1* \ + test_template_asn1_files test_template_asn1* \ + asn1_*_asn1.c *_asn1.json *_asn1_syms.c *_asn1_oids.c dist_include_HEADERS = der.h heim_asn1.h dist_include_HEADERS += $(srcdir)/der-protos.h $(srcdir)/der-private.h @@ -338,36 +340,36 @@ $(asn1_print_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) asn1parse.h: asn1parse.c -$(gen_files_krb5) krb5_asn1.hx krb5_asn1-priv.hx: krb5_asn1_files -$(gen_files_krb5_template) krb5_template_asn1.hx krb5_template_asn1-priv.hx: krb5_template_asn1_files -$(gen_files_ocsp) ocsp_asn1.hx ocsp_asn1-priv.hx: ocsp_asn1_files -$(gen_files_ocsp_template) ocsp_template_asn1.hx ocsp_template_asn1-priv.hx: ocsp_template_asn1_files -$(gen_files_pkinit) pkinit_asn1.hx pkinit_asn1-priv.hx: pkinit_asn1_files -$(gen_files_pkinit_template) pkinit_template_asn1.hx pkinit_template_asn1-priv.hx: pkinit_template_asn1_files -$(gen_files_pkcs8) pkcs8_asn1.hx pkcs8_asn1-priv.hx: pkcs8_asn1_files -$(gen_files_pkcs8_template) pkcs8_template_asn1.hx pkcs8_template_asn1-priv.hx: pkcs8_template_asn1_files -$(gen_files_pkcs9) pkcs9_asn1.hx pkcs9_asn1-priv.hx: pkcs9_asn1_files -$(gen_files_pkcs9_template) pkcs9_template_asn1.hx pkcs9_template_asn1-priv.hx: pkcs9_template_asn1_files -$(gen_files_pkcs10) pkcs10_asn1.hx pkcs10_asn1-priv.hx: pkcs10_asn1_files -$(gen_files_pkcs10_template) pkcs10_template_asn1.hx pkcs10_template_asn1-priv.hx: pkcs10_template_asn1_files -$(gen_files_pkcs12) pkcs12_asn1.hx pkcs12_asn1-priv.hx: pkcs12_asn1_files -$(gen_files_pkcs12_template) pkcs12_template_asn1.hx pkcs12_template_asn1-priv.hx: pkcs12_template_asn1_files -$(gen_files_digest) digest_asn1.hx digest_asn1-priv.hx: digest_asn1_files -$(gen_files_digest_template) digest_template_asn1.hx digest_template_asn1-priv.hx: digest_template_asn1_files -$(gen_files_kx509) kx509_asn1.hx kx509_asn1-priv.hx: kx509_asn1_files -$(gen_files_kx509_template) kx509_template_asn1.hx kx509_template_asn1-priv.hx: kx509_template_asn1_files -$(gen_files_rfc2459) rfc2459_asn1.hx rfc2459_asn1-priv.hx: rfc2459_asn1_files -$(gen_files_rfc2459_template) rfc2459_template_asn1.hx rfc2459_template_asn1-priv.hx: rfc2459_template_asn1_files -$(gen_files_rfc4108) rfc4108_asn1.hx rfc4108_asn1-priv.hx: rfc4108_asn1_files -$(gen_files_rfc4108_template) rfc4108_template_asn1.hx rfc4108_template_asn1-priv.hx: rfc4108_template_asn1_files -$(gen_files_cms) cms_asn1.hx cms_asn1-priv.hx: cms_asn1_files -$(gen_files_cms_template) cms_template_asn1.hx cms_template_asn1-priv.hx: cms_template_asn1_files -$(gen_files_crmf) crmf_asn1.hx crmf_asn1-priv.hx: crmf_asn1_files -$(gen_files_crmf_template) crmf_template_asn1.hx crmf_template_asn1-priv.hx: crmf_template_asn1_files -$(gen_files_x690sample) x690sample_asn1.hx x690sample_asn1-priv.hx: x690sample_asn1_files -$(gen_files_x690sample_template) x690sample_template_asn1.hx x690sample_template_asn1-priv.hx: x690sample_template_asn1_files -$(gen_files_test) test_asn1.hx test_asn1-priv.hx: test_asn1_files -$(gen_files_test_template) test_template_asn1.hx test_template_asn1-priv.hx: test_template_asn1_files +$(gen_files_krb5) krb5_asn1.h krb5_asn1-priv.h: krb5_asn1_files +$(gen_files_krb5_template) krb5_template_asn1.h krb5_template_asn1-priv.h: krb5_template_asn1_files +$(gen_files_ocsp) ocsp_asn1.h ocsp_asn1-priv.h: ocsp_asn1_files +$(gen_files_ocsp_template) ocsp_template_asn1.h ocsp_template_asn1-priv.h: ocsp_template_asn1_files +$(gen_files_pkinit) pkinit_asn1.h pkinit_asn1-priv.h: pkinit_asn1_files +$(gen_files_pkinit_template) pkinit_template_asn1.h pkinit_template_asn1-priv.h: pkinit_template_asn1_files +$(gen_files_pkcs8) pkcs8_asn1.h pkcs8_asn1-priv.h: pkcs8_asn1_files +$(gen_files_pkcs8_template) pkcs8_template_asn1.h pkcs8_template_asn1-priv.h: pkcs8_template_asn1_files +$(gen_files_pkcs9) pkcs9_asn1.h pkcs9_asn1-priv.h: pkcs9_asn1_files +$(gen_files_pkcs9_template) pkcs9_template_asn1.h pkcs9_template_asn1-priv.h: pkcs9_template_asn1_files +$(gen_files_pkcs10) pkcs10_asn1.h pkcs10_asn1-priv.h: pkcs10_asn1_files +$(gen_files_pkcs10_template) pkcs10_template_asn1.h pkcs10_template_asn1-priv.h: pkcs10_template_asn1_files +$(gen_files_pkcs12) pkcs12_asn1.h pkcs12_asn1-priv.h: pkcs12_asn1_files +$(gen_files_pkcs12_template) pkcs12_template_asn1.h pkcs12_template_asn1-priv.h: pkcs12_template_asn1_files +$(gen_files_digest) digest_asn1.h digest_asn1-priv.h: digest_asn1_files +$(gen_files_digest_template) digest_template_asn1.h digest_template_asn1-priv.h: digest_template_asn1_files +$(gen_files_kx509) kx509_asn1.h kx509_asn1-priv.h: kx509_asn1_files +$(gen_files_kx509_template) kx509_template_asn1.h kx509_template_asn1-priv.h: kx509_template_asn1_files +$(gen_files_rfc2459) rfc2459_asn1.h rfc2459_asn1-priv.h: rfc2459_asn1_files +$(gen_files_rfc2459_template) rfc2459_template_asn1.h rfc2459_template_asn1-priv.h: rfc2459_template_asn1_files +$(gen_files_rfc4108) rfc4108_asn1.h rfc4108_asn1-priv.h: rfc4108_asn1_files +$(gen_files_rfc4108_template) rfc4108_template_asn1.h rfc4108_template_asn1-priv.h: rfc4108_template_asn1_files +$(gen_files_cms) cms_asn1.h cms_asn1-priv.h: cms_asn1_files +$(gen_files_cms_template) cms_template_asn1.h cms_template_asn1-priv.h: cms_template_asn1_files +$(gen_files_crmf) crmf_asn1.h crmf_asn1-priv.h: crmf_asn1_files +$(gen_files_crmf_template) crmf_template_asn1.h crmf_template_asn1-priv.h: crmf_template_asn1_files +$(gen_files_x690sample) x690sample_asn1.h x690sample_asn1-priv.h: x690sample_asn1_files +$(gen_files_x690sample_template) x690sample_template_asn1.h x690sample_template_asn1-priv.h: x690sample_template_asn1_files +$(gen_files_test) test_asn1.h test_asn1-priv.h: test_asn1_files +$(gen_files_test_template) test_template_asn1.h test_template_asn1-priv.h: test_template_asn1_files if ASN1_TEMPLATING TEMPLATE_OPTION=--template @@ -379,136 +381,171 @@ endif # templated anyways. rfc2459_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc2459.asn1 $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_template_asn1 || (rm -f rfc2459_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc2459_template_asn1.c rfc4108_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4108.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/rfc4108.asn1 rfc4108_template_asn1 || (rm -f rfc4108_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc4108_template_asn1.c cms_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/cms.asn1 $(srcdir)/cms.opt $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/cms.opt $(srcdir)/cms.asn1 cms_template_asn1 || (rm -f cms_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_cms_template_asn1.c crmf_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_template_asn1 || (rm -f crmf_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_crmf_template_asn1.c krb5_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt $(ASN1_COMPILE) --one-code-file --template \ --option-file=$(srcdir)/krb5.opt \ - --decorate='Principal:PrincipalNameAttrs:nameattrs?' \ $(srcdir)/krb5.asn1 krb5_template_asn1 || (rm -f krb5_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_krb5_template_asn1.c ocsp_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_template_asn1 || (rm -f ocsp_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_ocsp_template_asn1.c pkinit_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkinit.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkinit.asn1 pkinit_template_asn1 || (rm -f pkinit_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkinit_template_asn1.c pkcs8_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs8.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs8.asn1 pkcs8_template_asn1 || (rm -f pkcs8_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs8_template_asn1.c pkcs9_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs9.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs9.asn1 pkcs9_template_asn1 || (rm -f pkcs9_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs9_template_asn1.c pkcs10_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs10.asn1 $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/pkcs10.opt $(srcdir)/pkcs10.asn1 pkcs10_template_asn1 || (rm -f pkcs10_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs10_template_asn1.c pkcs12_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs12.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs12.asn1 pkcs12_template_asn1 || (rm -f pkcs12_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs12_template_asn1.c digest_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/digest.asn1 digest_template_asn1 || (rm -f digest_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_digest_template_asn1.c kx509_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/kx509.asn1 kx509_template_asn1 || (rm -f kx509_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_kx509_template_asn1.c rfc2459_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc2459.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_asn1 || (rm -f rfc2459_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc2459_asn1.c rfc4108_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4108.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/rfc4108.asn1 rfc4108_asn1 || (rm -f rfc4108_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc4108_asn1.c cms_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/cms.asn1 $(srcdir)/cms.opt $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/cms.opt $(srcdir)/cms.asn1 cms_asn1 || (rm -f cms_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_cms_asn1.c crmf_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_asn1 || (rm -f crmf_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_crmf_asn1.c krb5_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) \ --option-file=$(srcdir)/krb5.opt \ - --decorate='Principal:PrincipalNameAttrs:nameattrs?' \ $(srcdir)/krb5.asn1 krb5_asn1 || (rm -f krb5_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_krb5_asn1.c ocsp_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_asn1 || (rm -f ocsp_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_ocsp_asn1.c pkinit_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkinit.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkinit.asn1 pkinit_asn1 || (rm -f pkinit_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkinit_asn1.c pkcs8_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs8.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs8.asn1 pkcs8_asn1 || (rm -f pkcs8_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs8_asn1.c pkcs9_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs9.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs9.asn1 pkcs9_asn1 || (rm -f pkcs9_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs9_asn1.c pkcs10_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs10.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/pkcs10.opt $(srcdir)/pkcs10.asn1 pkcs10_asn1 || (rm -f pkcs10_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs10_asn1.c pkcs12_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs12.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs12.asn1 pkcs12_asn1 || (rm -f pkcs12_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs12_asn1.c digest_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/digest.asn1 digest_asn1 || (rm -f digest_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_digest_asn1.c kx509_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/kx509.asn1 kx509_asn1 || (rm -f kx509_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_kx509_asn1.c x690sample_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 $(ASN1_COMPILE) --one-code-file --template $(srcdir)/x690sample.asn1 x690sample_template_asn1 || (rm -f x690sample_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_x690sample_template_asn1.c x690sample_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 $(ASN1_COMPILE) --one-code-file $(srcdir)/x690sample.asn1 x690sample_asn1 || (rm -f x690sample_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_x690sample_asn1.c test_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 $(ASN1_COMPILE) --one-code-file \ --template \ - --sequence=TESTSeqOf \ - --decorate='TESTDecorated:TESTuint32:version2?' \ + --option-file=$(srcdir)/test.opt \ $(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_test_template_asn1.c test_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 $(ASN1_COMPILE) --one-code-file \ - --decorate='TESTDecorated:TESTuint32:version2?' \ - --sequence=TESTSeqOf \ + --option-file=$(srcdir)/test.opt \ $(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1) - - -EXTRA_DIST = \ - NTMakefile \ - README.template \ - asn1_compile-version.rc \ - libasn1-exports.def \ - cms.asn1 \ - cms.opt \ - crmf.asn1 \ - crmf.opt \ - asn1_err.et \ - canthandle.asn1 \ - digest.asn1 \ - krb5.asn1 \ - krb5.opt \ - kx509.asn1 \ - ocsp.asn1 \ - pkcs12.asn1 \ - pkcs8.asn1 \ - pkcs9.asn1 \ - pkcs10.asn1 \ - pkinit.asn1 \ - rfc2459.asn1 \ - rfc4108.asn1 \ - tcg.asn1 \ - setchgpw2.asn1 \ - x690sample.asn1 \ - test.asn1 \ - test.gen \ + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_test_asn1.c + + +EXTRA_DIST = \ + NTMakefile \ + README-template.md \ + asn1_compile-version.rc \ + libasn1-exports.def \ + canthandle.asn1 \ + cms.asn1 \ + cms.opt \ + crmf.asn1 \ + crmf.opt \ + digest.asn1 \ + krb5.asn1 \ + krb5.opt \ + kx509.asn1 \ + ocsp.asn1 \ + ocsp.opt \ + pkcs10.asn1 \ + pkcs10.opt \ + pkcs12.asn1 \ + pkcs8.asn1 \ + pkcs9.asn1 \ + pkinit.asn1 \ + pku2u.asn1 \ + rfc2459.asn1 \ + rfc2459.opt \ + rfc4108.asn1 \ + setchgpw2.asn1 \ + tcg.asn1 \ + test.asn1 \ + test.opt \ + x690sample.asn1 \ + test.gen \ + asn1_err.et \ + asn1_err.c \ + asn1_err.h \ + asn1_print.1 \ + asn1_compile.1 \ version-script.map DER_PROTOS = $(srcdir)/der-protos.h $(srcdir)/der-private.h diff --git a/third_party/heimdal/lib/asn1/NTMakefile b/third_party/heimdal/lib/asn1/NTMakefile index eca92bd3853c..19255c6cf710 100644 --- a/third_party/heimdal/lib/asn1/NTMakefile +++ b/third_party/heimdal/lib/asn1/NTMakefile @@ -1,6 +1,6 @@ ######################################################################## # -# Copyright (c) 2009, Secure Endpoints Inc. +# Copyright (c) 2009-2022, Secure Endpoints Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,42 +31,10 @@ RELDIR=lib\asn1 -intcflags=-I$(SRCDIR) -I$(OBJ) -DROKEN_RENAME -DASN1_IOS_SUPPORTED +intcflags=-I$(SRCDIR) -I$(OBJ) -DROKEN_RENAME -DASN1_IOS_SUPPORTED -DASN1_LIB !include ../../windows/NTMakefile.w32 -gen_files_krb5 = $(OBJ)\asn1_krb5_asn1.x - -gen_files_cms = $(OBJ)\asn1_cms_asn1.x - -gen_files_crmf = $(OBJ)\asn1_crmf_asn1.x - -gen_files_rfc2459 = $(OBJ)\asn1_rfc2459_asn1.x - -gen_files_rfc4108 = $(OBJ)\asn1_rfc4108_asn1.x - -gen_files_ocsp = $(OBJ)\asn1_ocsp_asn1.x - -gen_files_pkinit = $(OBJ)\asn1_pkinit_asn1.x - -gen_files_pkcs12 = $(OBJ)\asn1_pkcs12_asn1.x - -gen_files_pkcs8 = $(OBJ)\asn1_pkcs8_asn1.x - -gen_files_pkcs9 = $(OBJ)\asn1_pkcs9_asn1.x - -gen_files_pkcs10 = $(OBJ)\asn1_pkcs10_asn1.x - -gen_files_test = $(OBJ)\asn1_test_asn1.x - -gen_files_test_template = $(OBJ)\asn1_test_template_asn1.x - -gen_files_digest = $(OBJ)\asn1_digest_asn1.x - -gen_files_kx509 = $(OBJ)\asn1_kx509_asn1.x - -gen_files_x690sample = $(OBJ)\asn1_x690sample_asn1.x - ASN1_BINARIES = \ $(LIBEXECDIR)\asn1_compile.exe @@ -112,6 +80,21 @@ $(BINDIR)\asn1_gen.exe: $(OBJ)\asn1_gen.obj $(LIBHEIMDAL) $(EXECONLINK) $(LIBVERS) $(LIBROKEN) $(EXEPREP) +LIBASN1_X= \ + $(OBJ)\asn1_rfc2459_asn1.c \ + $(OBJ)\asn1_rfc4108_asn1.c \ + $(OBJ)\asn1_cms_asn1.c \ + $(OBJ)\asn1_krb5_asn1.c \ + $(OBJ)\asn1_ocsp_asn1.c \ + $(OBJ)\asn1_pkinit_asn1.c \ + $(OBJ)\asn1_pkcs8_asn1.c \ + $(OBJ)\asn1_pkcs9_asn1.c \ + $(OBJ)\asn1_pkcs10_asn1.c \ + $(OBJ)\asn1_pkcs12_asn1.c \ + $(OBJ)\asn1_digest_asn1.c \ + $(OBJ)\asn1_kx509_asn1.c \ + $(OBJ)\asn1_x690sample_asn1.c + LIBASN1_OBJS= \ $(OBJ)\der.obj \ $(OBJ)\der_get.obj \ @@ -124,27 +107,26 @@ LIBASN1_OBJS= \ $(OBJ)\der_format.obj \ $(OBJ)\template.obj \ $(OBJ)\extra.obj \ + $(OBJ)\oid_resolution.obj \ $(OBJ)\timegm.obj \ - $(gen_files_rfc2459:.x=.obj) \ - $(gen_files_rfc4108:.x=.obj) \ - $(gen_files_cms:.x=.obj) \ - $(gen_files_krb5:.x=.obj) \ - $(gen_files_ocsp:.x=.obj) \ - $(gen_files_pkinit:.x=.obj) \ - $(gen_files_pkcs8:.x=.obj) \ - $(gen_files_pkcs9:.x=.obj) \ - $(gen_files_pkcs10:.x=.obj) \ - $(gen_files_pkcs12:.x=.obj) \ - $(gen_files_digest:.x=.obj) \ - $(gen_files_kx509:.x=.obj) \ - $(gen_files_x690sample:.x=.obj) \ + $(OBJ)\asn1_rfc2459_asn1.obj \ + $(OBJ)\asn1_rfc4108_asn1.obj \ + $(OBJ)\asn1_cms_asn1.obj \ + $(OBJ)\asn1_krb5_asn1.obj \ + $(OBJ)\asn1_ocsp_asn1.obj \ + $(OBJ)\asn1_pkinit_asn1.obj \ + $(OBJ)\asn1_pkcs8_asn1.obj \ + $(OBJ)\asn1_pkcs9_asn1.obj \ + $(OBJ)\asn1_pkcs10_asn1.obj \ + $(OBJ)\asn1_pkcs12_asn1.obj \ + $(OBJ)\asn1_digest_asn1.obj \ + $(OBJ)\asn1_kx509_asn1.obj \ + $(OBJ)\asn1_x690sample_asn1.obj \ $(OBJ)\asn1_err.obj -$(OBJ)\oid_resolution.obj: $(LIBASN1_OBJS) - -LIBASN1_OBJS2= $(LIBASN1_OBJS) $(OBJ)\oid_resolution.obj +$(OBJ)\oid_resolution.obj: $(LIBASN1_X) -$(LIBASN1): $(LIBASN1_OBJS2) +$(LIBASN1): $(LIBASN1_OBJS) $(LIBCON_C) -out:$@ @<< $(**: = ) @@ -154,61 +136,159 @@ clean:: -$(RM) $(LIBASN1) # -# Generate list of exports -# -# This target is only used during development to generate a list of -# symbols that are exported from all the object files in LIBASN1_OBJS. -# -exports-list.txt: $(LIBASN1_OBJS) - $(PERL) ..\..\cf\w32-list-externs-from-objs.pl -q -u @<< > $@ -$(**: = -) -<< +# The static runtime version LIBASN1_S is for use by thirdparty +# components. It is not used in the construction of the Heimdal +# DLLs. + +LIBASN1_S_OBJS= \ + $(OBJ)\der.s.obj \ + $(OBJ)\der_get.s.obj \ + $(OBJ)\der_put.s.obj \ + $(OBJ)\der_free.s.obj \ + $(OBJ)\der_print.s.obj \ + $(OBJ)\der_length.s.obj \ + $(OBJ)\der_copy.s.obj \ + $(OBJ)\der_cmp.s.obj \ + $(OBJ)\der_format.s.obj \ + $(OBJ)\template.s.obj \ + $(OBJ)\extra.s.obj \ + $(OBJ)\oid_resolution.s.obj \ + $(OBJ)\timegm.s.obj \ + $(OBJ)\asn1_rfc2459_asn1.s.obj \ + $(OBJ)\asn1_rfc4108_asn1.s.obj \ + $(OBJ)\asn1_cms_asn1.s.obj \ + $(OBJ)\asn1_krb5_asn1.s.obj \ + $(OBJ)\asn1_ocsp_asn1.s.obj \ + $(OBJ)\asn1_pkinit_asn1.s.obj \ + $(OBJ)\asn1_pkcs8_asn1.s.obj \ + $(OBJ)\asn1_pkcs9_asn1.s.obj \ + $(OBJ)\asn1_pkcs10_asn1.s.obj \ + $(OBJ)\asn1_pkcs12_asn1.s.obj \ + $(OBJ)\asn1_digest_asn1.s.obj \ + $(OBJ)\asn1_kx509_asn1.s.obj \ + $(OBJ)\asn1_x690sample_asn1.s.obj \ + $(OBJ)\asn1_err.s.obj + +$(OBJ)\oid_resolution.s.obj: oid_resolution.c $(LIBASN1_X) + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ oid_resolution.c + +$(OBJ)\der.s.obj: der.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_get.s.obj: der_get.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_krb5:.x=.c) : $$(@R).x +$(OBJ)\der_put.s.obj: der_put.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_ocsp:.x=.c) : $$(@R).x +$(OBJ)\der_free.s.obj: der_free.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_pkinit:.x=.c) : $$(@R).x +$(OBJ)\der_print.s.obj: der_print.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_pkcs8:.x=.c) : $$(@R).x +$(OBJ)\der_length.s.obj: der_length.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_pkcs9:.x=.c) : $$(@R).x +$(OBJ)\der_copy.s.obj: der_copy.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_pkcs10:.x=.c) : $$(@R).x +$(OBJ)\der_cmp.s.obj: der_cmp.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_pkcs12:.x=.c) : $$(@R).x +$(OBJ)\der_format.s.obj: der_format.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_digest:.x=.c) : $$(@R).x +$(OBJ)\template.s.obj: template.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_kx509:.x=.c) : $$(@R).x +$(OBJ)\extra.s.obj: extra.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_rfc2459:.x=.c) : $$(@R).x +$(OBJ)\timegm.s.obj: timegm.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_rfc4108:.x=.c) : $$(@R).x +$(OBJ)\asn1_rfc2459_asn1.s.obj: $(OBJ)\asn1_rfc2459_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_cms:.x=.c) : $$(@R).x +$(OBJ)\asn1_rfc4108_asn1.s.obj: $(OBJ)\asn1_rfc4108_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_crmf:.x=.c) : $$(@R).x +$(OBJ)\asn1_cms_asn1.s.obj: $(OBJ)\asn1_cms_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_x690sample:.x=.c) : $$(@R).x +$(OBJ)\asn1_krb5_asn1.s.obj: $(OBJ)\asn1_krb5_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_test:.x=.c) : $$(@R).x +$(OBJ)\asn1_ocsp_asn1.s.obj: $(OBJ)\asn1_ocsp_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_test_template:.x=.c) : $$(@R).x +$(OBJ)\asn1_pkinit_asn1.s.obj: $(OBJ)\asn1_pkinit_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** -$(gen_files_krb5) $(OBJ)\krb5_asn1.hx: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5.opt +$(OBJ)\asn1_pkcs8_asn1.s.obj: $(OBJ)\asn1_pkcs8_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs9_asn1.s.obj: $(OBJ)\asn1_pkcs9_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs10_asn1.s.obj: $(OBJ)\asn1_pkcs10_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs12_asn1.s.obj: $(OBJ)\asn1_pkcs12_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_digest_asn1.s.obj: $(OBJ)\asn1_digest_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_kx509_asn1.s.obj: $(OBJ)\asn1_kx509_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_x690sample_asn1.s.obj: $(OBJ)\asn1_x690sample_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_test_asn1.s.obj: $(OBJ)\asn1_test_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_test_template_asn1.s.obj: $(OBJ)\asn1_test_template_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_err.s.obj: $(OBJ)\asn1_err.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(LIBASN1_S): $(LIBASN1_S_OBJS) + $(LIBCON_C) -out:$@ @<< +$(**: = +) +<< + +clean:: + -$(RM) $(LIBASN1_S) + + +# +# Generate list of exports +# +# This target is only used during development to generate a list of +# symbols that are exported from all the object files in LIBASN1_OBJS. +# +exports-list.txt: $(LIBASN1_OBJS) + $(PERL) ..\..\cf\w32-list-externs-from-objs.pl -q -u @<< > $@ +$(**: = +) +<< + +$(OBJ)\asn1_krb5_asn1.c $(OBJ)\krb5_asn1.h: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5.opt cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ --one-code-file \ - --decorate="Principal:PrincipalNameAttrs:nameattrs?" \ --option-file=$(SRCDIR)\krb5.opt \ $(SRCDIR)\krb5.asn1 krb5_asn1 \ || ($(RM) $(OBJ)\krb5_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_ocsp) $(OBJ)\ocsp_asn1.hx: $(BINDIR)\asn1_compile.exe ocsp.asn1 +$(OBJ)\asn1_ocsp_asn1.c $(OBJ)\ocsp_asn1.h: $(BINDIR)\asn1_compile.exe ocsp.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ @@ -219,25 +299,25 @@ $(gen_files_ocsp) $(OBJ)\ocsp_asn1.hx: $(BINDIR)\asn1_compile.exe ocsp.asn1 || ($(RM) $(OBJ)\ocsp_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_pkinit) $(OBJ)\pkinit_asn1.hx: $(BINDIR)\asn1_compile.exe pkinit.asn1 +$(OBJ)\asn1_pkinit_asn1.c $(OBJ)\pkinit_asn1.h: $(BINDIR)\asn1_compile.exe pkinit.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkinit.asn1 pkinit_asn1 \ || ($(RM) $(OBJ)\pkinit_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_pkcs8) $(OBJ)\pkcs8_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs8.asn1 +$(OBJ)\asn1_pkcs8_asn1.c $(OBJ)\pkcs8_asn1.h: $(BINDIR)\asn1_compile.exe pkcs8.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs8.asn1 pkcs8_asn1 \ || ($(RM) $(OBJ)\pkcs8_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_pkcs9) $(OBJ)\pkcs9_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs9.asn1 +$(OBJ)\asn1_pkcs9_asn1.c $(OBJ)\pkcs9_asn1.h: $(BINDIR)\asn1_compile.exe pkcs9.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs9.asn1 pkcs9_asn1 \ || ($(RM) $(OBJ)\pkcs9_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_pkcs10) $(OBJ)\pkcs10_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs10.asn1 +$(OBJ)\asn1_pkcs10_asn1.c $(OBJ)\pkcs10_asn1.h: $(BINDIR)\asn1_compile.exe pkcs10.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ @@ -248,25 +328,25 @@ $(gen_files_pkcs10) $(OBJ)\pkcs10_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs10.asn || ($(RM) $(OBJ)\pkcs10_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_pkcs12) $(OBJ)\pkcs12_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs12.asn1 +$(OBJ)\asn1_pkcs12_asn1.c $(OBJ)\pkcs12_asn1.h: $(BINDIR)\asn1_compile.exe pkcs12.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs12.asn1 pkcs12_asn1 \ || ($(RM) $(OBJ)\pkcs12_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_digest) $(OBJ)\digest_asn1.hx: $(BINDIR)\asn1_compile.exe digest.asn1 +$(OBJ)\asn1_digest_asn1.c $(OBJ)\digest_asn1.h: $(BINDIR)\asn1_compile.exe digest.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\digest.asn1 digest_asn1 \ || ($(RM) $(OBJ)\digest_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_kx509) $(OBJ)\kx509_asn1.hx: $(BINDIR)\asn1_compile.exe kx509.asn1 +$(OBJ)\asn1_kx509_asn1.c $(OBJ)\kx509_asn1.h: $(BINDIR)\asn1_compile.exe kx509.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\kx509.asn1 kx509_asn1 \ || ($(RM) $(OBJ)\kx509_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_rfc2459) $(OBJ)\rfc2459_asn1.hx: $(BINDIR)\asn1_compile.exe rfc2459.asn1 +$(OBJ)\asn1_rfc2459_asn1.c $(OBJ)\rfc2459_asn1.h: $(BINDIR)\asn1_compile.exe rfc2459.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ @@ -276,7 +356,7 @@ $(gen_files_rfc2459) $(OBJ)\rfc2459_asn1.hx: $(BINDIR)\asn1_compile.exe rfc2459. || ($(RM) $(OBJ)\rfc2459_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_rfc4108) $(OBJ)\rfc4108_asn1.hx: $(BINDIR)\asn1_compile.exe rfc4108.asn1 +$(OBJ)\asn1_rfc4108_asn1.c $(OBJ)\rfc4108_asn1.h: $(BINDIR)\asn1_compile.exe rfc4108.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ @@ -285,7 +365,7 @@ $(gen_files_rfc4108) $(OBJ)\rfc4108_asn1.hx: $(BINDIR)\asn1_compile.exe rfc4108. || ($(RM) $(OBJ)\rfc4108_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_cms) $(OBJ)\cms_asn1.hx: $(BINDIR)\asn1_compile.exe cms.asn1 cms.opt +$(OBJ)\asn1_cms_asn1.c $(OBJ)\cms_asn1.h: $(BINDIR)\asn1_compile.exe cms.asn1 cms.opt cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ @@ -294,7 +374,7 @@ $(gen_files_cms) $(OBJ)\cms_asn1.hx: $(BINDIR)\asn1_compile.exe cms.asn1 cms.opt || ($(RM) $(OBJ)\cms_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_crmf) $(OBJ)\crmf_asn1.hx: $(BINDIR)\asn1_compile.exe crmf.asn1 crmf.opt +$(gen_files_crmf) $(OBJ)\crmf_asn1.h: $(BINDIR)\asn1_compile.exe crmf.asn1 crmf.opt cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ @@ -303,7 +383,7 @@ $(gen_files_crmf) $(OBJ)\crmf_asn1.hx: $(BINDIR)\asn1_compile.exe crmf.asn1 crmf || ($(RM) $(OBJ)\crmf_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_x690sample) $(OBJ)\x690sample_asn1.hx: $(BINDIR)\asn1_compile.exe x690sample.asn1 +$(OBJ)\asn1_x690sample_asn1.c $(OBJ)\x690sample_asn1.h: $(BINDIR)\asn1_compile.exe x690sample.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ @@ -312,23 +392,22 @@ $(gen_files_x690sample) $(OBJ)\x690sample_asn1.hx: $(BINDIR)\asn1_compile.exe x6 || ($(RM) $(OBJ)\x690sample_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_test) $(OBJ)\test_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1 +$(OBJ)\asn1_test_asn1.c $(OBJ)\test_asn1.h: $(BINDIR)\asn1_compile.exe test.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ - --decorate="TESTDecorated:TESTuint32:version2?" \ - --one-code-file --sequence=TESTSeqOf \ + --option-file=$(SRCDIR)/test.opt \ + --one-code-file \ $(SRCDIR)\test.asn1 test_asn1 \ || ($(RM) $(OBJ)\test_asn1.h ; exit /b 1) cd $(SRCDIR) -$(gen_files_test_template) $(OBJ)\test_template_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1 +$(OBJ)\asn1_test_template_asn1.c $(OBJ)\test_template_asn1.h: $(BINDIR)\asn1_compile.exe test.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ - --decorate="TESTDecorated:TESTuint32:version2?" \ + --option-file=$(SRCDIR)/test.opt \ --one-code-file \ - --sequence=TESTSeqOf \ $(SRCDIR)\test.asn1 test_template_asn1 \ || ($(RM) $(OBJ)\test_template_asn1.h ; exit /b 1) cd $(SRCDIR) @@ -408,7 +487,7 @@ $(OBJ)\der-private.h: $(libasn1_SOURCES) clean:: -$(RM) $(INCDIR)\der-protos.h -all:: $(INCFILES) $(GENINCFILES) $(ASN1_BINARIES) $(LIBASN1) +all:: $(INCFILES) $(GENINCFILES) $(ASN1_BINARIES) $(LIBASN1) $(LIBASN1_S) all-tools:: $(LIBEXECDIR)\asn1_print.exe $(BINDIR)\asn1_gen.exe @@ -454,7 +533,7 @@ $(OBJ)\check-der.exe: $(OBJ)\check-der.obj $(OBJ)\check-common.obj \ $(EXEPREP_NODIST) $(OBJ)\check-gen-template.exe: $(OBJ)\check-gen.obj $(OBJ)\check-common.obj \ - $(LIBHEIMDAL) $(LIBROKEN) $(gen_files_test_template:.x=.obj) + $(LIBHEIMDAL) $(LIBROKEN) $(OBJ)\asn1_test_template_asn1.obj $(EXECONLINK) $(EXEPREP_NODIST) @@ -464,6 +543,6 @@ $(OBJ)\check-timegm.exe: $(OBJ)\check-timegm.obj \ $(EXEPREP_NODIST) $(OBJ)\check-template.exe: $(OBJ)\check-template.obj $(OBJ)\check-common.obj \ - $(LIBHEIMDAL) $(LIBROKEN) $(gen_files_test:.x=.obj) + $(LIBHEIMDAL) $(LIBROKEN) $(OBJ)\asn1_test_asn1.obj $(EXECONLINK) $(EXEPREP_NODIST) diff --git a/third_party/heimdal/lib/asn1/README.md b/third_party/heimdal/lib/asn1/README.md index a00dde72227f..9c4e6979569c 100644 --- a/third_party/heimdal/lib/asn1/README.md +++ b/third_party/heimdal/lib/asn1/README.md @@ -14,7 +14,7 @@ annotations](/lib/asn1/README-X681.md). 5. [Limitations](#Limitations) 6. [Compiler Usage](#Compiler-usage) 7. [APIs Generated by the Compiler](#APIs-generated-by-the-compiler) - 8. [asn1_print Usage](#asn1_print-usage) + 8. [`asn1_print` Usage](#asn1_print-usage) 9. [Implementation](#implementation) 10. [Moving From C](#moving-from-c) @@ -166,11 +166,14 @@ In recent times the following features have been added: - Automatic open type traversal, using a subset of X.681/X.682/X.683 for expressing the requisite metadata. + - Decoration of ASN.1 types with "hidden" fields (ones that don't get encoded + or decoded) of ASN.1 or C types. + ## Futures - JER support? - - XDR/OER support? + - XDR/NDR/OER support? - Generate comparators? (lib/hx509 has a half-baked Certificate comparator) @@ -181,6 +184,43 @@ In recent times the following features have been added: - Most of X.690 is supported for decoding, with only DER supported for encoding. + - For cryptographic applications there is a `--preserve-binary=TYPE` compiler + option that causes the `TYPE`'s C `struct` to gain a `_save` field where the + original encoding of the `TYPE` is preserved by the decoder. This allows + cryptographic applications to validate signatures, MACs, authenticated + decryption tags, checksums, etc., without having to re-encode the `TYPE` + (which wouldn't even work if the encoding received were BER and BER were + permitted for that `TYPE`). + + - Unconstrained integer types have a large integer representation in C that is + not terribly useful in common cases. Range and member constraints on + integer types cause the compiler to use `int`, `int64_t`, `unsigned int`, + and/or `uint64_t` as appropriate. + + - The Heimdal ASN.1 compiler currently handles a large subset of X.680, and + (in a branch) a small subset of X.681, X.682, and X.683, which manifests as + automatic handling of all open types contained in `SET`/`SEQUENCE` types + that are parameterized with information object sets. This allows all open + types in PKIX certificates, for example, to get decoded automatically no + matter how deeply nested. We use a TCG EK certificate that has eight + certificate extensions, including subject alternative names and subject + directory attributes where the attribute values are not string types, and + all of these things get decoded automatically. + + - The template backend dedups templates to save space. This is an O(N^2) kind + of feature that we need to make optional, but it works. (When we implement + JER this will have the side-effect of printing the wrong type names in some + cases because two or more types have the same templates and get deduped.) + + - There is an _experimental_ ASN.1 module -> JSON feature in the compiler. It + currently dumps type and value definitions, but not class, or object set + definitions. Even for types, it is not complete, and the JSON schema used + is subject to change *WITHOUT NOTICE*. + + Perhaps eventually we can re-write the compiler as a C-coded ASN.1 -> JSON + stage followed by a jq-coded code and template generator state, which would + make it much easier to extend the compiler. + - We have an `asn1_print` program that can decode DER from any exported types from any ASN.1 modules committed in Heimdal: @@ -780,40 +820,12 @@ In recent times the following features have been added: slightly different names in the ASN.1 modules in Heimdal's source tree. We'll fix this eventually.) - - Unconstrained integer types have a large integer representation in C that is - not terribly useful in common cases. Range constraints on integer types - cause the compiler to use `int32_t`, `int64_t`, `uint32_t`, and/or - `uint64_t`. - - - The Heimdal ASN.1 compiler currently handles a large subset of X.680, and - (in a branch) a small subset of X.681, X.682, and X.683, which manifests as - automatic handling of all open types contained in `SET`/`SEQUENCE` types - that are parameterized with information object sets. This allows all open - types in PKIX certificates, for example, to get decoded automatically no - matter how deeply nested. We use a TCG EK certificate that has eight - certificate extensions, including subject alternative names and subject - directory attributes where the attribute values are not string types, and - all of these things get decoded automatically. - - - The template backend dedups templates to save space. This is an O(N^2) kind - of feature that we need to make optional, but it works. (When we implement - JER this will have the side-effect of printing the wrong type names in some - cases because two or more types have the same templates and get deduped.) - - - There is an _experimental_ ASN.1 -> JSON feature in the compiler. It - currently dumps type and value definitions, but not class, or object set - definitions. Even for types, it is not complete, and the JSON schema used - is subject to change *WITHOUT NOTICE*. - - Perhaps eventually we can re-write the compiler as a C-coded ASN.1 -> JSON - stage followed by a jq-coded code and template generator state, which would - make it much easier to extend the compiler. - ... ## Limitations - - `asn1_print`'s JSON support is not X.697 (JER) compatible. + - `libasn1`'s and, therefore, `asn1_print`'s JSON support is not X.697 (JER) + compatible. - Control over C types generated is very limited, mainly only for integer types. @@ -839,6 +851,12 @@ In recent times the following features have been added: values of `SET`, `SEQUENCE`, `SET OF`, and `SEQUENCE OF`), is not supported. Values of `CHOICE` types are also not supported. + - There is no way to substitute object sets at run-time. This means that + automatic decoding through open types will spend more CPU cycles than the + application might want, by decoding more types than the application might + care about. The ability to substitute object sets at run-time would require + a change to the APIs generated. + - ... ## Compiler Usage @@ -861,104 +879,218 @@ functions for adding or removing items from the named type when it is a See the manual page `asn1_compile.1`: -``` -ASN1_COMPILE(1) HEIMDAL General Commands Manual ASN1_COMPILE(1) +```text +ASN1_COMPILE(1) BSD General Commands Manual ASN1_COMPILE(1) NAME asn1_compile — compile ASN.1 modules SYNOPSIS asn1_compile [--template] [--prefix-enum] [--enum-prefix=PREFIX] - [--encode-rfc1510-bit-string] [--decode-dce-ber] - [--support-ber] [--preserve-binary=TYPE-NAME] - [--sequence=TYPE-NAME] [--one-code-file] [--gen-name=NAME] - [--decorate=TYPE-NAME:FIELD-TYPE:field-name[?]] - [--option-file=FILE] [--original-order] [--no-parse-units] - [--type-file=C-HEADER-FILE] [--version] [--help] - [FILE.asn1 [NAME]] + [--encode-rfc1510-bit-string] [--decode-dce-ber] + [--support-ber] [--preserve-binary=TYPE] [--sequence=TYPE] + [--decorate=DECORATION] [--one-code-file] [--gen-name=NAME] + [--option-file=FILE] [--original-order] [--no-parse-units] + [--type-file=C-HEADER-FILE] [--version] [--help] + [FILE.asn1 [NAME]] DESCRIPTION - asn1_compile Compiles an ASN.1 module into C source code and header + asn1_compile compiles an ASN.1 module into C source code and header files. + A fairly large subset of ASN.1 as specified in X.680, and the ASN.1 In‐ + formation Object System as specified in X.681, X.682, and X.683 is sup‐ + ported, with support for the Distinguished Encoding Rules (DER), partial + Basic Encoding Rules (BER) support, and experimental JSON support (encod‐ + ing only at this time). + + See the compiler's README files for details about the C code and inter‐ + faces it generates. + + The Information Object System support includes automatic codec support + for encoding and decoding through “open types” which are also known as + “typed holes”. See RFC 5912 for examples of how to use the ASN.1 Infor‐ + mation Object System via X.681/X.682/X.683 annotations. See the com‐ + piler's README files for more information on ASN.1 Information Object + System support. + + Extensions specific to Heimdal are generally not syntactic in nature but + rather command-line options to this program. For example, one can use + command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei‐ + ther encoded nor decoded; + etc. + + ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + + Size and range constraints on the ‘INTEGER’ type cause the compiler to + generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, + ‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which + represents an integer of arbitrary size. + + Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. + Options supported: --template - Use the “template” backend instead of the “codegen” backend - (which is the default backend). The template backend generates - “templates” which are akin to bytecode, and which are interpreted - at run-time. The codegen backend generates C code for all func- - tions directly, with no template interpretation. The template - backend scales better than the codegen backend because as we add - support for more encoding rules the templates stay mostly the - same, thus scaling linearly with size of module. Whereas the - codegen backend scales linear with the product of module size and - number of encoding rules supported. More importantly, currently - only the template backend supports automatic decoding of open - types via X.681/X.682/X.683 annotations. + Use the “template” backend instead of the “codegen” backend + (which is the default backend). + + The template backend generates “templates” which are akin to + bytecode, and which are interpreted at run-time. + + The codegen backend generates C code for all functions directly, + with no template interpretation. + + The template backend scales better than the codegen backend be‐ + cause as we add support for more encoding rules and more opera‐ + tions (we may add value comparators) the templates stay mostly + the same, thus scaling linearly with size of module. Whereas the + codegen backend scales linear with the product of module size and + number of encoding rules supported. --prefix-enum - This option should be removed because ENUMERATED types should - always have their labels prefixed. + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. --enum-prefix=PREFIX - This option should be removed because ENUMERATED types should - always have their labels prefixed. + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. --encode-rfc1510-bit-string - Use RFC1510, non-standard handling of “BIT STRING” types. + Use RFC1510, non-standard handling of “BIT STRING” types. --decode-dce-ber + --support-ber - --preserve-binary=TYPE-NAME - Generate ‘_save’ fields in structs to preserve the original - encoding of some sub-value. This is useful for cryptographic - applications to avoid having to re-encode values to check signa- - tures, etc. - - --sequence=TYPE-NAME - Generate add/remove functions for ‘SET OF’ and ‘SEQUENCE OF’ - types. - - --decorate=TYPE-NAME:FIELD-TYPE:field-name[?] - Add to the TYPE-NAME SET or SEQUENCE type a field of the given - FIELD-TYPE and field-name, but do not encode or decode this - field. If the field-name ends in a question mark, then treat the - field as OPTIONAL for the purposes of copy/free function stubs. - This is useful for adding fields to existing types that can be - used for internal bookkeeping but which do not affect interoper- - ability because they are not encoded. + --preserve-binary=TYPE + Generate a field named ‘_save’ in the C struct generated for the + named TYPE. This field is used to preserve the original encoding + of the value of the TYPE. + + This is useful for cryptographic applications so that they can + check signatures of encoded values as-received without having to + re-encode those values. + + For example, the TBSCertificate type should have values preserved + so that Certificate validation can check the signatureValue over + the tbsCertificate's value as-received. + + The alternative of encoding a value to check a signature of it is + brittle. For types where non-canonical encodings (such as BER) + are allowed, this alternative is bound to fail. Thus the point + of this option. + + --sequence=TYPE + Generate add/remove functions for the named ASN.1 TYPE which must + be a ‘SET OF’ or ‘SEQUENCE OF’ type. + + --decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given ASN.1 type FIELD-ASN1-TYPE, but do not encode or decode + it. If the fname ends in a question mark, then treat the field + as OPTIONAL. + + This is useful for adding fields to existing types that can be + used for internal bookkeeping but which do not affect interoper‐ + ability because they are neither encoded nor decoded. For exam‐ + ple, one might decorate a request type with state needed during + processing of the request. + + --decorate=ASN1-TYPE:void*:fname + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + type ‘void *’ (but do not encode or decode it. + + The destructor and copy constructor functions generated by this + compiler for ASN1-TYPE will set this field to the ‘NULL’ pointer. + + --decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given external C type FIELD-C-TYPE, declared in the given + header but do not encode or decode this field. If the fname ends + in a question mark, then treat the field as OPTIONAL. + + The header must include double quotes or angle brackets. The + copyfn must be the name of a copy constructor function that takes + a pointer to a source value of the type, and a pointer to a des‐ + tination value of the type, in that order, and which returns zero + on success or else a system error code on failure. The freefn + must be the name of a destructor function that takes a pointer to + a value of the type and which releases resources referenced by + that value, but does not free the value itself (the run-time al‐ + locates this value as needed from the C heap). The freefn should + also reset the value to a pristine state (such as all zeros). + + If the copyfn and freefn are empty strings, then the decoration + field will neither be copied nor freed by the functions generated + for the TYPE. --one-code-file - Generate a single source code file. Otherwise a separate code - file will be generated for every type. + Generate a single source code file. Otherwise a separate code + file will be generated for every type. --gen-name=NAME - Use NAME to form the names of the files generated. + Use NAME to form the names of the files generated. --option-file=FILE - Take additional command-line options from FILE. + Take additional command-line options from FILE. --original-order - Attempt to preserve the original order of type definition in the - ASN.1 module. By default the compiler generates types in a topo- - logical sort order. + Attempt to preserve the original order of type definition in the + ASN.1 module. By default the compiler generates types in a topo‐ + logical sort order. --no-parse-units - Do not generate to-int / from-int functions for enumeration - types. + Do not generate to-int / from-int functions for enumeration + types. --type-file=C-HEADER-FILE - Generate an include of the named header file that might be needed - for common type defintions. + Generate an include of the named header file that might be needed + for common type defintions. --version --help -HEIMDAL February 22, 2021 HEIMDAL +NOTES + Currently only the template backend supports automatic encoding and de‐ + coding of open types via the ASN.1 Information Object System and + X.681/X.682/X.683 annotations. +HEIMDAL February 22, 2021 HEIMDAL ``` ## APIs Generated by the Compiler @@ -1076,9 +1208,9 @@ absence and non-NULL indicating presence. And so on. -## asn1_print Usage +## `asn1_print` Usage -``` +```text ASN1_PRINT(1) BSD General Commands Manual ASN1_PRINT(1) NAME @@ -1170,13 +1302,19 @@ See: - Add JER support so we can convert between JER and DER? - - Add XDR support? + - Add XDR support? There are no ASN.1 Encoding Rules based on XDR, but it is + trivial to construct such for at least that subset of ASN.1 for which the + XDR syntax has equivalent semantics. - Add OER support? - - Add NDR support? + - Add NDR support? There are no ASN.1 Encoding Rules based on NDR, but it is + trivial to construct such for at least that subset of ASN.1 for which the + IDL syntax has equivalent semantics. - - Perhaps third parties will contribute more control over generate types? + - Perhaps third parties will contribute more control over generated types? + This may require separate publication of the Heimdal ASN.1 compiler from the + rest of Heimdal. ## Moving From C diff --git a/third_party/heimdal/lib/asn1/asn1-template.h b/third_party/heimdal/lib/asn1/asn1-template.h index e75734ea26ce..07c4461e3e9a 100644 --- a/third_party/heimdal/lib/asn1/asn1-template.h +++ b/third_party/heimdal/lib/asn1/asn1-template.h @@ -42,43 +42,16 @@ * TBD: * * - For OER also encode number of optional/default/extension elements into - * header entry's ptr field, not just the number of entries that follow it + * header entry's ptr field, not just the number of entries that follow it. * - * - For JER/GSER/whatver, and probably for not-C-coded template interpreters, - * we'll need to have an entry type for the names of structures and their - * fields. + * - For JER we'll need to encode encoding options (encode as array, encode as + * object, etc.) * - * - For auto open types we need a new opcode, let's call it - * A1_OP_OPENTYPE_OBJSET, and we need to encode into its entry: - * a) the index of the template entry for the type ID field, and - * b) the index of the template entry for the open type field, - * c) 1 bit to indicate whether the object set is sorted by type ID value, - * d) a pointer to the object set's template. - * With that we can then find the struct offsets of those, and also their - * types (since we can find their template entries). - * The object set entries should be encoded into two template entries each: - * one pointing to the value of the type ID field for that object (unless - * the value is an integer, in which case the ptr should be the integer - * value directly), and the other pointing to the template for the type - * identified by the type ID. These will need an opcode each... - * A1_OP_OPENTYPE_ID and A1_OP_OPENTYPE. - * We should also end the object set with an A1_OP_OPENTYPE_OBJSET entry so - * that iterating backwards can be fast. Unless... unless we don't inline - * the object set and its objects but point to the object set's template. - * Also, for extensible object sets we can point to the object set's name, - * and we can then have a function to get an object set template by name, - * one to release that, and one to add an object to the object set (there's - * no need to remove objects from object sets, which helps with thread- - * safety). And then we don't need (c) either. - * The decoder will then not see these entries until after decoding the type - * ID and open type field (as its outer type, so OCTET STRING, BIT STRING, - * or HEIM_ANY) and so it will be able to find those values in the struct at - * their respective offsets. - * The encoder and decoder both need to identify the relevant object in the - * object set, either by linear search or binary search if they are sorted - * by type ID value, then interpret the template for the identified type. - * The encoder needs to place the encoding into the normal location for it - * in the struct, then it can execute the normal template entry for it. + * - For open types we'll need to be able to indicate what encoding rules the + * type uses. + * + * - We have too many bits for tags (20) and probably not enough for ops (4 + * bits, and we've used all but one). */ /* header: @@ -155,21 +128,23 @@ * 28..31 op */ -#define A1_OP_MASK (0xf0000000) -#define A1_OP_TYPE (0x10000000) -#define A1_OP_TYPE_EXTERN (0x20000000) -#define A1_OP_TAG (0x30000000) -#define A1_OP_PARSE (0x40000000) -#define A1_OP_SEQOF (0x50000000) -#define A1_OP_SETOF (0x60000000) -#define A1_OP_BMEMBER (0x70000000) -#define A1_OP_CHOICE (0x80000000) -#define A1_OP_DEFVAL (0x90000000) -#define A1_OP_OPENTYPE_OBJSET (0xa0000000) -#define A1_OP_OPENTYPE_ID (0xb0000000) -#define A1_OP_OPENTYPE (0xc0000000) -#define A1_OP_NAME (0xd0000000) -#define A1_OP_TYPE_DECORATE (0xe0000000) +#define A1_OP_MASK (0xf0000000) +#define A1_OP_TYPE (0x10000000) /* templated type */ +#define A1_OP_TYPE_EXTERN (0x20000000) /* templated type (imported) */ +#define A1_OP_TAG (0x30000000) /* a tag */ +#define A1_OP_PARSE (0x40000000) /* primitive type */ +#define A1_OP_SEQOF (0x50000000) /* sequence of */ +#define A1_OP_SETOF (0x60000000) /* set of */ +#define A1_OP_BMEMBER (0x70000000) /* BIT STRING member */ +#define A1_OP_CHOICE (0x80000000) /* CHOICE */ +#define A1_OP_DEFVAL (0x90000000) /* def. value */ +#define A1_OP_OPENTYPE_OBJSET (0xa0000000) /* object set for open type */ +#define A1_OP_OPENTYPE_ID (0xb0000000) /* open type id field */ +#define A1_OP_OPENTYPE (0xc0000000) /* open type field */ +#define A1_OP_NAME (0xd0000000) /* symbol */ +#define A1_OP_TYPE_DECORATE (0xe0000000) /* decoration w/ templated type */ +#define A1_OP_TYPE_DECORATE_EXTERN (0xf0000000) /* decoration w/ some C type */ + /* 0x00.. is still free */ #define A1_FLAG_MASK (0x0f000000) #define A1_FLAG_OPTIONAL (0x01000000) diff --git a/third_party/heimdal/lib/asn1/asn1_compile.1 b/third_party/heimdal/lib/asn1/asn1_compile.1 index 74cf314f16e4..a7953df5fa17 100644 --- a/third_party/heimdal/lib/asn1/asn1_compile.1 +++ b/third_party/heimdal/lib/asn1/asn1_compile.1 @@ -46,9 +46,9 @@ .Op Fl Fl encode-rfc1510-bit-string .Op Fl Fl decode-dce-ber .Op Fl Fl support-ber -.Op Fl Fl preserve-binary=TYPE-NAME -.Op Fl Fl sequence=TYPE-NAME -.Op Fl Fl decorate=TYPE-NAME:FIELD-TYPE:field-name[?] +.Op Fl Fl preserve-binary=TYPE +.Op Fl Fl sequence=TYPE +.Op Fl Fl decorate=DECORATION .Op Fl Fl one-code-file .Op Fl Fl gen-name=NAME .Op Fl Fl option-file=FILE @@ -61,7 +61,117 @@ .Ek .Sh DESCRIPTION .Nm -Compiles an ASN.1 module into C source code and header files. +compiles an ASN.1 module into C source code and header files. +.Pp +A fairly large subset of ASN.1 as specified in X.680, and the +ASN.1 Information Object System as specified in X.681, X.682, and +X.683 is supported, with support for the Distinguished Encoding +Rules (DER), partial Basic Encoding Rules (BER) support, and +experimental JSON support (encoding only at this time). +.Pp +See the compiler's README files for details about the C code and +interfaces it generates. +.Pp +The Information Object System support includes automatic codec +support for encoding and decoding through +.Dq open types +which are also known as +.Dq typed holes . +See RFC 5912 for examples of how to use the ASN.1 +Information Object System via X.681/X.682/X.683 annotations. See +the compiler's README files for more information on ASN.1 +Information Object System support. +.Pp +Extensions specific to Heimdal are generally not syntactic in +nature but rather command-line options to this program. +For example, one can use command-line options to: +.Bl -bullet -compact -width Ds -offset indent +.It +enable decoding of BER-encoded values; +.It +enable RFC1510-style handling of +.Sq BIT STRING +types; +.It +enable saving of as-received encodings of specific types for the +purpose of signature validation; +.It +generate add/remove utility functions for array types; +.It +decorate generated +.Sq struct +types with fields that are neither encoded nor decoded; +.El +etc. +.Pp +ASN.1 x.680 features supported: +.Bl -bullet -compact -width Ds -offset indent +.It +most primitive types (except BMPString and REAL); +.It +all constructed types, including SET and SET OF; +.It +explicit and implicit tagging. +.El +.Pp +Size and range constraints on the +.Sq INTEGER +type cause the compiler to generate appropriate C types such as +.Sq int , +.Sq unsigned int , +.Sq int64_t , +.Sq uint64_t . +Unconstrained +.Sq INTEGER +is treated as +.Sq heim_integer , +which represents an integer of arbitrary size. +.Pp +Caveats and ASN.1 x.680 features not supported: +.Bl -bullet -compact -width Ds -offset indent +.It +JSON encoding support is not quite X.697 (JER) compatible. +Its JSON schema is subject to change without notice. +.It +Control over C types generated is very limited, mainly only for +integer types. +.It +When using the template backend, `SET { .. }` types are currently +not sorted by tag as they should be, but if the module author +sorts them by hand then correct DER will be produced. +.It +.Sq AUTOMATIC TAGS +is not supported. +.It +The +.Va REAL +type is not supported. +.It +The +.Va EmbeddedPDV +type is not supported. +.It +The +.Va BMPString +type is not supported. +.It +The +.Va IA5String +is not properly supported, as it's essentially treated as a +.Va UTF8String +with a different tag. +.It +All supported non-octet strings are treated as like the +.Va UTF8String +type. +.It +Only types can be imported into ASN.1 modules at this time. +.It +Only simple value syntax is supported. +Constructed value syntax (i.e., values of SET, SEQUENCE, SET OF, +and SEQUENCE OF types), is not supported. +Values of `CHOICE` types are also not supported. +.El .Pp Options supported: .Bl -tag -width Ds @@ -71,20 +181,21 @@ Use the backend instead of the .Dq codegen backend (which is the default backend). +.Pp The template backend generates .Dq templates which are akin to bytecode, and which are interpreted at run-time. +.Pp The codegen backend generates C code for all functions directly, with no template interpretation. +.Pp The template backend scales better than the codegen backend -because as we add support for more encoding rules the templates -stay mostly the same, thus scaling linearly with size of module. +because as we add support for more encoding rules and more +operations (we may add value comparators) the templates stay +mostly the same, thus scaling linearly with size of module. Whereas the codegen backend scales linear with the product of module size and number of encoding rules supported. -More importantly, currently only the template backend supports -automatic decoding of open types via X.681/X.682/X.683 -annotations. .It Fl Fl prefix-enum This option should be removed because ENUMERATED types should always have their labels prefixed. @@ -97,34 +208,118 @@ Use RFC1510, non-standard handling of types. .It Fl Fl decode-dce-ber .It Fl Fl support-ber -.It Fl Fl preserve-binary=TYPE-NAME -Generate +.It Fl Fl preserve-binary=TYPE +Generate a field named .Sq _save -fields in structs to preserve the original encoding of some -sub-value. -This is useful for cryptographic applications to avoid having to -re-encode values to check signatures, etc. -.It Fl Fl sequence=TYPE-NAME -Generate add/remove functions for +in the C struct generated for the named +.Ar TYPE . +This field is used to preserve the original encoding of the value +of the +.Ar TYPE . +.Pp +This is useful for cryptographic applications so that they can +check signatures of encoded values as-received without having to +re-encode those values. +.Pp +For example, the TBSCertificate type should have values preserved +so that Certificate validation can check the signatureValue over +the tbsCertificate's value as-received. +.Pp +The alternative of encoding a value to check a signature of it is +brittle. +For types where non-canonical encodings (such as BER) are +allowed, this alternative is bound to fail. +Thus the point of this option. +.It Fl Fl sequence=TYPE +Generate add/remove functions for the named ASN.1 +.Ar TYPE +which must be a .Sq SET OF -and +or .Sq SEQUENCE OF -types. -.It Fl Fl decorate=TYPE-NAME:FIELD-TYPE:field-name[?] -Add to the -.Va TYPE-NAME -SET or SEQUENCE type a field of the given -.Va FIELD-TYPE -and -.Va field-name , +type. +.It Fl Fl decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of the given ASN.1 type +.Ar FIELD-ASN1-TYPE , +but do not encode or decode it. +If the +.Ar fname +ends in a question mark, then treat the field as OPTIONAL. +.Pp +This is useful for adding fields to existing types that can be +used for internal bookkeeping but which do not affect +interoperability because they are neither encoded nor decoded. +For example, one might decorate a request type with state needed +during processing of the request. +.It Fl Fl decorate=ASN1-TYPE:void*:fname +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of type +.Sq void * +(but do not encode or decode it. +.Pp +The destructor and copy constructor functions generated by this +compiler for +.Ar ASN1-TYPE +will set this field to the +.Sq NULL +pointer. +.It Fl Fl decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of the given external C type +.Ar FIELD-C-TYPE , +declared in the given +.Ar header but do not encode or decode this field. If the -.Va field-name -ends in a question mark, then treat the field as OPTIONAL for -the purposes of copy/free function stubs. -This is useful for adding fields to existing types that can be used -for internal bookkeeping but which do not affect interoperability -because they are not encoded. +.Ar fname +ends in a question mark, then treat the field as OPTIONAL. +.Pp +The +.Ar header +must include double quotes or angle brackets. +The +.Ar copyfn +must be the name of a copy constructor function that takes a +pointer to a source value of the type, and a pointer to a +destination value of the type, in that order, and which returns +zero on success or else a system error code on failure. +The +.Ar freefn +must be the name of a destructor function that takes a pointer to +a value of the type and which releases resources referenced by +that value, but does not free the value itself (the run-time +allocates this value as needed from the C heap). +The +.Ar freefn +should also reset the value to a pristine state (such as all +zeros). +.Pp +If the +.Ar copyfn +and +.Ar freefn +are empty strings, then the decoration field will neither be +copied nor freed by the functions generated for the +.Ar TYPE . .It Fl Fl one-code-file Generate a single source code file. Otherwise a separate code file will be generated for every type. @@ -149,3 +344,7 @@ for common type defintions. .It Fl Fl version .It Fl Fl help .El +.Sh NOTES +Currently only the template backend supports automatic encoding +and decoding of open types via the ASN.1 Information Object +System and X.681/X.682/X.683 annotations. diff --git a/third_party/heimdal/lib/asn1/asn1_print.c b/third_party/heimdal/lib/asn1/asn1_print.c index 39c43341aa62..40c37fbbb946 100644 --- a/third_party/heimdal/lib/asn1/asn1_print.c +++ b/third_party/heimdal/lib/asn1/asn1_print.c @@ -114,22 +114,22 @@ const struct types { (releaser)free_ ## gns, \ }, #endif -#include "cms_asn1_syms.x" -#include "digest_asn1_syms.x" -#include "krb5_asn1_syms.x" -#include "kx509_asn1_syms.x" -#include "ocsp_asn1_syms.x" -#include "pkcs10_asn1_syms.x" -#include "pkcs12_asn1_syms.x" -#include "pkcs8_asn1_syms.x" -#include "pkcs9_asn1_syms.x" -#include "pkinit_asn1_syms.x" -#include "rfc2459_asn1_syms.x" -#include "rfc4108_asn1_syms.x" +#include "cms_asn1_syms.c" +#include "digest_asn1_syms.c" +#include "krb5_asn1_syms.c" +#include "kx509_asn1_syms.c" +#include "ocsp_asn1_syms.c" +#include "pkcs10_asn1_syms.c" +#include "pkcs12_asn1_syms.c" +#include "pkcs8_asn1_syms.c" +#include "pkcs9_asn1_syms.c" +#include "pkinit_asn1_syms.c" +#include "rfc2459_asn1_syms.c" +#include "rfc4108_asn1_syms.c" #ifdef ASN1_PRINT_SUPPORTED -#include "x690sample_template_asn1_syms.x" +#include "x690sample_template_asn1_syms.c" #else -#include "x690sample_asn1_syms.x" +#include "x690sample_asn1_syms.c" #endif }; @@ -453,10 +453,8 @@ dotype(unsigned char *buf, size_t len, char **argv, size_t *size) char *s; s = sorted_types[i].print(v, indent_flag ? ASN1_PRINT_INDENT : 0); - if (!s) { - ret = errno; + if (!s) err(1, "Could not print %s\n", typename); - } if (!quiet_flag) printf("%s\n", s); free(s); diff --git a/third_party/heimdal/lib/asn1/asn1parse.y b/third_party/heimdal/lib/asn1/asn1parse.y index 290cb86310ed..f6f6ec0e5c46 100644 --- a/third_party/heimdal/lib/asn1/asn1parse.y +++ b/third_party/heimdal/lib/asn1/asn1parse.y @@ -242,6 +242,7 @@ static unsigned long idcounter; %type BooleanType %type ChoiceType %type ConstrainedType +%type UnconstrainedType %type EnumeratedType %type IntegerType %type NullType @@ -288,6 +289,7 @@ static unsigned long idcounter; %type Constraint %type ConstraintSpec +%type SubtypeConstraint %type GeneralConstraint %type ContentsConstraint %type UserDefinedConstraint @@ -295,7 +297,6 @@ static unsigned long idcounter; %type ComponentRelationConstraint - %start ModuleDefinition %% @@ -304,6 +305,9 @@ static unsigned long idcounter; * We have sinned by allowing types to have names that start with lower-case, * and values that have names that start with upper-case. * + * UPDATE: We sin no more. However, parts of this block comment are still + * relevant. + * * That worked when we only supported basic X.680 because the rules for * TypeAssignment and ValueAssignment are clearly unambiguous in spite of the * case issue. @@ -312,35 +316,41 @@ static unsigned long idcounter; * have to help us distinguish certain rules is the form of an identifier: the * case of its first letter. * - * We have begun to undo our sin by not allowing wrong-case identifiers in - * certain situations. + * We have cleansed our sin by not allowing wrong-case identifiers any more. * * Some historical instances of this sin in-tree: * - * - DOMAIN-X500-COMPRESS (value (enum) but name starts with upper-case) - * - krb5int32 (type but name starts with lower-case) - * - krb5uint32 (type but name starts with lower-case) - * - hdb_keyset (type but name starts with lower-case) - * - hdb_entry (type but name starts with lower-case) - * - hdb_entry_alias (type but name starts with lower-case) + * - DOMAIN-X500-COMPRESS (value (enum) but name starts with upper-case) + * - krb5int32 (type but name starts with lower-case) + * - krb5uint32 (type but name starts with lower-case) + * - hdb_keyset (type but name starts with lower-case) + * - hdb_entry (type but name starts with lower-case) + * - hdb_entry_alias (type but name starts with lower-case) + * - HDB_DB_FORMAT INTEGER (value (int) but name starts with upper-case) * - * We have fixed most of these, in some cases leaving behind aliases in header - * files as needed. + * We have fixed all of these and others, in some cases leaving behind aliases + * in header files as needed. * - * This issue is probably also the source of remaining shift/reduce conflicts. + * We have one shift/reduce conflict (shift ObjectClassAssignment, reduce + * TypeAssignment) and one reduce/reduce conflict (ObjectAssignment vs + * ValueAssignment) that we avoid by requiring CLASS names to start with an + * underscore. * - * In the FieldSetting rule in particular, we get a reduce/reduce conflict if - * we use `Identifier' instead of `TYPE_IDENTIFIER' for type field settings and + * In the FieldSetting rule, also, we get a reduce/reduce conflict if we use + * `Identifier' instead of `TYPE_IDENTIFIER' for type field settings and * `VALUE_IDENTIFIER' for value field settings, and then we can't make * progress. * * Looking forward, we may not (will not) be able to distinguish ValueSet and - * ObjectSet field settings from each other either even without committing this - * leading-identifier-character-case sin, and we may not (will not) be able - * distinguish Object and Value field settings from each other as well. To - * deal with those we will have to run-time type-tag/pun the C structures for - * valueset/objectset and value/object, and have one rule for each of those - * that inspects the type of the item to decide what kind of setting it is. + * ObjectSet field settings from each other either, and we may not (will not) + * be able distinguish Object and Value field settings from each other as well. + * To deal with those we will have to run-time type-tag and type-pun the C + * structures for valueset/objectset and value/object, and have one rule for + * each of those that inspects the type of the item to decide what kind of + * setting it is. + * + * Sadly, the extended syntax for ASN.1 (x.680 + x.681/2/3) appears to have + * ambiguities that cannot be resolved with bison/yacc. */ Identifier : TYPE_IDENTIFIER { $$ = $1; } | VALUE_IDENTIFIER { $$ = $1; }; @@ -364,8 +374,6 @@ ModuleDefinition: Identifier objid_opt kw_DEFINITIONS TagDefault ExtensionDefaul fprintf(jsonfile, "]}\n"); free(o); } - | CLASS_IDENTIFIER objid_opt kw_DEFINITIONS TagDefault ExtensionDefault - EEQUAL kw_BEGIN ModuleBody kw_END ; TagDefault : kw_EXPLICIT kw_TAGS @@ -914,10 +922,20 @@ ParamGovernor : DefinedObjectClass /* | Type */ ; -Type : BuiltinType - | ReferencedType - | ConstrainedType - ; +UnconstrainedType : BitStringType + | BooleanType + | CharacterStringType + | ChoiceType + | EnumeratedType + | IntegerType + | NullType + | ObjectIdentifierType + | OctetStringType + | SequenceType + | SetType + | ObjectClassFieldType; /* X.681 */ + +Type : BuiltinType | ReferencedType | ConstrainedType ; BuiltinType : BitStringType | BooleanType @@ -948,39 +966,49 @@ BooleanType : kw_BOOLEAN } ; -range : '(' Value RANGE Value ')' + /* + * The spec says the values in a ValueRange are Values, but a) all + * the various value ranges do not involve OBJECT IDENTIFIER, b) + * we only support integer value ranges at this time (as opposed + * to, e.g., time ranges, and we don't even support time values at + * this time), c) allowing OBJECT IDENTIFIER here causes a + * shift-reduce conflict, so we limit ourselves to integer values + * in ranges. We could always define IntegerValueRange, + * TimeValueRange, etc. when we add support for more value types. + */ +range : IntegerValue RANGE IntegerValue { - if($2->type != integervalue) + if($1->type != integervalue) lex_error_message("Non-integer used in first part of range"); - if($2->type != integervalue) + if($1->type != integervalue) lex_error_message("Non-integer in second part of range"); $$ = ecalloc(1, sizeof(*$$)); - $$->min = $2->u.integervalue; - $$->max = $4->u.integervalue; + $$->min = $1->u.integervalue; + $$->max = $3->u.integervalue; } - | '(' Value RANGE kw_MAX ')' + | IntegerValue RANGE kw_MAX { - if($2->type != integervalue) + if($1->type != integervalue) lex_error_message("Non-integer in first part of range"); $$ = ecalloc(1, sizeof(*$$)); - $$->min = $2->u.integervalue; + $$->min = $1->u.integervalue; $$->max = INT_MAX; } - | '(' kw_MIN RANGE Value ')' + | kw_MIN RANGE IntegerValue { - if($4->type != integervalue) + if($3->type != integervalue) lex_error_message("Non-integer in second part of range"); $$ = ecalloc(1, sizeof(*$$)); $$->min = INT_MIN; - $$->max = $4->u.integervalue; + $$->max = $3->u.integervalue; } - | '(' Value ')' + | IntegerValue { - if($2->type != integervalue) + if($1->type != integervalue) lex_error_message("Non-integer used in limit"); $$ = ecalloc(1, sizeof(*$$)); - $$->min = $2->u.integervalue; - $$->max = $2->u.integervalue; + $$->min = $1->u.integervalue; + $$->max = $1->u.integervalue; } ; @@ -990,12 +1018,6 @@ 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); @@ -1101,8 +1123,8 @@ NullType : kw_NULL size : { $$ = NULL; } - | kw_SIZE range - { $$ = $2; } + | kw_SIZE '(' range ')' + { $$ = $3; } ; @@ -1250,10 +1272,17 @@ UsefulType : kw_GeneralizedTime } ; -ConstrainedType : Type Constraint +ConstrainedType : UnconstrainedType Constraint { $$ = $1; - $$->constraint = $2; + if ($2->ctype == CT_RANGE) { + if ($1->type != TTag || $1->subtype->type != TInteger) + lex_error_message("RANGE constraints apply only to INTEGER types"); + $$->subtype->range = $2->u.range; + free($2); + } else { + $$->constraint = $2; + } /* if (Constraint.type == contentConstraint) { assert(Constraint.u.constraint.type == octetstring|bitstring-w/o-NamedBitList); // remember to check type reference too if (Constraint.u.constraint.type) { @@ -1274,9 +1303,15 @@ Constraint : '(' ConstraintSpec ')' } ; -ConstraintSpec : GeneralConstraint +ConstraintSpec : SubtypeConstraint | GeneralConstraint ; +SubtypeConstraint: range + { + $$ = new_constraint_spec(CT_RANGE); + $$->u.range = $1; + } + GeneralConstraint: ContentsConstraint | UserDefinedConstraint | TableConstraint @@ -1452,7 +1487,7 @@ tagenv : /* */ ; -ValueAssignment : Identifier Type EEQUAL Value +ValueAssignment : VALUE_IDENTIFIER Type EEQUAL Value { Symbol *s; s = addsym ($1); diff --git a/third_party/heimdal/lib/asn1/check-common.h b/third_party/heimdal/lib/asn1/check-common.h index 97d118997397..6ea1f812651e 100644 --- a/third_party/heimdal/lib/asn1/check-common.h +++ b/third_party/heimdal/lib/asn1/check-common.h @@ -34,7 +34,8 @@ */ #define IF_OPT_COMPARE(ac,bc,e) \ - if (((ac)->e == NULL && (bc)->e != NULL) || (((ac)->e != NULL && (bc)->e == NULL))) return 1; if ((ac)->e) + if (((ac)->e == NULL && (bc)->e != NULL) || (((ac)->e != NULL && (bc)->e == NULL))) return 1; \ + if ((ac)->e) #define COMPARE_OPT_STRING(ac,bc,e) \ do { if (strcmp(*(ac)->e, *(bc)->e) != 0) return 1; } while(0) #define COMPARE_OPT_OCTET_STRING(ac,bc,e) \ diff --git a/third_party/heimdal/lib/asn1/check-der.c b/third_party/heimdal/lib/asn1/check-der.c index 15fd2bcff920..a8956a74bd26 100644 --- a/third_party/heimdal/lib/asn1/check-der.c +++ b/third_party/heimdal/lib/asn1/check-der.c @@ -900,6 +900,8 @@ test_heim_oid_format_same(const char *str, const heim_oid *oid) ret = der_heim_oid_cmp(&o2, oid); der_free_oid(&o2); + if (ret != 0) + return 1; return 0; } diff --git a/third_party/heimdal/lib/asn1/check-gen.c b/third_party/heimdal/lib/asn1/check-gen.c index f49f5e8edf92..6b5c71c39f57 100644 --- a/third_party/heimdal/lib/asn1/check-gen.c +++ b/third_party/heimdal/lib/asn1/check-gen.c @@ -51,6 +51,24 @@ #include "check-common.h" +static int my_copy_vers_called; +static int my_free_vers_called; + +int +my_copy_vers(const my_vers *from, my_vers *to) +{ + my_copy_vers_called++; + *to = *from; + return 0; +} + +void +my_free_vers(my_vers *v) +{ + my_free_vers_called++; + v->v = -1; +} + static char *lha_principal[] = { "lha" }; static char *lharoot_princ[] = { "lha", "root" }; static char *datan_princ[] = { "host", "nutcracker.e.kth.se" }; @@ -1021,7 +1039,7 @@ static int test_decorated(void) { TESTNotDecorated tnd; - TESTDecorated td; + TESTDecorated td, td_copy; size_t len, size; void *ptr; int ret; @@ -1029,7 +1047,12 @@ test_decorated(void) memset(&td, 0, sizeof(td)); memset(&tnd, 0, sizeof(tnd)); + my_copy_vers_called = 0; + my_free_vers_called = 0; + td.version = 3; + td.version3.v = 5; + td.privthing = &td; if ((td.version2 = malloc(sizeof(*td.version2))) == NULL) errx(1, "out of memory"); *td.version2 = 5; @@ -1043,6 +1066,7 @@ test_decorated(void) warnx("could not decode a TESTDecorated struct as TESTNotDecorated"); return 1; } + free(ptr); if (size != len) { warnx("TESTDecorated encoded size mismatch"); return 1; @@ -1051,9 +1075,122 @@ test_decorated(void) warnx("TESTDecorated did not decode as a TESTNotDecorated correctly"); return 1; } + if (copy_TESTDecorated(&td, &td_copy)) { + warnx("copy_TESTDecorated() failed"); + return 1; + } + if (td.version != td_copy.version) { + warnx("copy_TESTDecorated() did not work correctly (1)"); + return 1; + } + if (td_copy.version2 == NULL || *td.version2 != *td_copy.version2) { + warnx("copy_TESTDecorated() did not work correctly (2)"); + return 1; + } + if (td.version3.v != td_copy.version3.v || + my_copy_vers_called != 1) { + warnx("copy_TESTDecorated() did not work correctly (3)"); + return 1; + } + if (td_copy.privthing != 0) { + warnx("copy_TESTDecorated() did not work correctly (4)"); + return 1; + } + + free_TESTDecorated(&td_copy); free_TESTDecorated(&td); if (td.version2) { - warnx("free_TESTDecorated() did not work correctly"); + warnx("free_TESTDecorated() did not work correctly (1)"); + return 1; + } + if (td.version3.v != 0 || my_free_vers_called != 2) { + warnx("free_TESTDecorated() did not work correctly (2)"); + return 1; + } + if (td.privthing != 0) { + warnx("free_TESTDecorated() did not work correctly (3)"); + return 1; + } + return 0; +} + +static int +test_decorated_choice(void) +{ + TESTNotDecoratedChoice tndc; + TESTDecoratedChoice tdc, tdc_copy; + size_t len, size; + void *ptr; + int ret; + + memset(&tdc, 0, sizeof(tdc)); + memset(&tndc, 0, sizeof(tndc)); + + my_copy_vers_called = 0; + my_free_vers_called = 0; + + tdc.element = choice_TESTDecoratedChoice_version; + tdc.u.version = 3; + tdc.version3.v = 5; + tdc.privthing = &tdc; + if ((tdc.version2 = malloc(sizeof(*tdc.version2))) == NULL) + errx(1, "out of memory"); + *tdc.version2 = 5; + ASN1_MALLOC_ENCODE(TESTDecoratedChoice, ptr, len, &tdc, &size, ret); + if (ret) { + warnx("could not encode a TESTDecoratedChoice struct"); + return 1; + } + ret = decode_TESTNotDecoratedChoice(ptr, len, &tndc, &size); + if (ret) { + warnx("could not decode a TESTDecoratedChoice struct as TESTNotDecoratedChoice"); + return 1; + } + free(ptr); + if (size != len) { + warnx("TESTDecoratedChoice encoded size mismatch"); + return 1; + } + if ((int)tdc.element != (int)tndc.element || + tdc.u.version != tndc.u.version) { + warnx("TESTDecoratedChoice did not decode as a TESTNotDecoratedChoice correctly"); + return 1; + } + if (copy_TESTDecoratedChoice(&tdc, &tdc_copy)) { + warnx("copy_TESTDecoratedChoice() failed"); + return 1; + } + if ((int)tdc.element != (int)tdc_copy.element || + tdc.u.version != tdc_copy.u.version) { + warnx("copy_TESTDecoratedChoice() did not work correctly (1)"); + return 1; + } + if (tdc_copy.version2 == NULL || *tdc.version2 != *tdc_copy.version2) { + warnx("copy_TESTDecoratedChoice() did not work correctly (2)"); + return 1; + } + if (tdc.version3.v != tdc_copy.version3.v || + my_copy_vers_called != 1) { + warnx("copy_TESTDecoratedChoice() did not work correctly (3)"); + return 1; + } + if (tdc_copy.privthing != 0) { + warnx("copy_TESTDecoratedChoice() did not work correctly (4)"); + return 1; + } + + free_TESTDecoratedChoice(&tdc_copy); + free_TESTDecoratedChoice(&tdc); + if (tdc.version2) { + warnx("free_TESTDecoratedChoice() did not work correctly (1)"); + return 1; + } + if (tdc.version3.v != 0 || my_free_vers_called != 2) { + warnx("free_TESTDecoratedChoice() did not work correctly (2)"); + return 1; + } + if (tdc.privthing != 0) { + warnx("free_TESTDecoratedChoice() did not work correctly (3)"); return 1; } return 0; @@ -1521,7 +1658,7 @@ static int check_seq(void) { TESTSeqOf seq; - TESTInteger i; + TESTInteger i = 0; int ret; seq.val = NULL; @@ -2537,6 +2674,7 @@ main(int argc, char **argv) DO_ONE(test_default); + DO_ONE(test_decorated_choice); DO_ONE(test_decorated); #if ASN1_IOS_SUPPORTED diff --git a/third_party/heimdal/lib/asn1/check-gen.h b/third_party/heimdal/lib/asn1/check-gen.h new file mode 100644 index 000000000000..df8c4747b6b8 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-gen.h @@ -0,0 +1,9 @@ +#ifndef _CHECK_GEN_H +#define _CHECK_GEN_H +typedef struct my_vers_s { + int v; +} my_vers; + +int my_copy_vers(const my_vers *, my_vers *); +void my_free_vers(my_vers *); +#endif /* _CHECK_GEN_H */ diff --git a/third_party/heimdal/lib/asn1/check-template.c b/third_party/heimdal/lib/asn1/check-template.c index 21132c8d1a4d..ef5bd6990ded 100644 --- a/third_party/heimdal/lib/asn1/check-template.c +++ b/third_party/heimdal/lib/asn1/check-template.c @@ -48,6 +48,19 @@ #include "check-common.h" #include "der_locl.h" +int +my_copy_vers(const my_vers *from, my_vers *to) +{ + *to = *from; + return 0; +} + +void +my_free_vers(my_vers *v) +{ + v->v = -1; +} + static int cmp_dummy (void *a, void *b) { diff --git a/third_party/heimdal/lib/asn1/der_copy.c b/third_party/heimdal/lib/asn1/der_copy.c index 854131e2ab47..2084cef5f088 100644 --- a/third_party/heimdal/lib/asn1/der_copy.c +++ b/third_party/heimdal/lib/asn1/der_copy.c @@ -99,11 +99,14 @@ int ASN1CALL der_copy_printable_string (const heim_printable_string *from, heim_printable_string *to) { - to->length = from->length; - to->data = malloc(to->length + 1); - if(to->data == NULL) + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + to->data = malloc(from->length + 1); + if (to->data == NULL) { + to->length = 0; return ENOMEM; - if (from->data != NULL) + } + to->length = from->length; + if (to->length > 0) memcpy(to->data, from->data, to->length); ((char *)to->data)[to->length] = '\0'; return 0; @@ -119,11 +122,17 @@ der_copy_ia5_string (const heim_ia5_string *from, int ASN1CALL der_copy_bmp_string (const heim_bmp_string *from, heim_bmp_string *to) { - to->length = from->length; - to->data = malloc(to->length * sizeof(to->data[0])); - if(to->length != 0 && to->data == NULL) + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, sizeof(from->data[0])); + else + to->data = malloc(from->length * sizeof(from->data[0])); + if (to->data == NULL) { + to->length = 0; return ENOMEM; - if (to->data != NULL && from->data != NULL) + } + to->length = from->length; + if (to->length > 0) memcpy(to->data, from->data, to->length * sizeof(to->data[0])); return 0; } @@ -132,11 +141,17 @@ int ASN1CALL der_copy_universal_string (const heim_universal_string *from, heim_universal_string *to) { - to->length = from->length; - to->data = malloc(to->length * sizeof(to->data[0])); - if(to->length != 0 && to->data == NULL) + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, sizeof(from->data[0])); + else + to->data = malloc(from->length * sizeof(from->data[0])); + if (to->data == NULL) { + to->length = 0; return ENOMEM; - if (to->data != NULL && from->data != NULL) + } + to->length = from->length; + if (to->length > 0) memcpy(to->data, from->data, to->length * sizeof(to->data[0])); return 0; } @@ -151,11 +166,17 @@ der_copy_visible_string (const heim_visible_string *from, int ASN1CALL der_copy_octet_string (const heim_octet_string *from, heim_octet_string *to) { - to->length = from->length; - to->data = malloc(to->length); - if(to->length != 0 && to->data == NULL) + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, 1); + else + to->data = malloc(from->length); + if (to->data == NULL) { + to->length = 0; return ENOMEM; - if (to->data != NULL && from->data != NULL) + } + to->length = from->length; + if (to->length > 0) memcpy(to->data, from->data, to->length); return 0; } @@ -163,11 +184,17 @@ der_copy_octet_string (const heim_octet_string *from, heim_octet_string *to) int ASN1CALL der_copy_heim_integer (const heim_integer *from, heim_integer *to) { - to->length = from->length; - to->data = malloc(to->length); - if(to->length != 0 && to->data == NULL) + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, 1); + else + to->data = malloc(from->length); + if (to->data == NULL) { + to->length = 0; return ENOMEM; - if (to->data != NULL && from->data != NULL) + } + to->length = from->length; + if (to->length > 0) memcpy(to->data, from->data, to->length); to->negative = from->negative; return 0; @@ -176,13 +203,22 @@ der_copy_heim_integer (const heim_integer *from, heim_integer *to) int ASN1CALL der_copy_oid (const heim_oid *from, heim_oid *to) { - to->length = from->length; - to->components = malloc(to->length * sizeof(*to->components)); - if (to->length != 0 && to->components == NULL) + if (from->length == 0) { + to->length = 0; + to->components = calloc(1, sizeof(*from->components)); + if (to->components == NULL) + return ENOMEM; + return 0; + } + assert(from->components != NULL); + to->components = malloc(from->length * sizeof(*from->components)); + if (to->components == NULL) { + to->length = 0; return ENOMEM; - if (to->components != NULL && from->components != NULL) - memcpy(to->components, from->components, - to->length * sizeof(*to->components)); + } + to->length = from->length; + memcpy(to->components, from->components, + to->length * sizeof(*to->components)); return 0; } @@ -191,12 +227,19 @@ der_copy_bit_string (const heim_bit_string *from, heim_bit_string *to) { size_t len; + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + len = (from->length + 7) / 8; - to->length = from->length; - to->data = malloc(len); - if(len != 0 && to->data == NULL) + if (len == 0) + to->data = calloc(1, 1); + else + to->data = malloc(len); + if (to->data == NULL) { + to->length = 0; return ENOMEM; - if (to->data != NULL && from->data != NULL) + } + to->length = from->length; + if (len > 0) memcpy(to->data, from->data, len); return 0; } diff --git a/third_party/heimdal/lib/asn1/der_get.c b/third_party/heimdal/lib/asn1/der_get.c index 55ba62623595..c12f81700251 100644 --- a/third_party/heimdal/lib/asn1/der_get.c +++ b/third_party/heimdal/lib/asn1/der_get.c @@ -174,6 +174,11 @@ der_get_general_string (const unsigned char *p, size_t len, const unsigned char *p1; char *s; + assert(p != NULL); + + if (size) + *size = 0; + p1 = memchr(p, 0, len); if (p1 != NULL) { /* @@ -217,6 +222,11 @@ int ASN1CALL der_get_printable_string(const unsigned char *p, size_t len, heim_printable_string *str, size_t *size) { + assert(p != NULL); + + if (size) + *size = 0; + if (len == SIZE_MAX) { gen_data_zero(str); return ASN1_BAD_LENGTH; @@ -227,6 +237,7 @@ der_get_printable_string(const unsigned char *p, size_t len, gen_data_zero(str); return ENOMEM; } + memcpy(str->data, p, len); ((char *)str->data)[len] = '\0'; if(size) *size = len; @@ -246,6 +257,11 @@ der_get_bmp_string (const unsigned char *p, size_t len, { size_t i; + assert(p != NULL); + + if (size) + *size = 0; + if (len & 1) { gen_data_zero(data); return ASN1_BAD_FORMAT; @@ -282,6 +298,11 @@ der_get_universal_string (const unsigned char *p, size_t len, { size_t i; + assert(p != NULL); + + if (size) + *size = 0; + if (len & 3) { gen_data_zero(data); return ASN1_BAD_FORMAT; @@ -322,13 +343,23 @@ int ASN1CALL der_get_octet_string (const unsigned char *p, size_t len, heim_octet_string *data, size_t *size) { - data->length = len; - data->data = malloc(len); - if (data->data == NULL && data->length != 0) + assert(p != NULL); + + if (size) + *size = 0; + + if (len == 0) + data->data = malloc(1); + else + data->data = malloc(len); + if (data->data == NULL) { + data->length = 0; return ENOMEM; - if (data->data != NULL) - memcpy (data->data, p, len); - if(size) *size = len; + } + data->length = len; + memcpy (data->data, p, len); + if (size) + *size = len; return 0; } @@ -342,6 +373,11 @@ der_get_octet_string_ber (const unsigned char *p, size_t len, unsigned int tag, depth = 0; size_t l, datalen, oldlen = len; + assert(p != NULL); + + if (size) + *size = 0; + data->length = 0; data->data = NULL; @@ -409,11 +445,14 @@ der_get_heim_integer (const unsigned char *p, size_t len, data->negative = 0; data->data = NULL; - if (len == 0) { - if (size) - *size = 0; + if (size) + *size = 0; + + if (len == 0) return 0; - } + + assert(p != NULL); + if (p[0] & 0x80) { unsigned char *q; int carry = 1; @@ -494,6 +533,11 @@ der_get_time (const unsigned char *p, size_t len, char *times; int e; + assert(p != NULL); + + if (size) + *size = 0; + if (len == SIZE_MAX || len == 0) return ASN1_BAD_LENGTH; @@ -529,6 +573,11 @@ der_get_oid (const unsigned char *p, size_t len, size_t n; size_t oldlen = len; + assert(p != NULL); + + if (size) + *size = 0; + if (len < 1) return ASN1_OVERRUN; @@ -539,8 +588,10 @@ der_get_oid (const unsigned char *p, size_t len, return ERANGE; data->components = malloc((len + 1) * sizeof(data->components[0])); - if (data->components == NULL) + if (data->components == NULL) { + data->length = 0; return ENOMEM; + } data->components[0] = (*p) / 40; data->components[1] = (*p) % 40; --len; @@ -576,8 +627,15 @@ der_get_tag (const unsigned char *p, size_t len, unsigned int *tag, size_t *size) { size_t ret = 0; + + if (size) + *size = 0; + if (len < 1) return ASN1_MISSING_FIELD; + + assert(p != NULL); + *cls = (Der_class)(((*p) >> 6) & 0x03); *type = (Der_type)(((*p) >> 5) & 0x01); *tag = (*p) & 0x1f; @@ -626,6 +684,9 @@ der_match_tag2 (const unsigned char *p, size_t len, unsigned int thistag; int e; + if (size) + *size = 0; + e = der_get_tag(p, len, &thisclass, type, &thistag, &l); if (e) return e; /* @@ -701,6 +762,11 @@ int ASN1CALL der_get_bit_string (const unsigned char *p, size_t len, heim_bit_string *data, size_t *size) { + assert(p != NULL); + + if (size) + *size = 0; + if (len < 1) return ASN1_OVERRUN; if (p[0] > 7) @@ -717,8 +783,10 @@ der_get_bit_string (const unsigned char *p, size_t len, if (len - 1 > 0) { data->length = (len - 1) * 8; data->data = malloc(len - 1); - if (data->data == NULL) + if (data->data == NULL) { + data->length = 0; return ENOMEM; + } memcpy (data->data, p + 1, len - 1); data->length -= p[0]; } else { diff --git a/third_party/heimdal/lib/asn1/der_put.c b/third_party/heimdal/lib/asn1/der_put.c index 5f40fba16152..8fbd6f3da1c0 100644 --- a/third_party/heimdal/lib/asn1/der_put.c +++ b/third_party/heimdal/lib/asn1/der_put.c @@ -49,6 +49,8 @@ der_put_unsigned (unsigned char *p, size_t len, const unsigned *v, size_t *size) unsigned char *base = p; unsigned val = *v; + *size = 0; + if (val) { while (len > 0 && val) { *p-- = val % 256; @@ -81,6 +83,8 @@ der_put_unsigned64 (unsigned char *p, size_t len, const uint64_t *v, size_t *siz unsigned char *base = p; uint64_t val = *v; + *size = 0; + if (val) { while (len > 0 && val) { *p-- = val % 256; @@ -113,6 +117,8 @@ der_put_integer (unsigned char *p, size_t len, const int *v, size_t *size) unsigned char *base = p; int val = *v; + *size = 0; + if(val >= 0) { do { if(len < 1) @@ -153,6 +159,8 @@ der_put_integer64 (unsigned char *p, size_t len, const int64_t *v, size_t *size) unsigned char *base = p; int64_t val = *v; + *size = 0; + if(val >= 0) { do { if(len < 1) @@ -191,12 +199,16 @@ der_put_integer64 (unsigned char *p, size_t len, const int64_t *v, size_t *size) int ASN1CALL der_put_length (unsigned char *p, size_t len, size_t val, size_t *size) { + if (size) + *size = 0; + if (len < 1) return ASN1_OVERFLOW; if (val < 128) { *p = val; - *size = 1; + if (size) + *size = 1; } else { size_t l = 0; @@ -218,6 +230,8 @@ der_put_length (unsigned char *p, size_t len, size_t val, size_t *size) int ASN1CALL der_put_boolean(unsigned char *p, size_t len, const int *data, size_t *size) { + *size = 0; + if(len < 1) return ASN1_OVERFLOW; if(*data != 0) @@ -232,13 +246,15 @@ int ASN1CALL der_put_general_string (unsigned char *p, size_t len, const heim_general_string *str, size_t *size) { - size_t slen = strlen(*str); + size_t slen; + assert(p != NULL && str != NULL && *str != NULL && size != NULL); + *size = 0; + slen = strlen(*str); if (len < slen) return ASN1_OVERFLOW; p -= slen; - if (*str != NULL) - memcpy (p+1, *str, slen); + memcpy (p+1, *str, slen); *size = slen; return 0; } @@ -269,6 +285,12 @@ der_put_bmp_string (unsigned char *p, size_t len, const heim_bmp_string *data, size_t *size) { size_t i; + + assert(p != NULL && data != NULL); + + if (size) + *size = 0; + if (len / 2 < data->length) return ASN1_OVERFLOW; p -= data->length * 2; @@ -286,6 +308,10 @@ der_put_universal_string (unsigned char *p, size_t len, const heim_universal_string *data, size_t *size) { size_t i; + + if (size) + *size = 0; + if (len / 4 < data->length) return ASN1_OVERFLOW; p -= data->length * 4; @@ -311,11 +337,13 @@ int ASN1CALL der_put_octet_string (unsigned char *p, size_t len, const heim_octet_string *data, size_t *size) { + assert(p != NULL && data != NULL && size != NULL); + + *size = 0; if (len < data->length) return ASN1_OVERFLOW; p -= data->length; - if (data->data) - memcpy (p+1, data->data, data->length); + memcpy (p+1, data->data, data->length); *size = data->length; return 0; } @@ -324,9 +352,14 @@ int ASN1CALL der_put_heim_integer (unsigned char *p, size_t len, const heim_integer *data, size_t *size) { - unsigned char *buf = data->data; + unsigned char *buf; int hibitset = 0; + assert(p != NULL); + + if (size) + *size = 0; + if (data->length == 0) { if (len < 1) return ASN1_OVERFLOW; @@ -338,6 +371,8 @@ der_put_heim_integer (unsigned char *p, size_t len, if (len < data->length) return ASN1_OVERFLOW; + assert(data->data != NULL); + buf = data->data; len -= data->length; if (data->negative) { @@ -461,6 +496,8 @@ der_replace_tag(const unsigned char *p, size_t len, size_t payload_len, l, tag_len, len_len; int e; + assert(p != NULL && out != NULL && outlen != NULL); + e = der_get_tag(p, len, &found_class, &found_type, &found_tag, &l); if (e) return e; @@ -506,6 +543,8 @@ der_encode_implicit(unsigned char *p, size_t len, unsigned char *p2; int e; + assert(p != NULL && size != NULL); + /* Attempt to encode in place */ e = encoder(p, len, obj, size); if (e == 0) { @@ -630,13 +669,17 @@ int ASN1CALL der_put_bit_string (unsigned char *p, size_t len, const heim_bit_string *data, size_t *size) { - size_t data_size = (data->length + 7) / 8; + size_t data_size; + + assert(p != NULL && data != NULL && size != NULL); + + *size = 0; + data_size = (data->length + 7) / 8; if (len < data_size + 1) return ASN1_OVERFLOW; p -= data_size + 1; - if (data->data != NULL) - memcpy (p+2, data->data, data_size); + memcpy (p+2, data->data, data_size); if (data->length && (data->length % 8) != 0) p[1] = 8 - (data->length % 8); else @@ -648,9 +691,12 @@ der_put_bit_string (unsigned char *p, size_t len, int _heim_der_set_sort(const void *a1, const void *a2) { - const heim_octet_string *s1 = a1, *s2 = a2; + const heim_octet_string *s1, *s2; int ret; + assert(a1 != NULL && a2 != NULL); + s1 = a1; + s2 = a2; ret = memcmp(s1->data, s2->data, s1->length < s2->length ? s1->length : s2->length); if (ret != 0) diff --git a/third_party/heimdal/lib/asn1/extra.c b/third_party/heimdal/lib/asn1/extra.c index 5a494d23acaf..253ac5aca6f3 100644 --- a/third_party/heimdal/lib/asn1/extra.c +++ b/third_party/heimdal/lib/asn1/extra.c @@ -105,7 +105,7 @@ print_heim_any(const heim_any *data, int flags) free(s); s = NULL; if (r > -1) - r = asprintf(&s, "\"%s\"", s2); + (void) asprintf(&s, "\"%s\"", s2); free(s2); return s; } @@ -155,7 +155,7 @@ print_HEIM_ANY(const heim_any *data, int flags) free(s); s = NULL; if (r > -1) - r = asprintf(&s, "\"%s\"", s2); + (void) asprintf(&s, "\"%s\"", s2); free(s2); return s; } @@ -205,7 +205,7 @@ print_heim_any_set(const heim_any_set *data, int flags) free(s); s = NULL; if (r > -1) - r = asprintf(&s, "\"%s\"", s2); + (void) asprintf(&s, "\"%s\"", s2); free(s2); return s; } @@ -261,7 +261,7 @@ print_HEIM_ANY_SET(const heim_any_set *data, int flags) free(s); s = NULL; if (r > -1) - r = asprintf(&s, "\"%s\"", s2); + (void) asprintf(&s, "\"%s\"", s2); free(s2); return s; } diff --git a/third_party/heimdal/lib/asn1/gen.c b/third_party/heimdal/lib/asn1/gen.c index 8e323188fff9..10153c60379e 100644 --- a/third_party/heimdal/lib/asn1/gen.c +++ b/third_party/heimdal/lib/asn1/gen.c @@ -159,7 +159,7 @@ init_generate (const char *filename, const char *base) /* public header file */ if (asprintf(&header, "%s.h", headerbase) < 0 || header == NULL) errx(1, "malloc"); - if (asprintf(&fn, "%s.hx", headerbase) < 0 || fn == NULL) + if (asprintf(&fn, "%s.h", headerbase) < 0 || fn == NULL) errx(1, "malloc"); headerfile = fopen (fn, "w"); if (headerfile == NULL) @@ -170,7 +170,7 @@ init_generate (const char *filename, const char *base) /* private header file */ if (asprintf(&privheader, "%s-priv.h", headerbase) < 0 || privheader == NULL) errx(1, "malloc"); - if (asprintf(&fn, "%s-priv.hx", headerbase) < 0 || fn == NULL) + if (asprintf(&fn, "%s-priv.h", headerbase) < 0 || fn == NULL) errx(1, "malloc"); privheaderfile = fopen (fn, "w"); if (privheaderfile == NULL) @@ -179,7 +179,7 @@ init_generate (const char *filename, const char *base) fn = NULL; /* template file */ - if (asprintf(&template, "%s-template.x", headerbase) < 0 || template == NULL) + if (asprintf(&template, "%s-template.c", headerbase) < 0 || template == NULL) errx(1, "malloc"); fprintf (headerfile, "/* Generated from %s */\n" @@ -258,7 +258,7 @@ init_generate (const char *filename, const char *base) fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \\\n" " do { \\\n" " (BL) = length_##T((S)); \\\n" - " (B) = malloc((BL)); \\\n" + " (B) = calloc(1, (BL)); \\\n" " if((B) == NULL) { \\\n" " *(L) = 0; \\\n" " (R) = ENOMEM; \\\n" @@ -300,12 +300,12 @@ init_generate (const char *filename, const char *base) free(fn); fn = NULL; - if (asprintf(&fn, "%s_oids.x", base) < 0 || fn == NULL) + if (asprintf(&fn, "%s_oids.c", base) < 0 || fn == NULL) errx(1, "malloc"); oidsfile = fopen(fn, "w"); if (oidsfile == NULL) err (1, "open %s", fn); - if (asprintf(&fn, "%s_syms.x", base) < 0 || fn == NULL) + if (asprintf(&fn, "%s_syms.c", base) < 0 || fn == NULL) errx(1, "malloc"); symsfile = fopen(fn, "w"); if (symsfile == NULL) @@ -356,11 +356,19 @@ close_generate (void) err(1, "writes to private header file failed"); if (templatefile && fclose(templatefile) == EOF) err(1, "writes to template file failed"); - if (logfile) { - fprintf(logfile, "\n"); - if (fclose(logfile) == EOF) - err(1, "writes to log file failed"); - } + if (!jsonfile) abort(); + if (fclose(jsonfile) == EOF) + err(1, "writes to JSON file failed"); + if (!oidsfile) abort(); + if (fclose(oidsfile) == EOF) + err(1, "writes to OIDs file failed"); + if (!symsfile) abort(); + if (fclose(symsfile) == EOF) + err(1, "writes to symbols file failed"); + if (!logfile) abort(); + fprintf(logfile, "\n"); + if (fclose(logfile) == EOF) + err(1, "writes to log file failed"); } void @@ -415,7 +423,7 @@ generate_header_of_codefile(const char *name) if (codefile != NULL) abort(); - if (asprintf (&filename, "%s_%s.x", STEM, name) < 0 || filename == NULL) + if (asprintf (&filename, "%s_%s.c", STEM, name) < 0 || filename == NULL) errx(1, "malloc"); codefile = fopen (filename, "w"); if (codefile == NULL) @@ -427,7 +435,9 @@ generate_header_of_codefile(const char *name) fprintf (codefile, "/* Generated from %s */\n" "/* Do not edit */\n\n" - "#define ASN1_LIB\n\n" + "#if defined(_WIN32) && !defined(ASN1_LIB)\n" + "# error \"ASN1_LIB must be defined\"\n" + "#endif\n" "#include \n" "#include \n" "#include \n" @@ -757,8 +767,10 @@ define_asn1 (int level, Type *t) fprintf(headerfile, "%s.&%s", t->typeref.iosclass->symbol->name, t->typeref.field->name); - } else + } else if (t->symbol) fprintf(headerfile, "%s", t->symbol->name); + else + abort(); break; case TInteger: if(t->members == NULL) { @@ -772,8 +784,8 @@ define_asn1 (int level, Type *t) fprintf (headerfile, "INTEGER {\n"); HEIM_TAILQ_FOREACH(m, t->members, members) { space (level + 1); - fprintf(headerfile, "%s(%d)%s\n", m->gen_name, m->val, - last_member_p(m)); + fprintf(headerfile, "%s(%lld)%s\n", m->gen_name, + (long long)m->val, last_member_p(m)); } space(level); fprintf (headerfile, "}"); @@ -796,8 +808,8 @@ define_asn1 (int level, Type *t) fprintf (headerfile, "ENUMERATED {\n"); HEIM_TAILQ_FOREACH(m, t->members, members) { space(level + 1); - fprintf (headerfile, "%s(%d)%s\n", m->name, m->val, - last_member_p(m)); + fprintf(headerfile, "%s(%lld)%s\n", m->name, + (long long)m->val, last_member_p(m)); } space(level); fprintf (headerfile, "}"); @@ -1022,6 +1034,10 @@ get_open_type_defn_fields(const Type *t, subtype->constraint->u.content.type->constraint && subtype->constraint->u.content.type->constraint->ctype == CT_TABLE_CONSTRAINT) { /* Type like OCTET STRING or BIT STRING CONTAINING open type */ + if (*opentypemember) + errx(1, "Multiple open type members %s and %s for the same " + "field %s?", (*opentypemember)->name, m->name, + (*opentypefield)->name); *opentypemember = m; *opentypefield = subtype->constraint->u.content.type->typeref.field; *is_array_of = sOfType != NULL; @@ -1029,6 +1045,10 @@ get_open_type_defn_fields(const Type *t, break; } else if (subtype->symbol && strcmp(subtype->symbol->name, "HEIM_ANY") == 0) { /* Open type, but NOT embedded in OCTET STRING or BIT STRING */ + if (*opentypemember) + errx(1, "Multiple open type members %s and %s for the same " + "field %s?", (*opentypemember)->name, m->name, + (*opentypefield)->name); *opentypemember = m; *opentypefield = subtype->typeref.field; *is_array_of = sOfType != NULL; @@ -1036,6 +1056,10 @@ get_open_type_defn_fields(const Type *t, break; } } + + if (!idmembername) + errx(1, "Missing open type id member in %s", + t->symbol ? t->symbol->name : ""); /* Look for the type ID member identified in the previous loop */ HEIM_TAILQ_FOREACH(m, t->members, members) { if (!m->type->subtype || strcmp(m->name, idmembername) != 0) @@ -1169,11 +1193,12 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t define_open_type(level, newbasename, name, basename, t, t); } else if (!t->symbol && pt->actual_parameter) { define_open_type(level, newbasename, name, basename, pt, t); - } else { + } else if (t->symbol) { fprintf(headerfile, "%s %s;\n", t->symbol->gen_name, name); fprintf(jsonfile, "\"ttype\":\"%s\"," "\"alias\":true\n", t->symbol->gen_name); - } + } else + abort(); break; case TInteger: if (t->symbol && t->symbol->emitted_definition) @@ -1190,12 +1215,12 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t "\"members\":[\n"); HEIM_TAILQ_FOREACH(m, t->members, members) { space (level + 1); - fprintf(headerfile, "%s%s%s = %d%s\n", + fprintf(headerfile, "%s%s%s = %lld%s\n", label_prefix, label_prefix_sep, - m->gen_name, m->val, last_member_p(m)); - fprintf(jsonfile, "{\"%s%s%s\":%d}%s\n", + m->gen_name, (long long)m->val, last_member_p(m)); + fprintf(jsonfile, "{\"%s%s%s\":%lld}%s\n", label_prefix, label_prefix_sep, - m->gen_name, m->val, last_member_p(m)); + m->gen_name, (long long)m->val, last_member_p(m)); } fprintf(headerfile, "} %s;\n", name); fprintf(jsonfile, "]"); @@ -1268,7 +1293,7 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t fprintf (headerfile, "heim_bit_string %s;\n", name); fprintf(jsonfile, "\"ctype\":\"heim_bit_string\""); } else { - int pos = 0; + int64_t pos = 0; getnewbasename(&newbasename, typedefp || level == 0, basename, name); fprintf (headerfile, "struct %s {\n", newbasename); @@ -1281,7 +1306,8 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t * forces the compiler to give us an obvious layout) */ while (pos < m->val) { - if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL) + if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 || + n == NULL) err(1, "malloc"); define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE); fprintf(jsonfile, ","); @@ -1308,7 +1334,8 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t fprintf(jsonfile, ","); while (pos < bitset_size) { char *n = NULL; - if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL) + if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 || + n == NULL) errx(1, "malloc"); define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE); fprintf(jsonfile, "%s", (pos + 1) < bitset_size ? "," : ""); @@ -1339,12 +1366,12 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t if (m->ellipsis) { fprintf (headerfile, "/* ... */\n"); } else { - fprintf(headerfile, "%s%s%s = %d%s\n", + fprintf(headerfile, "%s%s%s = %lld%s\n", label_prefix, label_prefix_sep, - m->gen_name, m->val, last_member_p(m)); - fprintf(jsonfile, "{\"%s%s%s\":%d%s}\n", + m->gen_name, (long long)m->val, last_member_p(m)); + fprintf(jsonfile, "{\"%s%s%s\":%lld%s}\n", label_prefix, label_prefix_sep, - m->gen_name, m->val, last_member_p(m)); + m->gen_name, (long long)m->val, last_member_p(m)); } } space(level); @@ -1355,12 +1382,14 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t case TSet: case TSequence: { Member *m; - char *ft, *fn; - int deco_opt; + struct decoration deco; + ssize_t more_deco = -1; + int decorated = 0; getnewbasename(&newbasename, typedefp || level == 0, basename, name); space(level); + fprintf (headerfile, "struct %s {\n", newbasename); fprintf(jsonfile, "\"ttype\":\"%s\",\"extensible\":%s," "\"ctype\":\"struct %s\"", @@ -1397,15 +1426,37 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t fprintf(jsonfile, ",\"opentype\":"); define_open_type(level, newbasename, name, basename, t, t); } - if (decorate_type(newbasename, &ft, &fn, &deco_opt)) { + while (decorate_type(newbasename, &deco, &more_deco)) { + decorated++; space(level + 1); - fprintf(headerfile, "%s %s%s;\n", ft, deco_opt ? "*" : "", fn); - fprintf(jsonfile, ",\"decorate\":{\"type\":\"%s\",\"name\":\"%s\", \"optional\":%s}", ft, fn, deco_opt ? "true" : "false"); - free(ft); - free(fn); + fprintf(headerfile, "%s %s%s;\n", deco.field_type, + deco.opt ? "*" : "", deco.field_name); + if (deco.first) + fprintf(jsonfile, ",\"decorate\":["); + fprintf(jsonfile, "%s{" + "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s," + "\"external\":%s,\"pointer\":%s,\"void_star\":%s," + "\"struct_star\":%s," + "\"copy_function\":\"%s\"," + "\"free_function\":\"%s\",\"header_name\":%s%s%s" + "}", + deco.first ? "" : ",", + deco.field_type, deco.field_name, + deco.opt ? "true" : "false", deco.ext ? "true" : "false", + deco.ptr ? "true" : "false", deco.void_star ? "true" : "false", + deco.struct_star ? "true" : "false", + deco.copy_function_name ? deco.copy_function_name : "", + deco.free_function_name ? deco.free_function_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"", + deco.header_name ? deco.header_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"" + ); } + if (decorated) + fprintf(jsonfile, "]"); space(level); fprintf (headerfile, "} %s;\n", name); + free(deco.field_type); break; } case TSetOf: @@ -1454,6 +1505,9 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t define_type(level, name, basename, t, t->subtype, typedefp, preservep); break; case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + int decorated = 0; int first = 1; Member *m; @@ -1512,9 +1566,39 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t } space(level + 1); fprintf (headerfile, "} u;\n"); + fprintf(jsonfile, "]"); + + while (decorate_type(newbasename, &deco, &more_deco)) { + decorated++; + space(level + 1); + fprintf(headerfile, "%s %s%s;\n", deco.field_type, + deco.opt ? "*" : "", deco.field_name); + if (deco.first) + fprintf(jsonfile, ",\"decorate\":["); + fprintf(jsonfile, "%s{" + "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s," + "\"external\":%s,\"pointer\":%s,\"void_star\":%s," + "\"struct_star\":%s," + "\"copy_function\":\"%s\"," + "\"free_function\":\"%s\",\"header_name\":%s%s%s" + "}", + deco.first ? "" : ",", + deco.field_type, deco.field_name, + deco.opt ? "true" : "false", deco.ext ? "true" : "false", + deco.ptr ? "true" : "false", deco.void_star ? "true" : "false", + deco.struct_star ? "true" : "false", + deco.copy_function_name ? deco.copy_function_name : "", + deco.free_function_name ? deco.free_function_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"", + deco.header_name ? deco.header_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"" + ); + } + if (decorated) + fprintf(jsonfile, "]"); + space(level); fprintf (headerfile, "} %s;\n", name); - fprintf(jsonfile, "]"); break; } case TUTCTime: @@ -1617,19 +1701,37 @@ declare_type(const Symbol *s, Type *t, int typedefp) switch (t->type) { case TSet: - case TSequence: + case TSequence: { + struct decoration deco; + ssize_t more_deco = -1; + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + while (decorate_type(newbasename, &deco, &more_deco)) { + if (deco.header_name) + fprintf(headerfile, "#include %s\n", deco.header_name); + free(deco.field_type); + } break; + } case TSetOf: case TSequenceOf: getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); break; - case TChoice: + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + while (decorate_type(newbasename, &deco, &more_deco)) { + if (deco.header_name) + fprintf(headerfile, "#include %s\n", deco.header_name); + free(deco.field_type); + } break; + } default: abort (); } @@ -1755,6 +1857,7 @@ static void generate_type_header (const Symbol *s) { Type *t = s->type; + if (!s->type) return; @@ -1823,6 +1926,7 @@ generate_type_header (const Symbol *s) if (is_export(s->name)) fprintf(symsfile, "ASN1_SYM_TYPE(\"%s\", \"%s\", %s)\n", s->name, s->gen_name, s->gen_name); + fprintf(headerfile, "typedef "); define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, preserve_type(s->name) ? TRUE : FALSE); diff --git a/third_party/heimdal/lib/asn1/gen_copy.c b/third_party/heimdal/lib/asn1/gen_copy.c index 243aa2b0ccae..bec6f8b059f5 100644 --- a/third_party/heimdal/lib/asn1/gen_copy.c +++ b/third_party/heimdal/lib/asn1/gen_copy.c @@ -62,7 +62,7 @@ copy_type (const char *from, const char *to, const Type *t, int preserve) copy_primitive ("heim_integer", from, to); break; } - /* FALLTHROUGH */ + fallthrough; case TBoolean: case TEnumerated : fprintf(codefile, "*(%s) = *(%s);\n", to, from); @@ -125,7 +125,7 @@ copy_type (const char *from, const char *to, const Type *t, int preserve) errx(1, "malloc"); if(m->optional){ fprintf(codefile, "if(%s) {\n", fs); - fprintf(codefile, "%s = malloc(sizeof(*%s));\n", ts, ts); + fprintf(codefile, "%s = calloc(1, sizeof(*%s));\n", ts, ts); fprintf(codefile, "if(%s == NULL) goto fail;\n", ts); used_fail++; } @@ -161,7 +161,7 @@ copy_type (const char *from, const char *to, const Type *t, int preserve) char *f = NULL, *T = NULL; fprintf (codefile, "if(((%s)->val = " - "malloc((%s)->len * sizeof(*(%s)->val))) == NULL && (%s)->len != 0)\n", + "calloc(1, (%s)->len * sizeof(*(%s)->val))) == NULL && (%s)->len != 0)\n", to, from, to, from); fprintf (codefile, "goto fail;\n"); used_fail++; @@ -228,10 +228,10 @@ copy_type (const char *from, const char *to, const Type *t, int preserve) void generate_type_copy (const Symbol *s) { + struct decoration deco; + ssize_t more_deco = -1; int preserve = preserve_type(s->name) ? TRUE : FALSE; int save_used_fail = used_fail; - int deco_opt; - char *ft, *fn; used_fail = 0; @@ -241,18 +241,39 @@ generate_type_copy (const Symbol *s) "memset(to, 0, sizeof(*to));\n", s->gen_name, s->gen_name, s->gen_name); copy_type ("from", "to", s->type, preserve); - if (decorate_type(s->gen_name, &ft, &fn, &deco_opt)) { - if (deco_opt) { - fprintf(codefile, "if (from->%s) {\n", fn); - fprintf(codefile, "(to)->%s = malloc(sizeof(*(to)->%s));\n", fn, fn); - fprintf(codefile, "if (copy_%s((from)->%s, (to)->%s)) goto fail;\n", ft, fn, fn); + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (deco.ext && deco.copy_function_name == NULL) { + /* Decorated with field of external type but no copy function */ + if (deco.ptr) + fprintf(codefile, "(to)->%s = 0;\n", deco.field_name); + else + fprintf(codefile, "memset(&(to)->%s, 0, sizeof((to)->%s));\n", + deco.field_name, deco.field_name); + } else if (deco.ext) { + /* Decorated with field of external type w/ copy function */ + if (deco.ptr) { + fprintf(codefile, "if (from->%s) {\n", deco.field_name); + fprintf(codefile, "(to)->%s = calloc(1, sizeof(*(to)->%s));\n", + deco.field_name, deco.field_name); + fprintf(codefile, "if (%s((from)->%s, (to)->%s)) goto fail;\n", + deco.copy_function_name, deco.field_name, deco.field_name); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "if (%s(&(from)->%s, &(to)->%s)) goto fail;\n", + deco.copy_function_name, deco.field_name, deco.field_name); + } + } else if (deco.opt) { + /* Decorated with optional field of ASN.1 type */ + fprintf(codefile, "if (from->%s) {\n", deco.field_name); + fprintf(codefile, "(to)->%s = calloc(1, sizeof(*(to)->%s));\n", deco.field_name, deco.field_name); + fprintf(codefile, "if (copy_%s((from)->%s, (to)->%s)) goto fail;\n", deco.field_type, deco.field_name, deco.field_name); fprintf(codefile, "}\n"); } else { - fprintf(codefile, "if (copy_%s(&(from)->%s, &(to)->%s)) goto fail;\n", ft, fn, fn); + /* Decorated with required field of ASN.1 type */ + fprintf(codefile, "if (copy_%s(&(from)->%s, &(to)->%s)) goto fail;\n", deco.field_type, deco.field_name, deco.field_name); } used_fail++; - free(ft); - free(fn); + free(deco.field_type); } fprintf (codefile, "return 0;\n"); diff --git a/third_party/heimdal/lib/asn1/gen_decode.c b/third_party/heimdal/lib/asn1/gen_decode.c index 739f9d85f70a..93d412f63356 100644 --- a/third_party/heimdal/lib/asn1/gen_decode.c +++ b/third_party/heimdal/lib/asn1/gen_decode.c @@ -328,9 +328,9 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval, "if (len < 1) break;\n"); pos += 8; } - fprintf (codefile, - "(%s)->%s = (*p >> %d) & 1;\n", - name, m->gen_name, 7 - m->val % 8); + fprintf(codefile, + "(%s)->%s = (*p >> %d) & 1;\n", + name, m->gen_name, (int)(7 - m->val % 8)); } fprintf(codefile, "} while(0);\n"); diff --git a/third_party/heimdal/lib/asn1/gen_encode.c b/third_party/heimdal/lib/asn1/gen_encode.c index b0123a8be176..d61dc2e6d502 100644 --- a/third_party/heimdal/lib/asn1/gen_encode.c +++ b/third_party/heimdal/lib/asn1/gen_encode.c @@ -226,7 +226,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) fprintf (codefile, "if((%s)->%s) {\n" "c |= 1<<%d;\n", - name, m->gen_name, 7 - m->val % 8); + name, m->gen_name, (int)(7 - m->val % 8)); fprintf (codefile, "}\n"); } @@ -313,7 +313,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) name); fprintf(codefile, - "val = malloc(sizeof(val[0]) * (%s)->len);\n" + "val = calloc(1, sizeof(val[0]) * (%s)->len);\n" "if (val == NULL && (%s)->len != 0) return ENOMEM;\n", name, name); @@ -461,23 +461,24 @@ encode_type (const char *name, const Type *t, const char *tmpstr) if (replace_tag) fprintf(codefile, - "{ unsigned char *psave_%s = p;\n" + "{ unsigned char *psave_%s = p, *pfree_%s = NULL;\n" "size_t l2_%s, lensave_%s = len;\n" "len = length_%s(%s);\n" /* Allocate a temp buffer for the encoder */ - "if ((p = malloc(len)) == NULL) return ENOMEM;\n" + "if ((p = pfree_%s = calloc(1, len)) == NULL) return ENOMEM;\n" /* Make p point to the last byte of the allocated buf */ "p += len - 1;\n", - tmpstr, tmpstr, tmpstr, - t->subtype->symbol->gen_name, name); + tmpstr, tmpstr, tmpstr, tmpstr, + t->subtype->symbol->gen_name, name, tmpstr); + /* XXX Currently we generate code that leaks `pfree_%s` here. */ c = encode_type (name, t->subtype, tname); /* Explicit non-UNIVERSAL tags are always constructed */ if (!c && t->tag.tagclass != ASN1_C_UNIV && t->tag.tagenv == TE_EXPLICIT) c = 1; if (replace_tag) fprintf(codefile, - "if (len) abort();\n" + "if (len) { free(pfree_%s); return EINVAL; }\n" /* * Here we have `p' pointing to one byte before the buffer * we allocated above. @@ -552,16 +553,16 @@ encode_type (const char *name, const Type *t, const char *tmpstr) * +-- psave_ */ "e = der_put_tag(psave_%s, %lu, %s, %s, %d, &l2_%s);\n" - "if (e) return e;\n" + "if (e) { free(pfree_%s); return e; }\n" /* Restore `len' and adjust it (see `p' below) */ - "len = lensave_%s - (l + %lu - asn1_tag_length_%s);\n" + "len = lensave_%s - (l + %zu - asn1_tag_length_%s);\n" /* * Adjust `ret' to account for the difference in size * between the length of the right and wrong tags. */ - "ret += %lu - asn1_tag_length_%s;\n" + "ret += %zu - asn1_tag_length_%s;\n" /* Free the buffer and restore `p' */ - "free(p + 1);\n" + "free(pfree_%s);\n" /* * Make `p' point into the original buffer again, to one * byte before the bytes we wrote: @@ -573,7 +574,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) * +-- p */ "p = psave_%s - (1 + %lu - asn1_tag_length_%s); }\n", - tmpstr, tmpstr, t->subtype->symbol->name, + tmpstr, tmpstr, tmpstr, t->subtype->symbol->name, tmpstr, t->subtype->symbol->name, t->subtype->symbol->name, tmpstr, length_tag(t->tag.tagvalue), classname(t->tag.tagclass), @@ -581,9 +582,9 @@ encode_type (const char *name, const Type *t, const char *tmpstr) t->tag.tagvalue, tmpstr, - tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name, + tmpstr, tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name, length_tag(t->tag.tagvalue), t->subtype->symbol->name, - tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name); + tmpstr, tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name); else fprintf(codefile, "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n" diff --git a/third_party/heimdal/lib/asn1/gen_free.c b/third_party/heimdal/lib/asn1/gen_free.c index 6c9424cbf351..0507d5421803 100644 --- a/third_party/heimdal/lib/asn1/gen_free.c +++ b/third_party/heimdal/lib/asn1/gen_free.c @@ -56,6 +56,7 @@ free_type (const char *name, const Type *t, int preserve) free_primitive ("heim_integer", name); break; } + /* fallthrough; */ case TBoolean: case TEnumerated : case TNull: @@ -126,14 +127,14 @@ free_type (const char *name, const Type *t, int preserve) case TSequenceOf: { char *n; - fprintf (codefile, "while((%s)->len){\n", name); + fprintf (codefile, "if ((%s)->val)\nwhile((%s)->len){\n", name, name); if (asprintf (&n, "&(%s)->val[(%s)->len-1]", name, name) < 0 || n == NULL) errx(1, "malloc"); free_type(n, t->subtype, FALSE); fprintf(codefile, "(%s)->len--;\n" - "}\n", - name); + "} else (%s)->len = 0;\n", + name, name); fprintf(codefile, "free((%s)->val);\n" "(%s)->val = NULL;\n", name, name); @@ -178,9 +179,9 @@ free_type (const char *name, const Type *t, int preserve) void generate_type_free (const Symbol *s) { + struct decoration deco; + ssize_t more_deco = -1; int preserve = preserve_type(s->name) ? TRUE : FALSE; - int deco_opt; - char *ft, *fn; fprintf (codefile, "void ASN1CALL\n" "free_%s(%s *data)\n" @@ -188,18 +189,44 @@ generate_type_free (const Symbol *s) s->gen_name, s->gen_name); free_type ("data", s->type, preserve); - if (decorate_type(s->gen_name, &ft, &fn, &deco_opt)) { - if (deco_opt) { - fprintf(codefile, "if ((data)->%s) {\n", fn); - fprintf(codefile, "free_%s((data)->%s);\n", ft, fn); - fprintf(codefile, "free((data)->%s);\n", fn); - fprintf(codefile, "(data)->%s = NULL;\n", fn); + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (deco.ext && deco.free_function_name == NULL) { + /* Decorated with field of external type but no free function */ + if (deco.ptr) + fprintf(codefile, "(data)->%s = 0;\n", deco.field_name); + else + fprintf(codefile, + "memset(&(data)->%s, 0, sizeof((data)->%s));\n", + deco.field_name, deco.field_name); + } else if (deco.ext) { + /* Decorated with field of external type w/ free function */ + if (deco.ptr) { + fprintf(codefile, "if ((data)->%s) {\n", deco.field_name); + fprintf(codefile, "%s((data)->%s);\n", + deco.free_function_name, deco.field_name); + fprintf(codefile, "(data)->%s = 0;\n", deco.field_name); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "%s(&(data)->%s);\n", + deco.free_function_name, deco.field_name); + fprintf(codefile, + "memset(&(data)->%s, 0, sizeof((data)->%s));\n", + deco.field_name, deco.field_name); + } + } else if (deco.opt) { + /* Decorated with optional field of ASN.1 type */ + fprintf(codefile, "if ((data)->%s) {\n", deco.field_name); + fprintf(codefile, "free_%s((data)->%s);\n", + deco.field_type, deco.field_name); + fprintf(codefile, "free((data)->%s);\n", deco.field_name); + fprintf(codefile, "(data)->%s = NULL;\n", deco.field_name); fprintf(codefile, "}\n"); } else { - fprintf(codefile, "free_%s(&(data)->%s);\n", ft, fn); + /* Decorated with required field of ASN.1 type */ + fprintf(codefile, "free_%s(&(data)->%s);\n", + deco.field_type, deco.field_name); } - free(ft); - free(fn); + free(deco.field_type); } fprintf (codefile, "}\n\n"); } diff --git a/third_party/heimdal/lib/asn1/gen_glue.c b/third_party/heimdal/lib/asn1/gen_glue.c index 24f16528c630..424e5de5d5eb 100644 --- a/third_party/heimdal/lib/asn1/gen_glue.c +++ b/third_party/heimdal/lib/asn1/gen_glue.c @@ -62,7 +62,7 @@ generate_2int (const Type *t, const char *gen_name) HEIM_TAILQ_FOREACH(m, t->members, members) { fprintf (get_code_file(), "if(f.%s) r |= (1ULL << %d);\n", - m->gen_name, m->val); + m->gen_name, (int)m->val); } fprintf (get_code_file(), "return r;\n" "}\n\n"); @@ -87,7 +87,7 @@ generate_int2 (const Type *t, const char *gen_name) if(t->members) { HEIM_TAILQ_FOREACH(m, t->members, members) { fprintf (get_code_file(), "\tflags.%s = (n >> %d) & 1;\n", - m->gen_name, m->val); + m->gen_name, (int)m->val); } } fprintf (get_code_file(), "\treturn flags;\n" @@ -114,7 +114,7 @@ generate_units (const Type *t, const char *gen_name) if(t->members) { HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { fprintf (get_code_file(), - "\t{\"%s\",\t1ULL << %d},\n", m->name, m->val); + "\t{\"%s\",\t1ULL << %d},\n", m->name, (int)m->val); } } @@ -144,8 +144,11 @@ generate_glue (const Type *t, const char *gen_name) if (HEIM_TAILQ_EMPTY(t->members)) break; HEIM_TAILQ_FOREACH(m, t->members, members) { - if (m->val > 63) + if (m->val > 63) { + warnx("Not generating 2int, int2, or units for %s due to " + "having a member valued more than 63", gen_name); return; + } } generate_2int (t, gen_name); generate_int2 (t, gen_name); diff --git a/third_party/heimdal/lib/asn1/gen_locl.h b/third_party/heimdal/lib/asn1/gen_locl.h index ccef2acd2319..f37f1490320b 100644 --- a/third_party/heimdal/lib/asn1/gen_locl.h +++ b/third_party/heimdal/lib/asn1/gen_locl.h @@ -144,7 +144,22 @@ int is_tagged_type(const Type *); int preserve_type(const char *); int seq_type(const char *); -int decorate_type(const char *, char **, char **, int *); + +struct decoration { + char *field_type; /* C type name */ + char *field_name; /* C struct field name */ + char *copy_function_name; /* copy constructor function name */ + char *free_function_name; /* destructor function name */ + char *header_name; /* header name */ + unsigned int decorated:1; + unsigned int first:1; /* optional */ + unsigned int opt:1; /* optional */ + unsigned int ext:1; /* external */ + unsigned int ptr:1; /* external, pointer */ + unsigned int void_star:1; /* external, void * */ + unsigned int struct_star:1; /* external, struct foo * */ +}; +int decorate_type(const char *, struct decoration *, ssize_t *); void generate_header_of_codefile(const char *); void close_codefile(void); diff --git a/third_party/heimdal/lib/asn1/gen_template.c b/third_party/heimdal/lib/asn1/gen_template.c index af1e44ee68b3..883eab4b6714 100644 --- a/third_party/heimdal/lib/asn1/gen_template.c +++ b/third_party/heimdal/lib/asn1/gen_template.c @@ -449,14 +449,17 @@ add_line_pointer(struct templatehead *t, errx(1, "malloc"); va_end(ap); - q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr); + if (ptr[0] == '&') + q = add_line(t, "{ %s, %s, %s }", tt, offset, ptr); + else + q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr); q->tt = tt; q->offset = strdup(offset); q->ptr = strdup(ptr); } /* - * Add an entry to a template where the pointer firled is a string literal. + * Add an entry to a template where the pointer field is a string literal. */ static void add_line_string(struct templatehead *t, @@ -549,11 +552,11 @@ defval(struct templatehead *temp, Member *m) { switch (m->defval->type) { case booleanvalue: - add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)%u }", + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)(uintptr_t)%u }", m->defval->u.booleanvalue); break; case nullvalue: - add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)0 }"); + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)(uintptr_t)0 }"); break; case integervalue: { const char *dv = "A1_DV_INTEGER"; @@ -576,16 +579,16 @@ defval(struct templatehead *temp, Member *m) if (t->members) dv = "A1_DV_INTEGER32"; /* XXX Enum size assumptions! No good! */ - else if (t->range->min < 0 && + else if (t->range && t->range->min < 0 && (t->range->min < INT_MIN || t->range->max > INT_MAX)) dv = "A1_DV_INTEGER64"; - else if (t->range->min < 0) + else if (t->range && t->range->min < 0) dv = "A1_DV_INTEGER32"; - else if (t->range->max > UINT_MAX) + else if (t->range && t->range->max > UINT_MAX) dv = "A1_DV_INTEGER64"; else dv = "A1_DV_INTEGER32"; - add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)%llu }", + add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)(uintptr_t)%llu }", dv, (long long)m->defval->u.integervalue); break; } @@ -595,7 +598,7 @@ defval(struct templatehead *temp, Member *m) if (rk_strasvis("ed, m->defval->u.stringvalue, VIS_CSTYLE | VIS_NL, "\"") < 0) err(1, "Could not quote a string"); - add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)\"%s\" }", + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)(uintptr_t)\"%s\" }", quoted); free(quoted); break; @@ -624,11 +627,13 @@ defval(struct templatehead *temp, Member *m) sz -= len; p += len; } - len = snprintf(p, sz, " }"); + if ((len = snprintf(p, sz, " }")) >= sz) + abort(); sz -= len; - p += len; + if (sz != 0) + abort(); - add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)\"%s\" }", s); + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)(uintptr_t)\"%s\" }", s); free(s); break; } @@ -711,6 +716,8 @@ sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */ IOSObject *o; size_t i, nobjs = 0; + *objectsp = NULL; + HEIM_TAILQ_FOREACH(o, os->objects, objects) { ObjectField *typeidobjf = NULL; ObjectField *of; @@ -730,6 +737,9 @@ sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */ } *nobjsp = nobjs; + if (nobjs == 0) + return; + if ((objects = calloc(nobjs, sizeof(*objects))) == NULL) err(1, "Out of memory"); *objectsp = objects; @@ -752,7 +762,7 @@ sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */ static void template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) { - IOSObject **objects; + IOSObject **objects = NULL; IOSObject *o; struct tlist *tl; size_t nobjs, i; @@ -794,7 +804,7 @@ template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) switch (typeidobjf->value->type) { case integervalue: add_line(&tl->template, - "{ A1_OP_OPENTYPE_ID | A1_OTI_IS_INTEGER, 0, (void *)%lld }", + "{ A1_OP_OPENTYPE_ID | A1_OTI_IS_INTEGER, 0, (void *)(uintptr_t)%lld }", (long long)typeidobjf->value->u.integervalue); break; case objectidentifiervalue: @@ -820,7 +830,7 @@ template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) } free(objects); - tlist_header(tl, "{ 0, 0, ((void *)%lu) }", nobjs); + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%lu) }", nobjs); tlist_print(tl); tlist_add(tl); os->symbol->emitted_template = 1; @@ -952,12 +962,15 @@ template_members(struct templatehead *temp, */ HEIM_TAILQ_FOREACH(m, t->members, members) { if (m->val > UINT32_MAX) - continue; /* Wouldn't fit in the offset field */ + errx(1, "Cannot handle %s type %s with named bit %s " + "larger than 63", + t->type == TEnumerated ? "ENUMERATED" : "INTEGER", + name, m->gen_name); add_line(&tl->template, - "{ A1_OP_NAME, %d, \"%s\" }", m->val, m->name); + "{ A1_OP_NAME, %d, \"%s\" }", (int)m->val, m->name); nmemb++; } - tlist_header(tl, "{ 0, 0, ((void *)%lu) }", nmemb); + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%lu) }", nmemb); /* XXX Accidentally O(N^2)? */ if (!tlist_find_dup(tl)) { tlist_print(tl); @@ -1031,7 +1044,10 @@ template_members(struct templatehead *temp, output_name(bname); HEIM_TAILQ_FOREACH(m, t->members, members) { - add_line(&template, "{ 0, %d, \"%s\" }", m->val, m->gen_name); + if (m->val > UINT32_MAX) + errx(1, "Cannot handle BIT STRING type %s with named bit %s " + "larger than 63", name, m->gen_name); + add_line(&template, "{ 0, %d, \"%s\" }", (int)m->val, m->gen_name); } HEIM_TAILQ_FOREACH(q, &template, members) { @@ -1039,7 +1055,7 @@ template_members(struct templatehead *temp, } fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname); - fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)%lu) },\n", + fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)(uintptr_t)%lu) },\n", rfc1510_bitstring ? "|A1_HBF_RFC1510" : "", basetype, (unsigned long)count); i = 1; @@ -1061,10 +1077,10 @@ template_members(struct templatehead *temp, Field *opentypefield = NULL; Field *typeidfield = NULL; Member *m; + struct decoration deco; + ssize_t more_deco = -1; size_t i = 0, typeididx = 0, opentypeidx = 0; int is_array_of_open_type = 0; - int deco_opt; - char *ft, *fn; if (isstruct && t->actual_parameter) get_open_type_defn_fields(t, &typeidmember, &opentypemember, @@ -1104,15 +1120,29 @@ template_members(struct templatehead *temp, typeidfield, opentypefield, opentypemember, is_array_of_open_type); - if (decorate_type(basetype, &ft, &fn, &deco_opt)) { + while (decorate_type(basetype, &deco, &more_deco)) { char *poffset2; - poffset2 = partial_offset(basetype, fn, 1, isstruct); - add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s", - deco_opt ? "|A1_FLAG_OPTIONAL" : ""); + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); free(poffset2); - free(ft); - free(fn); + free(deco.field_type); } if (isstruct) @@ -1125,10 +1155,10 @@ template_members(struct templatehead *temp, Field *opentypefield = NULL; Field *typeidfield = NULL; Member *m; + struct decoration deco; + ssize_t more_deco = -1; size_t i = 0, typeididx = 0, opentypeidx = 0; int is_array_of_open_type = 0; - int deco_opt; - char *ft, *fn; if (isstruct && t->actual_parameter) get_open_type_defn_fields(t, &typeidmember, &opentypemember, @@ -1168,15 +1198,29 @@ template_members(struct templatehead *temp, typeidfield, opentypefield, opentypemember, is_array_of_open_type); - if (decorate_type(basetype, &ft, &fn, &deco_opt)) { + while (decorate_type(basetype, &deco, &more_deco)) { char *poffset2; - poffset2 = partial_offset(basetype, fn, 1, isstruct); - add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s", - deco_opt ? "|A1_FLAG_OPTIONAL" : ""); + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); free(poffset2); - free(ft); - free(fn); + free(deco.field_type); } if (isstruct) @@ -1273,6 +1317,8 @@ template_members(struct templatehead *temp, break; } case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; struct templatehead template; struct template *q; size_t count = 0, i; @@ -1343,7 +1389,7 @@ template_members(struct templatehead *temp, } fprintf(f, "static const struct asn1_template %s[] = {\n", tname); - fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)%lu) },\n", + fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)(uintptr_t)%lu) },\n", e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count); i = 1; HEIM_TAILQ_FOREACH(q, &template, members) { @@ -1354,6 +1400,31 @@ template_members(struct templatehead *temp, add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname); + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + free(e); free(tname); break; @@ -1464,7 +1535,7 @@ generate_template_type(const char *varname, fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name); - tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)%lu) }", + tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)(uintptr_t)%lu) }", (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "", have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl)); @@ -1491,12 +1562,37 @@ generate_template(const Symbol *s) { FILE *f = get_code_file(); const char *dupname; + struct decoration deco; + ssize_t more_deco = -1; if (use_extern(s)) { gen_extern_stubs(f, s->gen_name); return; } + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (!deco.ext) + continue; + if (deco.void_star && deco.header_name) + fprintf(f, "#include %s\n", deco.header_name); + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s_%s = {\n" + "\t(asn1_type_encode)0,\n" + "\t(asn1_type_decode)0,\n" + "\t(asn1_type_length)0,\n" + "\t(asn1_type_copy)%s,\n" + "\t(asn1_type_release)%s,\n" + "\t(asn1_type_print)0,\n" + "\tsizeof(%s)\n" + "};\n", s->gen_name, deco.field_name, + deco.copy_function_name && deco.copy_function_name[0] ? + deco.copy_function_name : "0", + deco.free_function_name && deco.free_function_name[0] ? + deco.free_function_name : "0", + deco.void_star ? "void *" : deco.field_type); + free(deco.field_type); + } + generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1); fprintf(f, diff --git a/third_party/heimdal/lib/asn1/krb5.asn1 b/third_party/heimdal/lib/asn1/krb5.asn1 index baaec52f5f83..639ec5af2d25 100644 --- a/third_party/heimdal/lib/asn1/krb5.asn1 +++ b/third_party/heimdal/lib/asn1/krb5.asn1 @@ -18,6 +18,7 @@ EXPORTS CKSUMTYPE, ChangePasswdDataMS, Checksum, + CompositePrincipal, ENCTYPE, ETYPE-INFO, ETYPE-INFO-ENTRY, @@ -440,9 +441,9 @@ Checksum ::= SEQUENCE { -- -- Attributes have three possible sources in Heimdal Kerberos at this time: -- --- - the EncKDCRepPart --- - the EncTicketPart --- - the Authenticator's AuthorizationData (if any) +-- - the EncKDCRepPart (for the client's attributes on the client side) +-- - the EncTicketPart (for the client's attributes on the server side) +-- - the Authenticator's AuthorizationData (if any; server-side) -- -- In principle there can be more: -- @@ -461,18 +462,47 @@ PrincipalNameAttrSrc ::= CHOICE { enc-ticket-part [1] EncTicketPart -- minus session key } PrincipalNameAttrs ::= SEQUENCE { + -- True if this name was authenticated via an AP-REQ or a KDC-REP authenticated [0] BOOLEAN, - -- These are compiled from the Ticket and Authenticator: + -- These are compiled from the Ticket, KDC-REP, and/or Authenticator source [1] PrincipalNameAttrSrc OPTIONAL, - authenticator-ad [2] AuthorizationData OPTIONAL + authenticator-ad [2] AuthorizationData OPTIONAL, + -- For the server on the client side we should keep track of the + -- transit path taken to reach it (if absent -> unknown). + -- + -- We don't learn much more about the server from the KDC. + peer-realm [3] Realm OPTIONAL, + transited [4] TransitedEncoding OPTIONAL, + -- True if the PAC was verified + pac-verified [5] BOOLEAN, + -- True if any AD-KDC-ISSUEDs in the Ticket were validated + kdc-issued-verified [6] BOOLEAN, + -- TODO: Add requested attributes, for gss_set_name_attribute(), which + -- should cause corresponding authz-data elements to be added to + -- any TGS-REQ or to the AP-REQ's Authenticator as appropriate. + want-ad [7] AuthorizationData OPTIONAL +} +-- This is our type for exported composite name tokens for GSS [RFC6680]. +-- It's the same as Principal (below) as decorated with (see krb5.opt file and +-- asn1_compile usage), except it's not decorated, so the name attributes are +-- encoded/decoded. +CompositePrincipal ::= [APPLICATION 48] SEQUENCE { + name[0] PrincipalName, + realm[1] Realm, + nameattrs[2] PrincipalNameAttrs OPTIONAL } --- this is not part of RFC1510 +-- This is not part of RFC1510/RFC4120. We use this internally as our +-- krb5_principal (which is a typedef of *Principal), and in HDB entries. Principal ::= SEQUENCE { name[0] PrincipalName, realm[1] Realm - -- This will be decorated with a name-attrs field of - -- PrincipalNameAttrs type that doesn't get encoded + -- This will be decorated with an optional nameattrs field of + -- PrincipalNameAttrs type that doesn't get encoded. Same as + -- CompositePrincipal above, except that CompositePrincipal's + -- nameattrs field does get encoded, while Principal's does not: + -- + -- nameattrs[2] PrincipalNameAttrs OPTIONAL } Principals ::= SEQUENCE OF Principal diff --git a/third_party/heimdal/lib/asn1/krb5.opt b/third_party/heimdal/lib/asn1/krb5.opt index 5acc596d39ce..a8bd85c522fb 100644 --- a/third_party/heimdal/lib/asn1/krb5.opt +++ b/third_party/heimdal/lib/asn1/krb5.opt @@ -5,3 +5,5 @@ --sequence=ETYPE-INFO --sequence=ETYPE-INFO2 --preserve-binary=KDC-REQ-BODY +--decorate=PrincipalNameAttrs:void *:pac +--decorate=Principal:PrincipalNameAttrs:nameattrs? diff --git a/third_party/heimdal/lib/asn1/libasn1-exports.def b/third_party/heimdal/lib/asn1/libasn1-exports.def index ade5e2d0bfd0..15d3a37bebaf 100644 --- a/third_party/heimdal/lib/asn1/libasn1-exports.def +++ b/third_party/heimdal/lib/asn1/libasn1-exports.def @@ -335,6 +335,7 @@ EXPORTS copy_CommonCriteriaMeasures copy_CommunityIdentifier copy_CommunityIdentifiers + copy_CompositePrincipal copy_ContentEncryptionAlgorithmIdentifier copy_ContentInfo copy_ContentType @@ -691,6 +692,7 @@ EXPORTS decode_CommonCriteriaMeasures decode_CommunityIdentifier decode_CommunityIdentifiers + decode_CompositePrincipal decode_ContentEncryptionAlgorithmIdentifier decode_ContentInfo decode_ContentType @@ -1196,6 +1198,7 @@ EXPORTS encode_CommonCriteriaMeasures encode_CommunityIdentifier encode_CommunityIdentifiers + encode_CompositePrincipal encode_ContentEncryptionAlgorithmIdentifier encode_ContentInfo encode_ContentType @@ -1556,6 +1559,7 @@ EXPORTS free_CommonCriteriaMeasures free_CommunityIdentifier free_CommunityIdentifiers + free_CompositePrincipal free_ContentEncryptionAlgorithmIdentifier free_ContentInfo free_ContentType @@ -1938,6 +1942,7 @@ EXPORTS length_CommonCriteriaMeasures length_CommunityIdentifier length_CommunityIdentifiers + length_CompositePrincipal length_ContentEncryptionAlgorithmIdentifier length_ContentInfo length_ContentType @@ -2294,6 +2299,7 @@ EXPORTS print_CommonCriteriaMeasures print_CommunityIdentifier print_CommunityIdentifiers + print_CompositePrincipal print_ContentEncryptionAlgorithmIdentifier print_ContentInfo print_ContentType diff --git a/third_party/heimdal/lib/asn1/main.c b/third_party/heimdal/lib/asn1/main.c index 64db63ab2ecb..bcfdad62e2e7 100644 --- a/third_party/heimdal/lib/asn1/main.c +++ b/third_party/heimdal/lib/asn1/main.c @@ -41,60 +41,195 @@ static getarg_strings preserve; static getarg_strings seq; static getarg_strings decorate; +static int +strcmp4mergesort_r(const void *ap, const void *bp, void *d) +{ + const char *a = *(const char **)ap; + const char *b = *(const char **)bp; + char sep = *(const char *)d; + int cmp; + + if (sep) { + const char *sepa = strchr(a, sep); + const char *sepb = strchr(b, sep); + size_t alen, blen; + + if (sepa == NULL) sepa = a + strlen(a); + if (sepb == NULL) sepb = b + strlen(b); + alen = sepa - a; + blen = sepb - b; + cmp = strncmp(a, b, alen > blen ? alen : blen); + if (cmp == 0) + cmp = alen - blen; + } else + cmp = strcmp(a, b); + if (cmp == 0) + return (uintptr_t)ap - (uintptr_t)bp; /* stable sort */ + return cmp; +} + +static int +prefix_check(const char *s, const char *p, size_t plen, char sep, int *cmp) +{ + if ((*cmp = strncmp(p, s, plen)) == 0 && s[plen] == sep) + return 1; + if (*cmp == 0) + *cmp = 1; + return 0; +} + +static ssize_t +bsearch_strings(struct getarg_strings *strs, const char *p, + char sep, ssize_t *more) +{ + ssize_t right = (ssize_t)strs->num_strings - 1; + ssize_t left = 0; + ssize_t plen = 0; + int cmp; + + if (sep) + plen = strlen(p); + + if (strs->num_strings == 0) + return -1; + + if (sep && more && *more > -1) { + /* If *more > -1 we're continuing an iteration */ + if (*more > right) + return -1; + if (prefix_check(strs->strings[*more], p, plen, sep, &cmp)) + return (*more)++; + (*more)++; + return -1; + } + + while (left <= right) { + ssize_t mid = left + (right - left) / 2; + + if (sep) { + int cmp2; + + while (prefix_check(strs->strings[mid], p, plen, sep, &cmp) && + mid > 0 && + prefix_check(strs->strings[mid - 1], p, plen, sep, &cmp2)) + mid--; + } else + cmp = strcmp(p, strs->strings[mid]); + if (cmp == 0) { + if (more) + *more = mid + 1; + return mid; + } + if (cmp < 0) + right = mid - 1; /* -1 if `p' is smaller than smallest in strs */ + else + left = mid + 1; + } + return -1; +} + int preserve_type(const char *p) { - int i; - for (i = 0; i < preserve.num_strings; i++) - if (strcmp(preserve.strings[i], p) == 0) - return 1; - return 0; + return bsearch_strings(&preserve, p, '\0', 0) > -1; } int seq_type(const char *p) { - size_t i; - - for (i = 0; i < seq.num_strings; i++) - if (strcmp(seq.strings[i], p) == 0) - return 1; - return 0; + return bsearch_strings(&seq, p, '\0', 0) > -1; } -int -decorate_type(const char *p, char **field_type, char **field_name, int *opt) +/* + * Split `s' on `sep' and fill fs[] with pointers to the substrings. + * + * Only the first substring is to be freed -- the rest share the same + * allocation. + * + * The last element may contain `sep' chars if there are more fields in `s' + * than output locations in `fs[]'. + */ +static void +split_str(const char *s, char sep, char ***fs) { - size_t plen = strlen(p); size_t i; - *field_type = NULL; - *field_name = NULL; - *opt = 0; - - for (i = 0; i < decorate.num_strings; i++) { - const char *r; + fs[0][0] = estrdup(s); + for (i = 1; fs[i]; i++) { char *q; - if (strncmp(decorate.strings[i], p, plen) != 0) - continue; - if (decorate.strings[i][plen] != ':') - errx(1, "--decorate argument missing field type"); - - p = &decorate.strings[i][plen + 1]; - if ((r = strchr(p, ':')) == NULL) - errx(1, "--decorate argument missing field name"); - r++; - *field_type = estrdup(p); - *(strchr(*field_type, ':')) = '\0'; - *field_name = estrdup(r); - if ((q = strchr(*field_name, '?'))) { - *q = '\0'; - *opt = 1; - } - return 1; + if ((q = strchr(fs[i-1][0], sep)) == NULL) + break; + *(q++) = '\0'; + fs[i][0] = q; } - return 0; + for (; fs[i]; i++) + fs[i][0] = NULL; +} + +/* + * If `p' is "decorated" with a not-to-be-encoded-or-decoded field, + * output the field's typename and fieldname, whether it's optional, whether + * it's an ASN.1 type or an "external" type, and if external the names of + * functions to copy and free values of that type. + */ +int +decorate_type(const char *p, struct decoration *deco, ssize_t *more) +{ + ssize_t i; + char **s[7]; + char *junk = NULL; + char *cp; + + deco->first = *more == -1; + deco->decorated = 0; + deco->field_type = NULL; + if ((i = bsearch_strings(&decorate, p, ':', more)) == -1) + return 0; + + deco->decorated = 1; + deco->opt = deco->ext = deco->ptr = 0; + deco->void_star = deco->struct_star = 0; + deco->field_name = deco->copy_function_name = deco->free_function_name = + deco->header_name = NULL; + + s[0] = &deco->field_type; + s[1] = &deco->field_name; + s[2] = &deco->copy_function_name; + s[3] = &deco->free_function_name; + s[4] = &deco->header_name; + s[5] = &junk; + s[6] = NULL; + split_str(decorate.strings[i] + strlen(p) + 1, ':', s); + + if (junk || deco->field_type[0] == '\0' || !deco->field_name || + deco->field_name[0] == '\0' || deco->field_name[0] == '?') { + errx(1, "Invalidate type decoration specification: --decorate=\"%s\"", + decorate.strings[i]); + } + if ((cp = strchr(deco->field_name, '?'))) { + deco->opt = 1; + *cp = '\0'; + } + if (strcmp(deco->field_type, "void*") == 0 || + strcmp(deco->field_type, "void *") == 0) { + deco->ext = deco->ptr = deco->void_star = 1; + deco->opt = 1; + deco->header_name = NULL; + } else if (strncmp(deco->field_type, "struct ", sizeof("struct ") - 1) == 0 && + deco->field_type[strlen(deco->field_type) - 1] == '*') + deco->ptr = deco->struct_star = 1; + if (deco->ptr || deco->copy_function_name) + deco->ext = 1; + if (deco->ext && deco->copy_function_name && !deco->copy_function_name[0]) + deco->copy_function_name = NULL; + if (deco->ext && deco->free_function_name && !deco->free_function_name[0]) + deco->free_function_name = NULL; + if (deco->header_name && !deco->header_name[0]) + deco->header_name = NULL; + if (deco->ptr) + deco->opt = 0; + return 1; } static const char * @@ -147,11 +282,11 @@ struct getargs args[] = { { "preserve-binary", 0, arg_strings, &preserve, "Names of types for which to generate _save fields, saving original " "encoding, in containing structures (useful for signature " - "verification)", "TYPE-NAME" }, + "verification)", "TYPE" }, { "sequence", 0, arg_strings, &seq, - "Generate add/remove functions for SEQUENCE OF types", "TYPE-NAME" }, + "Generate add/remove functions for SEQUENCE OF types", "TYPE" }, { "decorate", 0, arg_strings, &decorate, - "Generate private field for SEQUENCE/SET type", "TYPE-NAME:FIELD_TYPE:field_name[?]" }, + "Generate private field for SEQUENCE/SET type", "DECORATION" }, { "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL }, { "gen-name", 0, arg_string, &name, "Name of generated module", "NAME" }, @@ -166,7 +301,7 @@ struct getargs args[] = { "Do not generate roken-style units", NULL }, { "type-file", 0, arg_string, &type_file_string, "Name of a C header file to generate includes of for base types", - "C-HEADER-FILE" }, + "FILE" }, { "version", 0, arg_flag, &version_flag, NULL, NULL }, { "help", 0, arg_flag, &help_flag, NULL, NULL } }; @@ -175,7 +310,17 @@ int num_args = sizeof(args) / sizeof(args[0]); static void usage(int code) { + if (code) + dup2(STDERR_FILENO, STDOUT_FILENO); + else + dup2(STDOUT_FILENO, STDERR_FILENO); arg_printusage(args, num_args, NULL, "[asn1-file [name]]"); + fprintf(stderr, + "\nA DECORATION is one of:\n\n" + "\tTYPE:FTYPE:fname[?]\n" + "\tTYPE:FTYPE:fname[?]:[copy_function]:[free_function]:header\n" + "\tTYPE:void:fname:::\n" + "\nSee the manual page.\n"); exit(code); } @@ -304,6 +449,15 @@ main(int argc, char **argv) #endif } + if (preserve.num_strings) + mergesort_r(preserve.strings, preserve.num_strings, + sizeof(preserve.strings[0]), strcmp4mergesort_r, ""); + if (seq.num_strings) + mergesort_r(seq.strings, seq.num_strings, sizeof(seq.strings[0]), + strcmp4mergesort_r, ""); + if (decorate.num_strings) + mergesort_r(decorate.strings, decorate.num_strings, + sizeof(decorate.strings[0]), strcmp4mergesort_r, ":"); init_generate(file, name); @@ -316,12 +470,12 @@ main(int argc, char **argv) exit(1); if (!original_order) generate_types(); - close_generate (); if (argc != optidx) fclose(yyin); if (one_code_file) close_codefile(); + close_generate(); if (arg) { for (i = 1; i < len; i++) diff --git a/third_party/heimdal/lib/asn1/oid_resolution.c b/third_party/heimdal/lib/asn1/oid_resolution.c index 63155efbd073..db11b114282e 100644 --- a/third_party/heimdal/lib/asn1/oid_resolution.c +++ b/third_party/heimdal/lib/asn1/oid_resolution.c @@ -59,19 +59,19 @@ struct sym_oid { { #sym, &asn1_oid_ ## sym }, static const struct sym_oid sym_oids[] = { -#include "cms_asn1_oids.x" -#include "crmf_asn1_oids.x" -#include "digest_asn1_oids.x" -#include "krb5_asn1_oids.x" -#include "kx509_asn1_oids.x" -#include "ocsp_asn1_oids.x" -#include "pkcs10_asn1_oids.x" -#include "pkcs12_asn1_oids.x" -#include "pkcs8_asn1_oids.x" -#include "pkcs9_asn1_oids.x" -#include "pkinit_asn1_oids.x" -#include "rfc2459_asn1_oids.x" -#include "rfc4108_asn1_oids.x" +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" +#include "rfc4108_asn1_oids.c" }; static size_t num_sym_oids = sizeof(sym_oids) / sizeof(sym_oids[0]); @@ -95,18 +95,18 @@ static size_t count_sym_oids(void) { size_t c = 0; -#include "cms_asn1_oids.x" -#include "crmf_asn1_oids.x" -#include "digest_asn1_oids.x" -#include "krb5_asn1_oids.x" -#include "kx509_asn1_oids.x" -#include "ocsp_asn1_oids.x" -#include "pkcs10_asn1_oids.x" -#include "pkcs12_asn1_oids.x" -#include "pkcs8_asn1_oids.x" -#include "pkcs9_asn1_oids.x" -#include "pkinit_asn1_oids.x" -#include "rfc2459_asn1_oids.x" +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" return c; } #undef DEFINE_OID_WITH_NAME @@ -125,18 +125,18 @@ init_sym_oids(void) if (!sym_oids && (c = count_sym_oids()) && (tmp = calloc(c, sizeof(tmp[0])))) { -#include "cms_asn1_oids.x" -#include "crmf_asn1_oids.x" -#include "digest_asn1_oids.x" -#include "krb5_asn1_oids.x" -#include "kx509_asn1_oids.x" -#include "ocsp_asn1_oids.x" -#include "pkcs10_asn1_oids.x" -#include "pkcs12_asn1_oids.x" -#include "pkcs8_asn1_oids.x" -#include "pkcs9_asn1_oids.x" -#include "pkinit_asn1_oids.x" -#include "rfc2459_asn1_oids.x" +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" num_sym_oids = c; sym_oids = tmp; } @@ -331,7 +331,6 @@ der_print_heim_oid_sym(const heim_oid *oid, char delim, char **strp) *strp = s1; return 0; } - p = s2 + strlen(s1) + 1; for (p = s2 + strlen(s1) + 1; *p; p++) { if (*p == '_') *p = '-'; diff --git a/third_party/heimdal/lib/asn1/symbol.h b/third_party/heimdal/lib/asn1/symbol.h index b88386223b30..8a24e2515657 100644 --- a/third_party/heimdal/lib/asn1/symbol.h +++ b/third_party/heimdal/lib/asn1/symbol.h @@ -91,7 +91,7 @@ struct member { char *name; char *gen_name; char *label; - int val; + int64_t val; int optional; int ellipsis; struct type *type; @@ -120,7 +120,7 @@ struct range { int64_t max; }; -enum ctype { CT_CONTENTS, CT_USER, CT_TABLE_CONSTRAINT } ; +enum ctype { CT_CONTENTS, CT_USER, CT_TABLE_CONSTRAINT, CT_RANGE } ; struct constraint_spec; @@ -217,6 +217,7 @@ struct constraint_spec { struct value *encoding; struct component_relation_constraint crel; } content; + struct range *range; } u; }; diff --git a/third_party/heimdal/lib/asn1/template.c b/third_party/heimdal/lib/asn1/template.c index 7f5670f3456f..7a19e7477e3d 100644 --- a/third_party/heimdal/lib/asn1/template.c +++ b/third_party/heimdal/lib/asn1/template.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifndef ENOTSUP /* Very old MSVC CRTs don't have ENOTSUP */ @@ -774,6 +775,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, return ret; break; } + case A1_OP_TYPE_DECORATE_EXTERN: break; case A1_OP_TYPE_DECORATE: break; case A1_OP_NAME: break; case A1_OP_DEFVAL: @@ -829,6 +831,8 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, if (ret) { if (t->tt & A1_FLAG_OPTIONAL) { } else if (t->tt & A1_FLAG_DEFAULT) { + if (!tdefval) + return ASN1_PARSE_ERROR; /* Can't happen */ /* * Defaulted field not present in encoding, presumably, * though we should really look more carefully at `ret'. @@ -895,6 +899,8 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, data = olddata; break; } else if (t->tt & A1_FLAG_DEFAULT) { + if (!tdefval) + return ASN1_PARSE_ERROR; /* Can't happen */ /* * Defaulted field not present in encoding, presumably, * though we should really look more carefully at `ret'. @@ -1418,6 +1424,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; case A1_OP_TYPE_DECORATE: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { @@ -1583,10 +1590,9 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const } if (ret == 0) { /* Copy the encoding where it belongs */ - len -= l; p -= l; psave -= (datalen + l - oldtaglen); lensave -= (datalen + l - oldtaglen); - memcpy(psave + 1, p + 1, datalen + l - oldtaglen); + memcpy(psave + 1, p + 1 - l, datalen + l - oldtaglen); p = psave; len = lensave; } @@ -1828,7 +1834,7 @@ _asn1_length_open_type_id(const struct asn1_template *t, const void *data) { struct asn1_template pretend[2] = { - { 0, 0, ((void*)1) }, + { 0, 0, ((void*)(uintptr_t)1) }, }; pretend[1] = *t; while ((t->tt & A1_OP_MASK) == A1_OP_TAG) @@ -1895,8 +1901,6 @@ _asn1_length_open_type(const struct asn1_template *tbase, break; default: return 0; } - if (!typeid_is_int && !typeid_is_oid) - return 0; if (!(t->tt & A1_OS_OT_IS_ARRAY)) { struct heim_base_data *os = DPO(data, topentype->offset); @@ -1994,6 +1998,7 @@ _asn1_length(const struct asn1_template *t, const void *data) } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; case A1_OP_TYPE_DECORATE: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { @@ -2256,6 +2261,7 @@ _asn1_free(const struct asn1_template *t, void *data) } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: case A1_OP_TYPE_DECORATE: case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { @@ -2270,9 +2276,17 @@ _asn1_free(const struct asn1_template *t, void *data) if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { _asn1_free(t->ptr, el); - } else { + } else if ((t->tt & A1_OP_MASK) == A1_OP_TYPE_EXTERN) { const struct asn1_type_func *f = t->ptr; (f->release)(el); + } else { + /* A1_OP_TYPE_DECORATE_EXTERN */ + const struct asn1_type_func *f = t->ptr; + + if (f && f->release) + (f->release)(el); + else if (f) + memset(el, 0, f->size); } if (t->tt & A1_FLAG_OPTIONAL) { free(el); @@ -2432,9 +2446,9 @@ _asn1_print_open_type(const struct asn1_template *t, /* object set template */ if (s) r = rk_strpoolprintf(r, ",%s\"_%s\":%s", indents ? indents : "", opentype_name, s); - free(indents); free(s); } + free(indents); return r; } @@ -2450,8 +2464,7 @@ _asn1_print_open_type(const struct asn1_template *t, /* object set template */ opentype_name); free(indents); indents = getindent(flags, indent + 1); - if (indents) - r = rk_strpoolprintf(r, "%s", indents ? indents : ""); + r = rk_strpoolprintf(r, "%s", indents ? indents : ""); for (i = 0; r && i < len; i++) { struct rk_strpool *r2 = NULL; char *s = NULL;; @@ -2545,6 +2558,7 @@ _asn1_print(const struct asn1_template *t, break; case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; case A1_OP_TYPE_DECORATE: break; /* We could probably print this though */ case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { @@ -2816,7 +2830,7 @@ _asn1_copy_open_type(const struct asn1_template *t, /* object set template */ *dtop = NULL; if ((valto = calloc(len, sizeof(valto[0]))) == NULL) ret = ENOMEM; - for (i = 0, len = *lenfromp; ret == 0 && i < len; (*lentop)++, i++) { + for (i = 0, len = *lenfromp; ret == 0 && i < len; i++) { if (valfrom[i] == NULL) { valto[i] = NULL; continue; @@ -2825,17 +2839,19 @@ _asn1_copy_open_type(const struct asn1_template *t, /* object set template */ ret = ENOMEM; else ret = _asn1_copy(tactual_type->ptr, valfrom[i], valto[i]); + (*lentop)++; } - for (i = 0; ret && i < len; i++) { + for (i = 0; ret && i < (*lentop); i++) { if (valto[i]) { _asn1_free(tactual_type->ptr, valto[i]); free(valto[i]); } } - if (ret) + if (ret) { free(valto); - else + *lentop = 0; + } else *dtop = valto; return ret; } @@ -2863,6 +2879,7 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to) } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: case A1_OP_TYPE_DECORATE: case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { @@ -2871,7 +2888,8 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to) void **ptel = (void **)tel; size_t size; - if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || + (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { size = _asn1_sizeofType(t->ptr); } else { const struct asn1_type_func *f = t->ptr; @@ -2892,9 +2910,17 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to) if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { ret = _asn1_copy(t->ptr, fel, tel); + } else if ((t->tt & A1_OP_MASK) == A1_OP_TYPE_EXTERN) { + const struct asn1_type_func *f = t->ptr; + ret = (f->copy)(fel, tel); } else { const struct asn1_type_func *f = t->ptr; - ret = (f->copy)(fel, tel); + + /* A1_OP_TYPE_DECORATE_EXTERN */ + if (f && f->copy) + ret = (f->copy)(fel, tel); + else if (f) + memset(tel, 0, f->size); } if (ret) { diff --git a/third_party/heimdal/lib/asn1/test.asn1 b/third_party/heimdal/lib/asn1/test.asn1 index a76152712d9e..08c7dcd93ee1 100644 --- a/third_party/heimdal/lib/asn1/test.asn1 +++ b/third_party/heimdal/lib/asn1/test.asn1 @@ -288,7 +288,7 @@ TESTExtensible ::= SEQUENCE { TESTDecorated ::= SEQUENCE { version TESTuint32 - -- gets decorated + -- gets decorated with varius fields (see test.opt) } TESTNotDecorated ::= SEQUENCE { @@ -296,4 +296,14 @@ TESTNotDecorated ::= SEQUENCE { -- should have the same encoding as TESTDecorated } +TESTDecoratedChoice ::= CHOICE { + version TESTuint32 + -- gets decorated with varius fields (see test.opt) +} + +TESTNotDecoratedChoice ::= CHOICE { + version TESTuint32 + -- should have the same encoding as TESTDecoratedChoice +} + END diff --git a/third_party/heimdal/lib/asn1/test.opt b/third_party/heimdal/lib/asn1/test.opt index 500ee4ec8111..755eba01bfb9 100644 --- a/third_party/heimdal/lib/asn1/test.opt +++ b/third_party/heimdal/lib/asn1/test.opt @@ -1 +1,7 @@ --sequence=TESTSeqOf +--decorate=TESTDecorated:TESTuint32:version2? +--decorate=TESTDecorated:my_vers:version3:my_copy_vers:my_free_vers:"check-gen.h" +--decorate=TESTDecorated:void *:privthing +--decorate=TESTDecoratedChoice:TESTuint32:version2? +--decorate=TESTDecoratedChoice:my_vers:version3:my_copy_vers:my_free_vers:"check-gen.h" +--decorate=TESTDecoratedChoice:void *:privthing diff --git a/third_party/heimdal/lib/base/array.c b/third_party/heimdal/lib/base/array.c index b34f9de48800..994fa7d38e4c 100644 --- a/third_party/heimdal/lib/base/array.c +++ b/third_party/heimdal/lib/base/array.c @@ -46,7 +46,7 @@ struct heim_array_data { heim_object_t *allocated; }; -static void +static void HEIM_CALLCONV array_dealloc(heim_object_t ptr) { heim_array_t array = ptr; @@ -58,7 +58,7 @@ array_dealloc(heim_object_t ptr) struct heim_type_data array_object = { HEIM_TID_ARRAY, - "dict-object", + "array-object", NULL, array_dealloc, NULL, diff --git a/third_party/heimdal/lib/base/bsearch.c b/third_party/heimdal/lib/base/bsearch.c index 278962172683..268cc018df6f 100644 --- a/third_party/heimdal/lib/base/bsearch.c +++ b/third_party/heimdal/lib/base/bsearch.c @@ -275,11 +275,12 @@ bsearch_common(const char *buf, size_t sz, const char *key, ret = 0; if (val_len && value) { /* Avoid strndup() so we don't need libroken here yet */ - *value = malloc(val_len + 1); - if (!*value) - ret = errno; - (void) memcpy(*value, &buf[val_start], val_len); - (*value)[val_len] = '\0'; + if ((*value = malloc(val_len + 1))) { + (void) memcpy(*value, &buf[val_start], val_len); + (*value)[val_len] = '\0'; + } else { + ret = errno; + } } break; } @@ -708,6 +709,10 @@ _bsearch_file(bsearch_file_handle bfh, const char *key, if (reads) *reads = 0; + if (value) + *value = NULL; + if (loops) + *loops = 0; /* If whole file is in memory then search that and we're done */ if (bfh->file_sz == bfh->cache_sz) @@ -715,11 +720,6 @@ _bsearch_file(bsearch_file_handle bfh, const char *key, /* Else block-wise binary search */ - if (value) - *value = NULL; - if (loops) - *loops = 0; - l = 0; r = (bfh->file_sz / bfh->page_sz) + 1; for (level = 0, page = r >> 1; page >= l && page < r ; level++) { @@ -851,7 +851,7 @@ stdb_copy_value(void *db, heim_string_t table, heim_data_t key, { bsearch_file_handle bfh = db; const char *k; - char *v; + char *v = NULL; heim_data_t value; int ret; @@ -869,6 +869,8 @@ stdb_copy_value(void *db, heim_string_t table, heim_data_t key, else k = (const char *)heim_data_get_ptr(key); ret = _bsearch_file(bfh, k, &v, NULL, NULL, NULL); + if (ret == 0 && v == NULL) + ret = -1; /* Quiet lint */ if (ret != 0) { if (ret > 0 && error) *error = heim_error_create(ret, "%s", strerror(ret)); diff --git a/third_party/heimdal/lib/base/data.c b/third_party/heimdal/lib/base/data.c index 4aa6efc66774..cefdde0c1bbe 100644 --- a/third_party/heimdal/lib/base/data.c +++ b/third_party/heimdal/lib/base/data.c @@ -34,7 +34,7 @@ #include "baselocl.h" #include -static void +static void HEIM_CALLCONV data_dealloc(void *ptr) { heim_data_t d = ptr; @@ -61,7 +61,7 @@ data_cmp(void *a, void *b) return memcmp(osa->data, osb->data, osa->length); } -static unsigned long +static uintptr_t data_hash(void *ptr) { heim_octet_string *os = ptr; @@ -69,8 +69,9 @@ data_hash(void *ptr) if (os->length < 4) return os->length; - return s[0] | (s[1] << 8) | - (s[os->length - 2] << 16) | (s[os->length - 1] << 24); + + return ((unsigned long)s[os->length - 1] << 24) + | (s[os->length - 2] << 16) | (s[1] << 8) | s[0]; } struct heim_type_data _heim_data_object = { diff --git a/third_party/heimdal/lib/base/db.c b/third_party/heimdal/lib/base/db.c index cd750386accf..b206ff6d766b 100644 --- a/third_party/heimdal/lib/base/db.c +++ b/third_party/heimdal/lib/base/db.c @@ -84,7 +84,7 @@ static int open_file(const char *, int , int, int *, heim_error_t *); static int read_json(const char *, heim_object_t *, heim_error_t *); static struct heim_db_type json_dbt; -static void db_dealloc(void *ptr); +static void HEIM_CALLCONV db_dealloc(void *ptr); struct heim_type_data db_object = { HEIM_TID_DB, @@ -150,7 +150,7 @@ db_init_plugins_once(void *arg) db_plugins = heim_retain(arg); } -static void +static void HEIM_CALLCONV plugin_dealloc(void *arg) { db_plugin plug = arg; @@ -242,7 +242,7 @@ heim_db_register(const char *dbtype, return ret; } -static void +static void HEIM_CALLCONV db_dealloc(void *arg) { heim_db_t db = arg; @@ -577,7 +577,7 @@ heim_db_commit(heim_db_t db, heim_error_t *error) goto done; } - if (db->options == NULL) + if (db->options) journal_fname = heim_dict_get_value(db->options, HSTR("journal-filename")); if (journal_fname != NULL) { @@ -1144,21 +1144,15 @@ enomem: static heim_data_t from_base64(heim_string_t s, heim_error_t *error) { + ssize_t len = -1; void *buf; - size_t len; heim_data_t d; buf = malloc(strlen(heim_string_get_utf8(s))); - if (buf == NULL) - goto enomem; - - len = rk_base64_decode(heim_string_get_utf8(s), buf); - d = heim_data_ref_create(buf, len, free); - if (d == NULL) - goto enomem; - return d; - -enomem: + if (buf) + len = rk_base64_decode(heim_string_get_utf8(s), buf); + if (len > -1 && (d = heim_data_ref_create(buf, len, free))) + return d; free(buf); if (error) *error = heim_error_create_enomem(); diff --git a/third_party/heimdal/lib/base/dict.c b/third_party/heimdal/lib/base/dict.c index 8d73846b2bbb..86be109ffc5e 100644 --- a/third_party/heimdal/lib/base/dict.c +++ b/third_party/heimdal/lib/base/dict.c @@ -47,7 +47,7 @@ struct heim_dict_data { struct hashentry **tab; }; -static void +static void HEIM_CALLCONV dict_dealloc(void *ptr) { heim_dict_t dict = ptr; @@ -115,6 +115,8 @@ heim_dict_create(size_t size) heim_dict_t dict; dict = _heim_alloc_object(&dict_object, sizeof(*dict)); + if (dict == NULL) + return NULL; dict->size = findprime(size); if (dict->size == 0) { @@ -149,7 +151,7 @@ heim_dict_get_type_id(void) static struct hashentry * _search(heim_dict_t dict, heim_object_t ptr) { - unsigned long v = heim_get_hash(ptr); + uintptr_t v = heim_get_hash(ptr); struct hashentry *p; for (p = dict->tab[v % dict->size]; p != NULL; p = p->next) @@ -219,7 +221,7 @@ heim_dict_set_value(heim_dict_t dict, heim_object_t key, heim_object_t value) heim_release(h->value); h->value = heim_retain(value); } else { - unsigned long v; + uintptr_t v; h = malloc(sizeof(*h)); if (h == NULL) diff --git a/third_party/heimdal/lib/base/dll.c b/third_party/heimdal/lib/base/dll.c index 31017a01191b..59c39137b727 100644 --- a/third_party/heimdal/lib/base/dll.c +++ b/third_party/heimdal/lib/base/dll.c @@ -83,7 +83,8 @@ struct tls_values { static HEIMDAL_THREAD_LOCAL struct tls_values values; -#define DEAD_KEY ((void *)8) +static char dead_key; +#define DEAD_KEY ((void *)&dead_key) void heim_w32_service_thread_detach(void *unused) diff --git a/third_party/heimdal/lib/base/error.c b/third_party/heimdal/lib/base/error.c index 8ae65de4981e..6ba3bea412db 100644 --- a/third_party/heimdal/lib/base/error.c +++ b/third_party/heimdal/lib/base/error.c @@ -41,7 +41,7 @@ struct heim_error { struct heim_error *next; }; -static void +static void HEIM_CALLCONV error_dealloc(void *ptr) { struct heim_error *p = ptr; @@ -58,7 +58,7 @@ error_cmp(void *a, void *b) return heim_cmp(ap->msg, bp->msg); } -static unsigned long +static uintptr_t error_hash(void *ptr) { struct heim_error *p = ptr; diff --git a/third_party/heimdal/lib/base/error_string.c b/third_party/heimdal/lib/base/error_string.c index 5c787ba2ce51..a562833a91a0 100644 --- a/third_party/heimdal/lib/base/error_string.c +++ b/third_party/heimdal/lib/base/error_string.c @@ -39,6 +39,8 @@ void heim_clear_error_message(heim_context context) { + if (!context) + return; if (context->error_string) free(context->error_string); context->error_code = 0; @@ -53,7 +55,8 @@ heim_set_error_message(heim_context context, heim_error_code ret, va_list ap; va_start(ap, fmt); - heim_vset_error_message(context, ret, fmt, ap); + if (context) + heim_vset_error_message(context, ret, fmt, ap); va_end(ap); } @@ -164,7 +167,7 @@ heim_get_error_string(heim_context context) int heim_have_error_string(heim_context context) { - return context->error_string != NULL; + return context && context->error_string != NULL; } void diff --git a/third_party/heimdal/lib/base/expand_path.c b/third_party/heimdal/lib/base/expand_path.c index df382b99887d..cf249917e8fe 100644 --- a/third_party/heimdal/lib/base/expand_path.c +++ b/third_party/heimdal/lib/base/expand_path.c @@ -59,10 +59,9 @@ expand_temp_folder(heim_context context, PTYPE param, const char *postfix, size_t len; if (!GetTempPath(sizeof(tpath)/sizeof(tpath[0]), tpath)) { - if (context) - heim_set_error_message(context, EINVAL, - "Failed to get temporary path (GLE=%d)", - GetLastError()); + heim_set_error_message(context, EINVAL, + "Failed to get temporary path (GLE=%d)", + GetLastError()); return EINVAL; } @@ -170,55 +169,52 @@ expand_userid(heim_context context, PTYPE param, const char *postfix, } if (le != 0) { - if (context) - heim_set_error_message(context, rv, - "Can't open thread token (GLE=%d)", le); + heim_set_error_message(context, rv, + "Can't open thread token (GLE=%d)", le); goto _exit; } } if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &len)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - if (context) - heim_set_error_message(context, rv, - "Unexpected error reading token information (GLE=%d)", - GetLastError()); + heim_set_error_message(context, rv, + "Unexpected error reading token information (GLE=%d)", + GetLastError()); goto _exit; } if (len == 0) { - if (context) - heim_set_error_message(context, rv, - "GetTokenInformation() returned truncated buffer"); + heim_set_error_message(context, rv, + "GetTokenInformation() returned truncated buffer"); goto _exit; } pOwner = malloc(len); if (pOwner == NULL) { - if (context) - heim_set_error_message(context, rv, "Out of memory"); + heim_set_error_message(context, rv, "Out of memory"); goto _exit; } } else { - if (context) - heim_set_error_message(context, rv, "GetTokenInformation() returned truncated buffer"); + heim_set_error_message(context, rv, "GetTokenInformation() returned truncated buffer"); goto _exit; } if (!GetTokenInformation(hToken, TokenOwner, pOwner, len, &len)) { - if (context) - heim_set_error_message(context, rv, "GetTokenInformation() failed. GLE=%d", GetLastError()); + heim_set_error_message(context, rv, + "GetTokenInformation() failed. GLE=%d", + GetLastError()); goto _exit; } if (!ConvertSidToStringSid(pOwner->Owner, &strSid)) { - if (context) - heim_set_error_message(context, rv, "Can't convert SID to string. GLE=%d", GetLastError()); + heim_set_error_message(context, rv, + "Can't convert SID to string. GLE=%d", + GetLastError()); goto _exit; } *ret = strdup(strSid); - if (*ret == NULL && context) + if (*ret == NULL) heim_set_error_message(context, rv, "Out of memory"); rv = 0; @@ -248,8 +244,7 @@ expand_csidl(heim_context context, PTYPE folder, const char *postfix, size_t len; if (SHGetFolderPath(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path) != S_OK) { - if (context) - heim_set_error_message(context, EINVAL, "Unable to determine folder path"); + heim_set_error_message(context, EINVAL, "Unable to determine folder path"); return EINVAL; } @@ -387,7 +382,7 @@ expand_strftime(heim_context context, PTYPE param, const char *postfix, t = time(NULL); len = strftime(buf, sizeof(buf), arg, localtime(&t)); if (len == 0 || len >= sizeof(buf)) - return ENOMEM; + return heim_enomem(context); *ret = strdup(buf); return 0; } @@ -488,8 +483,7 @@ expand_token(heim_context context, if (token[0] != '%' || token[1] != '{' || token_end[0] != '}' || token_end - token <= 2) { - if (context) - heim_set_error_message(context, EINVAL,"Invalid token."); + heim_set_error_message(context, EINVAL,"Invalid token."); return EINVAL; } @@ -521,8 +515,7 @@ expand_token(heim_context context, return errcode; } - if (context) - heim_set_error_message(context, EINVAL, "Invalid token."); + heim_set_error_message(context, EINVAL, "Invalid token."); return EINVAL; } @@ -630,7 +623,6 @@ heim_expand_path_tokensv(heim_context context, break; extra_tokens[i] = strdup(s); if (extra_tokens[i++] == NULL) { - va_end(ap); free_extra_tokens(extra_tokens); return heim_enomem(context); } @@ -639,7 +631,6 @@ heim_expand_path_tokensv(heim_context context, s = ""; extra_tokens[i] = strdup(s); if (extra_tokens[i] == NULL) { - va_end(ap); free_extra_tokens(extra_tokens); return heim_enomem(context); } @@ -667,8 +658,7 @@ heim_expand_path_tokensv(heim_context context, if (*ppath_out) free(*ppath_out); *ppath_out = NULL; - if (context) - heim_set_error_message(context, EINVAL, "variable missing }"); + heim_set_error_message(context, EINVAL, "variable missing }"); return EINVAL; } diff --git a/third_party/heimdal/lib/base/heimbase-svc.h b/third_party/heimdal/lib/base/heimbase-svc.h index 1f0abd622e50..083917fb806a 100644 --- a/third_party/heimdal/lib/base/heimbase-svc.h +++ b/third_party/heimdal/lib/base/heimbase-svc.h @@ -36,6 +36,8 @@ #ifndef HEIMBASE_SVC_H #define HEIMBASE_SVC_H 1 +#include + /* * This file is meant to be included in services, which can * @@ -68,7 +70,9 @@ const char *e_text; \ char *e_text_buf; \ heim_string_t reason; \ - heim_array_t kv; \ - int32_t ret + /* auditing key/value store */ \ + heim_dict_t kv; \ + heim_dict_t attributes; \ + int32_t error_code #endif /* HEIMBASE_SVC_H */ diff --git a/third_party/heimdal/lib/base/heimbase.c b/third_party/heimdal/lib/base/heimbase.c index 8aacdb9187d2..1e6805a25e7f 100644 --- a/third_party/heimdal/lib/base/heimbase.c +++ b/third_party/heimdal/lib/base/heimbase.c @@ -53,7 +53,7 @@ struct heim_base_mem { HEIM_TAILQ_ENTRY(heim_base) autorel; heim_auto_release_t autorelpool; const char *name; - void (*dealloc)(void *); + void (HEIM_CALLCONV *dealloc)(void *); uintptr_t isaextra[1]; }; @@ -83,10 +83,10 @@ struct heim_auto_release { * @return the same object as passed in */ -void * -heim_retain(void *ptr) +heim_object_t +heim_retain(heim_object_t ptr) { - struct heim_base *p = NULL; + struct heim_base *p; if (ptr == NULL || heim_base_is_tagged(ptr)) return ptr; @@ -111,7 +111,7 @@ void heim_release(void *ptr) { heim_base_atomic_integer_type old; - struct heim_base *p = NULL; + struct heim_base *p; if (ptr == NULL || heim_base_is_tagged(ptr)) return; @@ -214,13 +214,13 @@ heim_get_tid(heim_object_t ptr) * @return a hash value */ -unsigned long +uintptr_t heim_get_hash(heim_object_t ptr) { heim_type_t isa = _heim_get_isa(ptr); if (isa->hash) return isa->hash(ptr); - return (unsigned long)ptr; + return (uintptr_t)ptr; } /** @@ -257,7 +257,7 @@ heim_cmp(heim_object_t a, heim_object_t b) * Private - allocates an memory object */ -static void +static void HEIM_CALLCONV memory_dealloc(void *ptr) { struct heim_base_mem *p = (struct heim_base_mem *)PTR2BASE(ptr); @@ -346,7 +346,7 @@ _heim_alloc_object(heim_type_t type, size_t size) void * _heim_get_isaextra(heim_object_t ptr, size_t idx) { - struct heim_base *p = NULL; + struct heim_base *p; heim_assert(ptr != NULL, "internal error"); p = (struct heim_base *)PTR2BASE(ptr); @@ -585,7 +585,7 @@ autorel_tls(void) } -static void +static void HEIM_CALLCONV autorel_dealloc(void *ptr) { heim_auto_release_t ar = ptr; @@ -614,10 +614,10 @@ autorel_cmp(void *a, void *b) return (a == b); } -static unsigned long +static uintptr_t autorel_hash(void *ptr) { - return (unsigned long)ptr; + return (uintptr_t)ptr; } @@ -671,7 +671,7 @@ heim_auto_release_create(void) heim_object_t heim_auto_release(heim_object_t ptr) { - struct heim_base *p = NULL; + struct heim_base *p; struct ar_tls *tls = autorel_tls(); heim_auto_release_t ar; @@ -763,9 +763,10 @@ heim_path_vget2(heim_object_t ptr, heim_object_t *parent, heim_object_t *key, next_node = heim_dict_get_value(node, path_element); } else if (node_type == HEIM_TID_DB) { next_node = _heim_db_get_value(node, NULL, path_element, NULL); - } else if (node_type == HEIM_TID_ARRAY) { + } else { int idx = -1; + /* node_type == HEIM_TID_ARRAY */ if (heim_get_tid(path_element) == HEIM_TID_NUMBER) idx = heim_number_get_int(path_element); if (idx < 0) { @@ -777,12 +778,6 @@ heim_path_vget2(heim_object_t ptr, heim_object_t *parent, heim_object_t *key, return NULL; } next_node = heim_array_get_value(node, idx); - } else { - if (error) - *error = heim_error_create(EINVAL, - "heim_path_get() node in path " - "not a container type"); - return NULL; } node = next_node; } diff --git a/third_party/heimdal/lib/base/heimbase.h b/third_party/heimdal/lib/base/heimbase.h index c0c94e2649b2..3706fc8710d2 100644 --- a/third_party/heimdal/lib/base/heimbase.h +++ b/third_party/heimdal/lib/base/heimbase.h @@ -168,12 +168,12 @@ typedef long heim_base_once_t; /* XXX arch dependant */ #endif -void * heim_retain(heim_object_t); +heim_object_t heim_retain(heim_object_t); void heim_release(heim_object_t); void heim_show(heim_object_t); -typedef void (*heim_type_dealloc)(void *); +typedef void (HEIM_CALLCONV *heim_type_dealloc)(void *); void * heim_alloc(size_t size, const char *name, heim_type_dealloc dealloc); @@ -184,7 +184,7 @@ heim_get_tid(heim_object_t object); int heim_cmp(heim_object_t a, heim_object_t b); -unsigned long +uintptr_t heim_get_hash(heim_object_t ptr); void @@ -436,9 +436,10 @@ void heim_db_iterate(heim_db_t, heim_string_t, typedef struct heim_number_data *heim_number_t; -heim_number_t heim_number_create(int); +heim_number_t heim_number_create(int64_t); heim_tid_t heim_number_get_type_id(void); int heim_number_get_int(heim_number_t); +int64_t heim_number_get_long(heim_number_t); /* * diff --git a/third_party/heimdal/lib/base/heimbasepriv.h b/third_party/heimdal/lib/base/heimbasepriv.h index 8f8fad0fc8c3..b9f63e56b6a1 100644 --- a/third_party/heimdal/lib/base/heimbasepriv.h +++ b/third_party/heimdal/lib/base/heimbasepriv.h @@ -42,7 +42,7 @@ typedef void (*heim_type_init)(void *); typedef heim_object_t (*heim_type_copy)(void *); typedef int (*heim_type_cmp)(void *, void *); -typedef unsigned long (*heim_type_hash)(void *); +typedef uintptr_t (*heim_type_hash)(void *); typedef heim_string_t (*heim_type_description)(void *); typedef struct heim_type_data *heim_type_t; @@ -65,6 +65,7 @@ enum { HEIM_TID_DATA = 134, HEIM_TID_DB = 135, HEIM_TID_PA_AUTH_MECH = 136, + HEIM_TID_PAC = 137, HEIM_TID_USER = 255 }; diff --git a/third_party/heimdal/lib/base/log.c b/third_party/heimdal/lib/base/log.c index 904d0c3ba124..818ac8398d53 100644 --- a/third_party/heimdal/lib/base/log.c +++ b/third_party/heimdal/lib/base/log.c @@ -40,6 +40,7 @@ #include #include #include +#include struct heim_log_facility_internal { int min; @@ -204,10 +205,13 @@ open_syslog(heim_context context, heim_log_facility *facility, int min, int max, const char *sev, const char *fac) { - struct _heimdal_syslog_data *sd = malloc(sizeof(*sd)); + struct _heimdal_syslog_data *sd; + heim_error_code ret; int i; - if (sd == NULL) + if (facility == NULL) + return EINVAL; + if ((sd = calloc(1, sizeof(*sd))) == NULL) return heim_enomem(context); i = find_value(sev, syslogvals); if (i == -1) @@ -218,8 +222,11 @@ open_syslog(heim_context context, i = LOG_AUTH; sd->priority |= i; roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i); - return heim_addlog_func(context, facility, min, max, - log_syslog, close_syslog, sd); + ret = heim_addlog_func(context, facility, min, max, log_syslog, + close_syslog, sd); + if (ret) + free(sd); + return ret; } struct file_data { @@ -247,7 +254,7 @@ log_file(heim_context context, const char *timestr, const char *msg, void *data) size_t i = 0; size_t j; - if (logf == NULL || (f->disp & FILEDISP_REOPEN)) { + if (f->filename && (logf == NULL || (f->disp & FILEDISP_REOPEN))) { int flags = O_WRONLY|O_APPEND; int fd; @@ -338,9 +345,9 @@ open_file(heim_context context, heim_log_facility *fac, int min, int max, if (ret) { free(fd->filename); free(fd); - } - if (disp & FILEDISP_KEEPOPEN) + } else if (disp & FILEDISP_KEEPOPEN) { log_file(context, NULL, NULL, fd); + } return ret; } @@ -384,7 +391,7 @@ heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig) p++; } if (strcmp(p, "STDERR") == 0) { - ret = open_file(context, f, min, max, NULL, NULL, stderr, + ret = open_file(context, f, min, max, NULL, "a", stderr, FILEDISP_KEEPOPEN, 0); } else if (strcmp(p, "CONSOLE") == 0) { /* XXX WIN32 */ @@ -608,10 +615,7 @@ __attribute__ ((__format__ (__printf__, 3, 0))) heim_error_code heim_have_debug(heim_context context, int level) { - heim_log_facility *fac; - - return (context != NULL && - (fac = heim_get_debug_dest(context)) != NULL); + return (context != NULL && heim_get_debug_dest(context) != NULL); } heim_error_code @@ -655,32 +659,34 @@ heim_add_debug_dest(heim_context context, const char *program, return 0; } -static heim_string_t +struct heim_audit_kv_tuple { + heim_string_t key; + heim_object_t value; +}; + +static struct heim_audit_kv_tuple zero_tuple; + +static struct heim_audit_kv_tuple fmtkv(int flags, const char *k, const char *fmt, va_list ap) __attribute__ ((__format__ (__printf__, 3, 0))) { - heim_string_t str; size_t i; ssize_t j; - char *buf1; - char *buf2; - char *buf3; - int ret = vasprintf(&buf1, fmt, ap); - if (ret < 0 || !buf1) - return NULL;; - - j = asprintf(&buf2, "%s=%s", k, buf1); - free(buf1); - if (j < 0 || !buf2) - return NULL;; + struct heim_audit_kv_tuple kv; + char *value; + char *value_vis; + + j = vasprintf(&value, fmt, ap); + if (j < 0 || value == NULL) + return zero_tuple; /* We optionally eat the whitespace. */ if (flags & HEIM_SVC_AUDIT_EATWHITE) { - for (i=0, j=0; buf2[i]; i++) - if (buf2[i] != ' ' && buf2[i] != '\t') - buf2[j++] = buf2[i]; - buf2[j] = '\0'; + for (i=0, j=0; value[i]; i++) + if (value[i] != ' ' && value[i] != '\t') + value[j++] = value[i]; + value[j] = '\0'; } if (flags & (HEIM_SVC_AUDIT_VIS | HEIM_SVC_AUDIT_VISLAST)) { @@ -688,48 +694,52 @@ fmtkv(int flags, const char *k, const char *fmt, va_list ap) if (flags & HEIM_SVC_AUDIT_VIS) vis_flags |= VIS_WHITE; - buf3 = malloc((j + 1) * 4 + 1); - if (buf3) - strvisx(buf3, buf2, j, vis_flags); - free(buf2); - if (buf3 == NULL) - return NULL; + value_vis = malloc((j + 1) * 4 + 1); + if (value_vis) + strvisx(value_vis, value, j, vis_flags); + free(value); + if (value_vis == NULL) + return zero_tuple; } else - buf3 = buf2; + value_vis = value; - str = heim_string_create(buf3); - free(buf3); - return str; + if (k) + kv.key = heim_string_create(k); + else + kv.key = NULL; + kv.value = heim_string_ref_create(value_vis, free); + + return kv; } void heim_audit_vaddreason(heim_svc_req_desc r, const char *fmt, va_list ap) __attribute__ ((__format__ (__printf__, 2, 0))) { - heim_string_t str; + struct heim_audit_kv_tuple kv; - str = fmtkv(HEIM_SVC_AUDIT_VISLAST, "reason", fmt, ap); - if (!str) { + kv = fmtkv(HEIM_SVC_AUDIT_VISLAST, NULL, fmt, ap); + if (kv.value == NULL) { heim_log(r->hcontext, r->logf, 1, "heim_audit_vaddreason: " "failed to add reason (out of memory)"); return; } heim_log(r->hcontext, r->logf, 7, "heim_audit_vaddreason(): " - "adding reason %s", heim_string_get_utf8(str)); + "adding reason %s", heim_string_get_utf8(kv.value)); if (r->reason) { heim_string_t str2; str2 = heim_string_create_with_format("%s: %s", - heim_string_get_utf8(str), + heim_string_get_utf8(kv.value), heim_string_get_utf8(r->reason)); if (str2) { - heim_release(str); - str = str2; + heim_release(kv.value); + kv.value = str2; } } heim_release(r->reason); - r->reason = str; + r->reason = kv.value; } void @@ -743,10 +753,37 @@ heim_audit_addreason(heim_svc_req_desc r, const char *fmt, ...) va_end(ap); } +size_t +addkv(heim_svc_req_desc r, heim_object_t key, heim_object_t value) +{ + size_t index; + heim_object_t obj; + + obj = heim_dict_get_value(r->kv, key); + if (obj) { + if (heim_get_tid(obj) == HEIM_TID_ARRAY) { + index = heim_array_get_length(obj); + heim_array_append_value(obj, value); + } else { + heim_array_t array = heim_array_create(); + + index = 1; + heim_array_append_value(array, obj); + heim_array_append_value(array, value); + heim_dict_set_value(r->kv, key, array); + heim_release(array); /* retained by r->kv */ + } + } else { + index = 0; + heim_dict_set_value(r->kv, key, value); + } + + return index; +} + /* - * append_token adds a token which is optionally a kv-pair and it - * also optionally eats the whitespace. If k == NULL, then it's - * not a kv-pair. + * add a key-value token. if the key already exists, the value is + * promoted to an array of values. */ void @@ -754,19 +791,26 @@ heim_audit_vaddkv(heim_svc_req_desc r, int flags, const char *k, const char *fmt, va_list ap) __attribute__ ((__format__ (__printf__, 4, 0))) { - heim_string_t str; + struct heim_audit_kv_tuple kv; + size_t index; - str = fmtkv(flags, k, fmt, ap); - if (!str) { + kv = fmtkv(flags, k, fmt, ap); + if (kv.key == NULL || kv.value == NULL) { heim_log(r->hcontext, r->logf, 1, "heim_audit_vaddkv: " "failed to add kv pair (out of memory)"); + heim_release(kv.key); + heim_release(kv.value); return; } + index = addkv(r, kv.key, kv.value); + heim_log(r->hcontext, r->logf, 7, "heim_audit_vaddkv(): " - "adding kv pair %s", heim_string_get_utf8(str)); - heim_array_append_value(r->kv, str); - heim_release(str); + "kv pair[%zu] %s=%s", index, + heim_string_get_utf8(kv.key), heim_string_get_utf8(kv.value)); + + heim_release(kv.key); + heim_release(kv.value); } void @@ -808,19 +852,197 @@ heim_audit_addkv_timediff(heim_svc_req_desc r, const char *k, heim_audit_addkv(r, 0, k, "%s%ld.%06d", sign, sec, usec); } +void +heim_audit_setkv_bool(heim_svc_req_desc r, const char *k, int v) +{ + heim_string_t key = heim_string_create(k); + heim_number_t value; + + if (key == NULL) + return; + + heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_bool(): " + "setting kv pair %s=%s", k, v ? "true" : "false"); + + value = heim_bool_create(v); + heim_dict_set_value(r->kv, key, value); + heim_release(key); + heim_release(value); +} + +void +heim_audit_addkv_number(heim_svc_req_desc r, const char *k, int64_t v) +{ + heim_string_t key = heim_string_create(k); + heim_number_t value; + + if (key == NULL) + return; + + heim_log(r->hcontext, r->logf, 7, "heim_audit_addkv_number(): " + "adding kv pair %s=%lld", k, (long long)v); + + value = heim_number_create(v); + addkv(r, key, value); + heim_release(key); + heim_release(value); +} + +void +heim_audit_setkv_number(heim_svc_req_desc r, const char *k, int64_t v) +{ + heim_string_t key = heim_string_create(k); + heim_number_t value; + + if (key == NULL) + return; + + heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_number(): " + "setting kv pair %s=%lld", k, (long long)v); + + value = heim_number_create(v); + heim_dict_set_value(r->kv, key, value); + heim_release(key); + heim_release(value); +} + +void +heim_audit_addkv_object(heim_svc_req_desc r, const char *k, heim_object_t value) +{ + heim_string_t key = heim_string_create(k); + heim_string_t descr; + + if (key == NULL) + return; + + descr = heim_json_copy_serialize(value, HEIM_JSON_F_NO_DATA_DICT, NULL); + heim_log(r->hcontext, r->logf, 7, "heim_audit_addkv_object(): " + "adding kv pair %s=%s", + k, descr ? heim_string_get_utf8(descr) : ""); + addkv(r, key, value); + heim_release(key); + heim_release(descr); +} + +void +heim_audit_setkv_object(heim_svc_req_desc r, const char *k, heim_object_t value) +{ + heim_string_t key = heim_string_create(k); + heim_string_t descr; + + if (key == NULL) + return; + + descr = heim_json_copy_serialize(value, HEIM_JSON_F_NO_DATA_DICT, NULL); + heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_object(): " + "setting kv pair %s=%s", + k, descr ? heim_string_get_utf8(descr) : ""); + heim_dict_set_value(r->kv, key, value); + heim_release(key); + heim_release(descr); +} + +heim_object_t +heim_audit_getkv(heim_svc_req_desc r, const char *k) +{ + heim_string_t key; + heim_object_t value; + + key = heim_string_create(k); + if (key == NULL) + return NULL; + + value = heim_dict_get_value(r->kv, key); + heim_release(key); + return value; +} + +struct heim_audit_kv_buf { + char buf[1024]; + size_t pos; + heim_object_t iter; +}; + +static void +audit_trail_iterator(heim_object_t key, heim_object_t value, void *arg); + +static void +audit_trail_iterator_array(heim_object_t value, void *arg, int *stop) +{ + struct heim_audit_kv_buf *kvb = arg; + + audit_trail_iterator(kvb->iter, value, kvb); +} + +static void +audit_trail_iterator(heim_object_t key, heim_object_t value, void *arg) +{ + struct heim_audit_kv_buf *kvb = arg; + char num[32]; + const char *k = heim_string_get_utf8(key), *v = NULL; + char *b64 = NULL; + + if (k == NULL || *k == '#') /* # keys are hidden */ + return; + + switch (heim_get_tid(value)) { + case HEIM_TID_STRING: + v = heim_string_get_utf8(value); + break; + case HEIM_TID_NUMBER: + snprintf(num, sizeof(num), "%lld", (long long)heim_number_get_long(value)); + v = num; + break; + case HEIM_TID_NULL: + v = "null"; + break; + case HEIM_TID_BOOL: + v = heim_bool_val(value) ? "true" : "false"; + break; + case HEIM_TID_ARRAY: + if (kvb->iter) + break; /* arrays cannot be nested */ + + kvb->iter = key; + heim_array_iterate_f(value, kvb, audit_trail_iterator_array); + kvb->iter = NULL; + break; + case HEIM_TID_DATA: { + const heim_octet_string *data = heim_data_get_data(value); + if (rk_base64_encode(data->data, data->length, &b64) >= 0) + v = b64; + break; + } + default: + break; + } + + if (v == NULL) + return; + + if (kvb->pos < sizeof(kvb->buf) - 1) + kvb->buf[kvb->pos++] = ' '; + for (; *k && kvb->pos < sizeof(kvb->buf) - 1; kvb->pos++) + kvb->buf[kvb->pos] = *k++; + if (kvb->pos < sizeof(kvb->buf) - 1) + kvb->buf[kvb->pos++] = '='; + for (; *v && kvb->pos < sizeof(kvb->buf) - 1; kvb->pos++) + kvb->buf[kvb->pos] = *v++; + + free(b64); +} + void heim_audit_trail(heim_svc_req_desc r, heim_error_code ret, const char *retname) { const char *retval; - char kvbuf[1024]; + struct heim_audit_kv_buf kvb; char retvalbuf[30]; /* Enough for UNKNOWN-%d */ - size_t nelem; - size_t i, j; #define CASE(x) case x : retval = #x; break if (retname) { retval = retname; - } else switch (ret ? ret : r->ret) { + } else switch (ret ? ret : r->error_code) { CASE(ENOMEM); CASE(ENOENT); CASE(EACCES); @@ -838,26 +1060,15 @@ heim_audit_trail(heim_svc_req_desc r, heim_error_code ret, const char *retname) if (r->e_text && r->kv) heim_audit_addkv(r, HEIM_SVC_AUDIT_VIS, "e-text", "%s", r->e_text); - nelem = r->kv ? heim_array_get_length(r->kv) : 0; - for (i=0, j=0; i < nelem; i++) { - heim_string_t s; - const char *kvpair; - - /* We know these are strings... */ - s = heim_array_get_value(r->kv, i); - kvpair = heim_string_get_utf8(s); - - if (j < sizeof(kvbuf) - 1) - kvbuf[j++] = ' '; - for (; *kvpair && j < sizeof(kvbuf) - 1; j++) - kvbuf[j] = *kvpair++; - } - kvbuf[j] = '\0'; + memset(&kvb, 0, sizeof(kvb)); + if (r->kv) + heim_dict_iterate_f(r->kv, &kvb, audit_trail_iterator); + kvb.buf[kvb.pos] = '\0'; heim_log(r->hcontext, r->logf, 3, "%s %s %s %s %s%s%s%s", r->reqtype, retval, r->from, r->cname ? r->cname : "", r->sname ? r->sname : "", - kvbuf, r->reason ? " " : "", + kvb.buf, r->reason ? " reason=" : "", r->reason ? heim_string_get_utf8(r->reason) : ""); } diff --git a/third_party/heimdal/lib/base/number.c b/third_party/heimdal/lib/base/number.c index c259f69971d0..8833c8b15233 100644 --- a/third_party/heimdal/lib/base/number.c +++ b/third_party/heimdal/lib/base/number.c @@ -35,7 +35,7 @@ #include "baselocl.h" -static void +static void HEIM_CALLCONV number_dealloc(void *ptr) { } @@ -58,12 +58,12 @@ number_cmp(void *a, void *b) return na - nb; } -static unsigned long +static uintptr_t number_hash(void *ptr) { if (heim_base_is_tagged_object(ptr)) return heim_base_tagged_object_value(ptr); - return (unsigned long)*(int *)ptr; + return (uintptr_t)*(int64_t *)ptr; } struct heim_type_data _heim_number_object = { @@ -86,16 +86,16 @@ struct heim_type_data _heim_number_object = { */ heim_number_t -heim_number_create(int number) +heim_number_create(int64_t number) { heim_number_t n; if (number < 0xffffff && number >= 0) return heim_base_make_tagged_object(number, HEIM_TID_NUMBER); - n = _heim_alloc_object(&_heim_number_object, sizeof(int)); + n = _heim_alloc_object(&_heim_number_object, sizeof(int64_t)); if (n) - *((int *)n) = number; + *((int64_t *)n) = number; return n; } @@ -124,5 +124,13 @@ heim_number_get_int(heim_number_t number) { if (heim_base_is_tagged_object(number)) return heim_base_tagged_object_value(number); - return *(int *)number; + return (int)(*(int64_t *)number); +} + +int64_t +heim_number_get_long(heim_number_t number) +{ + if (heim_base_is_tagged_object(number)) + return heim_base_tagged_object_value(number); + return *(int64_t *)number; } diff --git a/third_party/heimdal/lib/base/plugin.c b/third_party/heimdal/lib/base/plugin.c index df225a939c25..631a3386c831 100644 --- a/third_party/heimdal/lib/base/plugin.c +++ b/third_party/heimdal/lib/base/plugin.c @@ -112,7 +112,7 @@ struct heim_dso { void *dsohandle; }; -static void +static void HEIM_CALLCONV dso_dealloc(void *ptr) { struct heim_dso *p = ptr; @@ -156,7 +156,7 @@ struct heim_plugin { void *ctx; }; -static void +static void HEIM_CALLCONV plugin_free(void *ptr) { struct heim_plugin *pl = ptr; @@ -590,34 +590,37 @@ add_dso_plugins_load_fn(heim_context context, heim_error_code ret; heim_array_t plugins; heim_plugin_load_t load_fn; - char *sym; + char *sym = NULL; size_t i; heim_get_instance_func_t get_instance; size_t n_ftables; heim_plugin_common_ftable_cp *ftables; - if (asprintf(&sym, "%s_plugin_load", caller->name) == -1) + if (asprintf(&sym, "%s_plugin_load", caller->name) == -1 || sym == NULL) return NULL; /* suppress error here because we may be looking for a different plugin type */ load_fn = (heim_plugin_load_t)dlsym(dsohandle, sym); - free(sym); if (load_fn == NULL) { heim_debug(context, 15, "Symbol %s not found in %s", sym, dsopath); + free(sym); return NULL; } ret = load_fn(pcontext, &get_instance, &n_ftables, &ftables); if (ret) { heim_warn(context, ret, "plugin %s failed to load", dsopath); + free(sym); /* fallback to loading structure directly */ return add_dso_plugin_struct(context, pcontext, dsopath, dsohandle, caller->name); } - if (!validate_plugin_deps(context, caller, dsopath, get_instance)) + if (!validate_plugin_deps(context, caller, dsopath, get_instance)) { + free(sym); return NULL; + } plugins = heim_array_create(); @@ -639,6 +642,7 @@ add_dso_plugins_load_fn(heim_context context, } heim_debug(context, 15, "DSO %s loaded (%s)", dsopath, sym); + free(sym); return plugins; } #endif /* HAVE_DLOPEN */ diff --git a/third_party/heimdal/lib/base/string.c b/third_party/heimdal/lib/base/string.c index 5384998080a5..f942447163db 100644 --- a/third_party/heimdal/lib/base/string.c +++ b/third_party/heimdal/lib/base/string.c @@ -36,7 +36,7 @@ #include "baselocl.h" #include -static void +static void HEIM_CALLCONV string_dealloc(void *ptr) { heim_string_t s = ptr; @@ -73,11 +73,11 @@ string_cmp(void *a, void *b) return strcmp(a, b); } -static unsigned long +static uintptr_t string_hash(void *ptr) { const char *s = ptr; - unsigned long n; + uintptr_t n; for (n = 0; *s; ++s) n += *s; diff --git a/third_party/heimdal/lib/base/test_base.c b/third_party/heimdal/lib/base/test_base.c index fba675cf488e..be6c860e26b9 100644 --- a/third_party/heimdal/lib/base/test_base.c +++ b/third_party/heimdal/lib/base/test_base.c @@ -64,7 +64,7 @@ #include "baselocl.h" -static void +static void HEIM_CALLCONV memory_free(heim_object_t obj) { } @@ -238,8 +238,8 @@ test_json(void) "{ \"k1\" : \"s1\", \"k2\" : \"s2\" }", "{ \"k1\" : [\"s1\", \"s2\", \"s3\"], \"k2\" : \"s3\" }", "{ \"k1\" : {\"k2\":\"s1\",\"k3\":\"s2\",\"k4\":\"s3\"}, \"k5\" : \"s4\" }", - "[ \"v1\", \"v2\", [\"v3\",\"v4\",[\"v 5\",\" v 7 \"]], -123456789, " - "null, true, false, 123456789, \"\"]", + ("[ \"v1\", \"v2\", [\"v3\",\"v4\",[\"v 5\",\" v 7 \"]], -123456789, " + "null, true, false, 123456789, \"\"]"), " -1" }; char *s; diff --git a/third_party/heimdal/lib/base/version-script.map b/third_party/heimdal/lib/base/version-script.map index 0cd0c8444cb7..928e86199955 100644 --- a/third_party/heimdal/lib/base/version-script.map +++ b/third_party/heimdal/lib/base/version-script.map @@ -29,8 +29,14 @@ HEIMDAL_BASE_1.0 { heim_array_iterate_reverse_f; heim_array_set_value; heim_audit_addkv; + heim_audit_addkv_number; + heim_audit_addkv_object; heim_audit_addkv_timediff; + heim_audit_setkv_bool; + heim_audit_setkv_number; + heim_audit_setkv_object; heim_audit_addreason; + heim_audit_getkv; heim_audit_trail; heim_audit_vaddkv; heim_audit_vaddreason; @@ -147,6 +153,7 @@ HEIMDAL_BASE_1.0 { heim_null_create; heim_number_create; heim_number_get_int; + heim_number_get_long; heim_number_get_type_id; heim_openlog; heim_path_copy; diff --git a/third_party/heimdal/lib/com_err/Makefile.am b/third_party/heimdal/lib/com_err/Makefile.am index 8c027c74da9f..14e8e66fcdc6 100644 --- a/third_party/heimdal/lib/com_err/Makefile.am +++ b/third_party/heimdal/lib/com_err/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -YFLAGS = -d +YFLAGS = -d -o parse.c LFLAGS = @FLEXNOUNPUTARGS@ lib_LTLIBRARIES = libcom_err.la diff --git a/third_party/heimdal/lib/gss_preauth/pa_client.c b/third_party/heimdal/lib/gss_preauth/pa_client.c index 1159e63c2a46..de2d7b5cbe6d 100644 --- a/third_party/heimdal/lib/gss_preauth/pa_client.c +++ b/third_party/heimdal/lib/gss_preauth/pa_client.c @@ -95,9 +95,10 @@ pa_gss_step(krb5_context context, gss_name_t target_name = GSS_C_NO_NAME; OM_uint32 req_flags = GSS_C_MUTUAL_FLAG; OM_uint32 ret_flags; - struct gss_channel_bindings_struct cb = { 0 }; + struct gss_channel_bindings_struct cb; gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER; + memset(&cb, 0, sizeof(cb)); krb5_data_zero(out); if (flags.request_anonymous) diff --git a/third_party/heimdal/lib/gss_preauth/pa_common.c b/third_party/heimdal/lib/gss_preauth/pa_common.c index c2287ca707a7..00efde72d662 100644 --- a/third_party/heimdal/lib/gss_preauth/pa_common.c +++ b/third_party/heimdal/lib/gss_preauth/pa_common.c @@ -64,11 +64,6 @@ _krb5_gss_map_error(OM_uint32 major, OM_uint32 minor) ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; break; case GSS_S_FAILURE: - if (minor == (OM_uint32)KRB5KRB_AP_ERR_BAD_INTEGRITY || - minor == (OM_uint32)HNTLM_ERR_AUTH) { - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - break; - } default: ret = KRB5KDC_ERR_PREAUTH_FAILED; break; diff --git a/third_party/heimdal/lib/gssapi/Makefile.am b/third_party/heimdal/lib/gssapi/Makefile.am index 744232e2e35b..a69ebffb04ec 100644 --- a/third_party/heimdal/lib/gssapi/Makefile.am +++ b/third_party/heimdal/lib/gssapi/Makefile.am @@ -2,9 +2,12 @@ include $(top_srcdir)/Makefile.am.common +WFLAGS += $(WFLAGS_ENUM_CONV) + AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS += \ + -I$(top_srcdir)/lib \ -I$(srcdir)/../krb5 \ -I$(srcdir) \ -I$(srcdir)/gssapi \ @@ -59,6 +62,7 @@ krb5src = \ krb5/inquire_mechs_for_name.c \ krb5/inquire_names_for_mech.c \ krb5/inquire_sec_context_by_oid.c \ + krb5/name_attrs.c \ krb5/pname_to_uid.c \ krb5/process_context_token.c \ krb5/prf.c \ @@ -249,6 +253,7 @@ sanonsrc = \ sanon/process_context_token.c \ sanon/release_cred.c \ sanon/release_name.c \ + sanon/sanon_locl.h \ sanon/sanon-private.h dist_libgssapi_la_SOURCES = \ @@ -302,19 +307,20 @@ nobase_include_HEADERS = \ gssapidir = $(includedir)/gssapi nodist_gssapi_HEADERS = gkrb5_err.h negoex_err.h -gssapi_files = asn1_GSSAPIContextToken.x +gssapi_files = \ + asn1_GSSAPIContextToken.c spnego_files = \ - asn1_ContextFlags.x \ - asn1_MechType.x \ - asn1_MechTypeList.x \ - asn1_NegotiationToken.x \ - asn1_NegotiationToken2.x \ - asn1_NegHints.x \ - asn1_NegTokenInit.x \ - asn1_NegTokenInit2.x \ - asn1_NegTokenResp.x \ - asn1_NegStateEnum.x + asn1_ContextFlags.c \ + asn1_MechType.c \ + asn1_MechTypeList.c \ + asn1_NegHints.c \ + asn1_NegStateEnum.c \ + asn1_NegTokenInit.c \ + asn1_NegTokenInit2.c \ + asn1_NegTokenResp.c \ + asn1_NegotiationToken.c \ + asn1_NegotiationToken2.c BUILTHEADERS = \ $(srcdir)/krb5/gsskrb5-private.h \ @@ -327,7 +333,7 @@ $(test_context_OBJECTS): $(BUILTHEADERS) $(libgssapi_la_OBJECTS): $(srcdir)/version-script.map -BUILT_SOURCES = $(spnego_files:.x=.c) $(gssapi_files:.x=.c) +BUILT_SOURCES = $(spnego_files) $(gssapi_files) $(libgssapi_la_OBJECTS): gkrb5_err.h negoex_err.h gkrb5_err.h: $(srcdir)/krb5/gkrb5_err.et @@ -337,16 +343,27 @@ CLEANFILES = $(BUILT_SOURCES) \ gkrb5_err.[ch] negoex_err.[ch] \ $(spnego_files) spnego_asn1*.h* spnego_asn1_files spnego_asn1-template.[cx] \ $(gssapi_files) gssapi_asn1*.h* gssapi_asn1_files gssapi_asn1-template.[cx] \ - gss-commands.h gss-commands.c + gss-commands.h gss-commands.c \ + gssapi_asn1.json gssapi_asn1_oids.c gssapi_asn1_syms.c \ + spnego_asn1.json spnego_asn1_oids.c spnego_asn1_syms.c + +$(spnego_files) spnego_asn1.h spnego_asn1-priv.h: spnego_asn1_files + for genfile in '$(spnego_files)'; do \ + $(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $${genfile}; \ + done -$(spnego_files) spnego_asn1.hx spnego_asn1-priv.hx: spnego_asn1_files -$(gssapi_files) gssapi_asn1.hx gssapi_asn1-priv.hx: gssapi_asn1_files +$(gssapi_files) gssapi_asn1.h gssapi_asn1-priv.h: gssapi_asn1_files + for genfile in '$(gssapi_files)'; do \ + $(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $${genfile}; \ + done spnego_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/spnego/spnego.asn1 $(srcdir)/spnego/spnego.opt $(ASN1_COMPILE) --option-file=$(srcdir)/spnego/spnego.opt $(srcdir)/spnego/spnego.asn1 spnego_asn1 + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $$(cat spnego_asn1_files) gssapi_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/mech/gssapi.asn1 $(ASN1_COMPILE) $(srcdir)/mech/gssapi.asn1 gssapi_asn1 + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $$(cat gssapi_asn1_files) $(srcdir)/krb5/gsskrb5-private.h: cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p krb5/gsskrb5-private.h $(krb5src) || rm -f krb5/gsskrb5-private.h @@ -358,7 +375,7 @@ $(srcdir)/sanon/sanon-private.h: cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p sanon/sanon-private.h $(sanonsrc) || rm -f sanon/sanon-private.h TESTS = test_oid test_names test_cfx -# test_sequence +# test_sequence test_cfx_SOURCES = krb5/test_cfx.c @@ -381,6 +398,9 @@ LDADD = libgssapi.la \ $(top_builddir)/lib/krb5/libkrb5.la \ $(LIB_roken) +test_names_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la +test_context_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la $(top_builddir)/lib/wind/libwind.la + # gss dist_gsstool_SOURCES = gsstool.c @@ -441,9 +461,8 @@ $(srcdir)/gssapi/gssapi_oid.h $(srcdir)/mech/gss_oid.c: # NegoEx test mechanism, uses decode_GSSAPIContextToken # -test_negoex_mech_la_SOURCES = test_negoex_mech.c $(gssapi_files:.x=.c) +test_negoex_mech_la_SOURCES = test_negoex_mech.c $(gssapi_files) test_negoex_mech_la_LDFLAGS = -module test_negoex_mech_la_LIBADD = \ $(top_builddir)/lib/asn1/libasn1.la \ libgssapi.la - diff --git a/third_party/heimdal/lib/gssapi/NTMakefile b/third_party/heimdal/lib/gssapi/NTMakefile index 8d5784f17f11..ffba9d52be05 100644 --- a/third_party/heimdal/lib/gssapi/NTMakefile +++ b/third_party/heimdal/lib/gssapi/NTMakefile @@ -33,6 +33,8 @@ RELDIR=lib\gssapi +intcflags=-DASN1_LIB + !include ../../windows/NTMakefile.w32 krb5src = \ @@ -77,6 +79,7 @@ krb5src = \ krb5/inquire_mechs_for_name.c \ krb5/inquire_names_for_mech.c \ krb5/inquire_sec_context_by_oid.c \ + krb5/name_attrs.c \ krb5/pname_to_uid.c \ krb5/process_context_token.c \ krb5/prf.c \ @@ -274,22 +277,14 @@ $(OBJ)\spnego\spnego-private.h: $(spnegosrc) $(OBJ)\sanon\sanon-private.h: $(sanonsrc) $(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(sanonsrc) -gssapi_files = $(OBJ)\gssapi\asn1_gssapi_asn1.x - -spnego_files = $(OBJ)\spnego\asn1_spnego_asn1.x - -$(gssapi_files:.x=.c): $$(@R).x - -$(spnego_files:.x=.c): $$(@R).x - -$(gssapi_files) $(OBJ)\gssapi\gssapi_asn1.hx $(OBJ)\gssapi\gssapi_asn1-priv.hx: \ +$(OBJ)\gssapi\asn1_gssapi_asn1.c $(OBJ)\gssapi\gssapi_asn1.h $(OBJ)\gssapi\gssapi_asn1-priv.h: \ $(BINDIR)\asn1_compile.exe mech\gssapi.asn1 cd $(OBJ)\gssapi $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\mech\gssapi.asn1 gssapi_asn1 \ || ( $(RM) $(OBJ)\gssapi\gssapi_asn1.h ; exit /b 1 ) cd $(SRCDIR) -$(spnego_files) $(OBJ)\spnego\spnego_asn1.hx $(OBJ)\spnego\spnego_asn1-priv.hx: \ +$(OBJ)\spnego\asn1_spnego_asn1.c $(OBJ)\spnego\spnego_asn1.h $(OBJ)\spnego\spnego_asn1-priv.h: \ $(BINDIR)\asn1_compile.exe spnego\spnego.asn1 cd $(OBJ)\spnego $(BINDIR)\asn1_compile --one-code-file --sequence=MechTypeList \ @@ -368,6 +363,7 @@ libgssapi_OBJs = \ $(OBJ)\krb5/inquire_mechs_for_name.obj \ $(OBJ)\krb5/inquire_names_for_mech.obj \ $(OBJ)\krb5/inquire_sec_context_by_oid.obj \ + $(OBJ)\krb5/name_attrs.obj \ $(OBJ)\krb5/pname_to_uid.obj \ $(OBJ)\krb5/process_context_token.obj \ $(OBJ)\krb5/prf.obj \ @@ -537,8 +533,8 @@ libgssapi_OBJs = \ $(OBJ)\sanon/release_name.obj \ $(OBJ)\gkrb5_err.obj \ $(OBJ)\negoex_err.obj \ - $(spnego_files:.x=.obj) \ - $(gssapi_files:.x=.obj) + $(OBJ)\spnego\asn1_spnego_asn1.obj \ + $(OBJ)\gssapi\asn1_gssapi_asn1.obj GCOPTS=-I$(SRCDIR) -I$(OBJ) -Igssapi -DBUILD_GSSAPI_LIB @@ -578,24 +574,12 @@ GCOPTS=-I$(SRCDIR) -I$(OBJ) -Igssapi -DBUILD_GSSAPI_LIB {$(OBJ)}.c{$(OBJ)}.obj:: $(C2OBJ_P) $(GCOPTS) -{$(OBJ)\spnego}.x{$(OBJ)\spnego}.c: - $(CP) $** $@ - -{$(OBJ)\gssapi}.x{$(OBJ)\gssapi}.c: - $(CP) $** $@ - {gssapi}.h{$(INCDIR)\gssapi}.h: $(CP) $** $@ {$(OBJ)}.h{$(INCDIR)\gssapi}.h: $(CP) $** $@ -{$(OBJ)\gssapi}.hx{$(OBJ)\gssapi}.h: - $(CP) $** $@ - -{$(OBJ)\spnego}.hx{$(OBJ)\spnego}.h: - $(CP) $** $@ - LIBGSSAPI_LIBS=\ $(LIBHEIMBASE) \ $(LIBROKEN) \ @@ -690,8 +674,8 @@ $(OBJ)\gss-commands.c $(OBJ)\gss-commands.h: gss-commands.in (generate-obj-macro "libgssapi_OBJs" (concat "\t$(OBJ)\\gkrb5_err.obj \\\n" "\t$(OBJ)\\negoex_err.obj \\\n" - "\t$(spnego_files:.x=.obj) \\\n" - "\t$(gssapi_files:.x=.obj)") + "\t$(OBJ)\\spnego\\asn1_spnego_asn1.obj \\\n" + "\t$(OBJ)\\gssapi\\asn1_gssapi_asn1.obj") "krb5src" "mechsrc" "spnegosrc" "ntlmsrc") !endif @@ -715,7 +699,7 @@ $(OBJ)\test_oid.exe: $(OBJ)\test_oid.obj $(LIBGSSAPI) $(LIBROKEN) $(EXECONLINK) $(EXEPREP_NODIST) -$(OBJ)\test_names.exe: $(OBJ)\test_names.obj $(LIBGSSAPI) $(LIBROKEN) $(LIBVERS) +$(OBJ)\test_names.exe: $(OBJ)\test_names.obj $(LIBGSSAPI) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) $(EXECONLINK) $(EXEPREP_NODIST) diff --git a/third_party/heimdal/lib/gssapi/gss-token.c b/third_party/heimdal/lib/gssapi/gss-token.c index 1ead3e15b32f..844fa4d38206 100644 --- a/third_party/heimdal/lib/gssapi/gss-token.c +++ b/third_party/heimdal/lib/gssapi/gss-token.c @@ -250,7 +250,7 @@ write_and_free_token(gss_buffer_t out, int negotiate) bail: gss_release_buffer(&min, out); - return 0; + return ret; } static int @@ -402,7 +402,7 @@ static int initiate_many(gss_name_t service, int delegate, int negotiate, int memcache, size_t count) { - krb5_error_code kret; + krb5_error_code kret = 0; krb5_context kctx = NULL; krb5_ccache def_cache = NULL; krb5_ccache mem_cache = NULL; @@ -443,7 +443,8 @@ accept_one(gss_name_t service, const char *ccname, int negotiate) gss_OID mech_oid; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_buffer_desc in = GSS_C_EMPTY_BUFFER; - gss_buffer_desc out, dname; + gss_buffer_desc out; + gss_buffer_desc dname = GSS_C_EMPTY_BUFFER; krb5_context kctx = NULL; krb5_ccache ccache = NULL; krb5_error_code kret; @@ -488,6 +489,8 @@ accept_one(gss_name_t service, const char *ccname, int negotiate) if (!nflag) printf("Authenticated: %.*s\n", (int)dname.length, (char *)dname.value); + (void) gss_release_buffer(&min, &dname); + (void) gss_release_name(&min, &client); if (ccname) { #ifdef HAVE_GSS_STORE_CRED_INTO @@ -565,7 +568,7 @@ print_all_mechs(void) for (i=0; i < mech_set->count; i++) printf("%s\n", gss_oid_to_name(&mech_set->elements[i])); - maj = gss_release_oid_set(&min, &mech_set); + (void) gss_release_oid_set(&min, &mech_set); bail: exit(ret); diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi.h index 4214acc0e5f7..726543f5a382 100644 --- a/third_party/heimdal/lib/gssapi/gssapi/gssapi.h +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi.h @@ -233,6 +233,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_EMPTY_BUFFER_SET {0, NULL} #define GSS_C_NO_IOV_BUFFER ((gss_iov_buffer_t)0) #define GSS_C_NO_CRED_STORE ((gss_key_value_set_t)0) @@ -393,6 +394,18 @@ extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_anonymous_oid_desc; extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_export_name_oid_desc; #define GSS_C_NT_EXPORT_NAME (&__gss_c_nt_export_name_oid_desc) +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x06"}, corresponding to an + * object-identifier value of {iso(1) identified-organization(3) dod(6) + * internet(1) security(5) nametypes(6) gss-composite-export(6)}. + * The constant GSS_C_NT_COMPOSITE_EXPORT [RFC6680] should be initialized to + * point to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_composite_export_oid_desc; +#define GSS_C_NT_COMPOSITE_EXPORT (&__gss_c_nt_composite_export_oid_desc) + /* Major status codes */ #define GSS_S_COMPLETE 0 @@ -1240,9 +1253,6 @@ GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_destroy_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle); -GSSAPI_LIB_FUNCTION uintptr_t GSSAPI_CALLCONV -gss_get_instance(const char *libname); - /* * S4UProxy and S4USelf extensions. */ diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h index 74d5109aa19c..818042fa7739 100644 --- a/third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h @@ -218,6 +218,8 @@ gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, OM_uint32 num_enctypes, int32_t *enctypes); +#define GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "urn:ietf:kerberos:nameattr-" + GSSAPI_CPP_END #endif /* GSSAPI_SPNEGO_H_ */ diff --git a/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c index f125573c1372..3f8e2740e212 100644 --- a/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c +++ b/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c @@ -157,39 +157,31 @@ gsskrb5_accept_delegated_token(OM_uint32 *minor_status, krb5_ccache ccache = NULL; krb5_error_code kret; int32_t ac_flags, ret = GSS_S_COMPLETE; + gsskrb5_cred handle; *minor_status = 0; /* XXX Create a new delegated_cred_handle? */ - if (delegated_cred_handle == NULL) { - ret = GSS_S_COMPLETE; - goto out; - } + if (delegated_cred_handle == NULL) + return GSS_S_COMPLETE; *delegated_cred_handle = NULL; kret = krb5_cc_resolve(context, "MEMORY:anonymous", &ccache); - if (kret) { - ctx->flags &= ~GSS_C_DELEG_FLAG; - goto out; + if (kret == 0) + kret = krb5_cc_initialize(context, ccache, ctx->source); + if (kret == 0) { + (void) krb5_auth_con_removeflags(context, + ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_TIME, + &ac_flags); + kret = krb5_rd_cred2(context, + ctx->auth_context, + ccache, + &ctx->fwd_data); + (void) krb5_auth_con_setflags(context, + ctx->auth_context, + ac_flags); } - - kret = krb5_cc_initialize(context, ccache, ctx->source); - if (kret) { - ctx->flags &= ~GSS_C_DELEG_FLAG; - goto out; - } - - krb5_auth_con_removeflags(context, - ctx->auth_context, - KRB5_AUTH_CONTEXT_DO_TIME, - &ac_flags); - kret = krb5_rd_cred2(context, - ctx->auth_context, - ccache, - &ctx->fwd_data); - krb5_auth_con_setflags(context, - ctx->auth_context, - ac_flags); if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; ret = GSS_S_FAILURE; @@ -197,62 +189,54 @@ gsskrb5_accept_delegated_token(OM_uint32 *minor_status, goto out; } - if (delegated_cred_handle) { - gsskrb5_cred handle; + ret = _gsskrb5_krb5_import_cred(minor_status, + &ccache, + NULL, + NULL, + delegated_cred_handle); + if (ret != GSS_S_COMPLETE) + goto out; - ret = _gsskrb5_krb5_import_cred(minor_status, - &ccache, - NULL, - NULL, - delegated_cred_handle); - if (ret != GSS_S_COMPLETE) - goto out; - - handle = (gsskrb5_cred) *delegated_cred_handle; - handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; - - /* - * A root TGT is one of the form krbtgt/REALM@SAME-REALM. - * - * A destination TGT is a root TGT for the same realm as the acceptor - * service's realm. - * - * Normally clients delegate a root TGT for the client's realm. - * - * In some deployments clients may want to delegate destination TGTs as - * a form of constrained delegation: so that the destination service - * cannot use the delegated credential to impersonate the client - * principal to services in its home realm (due to KDC lineage/transit - * checks). In those deployments there may not even be a route back to - * the KDCs of the client's realm, and attempting to use a - * non-destination TGT might even lead to timeouts. - * - * We could simply pretend not to have obtained a credential, except - * that a) we don't (yet) have an app name here for the appdefault we - * need to check, b) the application really wants to be able to log a - * message about the delegated credential being no good. - * - * Thus we leave it to _gsskrb5_store_cred_into2() to decide what to do - * with non-destination TGTs. To do that, it needs the realm of the - * acceptor service, which we record here. - */ - handle->destination_realm = - strdup(krb5_principal_get_realm(context, ctx->target)); - if (handle->destination_realm == NULL) { - _gsskrb5_release_cred(minor_status, delegated_cred_handle); - *minor_status = krb5_enomem(context); - ret = GSS_S_FAILURE; - goto out; - } + handle = (gsskrb5_cred) *delegated_cred_handle; + handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + + /* + * A root TGT is one of the form krbtgt/REALM@SAME-REALM. + * + * A destination TGT is a root TGT for the same realm as the acceptor + * service's realm. + * + * Normally clients delegate a root TGT for the client's realm. + * + * In some deployments clients may want to delegate destination TGTs as + * a form of constrained delegation: so that the destination service + * cannot use the delegated credential to impersonate the client + * principal to services in its home realm (due to KDC lineage/transit + * checks). In those deployments there may not even be a route back to + * the KDCs of the client's realm, and attempting to use a + * non-destination TGT might even lead to timeouts. + * + * We could simply pretend not to have obtained a credential, except + * that a) we don't (yet) have an app name here for the appdefault we + * need to check, b) the application really wants to be able to log a + * message about the delegated credential being no good. + * + * Thus we leave it to _gsskrb5_store_cred_into2() to decide what to do + * with non-destination TGTs. To do that, it needs the realm of the + * acceptor service, which we record here. + */ + handle->destination_realm = + strdup(krb5_principal_get_realm(context, ctx->target)); + if (handle->destination_realm == NULL) { + _gsskrb5_release_cred(minor_status, delegated_cred_handle); + *minor_status = krb5_enomem(context); + ret = GSS_S_FAILURE; + goto out; } out: if (ccache) { - /* Don't destroy the default cred cache */ - if (delegated_cred_handle == NULL) - krb5_cc_close(context, ccache); - else - krb5_cc_destroy(context, ccache); + krb5_cc_close(context, ccache); } return ret; } @@ -478,6 +462,10 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, * lets only send the error token on clock skew, that * limit when send error token for non-MUTUAL. */ + krb5_auth_con_free(context, ctx->auth_context); + krb5_auth_con_free(context, ctx->deleg_auth_context); + ctx->deleg_auth_context = NULL; + ctx->auth_context = NULL; return send_error_token(minor_status, context, kret, server, &indata, output_token); } else if (kret) { diff --git a/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c b/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c index 6b625160668a..211dcaa7f753 100644 --- a/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c +++ b/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c @@ -203,7 +203,8 @@ acquire_cred_with_password(OM_uint32 *minor_status, { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; - krb5_get_init_creds_opt *opt; + krb5_init_creds_context ctx = NULL; + krb5_get_init_creds_opt *opt = NULL; krb5_ccache ccache = NULL; krb5_error_code kret; time_t now; @@ -236,13 +237,19 @@ acquire_cred_with_password(OM_uint32 *minor_status, if (kret) goto end; } - kret = krb5_get_init_creds_opt_alloc(context, &opt); - if (kret) - goto end; - realm = krb5_principal_get_realm(context, handle->principal); - krb5_get_init_creds_opt_set_default_flags(context, "gss_krb5", realm, opt); + kret = krb5_get_init_creds_opt_alloc(context, &opt); + if (kret == 0) { + krb5_get_init_creds_opt_set_default_flags(context, "gss_krb5", realm, + opt); + kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, 0, + opt, &ctx); + } + if (kret == 0) + kret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx); + if (kret == 0) + kret = krb5_init_creds_set_password(context, ctx, password); /* * Get the current time before the AS exchange so we don't @@ -256,21 +263,18 @@ acquire_cred_with_password(OM_uint32 *minor_status, */ krb5_timeofday(context, &now); - kret = krb5_get_init_creds_password(context, &cred, handle->principal, - password, NULL, NULL, 0, NULL, opt); - krb5_get_init_creds_opt_free(context, opt); - if (kret) - goto end; - - kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); - if (kret) - goto end; - - kret = krb5_cc_initialize(context, ccache, cred.client); - if (kret) - goto end; - - kret = krb5_cc_store_cred(context, ccache, &cred); + if (kret == 0) + kret = krb5_init_creds_get(context, ctx); + if (kret == 0) + kret = krb5_init_creds_get_creds(context, ctx, &cred); + if (kret == 0) + kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); + if (kret == 0) + kret = krb5_cc_initialize(context, ccache, cred.client); + if (kret == 0) + kret = krb5_init_creds_store(context, ctx, ccache); + if (kret == 0) + kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) goto end; @@ -284,14 +288,16 @@ acquire_cred_with_password(OM_uint32 *minor_status, handle->ccache = ccache; ccache = NULL; ret = GSS_S_COMPLETE; - kret = 0; end: + krb5_get_init_creds_opt_free(context, opt); + if (ctx) + krb5_init_creds_free(context, ctx); if (ccache != NULL) krb5_cc_destroy(context, ccache); if (cred.client != NULL) krb5_free_cred_contents(context, &cred); - if (ret != GSS_S_COMPLETE && kret != 0) + if (ret != GSS_S_COMPLETE) *minor_status = kret; return (ret); } diff --git a/third_party/heimdal/lib/gssapi/krb5/arcfour.c b/third_party/heimdal/lib/gssapi/krb5/arcfour.c index 9093b7a1d36a..8931b32e1c99 100644 --- a/third_party/heimdal/lib/gssapi/krb5/arcfour.c +++ b/third_party/heimdal/lib/gssapi/krb5/arcfour.c @@ -167,18 +167,20 @@ arcfour_mic_cksum_iov(krb5_context context, continue; } - if (iov[i].buffer.value != NULL) + if (iov[i].buffer.length > 0) { + assert(iov[i].buffer.value != NULL); memcpy(ptr + ofs, iov[i].buffer.value, iov[i].buffer.length); - ofs += iov[i].buffer.length; + ofs += iov[i].buffer.length; + } } if (padding) { memcpy(ptr + ofs, padding->buffer.value, padding->buffer.length); - ofs += padding->buffer.length; + /* ofs += padding->buffer.length; */ } ret = krb5_crypto_init(context, key, 0, &crypto); @@ -881,6 +883,11 @@ _gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status, } } + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer, FALSE); if (major_status != GSS_S_COMPLETE) { diff --git a/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c b/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c index 182421581a8c..fc0b9b128723 100644 --- a/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c +++ b/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c @@ -82,6 +82,7 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, krb5_error_code kret; gsskrb5_cred handle; OM_uint32 ret; + int id_given = (*id != NULL); *cred = NULL; @@ -142,8 +143,6 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, handle->ccache = *id; *id = NULL; - if (kret) - goto out; } @@ -171,7 +170,7 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, } - if (id || keytab) { + if (id_given || keytab) { ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, diff --git a/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c index 981baed6edd6..c29841537526 100644 --- a/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c +++ b/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c @@ -195,7 +195,7 @@ _gsskrb5_export_sec_context( } if (ctx->target) { - kret = krb5_store_principal(sp, ctx->source); + kret = krb5_store_principal(sp, ctx->target); if (kret) { *minor_status = kret; goto failure; diff --git a/third_party/heimdal/lib/gssapi/krb5/external.c b/third_party/heimdal/lib/gssapi/krb5/external.c index 91947025cc7f..e58df18c5f0a 100644 --- a/third_party/heimdal/lib/gssapi/krb5/external.c +++ b/third_party/heimdal/lib/gssapi/krb5/external.c @@ -152,6 +152,13 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_export_name_oid_desc = gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_nt_principal_name_oid_desc = {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01") }; +/* + * GSS_C_NT_COMPOSITE_EXPORT [RFC6680], OID {iso(1) identified-organization(3) + * dod(6) internet(1) security(5) nametypes(6) gss-composite-export(6)}. + */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_composite_export_oid_desc = + {6, rk_UNCONST("\x2b\x06\x01\x05\x06\x06")}; + /* * draft-ietf-cat-iakerb-09, IAKERB: * The mechanism ID for IAKERB proxy GSS-API Kerberos, in accordance @@ -383,12 +390,12 @@ static gssapi_mech_interface_desc krb5_mech = { sizeof(krb5_mo) / sizeof(krb5_mo[0]), _gsskrb5_localname, _gsskrb5_authorize_localname, - NULL, /* gm_display_name_ext */ - NULL, /* gm_inquire_name */ - NULL, /* gm_get_name_attribute */ - NULL, /* gm_set_name_attribute */ - NULL, /* gm_delete_name_attribute */ - NULL, /* gm_export_name_composite */ + _gsskrb5_display_name_ext, + _gsskrb5_inquire_name, + _gsskrb5_get_name_attribute, + _gsskrb5_set_name_attribute, + _gsskrb5_delete_name_attribute, + _gsskrb5_export_name_composite, _gsskrb5_duplicate_cred, _gsskrb5_add_cred_from, _gsskrb5_store_cred_into, diff --git a/third_party/heimdal/lib/gssapi/krb5/import_name.c b/third_party/heimdal/lib/gssapi/krb5/import_name.c index 77449612d05c..f4ee2313c16f 100644 --- a/third_party/heimdal/lib/gssapi/krb5/import_name.c +++ b/third_party/heimdal/lib/gssapi/krb5/import_name.c @@ -183,9 +183,12 @@ import_export_name (OM_uint32 *minor_status, const gss_buffer_t input_name_buffer, gss_name_t *output_name) { + CompositePrincipal *composite; unsigned char *p; uint32_t length; + size_t sz; OM_uint32 ret; + int is_composite; char *name; if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length) @@ -195,7 +198,9 @@ import_export_name (OM_uint32 *minor_status, p = input_name_buffer->value; - if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 || + if (p[0] != 0x04 || + (p[1] != 0x01 && p[1] != 0x02) || + p[2] != 0x00 || p[3] != GSS_KRB5_MECHANISM->length + 2 || p[4] != 0x06 || p[5] != GSS_KRB5_MECHANISM->length || @@ -203,6 +208,8 @@ import_export_name (OM_uint32 *minor_status, GSS_KRB5_MECHANISM->length) != 0) return GSS_S_BAD_NAME; + is_composite = p[1] == 0x02; + p += 6 + GSS_KRB5_MECHANISM->length; length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; @@ -211,6 +218,28 @@ import_export_name (OM_uint32 *minor_status, if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length) return GSS_S_BAD_NAME; + if (is_composite) { + if ((composite = calloc(1, sizeof(*composite))) == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = decode_CompositePrincipal(p, length, composite, &sz); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + if (sz != length) { + free_CompositePrincipal(composite); + free(composite); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + *output_name = (void *)composite; + return GSS_S_COMPLETE; + } + name = malloc(length + 1); if (name == NULL) { *minor_status = ENOMEM; @@ -221,7 +250,6 @@ import_export_name (OM_uint32 *minor_status, ret = parse_krb5_name(minor_status, context, name, output_name); free(name); - return ret; } @@ -253,7 +281,8 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_name context, input_name_buffer, output_name); - else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) { + else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME) || + gss_oid_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT)) { return import_export_name(minor_status, context, input_name_buffer, diff --git a/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c index c7dfdc85166c..62b26ed7eb91 100644 --- a/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c +++ b/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c @@ -33,6 +33,12 @@ #include "gsskrb5_locl.h" +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *, + krb5_context, + krb5_auth_context, + gss_const_name_t); + /* * copy the addresses from `input_chan_bindings' (if any) to * the auth context `ac' @@ -418,6 +424,11 @@ init_auth if (ret) goto failure; + ret = gsskrb5_set_authorization_data(minor_status, context, + ctx->auth_context, name); + if (ret) + goto failure; + ctx->endtime = ctx->kcred->times.endtime; ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); @@ -921,7 +932,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context time_rec); if (ret != GSS_S_COMPLETE) break; - /* FALLTHROUGH */ + fallthrough; case INITIATOR_RESTART: ret = init_auth_restart(minor_status, cred, @@ -980,3 +991,31 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context return ret; } + +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *minor_status, + krb5_context context, + krb5_auth_context auth_context, + gss_const_name_t gn) +{ + const CompositePrincipal *name = (const void *)gn; + AuthorizationData *ad; + krb5_error_code kret = 0; + size_t i; + + if (name->nameattrs == NULL || name->nameattrs->want_ad == NULL) + return GSS_S_COMPLETE; + + ad = name->nameattrs->want_ad; + for (i = 0; kret == 0 && i < ad->len; i++) { + kret = krb5_auth_con_add_AuthorizationData(context, auth_context, + ad->val[0].ad_type, + &ad->val[0].ad_data); + } + + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/name_attrs.c b/third_party/heimdal/lib/gssapi/krb5/name_attrs.c new file mode 100644 index 000000000000..11fc2ef969fb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/name_attrs.c @@ -0,0 +1,1171 @@ +/* + * Copyright (c) 2021 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" + +/* + * (Not-yet-)Standard name attributes for Kerberos MNs, + * GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "...". + * + * I.e., "urn:ietf:kerberos:nameattr-...". (XXX Register this URN namespace + * with IANA.) + * + * Note that we do use URN fragments. + * + * Specific attributes below the base URN: + * + * - name access attributes: + * - "realm" -> realm of name + * - "name-ncomp" -> count of name components + * - "name-ncomp#" -> name component N (0 <= N <= 9) + * + * Ticket and Authenticator access attributes: + * + * - "transit-path" -> encoding of the transited path + * - "authenticator-authz-data" -> encoding of all of the authz-data from + * the AP-REQ's Authenticator + * - "ticket-authz-data" -> encoding of all of the authz-data from + * the AP-REQ's Ticket + * - "ticket-authz-data#pac" -> the PAC + * - "authz-data#" -> encoding of all of a specific auth-data + * element type N (e.g., 2, meaning + * AD-INTENDED-FOR-SERVER) + * + * Misc. attributes: + * + * - "peer-realm" -> name of peer's realm (if this is an MN + * resulting for establishing a security + * context) + * - "canonical-name" -> exported name token and RFC1964 display + * syntax of the name's canonical name + * + * Compatibility with MIT: + * + * - "urn:mspac:" -> the PAC and its individual info buffers + * + * TODO: + * + * - Add some sort of display syntax for transit path + * - Add support for URN q-components or attribute prefixes to specify + * alternative raw and/or display value encodings (JSON?) + * - Add support for attributes for accessing other parts of the Ticket / KDC + * reply enc-parts, like auth times + * - Add support for getting PAC logon fields, including SIDs (one at a time) + * - Add support for CAMMAC? + */ + +static int +attr_eq(gss_const_buffer_t attr, const char *aname, size_t aname_len, \ + int prefix_check) +{ + if (attr->length < aname_len) + return 0; + + if (strncmp((char *)attr->value, aname, aname_len) != 0) + return 0; + + return prefix_check || attr->length == aname_len; +} + +#define ATTR_EQ(a, an) (attr_eq(a, an, sizeof(an) - 1, FALSE)) +#define ATTR_EQ_PREFIX(a, an) (attr_eq(a, an, sizeof(an) - 1, TRUE)) + +/* Split attribute into prefix, suffix, and fragment. See RFC6680. */ +static void +split_attr(gss_const_buffer_t orig, + gss_buffer_t prefix, + gss_buffer_t attr, + gss_buffer_t frag, + int *is_urn) +{ + char *last = NULL; + char *p = orig->value; + + *attr = *orig; + prefix->value = orig->value; + prefix->length = 0; + frag->length = 0; + frag->value = NULL; + + /* FIXME We don't have a memrchr() in lib/roken */ + for (p = memchr(p, ' ', orig->length); + p; + p = memchr(p + 1, ' ', orig->length)) { + last = p; + prefix->length = last - (const char *)orig->value; + attr->value = last + 1; + attr->length = orig->length - (prefix->length + 1); + } + if (prefix->length == 0) + prefix->value = NULL; + + if ((*is_urn = (strncmp(attr->value, "urn:", sizeof("urn:") - 1) == 0)) && + (p = memchr((char *)attr->value + 1, '#', attr->length - 1))) { + frag->value = ++p; + frag->length = attr->length - (p - (const char *)attr->value); + attr->length = --p - (const char *)attr->value; + } +} + +typedef OM_uint32 get_name_attr_f(OM_uint32 *, + const CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t, + int *, + int *, + gss_buffer_t, + gss_buffer_t, + int *); + +typedef OM_uint32 set_name_attr_f(OM_uint32 *, + CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t, + int, + gss_buffer_t); + +typedef OM_uint32 del_name_attr_f(OM_uint32 *, + CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t); +typedef get_name_attr_f *get_name_attr_fp; +typedef set_name_attr_f *set_name_attr_fp; +typedef del_name_attr_f *del_name_attr_fp; + +static get_name_attr_f get_realm; +static get_name_attr_f get_ncomps; +static get_name_attr_f get_peer_realm; +static get_name_attr_f get_pac; +static get_name_attr_f get_pac_buffer; +static get_name_attr_f get_authz_data; +static get_name_attr_f get_ticket_authz_data; +static get_name_attr_f get_authenticator_authz_data; +static set_name_attr_f set_authenticator_authz_data; +static get_name_attr_f get_transited; +static get_name_attr_f get_canonical_name; + +#define NB(n) \ + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n, n, \ + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n) - 1, \ + sizeof(n) - 1 +#define NM(n) \ + "urn:mspac:" n, n, sizeof("urn:mspac:" n) - 1, sizeof(n) - 1 + +static struct krb5_name_attrs { + const char *fullname; + const char *name; + size_t fullnamelen; + size_t namelen; + get_name_attr_fp getter; + set_name_attr_fp setter; + del_name_attr_fp deleter; + unsigned int indicate:1; + unsigned int is_krb5_name_attr_urn:1; +} name_attrs[] = { + /* XXX We should sort these so we can binary search them */ + { NB("realm"), get_realm, NULL, NULL, 1, 1 }, + { NB("name-ncomp"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#0"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#1"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#2"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#3"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#4"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#5"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#6"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#7"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#8"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#9"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("peer-realm"), get_peer_realm, NULL, NULL, 1, 1 }, + { NB("ticket-authz-data#pac"), get_pac, NULL, NULL, 1, 1 }, + { NM(""), get_pac, NULL, NULL, 1, 0 }, + { NM("logon-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("credentials-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("server-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("privsvr-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("client-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("delegation-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("upn-dns-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("ticket-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("attributes-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("requestor-sid"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NB("ticket-authz-data#kdc-issued"), + get_ticket_authz_data, NULL, NULL, 1, 1 }, + { NB("ticket-authz-data"), + get_ticket_authz_data, NULL, NULL, 1, 1 }, + { NB("authenticator-authz-data"), + get_authenticator_authz_data, + set_authenticator_authz_data, NULL, 1, 1 }, + { NB("authz-data"), get_authz_data, NULL, NULL, 1, 1 }, + { NB("transit-path"), get_transited, NULL, NULL, 1, 1 }, + { NB("canonical-name"), get_canonical_name, NULL, NULL, 1, 1 }, +}; + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_get_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t original_attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 0; + if (more) + *more = 0; + if (value) { + value->length = 0; + value->value = NULL; + } + if (display_value) { + display_value->length = 0; + display_value->value = NULL; + } + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].getter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0)) + continue; + } else + continue; + + return name_attrs[i].getter(minor_status, + (const CompositePrincipal *)name, + &prefix, &attr, &frag, authenticated, + complete, value, display_value, more); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_set_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t original_attr, + gss_buffer_t value) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].setter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else + continue; + + return name_attrs[i].setter(minor_status, (CompositePrincipal *)name, + &prefix, &attr, &frag, complete, value); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t original_attr) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].deleter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0)) + continue; + } else + continue; + + return name_attrs[i].deleter(minor_status, (CompositePrincipal *)name, + &prefix, &attr, &frag); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + gss_buffer_desc prefix, attr, frag, a; + OM_uint32 major = GSS_S_UNAVAILABLE; + size_t i; + int authenticated, is_urn; + + *minor_status = 0; + if (name_is_MN) + *name_is_MN = 1; + if (MN_mech) + *MN_mech = GSS_KRB5_MECHANISM; + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ; + if (attrs == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].indicate) + continue; + a.value = (void *)(uintptr_t)name_attrs[i].fullname; + a.length = name_attrs[i].fullnamelen; + split_attr(&a, &prefix, &attr, &frag, &is_urn); + major = name_attrs[i].getter(minor_status, + (const CompositePrincipal *)name, + &prefix, &attr, &frag, &authenticated, + NULL, NULL, NULL, NULL); + if (major == GSS_S_UNAVAILABLE) + continue; + if (major != GSS_S_COMPLETE) + break; + major = gss_add_buffer_set_member(minor_status, &a, attrs); + } + if (major == GSS_S_UNAVAILABLE) + major = GSS_S_COMPLETE; + return major; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_display_name_ext(OM_uint32 *minor_status, + gss_name_t name, + gss_OID display_as_name_type, + gss_buffer_t display_name) +{ + krb5_const_principal p = (void *)name; + char *s = NULL; + + *minor_status = 0; + if (display_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + display_name->length = 0; + display_name->value = NULL; + + if (gss_oid_equal(display_as_name_type, GSS_C_NT_USER_NAME)) { + if (p->name.name_string.len != 1) + return GSS_S_UNAVAILABLE; + return _gsskrb5_localname(minor_status, name, GSS_KRB5_MECHANISM, + display_name); + } + if (!gss_oid_equal(display_as_name_type, GSS_C_NT_HOSTBASED_SERVICE) || + p->name.name_string.len != 2 || + strchr(p->name.name_string.val[0], '@') || + strchr(p->name.name_string.val[1], '.') == NULL) + return GSS_S_UNAVAILABLE; + if (asprintf(&s, "%s@%s", p->name.name_string.val[0], + p->name.name_string.val[1]) == -1 || s == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + display_name->length = strlen(s); + display_name->value = s; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_export_name_composite(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exported_name) +{ + krb5_error_code kret; + gss_buffer_desc inner = GSS_C_EMPTY_BUFFER; + unsigned char *buf; + size_t sz; + + if (name == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + if (exported_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + ASN1_MALLOC_ENCODE(CompositePrincipal, inner.value, inner.length, + (void *)name, &sz, kret); + if (kret != 0) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + exported_name->length = 10 + inner.length + GSS_KRB5_MECHANISM->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) { + free(inner.value); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + buf[0] = 0x04; + buf[1] = 0x02; + buf[2] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff; + buf[3] = (GSS_KRB5_MECHANISM->length + 2) & 0xff; + buf[4] = 0x06; + buf[5] = (GSS_KRB5_MECHANISM->length) & 0xFF; + + memcpy(buf + 6, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length); + buf += 6 + GSS_KRB5_MECHANISM->length; + + buf[0] = (inner.length >> 24) & 0xff; + buf[1] = (inner.length >> 16) & 0xff; + buf[2] = (inner.length >> 8) & 0xff; + buf[3] = (inner.length) & 0xff; + buf += 4; + + memcpy(buf, inner.value, inner.length); + free(inner.value); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +#define CHECK_ENOMEM(v, dv) \ + do { \ + if (((v) && !(v)->value) || ((dv) && !(dv)->value)) { \ + if ((v) && (v)->value) { \ + free((v)->value); \ + (v)->length = 0; \ + (v)->value = NULL; \ + } \ + *minor_status = ENOMEM; \ + return GSS_S_FAILURE; \ + } \ + } while (0) + +static OM_uint32 +get_realm(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + + if (prefix->length || frag->length || !name->realm) + return GSS_S_UNAVAILABLE; + if (authenticated && nameattrs && nameattrs->authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + if (value && (value->value = strdup(name->realm))) + value->length = strlen(name->realm); + if (display_value && (display_value->value = strdup(name->realm))) + display_value->length = strlen(name->realm); + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_ncomps(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + int n = -1; + + if (authenticated && nameattrs && nameattrs->authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (frag->length == 1 && + ((const char *)frag->value)[0] >= '0' && + ((const char *)frag->value)[0] <= '9') { + n = ((const char *)frag->value)[0] - '0'; + } else if (frag->length == sizeof("all") - 1 && + strncmp(frag->value, "all", sizeof("all") - 1) == 0) { + if (!more || *more < -1 || *more == 0 || *more > CHAR_MAX || + *more > (int)name->name.name_string.len) { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + if (*more == -1) { + *more = name->name.name_string.len - 1; + n = 0; + } else { + n = name->name.name_string.len - *more; + (*more)--; + } + } + + if (frag->length == 0) { + char *s = NULL; + + /* Outut count of components */ + if (value && (value->value = malloc(sizeof(size_t)))) { + *((size_t *)value->value) = name->name.name_string.len; + value->length = sizeof(size_t); + } + if (display_value && + asprintf(&s, "%u", (unsigned int)name->name.name_string.len) > 0) { + display_value->value = s; + display_value->length = strlen(display_value->value); + } + } else { + /* + * Output a component. The value and the display value are the same in + * this case. + */ + if (n < 0 || n >= name->name.name_string.len) { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + if (value && (value->value = strdup(name->name.name_string.val[n]))) + value->length = strlen(name->name.name_string.val[n]); + if (display_value && + (display_value->value = strdup(name->name.name_string.val[n]))) + display_value->length = strlen(name->name.name_string.val[n]); + } + + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_peer_realm(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + + if (prefix->length || frag->length || !nameattrs || !nameattrs->peer_realm) + return GSS_S_UNAVAILABLE; + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + if (value && (value->value = strdup(nameattrs->peer_realm[0]))) + value->length = strlen(value->value); + if (display_value && + (display_value->value = strdup(nameattrs->peer_realm[0]))) + display_value->length = strlen(display_value->value); + + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_pac(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret; + krb5_context context; + krb5_data data; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + + krb5_data_zero(&data); + + if (src == NULL || + src->element != choice_PrincipalNameAttrSrc_enc_ticket_part) + return GSS_S_UNAVAILABLE; + + ticket = &src->u.enc_ticket_part; + + if (prefix->length || !authenticated || !ticket) + return GSS_S_UNAVAILABLE; + + GSSAPI_KRB5_INIT(&context); + + *authenticated = nameattrs->pac_verified; + if (complete) + *complete = 1; + + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_WIN2K_PAC, + value ? &data : NULL); + + if (value) { + value->length = data.length; + value->value = data.data; + } + + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_pac_buffer(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret; + krb5_context context; + krb5_data data; + PrincipalNameAttrs *nameattrs = name->nameattrs; + krb5_data suffix; + + krb5_data_zero(&data); + + if (prefix->length || !authenticated || + !nameattrs || !nameattrs->pac) + return GSS_S_UNAVAILABLE; + + GSSAPI_KRB5_INIT(&context); + + if (ATTR_EQ_PREFIX(attr, "urn:mspac:")) { + suffix.length = attr->length - (sizeof("urn:mspac:") - 1); + suffix.data = (char *)attr->value + sizeof("urn:mspac:") - 1; + } else if (ATTR_EQ_PREFIX(frag, "pac-")) { + suffix.length = frag->length - sizeof("pac-") - 1; + suffix.data = (char *)frag->value + sizeof("pac-") - 1; + } else + return GSS_S_UNAVAILABLE; /* should not be reached */ + + *authenticated = nameattrs->pac_verified; + if (complete) + *complete = 1; + + kret = _krb5_pac_get_buffer_by_name(context, nameattrs->pac, &suffix, + value ? &data : NULL); + + if (value) { + value->length = data.length; + value->value = data.data; + } + + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + krb5_context context; + krb5_data data; + char s[22]; + char *end; + int64_t n; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + default: + return GSS_S_UNAVAILABLE; + } + + if (!nameattrs || !frag->length || frag->length > sizeof(s) - 1) + return GSS_S_UNAVAILABLE; + + /* Output a specific AD element from the ticket or authenticator */ + krb5_data_zero(&data); + memcpy(s, frag->value, frag->length); + s[frag->length] = '\0'; + errno = 0; + n = strtoll(s, &end, 10); + if (end[0] == '\0' && (errno || n > INT_MAX || n < INT_MIN)) { + *minor_status = ERANGE; + return GSS_S_UNAVAILABLE; + } + if (end[0] != '\0') { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 1; + + GSSAPI_KRB5_INIT(&context); + + kret = ENOENT; + if (ticket && ticket->authorization_data) { + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, n, value ? &data : NULL); + + /* If it's from the ticket, it _may_ be authenticated: */ + if (kret == 0 && authenticated) { + if (n == KRB5_AUTHDATA_KDC_ISSUED) + *authenticated = nameattrs->kdc_issued_verified; + else if (n == KRB5_AUTHDATA_WIN2K_PAC) + *authenticated = nameattrs->pac_verified; + } + } + if (kret == ENOENT && nameattrs->authenticator_ad && + n != KRB5_AUTHDATA_KDC_ISSUED && + n != KRB5_AUTHDATA_WIN2K_PAC) { + kret = _krb5_get_ad(context, nameattrs->authenticator_ad, + NULL, n, value ? &data : NULL); + } + + if (value) { + value->length = data.length; + value->value = data.data; + } + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_ticket_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + size_t sz; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + default: + return GSS_S_UNAVAILABLE; + } + + if (!ticket) + return GSS_S_UNAVAILABLE; + + if (complete) + *complete = 1; + + if (frag->length == sizeof("kdc-issued") - 1 && + strncmp(frag->value, "kdc-issued", sizeof("kdc-issued") - 1) == 0) { + krb5_context context; + krb5_data data; + + GSSAPI_KRB5_INIT(&context); + if (authenticated) + *authenticated = nameattrs->kdc_issued_verified; + + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_KDC_ISSUED, + value ? &data : NULL); + if (value) { + value->length = data.length; + value->value = data.data; + } + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; + } else if (frag->length) { + return GSS_S_UNAVAILABLE; + } + + /* Just because it's in the Ticket doesn't make it authenticated */ + if (authenticated) + *authenticated = 0; + + if (value) { + ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length, + ticket->authorization_data, &sz, kret); + *minor_status = kret; + } + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_authenticator_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + size_t sz; + + if (!nameattrs || !nameattrs->authenticator_ad) + return GSS_S_UNAVAILABLE; + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 1; + + if (value) { + ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length, + nameattrs->authenticator_ad, &sz, kret); + *minor_status = kret; + } + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +set_authenticator_authz_data(OM_uint32 *minor_status, + CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int complete, + gss_buffer_t value) +{ + AuthorizationDataElement e; + krb5_error_code kret; + size_t sz; + + if (!value) + return GSS_S_CALL_INACCESSIBLE_READ; + if (frag->length && + !ATTR_EQ(frag, "if-relevant")) + return GSS_S_UNAVAILABLE; + + if ((name->nameattrs == NULL && + (name->nameattrs = calloc(1, sizeof(*name->nameattrs))) == NULL) || + (name->nameattrs->want_ad == NULL && + (name->nameattrs->want_ad = + calloc(1, sizeof(*name->nameattrs->want_ad))) == NULL)) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memset(&e, 0, sizeof(e)); + kret = decode_AuthorizationDataElement(value->value, value->length, &e, + &sz); + if (kret == 0) { + if (frag->length) { + AuthorizationData ir; + + ir.len = 0; + ir.val = NULL; + kret = add_AuthorizationData(&ir, &e); + free_AuthorizationDataElement(&e); + if (kret == 0) { + e.ad_type = KRB5_AUTHDATA_IF_RELEVANT; + ASN1_MALLOC_ENCODE(AuthorizationData, e.ad_data.data, + e.ad_data.length, &ir, &sz, kret); + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + } + free_AuthorizationData(&ir); + } else { + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + free_AuthorizationDataElement(&e); + } + } + + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_transited(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + size_t sz; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + break; + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + default: + return GSS_S_UNAVAILABLE; + } + + if (!nameattrs && !ticket) + return GSS_S_UNAVAILABLE; + if (nameattrs && !nameattrs->transited && !ticket) + return GSS_S_UNAVAILABLE; + + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (value && ticket) + ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length, + &ticket->transited, &sz, kret); + else if (value && nameattrs->transited) + ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length, + nameattrs->transited, &sz, kret); + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_canonical_name(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + krb5_principal p = NULL; + krb5_context context; + EncTicketPart *ticket = NULL; + EncKDCRepPart *kdcrep = NULL; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + kdcrep = &src->u.enc_kdc_rep_part; + break; + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + default: + return GSS_S_UNAVAILABLE; + } + + GSSAPI_KRB5_INIT(&context); + + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (kdcrep) { + kret = _krb5_principalname2krb5_principal(context, &p, + kdcrep->sname, + kdcrep->srealm); + } else if (nameattrs && nameattrs->pac && + (_krb5_pac_get_canon_principal(context, nameattrs->pac, &p)) == 0) { + if (authenticated) + *authenticated = nameattrs->pac_verified; + } else if (ticket) { + krb5_data data; + krb5_pac pac = NULL; + + krb5_data_zero(&data); + + /* Use canonical name from PAC if available */ + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_WIN2K_PAC, &data); + if (kret == 0) + kret = krb5_pac_parse(context, data.data, data.length, &pac); + if (kret == 0) + kret = _krb5_pac_get_canon_principal(context, pac, &p); + if (kret == 0 && authenticated) + *authenticated = nameattrs->pac_verified; + else if (kret == ENOENT) + kret = _krb5_principalname2krb5_principal(context, &p, + ticket->cname, + ticket->crealm); + + krb5_data_free(&data); + krb5_pac_free(context, pac); + } else + return GSS_S_UNAVAILABLE; + if (kret == 0 && value) { + OM_uint32 major; + /* + * Value is exported name token (exported composite name token + * should also work). + */ + major = _gsskrb5_export_name(minor_status, (gss_name_t)p, value); + if (major != GSS_S_COMPLETE) { + krb5_free_principal(context, p); + return major; + } + } + if (kret == 0 && display_value) { + /* Display value is principal name display form */ + kret = krb5_unparse_name(context, p, + (char **)&display_value->value); + if (kret == 0) + display_value->length = strlen(display_value->value); + } + + krb5_free_principal(context, p); + if (kret) { + if (value) { + free(value->value); + value->length = 0; + value->value = NULL; + } + *minor_status = kret; + return GSS_S_UNAVAILABLE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/store_cred.c b/third_party/heimdal/lib/gssapi/krb5/store_cred.c index 311686dc13a8..6d727b4e289e 100644 --- a/third_party/heimdal/lib/gssapi/krb5/store_cred.c +++ b/third_party/heimdal/lib/gssapi/krb5/store_cred.c @@ -185,7 +185,8 @@ _gsskrb5_store_cred_into2(OM_uint32 *minor_status, const char *cs_user_name = NULL; const char *cs_app_name = NULL; char *ccache_name = NULL; - OM_uint32 major_status, junk; + OM_uint32 major_status = GSS_S_FAILURE; + OM_uint32 junk; OM_uint32 overwrite_cred = store_cred_flags & GSS_C_STORE_CRED_OVERWRITE; int default_for = 0; @@ -346,7 +347,7 @@ _gsskrb5_store_cred_into2(OM_uint32 *minor_status, (void) gss_release_buffer_set(&junk, &env); free(ccache_name); *minor_status = ret; - return ret ? GSS_S_FAILURE : GSS_S_COMPLETE; + return ret ? major_status : GSS_S_COMPLETE; } OM_uint32 GSSAPI_CALLCONV diff --git a/third_party/heimdal/lib/gssapi/krb5/test_kcred.c b/third_party/heimdal/lib/gssapi/krb5/test_kcred.c index 3cbba243f0b8..c90a1443bc60 100644 --- a/third_party/heimdal/lib/gssapi/krb5/test_kcred.c +++ b/third_party/heimdal/lib/gssapi/krb5/test_kcred.c @@ -90,9 +90,11 @@ copy_import(void) if (!equal) errx(1, "names not equal"); - /* FIXME: This check is racy! */ - if (lifetime1 != lifetime2) + /* This check is racy! */ + if (getenv("TESTS_ENVIRONMENT") == NULL) && lifetime1 != lifetime2) errx(1, "lifetime not equal"); + if (lifetime1 != lifetime2) + warnx("lifetime not equal"); if (usage1 != usage1) errx(1, "usage not equal"); diff --git a/third_party/heimdal/lib/gssapi/libgssapi-exports.def b/third_party/heimdal/lib/gssapi/libgssapi-exports.def index b8f9e75c4bcc..6077c8e26f4f 100644 --- a/third_party/heimdal/lib/gssapi/libgssapi-exports.def +++ b/third_party/heimdal/lib/gssapi/libgssapi-exports.def @@ -1,5 +1,6 @@ EXPORTS __gss_c_nt_anonymous_oid_desc DATA + __gss_c_nt_composite_export_oid_desc DATA __gss_c_nt_export_name_oid_desc DATA __gss_c_nt_hostbased_service_oid_desc DATA __gss_c_nt_hostbased_service_x_oid_desc DATA @@ -41,7 +42,6 @@ EXPORTS gss_export_name gss_export_name_composite gss_export_sec_context - gss_get_instance gss_get_mic gss_get_neg_mechs gss_get_name_attribute diff --git a/third_party/heimdal/lib/gssapi/mech/gss_compare_name.c b/third_party/heimdal/lib/gssapi/mech/gss_compare_name.c index fd2523fd8e3e..97ef57898da1 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_compare_name.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_compare_name.c @@ -44,7 +44,15 @@ gss_compare_name(OM_uint32 *minor_status, * names have one. Otherwise, try to find common mechanism * names and compare them. */ - if (name1->gn_value.value && name2->gn_value.value) { + if (name1->gn_value.value && name2->gn_value.value && + name1->gn_type == GSS_C_NO_OID && name2->gn_type == GSS_C_NO_OID) { + *name_equal = + name1->gn_value.length == name2->gn_value.length && + memcmp(name1->gn_value.value, name2->gn_value.value, + name1->gn_value.length) == 0; + } else if (name1->gn_value.value && name2->gn_value.value && + name1->gn_type != GSS_C_NO_OID && + name2->gn_type != GSS_C_NO_OID) { *name_equal = 1; /* RFC 2743: anonymous names always compare false */ if (gss_oid_equal(name1->gn_type, GSS_C_NT_ANONYMOUS) || diff --git a/third_party/heimdal/lib/gssapi/mech/gss_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_cred.c index 3ba2dd84621e..00561ce928e9 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_cred.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_cred.c @@ -262,8 +262,7 @@ gss_import_cred(OM_uint32 * minor_status, goto out; } - if (m->gm_import_cred == NULL && - !gss_oid_equal(&m->gm_mech_oid, GSS_SPNEGO_MECHANISM)) { + if (m->gm_import_cred == NULL) { *minor_status = 0; major = GSS_S_BAD_MECH; goto out; @@ -287,8 +286,7 @@ gss_import_cred(OM_uint32 * minor_status, continue; } - major = m->gm_import_cred(minor_status, - &buffer, &mcred); + major = m->gm_import_cred(minor_status, &buffer, &mcred); gss_release_buffer(&junk, &buffer); if (major != GSS_S_COMPLETE) goto out; diff --git a/third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c b/third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c index 05a05f508dea..c0309809f745 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c @@ -72,6 +72,10 @@ gss_export_sec_context(OM_uint32 *minor_status, verflags |= EXPORT_CONTEXT_FLAG_MECH_CTX; kret = krb5_store_uint8(sp, verflags); + if (kret) { + *minor_status = kret; + goto failure; + } if (ctx->gc_target_len) { _gss_mg_log(10, "gss-esc: exporting partial token %zu/%zu", diff --git a/third_party/heimdal/lib/gssapi/mech/gss_import_name.c b/third_party/heimdal/lib/gssapi/mech/gss_import_name.c index d7559981dc53..54930bf46452 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_import_name.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_import_name.c @@ -31,6 +31,7 @@ static OM_uint32 _gss_import_export_name(OM_uint32 *minor_status, const gss_buffer_t input_name_buffer, + const gss_OID name_type, gss_name_t *output_name) { OM_uint32 major_status; @@ -65,6 +66,24 @@ _gss_import_export_name(OM_uint32 *minor_status, p += 2; len -= 2; + /* + * If the name token is a composite token (TOK_ID 0x04 0x02) then per + * RFC6680 everything after that is implementation-specific. This + * mech-glue is pluggable however, so we need the format of the rest of + * the header to be stable, otherwise we couldn't reliably determine + * what mechanism the token is for and we'd have to try all of them. + * + * So... we keep the same format for the exported composite name token + * as for normal exported name tokens (see RFC2743, section 3.2), with + * the TOK_ID 0x04 0x02, but only up to the mechanism OID. We don't + * enforce that there be a NAME_LEN in the exported composite name + * token, or that it match the length of the remainder of the token. + * + * FYI, at least one out-of-tree mechanism implements exported + * composite name tokens as the same as exported name tokens with + * attributes appended and the NAME_LEN not modified to match. + */ + /* * Get the mech length and the name length and sanity * check the size of of the buffer. @@ -107,17 +126,19 @@ _gss_import_export_name(OM_uint32 *minor_status, mech_oid.elements = p; - if (len < t + 4) - return (GSS_S_BAD_NAME); - p += t; - len -= t; + if (!composite) { + if (len < t + 4) + return (GSS_S_BAD_NAME); + p += t; + len -= t; - t = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - p += 4; - len -= 4; + t = ((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + /* p += 4; // we're done using `p' now */ + len -= 4; - if (!composite && len != t) - return (GSS_S_BAD_NAME); + if (len != t) + return (GSS_S_BAD_NAME); + } m = __gss_get_mechanism(&mech_oid); if (!m || !m->gm_import_name) @@ -127,7 +148,7 @@ _gss_import_export_name(OM_uint32 *minor_status, * Ask the mechanism to import the name. */ major_status = m->gm_import_name(minor_status, - input_name_buffer, GSS_C_NT_EXPORT_NAME, &new_canonical_name); + input_name_buffer, name_type, &new_canonical_name); if (major_status != GSS_S_COMPLETE) { _gss_mg_error(m, *minor_status); return major_status; @@ -156,6 +177,7 @@ _gss_import_export_name(OM_uint32 *minor_status, * - GSS_C_NT_USER_NAME * - GSS_C_NT_HOSTBASED_SERVICE * - GSS_C_NT_EXPORT_NAME + * - GSS_C_NT_COMPOSITE_EXPORT * - GSS_C_NT_ANONYMOUS * - GSS_KRB5_NT_PRINCIPAL_NAME * @@ -197,20 +219,15 @@ gss_import_name(OM_uint32 *minor_status, _gss_load_mech(); - /* - * Use GSS_NT_USER_NAME as default name type. - */ - if (name_type == GSS_C_NO_OID) - name_type = GSS_C_NT_USER_NAME; - /* * If this is an exported name, we need to parse it to find * the mechanism and then import it as an MN. See RFC 2743 * section 3.2 for a description of the format. */ - if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME)) { - return _gss_import_export_name(minor_status, - input_name_buffer, output_name); + if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME) || + gss_oid_equal(name_type, GSS_C_NT_COMPOSITE_EXPORT)) { + return _gss_import_export_name(minor_status, input_name_buffer, + name_type, output_name); } @@ -221,13 +238,16 @@ gss_import_name(OM_uint32 *minor_status, return (GSS_S_FAILURE); } - major_status = _gss_intern_oid(minor_status, - name_type, &name->gn_type); - if (major_status) { - rname = (gss_name_t)name; - gss_release_name(&ms, (gss_name_t *)&rname); - return (GSS_S_FAILURE); - } + if (name_type != GSS_C_NO_OID) { + major_status = _gss_intern_oid(minor_status, + name_type, &name->gn_type); + if (major_status) { + rname = (gss_name_t)name; + gss_release_name(&ms, (gss_name_t *)&rname); + return (GSS_S_FAILURE); + } + } else + name->gn_type = GSS_C_NO_OID; major_status = _gss_copy_buffer(minor_status, input_name_buffer, &name->gn_value); @@ -245,11 +265,13 @@ gss_import_name(OM_uint32 *minor_status, if ((m->gm_mech.gm_flags & GM_USE_MG_NAME)) continue; - major_status = gss_test_oid_set_member(minor_status, - name_type, m->gm_name_types, &present); + if (name_type != GSS_C_NO_OID) { + major_status = gss_test_oid_set_member(minor_status, + name_type, m->gm_name_types, &present); - if (major_status || present == 0) - continue; + if (GSS_ERROR(major_status) || present == 0) + continue; + } mn = malloc(sizeof(struct _gss_mechanism_name)); if (!mn) { diff --git a/third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c b/third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c index 0acae8533242..39b717e3dc2f 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c @@ -42,9 +42,9 @@ gss_import_sec_context(OM_uint32 *minor_status, _gss_mg_log(10, "gss-isc called"); - if (!minor_status || !context_handle) { + if (!context_handle) { *minor_status = EFAULT; - return GSS_S_FAILURE; + return GSS_S_CALL_INACCESSIBLE_WRITE; } *minor_status = 0; @@ -87,7 +87,7 @@ gss_import_sec_context(OM_uint32 *minor_status, if (ret != GSS_S_COMPLETE) goto failure; - ctx->gc_input.value = calloc(target_len, 1); + ctx->gc_free_this = ctx->gc_input.value = calloc(target_len, 1); if (ctx->gc_input.value == NULL) goto failure; diff --git a/third_party/heimdal/lib/gssapi/mech/gss_krb5.c b/third_party/heimdal/lib/gssapi/mech/gss_krb5.c index 0f6d14209af2..78c305689f00 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_krb5.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_krb5.c @@ -520,7 +520,8 @@ gss_krb5_ccache_name(OM_uint32 *minor_status, } } - *out_name = args.out_name; + if (out_name) + *out_name = args.out_name; return major_status; } @@ -571,7 +572,7 @@ gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, { unsigned char *buf = data_set->elements[0].value; - *authtime = (buf[3] <<24) | (buf[2] << 16) | + *authtime = ((unsigned long)buf[3] <<24) | (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); } @@ -729,7 +730,7 @@ gsskrb5_extract_key(OM_uint32 *minor_status, } *keyblock = calloc(1, sizeof(**keyblock)); - if (keyblock == NULL) { + if (*keyblock == NULL) { ret = ENOMEM; goto out; } diff --git a/third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c b/third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c index 60fe376a914e..372e72dd5da8 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c @@ -137,6 +137,8 @@ _gss_string_to_oid(const char* s, gss_OID *oidp) } } } + if (byte_count == 0) + return EINVAL; if (!res) { res = malloc(byte_count); if (!res) @@ -228,8 +230,12 @@ add_builtin(gssapi_mech_interface mech) free(m); return minor_status; } - gss_add_oid_set_member(&minor_status, - &m->gm_mech.gm_mech_oid, &_gss_mech_oids); + + if (gss_add_oid_set_member(&minor_status, &m->gm_mech.gm_mech_oid, + &_gss_mech_oids) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } /* pick up the oid sets of names */ @@ -237,8 +243,12 @@ add_builtin(gssapi_mech_interface mech) (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status, &m->gm_mech.gm_mech_oid, &m->gm_name_types); - if (m->gm_name_types == NULL) - gss_create_empty_oid_set(&minor_status, &m->gm_name_types); + if (m->gm_name_types == NULL && + gss_create_empty_oid_set(&minor_status, + &m->gm_name_types) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } HEIM_TAILQ_INSERT_TAIL(&_gss_mechs, m, gm_link); return 0; @@ -288,9 +298,15 @@ _gss_load_mech(void) return; } - add_builtin(__gss_krb5_initialize()); - add_builtin(__gss_spnego_initialize()); - add_builtin(__gss_ntlm_initialize()); + if (add_builtin(__gss_krb5_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin Kerberos GSS " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_spnego_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SPNEGO " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_ntlm_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin NTLM " + "mechanism to the GSS mechanism switch"); #ifdef HAVE_DLOPEN fp = fopen(conf ? conf : _PATH_GSS_MECH, "r"); @@ -461,7 +477,9 @@ _gss_load_mech(void) out: #endif - add_builtin(__gss_sanon_initialize()); + if (add_builtin(__gss_sanon_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SANON " + "mechanism to the GSS mechanism switch"); HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); } @@ -565,16 +583,3 @@ gss_oid_to_name(gss_const_OID oid) return NULL; } - -GSSAPI_LIB_FUNCTION uintptr_t GSSAPI_CALLCONV -gss_get_instance(const char *libname) -{ - static const char *instance = "libgssapi"; - - if (strcmp(libname, "gssapi") == 0) - return (uintptr_t)instance; - else if (strcmp(libname, "krb5") == 0) - return krb5_get_instance(libname); - - return 0; -} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c b/third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c index 72fd9de46245..5046faed0267 100644 --- a/third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c +++ b/third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c @@ -158,6 +158,10 @@ gss_pname_to_uid(OM_uint32 *minor_status, major = gss_localname(minor_status, pname, mech_type, &localname); if (GSS_ERROR(major)) return major; + if (localname.length == 0) { + *minor_status = KRB5_NO_LOCALNAME; + return GSS_S_FAILURE; + } szLocalname = malloc(localname.length + 1); if (szLocalname == NULL) { diff --git a/third_party/heimdal/lib/gssapi/mech/mech_locl.h b/third_party/heimdal/lib/gssapi/mech/mech_locl.h index 0d74091e054c..d451b87c4a71 100644 --- a/third_party/heimdal/lib/gssapi/mech/mech_locl.h +++ b/third_party/heimdal/lib/gssapi/mech/mech_locl.h @@ -35,24 +35,17 @@ #include -#include +#include -#include +#include -#include -#include -#include #include -#include -#include #include #include #include -#include - #include #include #include diff --git a/third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c index d6300006b210..6a3e8899ee76 100644 --- a/third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c +++ b/third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c @@ -171,12 +171,14 @@ _gss_ntlm_accept_sec_context output_token->value = malloc(out.length); if (output_token->value == NULL && out.length != 0) { OM_uint32 gunk; + heim_ntlm_free_buf(&out); _gss_ntlm_delete_sec_context(&gunk, context_handle, NULL); *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy(output_token->value, out.data, out.length); output_token->length = out.length; + heim_ntlm_free_buf(&out); ctx->flags = retflags; diff --git a/third_party/heimdal/lib/gssapi/ntlm/creds.c b/third_party/heimdal/lib/gssapi/ntlm/creds.c index 84a710c69e60..57940156cb59 100644 --- a/third_party/heimdal/lib/gssapi/ntlm/creds.c +++ b/third_party/heimdal/lib/gssapi/ntlm/creds.c @@ -76,10 +76,6 @@ _gss_ntlm_inquire_cred *cred_usage = 0; if (mechanisms) *mechanisms = GSS_C_NO_OID_SET; - - if (cred_handle == GSS_C_NO_CREDENTIAL) - return GSS_S_NO_CRED; - if (mechanisms) { ret = gss_create_empty_oid_set(minor_status, mechanisms); if (ret) diff --git a/third_party/heimdal/lib/gssapi/ntlm/crypto.c b/third_party/heimdal/lib/gssapi/ntlm/crypto.c index a8c670c50b28..efa71d911dcb 100644 --- a/third_party/heimdal/lib/gssapi/ntlm/crypto.c +++ b/third_party/heimdal/lib/gssapi/ntlm/crypto.c @@ -194,7 +194,10 @@ v2_sign_message(gss_buffer_t in, HMAC_CTX c; HMAC_CTX_init(&c); - HMAC_Init_ex(&c, signkey, 16, EVP_md5(), NULL); + if (HMAC_Init_ex(&c, signkey, 16, EVP_md5(), NULL) == 0) { + HMAC_CTX_cleanup(&c); + return GSS_S_FAILURE; + } encode_le_uint32(seq, hmac); HMAC_Update(&c, hmac, 4); diff --git a/third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c index 41c30b76f1a8..57587a020db3 100644 --- a/third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c +++ b/third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c @@ -39,6 +39,8 @@ OM_uint32 GSSAPI_CALLCONV _gss_ntlm_delete_sec_context gss_buffer_t output_token ) { + OM_uint32 min; + if (context_handle) { ntlm_ctx ctx = (ntlm_ctx)*context_handle; gss_cred_id_t cred = (gss_cred_id_t)ctx->client; @@ -49,6 +51,10 @@ OM_uint32 GSSAPI_CALLCONV _gss_ntlm_delete_sec_context (*ctx->server->nsi_destroy)(minor_status, ctx->ictx); _gss_ntlm_release_cred(NULL, &cred); + memset_s(ctx->sessionkey.data, ctx->sessionkey.length, 0, + ctx->sessionkey.length); + krb5_data_free(&ctx->sessionkey); + gss_release_buffer(&min, &ctx->pac); memset(ctx, 0, sizeof(*ctx)); free(ctx); diff --git a/third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c index 1063db19b0f1..be9c987c4ca0 100644 --- a/third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c +++ b/third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c @@ -56,20 +56,25 @@ from_file(const char *fn, const char *target_domain, d = strtok_r(buf, ":", &str); free(*domainp); *domainp = NULL; + if (!d) + continue; if (d && target_domain != NULL && strcasecmp(target_domain, d) != 0) continue; *domainp = strdup(d); - if (*domainp == NULL) + if (*domainp == NULL) { + fclose(f); return ENOMEM; + } u = strtok_r(NULL, ":", &str); p = strtok_r(NULL, ":", &str); if (u == NULL || p == NULL) continue; *usernamep = strdup(u); - if (*usernamep == NULL) + if (*usernamep == NULL) { + fclose(f); return ENOMEM; - + } heim_ntlm_nt_key(p, key); memset_s(buf, sizeof(buf), 0, sizeof(buf)); @@ -376,6 +381,7 @@ _gss_ntlm_init_sec_context if (RAND_bytes(nonce, sizeof(nonce)) != 1) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); *minor_status = EINVAL; return GSS_S_FAILURE; } @@ -394,6 +400,7 @@ _gss_ntlm_init_sec_context } if (ret) { _gss_ntlm_delete_sec_context(minor_status,context_handle,NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_FAILURE; } @@ -408,6 +415,7 @@ _gss_ntlm_init_sec_context if (type3.ntlm.data) free(type3.ntlm.data); _gss_ntlm_delete_sec_context(minor_status,context_handle,NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_FAILURE; } @@ -421,6 +429,7 @@ _gss_ntlm_init_sec_context if (type3.ntlm.data) free(type3.ntlm.data); _gss_ntlm_delete_sec_context(minor_status,context_handle,NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_FAILURE; } @@ -437,6 +446,7 @@ _gss_ntlm_init_sec_context if(ret) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_DEFECTIVE_TOKEN; } @@ -444,6 +454,7 @@ _gss_ntlm_init_sec_context if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); *minor_status = EINVAL; return GSS_S_FAILURE; } @@ -459,6 +470,7 @@ _gss_ntlm_init_sec_context if (ret) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_FAILURE; } @@ -470,6 +482,7 @@ _gss_ntlm_init_sec_context if (ret) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_FAILURE; } @@ -482,6 +495,7 @@ _gss_ntlm_init_sec_context if (ret) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_FAILURE; } @@ -499,6 +513,7 @@ _gss_ntlm_init_sec_context free(type3.ntlm.data); if (ret) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); *minor_status = ret; return GSS_S_FAILURE; } @@ -515,6 +530,7 @@ _gss_ntlm_init_sec_context ctx->status |= STATUS_OPEN; + heim_ntlm_free_type2(&type2); return GSS_S_COMPLETE; } } diff --git a/third_party/heimdal/lib/gssapi/ntlm/kdc.c b/third_party/heimdal/lib/gssapi/ntlm/kdc.c index e5c25596aa6d..1bce00fc5d6f 100644 --- a/third_party/heimdal/lib/gssapi/ntlm/kdc.c +++ b/third_party/heimdal/lib/gssapi/ntlm/kdc.c @@ -252,6 +252,7 @@ kdc_type2(OM_uint32 *minor_status, krb5_data ti; memset(&type2, 0, sizeof(type2)); + memset(out, 0, sizeof(*out)); /* * Request data for type 2 packet from the KDC. diff --git a/third_party/heimdal/lib/gssapi/sanon/import_name.c b/third_party/heimdal/lib/gssapi/sanon/import_name.c index 189308d96ea0..1a228b69e1a9 100644 --- a/third_party/heimdal/lib/gssapi/sanon/import_name.c +++ b/third_party/heimdal/lib/gssapi/sanon/import_name.c @@ -36,7 +36,8 @@ is_anonymous_identity_p(gss_buffer_t name_string, gss_OID name_type) { if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) return TRUE; - else if ((gss_oid_equal(name_type, GSS_C_NT_USER_NAME) || + else if ((name_type == GSS_C_NO_OID || + gss_oid_equal(name_type, GSS_C_NT_USER_NAME) || gss_oid_equal(name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) && buffer_equal_p(name_string, _gss_sanon_wellknown_user_name)) return TRUE; @@ -58,17 +59,15 @@ storage_ret_der_oid(krb5_storage *sp, gss_OID_desc *oid) oid->elements = NULL; ret = krb5_ret_uint16(sp, &der_oid_len); - if (ret != 0) + if (ret == 0) + ret = krb5_ret_uint8(sp, &tag); + if (ret == 0) + ret = krb5_ret_uint8(sp, &oid_len); + if (ret) return ret; - - ret = krb5_ret_uint8(sp, &tag); if (tag != 0x06) return EINVAL; - ret = krb5_ret_uint8(sp, &oid_len); - if (ret != 0) - return ret; - if (der_oid_len != 2 + oid_len) return EINVAL; @@ -125,10 +124,11 @@ import_export_name(OM_uint32 *minor, } if (ret == 0) ret = krb5_ret_uint32(sp, &name_len); - if (name_len != 1) - ret = EINVAL; - ret = krb5_ret_uint8(sp, &is_anonymous); + if (ret == 0) + ret = krb5_ret_uint8(sp, &is_anonymous); if (ret == 0) { + if (name_len != 1) + ret = EINVAL; if (is_anonymous == 1) { *output_name = _gss_sanon_anonymous_identity; major = GSS_S_COMPLETE; @@ -151,9 +151,6 @@ _gss_sanon_import_name(OM_uint32 *minor, const gss_OID input_name_type, gss_name_t *output_name) { - heim_assert(input_name_type != GSS_C_NO_OID, - "Mechglue passed null OID to _gss_sanon_import_name"); - if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) return import_export_name(minor, input_name_buffer, output_name); diff --git a/third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c b/third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c index 8cb4211da266..c4ac7455cf6e 100644 --- a/third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c +++ b/third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c @@ -743,6 +743,7 @@ acceptor_start } } else { *minor_status = 0; + gss_release_oid_set(&junk, &supported_mechs); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return gss_mg_set_error_string(GSS_C_NO_OID, GSS_S_NO_CONTEXT, *minor_status, diff --git a/third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c b/third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c index 13e28bb59fdd..3f8aa5c3e7b1 100644 --- a/third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c +++ b/third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c @@ -904,12 +904,14 @@ cleanup: if (GSS_ERROR(major)) { if (!mech_error) { - krb5_context context = _gss_mg_krb5_context(); - - gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, - major, *minor, - "NegoEx failed to initialize security context: %s", - krb5_get_error_message(context, *minor)); + krb5_context context = _gss_mg_krb5_context(); + const char *emsg = krb5_get_error_message(context, *minor); + + gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + major, *minor, + "NegoEx failed to initialize security context: %s", + emsg); + krb5_free_error_message(context, emsg); } _gss_negoex_release_context(ctx); @@ -1022,12 +1024,14 @@ cleanup: if (GSS_ERROR(major)) { if (!mech_error) { - krb5_context context = _gss_mg_krb5_context(); - - gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, - major, *minor, - "NegoEx failed to accept security context: %s", - krb5_get_error_message(context, *minor)); + krb5_context context = _gss_mg_krb5_context(); + const char *emsg = krb5_get_error_message(context, *minor); + + gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + major, *minor, + "NegoEx failed to accept security context: %s", + emsg); + krb5_free_error_message(context, emsg); } _gss_negoex_release_context(ctx); diff --git a/third_party/heimdal/lib/gssapi/test_context.c b/third_party/heimdal/lib/gssapi/test_context.c index 30fb5cb231f7..7446d15e0df1 100644 --- a/third_party/heimdal/lib/gssapi/test_context.c +++ b/third_party/heimdal/lib/gssapi/test_context.c @@ -56,6 +56,7 @@ static char *localname_string; static char *client_name; static char *client_password; static char *localname_string; +static char *on_behalf_of_string; static int dns_canon_flag = -1; static int mutual_auth_flag = 0; static int dce_style_flag = 0; @@ -134,6 +135,112 @@ string_to_oids(gss_OID_set *oidsetp, char *names) } } +static void +show_pac_client_info(gss_name_t n) +{ + gss_buffer_desc dv = GSS_C_EMPTY_BUFFER; + gss_buffer_desc v = GSS_C_EMPTY_BUFFER; + gss_buffer_desc a; + OM_uint32 maj, min; + int authenticated, complete, more, name_is_MN, found; + gss_OID MN_mech; + gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; + size_t i; + + krb5_error_code ret; + krb5_storage *sp = NULL; + uint16_t len = 0, *s; + uint64_t tmp; + char *logon_string = NULL; + + maj = gss_inquire_name(&min, n, &name_is_MN, &MN_mech, &attrs); + if (maj != GSS_S_COMPLETE) + errx(1, "gss_inquire_name: %s", + gssapi_err(maj, min, GSS_KRB5_MECHANISM)); + + a.value = "urn:mspac:client-info"; + a.length = sizeof("urn:mspac:client-info") - 1; + + for (found = 0, i = 0; i < attrs->count; i++) { + gss_buffer_t attr = &attrs->elements[i]; + + if (attr->length == a.length && + memcmp(attr->value, a.value, a.length) == 0) { + found++; + break; + } + } + + gss_release_buffer_set(&min, &attrs); + + if (!found) + errx(1, "gss_inquire_name: attribute %.*s not enumerated", + (int)a.length, (char *)a.value); + + more = 0; + maj = gss_get_name_attribute(&min, n, &a, &authenticated, &complete, &v, + &dv, &more); + if (maj != GSS_S_COMPLETE) + errx(1, "gss_get_name_attribute: %s", + gssapi_err(maj, min, GSS_KRB5_MECHANISM)); + + + sp = krb5_storage_from_readonly_mem(v.value, v.length); + if (sp == NULL) + errx(1, "show_pac_client_info: out of memory"); + + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + ret = krb5_ret_uint64(sp, &tmp); /* skip over time */ + if (ret == 0) + ret = krb5_ret_uint16(sp, &len); + if (ret || len == 0) + errx(1, "show_pac_client_info: invalid PAC logon info length"); + + s = malloc(len); + ret = krb5_storage_read(sp, s, len); + if (ret != len) + errx(1, "show_pac_client_info:, failed to read PAC logon name"); + + krb5_storage_free(sp); + + { + size_t ucs2len = len / 2; + uint16_t *ucs2; + size_t u8len; + unsigned int flags = WIND_RW_LE; + + ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); + if (ucs2 == NULL) + errx(1, "show_pac_client_info: out of memory"); + + ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); + free(s); + if (ret) + errx(1, "failed to convert string to UCS-2"); + + ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); + if (ret) + errx(1, "failed to count length of UCS-2 string"); + + u8len += 1; /* Add space for NUL */ + logon_string = malloc(u8len); + if (logon_string == NULL) + errx(1, "show_pac_client_info: out of memory"); + + ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len); + free(ucs2); + if (ret) + errx(1, "failed to convert to UTF-8"); + } + + printf("logon name: %s\n", logon_string); + free(logon_string); + + gss_release_buffer(&min, &dv); + gss_release_buffer(&min, &v); +} + static void loop(gss_OID mechoid, gss_OID nameoid, const char *target, @@ -155,12 +262,15 @@ loop(gss_OID mechoid, OM_uint32 flags = 0, ret_cflags = 0, ret_sflags = 0; gss_OID actual_mech_client = GSS_C_NO_OID; gss_OID actual_mech_server = GSS_C_NO_OID; - struct gss_channel_bindings_struct i_channel_bindings_data = {0}; - struct gss_channel_bindings_struct a_channel_bindings_data = {0}; + struct gss_channel_bindings_struct i_channel_bindings_data; + struct gss_channel_bindings_struct a_channel_bindings_data; gss_channel_bindings_t i_channel_bindings_p = GSS_C_NO_CHANNEL_BINDINGS; gss_channel_bindings_t a_channel_bindings_p = GSS_C_NO_CHANNEL_BINDINGS; size_t offset = 0; + memset(&i_channel_bindings_data, 0, sizeof(i_channel_bindings_data)); + memset(&a_channel_bindings_data, 0, sizeof(a_channel_bindings_data)); + *actual_mech = GSS_C_NO_OID; flags |= GSS_C_REPLAY_FLAG; @@ -188,6 +298,32 @@ loop(gss_OID mechoid, if (GSS_ERROR(maj_stat)) err(1, "import name creds failed with: %d", maj_stat); + if (on_behalf_of_string) { + AuthorizationDataElement e; + gss_buffer_desc attr, value; + int32_t kret; + size_t sz; + + memset(&e, 0, sizeof(e)); + e.ad_type = KRB5_AUTHDATA_ON_BEHALF_OF; + e.ad_data.length = strlen(on_behalf_of_string); + e.ad_data.data = on_behalf_of_string; + ASN1_MALLOC_ENCODE(AuthorizationDataElement, value.value, value.length, + &e, &sz, kret); + if (kret) + errx(1, "Could not encode AD-ON-BEHALF-OF AuthorizationDataElement"); + attr.value = + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authenticator-authz-data"; + attr.length = + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authenticator-authz-data") - 1; + maj_stat = gss_set_name_attribute(&min_stat, gss_target_name, 1, &attr, + &value); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_set_name_attribute() failed with: %s", + gssapi_err(maj_stat, min_stat, GSS_KRB5_MECHANISM)); + free(value.value); + } + input_token.length = 0; input_token.value = NULL; @@ -351,6 +487,25 @@ loop(gss_OID mechoid, errx(1, "mech mismatch"); *actual_mech = actual_mech_server; + if (on_behalf_of_string) { + gss_buffer_desc attr, value; + + attr.value = + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data#580"; + attr.length = + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data#580") - 1; + maj_stat = gss_get_name_attribute(&min_stat, src_name, &attr, NULL, + NULL, &value, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_get_name_attribute(authz-data#580) failed with %s", + gssapi_err(maj_stat, min_stat, GSS_KRB5_MECHANISM)); + + if (value.length != strlen(on_behalf_of_string) || + strncmp(value.value, on_behalf_of_string, + strlen(on_behalf_of_string)) != 0) + errx(1, "AD-ON-BEHALF-OF did not match"); + (void) gss_release_buffer(&min_stat, &value); + } if (localname_string) { gss_buffer_desc lname; @@ -393,6 +548,9 @@ loop(gss_OID mechoid, } else warnx("display_name: %s", gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + if (!anon_flag && + gss_oid_equal(actual_mech_server, GSS_KRB5_MECHANISM)) + show_pac_client_info(src_name); } gss_release_name(&min_stat, &src_name); @@ -756,6 +914,8 @@ static struct getargs args[] = { {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL }, {"max-loops", 0, arg_integer, &max_loops, "time", NULL }, {"token-split", 0, arg_integer, &token_split, "bytes", NULL }, + {"on-behalf-of", 0, arg_string, &on_behalf_of_string, "principal", + "send authenticator authz-data AD-ON-BEHALF-OF" }, {"version", 0, arg_flag, &version_flag, "print version", NULL }, {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL }, {"help", 0, arg_flag, &help_flag, NULL, NULL } @@ -1102,7 +1262,7 @@ main(int argc, char **argv) if (maj_stat != GSS_S_COMPLETE) keyblock2 = NULL; - else if (limit_enctype && keyblock->keytype != limit_enctype) + else if (limit_enctype && keyblock && keyblock->keytype != limit_enctype) errx(1, "gsskrb5_get_subkey wrong enctype"); if (keyblock || keyblock2) { @@ -1130,7 +1290,7 @@ main(int argc, char **argv) if (ret) krb5_err(context, 1, ret, "krb5_string_to_enctype"); - if (enctype != keyblock->keytype) + if (keyblock && enctype != keyblock->keytype) errx(1, "keytype is not the expected %d != %d", (int)enctype, (int)keyblock2->keytype); } diff --git a/third_party/heimdal/lib/gssapi/test_kcred.c b/third_party/heimdal/lib/gssapi/test_kcred.c index 866ee78ecf1f..abfe390449d9 100644 --- a/third_party/heimdal/lib/gssapi/test_kcred.c +++ b/third_party/heimdal/lib/gssapi/test_kcred.c @@ -102,10 +102,17 @@ copy_import(void) if (!equal) errx(1, "names not equal"); - /* FIXME: This check is racy! */ - if (lifetime1 != lifetime2) + /* + * This check is racy! It tends to fail when run with valgrind. + * + * make check-valgrind sets TESTS_ENVIRONMENT in the environment... + */ + if (getenv("TESTS_ENVIRONMENT") == NULL && lifetime1 != lifetime2) errx(1, "lifetime not equal %lu != %lu", (unsigned long)lifetime1, (unsigned long)lifetime2); + if (lifetime1 != lifetime2) + warnx("lifetime not equal %lu != %lu", + (unsigned long)lifetime1, (unsigned long)lifetime2); if (usage1 != usage2) { /* as long any of them is both are everything it ok */ @@ -127,10 +134,13 @@ copy_import(void) if (!equal) errx(1, "names not equal"); - /* FIXME: This check is racy! */ - if (lifetime1 != lifetime2) + /* This check is racy! */ + if (getenv("TESTS_ENVIRONMENT") == NULL && lifetime1 != lifetime2) errx(1, "lifetime not equal %lu != %lu", (unsigned long)lifetime1, (unsigned long)lifetime2); + if (lifetime1 != lifetime2) + warnx("lifetime not equal %lu != %lu", + (unsigned long)lifetime1, (unsigned long)lifetime2); gss_release_cred(&min_stat, &cred1); gss_release_cred(&min_stat, &cred2); diff --git a/third_party/heimdal/lib/gssapi/test_names.c b/third_party/heimdal/lib/gssapi/test_names.c index e195313505c4..933635e78c01 100644 --- a/third_party/heimdal/lib/gssapi/test_names.c +++ b/third_party/heimdal/lib/gssapi/test_names.c @@ -43,42 +43,286 @@ #include #include #include +#include #include #include +static void make_composite_name(CompositePrincipal *, gss_name_t *); +static void assert_attr(gss_name_t, const char *, OM_uint32, gss_buffer_t, + const char *, int, int, int); +static void assert_attr_unavail(gss_name_t, const char *); +static void assert_attr_set(gss_name_t, gss_buffer_set_t); + static void -gss_print_errors (int min_stat) +gss_print_errors(OM_uint32 stat, gss_OID mech) { - OM_uint32 new_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; + OM_uint32 junk; + OM_uint32 more = 0; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; OM_uint32 ret; + if (mech) { + junk = gss_oid_to_str(&junk, mech, &buf); + if (junk == GSS_S_COMPLETE) + fprintf(stderr, "mech = %.*s\n", (int)buf.length, (char *)buf.value); + gss_release_buffer(&junk, &buf); + } do { - ret = gss_display_status (&new_stat, - min_stat, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - if (!GSS_ERROR(ret)) { - fprintf (stderr, "%.*s\n", (int)status_string.length, - (char *)status_string.value); - gss_release_buffer (&new_stat, &status_string); - } - } while (!GSS_ERROR(ret) && msg_ctx != 0); + ret = gss_display_status(&junk, + stat, + mech ? GSS_C_MECH_CODE : GSS_C_GSS_CODE, + mech, + &more, + &buf); + if (ret != GSS_S_COMPLETE) + errx(1, "gss_display_status() failed"); + fprintf(stderr, "%.*s\n", (int)buf.length, (char *)buf.value); + gss_release_buffer(&junk, &buf); + } while (more); } static void -gss_err(int exitval, int status, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 5, 6))) +gss_err(int exitval, + OM_uint32 maj, + OM_uint32 min, + gss_OID mech, + const char *fmt, ...) { va_list args; va_start(args, fmt); - vwarnx (fmt, args); - gss_print_errors (status); + vwarnx(fmt, args); va_end(args); - exit (exitval); + gss_print_errors(maj, GSS_C_NO_OID); + if (mech) + gss_print_errors(min, mech); + exit(exitval); +} + +#define MAKE_URN(tail) \ + { sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN tail) - 1, \ + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN tail } + +/* + * Test RFC6680 name attributes for Kerberos. + */ +static void +check_name_attrs(void) +{ + CompositePrincipal p; + EncTicketPart *t; + gss_buffer_desc v = GSS_C_EMPTY_BUFFER; + gss_name_t n; + OM_uint32 maj, min; + int32_t ret; + gss_buffer_desc attrs[] = { + MAKE_URN("realm"), + MAKE_URN("name-ncomp"), + MAKE_URN("name-ncomp#0"), + MAKE_URN("peer-realm"), + MAKE_URN("ticket-authz-data"), + MAKE_URN("transit-path"), + MAKE_URN("canonical-name"), + }; /* Set of attributes we expect to see indicated */ + gss_buffer_set_desc attr_set; + size_t i, sz; + + memset(&p, 0, sizeof(p)); + attr_set.elements = attrs; + /* + * attr_set.count is set in each of the following sections to ever more + * items. + */ + + /* + * Testing name attributes is pretty tricky. + * + * Our approach is to construct a composite name, construct an exported + * composite name token for it, import it, then test the gss_inquire_name() + * and gss_get_name_attribute() accessors, and then gss_display_name_ext(). + * + * Ideally we'd test the accessors on names imported from query forms with + * gss_import_name(), and on names from established contexts. However, + * that belongs in the test_context program. + * + * TODO: Implement and test gss_set_name_attribute() and + * gss_delete_name_attribute(). + */ + + /* First construct and test an unauthenticated name */ + p.realm = estrdup("TEST.H5L.SE"); + p.name.name_type = KRB5_NT_PRINCIPAL; + p.name.name_string.val = ecalloc(1, sizeof(p.name.name_string.val[0])); + p.name.name_string.len = 1; + p.name.name_string.val[0] = estrdup("someuser"); + p.nameattrs = NULL; + make_composite_name(&p, &n); + + /* Test the attributes we expect it to have */ + v.length = sizeof("TEST.H5L.SE") - 1; + v.value = "TEST.H5L.SE"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "realm", GSS_S_COMPLETE, + &v, "TEST.H5L.SE", 0, 1, 0); + + i = 1; + v.length = sizeof(size_t); + v.value = &i; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp", + GSS_S_COMPLETE, &v, "1", 0, 1, 0); + + v.length = sizeof("someuser") - 1; + v.value = "someuser"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp#0", + GSS_S_COMPLETE, &v, "someuser", 0, 1, 0); + + attr_set.count = 3; + assert_attr_set(n, &attr_set); + + /* Check that it does not have prefixed attributes */ + assert_attr_unavail(n, "whatever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "realm"); + assert_attr_unavail(n, "whatever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "name-ncomp"); + assert_attr_unavail(n, "whatever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "name-ncomp#0"); + assert_attr_unavail(n, "what ever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "name-ncomp#0"); + + /* Check that it does not have various other supported attributes */ + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "peer-realm"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp#1"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "canonical-name"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "ticket-authz-data#pac"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "ticket-authz-data"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "transit-path"); + + /* Exercise URN parser */ + assert_attr_unavail(n, "urn:whatever"); + assert_attr_unavail(n, "urn:whatever#"); + assert_attr_unavail(n, "urn:what#ever"); + assert_attr_unavail(n, "#"); + assert_attr_unavail(n, "#whatever"); + assert_attr_unavail(n, "whatever"); + assert_attr_unavail(n, "what ever"); + assert_attr_unavail(n, "what ever#"); + + /* Now test an authenticated name */ + gss_release_name(&min, &n); + p.nameattrs = ecalloc(1, sizeof(p.nameattrs[0])); + p.nameattrs->authenticated = 1; + make_composite_name(&p, &n); + + v.length = sizeof("TEST.H5L.SE") - 1; + v.value = "TEST.H5L.SE"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "realm", GSS_S_COMPLETE, + &v, "TEST.H5L.SE", 1, 1, 0); + + i = 1; + v.length = sizeof(size_t); + v.value = &i; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp", + GSS_S_COMPLETE, &v, "1", 1, 1, 0); + + v.length = sizeof("someuser") - 1; + v.value = "someuser"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp#0", + GSS_S_COMPLETE, &v, "someuser", 1, 1, 0); + + assert_attr_set(n, &attr_set); + + /* Now add a peer realm */ + gss_release_name(&min, &n); + p.nameattrs->peer_realm = ecalloc(1, sizeof(p.nameattrs->peer_realm[0])); + p.nameattrs->peer_realm[0] = estrdup("FOO.TEST.H5L.SE"); + make_composite_name(&p, &n); + + v.length = sizeof("FOO.TEST.H5L.SE") - 1; + v.value = "FOO.TEST.H5L.SE"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "peer-realm", + GSS_S_COMPLETE, &v, "FOO.TEST.H5L.SE", 1, 1, 0); + attr_set.count = 4; + assert_attr_set(n, &attr_set); + + /* Now add canonical name and an authz-data element */ + gss_release_name(&min, &n); + p.nameattrs->source = ecalloc(1, sizeof(p.nameattrs->source[0])); + p.nameattrs->source->element = choice_PrincipalNameAttrSrc_enc_ticket_part; + + t = &p.nameattrs->source->u.enc_ticket_part; + t->cname.name_type = KRB5_NT_PRINCIPAL; + t->cname.name_string.val = ecalloc(1, sizeof(t->cname.name_string.val[0])); + t->crealm = estrdup("TEST.H5L.SE"); + t->cname.name_string.len = 1; + t->cname.name_string.val[0] = estrdup("realusername"); + t->authorization_data = ecalloc(1, sizeof(t->authorization_data[0])); + t->authorization_data->val = + ecalloc(1, sizeof(t->authorization_data->val[0])); + t->authorization_data->len = 1; + t->authorization_data->val[0].ad_type = + KRB5_AUTHDATA_ON_BEHALF_OF; /* whatever */ + t->authorization_data->val[0].ad_data.data = + estrdup("foobar@TEST.H5L.SE"); + t->authorization_data->val[0].ad_data.length = + sizeof("foobar@TEST.H5L.SE") - 1; + make_composite_name(&p, &n); + + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "canonical-name", + GSS_S_COMPLETE, GSS_C_NO_BUFFER, "realusername@TEST.H5L.SE", 1, + 1, 0); + + ASN1_MALLOC_ENCODE(AuthorizationData, v.value, v.length, + t->authorization_data, &sz, ret); + if (ret) + errx(1, "Failed to encode AuthorizationData"); + + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "ticket-authz-data", + GSS_S_COMPLETE, &v, NULL, 0, 1, 0); + free(v.value); + + attr_set.count = 7; + assert_attr_set(n, &attr_set); + + gss_release_name(&min, &n); + free_CompositePrincipal(&p); + + /* + * Test gss_display_name_ext() with a host-based service principal + * "host/somehost.test.h5l.se@TEST.H5L.SE". + * + * Where gss_display_name() would display this as a Kerberos principal + * name, gss_display_name_ext() with GSS_C_NT_HOSTBASED_SERVICE should + * display it as "host@somehost.test.h5l.se". + */ + p.realm = estrdup("TEST.H5L.SE"); + p.name.name_type = KRB5_NT_SRV_HST; + p.name.name_string.val = ecalloc(2, sizeof(p.name.name_string.val[0])); + p.name.name_string.len = 2; + p.name.name_string.val[0] = estrdup("host"); + p.name.name_string.val[1] = estrdup("somehost.test.h5l.se"); + p.nameattrs = NULL; + make_composite_name(&p, &n); + + maj = gss_display_name_ext(&min, n, GSS_C_NT_HOSTBASED_SERVICE, &v); + if (maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, "display name ext"); + if (v.length != sizeof("host@somehost.test.h5l.se") - 1 || + strncmp(v.value, "host@somehost.test.h5l.se", v.length) != 0) + errx(1, "display name ext"); + gss_release_buffer(&min, &v); + gss_release_name(&min, &n); + free_CompositePrincipal(&p); + + /* + * TODO: + * + * - test URN fragments for access to specific authorization data element + * types + * - test GSS_C_ATTR_LOCAL_LOGIN_USER support (requires configuration or + * that we register a plugin here) + */ } static int version_flag = 0; @@ -145,7 +389,7 @@ main(int argc, char **argv) GSS_C_NT_HOSTBASED_SERVICE, &name); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "import name error"); + gss_err(1, maj_stat, min_stat, GSS_C_NO_OID, "import name error"); free(str); if (anon_flag) @@ -158,13 +402,13 @@ main(int argc, char **argv) mech_oid, &MNname); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "canonicalize name error"); + gss_err(1, maj_stat, min_stat, mech_oid, "canonicalize name error"); maj_stat = gss_export_name(&min_stat, MNname, &name_buffer); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "export name error (KRB5)"); + gss_err(1, maj_stat, min_stat, mech_oid, "export name error"); /* * Import the exported name and compare @@ -174,13 +418,13 @@ main(int argc, char **argv) GSS_C_NT_EXPORT_NAME, &MNname2); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "import name error (exported KRB5 name)"); + gss_err(1, maj_stat, min_stat, mech_oid, "export name error"); maj_stat = gss_compare_name(&min_stat, MNname, MNname2, &equal); if (maj_stat != GSS_S_COMPLETE) - errx(1, "gss_compare_name"); - if (equal == anon_flag) + gss_err(1, maj_stat, min_stat, mech_oid, "compare name error"); + if (equal && anon_flag) errx(1, "names %s equal", anon_flag ? "incorrectly" : "not"); gss_release_name(&min_stat, &MNname2); @@ -205,13 +449,13 @@ main(int argc, char **argv) GSS_C_NO_OID, &name); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "import (no oid) name error"); + gss_err(1, maj_stat, min_stat, NULL, "import (no oid) name error"); maj_stat = gss_import_name(&min_stat, &name_buffer, GSS_KRB5_NT_USER_NAME, &MNname); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "import (krb5 mn) name error"); + gss_err(1, maj_stat, min_stat, NULL, "import (krb5 mn) name error"); free(str); @@ -230,14 +474,16 @@ main(int argc, char **argv) GSS_SPNEGO_MECHANISM, &MNname); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "canonicalize name error"); + gss_err(1, maj_stat, min_stat, GSS_SPNEGO_MECHANISM, + "canonicalize name error"); maj_stat = gss_export_name(&maj_stat, MNname, &name_buffer); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "export name error (SPNEGO)"); + gss_err(1, maj_stat, min_stat, GSS_SPNEGO_MECHANISM, + "export name error (SPNEGO)"); gss_release_name(&min_stat, &MNname); gss_release_buffer(&min_stat, &name_buffer); @@ -253,29 +499,177 @@ main(int argc, char **argv) maj_stat = gss_import_name(&min_stat, &name_buffer, GSS_C_NT_ANONYMOUS, &name); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "import (anon) name error"); + gss_err(1, maj_stat, min_stat, GSS_C_NO_OID, + "import (anon) name error"); maj_stat = gss_canonicalize_name(&min_stat, name, GSS_SANON_X25519_MECHANISM, &MNname); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "canonicalize (anon) name error"); + gss_err(1, maj_stat, min_stat, GSS_SANON_X25519_MECHANISM, + "canonicalize (anon) name error"); maj_stat = gss_display_name(&min_stat, MNname, &name_buffer, &name_type); if (maj_stat != GSS_S_COMPLETE) - gss_err(1, min_stat, "display_name (anon) name error"); + gss_err(1, maj_stat, min_stat, GSS_SANON_X25519_MECHANISM, + "display_name (anon) name error"); if (!gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) - gss_err(1, 0, "display name type not anonymous"); + errx(1, "display name type not anonymous"); if (memcmp(name_buffer.value, "WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS", sizeof("WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS") - 1) != 0) - gss_err(1, 0, "display name string not well known anonymous name"); + errx(1, "display name string not well known anonymous name"); gss_release_name(&min_stat, &MNname); gss_release_name(&min_stat, &name); gss_release_buffer(&min_stat, &name_buffer); } + check_name_attrs(); return 0; } + +/* Copied from _gsskrb5_export_name_composite() */ +static void +export_name_composite(CompositePrincipal *name, gss_buffer_t exported_name) +{ + gss_buffer_desc inner = GSS_C_EMPTY_BUFFER; + unsigned char *buf; + int32_t ret; + size_t sz; + + ASN1_MALLOC_ENCODE(CompositePrincipal, inner.value, inner.length, + (void *)name, &sz, ret); + if (ret) + errx(1, "Failed to encode exported composite name token"); + + exported_name->length = 10 + inner.length + GSS_KRB5_MECHANISM->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) + errx(1, "Failed to allocate exported composite name token"); + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + buf[0] = 0x04; + buf[1] = 0x02; + buf[2] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff; + buf[3] = (GSS_KRB5_MECHANISM->length + 2) & 0xff; + buf[4] = 0x06; + buf[5] = (GSS_KRB5_MECHANISM->length) & 0xFF; + + memcpy(buf + 6, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length); + buf += 6 + GSS_KRB5_MECHANISM->length; + + buf[0] = (inner.length >> 24) & 0xff; + buf[1] = (inner.length >> 16) & 0xff; + buf[2] = (inner.length >> 8) & 0xff; + buf[3] = (inner.length) & 0xff; + buf += 4; + + memcpy(buf, inner.value, inner.length); + free(inner.value); +} + +static void +make_composite_name(CompositePrincipal *princ, gss_name_t *n) +{ + gss_buffer_desc token, exported; + OM_uint32 maj, min; + + export_name_composite(princ, &token); + maj = gss_import_name(&min, &token, GSS_C_NT_COMPOSITE_EXPORT, n); + if (maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, "import composite name"); + maj = gss_export_name_composite(&min, *n, &exported); + if (maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, "export composite name"); + if (token.length != exported.length || + memcmp(token.value, exported.value, token.length) != 0) + errx(1, "import/export composite token disagreement"); + gss_release_buffer(&min, &exported); + free(token.value); /* Use free because we allocated this one */ +} + +static void +assert_attr(gss_name_t n, + const char *aname, + OM_uint32 exp_maj, + gss_buffer_t exp_v, + const char *exp_dv, + int exp_authenticated, + int exp_complete, + int exp_multivalued) +{ + gss_buffer_desc dv = GSS_C_EMPTY_BUFFER; + gss_buffer_desc v = GSS_C_EMPTY_BUFFER; + gss_buffer_desc a; + OM_uint32 maj, min; + int authenticated, complete, more; + + a.value = (void*)(uintptr_t)aname; + a.length = strlen(aname); + more = 0; + maj = gss_get_name_attribute(&min, n, &a, &authenticated, &complete, &v, + &dv, &more); + if (maj != GSS_S_COMPLETE && maj != exp_maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, + "import composite name error"); + if (maj == GSS_S_COMPLETE && maj != exp_maj) + errx(1, "unexpected name attribute %s", aname); + if (maj == GSS_S_COMPLETE) { + if (exp_v && + (v.length != exp_v->length || + memcmp(v.value, exp_v->value, exp_v->length) != 0)) + errx(1, "import composite name: wrong %s value", aname); + if (exp_dv && + (dv.length != strlen(exp_dv) || + strncmp(dv.value, exp_dv, dv.length) != 0)) + errx(1, "import composite name: wrong %s display value " + "(wanted %s, got %.*s)", aname, exp_dv, + (int)dv.length, (char *)dv.value); + if (authenticated != exp_authenticated) + errx(1, "import composite name: %s incorrectly marked " + "%sauthenticated", aname, authenticated ? "" : "un"); + if (complete != exp_complete) + errx(1, "import composite name: %s incorrectly marked " + "%scomplete", aname, complete ? "" : "in"); + if (more != exp_multivalued) + errx(1, "import composite name: %s incorrectly marked " + "%s-valued", aname, more ? "multi" : "single"); + } + gss_release_buffer(&min, &dv); + gss_release_buffer(&min, &v); +} + +static void +assert_attr_unavail(gss_name_t n, const char *aname) +{ + assert_attr(n, aname, GSS_S_UNAVAILABLE, GSS_C_NO_BUFFER, NULL, 0, 0, 0); +} + +static void +assert_attr_set(gss_name_t n, gss_buffer_set_t exp_as) +{ + OM_uint32 maj, min; + gss_buffer_set_t as = NULL; + gss_OID MN_mech = GSS_C_NO_OID; + size_t i; + int name_is_MN = 0; + + maj = gss_inquire_name(&min, n, &name_is_MN, &MN_mech, &as); + if (maj) + gss_err(1, maj, min, MN_mech, "inquire name"); + for (i = 0; i < as->count && i < exp_as->count; i++) { + if (as->elements[i].length != exp_as->elements[i].length || + memcmp(as->elements[i].value, exp_as->elements[i].value, + as->elements[i].length) != 0) + errx(1, "attribute sets differ"); + } + if (i < as->count) + errx(1, "more attributes indicated than expected"); + if (i < exp_as->count) + errx(1, "fewer attributes indicated than expected"); + gss_release_buffer_set(&min, &as); +} diff --git a/third_party/heimdal/lib/gssapi/version-script.map b/third_party/heimdal/lib/gssapi/version-script.map index be266da773c4..7f482b536240 100644 --- a/third_party/heimdal/lib/gssapi/version-script.map +++ b/third_party/heimdal/lib/gssapi/version-script.map @@ -4,6 +4,7 @@ HEIMDAL_GSS_2.0 { global: # __gss_c_nt_anonymous; __gss_c_nt_anonymous_oid_desc; + __gss_c_nt_composite_export_oid_desc; __gss_c_nt_export_name_oid_desc; __gss_c_nt_hostbased_service_oid_desc; __gss_c_nt_hostbased_service_x_oid_desc; @@ -44,7 +45,6 @@ HEIMDAL_GSS_2.0 { gss_export_name; gss_export_name_composite; gss_export_sec_context; - gss_get_instance; gss_get_mic; gss_get_neg_mechs; gss_get_name_attribute; diff --git a/third_party/heimdal/lib/hcrypto/Makefile.am b/third_party/heimdal/lib/hcrypto/Makefile.am index 1c610829feb3..bb36f7451907 100644 --- a/third_party/heimdal/lib/hcrypto/Makefile.am +++ b/third_party/heimdal/lib/hcrypto/Makefile.am @@ -16,6 +16,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/lib/hx509 \ WFLAGS += $(WFLAGS_LITE) -Wno-error=unused-function # XXX: Make these not necessary: WFLAGS += -Wno-error=unused-result -Wno-error=deprecated-declarations +WFLAGS += $(WFLAGS_UNUSED_BUT_SET_VAR) lib_LTLIBRARIES = libhcrypto.la check_LTLIBRARIES = libhctest.la @@ -60,8 +61,7 @@ hcryptoinclude_HEADERS = \ rsa.h \ sha.h \ ui.h \ - undef.h \ - x25519_ref10.h + undef.h install-build-headers:: $(hcryptoinclude_HEADERS) $(x25519include_HEADERS) @foo='$(hcryptoinclude_HEADERS)'; \ @@ -103,6 +103,22 @@ SCRIPT_TESTS = \ noinst_PROGRAMS = test_rand +noinst_HEADERS = \ + x25519/ed25519_ref10_fe_51.h \ + x25519/ed25519_ref10_fe_25_5.h \ + x25519/ed25519_ref10.h \ + x25519/fe_25_5/base.h \ + x25519/fe_25_5/base2.h \ + x25519/fe_25_5/constants.h \ + x25519/fe_25_5/fe.h \ + x25519/fe_51/base.h \ + x25519/fe_51/base2.h \ + x25519/fe_51/constants.h \ + x25519/fe_51/fe.h \ + x25519/align.h \ + x25519_ref10.h + + check_PROGRAMS = $(PROGRAM_TESTS) test_rsa test_dh example_evp_cipher check_SCRIPTS = $(SCRIPT_TESTS) @@ -335,7 +351,12 @@ ltmsources = \ libtommath/bn_s_mp_sqr_fast.c \ libtommath/bn_s_mp_sub.c \ libtommath/bn_s_mp_toom_mul.c \ - libtommath/bn_s_mp_toom_sqr.c + libtommath/bn_s_mp_toom_sqr.c \ + libtommath/tommath_private.h \ + libtommath/tommath_cutoffs.h \ + libtommath/tommath_superclass.h \ + libtommath/tommath_class.h \ + libtommath/tommath.h x25519sources = \ x25519/ed25519_ref10.c \ diff --git a/third_party/heimdal/lib/hcrypto/bn.c b/third_party/heimdal/lib/hcrypto/bn.c index 15bf78738adf..62297b145f10 100644 --- a/third_party/heimdal/lib/hcrypto/bn.c +++ b/third_party/heimdal/lib/hcrypto/bn.c @@ -142,7 +142,8 @@ BN_bin2bn(const void *s, int len, BIGNUM *bn) return NULL; } hi->length = len; - memcpy(hi->data, s, len); + if (len) + memcpy(hi->data, s, len); return (BIGNUM *)hi; } @@ -250,7 +251,7 @@ BN_set_bit(BIGNUM *bn, int bit) unsigned char *p; if ((bit / 8) > hi->length || hi->length == 0) { - size_t len = (bit + 7) / 8; + size_t len = bit == 0 ? 1 : (bit + 7) / 8; void *d = realloc(hi->data, len); if (d == NULL) return 0; @@ -286,6 +287,9 @@ BN_set_word(BIGNUM *bn, unsigned long num) unsigned long num2; int i, len; + if (bn == NULL) + return 0; + for (num2 = num, i = 0; num2 > 0; i++) num2 = num2 >> 8; diff --git a/third_party/heimdal/lib/hcrypto/des.c b/third_party/heimdal/lib/hcrypto/des.c index 9f5c648ec945..ac174180fb92 100644 --- a/third_party/heimdal/lib/hcrypto/des.c +++ b/third_party/heimdal/lib/hcrypto/des.c @@ -728,6 +728,7 @@ DES_cfb64_encrypt(const void *in, void *out, int i = *num; unsigned char c; + memset(tmp, 0, DES_CBLOCK_LEN); while (length > 0) { if (i == 0) { DES_encrypt(uiv, ks, 1); diff --git a/third_party/heimdal/lib/hcrypto/dh-ltm.c b/third_party/heimdal/lib/hcrypto/dh-ltm.c index 774f0e1176ab..720662199f99 100644 --- a/third_party/heimdal/lib/hcrypto/dh-ltm.c +++ b/third_party/heimdal/lib/hcrypto/dh-ltm.c @@ -40,7 +40,7 @@ #include "tommath.h" -static void +static int BN2mpz(mp_int *s, const BIGNUM *bn) { size_t len; @@ -49,8 +49,12 @@ BN2mpz(mp_int *s, const BIGNUM *bn) len = BN_num_bytes(bn); p = malloc(len); BN_bn2bin(bn, p); - mp_read_unsigned_bin(s, p, len); + if (mp_from_ubin(s, p, len) != MP_OKAY) { + free(p); + return -1; + } free(p); + return 0; } @@ -61,11 +65,14 @@ mpz2BN(mp_int *s) BIGNUM *bn; void *p; - size = mp_unsigned_bin_size(s); + size = mp_ubin_size(s); p = malloc(size); - if (p == NULL && size != 0) + if (p == NULL) + return NULL; + if (mp_to_ubin(s, p, SIZE_MAX, NULL) != MP_OKAY) { + free(p); return NULL; - mp_to_unsigned_bin(s, p); + }; bn = BN_bin2bn(p, size, NULL); free(p); @@ -110,11 +117,17 @@ ltm_dh_generate_key(DH *dh) dh->pub_key = NULL; } - mp_init_multi(&pub, &priv_key, &g, &p, NULL); + if (mp_init_multi(&pub, &priv_key, &g, &p, NULL) != MP_OKAY) + continue; - BN2mpz(&priv_key, dh->priv_key); - BN2mpz(&g, dh->g); - BN2mpz(&p, dh->p); + if (BN2mpz(&priv_key, dh->priv_key) != 0) + continue; + + if (BN2mpz(&g, dh->g) != 0) + continue; + + if (BN2mpz(&p, dh->p) != 0) + continue; res = mp_exptmod(&g, &priv_key, &p, &pub); @@ -157,9 +170,18 @@ ltm_dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh) if (dh->pub_key == NULL || dh->g == NULL || dh->priv_key == NULL) return -1; - mp_init_multi(&s, &priv_key, &p, &peer_pub, NULL); - BN2mpz(&p, dh->p); - BN2mpz(&peer_pub, pub); + if (mp_init_multi(&s, &priv_key, &p, &peer_pub, NULL) != MP_OKAY) + return -1; + + if (BN2mpz(&p, dh->p) != 0) { + ret = -1; + goto out; + } + + if (BN2mpz(&peer_pub, pub) != 0) { + ret = 1; + goto out; + } /* check if peers pubkey is reasonable */ if (mp_isneg(&peer_pub) @@ -170,17 +192,20 @@ ltm_dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh) goto out; } - BN2mpz(&priv_key, dh->priv_key); + if (BN2mpz(&priv_key, dh->priv_key) != 0) { + ret = -1; + goto out; + } ret = mp_exptmod(&peer_pub, &priv_key, &p, &s); - if (ret != 0) { ret = -1; goto out; } - ret = mp_unsigned_bin_size(&s); - mp_to_unsigned_bin(&s, shared); + ret = mp_ubin_size(&s); + if (mp_to_ubin(&s, shared, SIZE_MAX, NULL) != MP_OKAY) + ret = -1; out: mp_clear_multi(&s, &priv_key, &p, &peer_pub, NULL); diff --git a/third_party/heimdal/lib/hcrypto/dh.c b/third_party/heimdal/lib/hcrypto/dh.c index 0447c4f48384..5d2d214f7526 100644 --- a/third_party/heimdal/lib/hcrypto/dh.c +++ b/third_party/heimdal/lib/hcrypto/dh.c @@ -98,7 +98,7 @@ DH_new_method(ENGINE *engine) if (dh->engine) { dh->meth = ENGINE_get_DH(dh->engine); if (dh->meth == NULL) { - ENGINE_finish(engine); + ENGINE_finish(dh->engine); free(dh); return 0; } diff --git a/third_party/heimdal/lib/hcrypto/engine.c b/third_party/heimdal/lib/hcrypto/engine.c index 9cea24821767..3dae960fd0c8 100644 --- a/third_party/heimdal/lib/hcrypto/engine.c +++ b/third_party/heimdal/lib/hcrypto/engine.c @@ -44,15 +44,22 @@ struct hc_engine { const RSA_METHOD *rsa; const DH_METHOD *dh; const RAND_METHOD *rand; + void *dso_handle; }; -ENGINE * +ENGINE * ENGINE_new(void) { ENGINE *engine; engine = calloc(1, sizeof(*engine)); + if (engine == NULL) + return NULL; engine->references = 1; + engine->destroy = 0; + engine->dh = 0; + engine->rand = 0; + engine->dso_handle = 0; return engine; } @@ -77,6 +84,8 @@ ENGINE_finish(ENGINE *engine) free(engine->id); if(engine->destroy) (*engine->destroy)(engine); + if (engine->dso_handle) + dlclose(engine->dso_handle); memset(engine, 0, sizeof(*engine)); engine->references = -1; @@ -299,15 +308,17 @@ ENGINE_by_dso(const char *path, const char *id) { #ifdef HAVE_DLOPEN ENGINE *engine; - void *handle; int ret; engine = calloc(1, sizeof(*engine)); if (engine == NULL) return NULL; - - handle = dlopen(path, RTLD_NOW | RTLD_LOCAL | RTLD_GROUP); - if (handle == NULL) { + engine->references = 0; /* ref will be added below */ + engine->destroy = 0; + engine->dh = 0; + engine->rand = 0; + engine->dso_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL | RTLD_GROUP); + if (engine->dso_handle == NULL) { /* printf("error: %s\n", dlerror()); */ free(engine); return NULL; @@ -317,16 +328,16 @@ ENGINE_by_dso(const char *path, const char *id) unsigned long version; openssl_v_check v_check; - v_check = (openssl_v_check)dlsym(handle, "v_check"); + v_check = (openssl_v_check)dlsym(engine->dso_handle, "v_check"); if (v_check == NULL) { - dlclose(handle); + dlclose(engine->dso_handle); free(engine); return NULL; } version = (*v_check)(OPENSSL_DYNAMIC_VERSION); if (version == 0) { - dlclose(handle); + dlclose(engine->dso_handle); free(engine); return NULL; } @@ -335,16 +346,17 @@ ENGINE_by_dso(const char *path, const char *id) { openssl_bind_engine bind_engine; - bind_engine = (openssl_bind_engine)dlsym(handle, "bind_engine"); + bind_engine = + (openssl_bind_engine)dlsym(engine->dso_handle, "bind_engine"); if (bind_engine == NULL) { - dlclose(handle); + dlclose(engine->dso_handle); free(engine); return NULL; } ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */ if (ret != 1) { - dlclose(handle); + dlclose(engine->dso_handle); free(engine); return NULL; } @@ -354,7 +366,6 @@ ENGINE_by_dso(const char *path, const char *id) ret = add_engine(engine); if (ret != 1) { - dlclose(handle); ENGINE_finish(engine); return NULL; } diff --git a/third_party/heimdal/lib/hcrypto/evp.c b/third_party/heimdal/lib/hcrypto/evp.c index 23838709c8e9..9cced4c536ce 100644 --- a/third_party/heimdal/lib/hcrypto/evp.c +++ b/third_party/heimdal/lib/hcrypto/evp.c @@ -485,17 +485,20 @@ EVP_md2(void) HC_DEPRECATED_CRYPTO * */ -static void +static int null_Init (void *m) { + return 1; } -static void +static int null_Update (void *m, const void * data, size_t size) { + return 1; } -static void +static int null_Final(void *res, void *m) { + return 1; } /** diff --git a/third_party/heimdal/lib/hcrypto/hmac.c b/third_party/heimdal/lib/hcrypto/hmac.c index 6cdf4e97a4e9..6b387ae90dc7 100644 --- a/third_party/heimdal/lib/hcrypto/hmac.c +++ b/third_party/heimdal/lib/hcrypto/hmac.c @@ -85,7 +85,7 @@ HMAC_size(const HMAC_CTX *ctx) return EVP_MD_size(ctx->md); } -void +int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t keylen, @@ -103,17 +103,26 @@ HMAC_Init_ex(HMAC_CTX *ctx, ctx->md = md; ctx->key_length = EVP_MD_size(ctx->md); + ctx->opad = NULL; + ctx->ipad = NULL; + ctx->ctx = NULL; ctx->buf = malloc(ctx->key_length); - ctx->opad = malloc(blockSize); - ctx->ipad = malloc(blockSize); - ctx->ctx = EVP_MD_CTX_create(); + if (ctx->buf) + ctx->opad = malloc(blockSize); + if (ctx->opad) + ctx->ipad = malloc(blockSize); + if (ctx->ipad) + ctx->ctx = EVP_MD_CTX_create(); + if (!ctx->buf || !ctx->opad || !ctx->ipad || !ctx->ctx) + return 0; } #if 0 ctx->engine = engine; #endif if (keylen > blockSize) { - EVP_Digest(key, keylen, ctx->buf, NULL, ctx->md, engine); + if (EVP_Digest(key, keylen, ctx->buf, NULL, ctx->md, engine) == 0) + return 0; key = ctx->buf; keylen = EVP_MD_size(ctx->md); } @@ -126,8 +135,10 @@ HMAC_Init_ex(HMAC_CTX *ctx, for (i = 0, p = ctx->opad; i < keylen; i++) p[i] ^= ((const unsigned char *)key)[i]; - EVP_DigestInit_ex(ctx->ctx, ctx->md, ctx->engine); + if (EVP_DigestInit_ex(ctx->ctx, ctx->md, ctx->engine) == 0) + return 0; EVP_DigestUpdate(ctx->ctx, ctx->ipad, EVP_MD_block_size(ctx->md)); + return 1; } void @@ -156,7 +167,10 @@ HMAC(const EVP_MD *md, HMAC_CTX ctx; HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, key, key_size, md, NULL); + if (HMAC_Init_ex(&ctx, key, key_size, md, NULL) == 0) { + HMAC_CTX_cleanup(&ctx); + return NULL; + } HMAC_Update(&ctx, data, data_size); HMAC_Final(&ctx, hash, hash_len); HMAC_CTX_cleanup(&ctx); diff --git a/third_party/heimdal/lib/hcrypto/hmac.h b/third_party/heimdal/lib/hcrypto/hmac.h index 2c7d9b8803a9..cc99c879fb91 100644 --- a/third_party/heimdal/lib/hcrypto/hmac.h +++ b/third_party/heimdal/lib/hcrypto/hmac.h @@ -75,7 +75,7 @@ void HMAC_CTX_free(HMAC_CTX *ctx); size_t HMAC_size(const HMAC_CTX *ctx); -void HMAC_Init_ex(HMAC_CTX *, const void *, size_t, +int HMAC_Init_ex(HMAC_CTX *, const void *, size_t, const EVP_MD *, ENGINE *); void HMAC_Update(HMAC_CTX *ctx, const void *data, size_t len); void HMAC_Final(HMAC_CTX *ctx, void *md, unsigned int *len); diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c index a42fc70d9086..6f91b64f5034 100644 --- a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c @@ -3,7 +3,7 @@ /* LibTomMath, multiple-precision integer library -- Tom St Denis */ /* SPDX-License-Identifier: Unlicense */ -#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) +#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(_M_X86) || defined(__aarch64__) || defined(__arm__) mp_err mp_set_double(mp_int *a, double b) { uint64_t frac; diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c index 55c69390eef7..79879c35039a 100644 --- a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c @@ -96,7 +96,7 @@ static mp_err s_read_urandom(void *p, size_t n) if (fd == -1) return MP_ERR; while (n > 0u) { - ssize_t ret = read(fd, p, n); + ssize_t ret = read(fd, q, n); if (ret < 0) { if (errno == EINTR) { continue; diff --git a/third_party/heimdal/lib/hcrypto/libtommath/demo/test.c b/third_party/heimdal/lib/hcrypto/libtommath/demo/test.c index 7b29a4ce9489..9049fa81f91a 100644 --- a/third_party/heimdal/lib/hcrypto/libtommath/demo/test.c +++ b/third_party/heimdal/lib/hcrypto/libtommath/demo/test.c @@ -625,7 +625,7 @@ LBL_ERR: } -#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) +#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(_M_X86) || defined(__aarch64__) || defined(__arm__) static int test_mp_set_double(void) { int i; diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c b/third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c index bc2cdfe6e03e..e7b99fce2895 100644 --- a/third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c @@ -424,7 +424,7 @@ int main(int argc, char **argv) break; case 'h': s_exit_code = EXIT_SUCCESS; - /* FALLTHROUGH */ + /* FALLTHROUGH */ default: s_usage(argv[0]); } diff --git a/third_party/heimdal/lib/hcrypto/rsa-ltm.c b/third_party/heimdal/lib/hcrypto/rsa-ltm.c index 2852bd4d6b8a..1d5b73e60e5a 100644 --- a/third_party/heimdal/lib/hcrypto/rsa-ltm.c +++ b/third_party/heimdal/lib/hcrypto/rsa-ltm.c @@ -456,8 +456,11 @@ mpz2BN(mp_int *s) void *p; size = mp_ubin_size(s); + if (size == 0) + return NULL; + p = malloc(size); - if (p == NULL && size != 0) + if (p == NULL) return NULL; ret = mp_to_ubin(s, p, SIZE_MAX, NULL); @@ -534,8 +537,6 @@ ltm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) bitsp = (bits + 1) / 2; - ret = -1; - FIRST(mp_init_multi(&el, &p, &q, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL)); diff --git a/third_party/heimdal/lib/hcrypto/rsa.c b/third_party/heimdal/lib/hcrypto/rsa.c index c99b2b6cbe95..6172b25413f1 100644 --- a/third_party/heimdal/lib/hcrypto/rsa.c +++ b/third_party/heimdal/lib/hcrypto/rsa.c @@ -114,7 +114,7 @@ RSA_new_method(ENGINE *engine) if (rsa->engine) { rsa->meth = ENGINE_get_RSA(rsa->engine); if (rsa->meth == NULL) { - ENGINE_finish(engine); + ENGINE_finish(rsa->engine); free(rsa); return 0; } @@ -272,7 +272,10 @@ RSA_check_key(const RSA *key) * and then decrypt/verify. */ - if ((rsa->d == NULL || rsa->n == NULL) && + if (rsa->n == NULL) + return 0; + + if (rsa->d == NULL && (rsa->p == NULL || rsa->q || rsa->dmp1 == NULL || rsa->dmq1 == NULL || rsa->iqmp == NULL)) return 0; diff --git a/third_party/heimdal/lib/hcrypto/test_hmac.c b/third_party/heimdal/lib/hcrypto/test_hmac.c index 063a461cc161..36a5626a7086 100644 --- a/third_party/heimdal/lib/hcrypto/test_hmac.c +++ b/third_party/heimdal/lib/hcrypto/test_hmac.c @@ -51,7 +51,11 @@ main(int argc, char **argv) "\x6f\xd1\x52\x4d\x54\x58\x73\x0f\xf3\x24"; HMAC_CTX_init(&c); - HMAC_Init_ex(&c, hmackey, hmackey_size, EVP_sha1(), NULL); + if (HMAC_Init_ex(&c, hmackey, hmackey_size, EVP_sha1(), NULL) == 0) { + HMAC_CTX_cleanup(&c); + printf("out of memory\n"); + return 1; + } HMAC_Update(&c, buf, sizeof(buf)); HMAC_Final(&c, hmac, &hmaclen); HMAC_CTX_cleanup(&c); diff --git a/third_party/heimdal/lib/hcrypto/validate.c b/third_party/heimdal/lib/hcrypto/validate.c index 562e5aa4dd02..4b655f262c87 100644 --- a/third_party/heimdal/lib/hcrypto/validate.c +++ b/third_party/heimdal/lib/hcrypto/validate.c @@ -276,7 +276,8 @@ check_hmac(void) "\x6f\xd1\x52\x4d\x54\x58\x73\x0f\xf3\x24"; HMAC_CTX_init(&c); - HMAC_Init_ex(&c, hmackey, hmackey_size, EVP_sha1(), NULL); + if (HMAC_Init_ex(&c, hmackey, hmackey_size, EVP_sha1(), NULL) == 0) + errx(1, "HMAC_Init_ex() out of memory"); HMAC_Update(&c, buf, sizeof(buf)); HMAC_Final(&c, hmac, &hmaclen); HMAC_CTX_cleanup(&c); diff --git a/third_party/heimdal/lib/hdb/Makefile.am b/third_party/heimdal/lib/hdb/Makefile.am index 342aaffbe960..89ab15d9d3e5 100644 --- a/third_party/heimdal/lib/hdb/Makefile.am +++ b/third_party/heimdal/lib/hdb/Makefile.am @@ -2,6 +2,8 @@ include $(top_srcdir)/Makefile.am.common +WFLAGS += $(WFLAGS_ENUM_CONV) + AM_CPPFLAGS += -I../asn1 -I$(srcdir)/../asn1 AM_CPPFLAGS += $(INCLUDE_openldap) -DHDB_DB_DIR=\"$(DIR_hdbdir)\" AM_CPPFLAGS += -I$(srcdir)/../krb5 @@ -13,38 +15,40 @@ AM_CPPFLAGS += -I$(DBHEADER) endif BUILT_SOURCES = \ - $(gen_files_hdb:.x=.c) \ + $(gen_files_hdb) \ hdb_err.c \ hdb_err.h gen_files_hdb = \ - asn1_Salt.x \ - asn1_Key.x \ - asn1_Event.x \ - asn1_HDBFlags.x \ - asn1_GENERATION.x \ - asn1_HDB_Ext_PKINIT_acl.x \ - asn1_HDB_Ext_PKINIT_cert.x \ - asn1_HDB_Ext_PKINIT_hash.x \ - asn1_HDB_Ext_Constrained_delegation_acl.x \ - asn1_HDB_Ext_KeyRotation.x \ - asn1_HDB_Ext_Lan_Manager_OWF.x \ - asn1_HDB_Ext_Password.x \ - asn1_HDB_Ext_Aliases.x \ - asn1_HDB_Ext_KeySet.x \ - asn1_HDB_extension.x \ - asn1_HDB_extensions.x \ - asn1_HDB_EncTypeList.x \ - asn1_HDB_EntryOrAlias.x \ - asn1_KeyRotation.x \ - asn1_KeyRotationFlags.x \ - asn1_HDB_entry.x \ - asn1_HDB_entry_alias.x \ - asn1_HDB_keyset.x \ - asn1_Keys.x + asn1_Event.c \ + asn1_GENERATION.c \ + asn1_HDB_EncTypeList.c \ + asn1_HDB_Ext_Aliases.c \ + asn1_HDB_Ext_Constrained_delegation_acl.c \ + asn1_HDB_Ext_KeyRotation.c \ + asn1_HDB_Ext_KeySet.c \ + asn1_HDB_Ext_Lan_Manager_OWF.c \ + asn1_HDB_Ext_Password.c \ + asn1_HDB_Ext_PKINIT_acl.c \ + asn1_HDB_Ext_PKINIT_cert.c \ + asn1_HDB_Ext_PKINIT_hash.c \ + asn1_HDB_EntryOrAlias.c \ + asn1_HDB_entry_alias.c \ + asn1_HDB_entry.c \ + asn1_HDB_extension.c \ + asn1_HDB_extensions.c \ + asn1_HDB_keyset.c \ + asn1_HDBFlags.c \ + asn1_Key.c \ + asn1_KeyRotation.c \ + asn1_KeyRotationFlags.c \ + asn1_Keys.c \ + asn1_Salt.c CLEANFILES = $(BUILT_SOURCES) $(gen_files_hdb) \ - hdb_asn1{,-priv}.h* hdb_asn1_files hdb_asn1-template.[cx] + hdb_asn1{,-priv}.h hdb_asn1_files hdb_asn1-template.c \ + hdb_asn1_syms.c hdb_asn1_oids.c hdb_asn1.json \ + testhdb-* LDADD = libhdb.la \ ../krb5/libkrb5.la \ @@ -139,13 +143,14 @@ $(srcdir)/hdb-protos.h: $(dist_libhdb_la_SOURCES) $(srcdir)/hdb-private.h: $(dist_libhdb_la_SOURCES) cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -p hdb-private.h $(dist_libhdb_la_SOURCES) || rm -f hdb-private.h -$(gen_files_hdb) hdb_asn1.hx hdb_asn1-priv.hx: hdb_asn1_files +$(gen_files_hdb) hdb_asn1.h hdb_asn1-priv.h: hdb_asn1_files + for genfile in '$(gen_files_hdb)'; do \ + $(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $${genfile}; \ + done hdb_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/hdb.asn1 - $(ASN1_COMPILE) --sequence=HDB-extensions \ - --sequence=HDB-Ext-KeyRotation \ - --sequence=HDB-Ext-KeySet \ - --sequence=Keys $(srcdir)/hdb.asn1 hdb_asn1 + $(ASN1_COMPILE) --option-file=$(srcdir)/hdb.opt $(srcdir)/hdb.asn1 hdb_asn1 + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $$(cat hdb_asn1_files) # to help stupid solaris make diff --git a/third_party/heimdal/lib/hdb/NTMakefile b/third_party/heimdal/lib/hdb/NTMakefile index 5ad9d9c57424..f4801f7c54e9 100644 --- a/third_party/heimdal/lib/hdb/NTMakefile +++ b/third_party/heimdal/lib/hdb/NTMakefile @@ -31,17 +31,15 @@ RELDIR=lib\hdb -!include ../../windows/NTMakefile.w32 +intcflags=-DASN1_LIB -gen_files_hdb = $(OBJ)\asn1_hdb_asn1.x +!include ../../windows/NTMakefile.w32 -$(gen_files_hdb) $(OBJ)\hdb_asn1.hx $(OBJ)\hdb_asn1-priv.hx: $(BINDIR)\asn1_compile.exe hdb.asn1 +$(OBJ)\asn1_hdb_asn1.c $(OBJ)\hdb_asn1.h $(OBJ)\hdb_asn1-priv.h: $(BINDIR)\asn1_compile.exe hdb.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --sequence=HDB-extensions --sequence=HDB-Ext-KeyRotation --sequence=HDB-Ext-KeySet --sequence=Keys --one-code-file $(SRCDIR)\hdb.asn1 hdb_asn1 + $(BINDIR)\asn1_compile.exe --one-code-file --option-file=$(SRCDIR)\hdb.opt $(SRCDIR)\hdb.asn1 hdb_asn1 cd $(SRCDIR) -$(gen_files_hdb:.x=.c): $$(@R).x - !ifdef OPENLDAP_MODULE ldap_dll = $(BINDIR)\hdb_ldap.dll @@ -98,7 +96,7 @@ libhdb_OBJs = \ $(OBJ)\mkey.obj \ $(OBJ)\ndbm.obj \ $(OBJ)\print.obj \ - $(gen_files_hdb:.x=.obj) \ + $(OBJ)\asn1_hdb_asn1.obj \ $(OBJ)\hdb_err.obj $(OBJ)\hdb_err.c $(OBJ)\hdb_err.h: hdb_err.et diff --git a/third_party/heimdal/lib/hdb/common.c b/third_party/heimdal/lib/hdb/common.c index 251eb9b77148..a92cc1372db5 100644 --- a/third_party/heimdal/lib/hdb/common.c +++ b/third_party/heimdal/lib/hdb/common.c @@ -148,7 +148,7 @@ fetch_entry_or_alias(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, - hdb_entry_ex *entry) + hdb_entry *entry) { HDB_EntryOrAlias eoa; krb5_principal enterprise_principal = NULL; @@ -180,7 +180,7 @@ fetch_entry_or_alias(krb5_context context, if (ret == 0) ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL); if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) { - entry->entry = eoa.u.entry; + *entry = eoa.u.entry; } else if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias) { krb5_data_free(&key); ret = hdb_principal2key(context, eoa.u.alias.principal, &key); @@ -190,7 +190,7 @@ fetch_entry_or_alias(krb5_context context, } if (ret == 0) /* No alias chaining */ - ret = hdb_value2entry(context, &value, &entry->entry); + ret = hdb_value2entry(context, &value, entry); krb5_free_principal(context, eoa.u.alias.principal); } else if (ret == 0) ret = ENOTSUP; @@ -200,7 +200,7 @@ fetch_entry_or_alias(krb5_context context, * the canonicalize flag is unset, the original specification in * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should. */ - entry->entry.flags.force_canonicalize = 1; + entry->flags.force_canonicalize = 1; } /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */ @@ -208,7 +208,7 @@ fetch_entry_or_alias(krb5_context context, (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) { /* `principal' was alias but canon not req'd */ - free_HDB_entry(&entry->entry); + free_HDB_entry(entry); ret = HDB_ERR_NOENTRY; } @@ -221,7 +221,7 @@ fetch_entry_or_alias(krb5_context context, krb5_error_code _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, - unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) + unsigned flags, krb5_kvno kvno, hdb_entry *entry) { krb5_error_code ret; @@ -231,23 +231,23 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) { /* Decrypt the current keys */ - ret = hdb_unseal_keys(context, db, &entry->entry); + ret = hdb_unseal_keys(context, db, entry); if (ret) { - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); return ret; } /* Decrypt the key history too */ - ret = hdb_unseal_keys_kvno(context, db, 0, flags, &entry->entry); + ret = hdb_unseal_keys_kvno(context, db, 0, flags, entry); if (ret) { - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); return ret; } } else if ((flags & HDB_F_DECRYPT)) { - if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->entry.kvno) { + if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->kvno) { /* Decrypt the current keys */ - ret = hdb_unseal_keys(context, db, &entry->entry); + ret = hdb_unseal_keys(context, db, entry); if (ret) { - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); return ret; } } else { @@ -257,9 +257,9 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, * Find and decrypt the keys from the history that we want, * and swap them with the current keys */ - ret = hdb_unseal_keys_kvno(context, db, kvno, flags, &entry->entry); + ret = hdb_unseal_keys_kvno(context, db, kvno, flags, entry); if (ret) { - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); return ret; } } @@ -271,9 +271,9 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, * key was generated, but given the salt will be ignored by a keytab * client it doesn't hurt to include the default salt. */ - ret = add_default_salts(context, db, &entry->entry); + ret = add_default_salts(context, db, entry); if (ret) { - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); return ret; } } @@ -325,20 +325,20 @@ hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key) static krb5_error_code hdb_add_aliases(krb5_context context, HDB *db, - unsigned flags, hdb_entry_ex *entry) + unsigned flags, hdb_entry *entry) { const HDB_Ext_Aliases *aliases; krb5_error_code code; krb5_data key, value; size_t i; - code = hdb_entry_get_aliases(&entry->entry, &aliases); + code = hdb_entry_get_aliases(entry, &aliases); if (code || aliases == NULL) return code; for (i = 0; i < aliases->aliases.len; i++) { hdb_entry_alias entryalias; - entryalias.principal = entry->entry.principal; + entryalias.principal = entry->principal; code = hdb_entry_alias2value(context, &entryalias, &value); if (code) @@ -358,7 +358,7 @@ hdb_add_aliases(krb5_context context, HDB *db, /* Check if new aliases are already used for other entries */ static krb5_error_code -hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry) +hdb_check_aliases(krb5_context context, HDB *db, hdb_entry *entry) { const HDB_Ext_Aliases *aliases = NULL; HDB_EntryOrAlias eoa; @@ -370,7 +370,7 @@ hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry) krb5_data_zero(&value); akey = value; - ret = hdb_entry_get_aliases(&entry->entry, &aliases); + ret = hdb_entry_get_aliases(entry, &aliases); for (i = 0; ret == 0 && aliases && i < aliases->aliases.len; i++) { ret = hdb_principal2key(context, &aliases->aliases.val[i], &akey); if (ret == 0) @@ -385,7 +385,7 @@ hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry) ret = HDB_ERR_EXISTS; if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias && !krb5_principal_compare(context, eoa.u.alias.principal, - entry->entry.principal)) + entry->principal)) /* New alias names an existing alias of a different entry */ ret = HDB_ERR_EXISTS; if (ret == HDB_ERR_NOENTRY) /* from db->hdb__get */ @@ -433,14 +433,8 @@ hdb_derive_etypes(krb5_context context, hdb_entry *e, HDB_Ext_KeySet *base_keys) free(e->etypes->val); e->etypes->len = 0; e->etypes->val = 0; - } - - if (e->etypes == NULL && - (e->etypes = malloc(sizeof(e->etypes[0]))) == NULL) + } else if ((e->etypes = calloc(1, sizeof(e->etypes[0]))) == NULL) { ret = krb5_enomem(context); - if (ret == 0) { - e->etypes->len = 0; - e->etypes->val = 0; } if (ret == 0 && (e->etypes->val = calloc(netypes, sizeof(e->etypes->val[0]))) == NULL) @@ -465,13 +459,13 @@ hdb_derive_etypes(krb5_context context, hdb_entry *e, HDB_Ext_KeySet *base_keys) } krb5_error_code -_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { krb5_data key, value; int code; - if (entry->entry.flags.do_not_store || - entry->entry.flags.force_canonicalize) + if (entry->flags.do_not_store || + entry->flags.force_canonicalize) return HDB_ERR_MISUSE; /* check if new aliases already is used */ code = hdb_check_aliases(context, db, entry); @@ -482,7 +476,7 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) return 0; if ((flags & HDB_F_PRECHECK)) { - code = hdb_principal2key(context, entry->entry.principal, &key); + code = hdb_principal2key(context, entry->principal, &key); if (code) return code; code = db->hdb__get(context, db, key, &value); @@ -494,29 +488,31 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) return code ? code : HDB_ERR_EXISTS; } - if ((entry->entry.etypes == NULL || entry->entry.etypes->len == 0) && - (code = hdb_derive_etypes(context, &entry->entry, NULL))) + if ((entry->etypes == NULL || entry->etypes->len == 0) && + (code = hdb_derive_etypes(context, entry, NULL))) return code; - if (entry->entry.generation == NULL) { + if (entry->generation == NULL) { struct timeval t; - entry->entry.generation = malloc(sizeof(*entry->entry.generation)); - if(entry->entry.generation == NULL) { + entry->generation = malloc(sizeof(*entry->generation)); + if(entry->generation == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } gettimeofday(&t, NULL); - entry->entry.generation->time = t.tv_sec; - entry->entry.generation->usec = t.tv_usec; - entry->entry.generation->gen = 0; + entry->generation->time = t.tv_sec; + entry->generation->usec = t.tv_usec; + entry->generation->gen = 0; } else - entry->entry.generation->gen++; + entry->generation->gen++; - code = hdb_seal_keys(context, db, &entry->entry); + code = hdb_seal_keys(context, db, entry); if (code) return code; - hdb_principal2key(context, entry->entry.principal, &key); + code = hdb_principal2key(context, entry->principal, &key); + if (code) + return code; /* remove aliases */ code = hdb_remove_aliases(context, db, &key); @@ -524,8 +520,9 @@ _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) krb5_data_free(&key); return code; } - hdb_entry2value(context, &entry->entry, &value); - code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value); + code = hdb_entry2value(context, entry, &value); + if (code == 0) + code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value); krb5_data_free(&value); krb5_data_free(&key); if (code) @@ -554,8 +551,9 @@ _hdb_remove(krb5_context context, HDB *db, * HDB_entry_alias instead and assume it's an entry if decoding fails... */ - hdb_principal2key(context, principal, &key); - code = db->hdb__get(context, db, key, &value); + code = hdb_principal2key(context, principal, &key); + if (code == 0) + code = db->hdb__get(context, db, key, &value); if (code == 0) { code = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL); krb5_data_free(&value); @@ -573,7 +571,8 @@ _hdb_remove(krb5_context context, HDB *db, return code; } - code = hdb_remove_aliases(context, db, &key); + if (code == 0) + code = hdb_remove_aliases(context, db, &key); if (code == 0) code = db->hdb__del(context, db, key); krb5_data_free(&key); @@ -714,7 +713,7 @@ derive_keyset(krb5_context context, { dks->kvno = kvno; dks->keys.val = 0; - dks->set_time = malloc(sizeof(*dks->set_time)); + dks->set_time = malloc(sizeof(*(dks->set_time))); if (dks->set_time == NULL) return krb5_enomem(context); *dks->set_time = set_time; @@ -724,7 +723,7 @@ derive_keyset(krb5_context context, /* Possibly derive and install in `h' a keyset identified by `t' */ static krb5_error_code derive_keys_for_kr(krb5_context context, - hdb_entry_ex *h, + hdb_entry *h, HDB_Ext_KeySet *base_keys, int is_current_keyset, int rotation_period_offset, @@ -798,7 +797,7 @@ derive_keys_for_kr(krb5_context context, ret = derive_keyset(context, &base_keys->val[i].keys, princ, etype, kvno, set_time, &dks); if (ret == 0) - ret = hdb_install_keyset(context, &h->entry, is_current_keyset, &dks); + ret = hdb_install_keyset(context, h, is_current_keyset, &dks); free_HDB_keyset(&dks); return ret; @@ -807,7 +806,7 @@ derive_keys_for_kr(krb5_context context, /* Derive and install current keys, and possibly preceding or next keys */ static krb5_error_code derive_keys_for_current_kr(krb5_context context, - hdb_entry_ex *h, + hdb_entry *h, HDB_Ext_KeySet *base_keys, const char *princ, unsigned int flags, @@ -873,12 +872,12 @@ derive_keys_for_current_kr(krb5_context context, * Arguments: * * - `flags' is the flags passed to `hdb_fetch_kvno()' - * - `princ' is the name of the principal we'll end up with in `h->entry' + * - `princ' is the name of the principal we'll end up with in `entry' * - `h_is_namespace' indicates whether `h' is for a namespace or a concrete * principal (that might nonetheless have virtual/derived keys) * - `t' is the time such that the derived keys are for kvnos needed at `t' * - `etype' indicates what enctype to derive keys for (0 for all enctypes in - * `h->entry.etypes') + * `entry->etypes') * - `kvno' requests a particular kvno, or all if zero * * The caller doesn't know if the principal needs key derivation -- we make @@ -970,7 +969,7 @@ derive_keys(krb5_context context, krb5_timestamp t, krb5int32 etype, krb5uint32 kvno, - hdb_entry_ex *h) + hdb_entry *h) { HDB_Ext_KeyRotation kr; HDB_Ext_KeySet base_keys; @@ -979,14 +978,9 @@ derive_keys(krb5_context context, char *p = NULL; int valid = 1; - if (!h_is_namespace && !h->entry.flags.virtual_keys) + if (!h_is_namespace && !h->flags.virtual_keys) return 0; - h->entry.flags.virtual = 1; - if (h_is_namespace) { - /* Set the entry's principal name */ - free_Principal(h->entry.principal); - ret = copy_Principal(princ, h->entry.principal); - } + h->flags.virtual = 1; kr.len = 0; kr.val = 0; @@ -994,7 +988,7 @@ derive_keys(krb5_context context, const HDB_Ext_KeyRotation *ckr; /* Installing keys invalidates `ckr', so we copy it */ - ret = hdb_entry_get_key_rotation(context, &h->entry, &ckr); + ret = hdb_entry_get_key_rotation(context, h, &ckr); if (!ckr) return ret; if (ret == 0) @@ -1005,11 +999,11 @@ derive_keys(krb5_context context, base_keys.val = 0; base_keys.len = 0; if (ret == 0) - ret = hdb_remove_base_keys(context, &h->entry, &base_keys); + ret = _hdb_remove_base_keys(context, h, &base_keys, &kr); - /* Make sure we have h->entry.etypes */ - if (ret == 0 && !h->entry.etypes) - ret = hdb_derive_etypes(context, &h->entry, &base_keys); + /* Make sure we have h->etypes */ + if (ret == 0 && !h->etypes) + ret = hdb_derive_etypes(context, h, &base_keys); /* Keys not desired? Don't derive them! */ if (ret || !(flags & HDB_F_DECRYPT)) { @@ -1019,7 +1013,7 @@ derive_keys(krb5_context context, } /* The principal name will be used in key derivation and error messages */ - if (ret == 0 && h_is_namespace) + if (ret == 0) ret = krb5_unparse_name(context, princ, &p); /* Sanity check key rotations, determine current & last kr */ @@ -1101,10 +1095,10 @@ derive_keys(krb5_context context, /* * Derive and set in `h' its current kvno and current keys. * - * This will set h->entry.kvno as well. + * This will set h->kvno as well. * * This may set up to TWO keysets for the current key rotation period: - * - current keys (h->entry.keys and h->entry.kvno) + * - current keys (h->keys and h->kvno) * - possibly one future * OR * possibly one past keyset in hist_keys for the current_kr @@ -1137,14 +1131,14 @@ derive_keys(krb5_context context, kr.val[current_kr].epoch - 1, &kr.val[past_kr]); /* - * Impose a bound on h->entry.max_life so that [when the KDC is the caller] + * Impose a bound on h->max_life so that [when the KDC is the caller] * the KDC won't issue tickets longer lived than this. */ - if (ret == 0 && !h->entry.max_life && - (h->entry.max_life = malloc(sizeof(h->entry.max_life[0]))) == NULL) + if (ret == 0 && !h->max_life && + (h->max_life = calloc(1, sizeof(h->max_life[0]))) == NULL) ret = krb5_enomem(context); - if (ret == 0 && *h->entry.max_life > kr.val[current_kr].period >> 1) - *h->entry.max_life = kr.val[current_kr].period >> 1; + if (ret == 0 && *h->max_life > kr.val[current_kr].period >> 1) + *h->max_life = kr.val[current_kr].period >> 1; free_HDB_Ext_KeyRotation(&kr); free_HDB_Ext_KeySet(&base_keys); @@ -1153,6 +1147,10 @@ derive_keys(krb5_context context, } /* + * Pick a best kvno for the given principal at the given time. + * + * Implements the [hdb] new_service_key_delay configuration parameter. + * * In order for disparate keytab provisioning systems such as OSKT and our own * kadmin ext_keytab and httpkadmind's get-keys to coexist, we need to be able * to force keys set by the former to not become current keys until users of @@ -1163,9 +1161,9 @@ derive_keys(krb5_context context, * The context is that OSKT's krb5_keytab is very happy to change keys in a way * that requires all members of a cluster to rekey together. If one also * wishes to have cluster members that opt out of this and just fetch current, - * past, and future keys periodically, then the keys set by OSKT need to not - * come into effect until all the opt-out members have had a chance to fetch - * the new keys. + * past, and future keys periodically, then the keys set by OSKT must not come + * into effect until all the opt-out members have had a chance to fetch the new + * keys. * * The assumption is that services will fetch new keys periodically, say, every * four hours. Then one can set `[hdb] new_service_key_delay = 8h' in the @@ -1175,12 +1173,12 @@ derive_keys(krb5_context context, * Naturally, this applies only to concrete principals with concrete keys. */ static krb5_error_code -fix_keys(krb5_context context, - HDB *db, - unsigned flags, - krb5_timestamp now, - krb5uint32 kvno, - hdb_entry_ex *h) +pick_kvno(krb5_context context, + HDB *db, + unsigned flags, + krb5_timestamp now, + krb5uint32 kvno, + hdb_entry *h) { HDB_extension *ext; HDB_Ext_KeySet keys; @@ -1193,25 +1191,25 @@ fix_keys(krb5_context context, * delayed, or if there's no new-key delay configured, or we're not * fetching for use as a service principal, then we're out. */ - if (!(flags & HDB_F_DELAY_NEW_KEYS) || kvno || h->entry.flags.virtual || - h->entry.flags.virtual_keys || db->new_service_key_delay <= 0) + if (!(flags & HDB_F_DELAY_NEW_KEYS) || kvno || h->flags.virtual || + h->flags.virtual_keys || db->new_service_key_delay <= 0) return 0; /* No history -> current keyset is the only one and therefore the best */ - ext = hdb_find_extension(&h->entry, choice_HDB_extension_data_hist_keys); + ext = hdb_find_extension(h, choice_HDB_extension_data_hist_keys); if (!ext) return 0; /* Assume the current keyset is the best to start with */ - (void) hdb_entry_get_pw_change_time(&h->entry, ¤t); - if (current == 0 && h->entry.modified_by) - current = h->entry.modified_by->time; + (void) hdb_entry_get_pw_change_time(h, ¤t); + if (current == 0 && h->modified_by) + current = h->modified_by->time; if (current == 0) - current = h->entry.created_by.time; + current = h->created_by.time; /* Current keyset starts out as best */ best = current; - kvno = h->entry.kvno; + kvno = h->kvno; /* Look for a better keyset in the history */ keys = ext->data.u.hist_keys; @@ -1251,7 +1249,7 @@ fix_keys(krb5_context context, best = keys.val[i].set_time[0]; kvno = keys.val[i].kvno; } - return hdb_change_kvno(context, kvno, &h->entry); + return hdb_change_kvno(context, kvno, h); } /* @@ -1296,7 +1294,7 @@ make_namespace_princ(krb5_context context, /* First go around, need a namespace princ. Make it! */ ret = krb5_build_principal(context, namespace, strlen(realm), - realm, "WELLKNOWN", + realm, KRB5_WELLKNOWN_NAME, HDB_WK_NAMESPACE, comp0, NULL); if (ret == 0) ret = krb5_principal_set_comp_string(context, *namespace, 3, comp1); @@ -1307,6 +1305,138 @@ make_namespace_princ(krb5_context context, return ret; } +static int +is_namespace_princ_p(krb5_context context, + krb5_const_principal princ) +{ + return + krb5_principal_get_num_comp(context, princ) >= 4 + && strcmp(krb5_principal_get_comp_string(context, princ, 0), + KRB5_WELLKNOWN_NAME) == 0 + && strcmp(krb5_principal_get_comp_string(context, princ, 1), + HDB_WK_NAMESPACE) == 0; +} + +/* See call site */ +static krb5_error_code +rewrite_hostname(krb5_context context, + krb5_const_principal wanted_princ, + krb5_const_principal ns_princ, + krb5_const_principal found_ns_princ, + char **s) +{ + const char *ns_host_part, *wanted_host_part, *found_host_part; + const char *p, *r; + size_t ns_host_part_len, wanted_host_part_len; + + wanted_host_part = krb5_principal_get_comp_string(context, wanted_princ, 1); + wanted_host_part_len = strlen(wanted_host_part); + if (wanted_host_part_len > 256) { + krb5_set_error_message(context, HDB_ERR_NOENTRY, + "Aliases of host-based principals longer than " + "256 bytes not supported"); + return HDB_ERR_NOENTRY; + } + + ns_host_part = krb5_principal_get_comp_string(context, ns_princ, 3); + ns_host_part_len = strlen(ns_host_part); + + /* Find `ns_host_part' as the tail of `wanted_host_part' */ + for (r = p = strstr(wanted_host_part, ns_host_part); + r && strnlen(r, ns_host_part_len + 1) > ns_host_part_len; + p = (r = strstr(r, ns_host_part)) ? r : p) + ; + if (!p || strnlen(p, ns_host_part_len + 1) != ns_host_part_len) + return HDB_ERR_NOENTRY; /* Can't happen */ + if (p == wanted_host_part || p[-1] != '.') + return HDB_ERR_NOENTRY; + + found_host_part = + krb5_principal_get_comp_string(context, found_ns_princ, 3); + return + asprintf(s, "%.*s%s", (int)(p - wanted_host_part), wanted_host_part, + found_host_part) < 0 || + *s == NULL ? krb5_enomem(context) : 0; +} + +/* + * Fix `h->principal' to match the desired `princ' in the namespace + * `nsprinc' (which is either the same as `h->principal' or an alias + * of it). + */ +static krb5_error_code +fix_princ_name(krb5_context context, + krb5_const_principal princ, + krb5_const_principal nsprinc, + hdb_entry *h) +{ + krb5_error_code ret = 0; + char *s = NULL; + + if (!nsprinc) + return 0; + if (krb5_principal_get_num_comp(context, princ) < 2) + return HDB_ERR_NOENTRY; + + /* `nsprinc' must be a namespace principal */ + + if (krb5_principal_compare(context, nsprinc, h->principal)) { + /* + * `h' is the HDB entry for `nsprinc', and `nsprinc' is its canonical + * name. + * + * Set the entry's principal name to the desired name. The keys will + * be fixed next (upstairs, but don't forget to!). + */ + free_Principal(h->principal); + return copy_Principal(princ, h->principal); + } + + if (!is_namespace_princ_p(context, h->principal)) { + /* + * The alias is a namespace, but the canonical name is not. WAT. + * + * Well, the KDC will just issue a referral anyways, so we can leave + * `h->principal' as is... + * + * Remove all of `h's keys just in case, and leave + * `h->principal' as-is. + */ + free_Keys(&h->keys); + (void) hdb_entry_clear_password(context, h); + return hdb_clear_extension(context, h, + choice_HDB_extension_data_hist_keys); + } + + /* + * A namespace alias of a namespace entry. + * + * We'll want to rewrite the original principal accordingly. + * + * E.g., if the caller wanted host/foo.ns.test.h5l.se and we + * found WELLKNOWN/HOSTBASED-NAMESPACE/ns.test.h5l.se is an + * alias of WELLKNOWN/HOSTBASED-NAMESPACE/ns.example.org, then + * we'll want to treat host/foo.ns.test.h5l.se as an alias of + * host/foo.ns.example.org. + */ + if (krb5_principal_get_num_comp(context, h->principal) != + 2 + krb5_principal_get_num_comp(context, princ)) + ret = HDB_ERR_NOENTRY; /* Only host-based services for now */ + if (ret == 0) + ret = rewrite_hostname(context, princ, nsprinc, h->principal, &s); + if (ret == 0) { + krb5_free_principal(context, h->principal); + h->principal = NULL; + ret = krb5_make_principal(context, &h->principal, + krb5_principal_get_realm(context, princ), + krb5_principal_get_comp_string(context, + princ, 0), + s, + NULL); + } + return ret; +} + /* Wrapper around db->hdb_fetch_kvno() that implements virtual princs/keys */ static krb5_error_code fetch_it(krb5_context context, @@ -1316,10 +1446,10 @@ fetch_it(krb5_context context, krb5_timestamp t, krb5int32 etype, krb5uint32 kvno, - hdb_entry_ex *ent) + hdb_entry *ent) { krb5_const_principal tmpprinc = princ; - krb5_principal baseprinc = NULL; + krb5_principal nsprinc = NULL; krb5_error_code ret = 0; const char *comp0 = krb5_principal_get_comp_string(context, princ, 0); const char *comp1 = krb5_principal_get_comp_string(context, princ, 1); @@ -1330,8 +1460,10 @@ fetch_it(krb5_context context, char *host = NULL; int do_search = 0; + if (!db->enable_virtual_hostbased_princs) + maxdots = mindots = 0; if (db->enable_virtual_hostbased_princs && comp1 && - strcmp("krbtgt", comp0) != 0 && strcmp("WELLKNOWN", comp0) != 0) { + strcmp("krbtgt", comp0) != 0 && strcmp(KRB5_WELLKNOWN_NAME, comp0) != 0) { char *htmp; if ((host = strdup(comp1)) == NULL) @@ -1358,7 +1490,7 @@ fetch_it(krb5_context context, } tmp = host ? host : comp1; - for (ret = HDB_ERR_NOENTRY; ret == HDB_ERR_NOENTRY; tmpprinc = baseprinc) { + for (ret = HDB_ERR_NOENTRY; ret == HDB_ERR_NOENTRY; tmpprinc = nsprinc) { krb5_error_code ret2 = 0; /* @@ -1376,7 +1508,7 @@ fetch_it(krb5_context context, ret = db->hdb_fetch_kvno(context, db, tmpprinc, flags, kvno, ent); if (ret != HDB_ERR_NOENTRY || hdots == 0 || hdots < mindots || !tmp || !do_search) - break; + break; /* * Breadcrumb: @@ -1398,17 +1530,22 @@ fetch_it(krb5_context context, */ while (maxdots && hdots > maxdots && tmp) { tmp = strchr(tmp, '.'); - /* tmp != NULL because maxdots > 0 */ + /* tmp != NULL because maxdots > 0; we check to quiet linters */ + if (tmp == NULL) { + ret = HDB_ERR_NOENTRY; + goto out; + } tmp++; hdots--; } - if (baseprinc == NULL) + if (nsprinc == NULL) /* First go around, need a namespace princ. Make it! */ - ret2 = make_namespace_princ(context, db, tmpprinc, &baseprinc); - /* Update the hostname component */ + ret2 = make_namespace_princ(context, db, tmpprinc, &nsprinc); + + /* Update the hostname component of the namespace principal */ if (ret2 == 0) - ret2 = krb5_principal_set_comp_string(context, baseprinc, 3, tmp); + ret2 = krb5_principal_set_comp_string(context, nsprinc, 3, tmp); if (ret2) ret = ret2; @@ -1425,14 +1562,22 @@ fetch_it(krb5_context context, * key derivation to do, but that's decided in derive_keys(). */ if (ret == 0) { - ret = derive_keys(context, flags, princ, !!baseprinc, t, etype, kvno, - ent); + /* Fix the principal name if namespaced */ + ret = fix_princ_name(context, princ, nsprinc, ent); + + /* Derive keys if namespaced or virtual */ if (ret == 0) - ret = fix_keys(context, db, flags, t, kvno, ent); - if (ret) - hdb_free_entry(context, ent); + ret = derive_keys(context, flags, princ, !!nsprinc, t, etype, kvno, + ent); + /* Pick the best kvno for this principal at the given time */ + if (ret == 0) + ret = pick_kvno(context, db, flags, t, kvno, ent); } - krb5_free_principal(context, baseprinc); + +out: + if (ret != 0 && ret != HDB_ERR_WRONG_REALM) + hdb_free_entry(context, db, ent); + krb5_free_principal(context, nsprinc); free(host); return ret; } @@ -1468,7 +1613,7 @@ hdb_fetch_kvno(krb5_context context, krb5_timestamp t, krb5int32 etype, krb5uint32 kvno, - hdb_entry_ex *h) + hdb_entry *h) { krb5_error_code ret = HDB_ERR_NOENTRY; @@ -1485,8 +1630,8 @@ hdb_fetch_kvno(krb5_context context, * independently of principal aliases (used by Samba). */ if (ret == 0 && !(flags & HDB_F_ADMIN_DATA) && - !h->entry.flags.force_canonicalize && - !krb5_realm_compare(context, principal, h->entry.principal)) + !h->flags.force_canonicalize && + !krb5_realm_compare(context, principal, h->principal)) ret = HDB_ERR_WRONG_REALM; return ret; } diff --git a/third_party/heimdal/lib/hdb/db.c b/third_party/heimdal/lib/hdb/db.c index 6e415b95f169..5fcce7b8e8b3 100644 --- a/third_party/heimdal/lib/hdb/db.c +++ b/third_party/heimdal/lib/hdb/db.c @@ -114,7 +114,7 @@ DB_unlock(krb5_context context, HDB *db) static krb5_error_code DB_seq(krb5_context context, HDB *db, - unsigned flags, hdb_entry_ex *entry, int flag) + unsigned flags, hdb_entry *entry, int flag) { DB *d = (DB*)db->hdb_db; DBT key, value; @@ -138,21 +138,21 @@ DB_seq(krb5_context context, HDB *db, data.data = value.data; data.length = value.size; memset(entry, 0, sizeof(*entry)); - if (hdb_value2entry(context, &data, &entry->entry)) + if (hdb_value2entry(context, &data, entry)) return DB_seq(context, db, flags, entry, R_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); + code = hdb_unseal_keys (context, db, entry); if (code) - hdb_free_entry (context, entry); + hdb_free_entry (context, db, entry); } - if (code == 0 && entry->entry.principal == NULL) { - entry->entry.principal = malloc(sizeof(*entry->entry.principal)); - if (entry->entry.principal == NULL) { + if (code == 0 && entry->principal == NULL) { + entry->principal = malloc(sizeof(*entry->principal)); + if (entry->principal == NULL) { code = ENOMEM; krb5_set_error_message(context, code, "malloc: out of memory"); - hdb_free_entry (context, entry); + hdb_free_entry (context, db, entry); } else { - hdb_key2principal(context, &key_data, entry->entry.principal); + hdb_key2principal(context, &key_data, entry->principal); } } return code; @@ -160,14 +160,14 @@ DB_seq(krb5_context context, HDB *db, static krb5_error_code -DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return DB_seq(context, db, flags, entry, R_FIRST); } static krb5_error_code -DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return DB_seq(context, db, flags, entry, R_NEXT); } diff --git a/third_party/heimdal/lib/hdb/db3.c b/third_party/heimdal/lib/hdb/db3.c index 0daa25bbec46..9d0c0a97d9ab 100644 --- a/third_party/heimdal/lib/hdb/db3.c +++ b/third_party/heimdal/lib/hdb/db3.c @@ -136,7 +136,7 @@ DB_unlock(krb5_context context, HDB *db) static krb5_error_code DB_seq(krb5_context context, HDB *db, - unsigned flags, hdb_entry_ex *entry, int flag) + unsigned flags, hdb_entry *entry, int flag) { DBT key, value; DBC *dbcp = db->hdb_dbc; @@ -156,21 +156,21 @@ DB_seq(krb5_context context, HDB *db, data.data = value.data; data.length = value.size; memset(entry, 0, sizeof(*entry)); - if (hdb_value2entry(context, &data, &entry->entry)) + if (hdb_value2entry(context, &data, entry)) return DB_seq(context, db, flags, entry, DB_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); + code = hdb_unseal_keys (context, db, entry); if (code) - hdb_free_entry (context, entry); + hdb_free_entry (context, db, entry); } - if (entry->entry.principal == NULL) { - entry->entry.principal = malloc(sizeof(*entry->entry.principal)); - if (entry->entry.principal == NULL) { - hdb_free_entry (context, entry); + if (entry->principal == NULL) { + entry->principal = malloc(sizeof(*entry->principal)); + if (entry->principal == NULL) { + hdb_free_entry (context, db, entry); krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } else { - hdb_key2principal(context, &key_data, entry->entry.principal); + hdb_key2principal(context, &key_data, entry->principal); } } return 0; @@ -178,14 +178,14 @@ DB_seq(krb5_context context, HDB *db, static krb5_error_code -DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return DB_seq(context, db, flags, entry, DB_FIRST); } static krb5_error_code -DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return DB_seq(context, db, flags, entry, DB_NEXT); } diff --git a/third_party/heimdal/lib/hdb/ext.c b/third_party/heimdal/lib/hdb/ext.c index ec52d35dcba7..48683ef1607f 100644 --- a/third_party/heimdal/lib/hdb/ext.c +++ b/third_party/heimdal/lib/hdb/ext.c @@ -712,7 +712,7 @@ hdb_entry_add_key_rotation(krb5_context context, { krb5_error_code ret; HDB_extension new_ext; - HDB_extension *ext = 0; + HDB_extension *ext = &new_ext; KeyRotation tmp; size_t i, sz; @@ -734,8 +734,6 @@ hdb_entry_add_key_rotation(krb5_context context, ext = hdb_find_extension(entry, choice_HDB_extension_data_key_rotation); if (!ext) ext = &new_ext; - else - krs = &ext->data.u.key_rotation; } else { const KeyRotation *prev_kr = &krs->val[0]; unsigned int last_kvno = 0; diff --git a/third_party/heimdal/lib/hdb/hdb-keytab.c b/third_party/heimdal/lib/hdb/hdb-keytab.c index f3cb8fbe61da..c9b469cb1a85 100644 --- a/third_party/heimdal/lib/hdb/hdb-keytab.c +++ b/third_party/heimdal/lib/hdb/hdb-keytab.c @@ -90,14 +90,14 @@ hkt_unlock(krb5_context context, HDB *db) static krb5_error_code hkt_firstkey(krb5_context context, HDB *db, - unsigned flags, hdb_entry_ex *entry) + unsigned flags, hdb_entry *entry) { return HDB_ERR_DB_INUSE; } static krb5_error_code hkt_nextkey(krb5_context context, HDB * db, unsigned flags, - hdb_entry_ex * entry) + hdb_entry * entry) { return HDB_ERR_DB_INUSE; } @@ -119,7 +119,7 @@ hkt_open(krb5_context context, HDB * db, int flags, mode_t mode) static krb5_error_code hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, - unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry) + unsigned flags, krb5_kvno kvno, hdb_entry * entry) { hdb_keytab k = (hdb_keytab)db->hdb_db; krb5_error_code ret; @@ -132,13 +132,13 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, memset(&ktentry, 0, sizeof(ktentry)); - entry->entry.flags.server = 1; - entry->entry.flags.forwardable = 1; - entry->entry.flags.renewable = 1; + entry->flags.server = 1; + entry->flags.forwardable = 1; + entry->flags.renewable = 1; /* Not recorded in the OD backend, make something up */ ret = krb5_parse_name(context, "hdb/keytab@WELL-KNOWN:KEYTAB-BACKEND", - &entry->entry.created_by.principal); + &entry->created_by.principal); if (ret) goto out; @@ -155,7 +155,7 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, goto out; } - ret = krb5_copy_principal(context, principal, &entry->entry.principal); + ret = krb5_copy_principal(context, principal, &entry->principal); if (ret) goto out; @@ -163,8 +163,8 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, out: if (ret) { - free_HDB_entry(&entry->entry); - memset(&entry->entry, 0, sizeof(entry->entry)); + free_HDB_entry(entry); + memset(entry, 0, sizeof(*entry)); } krb5_kt_free_entry(context, &ktentry); @@ -173,7 +173,7 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, static krb5_error_code hkt_store(krb5_context context, HDB * db, unsigned flags, - hdb_entry_ex * entry) + hdb_entry * entry) { return HDB_ERR_DB_INUSE; } diff --git a/third_party/heimdal/lib/hdb/hdb-ldap.c b/third_party/heimdal/lib/hdb/hdb-ldap.c index 1dbb00d3e5f7..6a2876c51d71 100644 --- a/third_party/heimdal/lib/hdb/hdb-ldap.c +++ b/third_party/heimdal/lib/hdb/hdb-ldap.c @@ -47,7 +47,7 @@ static krb5_error_code LDAP_close(krb5_context context, HDB *); static krb5_error_code LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, - int flags, hdb_entry_ex * ent); + int flags, hdb_entry * ent); static const char *default_structural_object = "account"; static char *structural_object; @@ -388,14 +388,14 @@ bervalstrcmp(struct berval *v, const char *str) static krb5_error_code -LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, +LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry * ent, LDAPMessage * msg, LDAPMod *** pmods, krb5_boolean *pis_new_entry) { krb5_error_code ret; krb5_boolean is_new_entry = FALSE; char *tmp = NULL; LDAPMod **mods = NULL; - hdb_entry_ex orig; + hdb_entry orig; unsigned long oflags, nflags; int i; @@ -477,12 +477,12 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } if (is_new_entry || - krb5_principal_compare(context, ent->entry.principal, orig.entry.principal) + krb5_principal_compare(context, ent->principal, orig.principal) == FALSE) { if (is_heimdal_principal || is_heimdal_entry) { - ret = krb5_unparse_name(context, ent->entry.principal, &tmp); + ret = krb5_unparse_name(context, ent->principal, &tmp); if (ret) goto out; @@ -496,7 +496,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } if (is_account || is_samba_account) { - ret = krb5_unparse_name_short(context, ent->entry.principal, &tmp); + ret = krb5_unparse_name_short(context, ent->principal, &tmp); if (ret) goto out; ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp); @@ -508,15 +508,15 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } } - if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) { + if (is_heimdal_entry && (ent->kvno != orig.kvno || is_new_entry)) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "krb5KeyVersionNumber", - ent->entry.kvno); + ent->kvno); if (ret) goto out; } - if (is_heimdal_entry && ent->entry.extensions) { + if (is_heimdal_entry && ent->extensions) { if (!is_new_entry) { vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes"); if (vals) { @@ -527,11 +527,11 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } } - for (i = 0; i < ent->entry.extensions->len; i++) { + for (i = 0; i < ent->extensions->len; i++) { unsigned char *buf; size_t size, sz = 0; - ASN1_MALLOC_ENCODE(HDB_extension, buf, size, &ent->entry.extensions->val[i], &sz, ret); + ASN1_MALLOC_ENCODE(HDB_extension, buf, size, &ent->extensions->val[i], &sz, ret); if (ret) goto out; if (size != sz) @@ -543,42 +543,42 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } } - if (is_heimdal_entry && ent->entry.valid_start) { - if (orig.entry.valid_end == NULL - || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) { + if (is_heimdal_entry && ent->valid_start) { + if (orig.valid_end == NULL + || (*(ent->valid_start) != *(orig.valid_start))) { ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, "krb5ValidStart", - ent->entry.valid_start); + ent->valid_start); if (ret) goto out; } } - if (ent->entry.valid_end) { - if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) { + if (ent->valid_end) { + if (orig.valid_end == NULL || (*(ent->valid_end) != *(orig.valid_end))) { if (is_heimdal_entry) { ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, "krb5ValidEnd", - ent->entry.valid_end); + ent->valid_end); if (ret) goto out; } if (is_samba_account) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "sambaKickoffTime", - *(ent->entry.valid_end)); + *(ent->valid_end)); if (ret) goto out; } } } - if (ent->entry.pw_end) { - if (orig.entry.pw_end == NULL || (*(ent->entry.pw_end) != *(orig.entry.pw_end))) { + if (ent->pw_end) { + if (orig.pw_end == NULL || (*(ent->pw_end) != *(orig.pw_end))) { if (is_heimdal_entry) { ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, "krb5PasswordEnd", - ent->entry.pw_end); + ent->pw_end); if (ret) goto out; } @@ -586,7 +586,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, if (is_samba_account) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "sambaPwdMustChange", - *(ent->entry.pw_end)); + *(ent->pw_end)); if (ret) goto out; } @@ -595,43 +595,43 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, #if 0 /* we we have last_pw_change */ - if (is_samba_account && ent->entry.last_pw_change) { - if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) { + if (is_samba_account && ent->last_pw_change) { + if (orig.last_pw_change == NULL || (*(ent->last_pw_change) != *(orig.last_pw_change))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "sambaPwdLastSet", - *(ent->entry.last_pw_change)); + *(ent->last_pw_change)); if (ret) goto out; } } #endif - if (is_heimdal_entry && ent->entry.max_life) { - if (orig.entry.max_life == NULL - || (*(ent->entry.max_life) != *(orig.entry.max_life))) { + if (is_heimdal_entry && ent->max_life) { + if (orig.max_life == NULL + || (*(ent->max_life) != *(orig.max_life))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "krb5MaxLife", - *(ent->entry.max_life)); + *(ent->max_life)); if (ret) goto out; } } - if (is_heimdal_entry && ent->entry.max_renew) { - if (orig.entry.max_renew == NULL - || (*(ent->entry.max_renew) != *(orig.entry.max_renew))) { + if (is_heimdal_entry && ent->max_renew) { + if (orig.max_renew == NULL + || (*(ent->max_renew) != *(orig.max_renew))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, "krb5MaxRenew", - *(ent->entry.max_renew)); + *(ent->max_renew)); if (ret) goto out; } } - oflags = HDBFlags2int(orig.entry.flags); - nflags = HDBFlags2int(ent->entry.flags); + oflags = HDBFlags2int(orig.flags); + nflags = HDBFlags2int(ent->flags); if (is_heimdal_entry && oflags != nflags) { @@ -643,7 +643,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } /* Remove keys if they exists, and then replace keys. */ - if (!is_new_entry && orig.entry.keys.len > 0) { + if (!is_new_entry && orig.keys.len > 0) { vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); if (vals) { ldap_value_free_len(vals); @@ -654,21 +654,21 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } } - for (i = 0; i < ent->entry.keys.len; i++) { + for (i = 0; i < ent->keys.len; i++) { if (is_samba_account - && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { + && ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { char *ntHexPassword; char *nt; time_t now = time(NULL); /* the key might have been 'sealed', but samba passwords are clear in the directory */ - ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]); + ret = hdb_unseal_key(context, db, &ent->keys.val[i]); if (ret) goto out; - nt = ent->entry.keys.val[i].key.keyvalue.data; + nt = ent->keys.val[i].key.keyvalue.data; /* store in ntPassword, not krb5key */ ret = hex_encode(nt, 16, &ntHexPassword); if (ret < 0) { @@ -701,7 +701,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, unsigned char *buf; size_t len, buf_size; - ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->entry.keys.val[i], &len, ret); + ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->keys.val[i], &len, ret); if (ret) goto out; if(buf_size != len) @@ -714,7 +714,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } } - if (ent->entry.etypes) { + if (ent->etypes) { int add_krb5EncryptionType = 0; /* @@ -736,15 +736,15 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, add_krb5EncryptionType = 1; if (add_krb5EncryptionType) { - for (i = 0; i < ent->entry.etypes->len; i++) { + for (i = 0; i < ent->etypes->len; i++) { if (is_samba_account && - ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) + ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { ; } else if (is_heimdal_entry) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD, "krb5EncryptionType", - ent->entry.etypes->val[i]); + ent->etypes->val[i]); if (ret) goto out; } @@ -767,7 +767,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } if (msg) - hdb_free_entry(context, &orig); + hdb_free_entry(context, db, &orig); return ret; } @@ -1005,7 +1005,7 @@ LDAP_principal2message(krb5_context context, HDB * db, */ static krb5_error_code LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, - int flags, hdb_entry_ex * ent) + int flags, hdb_entry * ent) { char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL; char *samba_acct_flags = NULL; @@ -1015,18 +1015,18 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, int tmp, tmp_time, i, ret, have_arcfour = 0; memset(ent, 0, sizeof(*ent)); - ent->entry.flags = int2HDBFlags(0); + ent->flags = int2HDBFlags(0); ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name); if (ret == 0) { - ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal); + ret = krb5_parse_name(context, unparsed_name, &ent->principal); if (ret) goto out; } else { ret = LDAP_get_string_value(db, msg, "uid", &unparsed_name); if (ret == 0) { - ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal); + ret = krb5_parse_name(context, unparsed_name, &ent->principal); if (ret) goto out; } else { @@ -1042,25 +1042,25 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber", &integer); if (ret) - ent->entry.kvno = 0; + ent->kvno = 0; else - ent->entry.kvno = integer; + ent->kvno = integer; } keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); if (keys != NULL) { size_t l; - ent->entry.keys.len = ldap_count_values_len(keys); - ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key)); - if (ent->entry.keys.val == NULL) { + ent->keys.len = ldap_count_values_len(keys); + ent->keys.val = (Key *) calloc(ent->keys.len, sizeof(Key)); + if (ent->keys.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "calloc: out of memory"); goto out; } - for (i = 0; i < ent->entry.keys.len; i++) { + for (i = 0; i < ent->keys.len; i++) { decode_Key((unsigned char *) keys[i]->bv_val, - (size_t) keys[i]->bv_len, &ent->entry.keys.val[i], &l); + (size_t) keys[i]->bv_len, &ent->keys.val[i], &l); } ber_bvecfree(keys); } else { @@ -1070,8 +1070,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, * be related to a general directory entry without creating * the keys. Hopefully it's OK. */ - ent->entry.keys.len = 0; - ent->entry.keys.val = NULL; + ent->keys.len = 0; + ent->keys.val = NULL; #else ret = HDB_ERR_NOENTRY; goto out; @@ -1082,47 +1082,47 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, if (extensions != NULL) { size_t l; - ent->entry.extensions = calloc(1, sizeof(*(ent->entry.extensions))); - if (ent->entry.extensions == NULL) { + ent->extensions = calloc(1, sizeof(*(ent->extensions))); + if (ent->extensions == NULL) { ret = krb5_enomem(context); goto out; } - ent->entry.extensions->len = ldap_count_values_len(extensions); - ent->entry.extensions->val = (HDB_extension *) calloc(ent->entry.extensions->len, sizeof(HDB_extension)); - if (ent->entry.extensions->val == NULL) { - ent->entry.extensions->len = 0; + ent->extensions->len = ldap_count_values_len(extensions); + ent->extensions->val = (HDB_extension *) calloc(ent->extensions->len, sizeof(HDB_extension)); + if (ent->extensions->val == NULL) { + ent->extensions->len = 0; ret = krb5_enomem(context); goto out; } - for (i = 0; i < ent->entry.extensions->len; i++) { + for (i = 0; i < ent->extensions->len; i++) { ret = decode_HDB_extension((unsigned char *) extensions[i]->bv_val, - (size_t) extensions[i]->bv_len, &ent->entry.extensions->val[i], &l); + (size_t) extensions[i]->bv_len, &ent->extensions->val[i], &l); if (ret) krb5_set_error_message(context, ret, "decode_HDB_extension failed"); } ber_bvecfree(extensions); } else { - ent->entry.extensions = NULL; + ent->extensions = NULL; } vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); if (vals != NULL) { - ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes))); - if (ent->entry.etypes == NULL) { + ent->etypes = malloc(sizeof(*(ent->etypes))); + if (ent->etypes == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret,"malloc: out of memory"); goto out; } - ent->entry.etypes->len = ldap_count_values_len(vals); - ent->entry.etypes->val = calloc(ent->entry.etypes->len, - sizeof(ent->entry.etypes->val[0])); - if (ent->entry.etypes->val == NULL) { + ent->etypes->len = ldap_count_values_len(vals); + ent->etypes->val = calloc(ent->etypes->len, + sizeof(ent->etypes->val[0])); + if (ent->etypes->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); - ent->entry.etypes->len = 0; + ent->etypes->len = 0; goto out; } - for (i = 0; i < ent->entry.etypes->len; i++) { + for (i = 0; i < ent->etypes->len; i++) { char *buf; buf = malloc(vals[i]->bv_len + 1); @@ -1133,14 +1133,14 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, } memcpy(buf, vals[i]->bv_val, vals[i]->bv_len); buf[vals[i]->bv_len] = '\0'; - ent->entry.etypes->val[i] = atoi(buf); + ent->etypes->val[i] = atoi(buf); free(buf); } ldap_value_free_len(vals); } - for (i = 0; i < ent->entry.keys.len; i++) { - if (ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { + for (i = 0; i < ent->keys.len; i++) { + if (ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { have_arcfour = 1; break; } @@ -1152,146 +1152,151 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, unsigned *etypes; Key *ks; - ks = realloc(ent->entry.keys.val, - (ent->entry.keys.len + 1) * - sizeof(ent->entry.keys.val[0])); + ks = realloc(ent->keys.val, + (ent->keys.len + 1) * + sizeof(ent->keys.val[0])); if (ks == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } - ent->entry.keys.val = ks; - memset(&ent->entry.keys.val[ent->entry.keys.len], 0, sizeof(Key)); - ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; - ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16); + ent->keys.val = ks; + memset(&ent->keys.val[ent->keys.len], 0, sizeof(Key)); + ent->keys.val[ent->keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; + ret = krb5_data_alloc (&ent->keys.val[ent->keys.len].key.keyvalue, 16); if (ret) { krb5_set_error_message(context, ret, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = hex_decode(ntPasswordIN, - ent->entry.keys.val[ent->entry.keys.len].key.keyvalue.data, 16); - ent->entry.keys.len++; - - if (ent->entry.etypes == NULL) { - ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes))); - if (ent->entry.etypes == NULL) { + ent->keys.val[ent->keys.len].key.keyvalue.data, 16); + ent->keys.len++; + if (ret == -1) { + krb5_set_error_message(context, ret = EINVAL, + "invalid hex encoding of password"); + goto out; + } + + if (ent->etypes == NULL) { + ent->etypes = malloc(sizeof(*(ent->etypes))); + if (ent->etypes == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } - ent->entry.etypes->val = NULL; - ent->entry.etypes->len = 0; + ent->etypes->val = NULL; + ent->etypes->len = 0; } - for (i = 0; i < ent->entry.etypes->len; i++) - if (ent->entry.etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5) + for (i = 0; i < ent->etypes->len; i++) + if (ent->etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5) break; /* If there is no ARCFOUR enctype, add one */ - if (i == ent->entry.etypes->len) { - etypes = realloc(ent->entry.etypes->val, - (ent->entry.etypes->len + 1) * - sizeof(ent->entry.etypes->val[0])); + if (i == ent->etypes->len) { + etypes = realloc(ent->etypes->val, + (ent->etypes->len + 1) * + sizeof(ent->etypes->val[0])); if (etypes == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } - ent->entry.etypes->val = etypes; - ent->entry.etypes->val[ent->entry.etypes->len] = + ent->etypes->val = etypes; + ent->etypes->val[ent->etypes->len] = ETYPE_ARCFOUR_HMAC_MD5; - ent->entry.etypes->len++; + ent->etypes->len++; } } ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp", - &ent->entry.created_by.time); + &ent->created_by.time); if (ret) - ent->entry.created_by.time = time(NULL); + ent->created_by.time = time(NULL); - ent->entry.created_by.principal = NULL; + ent->created_by.principal = NULL; if (flags & HDB_F_ADMIN_DATA) { ret = LDAP_get_string_value(db, msg, "creatorsName", &dn); if (ret == 0) { - LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal); + LDAP_dn2principal(context, db, dn, &ent->created_by.principal); free(dn); } - ent->entry.modified_by = calloc(1, sizeof(*ent->entry.modified_by)); - if (ent->entry.modified_by == NULL) { + ent->modified_by = calloc(1, sizeof(*ent->modified_by)); + if (ent->modified_by == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp", - &ent->entry.modified_by->time); + &ent->modified_by->time); if (ret == 0) { ret = LDAP_get_string_value(db, msg, "modifiersName", &dn); if (ret == 0) { - LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal); + LDAP_dn2principal(context, db, dn, &ent->modified_by->principal); free(dn); } else { - free(ent->entry.modified_by); - ent->entry.modified_by = NULL; + free(ent->modified_by); + ent->modified_by = NULL; } } } - ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start)); - if (ent->entry.valid_start == NULL) { + ent->valid_start = malloc(sizeof(*ent->valid_start)); + if (ent->valid_start == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart", - ent->entry.valid_start); + ent->valid_start); if (ret) { /* OPTIONAL */ - free(ent->entry.valid_start); - ent->entry.valid_start = NULL; + free(ent->valid_start); + ent->valid_start = NULL; } - ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end)); - if (ent->entry.valid_end == NULL) { + ent->valid_end = malloc(sizeof(*ent->valid_end)); + if (ent->valid_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd", - ent->entry.valid_end); + ent->valid_end); if (ret) { /* OPTIONAL */ - free(ent->entry.valid_end); - ent->entry.valid_end = NULL; + free(ent->valid_end); + ent->valid_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time); if (ret == 0) { - if (ent->entry.valid_end == NULL) { - ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end)); - if (ent->entry.valid_end == NULL) { + if (ent->valid_end == NULL) { + ent->valid_end = malloc(sizeof(*ent->valid_end)); + if (ent->valid_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } - *ent->entry.valid_end = tmp_time; + *ent->valid_end = tmp_time; } - ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); - if (ent->entry.pw_end == NULL) { + ent->pw_end = malloc(sizeof(*ent->pw_end)); + if (ent->pw_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd", - ent->entry.pw_end); + ent->pw_end); if (ret) { /* OPTIONAL */ - free(ent->entry.pw_end); - ent->entry.pw_end = NULL; + free(ent->pw_end); + ent->pw_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); @@ -1305,76 +1310,76 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, NULL); if (delta) { - if (ent->entry.pw_end == NULL) { - ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); - if (ent->entry.pw_end == NULL) { + if (ent->pw_end == NULL) { + ent->pw_end = malloc(sizeof(*ent->pw_end)); + if (ent->pw_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } - *ent->entry.pw_end = tmp_time + delta; + *ent->pw_end = tmp_time + delta; } } ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time); if (ret == 0) { - if (ent->entry.pw_end == NULL) { - ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); - if (ent->entry.pw_end == NULL) { + if (ent->pw_end == NULL) { + ent->pw_end = malloc(sizeof(*ent->pw_end)); + if (ent->pw_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } - *ent->entry.pw_end = tmp_time; + *ent->pw_end = tmp_time; } /* OPTIONAL */ ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); if (ret == 0) - hdb_entry_set_pw_change_time(context, &ent->entry, tmp_time); + hdb_entry_set_pw_change_time(context, ent, tmp_time); { int max_life; - ent->entry.max_life = malloc(sizeof(*ent->entry.max_life)); - if (ent->entry.max_life == NULL) { + ent->max_life = malloc(sizeof(*ent->max_life)); + if (ent->max_life == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life); if (ret) { - free(ent->entry.max_life); - ent->entry.max_life = NULL; + free(ent->max_life); + ent->max_life = NULL; } else - *ent->entry.max_life = max_life; + *ent->max_life = max_life; } { int max_renew; - ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew)); - if (ent->entry.max_renew == NULL) { + ent->max_renew = malloc(sizeof(*ent->max_renew)); + if (ent->max_renew == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew); if (ret) { - free(ent->entry.max_renew); - ent->entry.max_renew = NULL; + free(ent->max_renew); + ent->max_renew = NULL; } else - *ent->entry.max_renew = max_renew; + *ent->max_renew = max_renew; } ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp); if (ret) tmp = 0; - ent->entry.flags = int2HDBFlags(tmp); + ent->flags = int2HDBFlags(tmp); /* Try and find Samba flags to put into the mix */ ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags); @@ -1406,7 +1411,7 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, /* Allow forwarding */ if (samba_forwardable) - ent->entry.flags.forwardable = TRUE; + ent->flags.forwardable = TRUE; for (i=0; i < flags_len; i++) { switch (samba_acct_flags[i]) { @@ -1418,36 +1423,36 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, /* how to handle no password in kerberos? */ break; case 'D': - ent->entry.flags.invalid = TRUE; + ent->flags.invalid = TRUE; break; case 'H': break; case 'T': /* temp duplicate */ - ent->entry.flags.invalid = TRUE; + ent->flags.invalid = TRUE; break; case 'U': - ent->entry.flags.client = TRUE; + ent->flags.client = TRUE; break; case 'M': break; case 'W': case 'S': - ent->entry.flags.server = TRUE; - ent->entry.flags.client = TRUE; + ent->flags.server = TRUE; + ent->flags.client = TRUE; break; case 'L': - ent->entry.flags.invalid = TRUE; + ent->flags.invalid = TRUE; break; case 'X': - if (ent->entry.pw_end) { - free(ent->entry.pw_end); - ent->entry.pw_end = NULL; + if (ent->pw_end) { + free(ent->pw_end); + ent->pw_end = NULL; } break; case 'I': - ent->entry.flags.server = TRUE; - ent->entry.flags.client = TRUE; + ent->flags.server = TRUE; + ent->flags.client = TRUE; break; } } @@ -1462,7 +1467,7 @@ out: free(ntPasswordIN); if (ret) - hdb_free_entry(context, ent); + hdb_free_entry(context, db, ent); return ret; } @@ -1491,7 +1496,7 @@ LDAP_unlock(krb5_context context, HDB * db) } static krb5_error_code -LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry) +LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry) { int msgid, rc, parserc; krb5_error_code ret; @@ -1545,9 +1550,9 @@ LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry) if (ret == 0) { if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - ret = hdb_unseal_keys(context, db, &entry->entry); + ret = hdb_unseal_keys(context, db, entry); if (ret) - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); } } @@ -1556,7 +1561,7 @@ LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry) static krb5_error_code LDAP_firstkey(krb5_context context, HDB *db, unsigned flags, - hdb_entry_ex *entry) + hdb_entry *entry) { krb5_error_code ret; int msgid; @@ -1584,7 +1589,7 @@ LDAP_firstkey(krb5_context context, HDB *db, unsigned flags, static krb5_error_code LDAP_nextkey(krb5_context context, HDB * db, unsigned flags, - hdb_entry_ex * entry) + hdb_entry * entry) { return LDAP_seq(context, db, flags, entry); } @@ -1687,7 +1692,7 @@ LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode) static krb5_error_code LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, - unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry) + unsigned flags, krb5_kvno kvno, hdb_entry * entry) { LDAPMessage *msg, *e; krb5_error_code ret; @@ -1705,9 +1710,9 @@ LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, ret = LDAP_message2entry(context, db, e, flags, entry); if (ret == 0) { if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - ret = hdb_unseal_keys(context, db, &entry->entry); + ret = hdb_unseal_keys(context, db, entry); if (ret) - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); } } @@ -1720,7 +1725,7 @@ LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, #if 0 static krb5_error_code LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, - unsigned flags, hdb_entry_ex * entry) + unsigned flags, hdb_entry * entry) { return LDAP_fetch_kvno(context, db, principal, flags & (~HDB_F_KVNO_SPECIFIED), 0, entry); @@ -1729,7 +1734,7 @@ LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, static krb5_error_code LDAP_store(krb5_context context, HDB * db, unsigned flags, - hdb_entry_ex * entry) + hdb_entry * entry) { LDAPMod **mods = NULL; krb5_error_code ret; @@ -1742,17 +1747,17 @@ LDAP_store(krb5_context context, HDB * db, unsigned flags, if ((flags & HDB_F_PRECHECK)) return 0; /* we can't guarantee whether we'll be able to perform it */ - ret = LDAP_principal2message(context, db, entry->entry.principal, &msg); + ret = LDAP_principal2message(context, db, entry->principal, &msg); if (ret == 0) e = ldap_first_entry(HDB2LDAP(db), msg); - ret = krb5_unparse_name(context, entry->entry.principal, &name); + ret = krb5_unparse_name(context, entry->principal, &name); if (ret) { free(name); return ret; } - ret = hdb_seal_keys(context, db, &entry->entry); + ret = hdb_seal_keys(context, db, entry); if (ret) goto out; diff --git a/third_party/heimdal/lib/hdb/hdb-mdb.c b/third_party/heimdal/lib/hdb/hdb-mdb.c index cabda277f4ee..6aa5201eb8a5 100644 --- a/third_party/heimdal/lib/hdb/hdb-mdb.c +++ b/third_party/heimdal/lib/hdb/hdb-mdb.c @@ -383,7 +383,7 @@ DB_unlock(krb5_context context, HDB *db) static krb5_error_code DB_seq(krb5_context context, HDB *db, - unsigned flags, hdb_entry_ex *entry, int flag) + unsigned flags, hdb_entry *entry, int flag) { mdb_info *mi = db->hdb_db; MDB_val key, value; @@ -406,21 +406,21 @@ DB_seq(krb5_context context, HDB *db, data.data = value.mv_data; data.length = value.mv_size; memset(entry, 0, sizeof(*entry)); - if (hdb_value2entry(context, &data, &entry->entry)) + if (hdb_value2entry(context, &data, entry)) return DB_seq(context, db, flags, entry, MDB_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); + code = hdb_unseal_keys (context, db, entry); if (code) - hdb_free_entry (context, entry); + hdb_free_entry (context, db, entry); } - if (entry->entry.principal == NULL) { - entry->entry.principal = malloc(sizeof(*entry->entry.principal)); - if (entry->entry.principal == NULL) { - hdb_free_entry (context, entry); + if (entry->principal == NULL) { + entry->principal = malloc(sizeof(*entry->principal)); + if (entry->principal == NULL) { + hdb_free_entry (context, db, entry); krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } else { - hdb_key2principal(context, &key_data, entry->entry.principal); + hdb_key2principal(context, &key_data, entry->principal); } } return 0; @@ -428,7 +428,7 @@ DB_seq(krb5_context context, HDB *db, static krb5_error_code -DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { krb5_error_code ret = 0; mdb_info *mi = db->hdb_db; @@ -462,7 +462,7 @@ DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) static krb5_error_code -DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return DB_seq(context, db, flags, entry, MDB_NEXT); } diff --git a/third_party/heimdal/lib/hdb/hdb-mitdb.c b/third_party/heimdal/lib/hdb/hdb-mitdb.c index 1ae013157c2b..7436f39edbbe 100644 --- a/third_party/heimdal/lib/hdb/hdb-mitdb.c +++ b/third_party/heimdal/lib/hdb/hdb-mitdb.c @@ -555,7 +555,7 @@ _hdb_mdb_value2entry(krb5_context context, krb5_data *data, goto out; } CHECK(ret = krb5_parse_name(context, p, &modby)); - ret = hdb_set_last_modified_by(context, entry, modby, u32); + CHECK(ret = hdb_set_last_modified_by(context, entry, modby, u32)); krb5_free_principal(context, modby); free(p); break; @@ -765,7 +765,7 @@ mdb_unlock(krb5_context context, HDB *db) static krb5_error_code mdb_seq(krb5_context context, HDB *db, - unsigned flags, hdb_entry_ex *entry, int flag) + unsigned flags, hdb_entry *entry, int flag) { DB *d = (DB*)db->hdb_db; DBT key, value; @@ -796,13 +796,13 @@ mdb_seq(krb5_context context, HDB *db, data.length = value.size; memset(entry, 0, sizeof(*entry)); - if (_hdb_mdb_value2entry(context, &data, 0, &entry->entry)) + if (_hdb_mdb_value2entry(context, &data, 0, entry)) return mdb_seq(context, db, flags, entry, R_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); + code = hdb_unseal_keys (context, db, entry); if (code) - hdb_free_entry (context, entry); + hdb_free_entry (context, db, entry); } return code; @@ -810,14 +810,14 @@ mdb_seq(krb5_context context, HDB *db, static krb5_error_code -mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return mdb_seq(context, db, flags, entry, R_FIRST); } static krb5_error_code -mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return mdb_seq(context, db, flags, entry, R_NEXT); } @@ -941,7 +941,7 @@ mdb__del(krb5_context context, HDB *db, krb5_data key) static krb5_error_code mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, - unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) + unsigned flags, krb5_kvno kvno, hdb_entry *entry) { krb5_data key, value; krb5_error_code ret; @@ -953,15 +953,15 @@ mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, krb5_data_free(&key); if(ret) return ret; - ret = _hdb_mdb_value2entry(context, &value, kvno, &entry->entry); + ret = _hdb_mdb_value2entry(context, &value, kvno, entry); krb5_data_free(&value); if (ret) return ret; if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - ret = hdb_unseal_keys (context, db, &entry->entry); + ret = hdb_unseal_keys (context, db, entry); if (ret) { - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); return ret; } } @@ -970,7 +970,7 @@ mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, } static krb5_error_code -mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { krb5_error_code ret; krb5_storage *sp = NULL; @@ -985,7 +985,7 @@ mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) return 0; if ((flags & HDB_F_PRECHECK)) { - ret = mdb_principal2key(context, entry->entry.principal, &key); + ret = mdb_principal2key(context, entry->principal, &key); if (ret) return ret; ret = db->hdb__get(context, db, key, &value); krb5_data_free(&key); @@ -999,9 +999,9 @@ mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) sp = krb5_storage_emem(); if (!sp) return ENOMEM; ret = _hdb_set_master_key_usage(context, db, 0); /* MIT KDB uses KU 0 */ - ret = hdb_seal_keys(context, db, &entry->entry); + ret = hdb_seal_keys(context, db, entry); if (ret) return ret; - ret = entry2mit_string_int(context, sp, &entry->entry); + ret = entry2mit_string_int(context, sp, entry); if (ret) goto out; sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */ ret = ENOMEM; @@ -1016,7 +1016,7 @@ mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) if (ret) goto out; ret = krb5_storage_to_data(spent, &kdb_ent); if (ret) goto out; - ret = mdb_principal2key(context, entry->entry.principal, &key); + ret = mdb_principal2key(context, entry->principal, &key); if (ret) goto out; ret = mdb__put(context, db, 1, key, kdb_ent); @@ -1253,17 +1253,16 @@ getdata(char **p, unsigned char *buf, size_t len, const char *what) } static int -getint(char **p, const char *what) +getint(char **p, const char *what, int *val) { - int val; char *q = nexttoken(p, 0, what); if (!q) { warnx("Failed to find a signed integer (%s) in dump", what); - return -1; + return 1; } - if (sscanf(q, "%d", &val) != 1) - return -1; - return val; + if (sscanf(q, "%d", val) != 1) + return 1; + return 0; } static unsigned int @@ -1327,7 +1326,7 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) "'policy', nor 'princ'"); return -1; } - if (getint(&p, "constant '38'") != 38) { + if (getint(&p, "constant '38'", &tmp) || tmp != 38) { warnx("Dump entry does not start with '38'"); return EINVAL; } @@ -1343,7 +1342,7 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) } num_tl_data = getuint(&p, "number of TL data"); num_key_data = getuint(&p, "number of key data"); - getint(&p, "5th field, length of 'extra data'"); + (void) getint(&p, "5th field, length of 'extra data'", &tmp); princ = nexttoken(&p, (int)princ_len, "principal name"); if (princ == NULL) { warnx("Failed to read principal name (expected length %llu)", @@ -1355,38 +1354,31 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) ret = krb5_store_uint32(sp, attributes); if (ret) return ret; - tmp = getint(&p, "max life"); - CHECK_UINT(tmp); + if (getint(&p, "max life", &tmp)) return EINVAL; ret = krb5_store_uint32(sp, tmp); if (ret) return ret; - tmp = getint(&p, "max renewable life"); - CHECK_UINT(tmp); + if (getint(&p, "max renewable life", &tmp)) return EINVAL; ret = krb5_store_uint32(sp, tmp); if (ret) return ret; - tmp = getint(&p, "expiration"); - CHECK_UINT(tmp); + if (getint(&p, "expiration", &tmp)) return EINVAL; ret = krb5_store_uint32(sp, tmp); if (ret) return ret; - tmp = getint(&p, "pw expiration"); - CHECK_UINT(tmp); + if (getint(&p, "pw expiration", &tmp)) return EINVAL; ret = krb5_store_uint32(sp, tmp); if (ret) return ret; - tmp = getint(&p, "last auth"); - CHECK_UINT(tmp); + if (getint(&p, "last auth", &tmp)) return EINVAL; ret = krb5_store_uint32(sp, tmp); if (ret) return ret; - tmp = getint(&p, "last failed auth"); - CHECK_UINT(tmp); + if (getint(&p, "last failed auth", &tmp)) return EINVAL; ret = krb5_store_uint32(sp, tmp); if (ret) return ret; - tmp = getint(&p,"fail auth count"); - CHECK_UINT(tmp); + if (getint(&p,"fail auth count", &tmp)) return EINVAL; ret = krb5_store_uint32(sp, tmp); if (ret) return ret; @@ -1414,8 +1406,9 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) int tl_type, tl_length; unsigned char *buf; - tl_type = getint(&p, "TL data type"); - tl_length = getint(&p, "data length"); + if (getint(&p, "TL data type", &tl_type) || + getint(&p, "data length", &tl_length)) + return EINVAL; if (asprintf(&reading_what, "TL data type %d (length %d)", tl_type, tl_length) < 0) @@ -1435,8 +1428,10 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) if (tl_length) { buf = malloc(tl_length); if (!buf) return ENOMEM; - if (getdata(&p, buf, tl_length, reading_what) != tl_length) + if (getdata(&p, buf, tl_length, reading_what) != tl_length) { + free(buf); return EINVAL; + } sz = krb5_storage_write(sp, buf, tl_length); free(buf); if (sz != tl_length) return ENOMEM; @@ -1454,23 +1449,23 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) int keylen; size_t k; - key_versions = getint(&p, "key data 'version'"); + if (getint(&p, "key data 'version'", &key_versions)) return EINVAL; CHECK_UINT16(key_versions); ret = krb5_store_int16(sp, key_versions); if (ret) return ret; - kvno = getint(&p, "kvno"); + if (getint(&p, "kvno", &kvno)) return EINVAL; CHECK_UINT16(kvno); ret = krb5_store_int16(sp, kvno); if (ret) return ret; for (k = 0; k < key_versions; k++) { - keytype = getint(&p, "enctype"); + if (getint(&p, "enctype", &keytype)) return EINVAL; CHECK_UINT16(keytype); ret = krb5_store_int16(sp, keytype); if (ret) return ret; - keylen = getint(&p, "encrypted key length"); + if (getint(&p, "encrypted key length", &keylen)) return EINVAL; CHECK_UINT16(keylen); ret = krb5_store_int16(sp, keylen); if (ret) return ret; @@ -1478,8 +1473,10 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) if (keylen) { buf = malloc(keylen); if (!buf) return ENOMEM; - if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) + if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) { + free(buf); return EINVAL; + } sz = krb5_storage_write(sp, buf, keylen); free(buf); if (sz != keylen) return ENOMEM; diff --git a/third_party/heimdal/lib/hdb/hdb-sqlite.c b/third_party/heimdal/lib/hdb/hdb-sqlite.c index 3cab9178965e..4bb2f8e8553c 100644 --- a/third_party/heimdal/lib/hdb/hdb-sqlite.c +++ b/third_party/heimdal/lib/hdb/hdb-sqlite.c @@ -495,7 +495,7 @@ hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename) */ static krb5_error_code hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, - unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) + unsigned flags, krb5_kvno kvno, hdb_entry *entry) { int sqlite_error; krb5_error_code ret; @@ -541,14 +541,14 @@ hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal princi value.length = sqlite3_column_bytes(fetch, 0); value.data = (void *) sqlite3_column_blob(fetch, 0); - ret = hdb_value2entry(context, &value, &entry->entry); + ret = hdb_value2entry(context, &value, entry); if(ret) goto out; if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - ret = hdb_unseal_keys(context, db, &entry->entry); + ret = hdb_unseal_keys(context, db, entry); if(ret) { - hdb_free_entry(context, entry); + hdb_free_entry(context, db, entry); goto out; } } @@ -600,7 +600,7 @@ hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement) */ static krb5_error_code hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, - hdb_entry_ex *entry) + hdb_entry *entry) { int ret; int i; @@ -624,17 +624,17 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, goto rollback; } - ret = hdb_seal_keys(context, db, &entry->entry); + ret = hdb_seal_keys(context, db, entry); if(ret) { goto rollback; } - ret = hdb_entry2value(context, &entry->entry, &value); + ret = hdb_entry2value(context, entry, &value); if(ret) { goto rollback; } - ret = bind_principal(context, entry->entry.principal, get_ids, 1); + ret = bind_principal(context, entry->principal, get_ids, 1); if (ret) goto rollback; @@ -656,7 +656,7 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, goto rollback; } - ret = bind_principal(context, entry->entry.principal, hsdb->add_principal, 1); + ret = bind_principal(context, entry->principal, hsdb->add_principal, 1); if (ret) goto rollback; @@ -684,8 +684,10 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, } else if(ret == SQLITE_ROW) { /* Found a principal */ - if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */ + if(!(flags & HDB_F_REPLACE)) { + ret = HDB_ERR_EXISTS; goto rollback; + } entry_id = sqlite3_column_int64(get_ids, 1); @@ -711,7 +713,7 @@ hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, goto rollback; } - ret = hdb_entry_get_aliases(&entry->entry, &aliases); + ret = hdb_entry_get_aliases(entry, &aliases); if(ret || aliases == NULL) goto commit; @@ -862,7 +864,7 @@ hdb_sqlite_unlock(krb5_context context, HDB *db) */ static krb5_error_code hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, - hdb_entry_ex *entry) + hdb_entry *entry) { krb5_error_code ret = 0; int sqlite_error; @@ -876,7 +878,7 @@ hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0); value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0); memset(entry, 0, sizeof(*entry)); - ret = hdb_value2entry(context, &value, &entry->entry); + ret = hdb_value2entry(context, &value, entry); } else if(sqlite_error == SQLITE_DONE) { /* No more entries */ @@ -900,7 +902,7 @@ hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, */ static krb5_error_code hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags, - hdb_entry_ex *entry) + hdb_entry *entry) { hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; krb5_error_code ret; @@ -950,11 +952,12 @@ hdb_sqlite_remove(krb5_context context, HDB *db, sqlite3_stmt *get_ids = hsdb->get_ids; sqlite3_stmt *rm = hsdb->remove; - bind_principal(context, principal, rm, 1); + ret = bind_principal(context, principal, rm, 1); - ret = hdb_sqlite_exec_stmt(context, hsdb, - "BEGIN IMMEDIATE TRANSACTION", - HDB_ERR_UK_SERROR); + if (ret == 0) + ret = hdb_sqlite_exec_stmt(context, hsdb, + "BEGIN IMMEDIATE TRANSACTION", + HDB_ERR_UK_SERROR); if (ret != SQLITE_OK) { ret = HDB_ERR_UK_SERROR; (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); diff --git a/third_party/heimdal/lib/hdb/hdb.asn1 b/third_party/heimdal/lib/hdb/hdb.asn1 index f6490783a6cd..9eb96be73d06 100644 --- a/third_party/heimdal/lib/hdb/hdb.asn1 +++ b/third_party/heimdal/lib/hdb/hdb.asn1 @@ -4,7 +4,7 @@ BEGIN IMPORTS EncryptionKey, KerberosTime, Principal FROM krb5; -HDB_DB_FORMAT INTEGER ::= 2 -- format of database, +hdb_db_format INTEGER ::= 2 -- format of database, -- update when making changes -- these must have the same value as the pa-* counterparts diff --git a/third_party/heimdal/lib/hdb/hdb.c b/third_party/heimdal/lib/hdb/hdb.c index 3978048ad17f..56c403842e60 100644 --- a/third_party/heimdal/lib/hdb/hdb.c +++ b/third_party/heimdal/lib/hdb/hdb.c @@ -232,38 +232,25 @@ hdb_remove_keys(krb5_context context, * @param context Context * @param e The HDB entry * @param ks A pointer to a variable of type HDB_Ext_KeySet + * @param ckr A pointer to stable (copied) HDB_Ext_KeyRotation * * @return Zero on success, an error code otherwise. */ krb5_error_code -hdb_remove_base_keys(krb5_context context, - hdb_entry *e, - HDB_Ext_KeySet *base_keys) +_hdb_remove_base_keys(krb5_context context, + hdb_entry *e, + HDB_Ext_KeySet *base_keys, + const HDB_Ext_KeyRotation *ckr) { - krb5_error_code ret; - const HDB_Ext_KeyRotation *ckr; - HDB_Ext_KeyRotation kr; + krb5_error_code ret = 0; size_t i, k; - ret = hdb_entry_get_key_rotation(context, e, &ckr); - if (!ckr) - return 0; - - if (ret == 0) { - /* - * Changing the entry's extensions invalidates extensions obtained - * before the change. - */ - ret = copy_HDB_Ext_KeyRotation(ckr, &kr); - ckr = NULL; - } base_keys->len = 0; - if (ret == 0 && - (base_keys->val = calloc(kr.len, sizeof(base_keys->val[0]))) == NULL) + if ((base_keys->val = calloc(ckr->len, sizeof(base_keys->val[0]))) == NULL) ret = krb5_enomem(context); - for (k = i = 0; ret == 0 && i < kr.len; i++) { - const KeyRotation *krp = &kr.val[i]; + for (k = i = 0; ret == 0 && i < ckr->len; i++) { + const KeyRotation *krp = &ckr->val[i]; /* * WARNING: O(N * M) where M is number of keysets and N is the number @@ -284,7 +271,6 @@ hdb_remove_base_keys(krb5_context context, base_keys->len = k; else free_HDB_Ext_KeySet(base_keys); - free_HDB_Ext_KeyRotation(&kr); return 0; } @@ -312,12 +298,12 @@ hdb_install_keyset(krb5_context context, (ret = hdb_add_current_keys_to_history(context, e))) return ret; free_Keys(&e->keys); + e->kvno = ks->kvno; if (ret == 0) ret = copy_Keys(&ks->keys, &e->keys); - e->kvno = ks->kvno; - if (ks->set_time) - return hdb_entry_set_pw_change_time(context, e, *ks->set_time); - return 0; + if (ret == 0 && ks->set_time) + ret = hdb_entry_set_pw_change_time(context, e, *ks->set_time); + return ret; } return hdb_add_history_keyset(context, e, ks); } @@ -359,9 +345,10 @@ hdb_enctype2key(krb5_context context, void hdb_free_key(Key *key) { - memset(key->key.keyvalue.data, - 0, - key->key.keyvalue.length); + memset_s(key->key.keyvalue.data, + key->key.keyvalue.length, + 0, + key->key.keyvalue.length); free_Key(key); free(key); } @@ -396,20 +383,23 @@ hdb_unlock(int fd) } void -hdb_free_entry(krb5_context context, hdb_entry_ex *ent) +hdb_free_entry(krb5_context context, HDB *db, hdb_entry *ent) { Key *k; size_t i; - if (ent->free_entry) - (*ent->free_entry)(context, ent); + if (db && db->hdb_free_entry_context) + db->hdb_free_entry_context(context, db, ent); - for(i = 0; i < ent->entry.keys.len; i++) { - k = &ent->entry.keys.val[i]; + for(i = 0; i < ent->keys.len; i++) { + k = &ent->keys.val[i]; - memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); + memset_s(k->key.keyvalue.data, + k->key.keyvalue.length, + 0, + k->key.keyvalue.length); } - free_HDB_entry(&ent->entry); + free_HDB_entry(ent); } krb5_error_code @@ -420,13 +410,13 @@ hdb_foreach(krb5_context context, void *data) { krb5_error_code ret; - hdb_entry_ex entry; + hdb_entry entry; ret = db->hdb_firstkey(context, db, flags, &entry); if (ret == 0) krb5_clear_error_message(context); while(ret == 0){ ret = (*func)(context, db, &entry, data); - hdb_free_entry(context, &entry); + hdb_free_entry(context, db, &entry); if(ret == 0) ret = db->hdb_nextkey(context, db, flags, &entry); } @@ -661,22 +651,22 @@ hdb_list_builtin(krb5_context context, char **list) krb5_error_code _hdb_keytab2hdb_entry(krb5_context context, const krb5_keytab_entry *ktentry, - hdb_entry_ex *entry) + hdb_entry *entry) { - entry->entry.kvno = ktentry->vno; - entry->entry.created_by.time = ktentry->timestamp; + entry->kvno = ktentry->vno; + entry->created_by.time = ktentry->timestamp; - entry->entry.keys.val = calloc(1, sizeof(entry->entry.keys.val[0])); - if (entry->entry.keys.val == NULL) + entry->keys.val = calloc(1, sizeof(entry->keys.val[0])); + if (entry->keys.val == NULL) return ENOMEM; - entry->entry.keys.len = 1; + entry->keys.len = 1; - entry->entry.keys.val[0].mkvno = NULL; - entry->entry.keys.val[0].salt = NULL; + entry->keys.val[0].mkvno = NULL; + entry->keys.val[0].salt = NULL; return krb5_copy_keyblock_contents(context, &ktentry->keyblock, - &entry->entry.keys.val[0].key); + &entry->keys.val[0].key); } static krb5_error_code @@ -789,7 +779,7 @@ hdb_create(krb5_context context, HDB **db, const char *filename) return ret; } for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++) { - if (cb_ctx.h->is_file_based && !pathish) + if (cb_ctx.h->is_file_based) continue; if (!cb_ctx.h->can_taste) continue; @@ -805,9 +795,11 @@ hdb_create(krb5_context context, HDB **db, const char *filename) (*db)->hdb_destroy(context, *db); *db = NULL; } + if (cb_ctx.h->prefix == NULL) + cb_ctx.h = NULL; } #ifdef HDB_DEFAULT_DB_TYPE - if (cb_ctx.h == NULL || cb_ctx.h->prefix == NULL) { + if (cb_ctx.h == NULL) { /* * If still we've not picked a backend, use a build configuration time * default. @@ -815,12 +807,14 @@ hdb_create(krb5_context context, HDB **db, const char *filename) for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++) if (strcmp(cb_ctx.h->prefix, HDB_DEFAULT_DB_TYPE) == 0) break; + if (cb_ctx.h->prefix == NULL) + cb_ctx.h = NULL; } #endif - if (cb_ctx.h == NULL || cb_ctx.h->prefix == NULL) + if (cb_ctx.h == NULL) /* Last resort default */ cb_ctx.h = &default_dbmethod; - if (cb_ctx.h == NULL || cb_ctx.h->prefix == NULL) { + if (cb_ctx.h->prefix == NULL) { krb5_set_error_message(context, ENOTSUP, "Could not determine default DB backend for %s", filename); diff --git a/third_party/heimdal/lib/hdb/hdb.h b/third_party/heimdal/lib/hdb/hdb.h index 97ca70c0a7e8..0f2c92151e5f 100644 --- a/third_party/heimdal/lib/hdb/hdb.h +++ b/third_party/heimdal/lib/hdb/hdb.h @@ -42,8 +42,12 @@ #include +#include #include #include + +#define HDB_DB_FORMAT hdb_db_format + typedef HDB_keyset hdb_keyset; typedef HDB_entry hdb_entry; typedef HDB_entry_alias hdb_entry_alias; @@ -53,25 +57,26 @@ struct hdb_dbinfo; enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK }; /* flags for various functions */ -#define HDB_F_DECRYPT 1 /* decrypt keys */ -#define HDB_F_REPLACE 2 /* replace entry */ -#define HDB_F_GET_CLIENT 4 /* fetch client */ -#define HDB_F_GET_SERVER 8 /* fetch server */ -#define HDB_F_GET_KRBTGT 16 /* fetch krbtgt */ -#define HDB_F_GET_ANY 28 /* fetch any of client,server,krbtgt */ -#define HDB_F_CANON 32 /* want canonicalition */ -#define HDB_F_ADMIN_DATA 64 /* want data that kdc don't use */ -#define HDB_F_KVNO_SPECIFIED 128 /* we want a particular KVNO */ -#define HDB_F_CURRENT_KVNO 256 /* we want the current KVNO */ -#define HDB_F_LIVE_CLNT_KVNOS 512 /* we want all live keys for pre-auth */ -#define HDB_F_LIVE_SVC_KVNOS 1024 /* we want all live keys for tix */ -#define HDB_F_ALL_KVNOS 2048 /* we want all the keys, live or not */ -#define HDB_F_FOR_AS_REQ 4096 /* fetch is for a AS REQ */ -#define HDB_F_FOR_TGS_REQ 8192 /* fetch is for a TGS REQ */ -#define HDB_F_PRECHECK 16384 /* check that the operation would succeed */ -#define HDB_F_DELAY_NEW_KEYS 32768 /* apply [hdb] new_service_key_delay */ -#define HDB_F_SYNTHETIC_OK 65536 /* synthetic principal for PKINIT or GSS preauth OK */ -#define HDB_F_GET_FAST_COOKIE 131072 /* fetch the FX-COOKIE key (not a normal principal) */ +#define HDB_F_DECRYPT 0x00001 /* decrypt keys */ +#define HDB_F_REPLACE 0x00002 /* replace entry */ +#define HDB_F_GET_CLIENT 0x00004 /* fetch client */ +#define HDB_F_GET_SERVER 0x00008 /* fetch server */ +#define HDB_F_GET_KRBTGT 0x00010 /* fetch krbtgt */ +#define HDB_F_GET_ANY ( HDB_F_GET_CLIENT | \ + HDB_F_GET_SERVER | \ + HDB_F_GET_KRBTGT ) /* fetch any of client,server,krbtgt */ +#define HDB_F_CANON 0x00020 /* want canonicalition */ +#define HDB_F_ADMIN_DATA 0x00040 /* want data that kdc don't use */ +#define HDB_F_KVNO_SPECIFIED 0x00080 /* we want a particular KVNO */ +#define HDB_F_LIVE_CLNT_KVNOS 0x00200 /* we want all live keys for pre-auth */ +#define HDB_F_LIVE_SVC_KVNOS 0x00400 /* we want all live keys for tix */ +#define HDB_F_ALL_KVNOS 0x00800 /* we want all the keys, live or not */ +#define HDB_F_FOR_AS_REQ 0x01000 /* fetch is for a AS REQ */ +#define HDB_F_FOR_TGS_REQ 0x02000 /* fetch is for a TGS REQ */ +#define HDB_F_PRECHECK 0x04000 /* check that the operation would succeed */ +#define HDB_F_DELAY_NEW_KEYS 0x08000 /* apply [hdb] new_service_key_delay */ +#define HDB_F_SYNTHETIC_OK 0x10000 /* synthetic principal for PKINIT or GSS preauth OK */ +#define HDB_F_GET_FAST_COOKIE 0x20000 /* fetch the FX-COOKIE key (not a normal principal) */ /* hdb_capability_flags */ #define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1 @@ -79,78 +84,15 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK }; #define HDB_CAP_F_PASSWORD_UPDATE_KEYS 4 #define HDB_CAP_F_SHARED_DIRECTORY 8 -/* auth status values */ - -/* - * Un-initialised value, not permitted, used to indicate that a value - * wasn't set for the benifit of logic in the caller, must not be - * passed to hdb_auth_status() - */ - -#define HDB_AUTHSTATUS_INVALID 0 +#define heim_pcontext krb5_context +#define heim_pconfig void * -/* - * A ticket was issued after authorization was successfully completed - * (eg flags on the entry and expiry times were checked) - */ -#define HDB_AUTHSTATUS_AUTHORIZATION_SUCCESS 1 +typedef struct hdb_request_desc { + HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; +} *hdb_request_t; -/* - * The user supplied the wrong password to a password-based - * authentication mechanism (eg ENC-TS, ENC-CHAL) - * - * The HDB backend might increment a bad password count. - */ -#define HDB_AUTHSTATUS_WRONG_PASSWORD 2 - -/* - * The user supplied a correct password to a password-based - * authentication mechanism (eg ENC-TS, ENC-CHAL) - * - * The HDB backend might reset a bad password count. - */ -#define HDB_AUTHSTATUS_CORRECT_PASSWORD 3 - -/* - * Attempted authenticaton with an unknown user - */ -#define HDB_AUTHSTATUS_CLIENT_UNKNOWN 4 - -/* - * Attempted authenticaton with an known user that is already locked - * out. - */ -#define HDB_AUTHSTATUS_CLIENT_LOCKED_OUT 5 - -/* - * Successful authentication with a pre-authentication mechanism - */ -#define HDB_AUTHSTATUS_GENERIC_SUCCESS 6 - -/* - * Failed authentication with a pre-authentication mechanism - */ -#define HDB_AUTHSTATUS_GENERIC_FAILURE 7 - -/* - * Successful pre-authentication with PKINIT (smart card login etc) - */ -#define HDB_AUTHSTATUS_PKINIT_SUCCESS 8 - -/* - * Failed pre-authentication with PKINIT (smart card login etc) - */ -#define HDB_AUTHSTATUS_PKINIT_FAILURE 9 - -/* - * Successful pre-authentication with GSS pre-authentication - */ -#define HDB_AUTHSTATUS_GSS_SUCCESS 10 - -/* - * Failed pre-authentication with GSS pre-authentication - */ -#define HDB_AUTHSTATUS_GSS_FAILURE 11 +#undef heim_pcontext +#undef heim_pconfig /* key usage for master key */ #define HDB_KU_MKEY 0x484442 @@ -163,20 +105,6 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK }; typedef struct hdb_master_key_data *hdb_master_key; -/** - * hdb_entry_ex is a wrapper structure around the hdb_entry structure - * that allows backends to keep a pointer to the backing store, ie in - * ->hdb_fetch_kvno(), so that we the kadmin/kpasswd backend gets around to - * ->hdb_store(), the backend doesn't need to lookup the entry again. - */ - -typedef struct hdb_entry_ex { - void *ctx; - hdb_entry entry; - void (*free_entry)(krb5_context, struct hdb_entry_ex *); -} hdb_entry_ex; - - /** * HDB backend function pointer structure * @@ -226,9 +154,9 @@ typedef struct HDB { */ krb5_error_code (*hdb_close)(krb5_context, struct HDB*); /** - * Free an entry after use. + * Free backend-specific entry context. */ - void (*hdb_free)(krb5_context, struct HDB*, hdb_entry_ex*); + void (*hdb_free_entry_context)(krb5_context, struct HDB*, hdb_entry*); /** * Fetch an entry from the backend * @@ -238,12 +166,12 @@ typedef struct HDB { */ krb5_error_code (*hdb_fetch_kvno)(krb5_context, struct HDB*, krb5_const_principal, unsigned, krb5_kvno, - hdb_entry_ex*); + hdb_entry*); /** * Store an entry to database */ krb5_error_code (*hdb_store)(krb5_context, struct HDB*, - unsigned, hdb_entry_ex*); + unsigned, hdb_entry*); /** * Remove an entry from the database. */ @@ -253,12 +181,12 @@ typedef struct HDB { * As part of iteration, fetch one entry */ krb5_error_code (*hdb_firstkey)(krb5_context, struct HDB*, - unsigned, hdb_entry_ex*); + unsigned, hdb_entry*); /** * As part of iteration, fetch next entry */ krb5_error_code (*hdb_nextkey)(krb5_context, struct HDB*, - unsigned, hdb_entry_ex*); + unsigned, hdb_entry*); /** * Lock database * @@ -337,40 +265,35 @@ typedef struct HDB { * The backend needs to call _kadm5_set_keys() and perform password * quality checks. */ - krb5_error_code (*hdb_password)(krb5_context, struct HDB*, hdb_entry_ex*, const char *, int); + krb5_error_code (*hdb_password)(krb5_context, struct HDB*, hdb_entry*, const char *, int); /** - * Auth feedback + * Authentication auditing. Note that this function is called by + * both the AS and TGS, but currently only the AS sets the auth + * event type. This may change in a future version. * - * This is a feedback call that allows backends that provides - * lockout functionality to register failure and/or successes. + * Event details are available by querying the request using + * heim_audit_getkv(HDB_REQUEST_KV_...). * * In case the entry is locked out, the backend should set the * hdb_entry.flags.locked-out flag. */ - krb5_error_code (*hdb_auth_status)(krb5_context, - struct HDB *, - hdb_entry_ex *, - const struct timeval *start_time, - const struct sockaddr *from_addr, - const char *original_client_name, - int auth_type, - const char *auth_details, - const char *pa_type); + krb5_error_code (*hdb_audit)(krb5_context, struct HDB *, hdb_entry *, hdb_request_t); + /** * Check if delegation is allowed. */ - krb5_error_code (*hdb_check_constrained_delegation)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal); + krb5_error_code (*hdb_check_constrained_delegation)(krb5_context, struct HDB *, hdb_entry *, krb5_const_principal); /** * Check if this name is an alias for the supplied client for PKINIT userPrinicpalName logins */ - krb5_error_code (*hdb_check_pkinit_ms_upn_match)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal); + krb5_error_code (*hdb_check_pkinit_ms_upn_match)(krb5_context, struct HDB *, hdb_entry *, krb5_const_principal); /** * Check if s4u2self is allowed from this client to this server or the SPN is a valid SPN of this client (for user2user) */ - krb5_error_code (*hdb_check_client_matches_target_service)(krb5_context, struct HDB *, hdb_entry_ex *, hdb_entry_ex *); + krb5_error_code (*hdb_check_client_matches_target_service)(krb5_context, struct HDB *, hdb_entry *, hdb_entry *); /** * Enable/disable synchronous updates @@ -405,7 +328,7 @@ struct hdb_print_entry_arg { }; typedef krb5_error_code (*hdb_foreach_func_t)(krb5_context, HDB*, - hdb_entry_ex*, void*); + hdb_entry*, void*); extern krb5_kt_ops hdb_kt_ops; extern krb5_kt_ops hdb_get_kt_ops; diff --git a/third_party/heimdal/lib/hdb/hdb.opt b/third_party/heimdal/lib/hdb/hdb.opt new file mode 100644 index 000000000000..626f8c7b07ab --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb.opt @@ -0,0 +1,5 @@ +--sequence=HDB-extensions +--sequence=HDB-Ext-KeyRotation +--sequence=HDB-Ext-KeySet +--sequence=Keys +--decorate=HDB_entry:void:context?::: diff --git a/third_party/heimdal/lib/hdb/keys.c b/third_party/heimdal/lib/hdb/keys.c index ae0b067f79ba..457e5daf7a7b 100644 --- a/third_party/heimdal/lib/hdb/keys.c +++ b/third_party/heimdal/lib/hdb/keys.c @@ -305,7 +305,7 @@ hdb_add_history_keyset(krb5_context context, HDB_Ext_KeySet *hist_keys; HDB_extension ext; HDB_extension *extp; - krb5_error_code ret; + krb5_error_code ret = 0; memset(&ext, 0, sizeof (ext)); diff --git a/third_party/heimdal/lib/hdb/keytab.c b/third_party/heimdal/lib/hdb/keytab.c index 83cc851d91f5..b1aa0207c978 100644 --- a/third_party/heimdal/lib/hdb/keytab.c +++ b/third_party/heimdal/lib/hdb/keytab.c @@ -42,7 +42,7 @@ struct hdb_data { struct hdb_cursor { HDB *db; - hdb_entry_ex hdb_entry; + hdb_entry hdb_entry; int first, next; int key_idx; }; @@ -160,8 +160,11 @@ find_db (krb5_context context, } hdb_free_dbinfo(context, &head); if (*dbname == NULL && - (*dbname = strdup(hdb_default_db(context))) == NULL) + (*dbname = strdup(hdb_default_db(context))) == NULL) { + free(*mkey); + *mkey = NULL; return krb5_enomem(context); + } return 0; } @@ -178,7 +181,7 @@ hdb_get_entry(krb5_context context, krb5_enctype enctype, krb5_keytab_entry *entry) { - hdb_entry_ex ent; + hdb_entry ent; krb5_error_code ret; struct hdb_data *d = id->data; const char *dbname = d->dbname; @@ -187,6 +190,9 @@ hdb_get_entry(krb5_context context, HDB *db; size_t i; + if (!principal) + return KRB5_KT_NOTFOUND; + memset(&ent, 0, sizeof(ent)); if (dbname == NULL) { @@ -223,27 +229,27 @@ hdb_get_entry(krb5_context context, }else if(ret) goto out; - if(kvno && (krb5_kvno)ent.entry.kvno != kvno) { - hdb_free_entry(context, &ent); + if(kvno && (krb5_kvno)ent.kvno != kvno) { + hdb_free_entry(context, db, &ent); ret = KRB5_KT_NOTFOUND; goto out; } if(enctype == 0) - if(ent.entry.keys.len > 0) - enctype = ent.entry.keys.val[0].key.keytype; + if(ent.keys.len > 0) + enctype = ent.keys.val[0].key.keytype; ret = KRB5_KT_NOTFOUND; - for(i = 0; i < ent.entry.keys.len; i++) { - if(ent.entry.keys.val[i].key.keytype == enctype) { + for(i = 0; i < ent.keys.len; i++) { + if(ent.keys.val[i].key.keytype == enctype) { krb5_copy_principal(context, principal, &entry->principal); - entry->vno = ent.entry.kvno; + entry->vno = ent.kvno; krb5_copy_keyblock_contents(context, - &ent.entry.keys.val[i].key, + &ent.keys.val[i].key, &entry->keyblock); ret = 0; break; } } - hdb_free_entry(context, &ent); + hdb_free_entry(context, db, &ent); out: (*db->hdb_close)(context, db); (*db->hdb_destroy)(context, db); @@ -333,8 +339,8 @@ hdb_next_entry(krb5_context context, else if (ret) return ret; - if (c->hdb_entry.entry.keys.len == 0) - hdb_free_entry(context, &c->hdb_entry); + if (c->hdb_entry.keys.len == 0) + hdb_free_entry(context, c->db, &c->hdb_entry); else c->next = FALSE; } @@ -350,8 +356,8 @@ hdb_next_entry(krb5_context context, return ret; /* If no keys on this entry, try again */ - if (c->hdb_entry.entry.keys.len == 0) - hdb_free_entry(context, &c->hdb_entry); + if (c->hdb_entry.keys.len == 0) + hdb_free_entry(context, c->db, &c->hdb_entry); else c->next = FALSE; } @@ -362,14 +368,14 @@ hdb_next_entry(krb5_context context, */ ret = krb5_copy_principal(context, - c->hdb_entry.entry.principal, + c->hdb_entry.principal, &entry->principal); if (ret) return ret; - entry->vno = c->hdb_entry.entry.kvno; + entry->vno = c->hdb_entry.kvno; ret = krb5_copy_keyblock_contents(context, - &c->hdb_entry.entry.keys.val[c->key_idx].key, + &c->hdb_entry.keys.val[c->key_idx].key, &entry->keyblock); if (ret) { krb5_free_principal(context, entry->principal); @@ -383,8 +389,8 @@ hdb_next_entry(krb5_context context, * next entry */ - if ((size_t)c->key_idx == c->hdb_entry.entry.keys.len) { - hdb_free_entry(context, &c->hdb_entry); + if ((size_t)c->key_idx == c->hdb_entry.keys.len) { + hdb_free_entry(context, c->db, &c->hdb_entry); c->next = TRUE; c->key_idx = 0; } @@ -401,7 +407,7 @@ hdb_end_seq_get(krb5_context context, struct hdb_cursor *c = cursor->data; if (!c->next) - hdb_free_entry(context, &c->hdb_entry); + hdb_free_entry(context, c->db, &c->hdb_entry); (c->db->hdb_close)(context, c->db); (c->db->hdb_destroy)(context, c->db); diff --git a/third_party/heimdal/lib/hdb/libhdb-exports.def b/third_party/heimdal/lib/hdb/libhdb-exports.def index a124f93f6456..72a7fb7aaad7 100644 --- a/third_party/heimdal/lib/hdb/libhdb-exports.def +++ b/third_party/heimdal/lib/hdb/libhdb-exports.def @@ -69,7 +69,6 @@ EXPORTS hdb_prune_keys hdb_prune_keys_kvno hdb_read_master_key - hdb_remove_base_keys hdb_remove_keys hdb_replace_extension hdb_seal_key diff --git a/third_party/heimdal/lib/hdb/ndbm.c b/third_party/heimdal/lib/hdb/ndbm.c index 4e3a340fe555..52c52c890dc0 100644 --- a/third_party/heimdal/lib/hdb/ndbm.c +++ b/third_party/heimdal/lib/hdb/ndbm.c @@ -76,7 +76,7 @@ NDBM_unlock(krb5_context context, HDB *db) static krb5_error_code NDBM_seq(krb5_context context, HDB *db, - unsigned flags, hdb_entry_ex *entry, int first) + unsigned flags, hdb_entry *entry, int first) { struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; @@ -99,21 +99,21 @@ NDBM_seq(krb5_context context, HDB *db, data.data = value.dptr; data.length = value.dsize; memset(entry, 0, sizeof(*entry)); - if(hdb_value2entry(context, &data, &entry->entry)) + if(hdb_value2entry(context, &data, entry)) return NDBM_seq(context, db, flags, entry, 0); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - ret = hdb_unseal_keys (context, db, &entry->entry); + ret = hdb_unseal_keys (context, db, entry); if (ret) - hdb_free_entry (context, entry); + hdb_free_entry (context, db, entry); } - if (ret == 0 && entry->entry.principal == NULL) { - entry->entry.principal = malloc (sizeof(*entry->entry.principal)); - if (entry->entry.principal == NULL) { - hdb_free_entry (context, entry); + if (ret == 0 && entry->principal == NULL) { + entry->principal = malloc (sizeof(*entry->principal)); + if (entry->principal == NULL) { + hdb_free_entry (context, db, entry); ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); } else { - hdb_key2principal (context, &key_data, entry->entry.principal); + hdb_key2principal (context, &key_data, entry->principal); } } return ret; @@ -121,14 +121,14 @@ NDBM_seq(krb5_context context, HDB *db, static krb5_error_code -NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry) +NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry *entry) { return NDBM_seq(context, db, flags, entry, 1); } static krb5_error_code -NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry) +NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry *entry) { return NDBM_seq(context, db, flags, entry, 0); } @@ -140,8 +140,7 @@ open_lock_file(krb5_context context, const char *db_name, int *fd) int ret = 0; /* lock old and new databases */ - asprintf(&lock_file, "%s.lock", db_name); - if(lock_file == NULL) { + if (asprintf(&lock_file, "%s.lock", db_name) == -1) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } @@ -161,7 +160,8 @@ static krb5_error_code NDBM_rename(krb5_context context, HDB *db, const char *new_name) { int ret; - char *old_dir, *old_pag, *new_dir, *new_pag; + char *old_dir = NULL, *old_pag = NULL; + char *new_dir = NULL, *new_pag = NULL; int old_lock_fd, new_lock_fd; /* lock old and new databases */ @@ -190,10 +190,26 @@ NDBM_rename(krb5_context context, HDB *db, const char *new_name) return ret; } - asprintf(&old_dir, "%s.dir", db->hdb_name); - asprintf(&old_pag, "%s.pag", db->hdb_name); - asprintf(&new_dir, "%s.dir", new_name); - asprintf(&new_pag, "%s.pag", new_name); + if (asprintf(&old_dir, "%s.dir", db->hdb_name) == -1) { + old_dir = NULL; + ret = ENOMEM; + goto out; + } + if (asprintf(&old_pag, "%s.pag", db->hdb_name) == -1) { + old_pag = NULL; + ret = ENOMEM; + goto out; + } + if (asprintf(&new_dir, "%s.dir", new_name) == -1) { + new_dir = NULL; + ret = ENOMEM; + goto out; + } + if (asprintf(&new_pag, "%s.pag", new_name) == -1) { + new_pag = NULL; + ret = ENOMEM; + goto out; + } ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); if (ret) { @@ -203,6 +219,7 @@ NDBM_rename(krb5_context context, HDB *db, const char *new_name) krb5_set_error_message(context, ret, "rename: %s", strerror(ret)); } + out: free(old_dir); free(old_pag); free(new_dir); diff --git a/third_party/heimdal/lib/hdb/print.c b/third_party/heimdal/lib/hdb/print.c index 0d1e2855217d..7f2535881892 100644 --- a/third_party/heimdal/lib/hdb/print.c +++ b/third_party/heimdal/lib/hdb/print.c @@ -453,7 +453,8 @@ entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent) unsigned char *ptr; ptr = (unsigned char *)&last_pw_chg; - val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + val = ((unsigned long)ptr[3] << 24) | (ptr[2] << 16) + | (ptr[1] << 8) | ptr[0]; d.data = &val; d.length = sizeof (last_pw_chg); sz = append_string(context, sp, "\t%u\t%u\t", @@ -474,12 +475,16 @@ entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent) d.data = &val; d.length = sizeof (ent->modified_by->time); ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p); - if (ret) return ret; + if (ret) + return ret; plen = strlen(modby_p); sz = append_string(context, sp, "\t%u\t%u\t", mit_KRB5_TL_MOD_PRINC, d.length + plen + 1 /* NULL counted */); - if (sz == -1) return ENOMEM; + if (sz == -1) { + free(modby_p); + return ENOMEM; + } sz = append_hex(context, sp, 1, 1, &d); if (sz == -1) { free(modby_p); @@ -489,7 +494,8 @@ entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent) d.length = plen + 1; sz = append_hex(context, sp, 1, 1, &d); free(modby_p); - if (sz == -1) return ENOMEM; + if (sz == -1) + return ENOMEM; } /* * Dump keys (remembering to not include any with kvno higher than @@ -556,7 +562,7 @@ hdb_entry2string(krb5_context context, hdb_entry *ent, char **str) /* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */ krb5_error_code -hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, +hdb_print_entry(krb5_context context, HDB *db, hdb_entry *entry, void *data) { struct hdb_print_entry_arg *parg = data; @@ -572,10 +578,10 @@ hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, switch (parg->fmt) { case HDB_DUMP_HEIMDAL: - ret = entry2string_int(context, sp, &entry->entry); + ret = entry2string_int(context, sp, entry); break; case HDB_DUMP_MIT: - ret = entry2mit_string_int(context, sp, &entry->entry); + ret = entry2mit_string_int(context, sp, entry); break; default: heim_abort("Only two dump formats supported: Heimdal and MIT"); diff --git a/third_party/heimdal/lib/hdb/test_concurrency.c b/third_party/heimdal/lib/hdb/test_concurrency.c index 9c95e6390f40..35c01f59f594 100644 --- a/third_party/heimdal/lib/hdb/test_concurrency.c +++ b/third_party/heimdal/lib/hdb/test_concurrency.c @@ -70,7 +70,7 @@ threaded_reader(void *d) krb5_error_code ret; krb5_context context; struct tsync *s = d; - hdb_entry_ex entr; + hdb_entry entr; HDB *dbr = NULL; printf("Reader thread opening HDB\n"); @@ -101,7 +101,7 @@ threaded_reader(void *d) //(void) unlink(s->fname); krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name); } - free_HDB_entry(&entr.entry); + free_HDB_entry(&entr); /* Tell the writer to go ahead and write */ printf("Reader thread iterated one entry; telling writer to write more\n"); @@ -124,7 +124,7 @@ threaded_reader(void *d) "Could not iterate while writing to HDB %s", s->hdb_name); } printf("Reader thread iterated another entry\n"); - free_HDB_entry(&entr.entry); + free_HDB_entry(&entr); if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) { //(void) unlink(s->fname); krb5_warn(context, ret, @@ -154,7 +154,7 @@ forked_reader(struct tsync *s) { krb5_error_code ret; krb5_context context; - hdb_entry_ex entr; + hdb_entry entr; ssize_t bytes; char b[1]; HDB *dbr = NULL; @@ -172,6 +172,8 @@ forked_reader(struct tsync *s) while ((bytes = read(s->reader_go_pipe[0], b, sizeof(b))) == -1 && errno == EINTR) ; + if (bytes == -1) + err(1, "Could not read from reader-go pipe (error)"); /* Open a new HDB handle to read */ if ((ret = hdb_create(context, &dbr, s->hdb_name))) { @@ -188,13 +190,15 @@ forked_reader(struct tsync *s) krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name); } printf("Reader process iterated one entry\n"); - free_HDB_entry(&entr.entry); + free_HDB_entry(&entr); /* Tell the writer to go ahead and write */ printf("Reader process iterated one entry; telling writer to write more\n"); while ((bytes = write(s->writer_go_pipe[1], "", sizeof(""))) == -1 && errno == EINTR) ; + if (bytes == -1) + err(1, "Could not write to writer-go pipe (error)"); /* Wait for the writer to have written one more entry to the HDB */ @@ -213,13 +217,13 @@ forked_reader(struct tsync *s) krb5_err(context, 1, ret, "Could not iterate while writing to HDB %s", s->hdb_name); } - free_HDB_entry(&entr.entry); + free_HDB_entry(&entr); printf("Reader process iterated another entry\n"); if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) { //(void) unlink(s->fname); krb5_warn(context, ret, "HDB %s sees writes committed since starting iteration (%s)", - s->hdb_name, entr.entry.principal->name.name_string.val[0]); + s->hdb_name, entr.principal->name.name_string.val[0]); } else if (ret != HDB_ERR_NOENTRY) { //(void) unlink(s->fname); krb5_err(context, 1, ret, @@ -231,6 +235,8 @@ forked_reader(struct tsync *s) while ((bytes = write(s->writer_go_pipe[1], "", sizeof(""))) == -1 && errno == EINTR) ; + if (bytes == -1) + err(1, "Could not write to writer-go pipe (error)"); dbr->hdb_close(context, dbr); dbr->hdb_destroy(context, dbr); @@ -242,27 +248,27 @@ forked_reader(struct tsync *s) } static krb5_error_code -make_entry(krb5_context context, hdb_entry_ex *entry, const char *name) +make_entry(krb5_context context, hdb_entry *entry, const char *name) { krb5_error_code ret; memset(entry, 0, sizeof(*entry)); - entry->entry.kvno = 2; - entry->entry.keys.len = 0; - entry->entry.keys.val = NULL; - entry->entry.created_by.time = time(NULL); - entry->entry.modified_by = NULL; - entry->entry.valid_start = NULL; - entry->entry.valid_end = NULL; - entry->entry.max_life = NULL; - entry->entry.max_renew = NULL; - entry->entry.etypes = NULL; - entry->entry.generation = NULL; - entry->entry.extensions = NULL; - if ((ret = krb5_make_principal(context, &entry->entry.principal, + entry->kvno = 2; + entry->keys.len = 0; + entry->keys.val = NULL; + entry->created_by.time = time(NULL); + entry->modified_by = NULL; + entry->valid_start = NULL; + entry->valid_end = NULL; + entry->max_life = NULL; + entry->max_renew = NULL; + entry->etypes = NULL; + entry->generation = NULL; + entry->extensions = NULL; + if ((ret = krb5_make_principal(context, &entry->principal, "TEST.H5L.SE", name, NULL))) return ret; - if ((ret = krb5_make_principal(context, &entry->entry.created_by.principal, + if ((ret = krb5_make_principal(context, &entry->created_by.principal, "TEST.H5L.SE", "tester", NULL))) return ret; return 0; @@ -320,7 +326,7 @@ test_hdb_concurrency(char *name, const char *ext, int threaded) char *fname_ext = NULL; pthread_t reader_thread; struct tsync ts; - hdb_entry_ex entw; + hdb_entry entw; pid_t child = getpid(); HDB *dbw = NULL; int status; @@ -387,14 +393,14 @@ test_hdb_concurrency(char *name, const char *ext, int threaded) krb5_err(context, 1, ret, "Could not store entry for \"foo\" in HDB %s", name); } - free_HDB_entry(&entw.entry); + free_HDB_entry(&entw); if ((ret = make_entry(context, &entw, "bar")) || (ret = dbw->hdb_store(context, dbw, 0, &entw))) { (void) unlink(fname_ext); krb5_err(context, 1, ret, "Could not store entry for \"foo\" in HDB %s", name); } - free_HDB_entry(&entw.entry); + free_HDB_entry(&entw); /* Tell the reader to start reading */ readers_turn(&ts, child, threaded); @@ -407,7 +413,7 @@ test_hdb_concurrency(char *name, const char *ext, int threaded) "Could not store entry for \"foobar\" in HDB %s " "while iterating it", name); } - free_HDB_entry(&entw.entry); + free_HDB_entry(&entw); /* Tell the reader to go again */ readers_turn(&ts, child, threaded); diff --git a/third_party/heimdal/lib/hdb/test_namespace.c b/third_party/heimdal/lib/hdb/test_namespace.c index 6aaecc083ec7..a4c44ba190e5 100644 --- a/third_party/heimdal/lib/hdb/test_namespace.c +++ b/third_party/heimdal/lib/hdb/test_namespace.c @@ -106,7 +106,7 @@ TDB_unlock(krb5_context context, HDB *db) } static krb5_error_code -TDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +TDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { /* XXX Implement */ /* Tricky thing: heim_dict_iterate_f() is inconvenient here */ @@ -115,7 +115,7 @@ TDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) } static krb5_error_code -TDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +TDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { /* XXX Implement */ /* Tricky thing: heim_dict_iterate_f() is inconvenient here */ @@ -151,14 +151,13 @@ TDB__put(krb5_context context, HDB *db, int rplc, krb5_data kd, krb5_data vd) { krb5_error_code ret = 0; TEST_HDB *tdb = (void *)db; - heim_object_t e = NULL; heim_object_t k = NULL; heim_object_t v = NULL; if ((k = heim_data_create(kd.data, kd.length)) == NULL || (v = heim_data_create(vd.data, vd.length)) == NULL) ret = krb5_enomem(context); - if (ret == 0 && !rplc && (e = heim_dict_get_value(tdb->dict, k)) != NULL) + if (ret == 0 && !rplc && heim_dict_get_value(tdb->dict, k) != NULL) ret = HDB_ERR_EXISTS; if (ret == 0 && heim_dict_set_value(tdb->dict, k, v)) ret = krb5_enomem(context); @@ -172,11 +171,11 @@ TDB__del(krb5_context context, HDB *db, krb5_data key) { krb5_error_code ret = 0; TEST_HDB *tdb = (void *)db; - heim_object_t k, v; + heim_object_t k; if ((k = heim_data_create(key.data, key.length)) == NULL) ret = krb5_enomem(context); - if (ret == 0 && (v = heim_dict_get_value(tdb->dict, k)) == NULL) + if (ret == 0 && heim_dict_get_value(tdb->dict, k) == NULL) ret = HDB_ERR_NOENTRY; if (ret == 0) heim_dict_delete_key(tdb->dict, k); @@ -198,7 +197,8 @@ hdb_test_create(krb5_context context, struct HDB **db, const char *arg) if ((tdb = calloc(1, sizeof(tdb[0]))) == NULL || (tdb->hdb.hdb_name = strdup(arg)) == NULL || (tdb->dict = heim_dict_create(10)) == NULL) { - free(tdb->hdb.hdb_name); + if (tdb) + free(tdb->hdb.hdb_name); free(tdb); return krb5_enomem(context); } @@ -337,7 +337,7 @@ static void make_namespace(krb5_context context, HDB *db, const char *name) { krb5_error_code ret = 0; - hdb_entry_ex e; + hdb_entry e; Key k; memset(&k, 0, sizeof(k)); @@ -346,85 +346,83 @@ make_namespace(krb5_context context, HDB *db, const char *name) /* Setup the HDB entry */ memset(&e, 0, sizeof(e)); - e.ctx = 0; - e.free_entry = 0; - e.entry.created_by.time = krs[0].epoch; - e.entry.valid_start = e.entry.valid_end = e.entry.pw_end = 0; - e.entry.generation = 0; - e.entry.flags = int2HDBFlags(0); - e.entry.flags.server = e.entry.flags.client = 1; - e.entry.flags.virtual = 1; + e.created_by.time = krs[0].epoch; + e.valid_start = e.valid_end = e.pw_end = 0; + e.generation = 0; + e.flags = int2HDBFlags(0); + e.flags.server = e.flags.client = 1; + e.flags.virtual = 1; /* Setup etypes */ if (ret == 0 && - (e.entry.etypes = malloc(sizeof(*e.entry.etypes))) == NULL) + (e.etypes = malloc(sizeof(*e.etypes))) == NULL) ret = krb5_enomem(context); if (ret == 0) - e.entry.etypes->len = 3; + e.etypes->len = 3; if (ret == 0 && - (e.entry.etypes->val = calloc(e.entry.etypes->len, - sizeof(e.entry.etypes->val[0]))) == NULL) + (e.etypes->val = calloc(e.etypes->len, + sizeof(e.etypes->val[0]))) == NULL) ret = krb5_enomem(context); if (ret == 0) { - e.entry.etypes->val[0] = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128; - e.entry.etypes->val[1] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192; - e.entry.etypes->val[2] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96; + e.etypes->val[0] = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128; + e.etypes->val[1] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192; + e.etypes->val[2] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96; } /* Setup max_life and max_renew */ if (ret == 0 && - (e.entry.max_life = malloc(sizeof(*e.entry.max_life))) == NULL) + (e.max_life = malloc(sizeof(*e.max_life))) == NULL) ret = krb5_enomem(context); if (ret == 0 && - (e.entry.max_renew = malloc(sizeof(*e.entry.max_renew))) == NULL) + (e.max_renew = malloc(sizeof(*e.max_renew))) == NULL) ret = krb5_enomem(context); if (ret == 0) /* Make it long, so we see the clamped max */ - *e.entry.max_renew = 2 * ((*e.entry.max_life = 15 * 24 * 3600)); + *e.max_renew = 2 * ((*e.max_life = 15 * 24 * 3600)); /* Setup principal name and created_by */ if (ret == 0) - ret = krb5_parse_name(context, name, &e.entry.principal); + ret = krb5_parse_name(context, name, &e.principal); if (ret == 0) ret = krb5_parse_name(context, "admin@BAR.EXAMPLE", - &e.entry.created_by.principal); + &e.created_by.principal); /* Make base keys for first epoch */ if (ret == 0) - ret = make_base_key(context, e.entry.principal, base_pw[0], &k.key); + ret = make_base_key(context, e.principal, base_pw[0], &k.key); if (ret == 0) - add_Keys(&e.entry.keys, &k); + add_Keys(&e.keys, &k); if (ret == 0) - ret = hdb_entry_set_pw_change_time(context, &e.entry, krs[0].epoch); + ret = hdb_entry_set_pw_change_time(context, &e, krs[0].epoch); free_Key(&k); - e.entry.kvno = krs[0].base_key_kvno; + e.kvno = krs[0].base_key_kvno; /* Move them to history */ if (ret == 0) - ret = hdb_add_current_keys_to_history(context, &e.entry); - free_Keys(&e.entry.keys); + ret = hdb_add_current_keys_to_history(context, &e); + free_Keys(&e.keys); /* Make base keys for second epoch */ if (ret == 0) - ret = make_base_key(context, e.entry.principal, base_pw[1], &k.key); + ret = make_base_key(context, e.principal, base_pw[1], &k.key); if (ret == 0) - add_Keys(&e.entry.keys, &k); - e.entry.kvno = krs[1].base_key_kvno; + add_Keys(&e.keys, &k); + e.kvno = krs[1].base_key_kvno; if (ret == 0) - ret = hdb_entry_set_pw_change_time(context, &e.entry, krs[1].epoch); + ret = hdb_entry_set_pw_change_time(context, &e, krs[1].epoch); /* Add the key rotation metadata */ if (ret == 0) - ret = hdb_entry_add_key_rotation(context, &e.entry, 0, &krs[0]); + ret = hdb_entry_add_key_rotation(context, &e, 0, &krs[0]); if (ret == 0) - ret = hdb_entry_add_key_rotation(context, &e.entry, 0, &krs[1]); + ret = hdb_entry_add_key_rotation(context, &e, 0, &krs[1]); if (ret == 0) ret = db->hdb_store(context, db, 0, &e); if (ret) krb5_err(context, 1, ret, "failed to setup a namespace principal"); free_Key(&k); - hdb_free_entry(context, &e); + hdb_free_entry(context, db, &e); } #define WK_PREFIX "WELLKNOWN/" HDB_WK_NAMESPACE "/" @@ -449,7 +447,7 @@ static const char *unexpected[] = { * different time offsets in each period. */ #define NUM_OFFSETS 5 -static hdb_entry_ex e[ +static hdb_entry e[ (sizeof(expected) / sizeof(expected[0])) * (sizeof(krs) / sizeof(krs[0])) * NUM_OFFSETS @@ -481,8 +479,8 @@ fetch_entries(krb5_context context, krb5_error_code ret = 0; krb5_principal p = NULL; krb5_keyblock base_key, dk; - hdb_entry_ex *ep; - hdb_entry_ex no; + hdb_entry *ep; + hdb_entry no; size_t i, b; int toffset = 0; @@ -543,14 +541,14 @@ fetch_entries(krb5_context context, } } else { if (ret == 0 && - !krb5_principal_compare(context, p, ep->entry.principal)) + !krb5_principal_compare(context, p, ep->principal)) krb5_errx(context, 1, "wrong principal in fetched entry"); } { HDB_Ext_KeySet *hist_keys; HDB_extension *ext; - ext = hdb_find_extension(&ep->entry, + ext = hdb_find_extension(ep, choice_HDB_extension_data_hist_keys); if (ext) { /* Sort key history by kvno, why not */ @@ -613,23 +611,23 @@ fetch_entries(krb5_context context, if (ret) krb5_err(context, 1, ret, "deriving keys for comparison"); - if (kvno != ep->entry.kvno) - krb5_errx(context, 1, "kvno mismatch (%u != %u)", kvno, ep->entry.kvno); - (void) hdb_entry_get_pw_change_time(&ep->entry, &chg_time); + if (kvno != ep->kvno) + krb5_errx(context, 1, "kvno mismatch (%u != %u)", kvno, ep->kvno); + (void) hdb_entry_get_pw_change_time(ep, &chg_time); if (set_time != chg_time) krb5_errx(context, 1, "key change time mismatch"); - if (ep->entry.keys.len == 0) + if (ep->keys.len == 0) krb5_errx(context, 1, "no keys!"); - if (ep->entry.keys.val[0].key.keytype != dk.keytype) + if (ep->keys.val[0].key.keytype != dk.keytype) krb5_errx(context, 1, "enctype mismatch!"); - if (ep->entry.keys.val[0].key.keyvalue.length != + if (ep->keys.val[0].key.keyvalue.length != dk.keyvalue.length) krb5_errx(context, 1, "key length mismatch!"); - if (memcmp(ep->entry.keys.val[0].key.keyvalue.data, + if (memcmp(ep->keys.val[0].key.keyvalue.data, dk.keyvalue.data, dk.keyvalue.length) != 0) krb5_errx(context, 1, "key mismatch!"); - if (memcmp(ep->entry.keys.val[0].key.keyvalue.data, - e[b + i - 1].entry.keys.val[0].key.keyvalue.data, + if (memcmp(ep->keys.val[0].key.keyvalue.data, + e[b + i - 1].keys.val[0].key.keyvalue.data, dk.keyvalue.length) == 0) krb5_errx(context, 1, "different virtual principals have the same keys!"); /* XXX Add check that we have the expected number of history keys */ @@ -655,14 +653,14 @@ check_kvnos(krb5_context context) for (k = 0; k < sizeof(e)/sizeof(e[0]); k++) { HDB_Ext_KeySet *hist_keys; HDB_extension *ext; - hdb_entry_ex *ep; + hdb_entry *ep; int match = 0; if ((k % NUM_OFFSETS) != i) continue; ep = &e[k]; - if (ep->entry.principal == NULL) + if (ep->principal == NULL) continue; /* Didn't fetch this one */ /* @@ -670,15 +668,15 @@ check_kvnos(krb5_context context) * or else add them to `keysets'. */ for (m = 0; m < keysets.len; m++) { - if (ep->entry.kvno == keysets.val[m].kvno) { + if (ep->kvno == keysets.val[m].kvno) { /* Check the key is the same */ - if (ep->entry.keys.val[0].key.keytype != + if (ep->keys.val[0].key.keytype != keysets.val[m].keys.val[0].key.keytype || - ep->entry.keys.val[0].key.keyvalue.length != + ep->keys.val[0].key.keyvalue.length != keysets.val[m].keys.val[0].key.keyvalue.length || - memcmp(ep->entry.keys.val[0].key.keyvalue.data, + memcmp(ep->keys.val[0].key.keyvalue.data, keysets.val[m].keys.val[0].key.keyvalue.data, - ep->entry.keys.val[0].key.keyvalue.length) != 0) + ep->keys.val[0].key.keyvalue.length) != 0) krb5_errx(context, 1, "key mismatch for same princ & kvno"); match = 1; @@ -687,8 +685,8 @@ check_kvnos(krb5_context context) if (m == keysets.len) { hdb_keyset ks; - ks.kvno = ep->entry.kvno; - ks.keys = ep->entry.keys; + ks.kvno = ep->kvno; + ks.keys = ep->keys; ks.set_time = 0; if (add_HDB_Ext_KeySet(&keysets, &ks)) krb5_err(context, 1, ENOMEM, "out of memory"); @@ -698,7 +696,7 @@ check_kvnos(krb5_context context) continue; /* For all non-current keysets, repeat the above */ - ext = hdb_find_extension(&ep->entry, + ext = hdb_find_extension(ep, choice_HDB_extension_data_hist_keys); if (!ext) continue; @@ -706,20 +704,20 @@ check_kvnos(krb5_context context) for (p = 0; p < hist_keys->len; p++) { for (m = 0; m < keysets.len; m++) { if (keysets.val[m].kvno == hist_keys->val[p].kvno) - if (ep->entry.keys.val[0].key.keytype != + if (ep->keys.val[0].key.keytype != keysets.val[m].keys.val[0].key.keytype || - ep->entry.keys.val[0].key.keyvalue.length != + ep->keys.val[0].key.keyvalue.length != keysets.val[m].keys.val[0].key.keyvalue.length || - memcmp(ep->entry.keys.val[0].key.keyvalue.data, + memcmp(ep->keys.val[0].key.keyvalue.data, keysets.val[m].keys.val[0].key.keyvalue.data, - ep->entry.keys.val[0].key.keyvalue.length) != 0) + ep->keys.val[0].key.keyvalue.length) != 0) krb5_errx(context, 1, "key mismatch for same princ & kvno"); } if (m == keysets.len) { hdb_keyset ks; - ks.kvno = ep->entry.kvno; - ks.keys = ep->entry.keys; + ks.kvno = ep->kvno; + ks.keys = ep->keys; ks.set_time = 0; if (add_HDB_Ext_KeySet(&keysets, &ks)) krb5_err(context, 1, ENOMEM, "out of memory"); @@ -743,15 +741,14 @@ print_em(krb5_context context) if (0 == i % (sizeof(expected)/sizeof(expected[0]))) continue; - if (e[i].entry.principal == NULL) + if (e[i].principal == NULL) continue; - hex_encode(e[i].entry.keys.val[0].key.keyvalue.data, - e[i].entry.keys.val[0].key.keyvalue.length, &x); - printf("%s %u %s\n", x, e[i].entry.kvno, name); + hex_encode(e[i].keys.val[0].key.keyvalue.data, + e[i].keys.val[0].key.keyvalue.length, &x); + printf("%s %u %s\n", x, e[i].kvno, name); free(x); - ext = hdb_find_extension(&e[i].entry, - choice_HDB_extension_data_hist_keys); + ext = hdb_find_extension(&e[i], choice_HDB_extension_data_hist_keys); if (!ext) continue; hist_keys = &ext->data.u.hist_keys; @@ -759,6 +756,7 @@ print_em(krb5_context context) hex_encode(hist_keys->val[p].keys.val[0].key.keyvalue.data, hist_keys->val[p].keys.val[0].key.keyvalue.length, &x); printf("%s %u %s\n", x, hist_keys->val[p].kvno, name); + free(x); } } } @@ -773,12 +771,12 @@ check_expected_kvnos(krb5_context context) for (i = 0; i < sizeof(expected)/sizeof(expected[0]); i++) { for (k = 0; k < sizeof(krs)/sizeof(krs[0]); k++) { - hdb_entry_ex *ep = &e[k * sizeof(expected)/sizeof(expected[0]) + i]; + hdb_entry *ep = &e[k * sizeof(expected)/sizeof(expected[0]) + i]; - if (ep->entry.principal == NULL) + if (ep->principal == NULL) continue; for (m = 0; m < NUM_OFFSETS; m++) { - ext = hdb_find_extension(&ep->entry, + ext = hdb_find_extension(ep, choice_HDB_extension_data_hist_keys); if (!ext) continue; @@ -789,7 +787,7 @@ check_expected_kvnos(krb5_context context) } } fprintf(stderr, "%s at %lu: kvno %u\n", expected[i], k, - ep->entry.kvno); + ep->kvno); } } } @@ -936,7 +934,7 @@ main(int argc, char **argv) /* Cleanup */ for (i = 0; ret == 0 && i < sizeof(e) / sizeof(e[0]); i++) - hdb_free_entry(context, &e[i]); + hdb_free_entry(context, db, &e[i]); db->hdb_destroy(context, db); krb5_free_context(context); return 0; diff --git a/third_party/heimdal/lib/hdb/version-script.map b/third_party/heimdal/lib/hdb/version-script.map index 0846f7337430..058060dae0c1 100644 --- a/third_party/heimdal/lib/hdb/version-script.map +++ b/third_party/heimdal/lib/hdb/version-script.map @@ -70,7 +70,6 @@ HEIMDAL_HDB_1.0 { hdb_prune_keys; hdb_prune_keys_kvno; hdb_read_master_key; - hdb_remove_base_keys; hdb_remove_keys; hdb_replace_extension; hdb_seal_key; diff --git a/third_party/heimdal/lib/hx509/Makefile.am b/third_party/heimdal/lib/hx509/Makefile.am index e32da3b93c3d..214dabf0e831 100644 --- a/third_party/heimdal/lib/hx509/Makefile.am +++ b/third_party/heimdal/lib/hx509/Makefile.am @@ -11,7 +11,7 @@ BUILT_SOURCES = \ hx509_err.c \ hx509_err.h -AM_YFLAGS = -d +AM_YFLAGS = -o sel-gram.c dist_libhx509_la_SOURCES = \ ca.c \ @@ -50,6 +50,7 @@ dist_libhx509_la_SOURCES = \ dist_libhx509template_la_SOURCES = $(dist_libhx509_la_SOURCES) +sel-gram.h: sel-gram.c sel-lex.c: sel-gram.h libhx509_la_DEPENDENCIES = version-script.map diff --git a/third_party/heimdal/lib/hx509/ca.c b/third_party/heimdal/lib/hx509/ca.c index 807621c21d15..3d62b93fa57e 100644 --- a/third_party/heimdal/lib/hx509/ca.c +++ b/third_party/heimdal/lib/hx509/ca.c @@ -2353,7 +2353,6 @@ count_sans(hx509_request req, size_t *n) for (i = 0; ret == 0; i++) { hx509_san_type san_type; - frees(&s); ret = hx509_request_get_san(req, i, &san_type, &s); if (ret) break; @@ -2370,6 +2369,7 @@ count_sans(hx509_request req, size_t *n) } frees(&s); } + free(s); return ret == HX509_NO_ITEM ? 0 : ret; } @@ -2565,9 +2565,9 @@ get_cf(hx509_context context, } *out = heim_config_get_list(context->hcontext, cf, label, svc, NULL); - if (*out) + if (*out) { ret = 0; - if (ret) { + } else { heim_log_msg(context->hcontext, logf, 3, NULL, "No configuration for %s %s certificate's realm " "-> %s -> kx509 -> %s%s%s", def, label, realm, label, @@ -2741,7 +2741,8 @@ set_tbs(hx509_context context, realm); /* Populate requested certificate extensions from CSR/CSRPlus if allowed */ - ret = hx509_ca_tbs_set_from_csr(context, tbs, req); + if (ret == 0) + ret = hx509_ca_tbs_set_from_csr(context, tbs, req); if (ret == 0) ret = set_template(context, logf, cf, tbs); @@ -2939,6 +2940,8 @@ _hx509_ca_issue_certificate(hx509_context context, hx509_request_authorize_ku(req, ku); ret = get_cf(context, cf, logf, req, cprinc, &cf); + if (ret) + return ret; if ((ca = heim_config_get_string(context->hcontext, cf, "ca", NULL)) == NULL) { @@ -3050,9 +3053,8 @@ _hx509_ca_issue_certificate(hx509_context context, hx509_env_free(&env); /* All done with the TBS, sign/issue the certificate */ - ret = hx509_ca_sign(context, tbs, signer, &cert); - if (ret) - goto out; + if (ret == 0) + ret = hx509_ca_sign(context, tbs, signer, &cert); /* * Gather the certificate and chain into a MEMORY store, being careful not @@ -3063,8 +3065,9 @@ _hx509_ca_issue_certificate(hx509_context context, * the full chain in the issuer credential store and copying only the certs * (but not the private keys) is safer and easier to configure. */ - ret = hx509_certs_init(context, "MEMORY:certs", - HX509_CERTS_NO_PRIVATE_KEYS, NULL, out); + if (ret == 0) + ret = hx509_certs_init(context, "MEMORY:certs", + HX509_CERTS_NO_PRIVATE_KEYS, NULL, out); if (ret == 0) ret = hx509_certs_add(context, *out, cert); if (ret == 0 && send_chain) { diff --git a/third_party/heimdal/lib/hx509/cert.c b/third_party/heimdal/lib/hx509/cert.c index 0d99a748fc6a..33805b8ed1a7 100644 --- a/third_party/heimdal/lib/hx509/cert.c +++ b/third_party/heimdal/lib/hx509/cert.c @@ -893,9 +893,12 @@ HX509_LIB_FUNCTION void HX509_LIB_CALL hx509_free_octet_string_list(hx509_octet_string_list *list) { size_t i; - for (i = 0; i < list->len; i++) - der_free_octet_string(&list->val[i]); - free(list->val); + + if (list->val) { + for (i = 0; i < list->len; i++) + der_free_octet_string(&list->val[i]); + free(list->val); + } list->val = NULL; list->len = 0; } @@ -2438,10 +2441,9 @@ hx509_verify_path(hx509_context context, * EE checking below. */ type = EE_CERT; - /* FALLTHROUGH */ } } - /* FALLTHROUGH */ + fallthrough; case EE_CERT: /* * If there where any proxy certificates in the chain @@ -2808,6 +2810,12 @@ _hx509_set_cert_attribute(hx509_context context, { hx509_cert_attribute a; void *d; + int ret; + + /* + * TODO: Rewrite this (and hx509_cert_attribute, and _hx509_cert_attrs) to + * use the add_AttributeValues() util generated by asn1_compile. + */ if (hx509_cert_get_attribute(cert, oid) != NULL) return 0; @@ -2824,13 +2832,18 @@ _hx509_set_cert_attribute(hx509_context context, if (a == NULL) return ENOMEM; - der_copy_octet_string(attr, &a->data); - der_copy_oid(oid, &a->oid); - - cert->attrs.val[cert->attrs.len] = a; - cert->attrs.len++; + ret = der_copy_octet_string(attr, &a->data); + if (ret == 0) + ret = der_copy_oid(oid, &a->oid); + if (ret == 0) { + cert->attrs.val[cert->attrs.len] = a; + cert->attrs.len++; + } else { + der_free_octet_string(&a->data); + free(a); + } - return 0; + return ret; } /** @@ -3705,13 +3718,12 @@ _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env) goto out; ret = hx509_name_to_string(name, &buf); - if (ret) { - hx509_name_free(&name); + hx509_name_free(&name); + if (ret) goto out; - } ret = hx509_env_add(context, &envcert, "subject", buf); - hx509_name_free(&name); + hx509_xfree(buf); if (ret) goto out; diff --git a/third_party/heimdal/lib/hx509/cms.c b/third_party/heimdal/lib/hx509/cms.c index 453762bd10f6..d2728a38c2f9 100644 --- a/third_party/heimdal/lib/hx509/cms.c +++ b/third_party/heimdal/lib/hx509/cms.c @@ -182,7 +182,7 @@ fill_CMSIdentifier(const hx509_cert cert, &id->u.subjectKeyIdentifier); if (ret == 0) break; - /* FALLTHROUGH */ + fallthrough; case CMS_ID_NAME: { hx509_name name; @@ -1565,7 +1565,9 @@ hx509_cms_create_signed(hx509_context context, sigctx.sd.version = cMSVersion_v3; - der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); + ret = der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); + if (ret) + goto out; /** * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures. diff --git a/third_party/heimdal/lib/hx509/collector.c b/third_party/heimdal/lib/hx509/collector.c index dd6222687af4..7b46809816cf 100644 --- a/third_party/heimdal/lib/hx509/collector.c +++ b/third_party/heimdal/lib/hx509/collector.c @@ -191,8 +191,9 @@ match_localkeyid(hx509_context context, q.local_key_id = &value->localKeyId; ret = hx509_certs_find(context, certs, &q, &cert); + if (ret == 0 && cert == NULL) + ret = HX509_CERT_NOT_FOUND; if (ret == 0) { - if (value->private_key) _hx509_cert_assign_key(cert, value->private_key); hx509_cert_free(cert); diff --git a/third_party/heimdal/lib/hx509/crypto.c b/third_party/heimdal/lib/hx509/crypto.c index 77e721064ef1..8d368ed9c4d1 100644 --- a/third_party/heimdal/lib/hx509/crypto.c +++ b/third_party/heimdal/lib/hx509/crypto.c @@ -436,6 +436,8 @@ rsa_private_key2SPKI(hx509_context context, memset(spki, 0, sizeof(*spki)); len = i2d_RSAPublicKey(private_key->private_key.rsa, NULL); + if (len < 0) + return -1; spki->subjectPublicKey.data = malloc(len); if (spki->subjectPublicKey.data == NULL) { @@ -1625,6 +1627,8 @@ _hx509_private_key_export(hx509_context context, hx509_key_format_t format, heim_octet_string *data) { + data->length = 0; + data->data = NULL; if (key->ops->export == NULL) { hx509_clear_error_string(context); return HX509_UNIMPLEMENTED_OPERATION; diff --git a/third_party/heimdal/lib/hx509/error.c b/third_party/heimdal/lib/hx509/error.c index d3ebd1bf6487..aee4f79e747d 100644 --- a/third_party/heimdal/lib/hx509/error.c +++ b/third_party/heimdal/lib/hx509/error.c @@ -147,48 +147,28 @@ hx509_enomem(hx509_context context) HX509_LIB_FUNCTION char * HX509_LIB_CALL hx509_get_error_string(hx509_context context, int error_code) { - heim_error_t msg; - heim_string_t s; - char *str = NULL; - - if (context == NULL) { - const char *sys_err_msg; - - /* This case should only happen on hx509_context_init() failure */ - if ((sys_err_msg = strerror(error_code))) { - if (asprintf(&str, "hx509_context_init system error: %s (%d)", - sys_err_msg, error_code) == -1) - return NULL; - return str; - } - if (asprintf(&str, "hx509_context_init unknown error: %d", - error_code) == -1) - return NULL; - return str; - } + heim_string_t s = NULL; + const char *cstr = NULL; + char *str; - msg = context->error; - if (msg == NULL || heim_error_get_code(msg) != error_code) { - const char *cstr; - - cstr = com_right(context->et_list, error_code); - if (cstr) - return strdup(cstr); - cstr = strerror(error_code); - if (cstr) - return strdup(cstr); - if (asprintf(&str, "", error_code) == -1) - return NULL; - return str; - } + if (context) { + if (context->error && + heim_error_get_code(context->error) == error_code && + (s = heim_error_copy_string(context->error))) + cstr = heim_string_get_utf8(s); - s = heim_error_copy_string(msg); - if (s) { - const char *cstr = heim_string_get_utf8(s); - if (cstr) - str = strdup(cstr); - heim_release(s); - } + if (cstr == NULL) + cstr = com_right(context->et_list, error_code); + + if (cstr == NULL && error_code > -1) + cstr = strerror(error_code); + } /* else this could be an error in hx509_context_init() */ + + if (cstr == NULL) + cstr = error_message(error_code); /* never returns NULL */ + + str = strdup(cstr); + heim_release(s); return str; } @@ -218,9 +198,11 @@ hx509_free_error_string(char *str) * @ingroup hx509_error */ -HX509_LIB_FUNCTION void HX509_LIB_CALL +HX509_LIB_NORETURN_FUNCTION + __attribute__ ((__noreturn__, __format__ (__printf__, 4, 5))) +void HX509_LIB_CALL hx509_err(hx509_context context, int exit_code, - int error_code, const char *fmt, ...) + int error_code, const char *fmt, ...) { va_list ap; const char *msg; diff --git a/third_party/heimdal/lib/hx509/file.c b/third_party/heimdal/lib/hx509/file.c index 1b5ca3eae710..a22f6252cfa7 100644 --- a/third_party/heimdal/lib/hx509/file.c +++ b/third_party/heimdal/lib/hx509/file.c @@ -230,7 +230,7 @@ hx509_pem_read(hx509_context context, where = INDATA; goto indata; } - /* FALLTHROUGH */ + fallthrough; case INHEADER: if (buf[0] == '\0') { where = INDATA; @@ -342,17 +342,15 @@ _hx509_erase_file(hx509_context context, const char *fn) if (ret == -1 && errno == ENOENT) return 0; if (ret == -1) { - hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: " - "stat of \"%s\": %s", fn, strerror(ret)); + hx509_set_error_string(context, 0, errno, "hx509_certs_destroy: " + "stat of \"%s\": %s", fn, strerror(errno)); return errno; } fd = open(fn, O_RDWR | O_BINARY | O_CLOEXEC | O_NOFOLLOW); + if (fd < 0) + return errno == ENOENT ? 0 : errno; rk_cloexec(fd); - if (ret == -1 && errno == ENOENT) - return 0; - if (ret == -1) - return errno; if (unlink(fn) < 0) { ret = errno; diff --git a/third_party/heimdal/lib/hx509/hxtool.c b/third_party/heimdal/lib/hx509/hxtool.c index 43c4713d1163..1bcfdfa44e9d 100644 --- a/third_party/heimdal/lib/hx509/hxtool.c +++ b/third_party/heimdal/lib/hx509/hxtool.c @@ -412,17 +412,19 @@ cms_create_sd(struct cms_create_sd_options *opt, int argc, char **argv) size_t sz; void *p; int ret, flags = 0; - char *infile, *outfile = NULL; + const char *outfile = NULL; + char *infile, *freeme = NULL; memset(&contentType, 0, sizeof(contentType)); infile = argv[0]; if (argc < 2) { - ret = asprintf(&outfile, "%s.%s", infile, + ret = asprintf(&freeme, "%s.%s", infile, opt->pem_flag ? "pem" : "cms-signeddata"); - if (ret == -1 || outfile == NULL) + if (ret == -1 || freeme == NULL) errx(1, "out of memory"); + outfile = freeme; } else outfile = argv[1]; @@ -549,6 +551,7 @@ cms_create_sd(struct cms_create_sd_options *opt, int argc, char **argv) hx509_certs_free(&signer); free(o.data); + free(freeme); return 0; } @@ -843,6 +846,7 @@ pcert_validate(struct validate_options *opt, int argc, char **argv) hx509_certs_iter_f(context, certs, validate_f, ctx); hx509_certs_free(&certs); argv++; + free(sn); } hx509_validate_ctx_free(ctx); @@ -1263,6 +1267,7 @@ revoke_print(struct revoke_print_options *opt, int argc, char **argv) if (ret) warnx("hx509_revoke_print: %d", ret); + hx509_revoke_free(&revoke_ctx); return ret; } @@ -1363,7 +1368,7 @@ get_key(const char *fn, const char *type, int optbits, int ret = 0; if (type) { - struct hx509_generate_private_context *gen_ctx; + struct hx509_generate_private_context *gen_ctx = NULL; if (strcasecmp(type, "rsa") != 0) errx(1, "can only handle rsa keys for now"); @@ -1375,6 +1380,7 @@ get_key(const char *fn, const char *type, int optbits, ret = _hx509_generate_private_key_bits(context, gen_ctx, optbits); if (ret == 0) ret = _hx509_generate_private_key(context, gen_ctx, signer); + _hx509_generate_private_key_free(&gen_ctx); if (ret) hx509_err(context, 1, ret, "failed to generate private key of type %s", type); @@ -1420,6 +1426,7 @@ generate_key(struct generate_key_options *opt, int argc, char **argv) const char *type = opt->type_string ? opt->type_string : "rsa"; int bits = opt->key_bits_integer ? opt->key_bits_integer : 2048; + memset(&signer, 0, sizeof(signer)); get_key(argv[0], type, bits, &signer); hx509_private_key_free(&signer); return 0; @@ -1436,6 +1443,7 @@ request_create(struct request_create_options *opt, int argc, char **argv) const char *outfile = argv[0]; memset(&key, 0, sizeof(key)); + memset(&signer, 0, sizeof(signer)); get_key(opt->key_string, opt->generate_key_string, @@ -2416,6 +2424,7 @@ test_crypto(struct test_crypto_options *opt, int argc, char ** argv) hx509_err(context, 1, ret, "hx509_cert_iter"); hx509_certs_free(&certs); + hx509_verify_destroy_ctx(vctx); return 0; } @@ -2507,6 +2516,7 @@ crl_sign(struct crl_sign_options *opt, int argc, char **argv) ret = hx509_certs_append(context, revoked, lock, sn); if (ret) hx509_err(context, 1, ret, "hx509_certs_append: %s", sn); + free(sn); } hx509_crl_add_revoked_certs(context, crl, revoked); @@ -2775,9 +2785,12 @@ acert1_kus(struct acert_options *opt, size_t unwanted = 0; size_t wanted = opt->has_ku_strings.num_strings; size_t i, k, sz; + int ret; memset(&ku, 0, sizeof(ku)); - decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &sz); + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &sz); + if (ret) + return ret; ku_num = KeyUsage2int(ku); /* Validate requested key usage values */ @@ -2983,7 +2996,7 @@ acert1(struct acert_options *opt, size_t cert_num, hx509_cert cert, int *matched ekus_wanted = opt->has_eku_strings.num_strings; kus_wanted = opt->has_ku_strings.num_strings; wanted = sans_wanted + ekus_wanted + kus_wanted; - found = sans_found = ekus_found = kus_found = 0; + sans_found = ekus_found = kus_found = 0; if (e == NULL) { if (wanted) @@ -3080,6 +3093,8 @@ acert(struct acert_options *opt, int argc, char **argv) ret = acert1(opt, n++, cert, &matched); if (matched) break; + hx509_cert_free(cert); + cert = NULL; } if (cursor) (void) hx509_certs_end_seq(context, certs, cursor); @@ -3093,6 +3108,7 @@ acert(struct acert_options *opt, int argc, char **argv) if (ret) hx509_err(context, 1, ret, "Matching certificate did not meet " "requirements"); + hx509_cert_free(cert); free(sn); return 0; } diff --git a/third_party/heimdal/lib/hx509/keyset.c b/third_party/heimdal/lib/hx509/keyset.c index ef3465050225..f25cdf4e419b 100644 --- a/third_party/heimdal/lib/hx509/keyset.c +++ b/third_party/heimdal/lib/hx509/keyset.c @@ -561,11 +561,14 @@ hx509_certs_find(hx509_context context, break; if (_hx509_query_match_cert(context, q, c)) { *r = c; + c = NULL; break; } hx509_cert_free(c); + c = NULL; } + hx509_cert_free(c); hx509_certs_end_seq(context, certs, cursor); if (ret) return ret; @@ -573,7 +576,7 @@ hx509_certs_find(hx509_context context, * Return HX509_CERT_NOT_FOUND if no certificate in certs matched * the query. */ - if (c == NULL) { + if (*r == NULL) { hx509_clear_error_string(context); return HX509_CERT_NOT_FOUND; } diff --git a/third_party/heimdal/lib/hx509/ks_file.c b/third_party/heimdal/lib/hx509/ks_file.c index b22093cd4526..880668b45616 100644 --- a/third_party/heimdal/lib/hx509/ks_file.c +++ b/third_party/heimdal/lib/hx509/ks_file.c @@ -548,7 +548,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) { struct store_ctx *sc = ctx; heim_octet_string data; - int ret; + int ret = 0; if (hx509_cert_have_private_key_only(c)) { data.length = 0; @@ -564,15 +564,17 @@ store_func(hx509_context context, void *ctx, hx509_cert c) /* Can't store both. Well, we could, but nothing will support it */ if (data.data) { fwrite(data.data, data.length, 1, sc->f); - free(data.data); } else if (_hx509_cert_private_key_exportable(c) && !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) { hx509_private_key key = _hx509_cert_private_key(c); + free(data.data); + data.length = 0; + data.data = NULL; ret = _hx509_private_key_export(context, key, HX509_KEY_FORMAT_DER, &data); - fwrite(data.data, data.length, 1, sc->f); - free(data.data); + if (ret == 0 && data.length) + fwrite(data.data, data.length, 1, sc->f); } break; case USE_PEM: @@ -583,23 +585,20 @@ store_func(hx509_context context, void *ctx, hx509_cert c) ret = _hx509_private_key_export(context, key, HX509_KEY_FORMAT_DER, &priv_key); - if (ret) { - free(data.data); - break; - } - hx509_pem_write(context, _hx509_private_pem_name(key), NULL, sc->f, - priv_key.data, priv_key.length); + if (ret == 0) + ret = hx509_pem_write(context, _hx509_private_pem_name(key), NULL, + sc->f, priv_key.data, priv_key.length); free(priv_key.data); } - if (data.data) { - hx509_pem_write(context, "CERTIFICATE", NULL, sc->f, - data.data, data.length); - free(data.data); + if (ret == 0 && data.data) { + ret = hx509_pem_write(context, "CERTIFICATE", NULL, sc->f, + data.data, data.length); } break; } - return 0; + free(data.data); + return ret; } static int diff --git a/third_party/heimdal/lib/hx509/name.c b/third_party/heimdal/lib/hx509/name.c index 9b6a156af6c5..7d67716b953a 100644 --- a/third_party/heimdal/lib/hx509/name.c +++ b/third_party/heimdal/lib/hx509/name.c @@ -358,29 +358,29 @@ _hx509_Name_to_string(const Name *n, char **str) return 0; } -#define COPYCHARARRAY(_ds,_el,_l,_n) \ - (_l) = strlen(_ds->u._el); \ - (_n) = malloc((_l) * sizeof((_n)[0])); \ - if ((_n) == NULL) \ - return ENOMEM; \ - for (i = 0; i < (_l); i++) \ +#define COPYCHARARRAY(_ds,_el,_l,_n) \ + (_l) = strlen(_ds->u._el); \ + (_n) = malloc((_l + 1) * sizeof((_n)[0])); \ + if ((_n) == NULL) \ + return ENOMEM; \ + for (i = 0; i < (_l); i++) \ (_n)[i] = _ds->u._el[i] -#define COPYVALARRAY(_ds,_el,_l,_n) \ - (_l) = _ds->u._el.length; \ - (_n) = malloc((_l) * sizeof((_n)[0])); \ - if ((_n) == NULL) \ - return ENOMEM; \ - for (i = 0; i < (_l); i++) \ +#define COPYVALARRAY(_ds,_el,_l,_n) \ + (_l) = _ds->u._el.length; \ + (_n) = malloc((_l + 1) * sizeof((_n)[0])); \ + if ((_n) == NULL) \ + return ENOMEM; \ + for (i = 0; i < (_l); i++) \ (_n)[i] = _ds->u._el.data[i] -#define COPYVOIDARRAY(_ds,_el,_l,_n) \ - (_l) = _ds->u._el.length; \ - (_n) = malloc((_l) * sizeof((_n)[0])); \ - if ((_n) == NULL) \ - return ENOMEM; \ - for (i = 0; i < (_l); i++) \ +#define COPYVOIDARRAY(_ds,_el,_l,_n) \ + (_l) = _ds->u._el.length; \ + (_n) = malloc((_l + 1) * sizeof((_n)[0])); \ + if ((_n) == NULL) \ + return ENOMEM; \ + for (i = 0; i < (_l); i++) \ (_n)[i] = ((unsigned char *)_ds->u._el.data)[i] @@ -423,7 +423,7 @@ dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) ret = wind_utf8ucs4_length(ds->u.utf8String, &len); if (ret) return ret; - name = malloc(len * sizeof(name[0])); + name = malloc((len + 1) * sizeof(name[0])); if (name == NULL) return ENOMEM; ret = wind_utf8ucs4(ds->u.utf8String, name, &len); @@ -440,7 +440,7 @@ dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) /* try a couple of times to get the length right, XXX gross */ for (i = 0; i < 4; i++) { *rlen = *rlen * 2; - if ((*rname = malloc(*rlen * sizeof((*rname)[0]))) == NULL) { + if ((*rname = malloc((rlen[0] + 1) * sizeof((*rname)[0]))) == NULL) { ret = ENOMEM; break; } @@ -579,9 +579,9 @@ _hx509_name_modify(hx509_context context, { RelativeDistinguishedName rdn; size_t max_len = oidtomaxlen(oid); - int type_choice, ret; - const char *a = oidtostring(oid, &type_choice); char *s = NULL; + int type_choice = choice_DirectoryString_printableString; + int ret; /* * Check string length upper bounds. @@ -591,10 +591,13 @@ _hx509_name_modify(hx509_context context, * here. */ if (max_len && strlen(str) > max_len) { + char *a = oidtostring(oid, &type_choice); + ret = HX509_PARSING_NAME_FAILED; hx509_set_error_string(context, 0, ret, "RDN attribute %s value too " "long (max %llu): %s", a ? a : "", max_len, str); + free(a); return ret; } @@ -622,7 +625,7 @@ _hx509_name_modify(hx509_context context, */ rdn.val[0].value.element = type_choice; if ((s = strdup(str)) == NULL || - (ret = der_copy_oid(oid, &rdn.val[0].type))) { + der_copy_oid(oid, &rdn.val[0].type)) { free(rdn.val); free(s); return hx509_enomem(context); @@ -934,9 +937,6 @@ hx509_name_expand(hx509_context context, return ENOMEM; } } - free(s); - sval = NULL; - s = NULL; while (p != NULL) { /* expand variables */ @@ -945,6 +945,7 @@ hx509_name_expand(hx509_context context, if (p2 == NULL) { hx509_set_error_string(context, 0, EINVAL, "missing }"); rk_strpoolfree(strpool); + free(s); return EINVAL; } p += 2; @@ -954,11 +955,13 @@ hx509_name_expand(hx509_context context, "variable %.*s missing", (int)(p2 - p), p); rk_strpoolfree(strpool); + free(s); return EINVAL; } strpool = rk_strpoolprintf(strpool, "%s", value); if (strpool == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + free(s); return ENOMEM; } p2++; @@ -971,9 +974,14 @@ hx509_name_expand(hx509_context context, strpool = rk_strpoolprintf(strpool, "%s", p2); if (strpool == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + free(s); return ENOMEM; } } + + free(s); + s = NULL; + if (strpool) { size_t max_bytes; @@ -1392,7 +1400,9 @@ hx509_general_name_unparse(GeneralName *name, char **str) if ((ret = hx509_context_init(&context))) return ret; - return hx509_general_name_unparse2(context, name, str); + ret = hx509_general_name_unparse2(context, name, str); + hx509_context_free(&context); + return ret; } /** @@ -1511,8 +1521,9 @@ hx509_general_name_unparse2(hx509_context context, default: return EINVAL; } - if (strpool == NULL || - (*str = rk_strpoolcollect(strpool)) == NULL) + if (ret) + rk_strpoolfree(strpool); + else if (strpool == NULL || (*str = rk_strpoolcollect(strpool)) == NULL) return ENOMEM; - return 0; + return ret; } diff --git a/third_party/heimdal/lib/hx509/print.c b/third_party/heimdal/lib/hx509/print.c index 544001ebc0df..3309913f3575 100644 --- a/third_party/heimdal/lib/hx509/print.c +++ b/third_party/heimdal/lib/hx509/print.c @@ -361,6 +361,7 @@ check_authorityKeyIdentifier(hx509_validate_ctx ctx, } } + free_AuthorityKeyIdentifier(&ai); return 0; } @@ -771,6 +772,7 @@ check_certificatePolicies(hx509_validate_ctx ctx, validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " Unknown:%s", qoid); } + free_UserNotice(&un); } } else { validate_print(ctx, HX509_VALIDATE_F_VERBOSE, @@ -842,8 +844,11 @@ check_policyMappings(hx509_validate_ctx ctx, else validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "ret=%d while decoding PolicyMappings\n", ret); + free(sdpoid); + free(idpoid); } + free_PolicyMappings(&pm); return 0; } diff --git a/third_party/heimdal/lib/hx509/req.c b/third_party/heimdal/lib/hx509/req.c index f0a7c2186575..2b3f46d532a6 100644 --- a/third_party/heimdal/lib/hx509/req.c +++ b/third_party/heimdal/lib/hx509/req.c @@ -518,14 +518,13 @@ get_exts(hx509_context context, const hx509_request req, Extensions *exts) { - uint64_t ku_num; size_t size; int ret = 0; exts->val = NULL; exts->len = 0; - if ((ku_num = KeyUsage2int(req->ku))) { + if (KeyUsage2int(req->ku)) { Extension e; memset(&e, 0, sizeof(e)); @@ -718,6 +717,7 @@ hx509_request_to_pkcs10(hx509_context context, abort(); free_CertificationRequest(&r); + free_Extensions(&exts); return ret; } @@ -899,9 +899,9 @@ hx509_request_parse_der(hx509_context context, out: free_CertificationRequest(&r); + free_Extensions(&exts); if (ret) hx509_request_free(req); - free_CertificationRequest(&r); return ret; } @@ -1046,7 +1046,7 @@ authorize_feat(hx509_request req, abitstring a, size_t n, int idx) switch (ret) { case 0: req->nauthorized++; - /*fallthrough*/ + fallthrough; case -1: return 0; default: @@ -1063,7 +1063,7 @@ reject_feat(hx509_request req, abitstring a, size_t n, int idx) switch (ret) { case 0: req->nauthorized--; - /*fallthrough*/ + fallthrough; case -1: return 0; default: @@ -1245,7 +1245,7 @@ san_map_type(GeneralName *san) if (der_heim_oid_cmp(&san->u.otherName.type_id, map[i].oid) == 0) return map[i].type; } - /*fallthrough*/ + fallthrough; default: return HX509_SAN_TYPE_UNSUPPORTED; } } @@ -1360,14 +1360,13 @@ hx509_request_get_san(hx509_request req, case HX509_SAN_TYPE_REGISTERED_ID: return der_print_heim_oid(&san->u.registeredID, '.', out); case HX509_SAN_TYPE_XMPP: - /*fallthrough*/ + fallthrough; case HX509_SAN_TYPE_MS_UPN: { int ret; ret = _hx509_unparse_utf8_string_name(req->context, &pool, &san->u.otherName.value); - if (ret == 0 && - (*out = rk_strpoolcollect(pool)) == NULL) + if ((*out = rk_strpoolcollect(pool)) == NULL) return hx509_enomem(req->context); return ret; } @@ -1376,10 +1375,9 @@ hx509_request_get_san(hx509_request req, ret = _hx509_unparse_KRB5PrincipalName(req->context, &pool, &san->u.otherName.value); - if (ret == 0 && - (*out = rk_strpoolcollect(pool)) == NULL) + if ((*out = rk_strpoolcollect(pool)) == NULL) return hx509_enomem(req->context); - return 0; + return ret; } default: *type = HX509_SAN_TYPE_UNSUPPORTED; diff --git a/third_party/heimdal/lib/hx509/revoke.c b/third_party/heimdal/lib/hx509/revoke.c index c2f2e00cc297..18b2f8f8f96d 100644 --- a/third_party/heimdal/lib/hx509/revoke.c +++ b/third_party/heimdal/lib/hx509/revoke.c @@ -202,6 +202,8 @@ verify_ocsp(hx509_context context, ret = hx509_certs_find(context, certs, &q, &signer); if (ret && ocsp->certs) ret = hx509_certs_find(context, ocsp->certs, &q, &signer); + if (ret == 0 && signer == NULL) + ret = HX509_CERT_NOT_FOUND; if (ret) goto out; @@ -500,6 +502,8 @@ verify_crl(hx509_context context, q.subject_name = &crl->tbsCertList.issuer; ret = hx509_certs_find(context, certs, &q, &signer); + if (ret == 0 && signer == NULL) + ret = HX509_CERT_NOT_FOUND; if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "Failed to find certificate for CRL"); diff --git a/third_party/heimdal/lib/hx509/sel-gram.y b/third_party/heimdal/lib/hx509/sel-gram.y index 7e9d4f26d9c2..09f641d7c051 100644 --- a/third_party/heimdal/lib/hx509/sel-gram.y +++ b/third_party/heimdal/lib/hx509/sel-gram.y @@ -78,6 +78,10 @@ %token STRING %token IDENTIFIER +%left '!' +%left kw_AND +%left kw_OR + %start start %% diff --git a/third_party/heimdal/lib/hx509/softp11.c b/third_party/heimdal/lib/hx509/softp11.c index 0a1445ba5233..75f675579c77 100644 --- a/third_party/heimdal/lib/hx509/softp11.c +++ b/third_party/heimdal/lib/hx509/softp11.c @@ -311,7 +311,7 @@ add_st_object(void) return NULL; for (i = 0; i < soft_token.object.num_objs; i++) { - if (soft_token.object.objs == NULL) { + if (soft_token.object.objs[i] == NULL) { soft_token.object.objs[i] = o; break; } @@ -342,6 +342,9 @@ add_object_attribute(struct st_object *o, struct st_attr *a; int i; + if (pValue == NULL && ulValueLen) + return CKR_ARGUMENTS_BAD; + i = o->num_attributes; a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0])); if (a == NULL) @@ -352,7 +355,8 @@ add_object_attribute(struct st_object *o, o->attrs[i].attribute.pValue = malloc(ulValueLen); if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0) return CKR_DEVICE_MEMORY; - memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen); + if (ulValueLen) + memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen); o->attrs[i].attribute.ulValueLen = ulValueLen; o->num_attributes++; diff --git a/third_party/heimdal/lib/ipc/Makefile.am b/third_party/heimdal/lib/ipc/Makefile.am index 9338b141e171..6915175618e5 100644 --- a/third_party/heimdal/lib/ipc/Makefile.am +++ b/third_party/heimdal/lib/ipc/Makefile.am @@ -38,6 +38,10 @@ EXTRA_DIST = heim_ipc.defs heim_ipc_async.defs heim_ipc_reply.defs if have_gcd +# We still use dispatch_get_current_queue(), which is deprecated, and that +# stops building on recent OS X releases unless we disable this warning. +WFLAGS += -Wno-deprecated-declarations + heim_ipc.h heim_ipcUser.c heim_ipcServer.c heim_ipcServer.h: heim_ipc.defs mig -header heim_ipc.h -user heim_ipcUser.c -sheader heim_ipcServer.h -server heim_ipcServer.c -I$(srcdir) $(srcdir)/heim_ipc.defs diff --git a/third_party/heimdal/lib/ipc/server.c b/third_party/heimdal/lib/ipc/server.c index 839a596388a5..40601b9744fa 100644 --- a/third_party/heimdal/lib/ipc/server.c +++ b/third_party/heimdal/lib/ipc/server.c @@ -1014,15 +1014,12 @@ process_loop(void) for (n = 0 ; n < num_fds; n++) { if (clients[n] == NULL) continue; - if (fds[n].revents & POLLERR) { - clients[n]->flags |= WAITING_CLOSE; - continue; - } - if (fds[n].revents & POLLIN) handle_read(clients[n]); if (fds[n].revents & POLLOUT) handle_write(clients[n]); + if (fds[n].revents & POLLERR) + clients[n]->flags |= WAITING_CLOSE; } n = 0; @@ -1055,12 +1052,16 @@ heim_sipc_stream_listener(int fd, int type, heim_ipc_callback callback, void *user, heim_sipc *ctx) { - heim_sipc ct = calloc(1, sizeof(*ct)); + heim_sipc ct; struct client *c; if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP))) return EINVAL; + ct = calloc(1, sizeof(*ct)); + if (ct == NULL) + return ENOMEM; + switch (type) { case HEIM_SIPC_TYPE_IPC: c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user); @@ -1111,7 +1112,7 @@ heim_sipc_service_unix(const char *service, #ifdef LOCAL_CREDS { int one = 1; - setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one)); + (void) setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one)); } #endif diff --git a/third_party/heimdal/lib/kadm5/ad.c b/third_party/heimdal/lib/kadm5/ad.c index 0b4ee656604e..58ccf32eacdd 100644 --- a/third_party/heimdal/lib/kadm5/ad.c +++ b/third_party/heimdal/lib/kadm5/ad.c @@ -1438,6 +1438,7 @@ kadm5_ad_init_with_password_ctx(krb5_context context, ret = ad_get_cred(ctx, NULL); if(ret) { kadm5_ad_destroy(ctx); + free(ctx); return ret; } @@ -1445,6 +1446,7 @@ kadm5_ad_init_with_password_ctx(krb5_context context, ret = _kadm5_ad_connect(ctx); if (ret) { kadm5_ad_destroy(ctx); + free(ctx); return ret; } #endif diff --git a/third_party/heimdal/lib/kadm5/chpass_s.c b/third_party/heimdal/lib/kadm5/chpass_s.c index e0d63d2ef421..c89448f4882a 100644 --- a/third_party/heimdal/lib/kadm5/chpass_s.c +++ b/third_party/heimdal/lib/kadm5/chpass_s.c @@ -111,7 +111,7 @@ change(void *server_handle, int cond) { kadm5_server_context *context = server_handle; - hdb_entry_ex ent; + hdb_entry ent; kadm5_ret_t ret; Key *keys; size_t num_keys; @@ -167,7 +167,7 @@ change(void *server_handle, * We save these for now so we can handle password history checking; * we handle keepold further below. */ - ret = hdb_add_current_keys_to_history(context->context, &ent.entry); + ret = hdb_add_current_keys_to_history(context->context, &ent); if (ret) goto out3; } @@ -179,13 +179,13 @@ change(void *server_handle, goto out3; } else { - num_keys = ent.entry.keys.len; - keys = ent.entry.keys.val; + num_keys = ent.keys.len; + keys = ent.keys.val; - ent.entry.keys.len = 0; - ent.entry.keys.val = NULL; + ent.keys.len = 0; + ent.keys.val = NULL; - ret = _kadm5_set_keys(context, &ent.entry, n_ks_tuple, ks_tuple, + ret = _kadm5_set_keys(context, &ent, n_ks_tuple, ks_tuple, password); if(ret) { _kadm5_free_keys(context->context, num_keys, keys); @@ -196,10 +196,10 @@ change(void *server_handle, if (cond) { HDB_extension *ext; - ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys); + ext = hdb_find_extension(&ent, choice_HDB_extension_data_hist_keys); if (ext != NULL) - existsp = _kadm5_exists_keys_hist(ent.entry.keys.val, - ent.entry.keys.len, + existsp = _kadm5_exists_keys_hist(ent.keys.val, + ent.keys.len, &ext->data.u.hist_keys); } @@ -210,9 +210,9 @@ change(void *server_handle, goto out3; } } - ent.entry.kvno++; + ent.kvno++; - ent.entry.flags.require_pwchange = 0; + ent.flags.require_pwchange = 0; if (!keepold) { HDB_extension ext; @@ -220,25 +220,25 @@ change(void *server_handle, memset(&ext, 0, sizeof (ext)); ext.mandatory = FALSE; ext.data.element = choice_HDB_extension_data_hist_keys; - ret = hdb_replace_extension(context->context, &ent.entry, &ext); + ret = hdb_replace_extension(context->context, &ent, &ext); if (ret) goto out3; } - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out3; - ret = _kadm5_set_modifier(context, &ent.entry); + ret = _kadm5_set_modifier(context, &ent); if(ret) goto out3; - ret = _kadm5_bump_pw_expire(context, &ent.entry); + ret = _kadm5_bump_pw_expire(context, &ent); if (ret) goto out3; /* This logs the change for iprop and writes to the HDB */ - ret = kadm5_log_modify(context, &ent.entry, + ret = kadm5_log_modify(context, &ent, KADM5_ATTRIBUTES | KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | @@ -249,7 +249,7 @@ change(void *server_handle, n_ks_tuple, ks_tuple, password); out3: - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); out2: (void) kadm5_log_end(context); out: @@ -367,7 +367,7 @@ kadm5_s_chpass_principal_with_key(void *server_handle, krb5_key_data *key_data) { kadm5_server_context *context = server_handle; - hdb_entry_ex ent; + hdb_entry ent; kadm5_ret_t ret; uint32_t hook_flags = 0; @@ -396,23 +396,23 @@ kadm5_s_chpass_principal_with_key(void *server_handle, goto out3; if (keepold) { - ret = hdb_add_current_keys_to_history(context->context, &ent.entry); + ret = hdb_add_current_keys_to_history(context->context, &ent); if (ret) goto out3; } - ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data); + ret = _kadm5_set_keys2(context, &ent, n_key_data, key_data); if (ret) goto out3; - ent.entry.kvno++; - ret = _kadm5_set_modifier(context, &ent.entry); + ent.kvno++; + ret = _kadm5_set_modifier(context, &ent); if (ret) goto out3; - ret = _kadm5_bump_pw_expire(context, &ent.entry); + ret = _kadm5_bump_pw_expire(context, &ent); if (ret) goto out3; if (keepold) { - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out3; } else { @@ -423,11 +423,11 @@ kadm5_s_chpass_principal_with_key(void *server_handle, ext.data.element = choice_HDB_extension_data_hist_keys; ext.data.u.hist_keys.len = 0; ext.data.u.hist_keys.val = NULL; - hdb_replace_extension(context->context, &ent.entry, &ext); + hdb_replace_extension(context->context, &ent, &ext); } /* This logs the change for iprop and writes to the HDB */ - ret = kadm5_log_modify(context, &ent.entry, + ret = kadm5_log_modify(context, &ent, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); @@ -437,7 +437,7 @@ kadm5_s_chpass_principal_with_key(void *server_handle, n_key_data, key_data); out3: - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); out2: (void) kadm5_log_end(context); out: diff --git a/third_party/heimdal/lib/kadm5/context_s.c b/third_party/heimdal/lib/kadm5/context_s.c index b5674f19ab6e..0c154ecfef08 100644 --- a/third_party/heimdal/lib/kadm5/context_s.c +++ b/third_party/heimdal/lib/kadm5/context_s.c @@ -161,29 +161,37 @@ find_db_spec(kadm5_server_context *ctx) p = hdb_dbinfo_get_dbname(context, d); if (p) { ctx->config.dbname = strdup(p); - if (ctx->config.dbname == NULL) + if (ctx->config.dbname == NULL) { + hdb_free_dbinfo(context, &info); return krb5_enomem(context); + } } p = hdb_dbinfo_get_acl_file(context, d); if (p) { ctx->config.acl_file = strdup(p); - if (ctx->config.acl_file == NULL) + if (ctx->config.acl_file == NULL) { + hdb_free_dbinfo(context, &info); return krb5_enomem(context); + } } p = hdb_dbinfo_get_mkey_file(context, d); if (p) { ctx->config.stash_file = strdup(p); - if (ctx->config.stash_file == NULL) + if (ctx->config.stash_file == NULL) { + hdb_free_dbinfo(context, &info); return krb5_enomem(context); + } } p = hdb_dbinfo_get_log_file(context, d); if (p) { ctx->log_context.log_file = strdup(p); - if (ctx->log_context.log_file == NULL) + if (ctx->log_context.log_file == NULL) { + hdb_free_dbinfo(context, &info); return krb5_enomem(context); + } } break; } diff --git a/third_party/heimdal/lib/kadm5/create_s.c b/third_party/heimdal/lib/kadm5/create_s.c index 42125e28a7e0..1c2ab15f30db 100644 --- a/third_party/heimdal/lib/kadm5/create_s.c +++ b/third_party/heimdal/lib/kadm5/create_s.c @@ -57,7 +57,7 @@ static kadm5_ret_t create_principal(kadm5_server_context *context, kadm5_principal_ent_t princ, uint32_t mask, - hdb_entry_ex *ent, + hdb_entry *ent, uint32_t required_mask, uint32_t forbidden_mask) { @@ -74,7 +74,7 @@ create_principal(kadm5_server_context *context, /* XXX no real policies for now */ return KADM5_UNK_POLICY; ret = krb5_copy_principal(context->context, princ->principal, - &ent->entry.principal); + &ent->principal); if(ret) return ret; @@ -96,10 +96,10 @@ create_principal(kadm5_server_context *context, if (ret) return ret; - ent->entry.created_by.time = time(NULL); + ent->created_by.time = time(NULL); return krb5_copy_principal(context->context, context->caller, - &ent->entry.created_by.principal); + &ent->created_by.principal); } struct create_principal_hook_ctx { @@ -167,7 +167,7 @@ kadm5_s_create_principal_with_key(void *server_handle, uint32_t mask) { kadm5_ret_t ret; - hdb_entry_ex ent; + hdb_entry ent; kadm5_server_context *context = server_handle; if ((mask & KADM5_KVNO) == 0) { @@ -194,7 +194,7 @@ kadm5_s_create_principal_with_key(void *server_handle, if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if (ret) { - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); return ret; } } @@ -203,7 +203,7 @@ kadm5_s_create_principal_with_key(void *server_handle, if (ret) goto out; - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out2; @@ -213,7 +213,7 @@ kadm5_s_create_principal_with_key(void *server_handle, * Creation of would-be virtual principals w/o the materialize flag will be * rejected in kadm5_log_create(). */ - ret = kadm5_log_create(context, &ent.entry); + ret = kadm5_log_create(context, &ent); (void) create_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, princ, mask, NULL); @@ -227,7 +227,7 @@ kadm5_s_create_principal_with_key(void *server_handle, if (ret == 0 && ret2 != 0) ret = ret2; } - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); return _kadm5_error_code(ret); } @@ -241,7 +241,7 @@ kadm5_s_create_principal(void *server_handle, const char *password) { kadm5_ret_t ret; - hdb_entry_ex ent; + hdb_entry ent; kadm5_server_context *context = server_handle; int use_pw = 1; @@ -315,7 +315,7 @@ kadm5_s_create_principal(void *server_handle, if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if (ret) { - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); return ret; } } @@ -324,20 +324,20 @@ kadm5_s_create_principal(void *server_handle, if (ret) goto out; - free_Keys(&ent.entry.keys); + free_Keys(&ent.keys); if (use_pw) { - ret = _kadm5_set_keys(context, &ent.entry, n_ks_tuple, ks_tuple, password); + ret = _kadm5_set_keys(context, &ent, n_ks_tuple, ks_tuple, password); if (ret) goto out2; } - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out2; /* This logs the change for iprop and writes to the HDB */ - ret = kadm5_log_create(context, &ent.entry); + ret = kadm5_log_create(context, &ent); (void) create_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, princ, mask, password); @@ -351,7 +351,7 @@ kadm5_s_create_principal(void *server_handle, if (ret == 0 && ret2 != 0) ret = ret2; } - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); return _kadm5_error_code(ret); } diff --git a/third_party/heimdal/lib/kadm5/delete_s.c b/third_party/heimdal/lib/kadm5/delete_s.c index 6942148dbb53..aa9fdb4fc0a2 100644 --- a/third_party/heimdal/lib/kadm5/delete_s.c +++ b/third_party/heimdal/lib/kadm5/delete_s.c @@ -92,7 +92,7 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; - hdb_entry_ex ent; + hdb_entry ent; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) { @@ -112,7 +112,7 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ) 0, &ent); if (ret == HDB_ERR_NOENTRY) goto out2; - if (ent.entry.flags.immutable) { + if (ent.flags.immutable) { ret = KADM5_PROTECT_PRINCIPAL; goto out3; } @@ -121,7 +121,7 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ) if (ret) goto out3; - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out3; @@ -131,7 +131,7 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ) (void) delete_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, princ); out3: - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); out2: (void) kadm5_log_end(context); out: diff --git a/third_party/heimdal/lib/kadm5/ent_setup.c b/third_party/heimdal/lib/kadm5/ent_setup.c index 677bda6d8973..24a7983b6e1f 100644 --- a/third_party/heimdal/lib/kadm5/ent_setup.c +++ b/third_party/heimdal/lib/kadm5/ent_setup.c @@ -73,7 +73,7 @@ attr_to_flags(unsigned attr, HDBFlags *flags) static kadm5_ret_t perform_tl_data(krb5_context context, HDB *db, - hdb_entry_ex *ent, + hdb_entry *ent, const krb5_tl_data *tl_data) { kadm5_ret_t ret = 0; @@ -84,7 +84,7 @@ perform_tl_data(krb5_context context, if (pw[tl_data->tl_data_length] != '\0') return KADM5_BAD_TL_TYPE; - ret = hdb_entry_set_password(context, db, &ent->entry, pw); + ret = hdb_entry_set_password(context, db, ent, pw); } else if (tl_data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE) { unsigned long t; @@ -96,7 +96,7 @@ perform_tl_data(krb5_context context, s = tl_data->tl_data_contents; (void) _krb5_get_int(s, &t, tl_data->tl_data_length); - ret = hdb_entry_set_pw_change_time(context, &ent->entry, t); + ret = hdb_entry_set_pw_change_time(context, ent, t); } else if (tl_data->tl_data_type == KRB5_TL_KEY_ROTATION) { HDB_Ext_KeyRotation *prev_kr = 0; @@ -105,7 +105,7 @@ perform_tl_data(krb5_context context, ext.mandatory = 0; ext.data.element = choice_HDB_extension_data_key_rotation; - prev_ext = hdb_find_extension(&ent->entry, ext.data.element); + prev_ext = hdb_find_extension(ent, ext.data.element); if (prev_ext) prev_kr = &prev_ext->data.u.key_rotation; ret = decode_HDB_Ext_KeyRotation(tl_data->tl_data_contents, @@ -115,7 +115,7 @@ perform_tl_data(krb5_context context, ret = hdb_validate_key_rotations(context, prev_kr, &ext.data.u.key_rotation); if (ret == 0) - ret = hdb_replace_extension(context, &ent->entry, &ext); + ret = hdb_replace_extension(context, ent, &ext); free_HDB_extension(&ext); } else if (tl_data->tl_data_type == KRB5_TL_EXTENSION) { HDB_extension ext; @@ -128,7 +128,7 @@ perform_tl_data(krb5_context context, return KADM5_BAD_TL_TYPE; if (ext.data.element == choice_HDB_extension_data_key_rotation) { - HDB_extension *prev_ext = hdb_find_extension(&ent->entry, + HDB_extension *prev_ext = hdb_find_extension(ent, ext.data.element); HDB_Ext_KeyRotation *prev_kr = 0; @@ -140,19 +140,19 @@ perform_tl_data(krb5_context context, if (ret) ret = KADM5_BAD_TL_TYPE; /* XXX Need new error code */ if (ret == 0) - ret = hdb_replace_extension(context, &ent->entry, &ext); + ret = hdb_replace_extension(context, ent, &ext); free_HDB_extension(&ext); } else if (tl_data->tl_data_type == KRB5_TL_ETYPES) { - if (!ent->entry.etypes && - (ent->entry.etypes = calloc(1, - sizeof(ent->entry.etypes[0]))) == NULL) + if (!ent->etypes && + (ent->etypes = calloc(1, + sizeof(ent->etypes[0]))) == NULL) ret = krb5_enomem(context); - if (ent->entry.etypes) - free_HDB_EncTypeList(ent->entry.etypes); + if (ent->etypes) + free_HDB_EncTypeList(ent->etypes); if (ret == 0) ret = decode_HDB_EncTypeList(tl_data->tl_data_contents, tl_data->tl_data_length, - ent->entry.etypes, NULL); + ent->etypes, NULL); if (ret) return KADM5_BAD_TL_TYPE; } else if (tl_data->tl_data_type == KRB5_TL_ALIASES) { @@ -164,14 +164,14 @@ perform_tl_data(krb5_context context, } static void -default_flags(hdb_entry_ex *ent) +default_flags(hdb_entry *ent) { - ent->entry.flags.client = 1; - ent->entry.flags.server = 1; - ent->entry.flags.forwardable = 1; - ent->entry.flags.proxiable = 1; - ent->entry.flags.renewable = 1; - ent->entry.flags.postdate = 1; + ent->flags.client = 1; + ent->flags.server = 1; + ent->flags.forwardable = 1; + ent->flags.proxiable = 1; + ent->flags.renewable = 1; + ent->flags.postdate = 1; } @@ -183,7 +183,7 @@ default_flags(hdb_entry_ex *ent) kadm5_ret_t _kadm5_setup_entry(kadm5_server_context *context, - hdb_entry_ex *ent, + hdb_entry *ent, uint32_t mask, kadm5_principal_ent_t princ, uint32_t princ_mask, @@ -193,23 +193,23 @@ _kadm5_setup_entry(kadm5_server_context *context, if(mask & KADM5_PRINC_EXPIRE_TIME && princ_mask & KADM5_PRINC_EXPIRE_TIME) { if (princ->princ_expire_time) - set_value(ent->entry.valid_end, princ->princ_expire_time); + set_value(ent->valid_end, princ->princ_expire_time); else - set_null(ent->entry.valid_end); + set_null(ent->valid_end); } if(mask & KADM5_PW_EXPIRATION && princ_mask & KADM5_PW_EXPIRATION) { if (princ->pw_expiration) - set_value(ent->entry.pw_end, princ->pw_expiration); + set_value(ent->pw_end, princ->pw_expiration); else - set_null(ent->entry.pw_end); + set_null(ent->pw_end); } if(mask & KADM5_ATTRIBUTES) { if (princ_mask & KADM5_ATTRIBUTES) { - attr_to_flags(princ->attributes, &ent->entry.flags); + attr_to_flags(princ->attributes, &ent->flags); } else if(def_mask & KADM5_ATTRIBUTES) { - attr_to_flags(def->attributes, &ent->entry.flags); - ent->entry.flags.invalid = 0; + attr_to_flags(def->attributes, &ent->flags); + ent->flags.invalid = 0; } else { default_flags(ent); } @@ -218,41 +218,41 @@ _kadm5_setup_entry(kadm5_server_context *context, if(mask & KADM5_MAX_LIFE) { if(princ_mask & KADM5_MAX_LIFE) { if(princ->max_life) - set_value(ent->entry.max_life, princ->max_life); + set_value(ent->max_life, princ->max_life); else - set_null(ent->entry.max_life); + set_null(ent->max_life); } else if(def_mask & KADM5_MAX_LIFE) { if(def->max_life) - set_value(ent->entry.max_life, def->max_life); + set_value(ent->max_life, def->max_life); else - set_null(ent->entry.max_life); + set_null(ent->max_life); } } if(mask & KADM5_KVNO && (princ_mask & KADM5_KVNO)) { krb5_error_code ret; - ret = hdb_change_kvno(context->context, princ->kvno, &ent->entry); + ret = hdb_change_kvno(context->context, princ->kvno, ent); if (ret && ret != HDB_ERR_KVNO_NOT_FOUND) return ret; - ent->entry.kvno = princ->kvno; /* force it */ + ent->kvno = princ->kvno; /* force it */ } if(mask & KADM5_MAX_RLIFE) { if(princ_mask & KADM5_MAX_RLIFE) { if(princ->max_renewable_life) - set_value(ent->entry.max_renew, princ->max_renewable_life); + set_value(ent->max_renew, princ->max_renewable_life); else - set_null(ent->entry.max_renew); + set_null(ent->max_renew); } else if(def_mask & KADM5_MAX_RLIFE) { if(def->max_renewable_life) - set_value(ent->entry.max_renew, def->max_renewable_life); + set_value(ent->max_renew, def->max_renewable_life); else - set_null(ent->entry.max_renew); + set_null(ent->max_renew); } } if(mask & KADM5_KEY_DATA && princ_mask & KADM5_KEY_DATA) { - _kadm5_set_keys2(context, &ent->entry, + _kadm5_set_keys2(context, ent, princ->n_key_data, princ->key_data); } if(mask & KADM5_TL_DATA) { diff --git a/third_party/heimdal/lib/kadm5/get_princs_s.c b/third_party/heimdal/lib/kadm5/get_princs_s.c index f7182d7ec88d..27fac2bbb0bc 100644 --- a/third_party/heimdal/lib/kadm5/get_princs_s.c +++ b/third_party/heimdal/lib/kadm5/get_princs_s.c @@ -55,12 +55,12 @@ add_princ(krb5_context context, struct foreach_data *d, char *princ) } static krb5_error_code -foreach(krb5_context context, HDB *db, hdb_entry_ex *ent, void *data) +foreach(krb5_context context, HDB *db, hdb_entry *ent, void *data) { struct foreach_data *d = data; char *princ; krb5_error_code ret; - ret = krb5_unparse_name(context, ent->entry.principal, &princ); + ret = krb5_unparse_name(context, ent->principal, &princ); if(ret) return ret; if(d->exp){ @@ -98,7 +98,9 @@ kadm5_s_get_principals(void *server_handle, krb5_realm r; int aret; - krb5_get_default_realm(context->context, &r); + ret = krb5_get_default_realm(context->context, &r); + if (ret) + goto out; aret = asprintf(&d.exp2, "%s@%s", expression, r); free(r); if (aret == -1 || d.exp2 == NULL) { diff --git a/third_party/heimdal/lib/kadm5/get_s.c b/third_party/heimdal/lib/kadm5/get_s.c index 56aec67a2231..0c87343d2e17 100644 --- a/third_party/heimdal/lib/kadm5/get_s.c +++ b/third_party/heimdal/lib/kadm5/get_s.c @@ -122,7 +122,7 @@ kadm5_s_get_principal(void *server_handle, { kadm5_server_context *context = server_handle; kadm5_ret_t ret; - hdb_entry_ex ent; + hdb_entry ent; unsigned int flags = HDB_F_GET_ANY | HDB_F_ADMIN_DATA; if ((mask & KADM5_KEY_DATA) || (mask & KADM5_KVNO)) @@ -157,57 +157,57 @@ kadm5_s_get_principal(void *server_handle, return _kadm5_error_code(ret); if(mask & KADM5_PRINCIPAL) - ret = krb5_copy_principal(context->context, ent.entry.principal, + ret = krb5_copy_principal(context->context, ent.principal, &out->principal); if(ret) goto out; - if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end) - out->princ_expire_time = *ent.entry.valid_end; - if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end) - out->pw_expiration = *ent.entry.pw_end; + if(mask & KADM5_PRINC_EXPIRE_TIME && ent.valid_end) + out->princ_expire_time = *ent.valid_end; + if(mask & KADM5_PW_EXPIRATION && ent.pw_end) + out->pw_expiration = *ent.pw_end; if(mask & KADM5_LAST_PWD_CHANGE) - hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change); + hdb_entry_get_pw_change_time(&ent, &out->last_pwd_change); if(mask & KADM5_ATTRIBUTES){ - out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; - out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; - out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; - out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; - out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; - out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; - out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; - out->attributes |= ent.entry.flags.require_pwchange ? KRB5_KDB_REQUIRES_PWCHANGE : 0; - out->attributes |= ent.entry.flags.client ? 0 : KRB5_KDB_DISALLOW_CLIENT; - out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; - out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; - out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; - out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; - out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; - out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; - out->attributes |= ent.entry.flags.virtual_keys ? KRB5_KDB_VIRTUAL_KEYS : 0; - out->attributes |= ent.entry.flags.virtual ? KRB5_KDB_VIRTUAL : 0; - out->attributes |= ent.entry.flags.no_auth_data_reqd ? KRB5_KDB_NO_AUTH_DATA_REQUIRED : 0; + out->attributes |= ent.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; + out->attributes |= ent.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; + out->attributes |= ent.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; + out->attributes |= ent.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; + out->attributes |= ent.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; + out->attributes |= ent.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; + out->attributes |= ent.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; + out->attributes |= ent.flags.require_pwchange ? KRB5_KDB_REQUIRES_PWCHANGE : 0; + out->attributes |= ent.flags.client ? 0 : KRB5_KDB_DISALLOW_CLIENT; + out->attributes |= ent.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; + out->attributes |= ent.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; + out->attributes |= ent.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; + out->attributes |= ent.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; + out->attributes |= ent.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; + out->attributes |= ent.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; + out->attributes |= ent.flags.virtual_keys ? KRB5_KDB_VIRTUAL_KEYS : 0; + out->attributes |= ent.flags.virtual ? KRB5_KDB_VIRTUAL : 0; + out->attributes |= ent.flags.no_auth_data_reqd ? KRB5_KDB_NO_AUTH_DATA_REQUIRED : 0; } if(mask & KADM5_MAX_LIFE) { - if(ent.entry.max_life) - out->max_life = *ent.entry.max_life; + if(ent.max_life) + out->max_life = *ent.max_life; else out->max_life = INT_MAX; } if(mask & KADM5_MOD_TIME) { - if(ent.entry.modified_by) - out->mod_date = ent.entry.modified_by->time; + if(ent.modified_by) + out->mod_date = ent.modified_by->time; else - out->mod_date = ent.entry.created_by.time; + out->mod_date = ent.created_by.time; } if(mask & KADM5_MOD_NAME) { - if(ent.entry.modified_by) { - if (ent.entry.modified_by->principal != NULL) + if(ent.modified_by) { + if (ent.modified_by->principal != NULL) ret = krb5_copy_principal(context->context, - ent.entry.modified_by->principal, + ent.modified_by->principal, &out->mod_name); - } else if(ent.entry.created_by.principal != NULL) + } else if(ent.created_by.principal != NULL) ret = krb5_copy_principal(context->context, - ent.entry.created_by.principal, + ent.created_by.principal, &out->mod_name); else out->mod_name = NULL; @@ -216,13 +216,13 @@ kadm5_s_get_principal(void *server_handle, goto out; if(mask & KADM5_KVNO) - out->kvno = ent.entry.kvno; + out->kvno = ent.kvno; if(mask & KADM5_MKVNO) { size_t n; out->mkvno = 0; /* XXX */ - for(n = 0; n < ent.entry.keys.len; n++) - if(ent.entry.keys.val[n].mkvno) { - out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */ + for(n = 0; n < ent.keys.len; n++) + if(ent.keys.val[n].mkvno) { + out->mkvno = *ent.keys.val[n].mkvno; /* XXX this isn't right */ break; } } @@ -239,7 +239,7 @@ kadm5_s_get_principal(void *server_handle, if(mask & KADM5_POLICY) { HDB_extension *ext; - ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_policy); + ext = hdb_find_extension(&ent, choice_HDB_extension_data_policy); if (ext == NULL) { out->policy = strdup("default"); /* It's OK if we retun NULL instead of "default" */ @@ -252,27 +252,27 @@ kadm5_s_get_principal(void *server_handle, } } if(mask & KADM5_MAX_RLIFE) { - if(ent.entry.max_renew) - out->max_renewable_life = *ent.entry.max_renew; + if(ent.max_renew) + out->max_renewable_life = *ent.max_renew; else out->max_renewable_life = INT_MAX; } if(mask & KADM5_KEY_DATA){ size_t i; - size_t n_keys = ent.entry.keys.len; + size_t n_keys = ent.keys.len; krb5_salt salt; HDB_extension *ext; HDB_Ext_KeySet *hist_keys = NULL; /* Don't return stale keys to kadm5 clients */ - ret = hdb_prune_keys(context->context, &ent.entry); + ret = hdb_prune_keys(context->context, &ent); if (ret) goto out; - ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys); + ext = hdb_find_extension(&ent, choice_HDB_extension_data_hist_keys); if (ext != NULL) hist_keys = &ext->data.u.hist_keys; - krb5_get_pw_salt(context->context, ent.entry.principal, &salt); + krb5_get_pw_salt(context->context, ent.principal, &salt); for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) n_keys += hist_keys->val[i].keys.len; out->key_data = malloc(n_keys * sizeof(*out->key_data)); @@ -281,8 +281,8 @@ kadm5_s_get_principal(void *server_handle, goto out; } out->n_key_data = 0; - ret = copy_keyset_to_kadm5(context, ent.entry.kvno, ent.entry.keys.len, - ent.entry.keys.val, &salt, out); + ret = copy_keyset_to_kadm5(context, ent.kvno, ent.keys.len, + ent.keys.val, &salt, out); if (ret) goto out; for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) { @@ -296,8 +296,7 @@ kadm5_s_get_principal(void *server_handle, krb5_free_salt(context->context, salt); assert( out->n_key_data == n_keys ); } - if (ret) - goto out; + assert(ret == 0); if(mask & KADM5_TL_DATA) { time_t last_pw_expire; const HDB_Ext_PKINIT_acl *acl; @@ -305,12 +304,12 @@ kadm5_s_get_principal(void *server_handle, const HDB_Ext_KeyRotation *kr; heim_octet_string krb5_config; - if (ent.entry.etypes) { + if (ent.etypes) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_EncTypeList, buf.data, buf.length, - ent.entry.etypes, &len, ret); + ent.etypes, &len, ret); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_ETYPES, buf.data, buf.length); free(buf.data); @@ -319,20 +318,22 @@ kadm5_s_get_principal(void *server_handle, goto out; } - ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire); + ret = hdb_entry_get_pw_change_time(&ent, &last_pw_expire); if (ret == 0 && last_pw_expire) { unsigned char buf[4]; _krb5_put_int(buf, last_pw_expire, sizeof(buf)); ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); + if (ret) + goto out; } - if (ret == 0) - ret = hdb_entry_get_krb5_config(&ent.entry, &krb5_config); + + ret = hdb_entry_get_krb5_config(&ent, &krb5_config); if (ret == 0 && krb5_config.length) { ret = add_tl_data(out, KRB5_TL_KRB5_CONFIG, krb5_config.data, krb5_config.length); + if (ret) + goto out; } - if (ret) - goto out; /* * If the client was allowed to get key data, let it have the * password too. @@ -342,15 +343,17 @@ kadm5_s_get_principal(void *server_handle, /* XXX But not if the client doesn't have ext-keys */ ret = hdb_entry_get_password(context->context, - context->db, &ent.entry, &pw); + context->db, &ent, &pw); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); free(pw); + if (ret) + goto out; } krb5_clear_error_message(context->context); } - ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl); + ret = hdb_entry_get_pkinit_acl(&ent, &acl); if (ret == 0 && acl) { krb5_data buf; size_t len; @@ -367,10 +370,8 @@ kadm5_s_get_principal(void *server_handle, if (ret) goto out; } - if (ret) - goto out; - ret = hdb_entry_get_aliases(&ent.entry, &aliases); + ret = hdb_entry_get_aliases(&ent, &aliases); if (ret == 0 && aliases) { krb5_data buf; size_t len; @@ -387,34 +388,24 @@ kadm5_s_get_principal(void *server_handle, if (ret) goto out; } - if (ret) - goto out; - ret = hdb_entry_get_key_rotation(context->context, &ent.entry, &kr); + ret = hdb_entry_get_key_rotation(context->context, &ent, &kr); if (ret == 0 && kr) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_KeyRotation, buf.data, buf.length, kr, &len, ret); - if (ret) - goto out; - if (len != buf.length) - krb5_abortx(context->context, - "internal ASN.1 encoder error"); - ret = add_tl_data(out, KRB5_TL_KEY_ROTATION, buf.data, buf.length); + if (ret == 0) + ret = add_tl_data(out, KRB5_TL_KEY_ROTATION, buf.data, buf.length); free(buf.data); - if (ret) - goto out; } - if (ret) - goto out; } out: if (ret) kadm5_free_principal_ent(context, out); - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); return _kadm5_error_code(ret); } diff --git a/third_party/heimdal/lib/kadm5/init_c.c b/third_party/heimdal/lib/kadm5/init_c.c index a0a3443898a5..5d585d1a2951 100644 --- a/third_party/heimdal/lib/kadm5/init_c.c +++ b/third_party/heimdal/lib/kadm5/init_c.c @@ -427,12 +427,15 @@ _kadm5_c_get_cred_cache(krb5_context context, user = roken_get_username(userbuf, sizeof(userbuf)); if (user == NULL) { krb5_set_error_message(context, KADM5_FAILURE, "Unable to find local user name"); + krb5_free_principal(context, client); return KADM5_FAILURE; } ret = krb5_make_principal(context, &default_client, NULL, user, "admin", NULL); - if(ret) + if (ret) { + krb5_free_principal(context, client); return ret; + } } } @@ -509,9 +512,9 @@ kadm_connect(kadm5_client_context *ctx) hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; - snprintf(portstr, sizeof(portstr), "%u", ntohs(ctx->kadmind_port)); + snprintf(portstr, sizeof(portstr), "%u", ntohs(kadmin_port)); - hostname = ctx->admin_server; + hostname = admin_server; slash = strchr(hostname, '/'); if (slash != NULL) hostname = slash + 1; @@ -530,6 +533,7 @@ kadm_connect(kadm5_client_context *ctx) if (connect(s, a->ai_addr, a->ai_addrlen) < 0) { krb5_warn(context, errno, "connect(%s)", hostname); rk_closesocket(s); + s = rk_INVALID_SOCKET; continue; } break; @@ -640,7 +644,7 @@ kadm5_c_init_with_context(krb5_context context, void **server_handle) { kadm5_ret_t ret; - kadm5_client_context *ctx; + kadm5_client_context *ctx = NULL; krb5_ccache cc; ret = _kadm5_c_init_context(&ctx, realm_params, context); diff --git a/third_party/heimdal/lib/kadm5/init_s.c b/third_party/heimdal/lib/kadm5/init_s.c index 926c23510e9e..1b1d7f2ff58c 100644 --- a/third_party/heimdal/lib/kadm5/init_s.c +++ b/third_party/heimdal/lib/kadm5/init_s.c @@ -45,14 +45,16 @@ kadm5_s_init_with_context(krb5_context context, void **server_handle) { kadm5_ret_t ret; - kadm5_server_context *ctx; + kadm5_server_context *ctx = NULL; char *dbname; char *stash_file; *server_handle = NULL; ret = _kadm5_s_init_context(&ctx, realm_params, context); - if (ret) + if (ret) { + kadm5_s_destroy(ctx); return ret; + } if (realm_params->mask & KADM5_CONFIG_DBNAME) dbname = realm_params->dbname; diff --git a/third_party/heimdal/lib/kadm5/iprop-log.c b/third_party/heimdal/lib/kadm5/iprop-log.c index 9c18f832e132..a2ad51e7d081 100644 --- a/third_party/heimdal/lib/kadm5/iprop-log.c +++ b/third_party/heimdal/lib/kadm5/iprop-log.c @@ -137,21 +137,29 @@ print_entry(kadm5_server_context *server_context, entry_kind, op_names[op], ver, t, len); switch(op) { case kadm_delete: - krb5_ret_principal(sp, &source); - krb5_unparse_name(scontext, source, &name1); + ret = krb5_ret_principal(sp, &source); + if (ret == 0) + ret = krb5_unparse_name(scontext, source, &name1); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a delete record"); printf(" %s\n", name1); free(name1); krb5_free_principal(scontext, source); break; case kadm_rename: ret = krb5_data_alloc(&data, len); - if (ret) - krb5_err (scontext, 1, ret, "kadm_rename: data alloc: %d", len); - krb5_ret_principal(sp, &source); - krb5_storage_read(sp, data.data, data.length); - hdb_value2entry(scontext, &data, &ent); - krb5_unparse_name(scontext, source, &name1); - krb5_unparse_name(scontext, ent.principal, &name2); + if (ret == 0) + ret = krb5_ret_principal(sp, &source); + if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1) + ret = errno; + if (ret == 0) + ret = hdb_value2entry(scontext, &data, &ent); + if (ret == 0) + ret = krb5_unparse_name(scontext, source, &name1); + if (ret == 0) + ret = krb5_unparse_name(scontext, ent.principal, &name2); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a rename record"); printf(" %s -> %s\n", name1, name2); free(name1); free(name2); @@ -160,26 +168,30 @@ print_entry(kadm5_server_context *server_context, break; case kadm_create: ret = krb5_data_alloc(&data, len); + if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1) + ret = errno; + if (ret == 0) + ret = hdb_value2entry(scontext, &data, &ent); if (ret) - krb5_err (scontext, 1, ret, "kadm_create: data alloc: %d", len); - krb5_storage_read(sp, data.data, data.length); - ret = hdb_value2entry(scontext, &data, &ent); - if(ret) - abort(); + krb5_err(scontext, 1, ret, "Failed to read a create record"); mask = ~0; goto foo; case kadm_modify: ret = krb5_data_alloc(&data, len); + if (ret == 0) + ret = krb5_ret_int32(sp, &mask); + if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1) + ret = errno; + if (ret == 0) + ret = hdb_value2entry(scontext, &data, &ent); if (ret) - krb5_err (scontext, 1, ret, "kadm_modify: data alloc: %d", len); - krb5_ret_int32(sp, &mask); - krb5_storage_read(sp, data.data, data.length); - ret = hdb_value2entry(scontext, &data, &ent); - if(ret) - abort(); + krb5_err(scontext, 1, ret, "Failed to read a modify record"); foo: if(ent.principal /* mask & KADM5_PRINCIPAL */) { - krb5_unparse_name(scontext, ent.principal, &name1); + ret = krb5_unparse_name(scontext, ent.principal, &name1); + if (ret) + krb5_err(scontext, 1, ret, + "Failed to process a create or modify record"); printf(" principal = %s\n", name1); free(name1); } @@ -263,14 +275,19 @@ print_entry(kadm5_server_context *server_context, case kadm_nop : if (len == 16) { uint64_t off; - krb5_ret_uint64(sp, &off); + ret = krb5_ret_uint64(sp, &off); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a no-op record"); printf("uberblock offset %llu ", (unsigned long long)off); } else { printf("nop"); } if (len == 16 || len == 8) { - krb5_ret_int32(sp, &nop_time); - krb5_ret_uint32(sp, &nop_ver); + ret = krb5_ret_int32(sp, &nop_time); + if (ret == 0) + ret = krb5_ret_uint32(sp, &nop_ver); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a no-op record"); timestamp = nop_time; strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); @@ -279,7 +296,7 @@ print_entry(kadm5_server_context *server_context, printf("\n"); break; default: - abort(); + krb5_errx(scontext, 1, "Unknown record type"); } krb5_data_free(&data); diff --git a/third_party/heimdal/lib/kadm5/ipropd_common.c b/third_party/heimdal/lib/kadm5/ipropd_common.c index be0adc1b3802..1decfe3333d9 100644 --- a/third_party/heimdal/lib/kadm5/ipropd_common.c +++ b/third_party/heimdal/lib/kadm5/ipropd_common.c @@ -53,6 +53,7 @@ setup_signal(void) { struct sigaction sa; + memset(&sa, 0, sizeof(sa)); sa.sa_flags = 0; sa.sa_handler = sigterm; sigemptyset(&sa.sa_mask); diff --git a/third_party/heimdal/lib/kadm5/ipropd_master.c b/third_party/heimdal/lib/kadm5/ipropd_master.c index a27d8f75a38b..b3f7d8105ea7 100644 --- a/third_party/heimdal/lib/kadm5/ipropd_master.c +++ b/third_party/heimdal/lib/kadm5/ipropd_master.c @@ -95,7 +95,7 @@ make_listen_socket (krb5_context context, const char *port_str) fd = socket (AF_INET, SOCK_STREAM, 0); if (rk_IS_BAD_SOCKET(fd)) krb5_err (context, 1, rk_SOCK_ERRNO, "socket AF_INET"); - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); + (void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); memset (&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; @@ -392,14 +392,14 @@ error: } static int -dump_one (krb5_context context, HDB *db, hdb_entry_ex *entry, void *v) +dump_one (krb5_context context, HDB *db, hdb_entry *entry, void *v) { krb5_error_code ret; krb5_storage *dump = (krb5_storage *)v; krb5_storage *sp; krb5_data data; - ret = hdb_entry2value (context, &entry->entry, &data); + ret = hdb_entry2value (context, entry, &data); if (ret) return ret; ret = krb5_data_realloc (&data, data.length + 4); @@ -450,6 +450,8 @@ write_dump (krb5_context context, krb5_storage *dump, */ ret = krb5_store_uint32(dump, 0); + if (ret) + return ret; ret = hdb_create (context, &db, database); if (ret) @@ -1117,7 +1119,7 @@ send_diffs(kadm5_server_context *server_context, slave *s, int log_fd, krb5_storage *sp; uint32_t initial_version; uint32_t initial_tstamp; - uint32_t ver; + uint32_t ver = 0; off_t left = 0; off_t right = 0; krb5_ssize_t bytes; @@ -1251,7 +1253,8 @@ fill_input(krb5_context context, slave *s) return EWOULDBLOCK; buf = s->input.header_buf; - len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + len = ((unsigned long)buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; if (len > SLAVE_MSG_MAX) return EINVAL; ret = krb5_data_alloc(&s->input.packet, len); @@ -1432,11 +1435,13 @@ write_master_down(krb5_context context) fp = fopen(slave_stats_temp_file, "w"); if (fp == NULL) return; - krb5_format_time(context, t, str, sizeof(str), TRUE); - fprintf(fp, "master down at %s\n", str); + if (krb5_format_time(context, t, str, sizeof(str), TRUE) == 0) + fprintf(fp, "master down at %s\n", str); + else + fprintf(fp, "master down\n"); if (fclose(fp) != EOF) - rk_rename(slave_stats_temp_file, slave_stats_file); + (void) rk_rename(slave_stats_temp_file, slave_stats_file); } static void @@ -1452,7 +1457,8 @@ write_stats(krb5_context context, slave *slaves, uint32_t current_version) if (fp == NULL) return; - krb5_format_time(context, t, str, sizeof(str), TRUE); + if (krb5_format_time(context, t, str, sizeof(str), TRUE)) + snprintf(str, sizeof(str), ""); fprintf(fp, "Status for slaves, last updated: %s\n\n", str); fprintf(fp, "Master version: %lu\n\n", (unsigned long)current_version); @@ -1494,7 +1500,10 @@ write_stats(krb5_context context, slave *slaves, uint32_t current_version) rtbl_add_column_entry(tbl, SLAVE_STATUS, "Up"); ret = krb5_format_time(context, slaves->seen, str, sizeof(str), TRUE); - rtbl_add_column_entry(tbl, SLAVE_SEEN, str); + if (ret) + rtbl_add_column_entry(tbl, SLAVE_SEEN, ""); + else + rtbl_add_column_entry(tbl, SLAVE_SEEN, str); slaves = slaves->next; } @@ -1503,7 +1512,7 @@ write_stats(krb5_context context, slave *slaves, uint32_t current_version) rtbl_destroy(tbl); if (fclose(fp) != EOF) - rk_rename(slave_stats_temp_file, slave_stats_file); + (void) rk_rename(slave_stats_temp_file, slave_stats_file); } diff --git a/third_party/heimdal/lib/kadm5/ipropd_slave.c b/third_party/heimdal/lib/kadm5/ipropd_slave.c index cd9a6f57a3b9..2b1be00ea606 100644 --- a/third_party/heimdal/lib/kadm5/ipropd_slave.c +++ b/third_party/heimdal/lib/kadm5/ipropd_slave.c @@ -184,6 +184,8 @@ ihave(krb5_context context, krb5_auth_context auth_context, krb5_data data; sp = krb5_storage_from_mem(buf, 8); + if (sp == NULL) + krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "Out of memory"); ret = krb5_store_uint32(sp, I_HAVE); if (ret == 0) ret = krb5_store_uint32(sp, version); @@ -571,7 +573,7 @@ receive_everything(krb5_context context, int fd, krb5_ret_uint32(sp, &opcode); if (opcode == ONE_PRINC) { krb5_data fake_data; - hdb_entry_ex entry; + hdb_entry entry; krb5_storage_free(sp); @@ -580,7 +582,7 @@ receive_everything(krb5_context context, int fd, memset(&entry, 0, sizeof(entry)); - ret = hdb_value2entry(context, &fake_data, &entry.entry); + ret = hdb_value2entry(context, &fake_data, &entry); if (ret) krb5_err(context, IPROPD_RESTART, ret, "hdb_value2entry"); ret = mydb->hdb_store(server_context->context, @@ -589,7 +591,7 @@ receive_everything(krb5_context context, int fd, if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "hdb_store"); - hdb_free_entry(context, &entry); + hdb_free_entry(context, mydb, &entry); krb5_data_free(&data); } else if (opcode == NOW_YOU_HAVE) ; diff --git a/third_party/heimdal/lib/kadm5/log.c b/third_party/heimdal/lib/kadm5/log.c index 376cecd9e40b..4f66426c4ca6 100644 --- a/third_party/heimdal/lib/kadm5/log.c +++ b/third_party/heimdal/lib/kadm5/log.c @@ -974,14 +974,12 @@ kadm5_log_create(kadm5_server_context *context, hdb_entry *entry) krb5_ssize_t bytes; kadm5_ret_t ret; krb5_data value; - hdb_entry_ex ent, existing; + hdb_entry ent, existing; kadm5_log_context *log_context = &context->log_context; memset(&existing, 0, sizeof(existing)); memset(&ent, 0, sizeof(ent)); - ent.ctx = 0; - ent.free_entry = 0; - ent.entry = *entry; + ent = *entry; /* * Do not allow creation of concrete entries within namespaces unless @@ -991,14 +989,14 @@ kadm5_log_create(kadm5_server_context *context, hdb_entry *entry) 0, 0, 0, &existing); if (ret != 0 && ret != HDB_ERR_NOENTRY) return ret; - if (ret == 0 && !ent.entry.flags.materialize && - (existing.entry.flags.virtual || existing.entry.flags.virtual_keys)) { - hdb_free_entry(context->context, &existing); + if (ret == 0 && !ent.flags.materialize && + (existing.flags.virtual || existing.flags.virtual_keys)) { + hdb_free_entry(context->context, context->db, &existing); return HDB_ERR_EXISTS; } if (ret == 0) - hdb_free_entry(context->context, &existing); - ent.entry.flags.materialize = 0; /* Clear in stored entry */ + hdb_free_entry(context->context, context->db, &existing); + ent.flags.materialize = 0; /* Clear in stored entry */ /* * If we're not logging then we can't recover-to-perform, so just @@ -1057,7 +1055,7 @@ kadm5_log_replay_create(kadm5_server_context *context, { krb5_error_code ret; krb5_data data; - hdb_entry_ex ent; + hdb_entry ent; memset(&ent, 0, sizeof(ent)); @@ -1067,7 +1065,7 @@ kadm5_log_replay_create(kadm5_server_context *context, return ret; } krb5_storage_read(sp, data.data, len); - ret = hdb_value2entry(context->context, &data, &ent.entry); + ret = hdb_value2entry(context->context, &data, &ent); krb5_data_free(&data); if (ret) { krb5_set_error_message(context->context, ret, @@ -1076,7 +1074,7 @@ kadm5_log_replay_create(kadm5_server_context *context, return ret; } ret = context->db->hdb_store(context->context, context->db, 0, &ent); - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); return ret; } @@ -1198,13 +1196,11 @@ kadm5_log_rename(kadm5_server_context *context, off_t end_off = 0; /* Ditto; this allows de-indentation by two levels */ off_t off; krb5_data value; - hdb_entry_ex ent; + hdb_entry ent; kadm5_log_context *log_context = &context->log_context; memset(&ent, 0, sizeof(ent)); - ent.ctx = 0; - ent.free_entry = 0; - ent.entry = *entry; + ent = *entry; if (strcmp(log_context->log_file, "/dev/null") == 0) { ret = context->db->hdb_store(context->context, context->db, 0, &ent); @@ -1310,7 +1306,7 @@ kadm5_log_replay_rename(kadm5_server_context *context, { krb5_error_code ret; krb5_principal source; - hdb_entry_ex target_ent; + hdb_entry target_ent; krb5_data value; off_t off; size_t princ_len, data_len; @@ -1332,7 +1328,7 @@ kadm5_log_replay_rename(kadm5_server_context *context, return ret; } krb5_storage_read(sp, value.data, data_len); - ret = hdb_value2entry(context->context, &value, &target_ent.entry); + ret = hdb_value2entry(context->context, &value, &target_ent); krb5_data_free(&value); if (ret) { krb5_free_principal(context->context, source); @@ -1340,7 +1336,7 @@ kadm5_log_replay_rename(kadm5_server_context *context, } ret = context->db->hdb_store(context->context, context->db, 0, &target_ent); - hdb_free_entry(context->context, &target_ent); + hdb_free_entry(context->context, context->db, &target_ent); if (ret) { krb5_free_principal(context->context, source); return ret; @@ -1364,13 +1360,11 @@ kadm5_log_modify(kadm5_server_context *context, kadm5_ret_t ret; krb5_data value; uint32_t len; - hdb_entry_ex ent; + hdb_entry ent; kadm5_log_context *log_context = &context->log_context; memset(&ent, 0, sizeof(ent)); - ent.ctx = 0; - ent.free_entry = 0; - ent.entry = *entry; + ent = *entry; if (strcmp(log_context->log_file, "/dev/null") == 0) return context->db->hdb_store(context->context, context->db, @@ -1434,7 +1428,7 @@ kadm5_log_replay_modify(kadm5_server_context *context, krb5_error_code ret; uint32_t mask; krb5_data value; - hdb_entry_ex ent, log_ent; + hdb_entry ent, log_ent; memset(&log_ent, 0, sizeof(log_ent)); @@ -1452,7 +1446,7 @@ kadm5_log_replay_modify(kadm5_server_context *context, ret = errno ? errno : EIO; return ret; } - ret = hdb_value2entry (context->context, &value, &log_ent.entry); + ret = hdb_value2entry (context->context, &value, &log_ent); krb5_data_free(&value); if (ret) return ret; @@ -1460,37 +1454,37 @@ kadm5_log_replay_modify(kadm5_server_context *context, memset(&ent, 0, sizeof(ent)); /* NOTE: We do not use hdb_fetch_kvno() here */ ret = context->db->hdb_fetch_kvno(context->context, context->db, - log_ent.entry.principal, + log_ent.principal, HDB_F_DECRYPT|HDB_F_ALL_KVNOS| HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if (ret) goto out; if (mask & KADM5_PRINC_EXPIRE_TIME) { - if (log_ent.entry.valid_end == NULL) { - ent.entry.valid_end = NULL; + if (log_ent.valid_end == NULL) { + ent.valid_end = NULL; } else { - if (ent.entry.valid_end == NULL) { - ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end)); - if (ent.entry.valid_end == NULL) { + if (ent.valid_end == NULL) { + ent.valid_end = malloc(sizeof(*ent.valid_end)); + if (ent.valid_end == NULL) { ret = krb5_enomem(context->context); goto out; } } - *ent.entry.valid_end = *log_ent.entry.valid_end; + *ent.valid_end = *log_ent.valid_end; } } if (mask & KADM5_PW_EXPIRATION) { - if (log_ent.entry.pw_end == NULL) { - ent.entry.pw_end = NULL; + if (log_ent.pw_end == NULL) { + ent.pw_end = NULL; } else { - if (ent.entry.pw_end == NULL) { - ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end)); - if (ent.entry.pw_end == NULL) { + if (ent.pw_end == NULL) { + ent.pw_end = malloc(sizeof(*ent.pw_end)); + if (ent.pw_end == NULL) { ret = krb5_enomem(context->context); goto out; } } - *ent.entry.pw_end = *log_ent.entry.pw_end; + *ent.pw_end = *log_ent.pw_end; } } if (mask & KADM5_LAST_PWD_CHANGE) { @@ -1498,39 +1492,39 @@ kadm5_log_replay_modify(kadm5_server_context *context, "Unimplemented mask KADM5_LAST_PWD_CHANGE"); } if (mask & KADM5_ATTRIBUTES) { - ent.entry.flags = log_ent.entry.flags; + ent.flags = log_ent.flags; } if (mask & KADM5_MAX_LIFE) { - if (log_ent.entry.max_life == NULL) { - ent.entry.max_life = NULL; + if (log_ent.max_life == NULL) { + ent.max_life = NULL; } else { - if (ent.entry.max_life == NULL) { - ent.entry.max_life = malloc (sizeof(*ent.entry.max_life)); - if (ent.entry.max_life == NULL) { + if (ent.max_life == NULL) { + ent.max_life = malloc (sizeof(*ent.max_life)); + if (ent.max_life == NULL) { ret = krb5_enomem(context->context); goto out; } } - *ent.entry.max_life = *log_ent.entry.max_life; + *ent.max_life = *log_ent.max_life; } } if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) { - if (ent.entry.modified_by == NULL) { - ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by)); - if (ent.entry.modified_by == NULL) { + if (ent.modified_by == NULL) { + ent.modified_by = malloc(sizeof(*ent.modified_by)); + if (ent.modified_by == NULL) { ret = krb5_enomem(context->context); goto out; } } else - free_Event(ent.entry.modified_by); - ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by); + free_Event(ent.modified_by); + ret = copy_Event(log_ent.modified_by, ent.modified_by); if (ret) { ret = krb5_enomem(context->context); goto out; } } if (mask & KADM5_KVNO) { - ent.entry.kvno = log_ent.entry.kvno; + ent.kvno = log_ent.kvno; } if (mask & KADM5_MKVNO) { krb5_warnx(context->context, "Unimplemented mask KADM5_KVNO"); @@ -1543,17 +1537,17 @@ kadm5_log_replay_modify(kadm5_server_context *context, krb5_warnx(context->context, "Unimplemented mask KADM5_POLICY_CLR"); } if (mask & KADM5_MAX_RLIFE) { - if (log_ent.entry.max_renew == NULL) { - ent.entry.max_renew = NULL; + if (log_ent.max_renew == NULL) { + ent.max_renew = NULL; } else { - if (ent.entry.max_renew == NULL) { - ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew)); - if (ent.entry.max_renew == NULL) { + if (ent.max_renew == NULL) { + ent.max_renew = malloc (sizeof(*ent.max_renew)); + if (ent.max_renew == NULL) { ret = krb5_enomem(context->context); goto out; } } - *ent.entry.max_renew = *log_ent.entry.max_renew; + *ent.max_renew = *log_ent.max_renew; } } if (mask & KADM5_LAST_SUCCESS) { @@ -1579,70 +1573,70 @@ kadm5_log_replay_modify(kadm5_server_context *context, */ mask |= KADM5_TL_DATA; - for (i = 0; i < ent.entry.keys.len; ++i) - free_Key(&ent.entry.keys.val[i]); - free (ent.entry.keys.val); + for (i = 0; i < ent.keys.len; ++i) + free_Key(&ent.keys.val[i]); + free (ent.keys.val); - num = log_ent.entry.keys.len; + num = log_ent.keys.len; - ent.entry.keys.len = num; - ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val)); - if (ent.entry.keys.val == NULL) { + ent.keys.len = num; + ent.keys.val = malloc(len * sizeof(*ent.keys.val)); + if (ent.keys.val == NULL) { krb5_enomem(context->context); goto out; } - for (i = 0; i < ent.entry.keys.len; ++i) { - ret = copy_Key(&log_ent.entry.keys.val[i], - &ent.entry.keys.val[i]); + for (i = 0; i < ent.keys.len; ++i) { + ret = copy_Key(&log_ent.keys.val[i], + &ent.keys.val[i]); if (ret) { krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } } - if ((mask & KADM5_TL_DATA) && log_ent.entry.etypes) { - if (ent.entry.etypes) - free_HDB_EncTypeList(ent.entry.etypes); - free(ent.entry.etypes); - ent.entry.etypes = calloc(1, sizeof(*ent.entry.etypes)); - if (ent.entry.etypes == NULL) + if ((mask & KADM5_TL_DATA) && log_ent.etypes) { + if (ent.etypes) + free_HDB_EncTypeList(ent.etypes); + free(ent.etypes); + ent.etypes = calloc(1, sizeof(*ent.etypes)); + if (ent.etypes == NULL) ret = ENOMEM; if (ret == 0) - ret = copy_HDB_EncTypeList(log_ent.entry.etypes, ent.entry.etypes); + ret = copy_HDB_EncTypeList(log_ent.etypes, ent.etypes); if (ret) { ret = krb5_enomem(context->context); - free(ent.entry.etypes); - ent.entry.etypes = NULL; + free(ent.etypes); + ent.etypes = NULL; goto out; } } - if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) { - if (ent.entry.extensions) { - free_HDB_extensions(ent.entry.extensions); - free(ent.entry.extensions); - ent.entry.extensions = NULL; + if ((mask & KADM5_TL_DATA) && log_ent.extensions) { + if (ent.extensions) { + free_HDB_extensions(ent.extensions); + free(ent.extensions); + ent.extensions = NULL; } - ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions)); - if (ent.entry.extensions == NULL) + ent.extensions = calloc(1, sizeof(*ent.extensions)); + if (ent.extensions == NULL) ret = ENOMEM; if (ret == 0) - ret = copy_HDB_extensions(log_ent.entry.extensions, - ent.entry.extensions); + ret = copy_HDB_extensions(log_ent.extensions, + ent.extensions); if (ret) { ret = krb5_enomem(context->context); - free(ent.entry.extensions); - ent.entry.extensions = NULL; + free(ent.extensions); + ent.extensions = NULL; goto out; } } ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); out: - hdb_free_entry(context->context, &ent); - hdb_free_entry(context->context, &log_ent); + hdb_free_entry(context->context, context->db, &ent); + hdb_free_entry(context->context, context->db, &log_ent); return ret; } diff --git a/third_party/heimdal/lib/kadm5/marshall.c b/third_party/heimdal/lib/kadm5/marshall.c index c66bcd75ae67..9d24233ba6ea 100644 --- a/third_party/heimdal/lib/kadm5/marshall.c +++ b/third_party/heimdal/lib/kadm5/marshall.c @@ -33,7 +33,7 @@ #include "kadm5_locl.h" -RCSID("$Id$"); +#define CHECK(e) do { if ((ret = e)) goto out; } while (0) int kadm5_some_keys_are_bogus(size_t n_keys, krb5_key_data *keys) @@ -72,29 +72,34 @@ kadm5_ret_t kadm5_store_key_data(krb5_storage *sp, krb5_key_data *key) { + kadm5_ret_t ret; krb5_data c; - krb5_store_int32(sp, key->key_data_ver); - krb5_store_int32(sp, key->key_data_kvno); - krb5_store_int32(sp, key->key_data_type[0]); + + CHECK(krb5_store_int32(sp, key->key_data_ver)); + CHECK(krb5_store_int32(sp, key->key_data_kvno)); + CHECK(krb5_store_int32(sp, key->key_data_type[0])); c.length = key->key_data_length[0]; c.data = key->key_data_contents[0]; - krb5_store_data(sp, c); - krb5_store_int32(sp, key->key_data_type[1]); + CHECK(krb5_store_data(sp, c)); + CHECK(krb5_store_int32(sp, key->key_data_type[1])); c.length = key->key_data_length[1]; c.data = key->key_data_contents[1]; - krb5_store_data(sp, c); - return 0; + CHECK(krb5_store_data(sp, c)); + +out: + return ret; } kadm5_ret_t kadm5_store_fake_key_data(krb5_storage *sp, krb5_key_data *key) { + kadm5_ret_t ret; krb5_data c; - krb5_store_int32(sp, key->key_data_ver); - krb5_store_int32(sp, key->key_data_kvno); - krb5_store_int32(sp, key->key_data_type[0]); + CHECK(krb5_store_int32(sp, key->key_data_ver)); + CHECK(krb5_store_int32(sp, key->key_data_kvno)); + CHECK(krb5_store_int32(sp, key->key_data_type[0])); /* * This is the key contents. We want it to be obvious to the client @@ -106,63 +111,88 @@ kadm5_store_fake_key_data(krb5_storage *sp, */ c.length = sizeof (KADM5_BOGUS_KEY_DATA) - 1; c.data = KADM5_BOGUS_KEY_DATA; - krb5_store_data(sp, c); + CHECK(krb5_store_data(sp, c)); /* This is the salt -- no need to send garbage */ - krb5_store_int32(sp, key->key_data_type[1]); + CHECK(krb5_store_int32(sp, key->key_data_type[1])); c.length = key->key_data_length[1]; c.data = key->key_data_contents[1]; - krb5_store_data(sp, c); - return 0; + CHECK(krb5_store_data(sp, c)); + +out: + return ret; } kadm5_ret_t kadm5_ret_key_data(krb5_storage *sp, krb5_key_data *key) { + kadm5_ret_t ret; krb5_data c; int32_t tmp; - krb5_ret_int32(sp, &tmp); - key->key_data_ver = tmp; - krb5_ret_int32(sp, &tmp); - key->key_data_kvno = tmp; - krb5_ret_int32(sp, &tmp); - key->key_data_type[0] = tmp; - krb5_ret_data(sp, &c); - key->key_data_length[0] = c.length; - key->key_data_contents[0] = c.data; - krb5_ret_int32(sp, &tmp); - key->key_data_type[1] = tmp; - krb5_ret_data(sp, &c); - key->key_data_length[1] = c.length; - key->key_data_contents[1] = c.data; - return 0; + + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) { + key->key_data_ver = tmp; + ret = krb5_ret_int32(sp, &tmp); + } + if (ret == 0) { + key->key_data_kvno = tmp; + ret = krb5_ret_int32(sp, &tmp); + } + if (ret == 0) { + key->key_data_type[0] = tmp; + ret = krb5_ret_data(sp, &c); + } + if (ret == 0) { + key->key_data_length[0] = c.length; + key->key_data_contents[0] = c.data; + ret = krb5_ret_int32(sp, &tmp); + } + if (ret == 0) { + key->key_data_type[1] = tmp; + ret = krb5_ret_data(sp, &c); + } + if (ret == 0) { + key->key_data_length[1] = c.length; + key->key_data_contents[1] = c.data; + return 0; + } + return KADM5_FAILURE; } kadm5_ret_t kadm5_store_tl_data(krb5_storage *sp, krb5_tl_data *tl) { + kadm5_ret_t ret; krb5_data c; - krb5_store_int32(sp, tl->tl_data_type); + + CHECK(krb5_store_int32(sp, tl->tl_data_type)); c.length = tl->tl_data_length; c.data = tl->tl_data_contents; - krb5_store_data(sp, c); - return 0; + CHECK(krb5_store_data(sp, c)); + +out: + return ret; } kadm5_ret_t kadm5_ret_tl_data(krb5_storage *sp, krb5_tl_data *tl) { + kadm5_ret_t ret; krb5_data c; int32_t tmp; - krb5_ret_int32(sp, &tmp); + + CHECK(krb5_ret_int32(sp, &tmp)); tl->tl_data_type = tmp; - krb5_ret_data(sp, &c); + CHECK(krb5_ret_data(sp, &c)); tl->tl_data_length = c.length; tl->tl_data_contents = c.data; - return 0; + +out: + return ret; } static kadm5_ret_t @@ -170,63 +200,66 @@ store_principal_ent(krb5_storage *sp, kadm5_principal_ent_t princ, uint32_t mask, int wkeys) { + kadm5_ret_t ret = 0; int i; if (mask & KADM5_PRINCIPAL) - krb5_store_principal(sp, princ->principal); + CHECK(krb5_store_principal(sp, princ->principal)); if (mask & KADM5_PRINC_EXPIRE_TIME) - krb5_store_int32(sp, princ->princ_expire_time); + CHECK(krb5_store_int32(sp, princ->princ_expire_time)); if (mask & KADM5_PW_EXPIRATION) - krb5_store_int32(sp, princ->pw_expiration); + CHECK(krb5_store_int32(sp, princ->pw_expiration)); if (mask & KADM5_LAST_PWD_CHANGE) - krb5_store_int32(sp, princ->last_pwd_change); + CHECK(krb5_store_int32(sp, princ->last_pwd_change)); if (mask & KADM5_MAX_LIFE) - krb5_store_int32(sp, princ->max_life); + CHECK(krb5_store_int32(sp, princ->max_life)); if (mask & KADM5_MOD_NAME) { - krb5_store_int32(sp, princ->mod_name != NULL); + CHECK(krb5_store_int32(sp, princ->mod_name != NULL)); if(princ->mod_name) - krb5_store_principal(sp, princ->mod_name); + CHECK(krb5_store_principal(sp, princ->mod_name)); } if (mask & KADM5_MOD_TIME) - krb5_store_int32(sp, princ->mod_date); + CHECK(krb5_store_int32(sp, princ->mod_date)); if (mask & KADM5_ATTRIBUTES) - krb5_store_int32(sp, princ->attributes); + CHECK(krb5_store_int32(sp, princ->attributes)); if (mask & KADM5_KVNO) - krb5_store_int32(sp, princ->kvno); + CHECK(krb5_store_int32(sp, princ->kvno)); if (mask & KADM5_MKVNO) - krb5_store_int32(sp, princ->mkvno); + CHECK(krb5_store_int32(sp, princ->mkvno)); if (mask & KADM5_POLICY) { - krb5_store_int32(sp, princ->policy != NULL); + CHECK(krb5_store_int32(sp, princ->policy != NULL)); if(princ->policy) - krb5_store_string(sp, princ->policy); + CHECK(krb5_store_string(sp, princ->policy)); } if (mask & KADM5_AUX_ATTRIBUTES) - krb5_store_int32(sp, princ->aux_attributes); + CHECK(krb5_store_int32(sp, princ->aux_attributes)); if (mask & KADM5_MAX_RLIFE) - krb5_store_int32(sp, princ->max_renewable_life); + CHECK(krb5_store_int32(sp, princ->max_renewable_life)); if (mask & KADM5_LAST_SUCCESS) - krb5_store_int32(sp, princ->last_success); + CHECK(krb5_store_int32(sp, princ->last_success)); if (mask & KADM5_LAST_FAILED) - krb5_store_int32(sp, princ->last_failed); + CHECK(krb5_store_int32(sp, princ->last_failed)); if (mask & KADM5_FAIL_AUTH_COUNT) - krb5_store_int32(sp, princ->fail_auth_count); + CHECK(krb5_store_int32(sp, princ->fail_auth_count)); if (mask & KADM5_KEY_DATA) { - krb5_store_int32(sp, princ->n_key_data); + CHECK(krb5_store_int32(sp, princ->n_key_data)); for(i = 0; i < princ->n_key_data; i++) { if (wkeys) - kadm5_store_key_data(sp, &princ->key_data[i]); - else - kadm5_store_fake_key_data(sp, &princ->key_data[i]); + CHECK(kadm5_store_key_data(sp, &princ->key_data[i])); + else + CHECK(kadm5_store_fake_key_data(sp, &princ->key_data[i])); } } if (mask & KADM5_TL_DATA) { krb5_tl_data *tp; - krb5_store_int32(sp, princ->n_tl_data); - for(tp = princ->tl_data; tp; tp = tp->tl_data_next) - kadm5_store_tl_data(sp, tp); + CHECK(krb5_store_int32(sp, princ->n_tl_data)); + for (tp = princ->tl_data; tp; tp = tp->tl_data_next) + CHECK(kadm5_store_tl_data(sp, tp)); } - return 0; + +out: + return ret; } @@ -249,8 +282,12 @@ kadm5_store_principal_ent_mask(krb5_storage *sp, kadm5_principal_ent_t princ, uint32_t mask) { - krb5_store_int32(sp, mask); - return store_principal_ent (sp, princ, mask, 1); + kadm5_ret_t ret; + + ret = krb5_store_int32(sp, mask); + if (ret == 0) + ret = store_principal_ent(sp, princ, mask, 1); + return ret; } static kadm5_ret_t @@ -258,101 +295,112 @@ ret_principal_ent(krb5_storage *sp, kadm5_principal_ent_t princ, uint32_t mask) { + kadm5_ret_t ret = 0; int i; int32_t tmp; if (mask & KADM5_PRINCIPAL) - krb5_ret_principal(sp, &princ->principal); + CHECK(krb5_ret_principal(sp, &princ->principal)); if (mask & KADM5_PRINC_EXPIRE_TIME) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->princ_expire_time = tmp; } if (mask & KADM5_PW_EXPIRATION) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->pw_expiration = tmp; } if (mask & KADM5_LAST_PWD_CHANGE) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->last_pwd_change = tmp; } if (mask & KADM5_MAX_LIFE) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->max_life = tmp; } if (mask & KADM5_MOD_NAME) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); if(tmp) - krb5_ret_principal(sp, &princ->mod_name); + CHECK(krb5_ret_principal(sp, &princ->mod_name)); else princ->mod_name = NULL; } if (mask & KADM5_MOD_TIME) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->mod_date = tmp; } if (mask & KADM5_ATTRIBUTES) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->attributes = tmp; } if (mask & KADM5_KVNO) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->kvno = tmp; } if (mask & KADM5_MKVNO) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->mkvno = tmp; } if (mask & KADM5_POLICY) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); if(tmp) - krb5_ret_string(sp, &princ->policy); + CHECK(krb5_ret_string(sp, &princ->policy)); else princ->policy = NULL; } if (mask & KADM5_AUX_ATTRIBUTES) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->aux_attributes = tmp; } if (mask & KADM5_MAX_RLIFE) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->max_renewable_life = tmp; } if (mask & KADM5_LAST_SUCCESS) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->last_success = tmp; } if (mask & KADM5_LAST_FAILED) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->last_failed = tmp; } if (mask & KADM5_FAIL_AUTH_COUNT) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->fail_auth_count = tmp; } if (mask & KADM5_KEY_DATA) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->n_key_data = tmp; princ->key_data = malloc(princ->n_key_data * sizeof(*princ->key_data)); if (princ->key_data == NULL && princ->n_key_data != 0) return ENOMEM; for(i = 0; i < princ->n_key_data; i++) - kadm5_ret_key_data(sp, &princ->key_data[i]); + ret = kadm5_ret_key_data(sp, &princ->key_data[i]); } if (mask & KADM5_TL_DATA) { - krb5_ret_int32(sp, &tmp); + CHECK(krb5_ret_int32(sp, &tmp)); princ->n_tl_data = tmp; princ->tl_data = NULL; for(i = 0; i < princ->n_tl_data; i++){ krb5_tl_data *tp = malloc(sizeof(*tp)); - if (tp == NULL) - return ENOMEM; - kadm5_ret_tl_data(sp, tp); - tp->tl_data_next = princ->tl_data; - princ->tl_data = tp; + if (tp == NULL) { + ret = ENOMEM; + goto out; + } + ret = kadm5_ret_tl_data(sp, tp); + if (ret == 0) { + tp->tl_data_next = princ->tl_data; + princ->tl_data = tp; + } else { + free(tp); + goto out; + } } } - return 0; + +out: + /* Can't free princ here -- we don't have a context */ + return ret; } kadm5_ret_t @@ -367,9 +415,14 @@ kadm5_ret_principal_ent_mask(krb5_storage *sp, kadm5_principal_ent_t princ, uint32_t *mask) { + kadm5_ret_t ret; int32_t tmp; - krb5_ret_int32 (sp, &tmp); + ret = krb5_ret_int32 (sp, &tmp); + if (ret) { + *mask = 0; + return ret; + } *mask = tmp; return ret_principal_ent (sp, princ, *mask); } @@ -379,18 +432,19 @@ _kadm5_marshal_params(krb5_context context, kadm5_config_params *params, krb5_data *out) { + kadm5_ret_t ret; + krb5_storage *sp = krb5_storage_emem(); if (sp == NULL) return krb5_enomem(context); - krb5_store_int32(sp, params->mask & (KADM5_CONFIG_REALM)); - - if(params->mask & KADM5_CONFIG_REALM) - krb5_store_string(sp, params->realm); - krb5_storage_to_data(sp, out); + ret = krb5_store_int32(sp, params->mask & (KADM5_CONFIG_REALM)); + if (ret == 0 && (params->mask & KADM5_CONFIG_REALM)) + ret = krb5_store_string(sp, params->realm); + if (ret == 0) + ret = krb5_storage_to_data(sp, out); krb5_storage_free(sp); - - return 0; + return ret; } kadm5_ret_t @@ -398,7 +452,7 @@ _kadm5_unmarshal_params(krb5_context context, krb5_data *in, kadm5_config_params *params) { - krb5_error_code ret; + kadm5_ret_t ret; krb5_storage *sp; int32_t mask; diff --git a/third_party/heimdal/lib/kadm5/modify_s.c b/third_party/heimdal/lib/kadm5/modify_s.c index cb2e1fd1deca..2159caf5517c 100644 --- a/third_party/heimdal/lib/kadm5/modify_s.c +++ b/third_party/heimdal/lib/kadm5/modify_s.c @@ -97,7 +97,7 @@ modify_principal(void *server_handle, uint32_t forbidden_mask) { kadm5_server_context *context = server_handle; - hdb_entry_ex ent; + hdb_entry ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); @@ -139,7 +139,7 @@ modify_principal(void *server_handle, ret = _kadm5_setup_entry(context, &ent, mask, princ, mask, NULL, 0); if (ret) goto out3; - ret = _kadm5_set_modifier(context, &ent.entry); + ret = _kadm5_set_modifier(context, &ent); if (ret) goto out3; @@ -157,7 +157,7 @@ modify_principal(void *server_handle, goto out3; } - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out3; @@ -174,21 +174,21 @@ modify_principal(void *server_handle, goto out3; } /* This calls free_HDB_extension(), freeing ext.data.u.policy */ - ret = hdb_replace_extension(context->context, &ent.entry, &ext); + ret = hdb_replace_extension(context->context, &ent, &ext); free(ext.data.u.policy); if (ret) goto out3; } /* This logs the change for iprop and writes to the HDB */ - ret = kadm5_log_modify(context, &ent.entry, + ret = kadm5_log_modify(context, &ent, mask | KADM5_MOD_NAME | KADM5_MOD_TIME); (void) modify_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, princ, mask); out3: - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); out2: (void) kadm5_log_end(context); out: diff --git a/third_party/heimdal/lib/kadm5/prune_s.c b/third_party/heimdal/lib/kadm5/prune_s.c index e5d77f6cfd74..96133f242a9f 100644 --- a/third_party/heimdal/lib/kadm5/prune_s.c +++ b/third_party/heimdal/lib/kadm5/prune_s.c @@ -95,7 +95,7 @@ kadm5_s_prune_principal(void *server_handle, int kvno) { kadm5_server_context *context = server_handle; - hdb_entry_ex ent; + hdb_entry ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); @@ -121,21 +121,21 @@ kadm5_s_prune_principal(void *server_handle, if (ret) goto out3; - ret = hdb_prune_keys_kvno(context->context, &ent.entry, kvno); + ret = hdb_prune_keys_kvno(context->context, &ent, kvno); if (ret) goto out3; - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out3; - ret = kadm5_log_modify(context, &ent.entry, KADM5_KEY_DATA); + ret = kadm5_log_modify(context, &ent, KADM5_KEY_DATA); (void) prune_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, princ, kvno); out3: - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); out2: (void) kadm5_log_end(context); out: diff --git a/third_party/heimdal/lib/kadm5/randkey_c.c b/third_party/heimdal/lib/kadm5/randkey_c.c index ace0687613c3..cb0ec86ae570 100644 --- a/third_party/heimdal/lib/kadm5/randkey_c.c +++ b/third_party/heimdal/lib/kadm5/randkey_c.c @@ -93,7 +93,7 @@ kadm5_c_randkey_principal(void *server_handle, for (i = 0; ret == 0 && i < n_ks_tuple; i++) { ret = krb5_store_int32(sp, ks_tuple[i].ks_enctype); if (ret == 0) - krb5_store_int32(sp, ks_tuple[i].ks_salttype); + ret = krb5_store_int32(sp, ks_tuple[i].ks_salttype); } /* Future extensions go here */ if (ret) diff --git a/third_party/heimdal/lib/kadm5/randkey_s.c b/third_party/heimdal/lib/kadm5/randkey_s.c index 9bb83cd14a14..cb3696720f91 100644 --- a/third_party/heimdal/lib/kadm5/randkey_s.c +++ b/third_party/heimdal/lib/kadm5/randkey_s.c @@ -102,7 +102,7 @@ kadm5_s_randkey_principal(void *server_handle, int *n_keys) { kadm5_server_context *context = server_handle; - hdb_entry_ex ent; + hdb_entry ent; kadm5_ret_t ret; size_t i; @@ -129,36 +129,36 @@ kadm5_s_randkey_principal(void *server_handle, goto out3; if (keepold) { - ret = hdb_add_current_keys_to_history(context->context, &ent.entry); + ret = hdb_add_current_keys_to_history(context->context, &ent); if (ret == 0 && keepold == 1) - ret = hdb_prune_keys_kvno(context->context, &ent.entry, 0); + ret = hdb_prune_keys_kvno(context->context, &ent, 0); if (ret) goto out3; } else { /* Remove all key history */ - ret = hdb_clear_extension(context->context, &ent.entry, + ret = hdb_clear_extension(context->context, &ent, choice_HDB_extension_data_hist_keys); if (ret) goto out3; } - ret = _kadm5_set_keys_randomly(context, &ent.entry, n_ks_tuple, ks_tuple, + ret = _kadm5_set_keys_randomly(context, &ent, n_ks_tuple, ks_tuple, new_keys, n_keys); if (ret) goto out3; - ent.entry.kvno++; + ent.kvno++; - ent.entry.flags.require_pwchange = 0; + ent.flags.require_pwchange = 0; - ret = _kadm5_set_modifier(context, &ent.entry); + ret = _kadm5_set_modifier(context, &ent); if(ret) goto out4; - ret = _kadm5_bump_pw_expire(context, &ent.entry); + ret = _kadm5_bump_pw_expire(context, &ent); if (ret) goto out4; if (keepold) { - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out4; } else { @@ -169,11 +169,11 @@ kadm5_s_randkey_principal(void *server_handle, ext.data.element = choice_HDB_extension_data_hist_keys; ext.data.u.hist_keys.len = 0; ext.data.u.hist_keys.val = NULL; - hdb_replace_extension(context->context, &ent.entry, &ext); + hdb_replace_extension(context->context, &ent, &ext); } /* This logs the change for iprop and writes to the HDB */ - ret = kadm5_log_modify(context, &ent.entry, + ret = kadm5_log_modify(context, &ent, KADM5_ATTRIBUTES | KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | @@ -190,7 +190,7 @@ kadm5_s_randkey_principal(void *server_handle, *n_keys = 0; } out3: - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); out2: (void) kadm5_log_end(context); out: diff --git a/third_party/heimdal/lib/kadm5/rename_s.c b/third_party/heimdal/lib/kadm5/rename_s.c index 1052042af05a..9143318176b7 100644 --- a/third_party/heimdal/lib/kadm5/rename_s.c +++ b/third_party/heimdal/lib/kadm5/rename_s.c @@ -97,7 +97,7 @@ kadm5_s_rename_principal(void *server_handle, { kadm5_server_context *context = server_handle; kadm5_ret_t ret; - hdb_entry_ex ent; + hdb_entry ent; krb5_principal oldname; size_t i; @@ -121,14 +121,14 @@ kadm5_s_rename_principal(void *server_handle, 0, &ent); if (ret) goto out2; - oldname = ent.entry.principal; + oldname = ent.principal; ret = rename_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, 0, source, target); if (ret) goto out3; - ret = _kadm5_set_modifier(context, &ent.entry); + ret = _kadm5_set_modifier(context, &ent); if (ret) goto out3; { @@ -136,17 +136,19 @@ kadm5_s_rename_principal(void *server_handle, Salt salt; krb5_salt salt2; memset(&salt, 0, sizeof(salt)); - krb5_get_pw_salt(context->context, source, &salt2); + ret = krb5_get_pw_salt(context->context, source, &salt2); + if (ret) + goto out3; salt.type = hdb_pw_salt; salt.salt = salt2.saltvalue; - for(i = 0; i < ent.entry.keys.len; i++){ - if(ent.entry.keys.val[i].salt == NULL){ - ent.entry.keys.val[i].salt = - malloc(sizeof(*ent.entry.keys.val[i].salt)); - if (ent.entry.keys.val[i].salt == NULL) + for(i = 0; i < ent.keys.len; i++){ + if(ent.keys.val[i].salt == NULL){ + ent.keys.val[i].salt = + malloc(sizeof(*ent.keys.val[i].salt)); + if (ent.keys.val[i].salt == NULL) ret = krb5_enomem(context->context); else - ret = copy_Salt(&salt, ent.entry.keys.val[i].salt); + ret = copy_Salt(&salt, ent.keys.val[i].salt); if (ret) break; } @@ -157,20 +159,20 @@ kadm5_s_rename_principal(void *server_handle, goto out3; /* Borrow target */ - ent.entry.principal = target; - ret = hdb_seal_keys(context->context, context->db, &ent.entry); + ent.principal = target; + ret = hdb_seal_keys(context->context, context->db, &ent); if (ret) goto out3; /* This logs the change for iprop and writes to the HDB */ - ret = kadm5_log_rename(context, source, &ent.entry); + ret = kadm5_log_rename(context, source, &ent); (void) rename_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, source, target); out3: - ent.entry.principal = oldname; /* Unborrow target */ - hdb_free_entry(context->context, &ent); + ent.principal = oldname; /* Unborrow target */ + hdb_free_entry(context->context, context->db, &ent); out2: (void) kadm5_log_end(context); diff --git a/third_party/heimdal/lib/kadm5/set_keys.c b/third_party/heimdal/lib/kadm5/set_keys.c index 1f458258592f..c30c5d829347 100644 --- a/third_party/heimdal/lib/kadm5/set_keys.c +++ b/third_party/heimdal/lib/kadm5/set_keys.c @@ -177,6 +177,8 @@ _kadm5_set_keys2(kadm5_server_context *context, /* A current key; add to current key set */ setup_Key(&key, &salt, key_data, i); ret = add_Keys(&keys, &key); + if (ret) + goto out; continue; } diff --git a/third_party/heimdal/lib/kadm5/setkey3_s.c b/third_party/heimdal/lib/kadm5/setkey3_s.c index 2f8eda54c093..584c194dd183 100644 --- a/third_party/heimdal/lib/kadm5/setkey3_s.c +++ b/third_party/heimdal/lib/kadm5/setkey3_s.c @@ -115,7 +115,7 @@ kadm5_s_setkey_principal_3(void *server_handle, krb5_keyblock *keyblocks, int n_keys) { kadm5_server_context *context = server_handle; - hdb_entry_ex ent; + hdb_entry ent; kadm5_ret_t ret = 0; size_t i; @@ -154,9 +154,9 @@ kadm5_s_setkey_principal_3(void *server_handle, } if (keepold) { - ret = hdb_add_current_keys_to_history(context->context, &ent.entry); + ret = hdb_add_current_keys_to_history(context->context, &ent); } else - ret = hdb_clear_extension(context->context, &ent.entry, + ret = hdb_clear_extension(context->context, &ent, choice_HDB_extension_data_hist_keys); /* @@ -167,7 +167,7 @@ kadm5_s_setkey_principal_3(void *server_handle, * each ks_tuple's enctype matches the corresponding key enctype. */ if (ret == 0) { - free_Keys(&ent.entry.keys); + free_Keys(&ent.keys); for (i = 0; i < n_keys; ++i) { Key k; Salt s; @@ -186,22 +186,22 @@ kadm5_s_setkey_principal_3(void *server_handle, s.opaque = 0; k.salt = &s; } - if ((ret = add_Keys(&ent.entry.keys, &k)) != 0) + if ((ret = add_Keys(&ent.keys, &k)) != 0) break; } } if (ret == 0) { - ent.entry.kvno++; - ent.entry.flags.require_pwchange = 0; - hdb_entry_set_pw_change_time(context->context, &ent.entry, 0); - hdb_entry_clear_password(context->context, &ent.entry); + ent.kvno++; + ent.flags.require_pwchange = 0; + hdb_entry_set_pw_change_time(context->context, &ent, 0); + hdb_entry_clear_password(context->context, &ent); if ((ret = hdb_seal_keys(context->context, context->db, - &ent.entry)) == 0 - && (ret = _kadm5_set_modifier(context, &ent.entry)) == 0 - && (ret = _kadm5_bump_pw_expire(context, &ent.entry)) == 0) - ret = kadm5_log_modify(context, &ent.entry, + &ent)) == 0 + && (ret = _kadm5_set_modifier(context, &ent)) == 0 + && (ret = _kadm5_bump_pw_expire(context, &ent)) == 0) + ret = kadm5_log_modify(context, &ent, KADM5_ATTRIBUTES | KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | @@ -212,7 +212,7 @@ kadm5_s_setkey_principal_3(void *server_handle, princ, keepold, n_ks_tuple, ks_tuple, n_keys, keyblocks); - hdb_free_entry(context->context, &ent); + hdb_free_entry(context->context, context->db, &ent); (void) kadm5_log_end(context); if (!context->keep_open) context->db->hdb_close(context->context, context->db); diff --git a/third_party/heimdal/lib/kafs/Makefile.am b/third_party/heimdal/lib/kafs/Makefile.am index dd23aef7665a..50d4878ae6cd 100644 --- a/third_party/heimdal/lib/kafs/Makefile.am +++ b/third_party/heimdal/lib/kafs/Makefile.am @@ -2,6 +2,8 @@ include $(top_srcdir)/Makefile.am.common +WFLAGS += $(WFLAGS_ENUM_CONV) + AM_CPPFLAGS += $(AFS_EXTRA_DEFS) $(ROKEN_RENAME) if KRB5 diff --git a/third_party/heimdal/lib/kafs/afskrb5.c b/third_party/heimdal/lib/kafs/afskrb5.c index 6033f2958b45..0077016f6242 100644 --- a/third_party/heimdal/lib/kafs/afskrb5.c +++ b/third_party/heimdal/lib/kafs/afskrb5.c @@ -85,8 +85,6 @@ v5_to_kt(krb5_creds *cred, uid_t uid, struct kafs_token *kt, int local524) return ENOMEM; kt->ticket_len = cred->ticket.length; memcpy(kt->ticket, cred->ticket.data, kt->ticket_len); - - ret = 0; } diff --git a/third_party/heimdal/lib/kafs/afssys.c b/third_party/heimdal/lib/kafs/afssys.c index ae33ff182994..b400626075ce 100644 --- a/third_party/heimdal/lib/kafs/afssys.c +++ b/third_party/heimdal/lib/kafs/afssys.c @@ -106,7 +106,9 @@ int _kafs_debug; /* this should be done in a better way */ #define SUN_PROC_POINT 8 static int afs_entry_point = UNKNOWN_ENTRY_POINT; +#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) || defined(AFS_PIOCTL) static int afs_syscalls[2]; +#endif static char *afs_ioctlpath; static unsigned long afs_ioctlnum; diff --git a/third_party/heimdal/lib/kafs/rxkad_kdf.c b/third_party/heimdal/lib/kafs/rxkad_kdf.c index 174fa3a6189a..5af391ed99b5 100644 --- a/third_party/heimdal/lib/kafs/rxkad_kdf.c +++ b/third_party/heimdal/lib/kafs/rxkad_kdf.c @@ -89,12 +89,16 @@ rxkad_derive_des_key(const void *in, size_t insize, char out[8]) /* stop when 8 bit counter wraps to 0 */ for (i = 1; i; i++) { HMAC_CTX_init(&mctx); - HMAC_Init_ex(&mctx, in, insize, EVP_md5(), NULL); + if (HMAC_Init_ex(&mctx, in, insize, EVP_md5(), NULL) == 0) { + HMAC_CTX_cleanup(&mctx); + return ENOMEM; + } HMAC_Update(&mctx, &i, 1); HMAC_Update(&mctx, label, sizeof(label)); /* includes label and separator */ HMAC_Update(&mctx, Lbuf, 4); mdsize = sizeof(tmp); HMAC_Final(&mctx, tmp, &mdsize); + HMAC_CTX_cleanup(&mctx); memcpy(ktmp, tmp, 8); DES_set_odd_parity(&ktmp); if (!DES_is_weak_key(&ktmp)) { @@ -205,7 +209,7 @@ _kafs_derive_des_key(krb5_enctype enctype, void *keydata, size_t keylen, ret = compress_parity_bits(keydata, &keylen); if (ret) return ret; - /* FALLTHROUGH */ + fallthrough; default: if (enctype < 0) return KRB5_PROG_ETYPE_NOSUPP; diff --git a/third_party/heimdal/lib/krb5/Makefile.am b/third_party/heimdal/lib/krb5/Makefile.am index 99171e727ce8..c1345c28a5ab 100644 --- a/third_party/heimdal/lib/krb5/Makefile.am +++ b/third_party/heimdal/lib/krb5/Makefile.am @@ -2,7 +2,9 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += -I../com_err -I$(srcdir)/../com_err $(INCLUDE_sqlite3) $(INCLUDE_libintl) $(INCLUDE_openssl_crypto) +WFLAGS += $(WFLAGS_ENUM_CONV) + +AM_CPPFLAGS += -I../com_err -I$(srcdir)/../com_err -I../base -I$(srcdir)/../base $(INCLUDE_sqlite3) $(INCLUDE_libintl) $(INCLUDE_openssl_crypto) bin_PROGRAMS = verify_krb5_conf diff --git a/third_party/heimdal/lib/krb5/NTMakefile b/third_party/heimdal/lib/krb5/NTMakefile index d32025130989..40ca0fb0bccc 100644 --- a/third_party/heimdal/lib/krb5/NTMakefile +++ b/third_party/heimdal/lib/krb5/NTMakefile @@ -31,6 +31,8 @@ RELDIR=lib\krb5 +intcflags=-I$(SRCDIR) -I$(SRCDIR)\..\com_err -I$(SRCDIR)\..\base + !include ../../windows/NTMakefile.w32 libkrb5_OBJS = \ diff --git a/third_party/heimdal/lib/krb5/acache.c b/third_party/heimdal/lib/krb5/acache.c index 5bc976263245..63d56c400bf5 100644 --- a/third_party/heimdal/lib/krb5/acache.c +++ b/third_party/heimdal/lib/krb5/acache.c @@ -121,10 +121,9 @@ init_ccapi(krb5_context context) if (cc_handle == NULL) { HEIMDAL_MUTEX_unlock(&acc_mutex); - if (context) - krb5_set_error_message(context, KRB5_CC_NOSUPP, - N_("Failed to load API cache module %s", "file"), - lib); + krb5_set_error_message(context, KRB5_CC_NOSUPP, + N_("Failed to load API cache module %s", "file"), + lib); return KRB5_CC_NOSUPP; } @@ -135,10 +134,9 @@ init_ccapi(krb5_context context) dlsym(cc_handle, "krb5_ipc_client_clear_target"); HEIMDAL_MUTEX_unlock(&acc_mutex); if (init_func == NULL) { - if (context) - krb5_set_error_message(context, KRB5_CC_NOSUPP, - N_("Failed to find cc_initialize" - "in %s: %s", "file, error"), lib, dlerror()); + krb5_set_error_message(context, KRB5_CC_NOSUPP, + N_("Failed to find cc_initialize" + "in %s: %s", "file, error"), lib, dlerror()); dlclose(cc_handle); return KRB5_CC_NOSUPP; } @@ -146,9 +144,8 @@ init_ccapi(krb5_context context) return 0; #else HEIMDAL_MUTEX_unlock(&acc_mutex); - if (context) - krb5_set_error_message(context, KRB5_CC_NOSUPP, - N_("no support for shared object", "")); + krb5_set_error_message(context, KRB5_CC_NOSUPP, + N_("no support for shared object", "")); return KRB5_CC_NOSUPP; #endif } @@ -988,6 +985,7 @@ acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) static krb5_error_code KRB5_CALLCONV acc_move(krb5_context context, krb5_ccache from, krb5_ccache to) { + krb5_error_code ret; krb5_acc *afrom = ACACHE(from); krb5_acc *ato = ACACHE(to); int32_t error; @@ -1011,9 +1009,10 @@ acc_move(krb5_context context, krb5_ccache from, krb5_ccache to) } error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache); - - krb5_cc_destroy(context, from); - return translate_cc_error(context, error); + ret = translate_cc_error(context, error); + if (ret == 0) + krb5_cc_destroy(context, from); + return ret; } static krb5_error_code KRB5_CALLCONV diff --git a/third_party/heimdal/lib/krb5/acl.c b/third_party/heimdal/lib/krb5/acl.c index b53c179b72ed..d3196148287e 100644 --- a/third_party/heimdal/lib/krb5/acl.c +++ b/third_party/heimdal/lib/krb5/acl.c @@ -246,7 +246,7 @@ krb5_acl_match_file(krb5_context context, ...) { krb5_error_code ret; - struct acl_field *acl; + struct acl_field *acl = NULL; char buf[256]; va_list ap; FILE *f; diff --git a/third_party/heimdal/lib/krb5/addr_families.c b/third_party/heimdal/lib/krb5/addr_families.c index 4d235fff4318..864c9cde8845 100644 --- a/third_party/heimdal/lib/krb5/addr_families.c +++ b/third_party/heimdal/lib/krb5/addr_families.c @@ -525,7 +525,7 @@ arange_parse_addr (krb5_context context, return ret; } - if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) { + if(high.len != 1 || high.val[0].addr_type != low.val[0].addr_type) { krb5_free_addresses(context, &low); krb5_free_addresses(context, &high); return -1; @@ -543,7 +543,13 @@ arange_parse_addr (krb5_context context, return ret; } - krb5_data_alloc(&addr->address, sizeof(*a)); + ret = krb5_data_alloc(&addr->address, sizeof(*a)); + if (ret) { + krb5_free_address(context, &low0); + krb5_free_address(context, &high0); + return ret; + } + addr->addr_type = KRB5_ADDRESS_ARANGE; a = addr->address.data; @@ -1208,7 +1214,7 @@ krb5_parse_address(krb5_context context, if (error) { krb5_error_code ret2; save_errno = errno; - ret2 = krb5_eai_to_heim_errno(error, save_errno); + ret2 = krb5_eai_to_heim_errno(save_errno, error); krb5_set_error_message (context, ret2, "%s: %s", string, gai_strerror(error)); return ret2; @@ -1377,12 +1383,7 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_free_addresses(krb5_context context, krb5_addresses *addresses) { - size_t i; - for(i = 0; i < addresses->len; i++) - krb5_free_address(context, &addresses->val[i]); - free(addresses->val); - addresses->len = 0; - addresses->val = NULL; + free_HostAddresses(addresses); return 0; } diff --git a/third_party/heimdal/lib/krb5/aes-test.c b/third_party/heimdal/lib/krb5/aes-test.c index 7bca78ab6068..01522dd593ab 100644 --- a/third_party/heimdal/lib/krb5/aes-test.c +++ b/third_party/heimdal/lib/krb5/aes-test.c @@ -754,6 +754,9 @@ krb_enc_test(krb5_context context) kb.keyvalue.data = krbencs[i].key; ret = krb5_crypto_init(context, &kb, krbencs[i].enctype, &crypto); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_init failed with %d for test %d", + ret, i); cipher.length = krbencs[i].elen; cipher.data = krbencs[i].edata; @@ -763,20 +766,24 @@ krb_enc_test(krb5_context context) ret = krb_enc(context, crypto, krbencs[i].usage, &cipher, &plain); if (ret) - errx(1, "krb_enc failed with %d for test %d", ret, i); + krb5_err(context, 1, ret, "krb_enc failed with %d for test %d", + ret, i); ret = krb_enc_iov(context, crypto, krbencs[i].usage, &cipher, &plain); if (ret) - errx(1, "krb_enc_iov failed with %d for test %d", ret, i); + krb5_err(context, 1, ret, "krb_enc_iov failed with %d for test %d", + ret, i); ret = krb_enc_iov2(context, crypto, krbencs[i].usage, cipher.length, &plain); if (ret) - errx(1, "krb_enc_iov2 failed with %d for test %d", ret, i); + krb5_err(context, 1, ret, "krb_enc_iov2 failed with %d for test %d", + ret, i); ret = krb_checksum_iov(context, crypto, krbencs[i].usage, &plain, NULL); if (ret) - errx(1, "krb_checksum_iov failed with %d for test %d", ret, i); + krb5_err(context, 1, ret, + "krb_checksum_iov failed with %d for test %d", ret, i); if (krbencs[i].cdata) { krb5_data checksum; @@ -787,7 +794,9 @@ krb_enc_test(krb5_context context) ret = krb_checksum_iov(context, crypto, krbencs[i].usage, &plain, &checksum); if (ret) - errx(1, "krb_checksum_iov(2) failed with %d for test %d", ret, i); + krb5_err(context, 1, ret, + "krb_checksum_iov(2) failed with %d for test %d", + ret, i); } krb5_crypto_destroy(context, crypto); @@ -795,7 +804,8 @@ krb_enc_test(krb5_context context) ret = krb_enc_mit(context, krbencs[i].enctype, &kb, krbencs[i].usage, &cipher, &plain); if (ret) - errx(1, "krb_enc_mit failed with %d for test %d", ret, i); + krb5_err(context, 1, ret, "krb_enc_mit failed with %d for test %d", + ret, i); } return 0; diff --git a/third_party/heimdal/lib/krb5/asn1_glue.c b/third_party/heimdal/lib/krb5/asn1_glue.c index 6df8defbce9a..16eda2f6f73d 100644 --- a/third_party/heimdal/lib/krb5/asn1_glue.c +++ b/third_party/heimdal/lib/krb5/asn1_glue.c @@ -38,8 +38,8 @@ #include "krb5_locl.h" KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -_krb5_principal2principalname (PrincipalName *p, - const krb5_principal from) +_krb5_principal2principalname(PrincipalName *p, + krb5_const_principal from) { return copy_PrincipalName(&from->name, p); } @@ -70,3 +70,93 @@ _krb5_principalname2krb5_principal (krb5_context context, *principal = p; return 0; } + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_ticket2krb5_principal(krb5_context context, + krb5_principal *principal, + const EncTicketPart *ticket, + const AuthorizationData *authenticator_ad) +{ + krb5_error_code ret; + krb5_principal p = NULL; + + *principal = NULL; + + ret = _krb5_principalname2krb5_principal(context, + &p, + ticket->cname, + ticket->crealm); + if (ret == 0 && + (p->nameattrs = calloc(1, sizeof(p->nameattrs[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) + p->nameattrs->authenticated = 1; + if (ret == 0 && + (p->nameattrs->source = + calloc(1, sizeof(p->nameattrs->source[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) { + p->nameattrs->source->element = + choice_PrincipalNameAttrSrc_enc_ticket_part; + ret = copy_EncTicketPart(ticket, + &p->nameattrs->source->u.enc_ticket_part); + /* NOTE: we don't want to keep a copy of the session key here! */ + if (ret == 0) + der_free_octet_string(&p->nameattrs->source->u.enc_ticket_part.key.keyvalue); + } + if (ret == 0 && authenticator_ad) { + p->nameattrs->authenticator_ad = + calloc(1, sizeof(p->nameattrs->authenticator_ad[0])); + if (p->nameattrs->authenticator_ad == NULL) + ret = krb5_enomem(context); + if (ret == 0) + ret = copy_AuthorizationData(authenticator_ad, + p->nameattrs->authenticator_ad); + } + + if (ret == 0) + *principal = p; + else + krb5_free_principal(context, p); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kdcrep2krb5_principal(krb5_context context, + krb5_principal *principal, + const EncKDCRepPart *kdcrep) +{ + krb5_error_code ret; + krb5_principal p = NULL; + + *principal = NULL; + + ret = _krb5_principalname2krb5_principal(context, + &p, + kdcrep->sname, + kdcrep->srealm); + if (ret == 0 && + (p->nameattrs = calloc(1, sizeof(p->nameattrs[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) + p->nameattrs->authenticated = 1; + if (ret == 0 && + (p->nameattrs->source = + calloc(1, sizeof(p->nameattrs->source[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) { + p->nameattrs->source->element = + choice_PrincipalNameAttrSrc_enc_kdc_rep_part; + ret = copy_EncKDCRepPart(kdcrep, + &p->nameattrs->source->u.enc_kdc_rep_part); + /* NOTE: we don't want to keep a copy of the session key here! */ + if (ret == 0) + der_free_octet_string(&p->nameattrs->source->u.enc_kdc_rep_part.key.keyvalue); + } + + if (ret == 0) + *principal = p; + else + krb5_free_principal(context, p); + return ret; +} diff --git a/third_party/heimdal/lib/krb5/auth_context.c b/third_party/heimdal/lib/krb5/auth_context.c index 43c762b7699b..8b43b63706c9 100644 --- a/third_party/heimdal/lib/krb5/auth_context.c +++ b/third_party/heimdal/lib/krb5/auth_context.c @@ -557,9 +557,8 @@ krb5_auth_con_getauthenticator(krb5_context context, if (*authenticator == NULL) return krb5_enomem(context); - copy_Authenticator(auth_context->authenticator, - *authenticator); - return 0; + return copy_Authenticator(auth_context->authenticator, + *authenticator); } diff --git a/third_party/heimdal/lib/krb5/cache.c b/third_party/heimdal/lib/krb5/cache.c index 1920796ffc3c..75083f828408 100644 --- a/third_party/heimdal/lib/krb5/cache.c +++ b/third_party/heimdal/lib/krb5/cache.c @@ -514,7 +514,7 @@ krb5_cc_get_subsidiary(krb5_context context, krb5_ccache id) const char *name = NULL; if (id->ops->version >= KRB5_CC_OPS_VERSION_5 - && id->ops->get_name_2 == NULL) + && id->ops->get_name_2 != NULL) (void) id->ops->get_name_2(context, id, NULL, NULL, &name); return name; } @@ -822,6 +822,17 @@ krb5_cc_configured_default_name(krb5_context context) return context->configured_default_cc_name = expanded; } +KRB5_LIB_FUNCTION char * KRB5_LIB_CALL +krb5_cccol_get_default_ccname(krb5_context context) +{ + const char *cfg = get_default_cc_type(context, 1); + char *cccol_default_ccname; + const krb5_cc_ops *ops = krb5_cc_get_prefix_ops(context, cfg); + + (void) (*ops->get_default_name)(context, &cccol_default_ccname); + return cccol_default_ccname; +} + /** * Open the default ccache in `id'. * @@ -923,7 +934,7 @@ krb5_cc_destroy(krb5_context context, /* * Destroy associated hx509 PKIX credential store created by krb5_kx509*(). */ - if ((ret = krb5_cc_get_config(context, id, NULL, "kx509store", &d)) == 0) { + if (krb5_cc_get_config(context, id, NULL, "kx509store", &d) == 0) { char *name; if ((name = strndup(d.data, d.length)) == NULL) { @@ -1001,7 +1012,6 @@ krb5_cc_close(krb5_context context, _krb5_debug(context, 2, "failed to fetch a certificate"); else _krb5_debug(context, 2, "fetched a certificate"); - ret = 0; } } @@ -1607,8 +1617,7 @@ krb5_cc_cache_match (krb5_context context, } else if (cache == NULL) { char *str; - krb5_unparse_name(context, client, &str); - + (void) krb5_unparse_name(context, client, &str); krb5_set_error_message(context, KRB5_CC_NOTFOUND, N_("Principal %s not found in any " "credential cache", ""), @@ -1653,7 +1662,8 @@ krb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to) ret = (*to->ops->move)(context, from, to); if (ret == 0) return 0; - if (ret != EXDEV && ret != ENOTSUP) + if (ret != EXDEV && ret != ENOTSUP && ret != KRB5_CC_NOSUPP && + ret != KRB5_FCC_INTERNAL) return ret; /* Fallback to high-level copy */ } /* Else high-level copy */ @@ -1766,7 +1776,8 @@ krb5_cc_set_config(krb5_context context, krb5_ccache id, /* Remove old configuration */ ret = krb5_cc_remove_cred(context, id, 0, &cred); - if (ret && ret != KRB5_CC_NOTFOUND) + if (ret && ret != KRB5_CC_NOTFOUND && ret != KRB5_CC_NOSUPP && + ret != KRB5_FCC_INTERNAL) goto out; if (data) { diff --git a/third_party/heimdal/lib/krb5/context.c b/third_party/heimdal/lib/krb5/context.c index 51faf8de99d6..4040a983518e 100644 --- a/third_party/heimdal/lib/krb5/context.c +++ b/third_party/heimdal/lib/krb5/context.c @@ -106,7 +106,7 @@ init_context_from_config_file(krb5_context context) krb5_error_code ret; const char * tmp; char **s; - krb5_enctype *tmptypes; + krb5_enctype *tmptypes = NULL; INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew"); INIT_FIELD(context, time, kdc_timeout, 30, "kdc_timeout"); @@ -246,10 +246,10 @@ init_context_from_config_file(krb5_context context) if (context->flags & KRB5_CTX_F_REPORT_CANONICAL_CLIENT_NAME) context->flags |= KRB5_CTX_F_CHECK_PAC; - if (context->default_cc_name) - free(context->default_cc_name); + free(context->default_cc_name); context->default_cc_name = NULL; context->default_cc_name_set = 0; + free(context->configured_default_cc_name); context->configured_default_cc_name = NULL; tmp = secure_getenv("KRB5_TRACE"); @@ -646,12 +646,9 @@ KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_free_context(krb5_context context) { _krb5_free_name_canon_rules(context, context->name_canon_rules); - if (context->default_cc_name) - free(context->default_cc_name); - if (context->default_cc_name_env) - free(context->default_cc_name_env); - if (context->configured_default_cc_name) - free(context->configured_default_cc_name); + free(context->default_cc_name); + free(context->default_cc_name_env); + free(context->configured_default_cc_name); free(context->etypes); free(context->cfg_etypes); free(context->etypes_des); diff --git a/third_party/heimdal/lib/krb5/crypto-evp.c b/third_party/heimdal/lib/krb5/crypto-evp.c index a16b83cb0e07..a03cdca2ebc1 100644 --- a/third_party/heimdal/lib/krb5/crypto-evp.c +++ b/third_party/heimdal/lib/krb5/crypto-evp.c @@ -137,8 +137,11 @@ _krb5_evp_hmac_iov(krb5_context context, if (ctx == NULL) return krb5_enomem(context); - HMAC_Init_ex(ctx, key->key->keyvalue.data, key->key->keyvalue.length, - md, engine); + if (HMAC_Init_ex(ctx, key->key->keyvalue.data, key->key->keyvalue.length, + md, engine) == 0) { + HMAC_CTX_free(ctx); + return krb5_enomem(context); + } for (i = 0; i < niov; i++) { if (_krb5_crypto_iov_should_sign(&iov[i])) { diff --git a/third_party/heimdal/lib/krb5/crypto.c b/third_party/heimdal/lib/krb5/crypto.c index 524b2e78681d..2fb4f0620f76 100644 --- a/third_party/heimdal/lib/krb5/crypto.c +++ b/third_party/heimdal/lib/krb5/crypto.c @@ -2152,7 +2152,10 @@ krb5_crypto_length(krb5_context context, *len = 0; return 0; case KRB5_CRYPTO_TYPE_TRAILER: - *len = CHECKSUMSIZE(crypto->et->keyed_checksum); + if (crypto->et->keyed_checksum) + *len = CHECKSUMSIZE(crypto->et->keyed_checksum); + else + *len = 0; return 0; case KRB5_CRYPTO_TYPE_CHECKSUM: if (crypto->et->keyed_checksum) @@ -2572,7 +2575,7 @@ krb5_crypto_init(krb5_context context, ALLOC(*crypto, 1); if (*crypto == NULL) return krb5_enomem(context); - if(etype == (krb5_enctype)ETYPE_NULL) + if(etype == ETYPE_NULL) etype = key->keytype; (*crypto)->et = _krb5_find_enctype(etype); if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) { diff --git a/third_party/heimdal/lib/krb5/data.c b/third_party/heimdal/lib/krb5/data.c index eafc4520b9e0..abfa0531f0ef 100644 --- a/third_party/heimdal/lib/krb5/data.c +++ b/third_party/heimdal/lib/krb5/data.c @@ -200,9 +200,12 @@ krb5_copy_data(krb5_context context, KRB5_LIB_FUNCTION int KRB5_LIB_CALL krb5_data_cmp(const krb5_data *data1, const krb5_data *data2) { - if (data1->length != data2->length) + size_t len = data1->length < data2->length ? data1->length : data2->length; + int cmp = memcmp(data1->data, data2->data, len); + + if (cmp == 0) return data1->length - data2->length; - return memcmp(data1->data, data2->data, data1->length); + return cmp; } /** diff --git a/third_party/heimdal/lib/krb5/dcache.c b/third_party/heimdal/lib/krb5/dcache.c index 22183efcafbe..af88aed91561 100644 --- a/third_party/heimdal/lib/krb5/dcache.c +++ b/third_party/heimdal/lib/krb5/dcache.c @@ -452,7 +452,7 @@ dcc_resolve_2(krb5_context context, /* Strip off extra slashes on the end */ for (len = strlen(dc->dir); len && ISPATHSEP(dc->dir[len - 1]); - len -= len ? 1 : 0) + len--) dc->dir[len - 1] = '\0'; /* If we got here then `dc->dir' and `dc->sub' must both be set */ @@ -676,17 +676,17 @@ dcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) /* Strip off extra slashes on the end */ for (len = strlen(iter->dc->dir); len && ISPATHSEP(iter->dc->dir[len - 1]); - len -= len ? 1 : 0) { + len--) { iter->dc->dir[len - 1] = '\0'; } if ((iter->d = opendir(iter->dc->dir)) == NULL) { - free(iter->dc->dir); - free(iter->dc); - free(iter); krb5_set_error_message(context, KRB5_CC_FORMAT, N_("Can't open DIR %s: %s", ""), iter->dc->dir, strerror(errno)); + free(iter->dc->dir); + free(iter->dc); + free(iter); return KRB5_CC_FORMAT; } @@ -709,8 +709,8 @@ dcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) /* Emit primary subsidiary first */ if (iter->first && - (ret = get_default_cache(context, iter->dc, NULL, &iter->primary)) == 0 && - is_filename_cacheish(iter->primary)) { + get_default_cache(context, iter->dc, NULL, &iter->primary) == 0 && + iter->primary && is_filename_cacheish(iter->primary)) { iter->first = 0; ret = KRB5_CC_END; if (asprintf(&p, "FILE:%s/%s", iter->dc->dir, iter->primary) > -1 && p != NULL && diff --git a/third_party/heimdal/lib/krb5/deprecated.c b/third_party/heimdal/lib/krb5/deprecated.c index bcd07e3c2d83..0efa162702cb 100644 --- a/third_party/heimdal/lib/krb5/deprecated.c +++ b/third_party/heimdal/lib/krb5/deprecated.c @@ -324,15 +324,13 @@ krb5_keytab_key_proc (krb5_context context, ret = krb5_kt_get_entry (context, real_keytab, principal, 0, enctype, &entry); + if (ret == 0) { + ret = krb5_copy_keyblock (context, &entry.keyblock, key); + krb5_kt_free_entry(context, &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; } diff --git a/third_party/heimdal/lib/krb5/enomem.c b/third_party/heimdal/lib/krb5/enomem.c index 371b07ff5833..b4444e5a2cdc 100644 --- a/third_party/heimdal/lib/krb5/enomem.c +++ b/third_party/heimdal/lib/krb5/enomem.c @@ -33,10 +33,10 @@ #include "krb5_locl.h" +#undef krb5_enomem KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_enomem(krb5_context context) { krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } - diff --git a/third_party/heimdal/lib/krb5/error_string.c b/third_party/heimdal/lib/krb5/error_string.c index 0e42f51bc211..da86b375f83c 100644 --- a/third_party/heimdal/lib/krb5/error_string.c +++ b/third_party/heimdal/lib/krb5/error_string.c @@ -95,15 +95,16 @@ krb5_vset_error_message(krb5_context context, krb5_error_code ret, const char *fmt, va_list args) __attribute__ ((__format__ (__printf__, 3, 0))) { - if (context) { - const char *msg; - - heim_vset_error_message(context->hcontext, ret, fmt, args); - msg = heim_get_error_message(context->hcontext, ret); - if (msg) { - _krb5_debug(context, 100, "error message: %s: %d", msg, ret); - heim_free_error_message(context->hcontext, msg); - } + const char *msg; + + if (context == NULL) + return; + + heim_vset_error_message(context->hcontext, ret, fmt, args); + msg = heim_get_error_message(context->hcontext, ret); + if (msg) { + _krb5_debug(context, 100, "error message: %s: %d", msg, ret); + heim_free_error_message(context->hcontext, msg); } } diff --git a/third_party/heimdal/lib/krb5/expand_path.c b/third_party/heimdal/lib/krb5/expand_path.c index a1f4dfcfcf78..a0402350d0f3 100644 --- a/third_party/heimdal/lib/krb5/expand_path.c +++ b/third_party/heimdal/lib/krb5/expand_path.c @@ -55,8 +55,8 @@ _krb5_expand_path_tokens(krb5_context context, int filepath, char **ppath_out) { - return heim_expand_path_tokens(context->hcontext, path_in, filepath, - ppath_out, NULL); + return heim_expand_path_tokens(context ? context->hcontext : NULL, path_in, + filepath, ppath_out, NULL); } /** diff --git a/third_party/heimdal/lib/krb5/fast.c b/third_party/heimdal/lib/krb5/fast.c index dcca7cc5eec3..617446c36342 100644 --- a/third_party/heimdal/lib/krb5/fast.c +++ b/third_party/heimdal/lib/krb5/fast.c @@ -138,6 +138,12 @@ make_local_fast_ap_fxarmor(krb5_context context, krb5_data empty; krb5_const_realm tgs_realm; + if (armor_ccache == NULL) { + krb5_set_error_message(context, EINVAL, + "Armor credential cache required"); + return EINVAL; + } + krb5_data_zero(&empty); memset(&cred, 0, sizeof(cred)); @@ -225,6 +231,8 @@ make_fast_ap_fxarmor(krb5_context context, KrbFastArmor *fxarmor = NULL; krb5_error_code ret; + *armor = NULL; + ALLOC(fxarmor, 1); if (fxarmor == NULL) { ret = ENOMEM; @@ -429,6 +437,7 @@ _krb5_fast_create_armor(krb5_context context, if (state->armor_data) { free_KrbFastArmor(state->armor_data); free(state->armor_data); + state->armor_data = NULL; } ret = make_fast_ap_fxarmor(context, state, realm, &state->armor_data); @@ -539,8 +548,6 @@ _krb5_fast_wrap_req(krb5_context context, if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) { fxreq.u.armored_data.armor = state->armor_data; state->armor_data = NULL; - if (ret) - goto out; heim_assert(state->armor_crypto != NULL, "FAST armor key missing when FAST started"); @@ -850,7 +857,7 @@ _krb5_fast_anon_pkinit_step(krb5_context context, ret = krb5_cc_set_config(context, ccache, cred.server, "fast_avail", &data); - if (ret) + if (ret && ret != KRB5_CC_NOSUPP) return ret; if (_krb5_pk_is_kdc_verified(context, state->anon_pkinit_opt)) diff --git a/third_party/heimdal/lib/krb5/fcache.c b/third_party/heimdal/lib/krb5/fcache.c index 08d4f4217e4c..30dff35893b3 100644 --- a/third_party/heimdal/lib/krb5/fcache.c +++ b/third_party/heimdal/lib/krb5/fcache.c @@ -477,7 +477,6 @@ fcc_open(krb5_context context, return krb5_einval(context, 2); if ((flags & O_EXCL)) { - flags &= ~O_EXCL; /* * FIXME Instead of mkostemp()... we could instead try to use a .new * file... with care. Or the O_TMPFILE / linkat() extensions. We need @@ -1177,7 +1176,7 @@ fcc_remove_cred(krb5_context context, krb5_free_cred_contents(context, &found_cred); } ret2 = krb5_cc_end_seq_get(context, id, &cursor); - if (ret == 0) + if (ret2) /* not expected to fail */ return ret2; if (ret == KRB5_CC_END) return 0; @@ -1548,8 +1547,10 @@ static krb5_error_code KRB5_CALLCONV fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) { krb5_error_code ret = 0; + krb5_fcache *f = FCACHE(from); + krb5_fcache *t = FCACHE(to); - if (TMPFILENAME(from)) { + if (f->tmpfn) { /* * If `from' has a temp file and we haven't renamed it into place yet, * then we should rename TMPFILENAME(from) to FILENAME(to). @@ -1557,13 +1558,13 @@ fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) * This can only happen if we're moving a ccache where only cc config * entries, or no entries, have been written. That's not likely. */ - if (rk_rename(TMPFILENAME(from), FILENAME(to))) { + if (rk_rename(f->tmpfn, t->filename)) { ret = errno; } else { - free(TMPFILENAME(from)); - TMPFILENAME(from) = NULL; + free(f->tmpfn); + f->tmpfn = NULL; } - } else if ((ret = rk_rename(FILENAME(from), FILENAME(to)))) { + } else if (rk_rename(f->filename, t->filename)) { ret = errno; } /* diff --git a/third_party/heimdal/lib/krb5/generate_subkey.c b/third_party/heimdal/lib/krb5/generate_subkey.c index 07047461ee77..767d94cf7fe6 100644 --- a/third_party/heimdal/lib/krb5/generate_subkey.c +++ b/third_party/heimdal/lib/krb5/generate_subkey.c @@ -58,7 +58,7 @@ krb5_generate_subkey_extended(krb5_context context, if (*subkey == NULL) return krb5_enomem(context); - if (etype == (krb5_enctype)ETYPE_NULL) + if (etype == ETYPE_NULL) etype = key->keytype; /* use session key etype */ /* XXX should we use the session key as input to the RF? */ diff --git a/third_party/heimdal/lib/krb5/get_cred.c b/third_party/heimdal/lib/krb5/get_cred.c index 3072cbf5f6bf..ec757797866d 100644 --- a/third_party/heimdal/lib/krb5/get_cred.c +++ b/third_party/heimdal/lib/krb5/get_cred.c @@ -50,7 +50,7 @@ get_cred_kdc_capath(krb5_context, krb5_kdc_flags, static krb5_error_code make_pa_tgs_req(krb5_context context, - krb5_auth_context ac, + krb5_auth_context *ac, KDC_REQ_BODY *body, krb5_ccache ccache, krb5_creds *creds, @@ -71,7 +71,7 @@ make_pa_tgs_req(krb5_context context, in_data.length = len; in_data.data = buf; - ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, + ret = _krb5_mk_req_internal(context, ac, 0, &in_data, creds, tgs_req, KRB5_KU_TGS_REQ_AUTH_CKSUM, KRB5_KU_TGS_REQ_AUTH); @@ -114,19 +114,20 @@ set_auth_data (krb5_context context, req_body->enc_authorization_data = NULL; return ret; } - krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, - buf, - len, - 0, - req_body->enc_authorization_data); + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, + buf, + len, + 0, + req_body->enc_authorization_data); free (buf); krb5_crypto_destroy(context, crypto); + return ret; } else { req_body->enc_authorization_data = NULL; + return 0; } - return 0; } /* @@ -286,7 +287,7 @@ init_tgs_req (krb5_context context, } ret = make_pa_tgs_req(context, - ac, + &ac, &t->req_body, ccache, krbtgt, @@ -516,7 +517,7 @@ get_cred_kdc(krb5_context context, TGS_REQ req; krb5_data enc; krb5_data resp; - krb5_kdc_rep rep = {0}; + krb5_kdc_rep rep; krb5_error_code ret; unsigned nonce; krb5_keyblock *subkey = NULL; @@ -524,6 +525,7 @@ get_cred_kdc(krb5_context context, Ticket second_ticket_data; METHOD_DATA padata; + memset(&rep, 0, sizeof(rep)); krb5_data_zero(&resp); krb5_data_zero(&enc); padata.val = NULL; @@ -777,7 +779,9 @@ get_cred_kdc_address(krb5_context context, "no-addresses", FALSE, &noaddr); if (!noaddr) { - krb5_get_all_client_addrs(context, &addresses); + ret = krb5_get_all_client_addrs(context, &addresses); + if (ret) + return ret; /* XXX this sucks. */ addrs = &addresses; if(addresses.len == 0) @@ -1375,6 +1379,8 @@ _krb5_get_cred_kdc_any(krb5_context context, krb5_deltat offset; krb5_data data; + krb5_data_zero(&data); + /* * If we are using LKDC, lets pull out the addreses from the * ticket and use that. @@ -1382,23 +1388,19 @@ _krb5_get_cred_kdc_any(krb5_context context, ret = krb5_cc_get_config(context, ccache, NULL, "lkdc-hostname", &data); if (ret == 0) { - kdc_hostname = malloc(data.length + 1); - if (kdc_hostname == NULL) - return krb5_enomem(context); - - memcpy(kdc_hostname, data.data, data.length); - kdc_hostname[data.length] = '\0'; + if ((kdc_hostname = strndup(data.data, data.length)) == NULL) { + ret = krb5_enomem(context); + goto out; + } krb5_data_free(&data); } ret = krb5_cc_get_config(context, ccache, NULL, "sitename", &data); if (ret == 0) { - sitename = malloc(data.length + 1); - if (sitename == NULL) - return krb5_enomem(context); - - memcpy(sitename, data.data, data.length); - sitename[data.length] = '\0'; + if ((sitename = strndup(data.data, data.length)) == NULL) { + ret = krb5_enomem(context); + goto out; + } krb5_data_free(&data); } @@ -1441,9 +1443,9 @@ _krb5_get_cred_kdc_any(krb5_context context, out_creds); out: + krb5_data_free(&data); free(kdc_hostname); free(sitename); - return ret; } diff --git a/third_party/heimdal/lib/krb5/get_in_tkt.c b/third_party/heimdal/lib/krb5/get_in_tkt.c index d6a1a9345dca..c19fc6992816 100644 --- a/third_party/heimdal/lib/krb5/get_in_tkt.c +++ b/third_party/heimdal/lib/krb5/get_in_tkt.c @@ -115,7 +115,7 @@ add_padata(krb5_context context, if (!enctypes) { enctypes = context->etypes; netypes = 0; - for (ep = enctypes; *ep != (krb5_enctype)ETYPE_NULL; ep++) + for (ep = enctypes; *ep != ETYPE_NULL; ep++) netypes++; } pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val)); diff --git a/third_party/heimdal/lib/krb5/init_creds_pw.c b/third_party/heimdal/lib/krb5/init_creds_pw.c index 4ad5deba0900..e42fcf10bc17 100644 --- a/third_party/heimdal/lib/krb5/init_creds_pw.c +++ b/third_party/heimdal/lib/krb5/init_creds_pw.c @@ -35,7 +35,8 @@ */ #include "krb5_locl.h" -#include "../base/heimbasepriv.h" /* XXX */ + +#include struct pa_info_data { krb5_enctype etype; @@ -431,8 +432,8 @@ krb5_init_creds_warn_user(krb5_context context, if (!suppress) { char *str = NULL, *p = NULL; int aret; - krb5_enctype_to_string(context, weak_enctype, &str); + (void) krb5_enctype_to_string(context, weak_enctype, &str); aret = asprintf(&p, "Encryption type %s(%d) used for authentication is weak and will be deprecated", str ? str : "unknown", weak_enctype); if (aret >= 0 && p) { @@ -467,7 +468,9 @@ get_init_creds_common(krb5_context context, if (options == NULL) { const char *realm = krb5_principal_get_realm(context, client); - krb5_get_init_creds_opt_alloc (context, &default_opt); + ret = krb5_get_init_creds_opt_alloc(context, &default_opt); + if (ret) + return ret; options = default_opt; krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options); } @@ -501,11 +504,8 @@ get_init_creds_common(krb5_context context, ctx->pre_auth_types = NULL; 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; - } + if (ret) + goto out; ret = krb5_init_creds_set_service(context, ctx, NULL); if (ret) @@ -579,10 +579,6 @@ get_init_creds_common(krb5_context context, else ctx->runflags.change_password_prompt = ctx->prompter != NULL; - 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); @@ -703,8 +699,7 @@ change_password (krb5_context context, strlcpy (newpw, buf1, newpw_sz); ret = 0; } else { - ret = ENOTTY; - krb5_set_error_message(context, ret, + krb5_set_error_message(context, ret = KRB5_CHPW_FAIL, N_("failed changing password: %s", ""), p); } free (p); @@ -1089,7 +1084,7 @@ add_enc_ts_padata(krb5_context context, if (!enctypes) { enctypes = context->etypes; netypes = 0; - for (ep = enctypes; *ep != (krb5_enctype)ETYPE_NULL; ep++) + for (ep = enctypes; *ep != ETYPE_NULL; ep++) netypes++; } @@ -1427,12 +1422,13 @@ pa_gss_step(krb5_context context, char *from = NULL; char *to = NULL; - if (krb5_unparse_name(context, ctx->cred.client, &from) == 0 && - krb5_unparse_name(context, cname, &to) == 0) { - _krb5_debug(context, 1, "pa_gss_step: %s as %s", - from, to); + if (krb5_unparse_name(context, ctx->cred.client, &from) == 0) { + if (krb5_unparse_name(context, cname, &to) == 0) { + _krb5_debug(context, 1, "pa_gss_step: %s as %s", + from, to); + krb5_xfree(to); + } krb5_xfree(from); - krb5_xfree(to); } } @@ -1661,11 +1657,6 @@ enc_chal_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, P EncryptedData enc_data; size_t size; - if (ret) { - _krb5_debug(context, 5, "enc-chal: failed to create reply key"); - return ret; - } - _krb5_debug(context, 5, "ENC_CHAL rep key"); if (ctx->fast_state.strengthen_key == NULL) { @@ -2139,28 +2130,30 @@ process_pa_info(krb5_context context, return p; } -static void +static krb5_error_code pa_announce(krb5_context context, int types, krb5_init_creds_context ctx, METHOD_DATA *in_md, METHOD_DATA *out_md) { + krb5_error_code ret = 0; size_t n; - for (n = 0; n < sizeof(patypes)/sizeof(patypes[0]); n++) { + for (n = 0; ret == 0 && n < sizeof(patypes)/sizeof(patypes[0]); n++) { if ((patypes[n].flags & types) == 0) continue; if (patypes[n].step) patypes[n].step(context, ctx, NULL, NULL, NULL, NULL, NULL, in_md, out_md); else - krb5_padata_add(context, out_md, patypes[n].type, NULL, 0); + ret = krb5_padata_add(context, out_md, patypes[n].type, NULL, 0); } + return ret; } -static void +static void HEIM_CALLCONV mech_dealloc(void *ctx) { struct pa_auth_mech *pa_mech = ctx; @@ -2406,8 +2399,7 @@ process_pa_data_to_md(krb5_context context, * Send announcement (what we support) and configuration (user * introduced behavior change) */ - - pa_announce(context, PA_F_ANNOUNCE|PA_F_CONFIG, ctx, in_md, *out_md); + ret = pa_announce(context, PA_F_ANNOUNCE|PA_F_CONFIG, ctx, in_md, *out_md); /* * @@ -2418,7 +2410,7 @@ process_pa_data_to_md(krb5_context context, *out_md = NULL; } - return 0; + return ret; } static krb5_error_code @@ -2634,7 +2626,11 @@ krb5_init_creds_set_service(krb5_context context, ret = krb5_parse_name (context, service, &principal); if (ret) return ret; - krb5_principal_set_realm (context, principal, client_realm); + ret = krb5_principal_set_realm (context, principal, client_realm); + if (ret) { + krb5_free_principal(context, principal); + return ret; + } } else { ret = krb5_make_principal(context, &principal, client_realm, KRB5_TGS_NAME, client_realm, @@ -2704,27 +2700,23 @@ keytab_key_proc(krb5_context context, krb5_enctype enctype, krb5_keytab keytab = args->keytab; krb5_principal principal = args->principal; krb5_error_code ret; - krb5_keytab real_keytab; + krb5_keytab real_keytab = NULL; krb5_keytab_entry entry; if (keytab == NULL) { ret = krb5_kt_default(context, &real_keytab); if (ret) return ret; - } 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); + keytab = real_keytab; + } - if (ret) - return ret; + ret = krb5_kt_get_entry (context, keytab, principal, 0, enctype, &entry); + if (ret == 0) { + ret = krb5_copy_keyblock(context, &entry.keyblock, key); + krb5_kt_free_entry(context, &entry); + } - ret = krb5_copy_keyblock (context, &entry.keyblock, key); - krb5_kt_free_entry(context, &entry); + krb5_kt_close(context, real_keytab); return ret; } @@ -2870,25 +2862,9 @@ krb5_init_creds_set_fast_ccache(krb5_context context, krb5_init_creds_context ctx, krb5_ccache fast_ccache) { - krb5_creds *cred = NULL; - krb5_error_code ret; - krb5_data data; - - ret = _krb5_get_krbtgt(context, fast_ccache, NULL, &cred); - if (ret) - return ret; - - ret = krb5_cc_get_config(context, fast_ccache, cred->server, - "fast_avail", &data); - krb5_free_creds(context, cred); - if (ret == 0) { - ctx->fast_state.armor_ccache = fast_ccache; - ctx->fast_state.flags |= KRB5_FAST_REQUIRED; - ctx->fast_state.flags |= KRB5_FAST_KDC_VERIFIED; - } else { - krb5_set_error_message(context, EINVAL, N_("FAST not available for the KDC in the armor ccache", "")); - return EINVAL; - } + ctx->fast_state.armor_ccache = fast_ccache; + ctx->fast_state.flags |= KRB5_FAST_REQUIRED; + ctx->fast_state.flags |= KRB5_FAST_KDC_VERIFIED; return 0; } @@ -2956,6 +2932,19 @@ krb5_init_creds_set_fast_anon_pkinit(krb5_context context, return 0; } +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_init_creds_set_fast_anon_pkinit_optimistic(krb5_context context, + krb5_init_creds_context ctx) +{ + if (ctx->fast_state.armor_ccache) + return EINVAL; + + ctx->fast_state.flags |= KRB5_FAST_REQUIRED; + ctx->fast_state.flags |= KRB5_FAST_ANON_PKINIT_ARMOR; + ctx->fast_state.flags |= KRB5_FAST_OPTIMISTIC; + return 0; +} + static size_t available_padata_count(METHOD_DATA *md) { @@ -3352,16 +3341,6 @@ init_creds_step(krb5_context context, goto out; } - if ((ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC) == 0) { - _krb5_debug(context, 10, "Preauth failed"); - goto out; - } - - _krb5_debug(context, 10, "preauth failed with optimistic FAST, trying w/o FAST"); - - ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC; - ctx->fast_state.flags |= KRB5_FAST_DISABLED; - retry: pa_restart(context, ctx); @@ -3370,6 +3349,8 @@ init_creds_step(krb5_context context, "Some other error %d failed with optimistic FAST, trying w/o FAST", ret); ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC; + ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED; + ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR; ctx->fast_state.flags |= KRB5_FAST_DISABLED; pa_restart(context, ctx); } else { @@ -3485,9 +3466,15 @@ krb5_init_creds_step(krb5_context context, ctx->fast_state.armor_ccache == NULL) { ret = _krb5_fast_anon_pkinit_step(context, ctx, &ctx->fast_state, in, out, hostinfo, flags); - if (ret || - ((*flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE) == 0) || - out->length) + if (ret && (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC)) { + _krb5_debug(context, 5, "Preauth failed with optimistic " + "FAST, trying w/o FAST"); + ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC; + ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED; + ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR; + } else if (ret || + ((*flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE) == 0) || + out->length) return ret; in = ∅ @@ -3649,7 +3636,7 @@ krb5_init_creds_store(krb5_context context, krb5_data data = { 3, rk_UNCONST("yes") }; ret = krb5_cc_set_config(context, id, ctx->cred.server, "fast_avail", &data); - if (ret) + if (ret && ret != KRB5_CC_NOSUPP) return ret; } @@ -4001,7 +3988,7 @@ _krb5_init_creds_init_gss(krb5_context context, const struct gss_OID_desc_struct *gss_mech, unsigned int flags) { - krb5_gss_init_ctx gssic = ctx->gss_init_ctx; + krb5_gss_init_ctx gssic; gssic = calloc(1, sizeof(*gssic)); if (gssic == NULL) diff --git a/third_party/heimdal/lib/krb5/kcm.c b/third_party/heimdal/lib/krb5/kcm.c index 760abf5c59dd..a75fc03f985d 100644 --- a/third_party/heimdal/lib/krb5/kcm.c +++ b/third_party/heimdal/lib/krb5/kcm.c @@ -73,6 +73,8 @@ kcm_send_request(krb5_context context, krb5_error_code ret = 0; krb5_data request_data; + krb5_data_zero(response_data); + HEIMDAL_MUTEX_lock(&kcm_mutex); if (kcm_ipc == NULL) ret = heim_ipc_init_context(kcm_ipc_name, &kcm_ipc); @@ -82,18 +84,11 @@ kcm_send_request(krb5_context context, ret = krb5_storage_to_data(request, &request_data); if (ret) { - krb5_clear_error_message(context); - return KRB5_CC_NOMEM; + return krb5_enomem(context); } ret = heim_ipc_call(kcm_ipc, &request_data, response_data, NULL); krb5_data_free(&request_data); - - if (ret) { - krb5_clear_error_message(context); - ret = KRB5_CC_NOSUPP; - } - return ret; } @@ -108,10 +103,8 @@ krb5_kcm_storage_request(krb5_context context, *storage_p = NULL; sp = krb5_storage_emem(); - if (sp == NULL) { - krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", "")); - return KRB5_CC_NOMEM; - } + if (sp == NULL) + return krb5_enomem(context); /* Send MAJOR | VERSION | OPCODE */ ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR); @@ -135,31 +128,166 @@ krb5_kcm_storage_request(krb5_context context, return ret; } +/* + * A sort of a state() for caches -- we use this to see if the local default + * cache name for KCM happens to exist. See kcm_alloc() below. + */ +static krb5_error_code +kcm_stat(krb5_context context, const char *name) +{ + krb5_error_code ret; + krb5_storage *request = NULL; + krb5_data response_data; + + krb5_data_zero(&response_data); + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request); + if (ret == 0) + ret = krb5_store_stringz(request, name); + if (ret == 0) + ret = krb5_kcm_call(context, request, NULL, &response_data); + krb5_storage_free(request); + krb5_data_free(&response_data); + return ret; +} + +static krb5_error_code kcm_get_default_name(krb5_context, + const krb5_cc_ops *, + const char *, char **); + static krb5_error_code kcm_alloc(krb5_context context, - const char *name, + const krb5_cc_ops *ops, + const char *residual, + const char *sub, krb5_ccache *id) { + krb5_error_code ret; krb5_kcmcache *k; + size_t ops_prefix_len = strlen(ops->prefix); + size_t plen = 0; + size_t local_def_name_len; + char *local_def_name = NULL; /* Our idea of default KCM cache name */ + char *kcm_def_name = NULL; /* KCM's knowledge of default cache name */ + int aret; - k = malloc(sizeof(*k)); - if (k == NULL) { - krb5_set_error_message(context, KRB5_CC_NOMEM, - N_("malloc: out of memory", "")); - return KRB5_CC_NOMEM; + /* Get the KCM:%{UID} default */ + if (ops == &krb5_kcm_ops) + ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_KCM_KCM, &local_def_name); + else + ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_KCM_API, &local_def_name); + if (ret) + return ret; + local_def_name_len = strlen(local_def_name); + + /* Get the default ccache name from KCM if possible */ + (void) kcm_get_default_name(context, ops, NULL, &kcm_def_name); + + /* + * We have a sticky situation in that applications that call + * krb5_cc_default() will be getting the locally configured or compiled-in + * default KCM cache name, which may not exist in the user's KCM session, + * and which the KCM daemon may not be able to alias to the actual default + * for the user's session. + * + * To deal with this we heuristically detect when an application uses the + * default KCM ccache name. + * + * If the residual happens to be the local default KCM name we may end up + * using whatever the default KCM cache name is instead of the local + * default. + * + * Note that here `residual' may be any of: + * + * - %{UID} + * - %{UID}: + * - %{UID}: + * - + * - + * - + * + * Only the first two count as "maybe I mean the default KCM cache". + */ + if (residual && !sub && + strncmp(residual, local_def_name + ops_prefix_len + 1, + local_def_name_len - (ops_prefix_len + 1)) == 0) { + if (residual[local_def_name_len - (ops_prefix_len + 1)] == '\0' || + (residual[local_def_name_len - (ops_prefix_len + 1)] == ':' && + residual[local_def_name_len - ops_prefix_len] == '\0')) { + /* + * If we got a default cache name from KCM and the requested default + * cache does not exist, use the former. + */ + if (kcm_def_name && kcm_stat(context, residual)) + residual = kcm_def_name + ops_prefix_len + 1; + } } - if (name != NULL) { - k->name = strdup(name); - if (k->name == NULL) { - free(k); - krb5_set_error_message(context, KRB5_CC_NOMEM, - N_("malloc: out of memory", "")); - return KRB5_CC_NOMEM; - } - } else - k->name = NULL; + if (residual && residual[0] == '\0') + residual = NULL; + if (sub && sub[0] == '\0') + sub = NULL; + + if (residual == NULL && sub == NULL) { + /* Use the default cache name, either from KCM or local default */ + if (kcm_def_name) + residual = kcm_def_name + ops_prefix_len + 1; + else + residual = local_def_name + ops_prefix_len + 1; + } + + if (residual) { + /* KCM cache names must start with {UID} or {UID}: */ + if (residual[0] != '0') + plen = strspn(residual, "0123456789"); + if (plen && residual[plen] != ':' && residual[plen] != '\0') + plen = 0; + /* + * If `plen', then residual is such a residual, else we'll want to + * prefix the {UID}:. + */ + } + + k = calloc(1, sizeof(*k)); + if (k == NULL) { + free(local_def_name); + free(kcm_def_name); + return krb5_enomem(context); + } + k->name = NULL; + + if (residual == NULL && sub == NULL) { + /* One more way to get a default */ + aret = asprintf(&k->name, "%llu", (unsigned long long)getuid()); + } else if (residual == NULL) { + /* + * Treat the subsidiary as the residual (maybe this will turn out to be + * wrong). + */ + aret = asprintf(&k->name, "%llu:%s", (unsigned long long)getuid(), + sub); + } else if (plen) { + /* The residual is a UID */ + aret = asprintf(&k->name, "%s%s%s", residual, + sub ? ":" : "", sub ? sub : ""); + } else if (sub == NULL) { + /* The residual is NOT a UID */ + aret = asprintf(&k->name, "%llu:%s", (unsigned long long)getuid(), + residual); + } else { + /* Ditto, plus we have a subsidiary. `residual && sub && !plen' */ + aret = asprintf(&k->name, "%llu:%s:%s", (unsigned long long)getuid(), + residual, sub); + } + if (aret == -1 || k->name == NULL) { + free(local_def_name); + free(kcm_def_name); + free(k); + return krb5_enomem(context); + } + free(local_def_name); + free(kcm_def_name); (*id)->data.data = k; (*id)->data.length = sizeof(*k); @@ -181,10 +309,11 @@ krb5_kcm_call(krb5_context context, *response_p = NULL; krb5_data_zero(&response_data); - ret = kcm_send_request(context, request, &response_data); - if (ret) - return ret; + if (ret) { + krb5_data_free(&response_data); + return ret; + } response = krb5_storage_from_data(&response_data); if (response == NULL) { @@ -224,8 +353,7 @@ kcm_free(krb5_context context, krb5_ccache *id) krb5_kcmcache *k = KCMCACHE(*id); if (k != NULL) { - if (k->name != NULL) - free(k->name); + free(k->name); memset_s(k, sizeof(*k), 0, sizeof(*k)); krb5_data_free(&(*id)->data); } @@ -255,10 +383,10 @@ kcm_get_name_2(krb5_context context, } static krb5_error_code -kcm_resolve_2(krb5_context context, - krb5_ccache *id, - const char *res, - const char *sub) +kcm_resolve_2_kcm(krb5_context context, + krb5_ccache *id, + const char *res, + const char *sub) { /* * For now, for KCM the `res' is the `sub'. @@ -266,7 +394,22 @@ kcm_resolve_2(krb5_context context, * TODO: We should use `res' as the IPC name instead of the one currently * hard-coded in `kcm_ipc_name'. */ - return kcm_alloc(context, sub && *sub ? sub : res, id); + return kcm_alloc(context, &krb5_kcm_ops, res, sub, id); +} + +static krb5_error_code +kcm_resolve_2_api(krb5_context context, + krb5_ccache *id, + const char *res, + const char *sub) +{ + /* + * For now, for KCM the `res' is the `sub'. + * + * TODO: We should use `res' as the IPC name instead of the one currently + * hard-coded in `kcm_ipc_name'. + */ + return kcm_alloc(context, &krb5_akcm_ops, res, sub, id); } /* @@ -276,14 +419,14 @@ kcm_resolve_2(krb5_context context, * NameZ */ static krb5_error_code -kcm_gen_new(krb5_context context, krb5_ccache *id) +kcm_gen_new(krb5_context context, const krb5_cc_ops *ops, krb5_ccache *id) { krb5_kcmcache *k; krb5_error_code ret; krb5_storage *request, *response; krb5_data response_data; - ret = kcm_alloc(context, NULL, id); + ret = kcm_alloc(context, ops, NULL, NULL, id); if (ret) return ret; @@ -302,6 +445,8 @@ kcm_gen_new(krb5_context context, krb5_ccache *id) return ret; } + free(k->name); + k->name = NULL; ret = krb5_ret_stringz(response, &k->name); if (ret) ret = KRB5_CC_IO; @@ -316,6 +461,18 @@ kcm_gen_new(krb5_context context, krb5_ccache *id) return ret; } +static krb5_error_code +kcm_gen_new_kcm(krb5_context context, krb5_ccache *id) +{ + return kcm_gen_new(context, &krb5_kcm_ops, id); +} + +static krb5_error_code +kcm_gen_new_api(krb5_context context, krb5_ccache *id) +{ + return kcm_gen_new(context, &krb5_akcm_ops, id); +} + /* * Request: * NameZ @@ -666,8 +823,7 @@ kcm_get_next (krb5_context context, c->offset++; if (sret != sizeof(c->uuids[c->offset])) { krb5_storage_free(request); - krb5_clear_error_message(context); - return ENOMEM; + return krb5_enomem(context); } ret = krb5_kcm_call(context, request, &response, &response_data); @@ -895,8 +1051,7 @@ kcm_get_cache_next(krb5_context context, krb5_cc_cursor cursor, const krb5_cc_op c->offset++; if (sret != sizeof(c->uuids[c->offset])) { krb5_storage_free(request); - krb5_clear_error_message(context); - return ENOMEM; + return krb5_enomem(context); } ret = krb5_kcm_call(context, request, &response, &response_data); @@ -913,7 +1068,7 @@ kcm_get_cache_next(krb5_context context, krb5_cc_cursor cursor, const krb5_cc_op if (ret == 0) { ret = _krb5_cc_allocate(context, ops, id); if (ret == 0) - ret = kcm_alloc(context, name, id); + ret = kcm_alloc(context, ops, name, NULL, id); krb5_xfree(name); } @@ -998,8 +1153,11 @@ kcm_get_default_name(krb5_context context, const krb5_cc_ops *ops, ret = krb5_kcm_call(context, request, &response, &response_data); krb5_storage_free(request); - if (ret) - return _krb5_expand_default_cc_name(context, defstr, str); + if (ret) { + if (defstr) + return _krb5_expand_default_cc_name(context, defstr, str); + return ret; + } ret = krb5_ret_stringz(response, &name); krb5_storage_free(response); @@ -1009,8 +1167,8 @@ kcm_get_default_name(krb5_context context, const krb5_cc_ops *ops, aret = asprintf(str, "%s:%s", ops->prefix, name); free(name); - if (aret == -1 || str == NULL) - return ENOMEM; + if (aret == -1 || *str == NULL) + return krb5_enomem(context); return 0; } @@ -1133,7 +1291,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = { "KCM", NULL, NULL, - kcm_gen_new, + kcm_gen_new_kcm, kcm_initialize, kcm_destroy, kcm_close, @@ -1156,7 +1314,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = { kcm_set_kdc_offset, kcm_get_kdc_offset, kcm_get_name_2, - kcm_resolve_2 + kcm_resolve_2_kcm }; KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = { @@ -1164,7 +1322,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = { "API", NULL, NULL, - kcm_gen_new, + kcm_gen_new_api, kcm_initialize, kcm_destroy, kcm_close, @@ -1187,10 +1345,9 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = { NULL, NULL, kcm_get_name_2, - kcm_resolve_2 + kcm_resolve_2_api }; - KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL _krb5_kcm_is_running(krb5_context context) { @@ -1199,7 +1356,7 @@ _krb5_kcm_is_running(krb5_context context) krb5_ccache id = &ccdata; krb5_boolean running; - ret = kcm_alloc(context, NULL, &id); + ret = kcm_alloc(context, NULL, NULL, NULL, &id); if (ret) return 0; diff --git a/third_party/heimdal/lib/krb5/keytab.c b/third_party/heimdal/lib/krb5/keytab.c index 6ec14b8e1719..559d640f002c 100644 --- a/third_party/heimdal/lib/krb5/keytab.c +++ b/third_party/heimdal/lib/krb5/keytab.c @@ -358,10 +358,11 @@ krb5_kt_read_service_key(krb5_context context, krb5_enctype enctype, krb5_keyblock **key) { - krb5_keytab keytab; + krb5_keytab keytab = NULL; /* Quiet lint */ krb5_keytab_entry entry; krb5_error_code ret; + memset(&entry, 0, sizeof(entry)); if (keyprocarg) ret = krb5_kt_resolve (context, keyprocarg, &keytab); else @@ -371,11 +372,11 @@ krb5_kt_read_service_key(krb5_context context, return ret; ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); + if (ret == 0) { + ret = krb5_copy_keyblock (context, &entry.keyblock, key); + krb5_kt_free_entry(context, &entry); + } krb5_kt_close (context, keytab); - if (ret) - return ret; - ret = krb5_copy_keyblock (context, &entry.keyblock, key); - krb5_kt_free_entry(context, &entry); return ret; } @@ -482,11 +483,13 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_kt_close(krb5_context context, krb5_keytab id) { - krb5_error_code ret; + krb5_error_code ret = 0; - ret = (*id->close)(context, id); - memset(id, 0, sizeof(*id)); - free(id); + if (id) { + ret = (id->close)(context, id); + memset(id, 0, sizeof(*id)); + free(id); + } return ret; } @@ -579,29 +582,31 @@ _krb5_kt_principal_not_found(krb5_context context, krb5_enctype enctype, int kvno) { - char princ[256], kvno_str[25], *kt_name; + char kvno_str[25]; char *enctype_str = NULL; + char *kt_name = NULL; + char *princ = NULL; - krb5_unparse_name_fixed (context, principal, princ, sizeof(princ)); - krb5_kt_get_full_name (context, id, &kt_name); + (void) krb5_unparse_name(context, principal, &princ); + (void) krb5_kt_get_full_name(context, id, &kt_name); if (enctype) - krb5_enctype_to_string(context, enctype, &enctype_str); + (void) 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"); + krb5_set_error_message(context, ret, + N_("Failed to find %s%s in keytab %s (%s)", + "principal, kvno, keytab file, enctype"), + princ ? princ : "", + kvno_str, + kt_name ? kt_name : "unknown keytab", + enctype_str ? enctype_str : "unknown enctype"); + free(princ); free(kt_name); - if (enctype_str) - free(enctype_str); + free(enctype_str); return ret; } @@ -620,6 +625,7 @@ krb5_kt_get_entry_wrapped(krb5_context context, if(id->get) return (*id->get)(context, id, principal, kvno, enctype, entry); + memset(&tmp, 0, sizeof(tmp)); ret = krb5_kt_start_seq_get (context, id, &cursor); if (ret) { /* This is needed for krb5_verify_init_creds, but keep error @@ -683,7 +689,8 @@ krb5_kt_get_entry(krb5_context context, krb5_name_canon_iterator name_canon_iter; if (!principal) - return krb5_kt_get_entry_wrapped(context, id, principal, kvno, enctype, + /* Use `NULL' instead of `principal' to quiet static analizers */ + return krb5_kt_get_entry_wrapped(context, id, NULL, kvno, enctype, entry); ret = krb5_name_canon_iterator_start(context, principal, &name_canon_iter); @@ -731,21 +738,21 @@ krb5_kt_copy_entry_contents(krb5_context context, krb5_error_code ret; memset(out, 0, sizeof(*out)); - out->vno = in->vno; ret = krb5_copy_principal (context, in->principal, &out->principal); if (ret) - goto fail; + return ret; ret = krb5_copy_keyblock_contents (context, &in->keyblock, &out->keyblock); - if (ret) - goto fail; + if (ret) { + krb5_free_principal(context, out->principal); + memset(out, 0, sizeof(*out)); + return ret; + } + out->vno = in->vno; out->timestamp = in->timestamp; return 0; -fail: - krb5_kt_free_entry (context, out); - return ret; } /** @@ -927,6 +934,7 @@ krb5_kt_have_content(krb5_context context, krb5_error_code ret; char *name; + memset(&entry, 0, sizeof(entry)); ret = krb5_kt_start_seq_get(context, id, &cursor); if (ret) goto notfound; diff --git a/third_party/heimdal/lib/krb5/keytab_file.c b/third_party/heimdal/lib/krb5/keytab_file.c index 595966ed3876..61b5d6d29cf8 100644 --- a/third_party/heimdal/lib/krb5/keytab_file.c +++ b/third_party/heimdal/lib/krb5/keytab_file.c @@ -371,6 +371,7 @@ fkt_start_seq_get_int(krb5_context context, struct fkt_data *d = id->data; const char *stdio_mode = "rb"; + memset(c, 0, sizeof(*c)); c->fd = open (d->filename, flags); if (c->fd < 0) { ret = errno; @@ -797,7 +798,7 @@ fkt_remove_entry(krb5_context context, krb5_set_error_message(context, ret, N_("Could not remove keytab entry from %s: %s", ""), fkt->filename, - krb5_get_error_message(context, ret)); + emsg); krb5_free_error_message(context, emsg); } else if (!found) { krb5_clear_error_message(context); diff --git a/third_party/heimdal/lib/krb5/keytab_keyfile.c b/third_party/heimdal/lib/krb5/keytab_keyfile.c index cb865a794c08..af3ac86faf0a 100644 --- a/third_party/heimdal/lib/krb5/keytab_keyfile.c +++ b/third_party/heimdal/lib/krb5/keytab_keyfile.c @@ -403,7 +403,7 @@ akf_add_entry(krb5_context context, ret = errno; krb5_set_error_message (context, ret, N_("keytab keyfile failed new length", "")); - return ret; + goto out; } if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) { diff --git a/third_party/heimdal/lib/krb5/krb5.conf.5 b/third_party/heimdal/lib/krb5/krb5.conf.5 index bac94b5f7dfe..1013a78d8731 100644 --- a/third_party/heimdal/lib/krb5/krb5.conf.5 +++ b/third_party/heimdal/lib/krb5/krb5.conf.5 @@ -1077,12 +1077,6 @@ an optional unit (the default unit is Indicates whether a client may request longer lifetimes than their authentication credentials. Defaults to false. -If a -.Li force_cert_lifetime -is specified, then -.Li allow_extra_lifetime -is implicitly forced to -.Va true . .It Li require_initial_kca_tickets = Va boolean Specified whether to require that tickets for the .Li kca_service diff --git a/third_party/heimdal/lib/krb5/krb5.h b/third_party/heimdal/lib/krb5/krb5.h index 3950bd30a4ec..e78edcac9af5 100644 --- a/third_party/heimdal/lib/krb5/krb5.h +++ b/third_party/heimdal/lib/krb5/krb5.h @@ -95,6 +95,7 @@ typedef struct krb5_ntlm_data *krb5_ntlm; struct krb5_pac_data; typedef struct krb5_pac_data *krb5_pac; +typedef const struct krb5_pac_data *krb5_const_pac; typedef struct krb5_rd_req_in_ctx_data *krb5_rd_req_in_ctx; typedef struct krb5_rd_req_out_ctx_data *krb5_rd_req_out_ctx; @@ -122,55 +123,53 @@ typedef struct krb5_enc_data { } krb5_enc_data; /* alternative names */ -enum { - ENCTYPE_NULL = KRB5_ENCTYPE_NULL, - ENCTYPE_DES_CBC_CRC = KRB5_ENCTYPE_DES_CBC_CRC, - ENCTYPE_DES_CBC_MD4 = KRB5_ENCTYPE_DES_CBC_MD4, - ENCTYPE_DES_CBC_MD5 = KRB5_ENCTYPE_DES_CBC_MD5, - ENCTYPE_DES3_CBC_MD5 = KRB5_ENCTYPE_DES3_CBC_MD5, - ENCTYPE_OLD_DES3_CBC_SHA1 = KRB5_ENCTYPE_OLD_DES3_CBC_SHA1, - ENCTYPE_SIGN_DSA_GENERATE = KRB5_ENCTYPE_SIGN_DSA_GENERATE, - ENCTYPE_ENCRYPT_RSA_PRIV = KRB5_ENCTYPE_ENCRYPT_RSA_PRIV, - ENCTYPE_ENCRYPT_RSA_PUB = KRB5_ENCTYPE_ENCRYPT_RSA_PUB, - ENCTYPE_DES3_CBC_SHA1 = KRB5_ENCTYPE_DES3_CBC_SHA1, - ENCTYPE_AES128_CTS_HMAC_SHA1_96 = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, - ENCTYPE_AES256_CTS_HMAC_SHA1_96 = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, - ENCTYPE_ARCFOUR_HMAC = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5, - ENCTYPE_ARCFOUR_HMAC_MD5 = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5, - ENCTYPE_ARCFOUR_HMAC_MD5_56 = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56, - ENCTYPE_ENCTYPE_PK_CROSS = KRB5_ENCTYPE_ENCTYPE_PK_CROSS, - ENCTYPE_DES_CBC_NONE = KRB5_ENCTYPE_DES_CBC_NONE, - ENCTYPE_DES3_CBC_NONE = KRB5_ENCTYPE_DES3_CBC_NONE, - ENCTYPE_DES_CFB64_NONE = KRB5_ENCTYPE_DES_CFB64_NONE, - ENCTYPE_DES_PCBC_NONE = KRB5_ENCTYPE_DES_PCBC_NONE, - ETYPE_NULL = KRB5_ENCTYPE_NULL, - ETYPE_DES_CBC_CRC = KRB5_ENCTYPE_DES_CBC_CRC, - ETYPE_DES_CBC_MD4 = KRB5_ENCTYPE_DES_CBC_MD4, - ETYPE_DES_CBC_MD5 = KRB5_ENCTYPE_DES_CBC_MD5, - ETYPE_DES3_CBC_MD5 = KRB5_ENCTYPE_DES3_CBC_MD5, - ETYPE_OLD_DES3_CBC_SHA1 = KRB5_ENCTYPE_OLD_DES3_CBC_SHA1, - ETYPE_SIGN_DSA_GENERATE = KRB5_ENCTYPE_SIGN_DSA_GENERATE, - ETYPE_ENCRYPT_RSA_PRIV = KRB5_ENCTYPE_ENCRYPT_RSA_PRIV, - ETYPE_ENCRYPT_RSA_PUB = KRB5_ENCTYPE_ENCRYPT_RSA_PUB, - ETYPE_DES3_CBC_SHA1 = KRB5_ENCTYPE_DES3_CBC_SHA1, - ETYPE_AES128_CTS_HMAC_SHA1_96 = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, - ETYPE_AES256_CTS_HMAC_SHA1_96 = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, - ETYPE_AES128_CTS_HMAC_SHA256_128 = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, - ETYPE_AES256_CTS_HMAC_SHA384_192 = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, - ETYPE_ARCFOUR_HMAC_MD5 = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5, - ETYPE_ARCFOUR_HMAC_MD5_56 = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56, - ETYPE_ENCTYPE_PK_CROSS = KRB5_ENCTYPE_ENCTYPE_PK_CROSS, - ETYPE_ARCFOUR_MD4 = KRB5_ENCTYPE_ARCFOUR_MD4, - ETYPE_ARCFOUR_HMAC_OLD = KRB5_ENCTYPE_ARCFOUR_HMAC_OLD, - ETYPE_ARCFOUR_HMAC_OLD_EXP = KRB5_ENCTYPE_ARCFOUR_HMAC_OLD_EXP, - ETYPE_DES_CBC_NONE = KRB5_ENCTYPE_DES_CBC_NONE, - ETYPE_DES3_CBC_NONE = KRB5_ENCTYPE_DES3_CBC_NONE, - ETYPE_DES_CFB64_NONE = KRB5_ENCTYPE_DES_CFB64_NONE, - ETYPE_DES_PCBC_NONE = KRB5_ENCTYPE_DES_PCBC_NONE, - ETYPE_DIGEST_MD5_NONE = KRB5_ENCTYPE_DIGEST_MD5_NONE, - ETYPE_CRAM_MD5_NONE = KRB5_ENCTYPE_CRAM_MD5_NONE - -}; +#define ENCTYPE_NULL KRB5_ENCTYPE_NULL +#define ENCTYPE_DES_CBC_CRC KRB5_ENCTYPE_DES_CBC_CRC +#define ENCTYPE_DES_CBC_MD4 KRB5_ENCTYPE_DES_CBC_MD4 +#define ENCTYPE_DES_CBC_MD5 KRB5_ENCTYPE_DES_CBC_MD5 +#define ENCTYPE_DES3_CBC_MD5 KRB5_ENCTYPE_DES3_CBC_MD5 +#define ENCTYPE_OLD_DES3_CBC_SHA1 KRB5_ENCTYPE_OLD_DES3_CBC_SHA1 +#define ENCTYPE_SIGN_DSA_GENERATE KRB5_ENCTYPE_SIGN_DSA_GENERATE +#define ENCTYPE_ENCRYPT_RSA_PRIV KRB5_ENCTYPE_ENCRYPT_RSA_PRIV +#define ENCTYPE_ENCRYPT_RSA_PUB KRB5_ENCTYPE_ENCRYPT_RSA_PUB +#define ENCTYPE_DES3_CBC_SHA1 KRB5_ENCTYPE_DES3_CBC_SHA1 +#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96 +#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96 +#define ENCTYPE_ARCFOUR_HMAC KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 +#define ENCTYPE_ARCFOUR_HMAC_MD5 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 +#define ENCTYPE_ARCFOUR_HMAC_MD5_56 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56 +#define ENCTYPE_ENCTYPE_PK_CROSS KRB5_ENCTYPE_ENCTYPE_PK_CROSS +#define ENCTYPE_DES_CBC_NONE KRB5_ENCTYPE_DES_CBC_NONE +#define ENCTYPE_DES3_CBC_NONE KRB5_ENCTYPE_DES3_CBC_NONE +#define ENCTYPE_DES_CFB64_NONE KRB5_ENCTYPE_DES_CFB64_NONE +#define ENCTYPE_DES_PCBC_NONE KRB5_ENCTYPE_DES_PCBC_NONE +#define ETYPE_NULL KRB5_ENCTYPE_NULL +#define ETYPE_DES_CBC_CRC KRB5_ENCTYPE_DES_CBC_CRC +#define ETYPE_DES_CBC_MD4 KRB5_ENCTYPE_DES_CBC_MD4 +#define ETYPE_DES_CBC_MD5 KRB5_ENCTYPE_DES_CBC_MD5 +#define ETYPE_DES3_CBC_MD5 KRB5_ENCTYPE_DES3_CBC_MD5 +#define ETYPE_OLD_DES3_CBC_SHA1 KRB5_ENCTYPE_OLD_DES3_CBC_SHA1 +#define ETYPE_SIGN_DSA_GENERATE KRB5_ENCTYPE_SIGN_DSA_GENERATE +#define ETYPE_ENCRYPT_RSA_PRIV KRB5_ENCTYPE_ENCRYPT_RSA_PRIV +#define ETYPE_ENCRYPT_RSA_PUB KRB5_ENCTYPE_ENCRYPT_RSA_PUB +#define ETYPE_DES3_CBC_SHA1 KRB5_ENCTYPE_DES3_CBC_SHA1 +#define ETYPE_AES128_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96 +#define ETYPE_AES256_CTS_HMAC_SHA1_96 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96 +#define ETYPE_AES128_CTS_HMAC_SHA256_128 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128 +#define ETYPE_AES256_CTS_HMAC_SHA384_192 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192 +#define ETYPE_ARCFOUR_HMAC_MD5 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 +#define ETYPE_ARCFOUR_HMAC_MD5_56 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56 +#define ETYPE_ENCTYPE_PK_CROSS KRB5_ENCTYPE_ENCTYPE_PK_CROSS +#define ETYPE_ARCFOUR_MD4 KRB5_ENCTYPE_ARCFOUR_MD4 +#define ETYPE_ARCFOUR_HMAC_OLD KRB5_ENCTYPE_ARCFOUR_HMAC_OLD +#define ETYPE_ARCFOUR_HMAC_OLD_EXP KRB5_ENCTYPE_ARCFOUR_HMAC_OLD_EXP +#define ETYPE_DES_CBC_NONE KRB5_ENCTYPE_DES_CBC_NONE +#define ETYPE_DES3_CBC_NONE KRB5_ENCTYPE_DES3_CBC_NONE +#define ETYPE_DES_CFB64_NONE KRB5_ENCTYPE_DES_CFB64_NONE +#define ETYPE_DES_PCBC_NONE KRB5_ENCTYPE_DES_PCBC_NONE +#define ETYPE_DIGEST_MD5_NONE KRB5_ENCTYPE_DIGEST_MD5_NONE +#define ETYPE_CRAM_MD5_NONE KRB5_ENCTYPE_CRAM_MD5_NONE +#define DOMAIN_X500_COMPRESS domain_X500_Compress /* PDU types */ typedef enum krb5_pdu { @@ -1043,5 +1042,24 @@ extern KRB5_LIB_VARIABLE const char *krb5_cc_type_scc; extern KRB5_LIB_VARIABLE const char *krb5_cc_type_dcc; extern KRB5_LIB_VARIABLE const char *krb5_cc_type_keyring; +/* clang analyzer workarounds */ + +#ifdef __clang_analyzer__ +/* + * The clang analyzer (lint) can't know that krb5_enomem() always returns + * non-zero, so code like: + * + * if ((x = malloc(...)) == NULL) + * ret = krb5_enomem(context) + * if (ret == 0) + * *x = ...; + * + * causes false positives. + * + * The fix is to make krb5_enomem() a macro that always evaluates to ENOMEM. + */ +#define krb5_enomem(c) (krb5_enomem(c), ENOMEM) +#endif + #endif /* __KRB5_H__ */ diff --git a/third_party/heimdal/lib/krb5/krb5_locl.h b/third_party/heimdal/lib/krb5/krb5_locl.h index 6b74653f565b..7045c5bb6016 100644 --- a/third_party/heimdal/lib/krb5/krb5_locl.h +++ b/third_party/heimdal/lib/krb5/krb5_locl.h @@ -87,8 +87,10 @@ struct mbuf; #ifdef LIBINTL #include +#undef N_ #define N_(x,y) dgettext(HEIMDAL_TEXTDOMAIN, x) #else +#undef N_ #define N_(x,y) (x) #define bindtextdomain(package, localedir) #endif diff --git a/third_party/heimdal/lib/krb5/krbhst-test.c b/third_party/heimdal/lib/krb5/krbhst-test.c index 873734fce77a..cd388ecfaaa0 100644 --- a/third_party/heimdal/lib/krb5/krbhst-test.c +++ b/third_party/heimdal/lib/krb5/krbhst-test.c @@ -59,6 +59,7 @@ usage (int ret) int main(int argc, char **argv) { + krb5_error_code ret; int i, j; krb5_context context; int types[] = {KRB5_KRBHST_KDC, KRB5_KRBHST_ADMIN, KRB5_KRBHST_CHANGEPW, @@ -82,7 +83,9 @@ main(int argc, char **argv) argc -= optidx; argv += optidx; - krb5_init_context (&context); + ret = krb5_init_context(&context); + if (ret) + krb5_err(NULL, 1, ret, "Failed to initialize context"); for(i = 0; i < argc; i++) { krb5_krbhst_handle handle; char host[MAXHOSTNAMELEN]; @@ -90,12 +93,16 @@ main(int argc, char **argv) for (j = 0; j < sizeof(types)/sizeof(*types); ++j) { printf ("%s for %s:\n", type_str[j], argv[i]); - krb5_krbhst_init(context, argv[i], types[j], &handle); - while(krb5_krbhst_next_as_string(context, handle, - host, sizeof(host)) == 0) + ret = krb5_krbhst_init(context, argv[i], types[j], &handle); + if (ret) + krb5_err(context, 1, ret, "Could not init krbhst iterator"); + while ((ret = krb5_krbhst_next_as_string(context, handle, host, + sizeof(host))) == 0) printf("\thost: %s\n", host); krb5_krbhst_reset(context, handle); - printf ("\n"); + printf("\n"); + if (ret) + krb5_err(context, 1, ret, "Could not iterate all krbhst"); } } return 0; diff --git a/third_party/heimdal/lib/krb5/krbhst.c b/third_party/heimdal/lib/krb5/krbhst.c index adb8e00e6dc8..3688d6ad7ce9 100644 --- a/third_party/heimdal/lib/krb5/krbhst.c +++ b/third_party/heimdal/lib/krb5/krbhst.c @@ -107,8 +107,24 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, } for(num_srv = 0, rr = r->head; rr; rr = rr->next) - if(rr->type == rk_ns_t_srv) + if(rr->type == rk_ns_t_srv) { + if (num_srv >= INT_MAX) { + rk_dns_free_data(r); + return KRB5_KDC_UNREACH; + } + if (num_srv >= SIZE_MAX / sizeof(**res)) { + rk_dns_free_data(r); + return KRB5_KDC_UNREACH; + } num_srv++; + } + + if (num_srv == 0) { + _krb5_debug(context, 0, + "DNS SRV RR lookup domain nodata: %s", domain); + rk_dns_free_data(r); + return KRB5_KDC_UNREACH; + } *res = malloc(num_srv * sizeof(**res)); if(*res == NULL) { @@ -431,7 +447,7 @@ krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host, static krb5_boolean get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host) { - struct krb5_krbhst_info *hi = *kd->index; + struct krb5_krbhst_info *hi = kd ? *kd->index : NULL; if(hi != NULL) { *host = hi; kd->index = &(*kd->index)->next; @@ -555,6 +571,7 @@ fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, "Realm %s needs immediate attention " "see https://icann.org/namecollision", kd->realm); + freeaddrinfo(ai); return KRB5_KDC_UNREACH; } } @@ -563,6 +580,7 @@ fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, hi = calloc(1, sizeof(*hi) + hostlen); if(hi == NULL) { free(host); + freeaddrinfo(ai); return krb5_enomem(context); } @@ -920,7 +938,7 @@ kpasswd_get_next(krb5_context context, return KRB5_KDC_UNREACH; } -static void +static void KRB5_CALLCONV krbhost_dealloc(void *ptr) { struct krb5_krbhst_data *handle = (struct krb5_krbhst_data *)ptr; diff --git a/third_party/heimdal/lib/krb5/krcache.c b/third_party/heimdal/lib/krb5/krcache.c index dbf81850ea34..9e992216153d 100644 --- a/third_party/heimdal/lib/krb5/krcache.c +++ b/third_party/heimdal/lib/krb5/krcache.c @@ -367,6 +367,9 @@ parse_residual(krb5_context context, *pcollection_name = NULL; *psubsidiary_name = NULL; + if (residual == NULL) + residual = ""; + /* Parse out the anchor name. Use the legacy anchor if not present. */ sep = strchr(residual, ':'); if (sep == NULL) { @@ -473,7 +476,7 @@ make_subsidiary_residual(krb5_context context, char **presidual) { if (asprintf(presidual, "%s:%s:%s", anchor_name, collection_name, - subsidiary_name) < 0) { + subsidiary_name ? subsidiary_name : "tkt") < 0) { *presidual = NULL; return krb5_enomem(context); } @@ -498,6 +501,9 @@ get_collection(krb5_context context, heim_base_atomic_init(pcollection_id, 0); + if (!anchor_name || !collection_name) + return KRB5_KCC_INVALID_ANCHOR; + if (strcmp(anchor_name, KRCC_PERSISTENT_ANCHOR) == 0) { /* * The collection name is a uid (or empty for the current effective @@ -1262,7 +1268,7 @@ alloc_cache(krb5_context context, subsidiary_name, &data->krc_name); if (ret || (data->krc_collection = strdup(collection_name)) == NULL || - (data->krc_subsidiary = strdup(subsidiary_name)) == NULL) { + (data->krc_subsidiary = strdup(subsidiary_name ? subsidiary_name : "tkt")) == NULL) { if (data) { free(data->krc_collection); free(data->krc_name); @@ -1702,7 +1708,7 @@ krcc_get_kdc_offset(krb5_context context, key_serial_t key, cache_id; krb5_storage *sp = NULL; krb5_data payload; - int32_t sec_offset, usec_offset; + int32_t sec_offset = 0; if (data == NULL) return krb5_einval(context, 2); @@ -1730,26 +1736,22 @@ krcc_get_kdc_offset(krb5_context context, sp = krb5_storage_from_data(&payload); if (sp == NULL) { - ret = KRB5_CC_IO; + ret = krb5_enomem(context);; goto cleanup; } krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); ret = krb5_ret_int32(sp, &sec_offset); - if (ret == 0) - krb5_ret_int32(sp, &usec_offset); - if (ret) { - ret = KRB5_CC_END; - goto cleanup; - } - - *offset = sec_offset; + /* + * We can't output nor use the usec_offset here, so we don't bother to read + * it, though we do write it. + */ cleanup: + *offset = sec_offset; krb5_storage_free(sp); krb5_data_free(&payload); - return ret; } @@ -1887,7 +1889,8 @@ krcc_get_cache_next(krb5_context context, continue; /* Don't repeat the primary cache. */ - if (strcmp(subsidiary_name, iter->primary_name) == 0) + if (iter->primary_name && + strcmp(subsidiary_name, iter->primary_name) == 0) continue; /* We found a valid key */ diff --git a/third_party/heimdal/lib/krb5/kx509.c b/third_party/heimdal/lib/krb5/kx509.c index bd5991fcbf81..7525739f66ca 100644 --- a/third_party/heimdal/lib/krb5/kx509.c +++ b/third_party/heimdal/lib/krb5/kx509.c @@ -376,10 +376,13 @@ load_priv_key(krb5_context context, ret = ENOENT; if (ret == 0) kx509_ctx->priv_key = _hx509_private_key_ref(keys[0]); - if (ret) + if (ret) { + char *emsg = hx509_get_error_string(context->hx509ctx, ret); + krb5_set_error_message(context, ret, "Could not load private key " - "from %s for kx509: %s", fn, - hx509_get_error_string(context->hx509ctx, ret)); + "from %s for kx509: %s", fn, emsg); + hx509_free_error_string(emsg); + } hx509_certs_free(&certs); return ret; } @@ -443,10 +446,13 @@ gen_priv_key(krb5_context context, if (ret == 0) ret = _hx509_generate_private_key(context->hx509ctx, key_gen_ctx, key); _hx509_generate_private_key_free(&key_gen_ctx); - if (ret) + if (ret) { + char *emsg = hx509_get_error_string(context->hx509ctx, ret); + krb5_set_error_message(context, ret, - "Could not generate a private key: %s", - hx509_get_error_string(context->hx509ctx, ret)); + "Could not generate a private key: %s", emsg); + hx509_free_error_string(emsg); + } return ret; } @@ -848,21 +854,28 @@ mk_kx509_req(krb5_context context, /* Add the the key and HMAC to the message */ HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, kx509_ctx->hmac_key->keyvalue.data, - kx509_ctx->hmac_key->keyvalue.length, EVP_sha1(), NULL); - HMAC_Update(&ctx, version_2_0, sizeof(version_2_0)); - if (private_key || kx509_ctx->given_csr.data) { - HMAC_Update(&ctx, kx509_req.pk_key.data, kx509_req.pk_key.length); + if (HMAC_Init_ex(&ctx, kx509_ctx->hmac_key->keyvalue.data, + kx509_ctx->hmac_key->keyvalue.length, + EVP_sha1(), NULL) == 0) { + HMAC_CTX_cleanup(&ctx); + ret = krb5_enomem(context); } else { - /* Probe */ - HMAC_Update(&ctx, kx509_req.authenticator.data, kx509_req.authenticator.length); + HMAC_Update(&ctx, version_2_0, sizeof(version_2_0)); + if (private_key || kx509_ctx->given_csr.data) { + HMAC_Update(&ctx, kx509_req.pk_key.data, kx509_req.pk_key.length); + } else { + /* Probe */ + HMAC_Update(&ctx, kx509_req.authenticator.data, kx509_req.authenticator.length); + } + HMAC_Final(&ctx, kx509_req.pk_hash.data, 0); + HMAC_CTX_cleanup(&ctx); } - HMAC_Final(&ctx, kx509_req.pk_hash.data, 0); - HMAC_CTX_cleanup(&ctx); /* Encode the message, prefix `version_2_0', output the result */ - ASN1_MALLOC_ENCODE(Kx509Request, pre_req.data, pre_req.length, &kx509_req, &len, ret); - ret = krb5_data_alloc(req, pre_req.length + sizeof(version_2_0)); + if (ret == 0) + ASN1_MALLOC_ENCODE(Kx509Request, pre_req.data, pre_req.length, &kx509_req, &len, ret); + if (ret == 0) + ret = krb5_data_alloc(req, pre_req.length + sizeof(version_2_0)); if (ret == 0) { memcpy(req->data, version_2_0, sizeof(version_2_0)); memcpy(((unsigned char *)req->data) + sizeof(version_2_0), @@ -984,8 +997,13 @@ rd_kx509_resp(krb5_context context, } HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, kx509_ctx->hmac_key->keyvalue.data, - kx509_ctx->hmac_key->keyvalue.length, EVP_sha1(), NULL); + if (HMAC_Init_ex(&ctx, kx509_ctx->hmac_key->keyvalue.data, + kx509_ctx->hmac_key->keyvalue.length, EVP_sha1(), NULL) == 0) { + free_Kx509Response(&r); + HMAC_CTX_cleanup(&ctx); + return krb5_enomem(context); + } + HMAC_Update(&ctx, version_2_0, sizeof(version_2_0)); { @@ -1090,7 +1108,7 @@ rd_kx509_resp(krb5_context context, ret = errno; } free_Kx509Response(&r); - if (cert) { + if (*cert) { heim_release(herr); return 0; } @@ -1250,7 +1268,9 @@ krb5_kx509(krb5_context context, krb5_ccache cc, const char *realm) char *store_exp = NULL; ret = krb5_kx509_ctx_init(context, &kx509_ctx); - if (ret == 0 && realm) + if (ret) + return ret; + if (realm) ret = krb5_kx509_ctx_set_realm(context, kx509_ctx, realm); /* diff --git a/third_party/heimdal/lib/krb5/libkrb5-exports.def.in b/third_party/heimdal/lib/krb5/libkrb5-exports.def.in index 245f4b1bf437..191a0c48c861 100644 --- a/third_party/heimdal/lib/krb5/libkrb5-exports.def.in +++ b/third_party/heimdal/lib/krb5/libkrb5-exports.def.in @@ -23,6 +23,8 @@ EXPORTS krb5_appdefault_time krb5_append_addresses krb5_auth_con_addflags + krb5_auth_con_add_AuthorizationData + krb5_auth_con_add_AuthorizationDataIfRelevant krb5_auth_con_free krb5_auth_con_genaddrs krb5_auth_con_generatelocalsubkey @@ -500,6 +502,7 @@ EXPORTS krb5_pac_add_buffer krb5_pac_free krb5_pac_get_buffer + _krb5_pac_get_buffer_by_name krb5_pac_get_kdc_checksum_info krb5_pac_get_types krb5_pac_init @@ -747,6 +750,7 @@ EXPORTS krb5_cccol_cursor_new krb5_cccol_cursor_next krb5_cccol_cursor_free + krb5_cccol_get_default_ccname ; com_err error tables initialize_krb5_error_table_r @@ -837,6 +841,8 @@ EXPORTS _krb5_enctype_requires_random_salt _krb5_principal2principalname _krb5_principalname2krb5_principal + _krb5_kdcrep2krb5_principal + _krb5_ticket2krb5_principal _krb5_put_int _krb5_s4u2self_to_checksumdata _krb5_HMAC_MD5_checksum @@ -857,6 +863,7 @@ EXPORTS krb5_init_creds_get_error krb5_init_creds_init krb5_init_creds_set_fast_anon_pkinit + _krb5_init_creds_set_fast_anon_pkinit_optimistic krb5_init_creds_set_fast_ccache krb5_init_creds_set_keytab krb5_init_creds_set_kdc_hostname diff --git a/third_party/heimdal/lib/krb5/mcache.c b/third_party/heimdal/lib/krb5/mcache.c index 4ccc415a2619..fdd5674c3b87 100644 --- a/third_party/heimdal/lib/krb5/mcache.c +++ b/third_party/heimdal/lib/krb5/mcache.c @@ -112,10 +112,10 @@ again: if (strcmp(m->name, m_c->name) == 0) break; if (m_c) { - free(m->name); - free(m); if (name && !create_anonymous) { /* We raced with another thread to create this cache */ + free(m->name); + free(m); m = m_c; HEIMDAL_MUTEX_lock(&(m->mutex)); m->refcnt++; diff --git a/third_party/heimdal/lib/krb5/mk_cred.c b/third_party/heimdal/lib/krb5/mk_cred.c index 33e62e5b0d26..41e858f80588 100644 --- a/third_party/heimdal/lib/krb5/mk_cred.c +++ b/third_party/heimdal/lib/krb5/mk_cred.c @@ -258,15 +258,16 @@ _krb5_mk_ncred(krb5_context context, */ ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); + if (ret == 0) + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_KRB_CRED, + buf, + len, + 0, + &cred.enc_part); if (ret) goto out; - ret = krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_KRB_CRED, - buf, - len, - 0, - &cred.enc_part); DISOWN_BUF(buf); krb5_crypto_destroy(context, crypto); } diff --git a/third_party/heimdal/lib/krb5/pac.c b/third_party/heimdal/lib/krb5/pac.c index cd9a6d6d3107..2bdeae8ecd1d 100644 --- a/third_party/heimdal/lib/krb5/pac.c +++ b/third_party/heimdal/lib/krb5/pac.c @@ -32,7 +32,10 @@ */ #include "krb5_locl.h" + +#include #include +#include struct PAC_INFO_BUFFER { uint32_t type; @@ -73,6 +76,8 @@ struct krb5_pac_data { #define PACTYPE_SIZE 8 #define PAC_INFO_BUFFER_SIZE 16 +#define PAC_LOGON_INFO 1 +#define PAC_CREDENTIALS_INFO 2 #define PAC_SERVER_CHECKSUM 6 #define PAC_PRIVSVR_CHECKSUM 7 #define PAC_LOGON_NAME 10 @@ -94,7 +99,39 @@ struct krb5_pac_data { } \ } while(0) -static const char zeros[PAC_ALIGNMENT] = { 0 }; +static const char zeros[PAC_ALIGNMENT]; + +static void HEIM_CALLCONV +pac_dealloc(void *ctx) +{ + krb5_pac pac = (krb5_pac)ctx; + + krb5_data_free(&pac->data); + krb5_data_free(&pac->ticket_sign_data); + + if (pac->upn_princ) { + free_Principal(pac->upn_princ); + free(pac->upn_princ); + } + if (pac->canon_princ) { + free_Principal(pac->canon_princ); + free(pac->canon_princ); + } + krb5_data_free(&pac->sid); + + free(pac->pac); +} + +struct heim_type_data pac_object = { + HEIM_TID_PAC, + "heim-pac", + NULL, + pac_dealloc, + NULL, + NULL, + NULL, + NULL +}; /* * HMAC-MD5 checksum over any key (needed for the PAC routines) @@ -152,7 +189,7 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len, krb5_storage *sp = NULL; uint32_t i, tmp, tmp2, header_end; - p = calloc(1, sizeof(*p)); + p = _heim_alloc_object(&pac_object, sizeof(*p)); if (p == NULL) { ret = krb5_enomem(context); goto out; @@ -302,7 +339,7 @@ out: if (p) { if (p->pac) free(p->pac); - free(p); + krb5_pac_free(context, p); } *pac = NULL; @@ -315,21 +352,21 @@ krb5_pac_init(krb5_context context, krb5_pac *pac) krb5_error_code ret; krb5_pac p; - p = calloc(1, sizeof(*p)); + p = _heim_alloc_object(&pac_object, sizeof(*p)); if (p == NULL) { return krb5_enomem(context); } p->pac = calloc(1, sizeof(*p->pac)); if (p->pac == NULL) { - free(p); + krb5_pac_free(context, p); return krb5_enomem(context); } ret = krb5_data_alloc(&p->data, PACTYPE_SIZE); if (ret) { free (p->pac); - free(p); + krb5_pac_free(context, p); return krb5_enomem(context); } @@ -346,6 +383,8 @@ krb5_pac_add_buffer(krb5_context context, krb5_pac p, size_t len, offset, header_end, old_end; uint32_t i; + assert(data->length > 0 && data->data != NULL); + len = p->pac->numbuffers; ptr = realloc(p->pac, @@ -394,9 +433,8 @@ krb5_pac_add_buffer(krb5_context context, krb5_pac p, * copy in new data part */ - if (data->data != NULL) - memcpy((unsigned char *)p->data.data + offset, - data->data, data->length); + memcpy((unsigned char *)p->data.data + offset, + data->data, data->length); memset((unsigned char *)p->data.data + offset + data->length, 0, p->data.length - offset - data->length); @@ -433,11 +471,14 @@ krb5_pac_get_buffer(krb5_context context, krb5_pac p, if (p->pac->buffers[i].type != type) continue; - ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len); - if (ret) { - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - return ret; + if (data) { + ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len); + if (ret) { + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + return ret; + } } + return 0; } krb5_set_error_message(context, ENOENT, "No PAC buffer of type %lu was found", @@ -445,6 +486,45 @@ krb5_pac_get_buffer(krb5_context context, krb5_pac p, return ENOENT; } +static struct { + uint32_t type; + krb5_data name; +} pac_buffer_name_map[] = { +#define PAC_MAP_ENTRY(type, name) { PAC_##type, { sizeof(name) - 1, name } } + PAC_MAP_ENTRY(LOGON_INFO, "logon-info" ), + PAC_MAP_ENTRY(CREDENTIALS_INFO, "credentials-info" ), + PAC_MAP_ENTRY(SERVER_CHECKSUM, "server-checksum" ), + PAC_MAP_ENTRY(PRIVSVR_CHECKSUM, "privsvr-checksum" ), + PAC_MAP_ENTRY(LOGON_NAME, "client-info" ), + PAC_MAP_ENTRY(CONSTRAINED_DELEGATION, "delegation-info" ), + PAC_MAP_ENTRY(UPN_DNS_INFO, "upn-dns-info" ), + PAC_MAP_ENTRY(TICKET_CHECKSUM, "ticket-checksum" ), + PAC_MAP_ENTRY(ATTRIBUTES_INFO, "attributes-info" ), + PAC_MAP_ENTRY(REQUESTOR_SID, "requestor-sid" ) +}; + +/* + * + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_pac_get_buffer_by_name(krb5_context context, krb5_pac p, + const krb5_data *name, krb5_data *data) +{ + size_t i; + + for (i = 0; + i < sizeof(pac_buffer_name_map) / sizeof(pac_buffer_name_map[0]); + i++) { + if (krb5_data_cmp(name, &pac_buffer_name_map[i].name) == 0) + return krb5_pac_get_buffer(context, p, pac_buffer_name_map[i].type, data); + } + + krb5_set_error_message(context, ENOENT, "No PAC buffer with name %.*s was found", + (int)name->length, (char *)name->data); + return ENOENT; +} + /* * */ @@ -476,17 +556,7 @@ krb5_pac_get_types(krb5_context context, KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_pac_free(krb5_context context, krb5_pac pac) { - if (pac == NULL) - return; - krb5_data_free(&pac->data); - krb5_data_free(&pac->ticket_sign_data); - - krb5_free_principal(context, pac->upn_princ); - krb5_free_principal(context, pac->canon_princ); - krb5_data_free(&pac->sid); - - free(pac->pac); - free(pac); + heim_release(pac); } /* @@ -889,7 +959,7 @@ build_logon_name(krb5_context context, krb5_error_code ret; krb5_storage *sp; uint64_t t; - char *s, *s2; + char *s, *s2 = NULL; size_t s2_len; t = unix2nttime(authtime); @@ -936,7 +1006,7 @@ build_logon_name(krb5_context context, krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s); free(s); return ret; - } else + } else free(s); s2_len = (ucs2_len + 1) * 2; @@ -965,18 +1035,14 @@ build_logon_name(krb5_context context, CHECK(ret, krb5_store_uint16(sp, s2_len), out); ret = krb5_storage_write(sp, s2, s2_len); - free(s2); if (ret != (int)s2_len) { ret = krb5_enomem(context); goto out; } ret = krb5_storage_to_data(sp, logon); - if (ret) - goto out; - krb5_storage_free(sp); - return 0; -out: + out: + free(s2); krb5_storage_free(sp); return ret; } @@ -1350,10 +1416,8 @@ _krb5_pac_sign(krb5_context context, if (ret == 0) { krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); spdata = krb5_storage_emem(); - if (spdata == NULL) { - krb5_storage_free(sp); + if (spdata == NULL) ret = krb5_enomem(context); - } } if (ret) @@ -1472,7 +1536,8 @@ _krb5_pac_sign(krb5_context context, krb5_storage *rs = krb5_storage_emem(); if (rs == NULL) ret = krb5_enomem(context); - krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE); + else + krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE); if (ret == 0) ret = krb5_store_uint16(rs, rodc_id); if (ret == 0) diff --git a/third_party/heimdal/lib/krb5/pkinit.c b/third_party/heimdal/lib/krb5/pkinit.c index 0198400d9eb1..c9a6e3e8f8b9 100644 --- a/third_party/heimdal/lib/krb5/pkinit.c +++ b/third_party/heimdal/lib/krb5/pkinit.c @@ -114,6 +114,14 @@ select_dh_group(krb5_context context, DH *dh, unsigned long bits, { const struct krb5_dh_moduli *m; + if (moduli[0] == NULL) { + krb5_set_error_message(context, EINVAL, + N_("Did not find a DH group parameter " + "matching requirement of %lu bits", ""), + bits); + return EINVAL; + } + if (bits == 0) { m = moduli[1]; /* XXX */ if (m == NULL) @@ -1198,11 +1206,13 @@ pk_rd_pa_reply_enckey(krb5_context context, &contentType, &unwrapped, &host); + if (ret == 0) { + krb5_data_free(&content); + ret = krb5_data_copy(&content, unwrapped.data, unwrapped.length); + der_free_octet_string(&unwrapped); + } if (ret) goto out; - krb5_data_free(&content); - ret = krb5_data_copy(&content, unwrapped.data, unwrapped.length); - der_free_octet_string(&unwrapped); heim_assert(host || (ctx->id->flags & PKINIT_NO_KDC_ANCHOR), "KDC signature must be verified unless PKINIT_NO_KDC_ANCHOR set"); @@ -1831,7 +1841,7 @@ _krb5_pk_set_user_id(krb5_context context, ret = der_print_hex_heim_integer(&i, &sn); der_free_heim_integer(&i); if (ret) { - free(name); + free(str); goto out; } @@ -1857,7 +1867,7 @@ _krb5_pk_load_id(krb5_context context, { struct krb5_pk_identity *id = NULL; struct prompter p; - int ret; + krb5_error_code ret; *ret_id = NULL; @@ -2100,7 +2110,6 @@ _krb5_parse_moduli_line(krb5_context context, m1->q.length = 0; m1->q.data = 0; krb5_clear_error_message(context); - ret = 0; } *m = m1; diff --git a/third_party/heimdal/lib/krb5/principal.c b/third_party/heimdal/lib/krb5/principal.c index ee25f6acb59d..6080e4623415 100644 --- a/third_party/heimdal/lib/krb5/principal.c +++ b/third_party/heimdal/lib/krb5/principal.c @@ -103,6 +103,8 @@ krb5_free_principal(krb5_context context, krb5_principal p) { if(p){ + if (p->nameattrs && p->nameattrs->pac) + heim_release(p->nameattrs->pac); free_Principal(p); free(p); } @@ -457,6 +459,22 @@ unparse_name_fixed(krb5_context context, int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0; int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0; + if (name == NULL) { + krb5_set_error_message(context, EINVAL, + N_("Invalid name buffer, " + "can't unparse", "")); + return EINVAL; + } + + if (len == 0) { + krb5_set_error_message(context, ERANGE, + N_("Invalid name buffer length, " + "can't unparse", "")); + return ERANGE; + } + + name[0] = '\0'; + if (!no_realm && princ_realm(principal) == NULL) { krb5_set_error_message(context, ERANGE, N_("Realm missing from principal, " @@ -932,6 +950,9 @@ krb5_copy_principal(krb5_context context, free(p); return krb5_enomem(context); } + if (inprinc->nameattrs && inprinc->nameattrs->pac) + p->nameattrs->pac = heim_retain(inprinc->nameattrs->pac); + *outprinc = p; return 0; } @@ -1766,7 +1787,7 @@ _krb5_get_name_canon_rules(krb5_context context, krb5_name_canon_rule *rules) "libdefaults", "safe_name_canon", NULL)) make_rules_safe(context, *rules); - heim_assert(rules != NULL && (*rules)[0].type != KRB5_NCRT_BOGUS, + heim_assert((*rules)[0].type != KRB5_NCRT_BOGUS, "internal error in parsing principal name " "canonicalization rules"); @@ -1968,10 +1989,12 @@ apply_name_canon_rule(krb5_context context, krb5_name_canon_rule rules, new_hostname = hostname_with_port; } - if (new_realm != NULL) - krb5_principal_set_realm(context, *out_princ, new_realm); - if (new_hostname != NULL) - krb5_principal_set_comp_string(context, *out_princ, 1, new_hostname); + if (new_realm != NULL && + (ret = krb5_principal_set_realm(context, *out_princ, new_realm))) + goto out; + if (new_hostname != NULL && + (ret = krb5_principal_set_comp_string(context, *out_princ, 1, new_hostname))) + goto out; if (princ_type(*out_princ) == KRB5_NT_SRV_HST_NEEDS_CANON) princ_type(*out_princ) = KRB5_NT_SRV_HST; diff --git a/third_party/heimdal/lib/krb5/rd_cred.c b/third_party/heimdal/lib/krb5/rd_cred.c index b24973978409..f8d57362310b 100644 --- a/third_party/heimdal/lib/krb5/rd_cred.c +++ b/third_party/heimdal/lib/krb5/rd_cred.c @@ -96,7 +96,7 @@ krb5_rd_cred(krb5_context context, goto out; } - if (cred.enc_part.etype == (krb5_enctype)ETYPE_NULL) { + if (cred.enc_part.etype == ETYPE_NULL) { /* DK: MIT GSS-API Compatibility */ enc_krb_cred_part_data.length = cred.enc_part.cipher.length; enc_krb_cred_part_data.data = cred.enc_part.cipher.data; diff --git a/third_party/heimdal/lib/krb5/rd_req.c b/third_party/heimdal/lib/krb5/rd_req.c index bd0b68b9cfb5..371037c8403f 100644 --- a/third_party/heimdal/lib/krb5/rd_req.c +++ b/third_party/heimdal/lib/krb5/rd_req.c @@ -351,11 +351,6 @@ krb5_verify_ap_req2(krb5_context context, ap_req->ticket.sname, ap_req->ticket.realm); if (ret) goto out; - ret = _krb5_principalname2krb5_principal(context, - &t->client, - t->ticket.cname, - t->ticket.crealm); - if (ret) goto out; ret = decrypt_authenticator (context, &t->ticket.key, @@ -387,6 +382,27 @@ krb5_verify_ap_req2(krb5_context context, } } + /* + * The ticket authenticates the client, and conveys naming attributes that + * we want to expose in GSS using RFC6680 APIs. + * + * So we same the ticket enc-part in the client's krb5_principal object + * (note though that the session key will be absent in that copy of the + * ticket enc-part). + */ + ret = _krb5_ticket2krb5_principal(context, &t->client, &t->ticket, + ac->authenticator->authorization_data); + if (ret) goto out; + + t->client->nameattrs->peer_realm = + calloc(1, sizeof(t->client->nameattrs->peer_realm[0])); + if (t->client->nameattrs->peer_realm == NULL) { + ret = krb5_enomem(context); + goto out; + } + ret = copy_Realm(&ap_req->ticket.realm, t->client->nameattrs->peer_realm); + if (ret) goto out; + /* check addresses */ if (t->ticket.caddr @@ -458,7 +474,7 @@ krb5_verify_ap_req2(krb5_context context, if (ap_req_options) { *ap_req_options = 0; - if (ac->keytype != (krb5_enctype)ETYPE_NULL) + if (ac->keytype != ETYPE_NULL) *ap_req_options |= AP_OPTS_USE_SUBKEY; if (ap_req->ap_options.use_session_key) *ap_req_options |= AP_OPTS_USE_SESSION_KEY; @@ -791,11 +807,10 @@ get_key_from_keytab(krb5_context context, kvno, ap_req->ticket.enc_part.etype, &entry); - if(ret) - goto out; - ret = krb5_copy_keyblock(context, &entry.keyblock, out_key); - krb5_kt_free_entry (context, &entry); -out: + if(ret == 0) { + ret = krb5_copy_keyblock(context, &entry.keyblock, out_key); + krb5_kt_free_entry(context, &entry); + } if(keytab == NULL) krb5_kt_close(context, real_keytab); @@ -840,7 +855,8 @@ krb5_rd_req_ctx(krb5_context context, krb5_keytab id = NULL, keytab = NULL; krb5_principal service = NULL; - *outctx = NULL; + if (outctx) + *outctx = NULL; o = calloc(1, sizeof(*o)); if (o == NULL) @@ -1021,6 +1037,12 @@ krb5_rd_req_ctx(krb5_context context, goto out; } + ret = krb5_ticket_get_authorization_data_type(context, o->ticket, + KRB5_AUTHDATA_KDC_ISSUED, + NULL); + if (ret == 0) + o->ticket->client->nameattrs->kdc_issued_verified = 1; + /* If there is a PAC, verify its server signature */ if (inctx == NULL || inctx->check_pac) { krb5_pac pac; @@ -1042,28 +1064,36 @@ krb5_rd_req_ctx(krb5_context context, o->ticket->client, o->keyblock, NULL); + if (ret == 0) + o->ticket->client->nameattrs->pac_verified = 1; if (ret == 0 && (context->flags & KRB5_CTX_F_REPORT_CANONICAL_CLIENT_NAME)) { krb5_error_code ret2; krb5_principal canon_name; ret2 = _krb5_pac_get_canon_principal(context, pac, &canon_name); if (ret2 == 0) { - krb5_free_principal(context, o->ticket->client); - o->ticket->client = canon_name; + free_Realm(&o->ticket->client->realm); + free_PrincipalName(&o->ticket->client->name); + ret = copy_Realm(&canon_name->realm, &o->ticket->client->realm); + if (ret == 0) + ret = copy_PrincipalName(&canon_name->name, &o->ticket->client->name); + krb5_free_principal(context, canon_name); } else if (ret2 != ENOENT) ret = ret2; } - krb5_pac_free(context, pac); - if (ret) + if (ret) { + krb5_pac_free(context, pac); goto out; + } + o->ticket->client->nameattrs->pac = pac; } else ret = 0; } out: - if (ret || outctx == NULL) { + if (ret || outctx == NULL) krb5_rd_req_out_ctx_free(context, o); - } else + else *outctx = o; free_AP_REQ(&ap_req); diff --git a/third_party/heimdal/lib/krb5/replay.c b/third_party/heimdal/lib/krb5/replay.c index d9c442bb27da..2fec8afd1043 100644 --- a/third_party/heimdal/lib/krb5/replay.c +++ b/third_party/heimdal/lib/krb5/replay.c @@ -220,8 +220,10 @@ krb5_rc_store(krb5_context context, } rk_cloexec_file(f); count = fread(&tmp, sizeof(ent), 1, f); - if(count != 1) + if (count != 1) { + fclose(f); return KRB5_RC_IO_UNKNOWN; + } t = ent.stamp - tmp.stamp; while(fread(&tmp, sizeof(ent), 1, f)){ if(tmp.stamp < t) diff --git a/third_party/heimdal/lib/krb5/salt-arcfour.c b/third_party/heimdal/lib/krb5/salt-arcfour.c index 38aaa25024e6..033128ed803d 100644 --- a/third_party/heimdal/lib/krb5/salt-arcfour.c +++ b/third_party/heimdal/lib/krb5/salt-arcfour.c @@ -47,10 +47,8 @@ ARCFOUR_string_to_key(krb5_context context, EVP_MD_CTX *m; m = EVP_MD_CTX_create(); - if (m == NULL) { - ret = krb5_enomem(context); - goto out; - } + if (m == NULL) + return krb5_enomem(context); EVP_DigestInit_ex(m, EVP_md4(), NULL); diff --git a/third_party/heimdal/lib/krb5/scache.c b/third_party/heimdal/lib/krb5/scache.c index 554f377125e3..7a39664946b8 100644 --- a/third_party/heimdal/lib/krb5/scache.c +++ b/third_party/heimdal/lib/krb5/scache.c @@ -276,9 +276,9 @@ make_dir(krb5_context context, const char *name) static krb5_error_code default_db(krb5_context context, const char *name, sqlite3 **db, char **file) { + krb5_error_code ret = 0; char *s = NULL; char *f = NULL; - int ret; if (file) *file = NULL; @@ -315,13 +315,24 @@ default_db(krb5_context context, const char *name, sqlite3 **db, char **file) #endif ret = make_dir(context, f); - if (ret == 0) - ret = sqlite3_open_v2(f, db, SQLITE_OPEN_READWRITE, NULL); - if (ret != SQLITE_OK) { - sqlite3_close(*db); - krb5_clear_error_message(context); - free(f); - return ENOENT; + if (ret == 0) { + int sret; + + sret = sqlite3_open_v2(f, db, SQLITE_OPEN_READWRITE, NULL); + if (sret != SQLITE_OK) { + if (*db) { + krb5_set_error_message(context, ENOENT, + N_("Error opening scache file %s: %s (%d)", ""), + f, sqlite3_errmsg(*db), sret); + sqlite3_close(*db); + *db = NULL; + } else + krb5_set_error_message(context, ENOENT, + N_("Error opening scache file %s: %s (%d)", ""), + f, sqlite3_errstr(sret), sret); + free(f); + return ENOENT; + } } #ifndef WIN32 @@ -341,7 +352,7 @@ default_db(krb5_context context, const char *name, sqlite3 **db, char **file) sqlite3_trace(*db, trace, NULL); #endif - return 0; + return ret; } static krb5_error_code @@ -435,10 +446,8 @@ scc_alloc(krb5_context context, name += sizeof("SCC:") - 1; if ((s->file = strdup(name)) == NULL) { - (void) krb5_enomem(context); - scc_free(s); - free(freeme); - return NULL; + ret = krb5_enomem(context); + goto out; } if ((subsidiary = strrchr(s->file, ':'))) { @@ -469,19 +478,23 @@ scc_alloc(krb5_context context, if (ret == 0 && s->file && s->sub && (asprintf(&s->name, "%s:%s", s->file, s->sub) < 0 || s->name == NULL)) ret = krb5_enomem(context); + + out: if (ret || s->file == NULL || s->sub == NULL || s->name == NULL) { scc_free(s); - free(freeme); - return NULL; + s = NULL; } + + free(freeme); return s; } static krb5_error_code open_database(krb5_context context, krb5_scache *s, int flags) { + krb5_error_code ret; struct stat st; - int ret; + int sret; if (!(flags & SQLITE_OPEN_CREATE) && stat(s->file, &st) == 0 && @@ -489,18 +502,20 @@ open_database(krb5_context context, krb5_scache *s, int flags) return ENOENT; ret = make_dir(context, s->file); - if (ret == 0) - ret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL); - if (ret) { + if (ret) + return ret; + sret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL); + if (sret != SQLITE_OK) { if (s->db) { krb5_set_error_message(context, ENOENT, - N_("Error opening scache file %s: %s", ""), - s->file, sqlite3_errmsg(s->db)); + N_("Error opening scache file %s: %s (%d)", ""), + s->file, sqlite3_errmsg(s->db), sret); sqlite3_close(s->db); s->db = NULL; } else krb5_set_error_message(context, ENOENT, - N_("malloc: out of memory", "")); + N_("Error opening scache file %s: %s (%d)", ""), + s->file, sqlite3_errstr(sret), sret); return ENOENT; } return 0; @@ -1270,24 +1285,22 @@ scc_remove_cred(krb5_context context, sqlite3_finalize(stmt); - if (id) { - ret = prepare_stmt(context, s->db, &stmt, - "DELETE FROM credentials WHERE oid=?"); - if (ret) - return ret; - sqlite3_bind_int(stmt, 1, credid); + ret = prepare_stmt(context, s->db, &stmt, + "DELETE FROM credentials WHERE oid=?"); + if (ret) + return ret; + sqlite3_bind_int(stmt, 1, credid); - do { - ret = sqlite3_step(stmt); - } while (ret == SQLITE_ROW); - sqlite3_finalize(stmt); - if (ret != SQLITE_DONE) { - ret = KRB5_CC_IO; - krb5_set_error_message(context, ret, - N_("failed to delete scache credental", "")); - } else - ret = 0; - } + do { + ret = sqlite3_step(stmt); + } while (ret == SQLITE_ROW); + sqlite3_finalize(stmt); + if (ret != SQLITE_DONE) { + ret = KRB5_CC_IO; + krb5_set_error_message(context, ret, + N_("failed to delete scache credental", "")); + } else + ret = 0; return ret; } diff --git a/third_party/heimdal/lib/krb5/send_to_kdc.c b/third_party/heimdal/lib/krb5/send_to_kdc.c index 704b095b5355..086f2edcd5db 100644 --- a/third_party/heimdal/lib/krb5/send_to_kdc.c +++ b/third_party/heimdal/lib/krb5/send_to_kdc.c @@ -176,7 +176,7 @@ struct krb5_sendto_ctx_data { unsigned int stid; }; -static void +static void KRB5_CALLCONV dealloc_sendto_ctx(void *ptr) { krb5_sendto_ctx ctx = (krb5_sendto_ctx)ptr; @@ -386,7 +386,7 @@ debug_host(krb5_context context, int level, struct host *host, const char *fmt, } -static void +static void HEIM_CALLCONV deallocate_host(void *ptr) { struct host *host = ptr; @@ -1180,7 +1180,7 @@ krb5_sendto_context(krb5_context context, action = KRB5_SENDTO_INITIAL; - while (action != KRB5_SENDTO_DONE && action != KRB5_SENDTO_FAILED) { + while (1) { krb5_krbhst_info *hi; switch (action) { @@ -1192,7 +1192,7 @@ krb5_sendto_context(krb5_context context, break; } action = KRB5_SENDTO_KRBHST; - /* FALLTHROUGH */ + fallthrough; case KRB5_SENDTO_KRBHST: if (ctx->krbhst == NULL) { ret = krb5_krbhst_init_flags(context, realm, type, @@ -1214,7 +1214,7 @@ krb5_sendto_context(krb5_context context, handle = heim_retain(ctx->krbhst); } action = KRB5_SENDTO_TIMEOUT; - /* FALLTHROUGH */ + fallthrough; case KRB5_SENDTO_TIMEOUT: /* @@ -1308,10 +1308,10 @@ krb5_sendto_context(krb5_context context, break; case KRB5_SENDTO_FAILED: ret = KRB5_KDC_UNREACH; - break; + goto out; case KRB5_SENDTO_DONE: ret = 0; - break; + goto out; default: heim_abort("invalid krb5_sendto_context state"); } diff --git a/third_party/heimdal/lib/krb5/sp800-108-kdf.c b/third_party/heimdal/lib/krb5/sp800-108-kdf.c index 37e06dec3e84..4a12067c68bd 100755 --- a/third_party/heimdal/lib/krb5/sp800-108-kdf.c +++ b/third_party/heimdal/lib/krb5/sp800-108-kdf.c @@ -73,7 +73,10 @@ _krb5_SP800_108_HMAC_KDF(krb5_context context, unsigned char tmp[4]; size_t len; - HMAC_Init_ex(&c, kdf_K1->data, kdf_K1->length, md, NULL); + if (HMAC_Init_ex(&c, kdf_K1->data, kdf_K1->length, md, NULL) == 0) { + HMAC_CTX_cleanup(&c); + return krb5_enomem(context); + } _krb5_put_int(tmp, i + 1, 4); HMAC_Update(&c, tmp, 4); diff --git a/third_party/heimdal/lib/krb5/store.c b/third_party/heimdal/lib/krb5/store.c index 6a287bdf950d..79f8e3adbab0 100644 --- a/third_party/heimdal/lib/krb5/store.c +++ b/third_party/heimdal/lib/krb5/store.c @@ -975,6 +975,10 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_store_string(krb5_storage *sp, const char *s) { krb5_data data; + + if (s == NULL) + return EINVAL; + data.length = strlen(s); data.data = rk_UNCONST(s); return krb5_store_data(sp, data); @@ -1025,9 +1029,13 @@ krb5_ret_string(krb5_storage *sp, KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_store_stringz(krb5_storage *sp, const char *s) { - size_t len = strlen(s) + 1; + size_t len; ssize_t ret; + if (s == NULL) + return EINVAL; + + len = strlen(s) + 1; ret = sp->store(sp, s, len); if(ret < 0) return ret; @@ -1089,9 +1097,13 @@ krb5_ret_stringz(krb5_storage *sp, KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_store_stringnl(krb5_storage *sp, const char *s) { - size_t len = strlen(s); + size_t len; ssize_t ret; + if (s == NULL) + return EINVAL; + + len = strlen(s); ret = sp->store(sp, s, len); if(ret < 0) return ret; @@ -1370,16 +1382,18 @@ krb5_ret_times(krb5_storage *sp, krb5_times *times) { int ret; int32_t tmp; + ret = krb5_ret_int32(sp, &tmp); + if (ret) return ret; times->authtime = tmp; - if(ret) return ret; ret = krb5_ret_int32(sp, &tmp); + if (ret) return ret; times->starttime = tmp; - if(ret) return ret; ret = krb5_ret_int32(sp, &tmp); + if (ret) return ret; times->endtime = tmp; - if(ret) return ret; ret = krb5_ret_int32(sp, &tmp); + if (ret) return ret; times->renew_till = tmp; return ret; } diff --git a/third_party/heimdal/lib/krb5/store_emem.c b/third_party/heimdal/lib/krb5/store_emem.c index da66e5fa75e5..6a3908f74635 100644 --- a/third_party/heimdal/lib/krb5/store_emem.c +++ b/third_party/heimdal/lib/krb5/store_emem.c @@ -33,6 +33,7 @@ #include "krb5_locl.h" #include "store-int.h" +#include typedef struct emem_storage{ unsigned char *base; @@ -45,10 +46,12 @@ static ssize_t emem_fetch(krb5_storage *sp, void *data, size_t size) { emem_storage *s = (emem_storage*)sp->data; + + assert(data != NULL && s->ptr != NULL); + if((size_t)(s->base + s->len - s->ptr) < size) size = s->base + s->len - s->ptr; - if (data != NULL) - memmove(data, s->ptr, size); + memmove(data, s->ptr, size); sp->seek(sp, size, SEEK_CUR); return size; } @@ -56,7 +59,17 @@ emem_fetch(krb5_storage *sp, void *data, size_t size) static ssize_t emem_store(krb5_storage *sp, const void *data, size_t size) { - emem_storage *s = (emem_storage*)sp->data; + emem_storage *s; + + if (size == 0) { + sp->seek(sp, 0, SEEK_CUR); + return 0; + } + + s = (emem_storage*)sp->data; + + assert(data != NULL); + if(size > (size_t)(s->base + s->size - s->ptr)){ void *base; size_t sz, off; @@ -71,8 +84,7 @@ emem_store(krb5_storage *sp, const void *data, size_t size) s->base = base; s->ptr = (unsigned char*)base + off; } - if (data != NULL) - memmove(s->ptr, data, size); + memmove(s->ptr, data, size); sp->seek(sp, size, SEEK_CUR); return size; } @@ -141,6 +153,9 @@ static void emem_free(krb5_storage *sp) { emem_storage *s = sp->data; + + assert(s->base != NULL); + memset_s(s->base, s->len, 0, s->len); free(s->base); } diff --git a/third_party/heimdal/lib/krb5/store_stdio.c b/third_party/heimdal/lib/krb5/store_stdio.c index 80323e1d8f26..dddaa9245782 100644 --- a/third_party/heimdal/lib/krb5/store_stdio.c +++ b/third_party/heimdal/lib/krb5/store_stdio.c @@ -137,6 +137,8 @@ stdio_trunc(krb5_storage * sp, off_t offset) if (fflush(F(sp)) == EOF) return errno; tmpoff = ftello(F(sp)); + if (tmpoff < 0) + return errno; if (tmpoff > offset) tmpoff = offset; if (ftruncate(fileno(F(sp)), offset) == -1) diff --git a/third_party/heimdal/lib/krb5/test_alname.c b/third_party/heimdal/lib/krb5/test_alname.c index 120143e51e7b..36775adef1b4 100644 --- a/third_party/heimdal/lib/krb5/test_alname.c +++ b/third_party/heimdal/lib/krb5/test_alname.c @@ -81,8 +81,8 @@ test_alname(krb5_context context, krb5_const_realm realm, } krb5_err(context, 1, ret, "krb5_aname_to_localname: %s -> %s", princ, localuser); - free(princ); } + free(princ); if (strcmp(localname, localuser) != 0) { if (ok) diff --git a/third_party/heimdal/lib/krb5/test_ap-req.c b/third_party/heimdal/lib/krb5/test_ap-req.c index c3aaef3606a7..0fd107833976 100644 --- a/third_party/heimdal/lib/krb5/test_ap-req.c +++ b/third_party/heimdal/lib/krb5/test_ap-req.c @@ -153,6 +153,7 @@ test_ap(krb5_context context, krb5_err(context, 1, ret, "pac parse"); krb5_pac_free(context, pac); + krb5_data_free(&data); } krb5_free_ticket(context, ticket); diff --git a/third_party/heimdal/lib/krb5/test_cc.c b/third_party/heimdal/lib/krb5/test_cc.c index 213bb0780d9b..0ca582eaaca6 100644 --- a/third_party/heimdal/lib/krb5/test_cc.c +++ b/third_party/heimdal/lib/krb5/test_cc.c @@ -670,6 +670,8 @@ test_move(krb5_context context, const char *type) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_move(context, fromid, toid); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_move"); ret = krb5_cc_get_principal(context, toid, &p2); if (ret) @@ -916,7 +918,7 @@ test_cccol_dcache(krb5_context context) ret = test_cccol(context, dcc, &what); free(dcc); if (ret) - krb5_err(context, 1, errno, "%s", what); + krb5_err(context, 1, ret, "%s", what); } static void @@ -1117,9 +1119,6 @@ main(int argc, char **argv) test_move(context, krb5_cc_type_file); test_move(context, krb5_cc_type_memory); -#ifdef HAVE_KCM - test_move(context, krb5_cc_type_kcm); -#endif test_move(context, krb5_cc_type_scc); #if 0 test_move(context, krb5_cc_type_dcc); @@ -1204,6 +1203,9 @@ main(int argc, char **argv) ret = test_cccol(context, fname, &what); if (ret) krb5_err(context, 1, ret, "%s", what); + free(config); + free(fname); + free(d); } krb5_free_context(context); diff --git a/third_party/heimdal/lib/krb5/test_hostname.c b/third_party/heimdal/lib/krb5/test_hostname.c index fbdb5c9c322a..f722353f664a 100644 --- a/third_party/heimdal/lib/krb5/test_hostname.c +++ b/third_party/heimdal/lib/krb5/test_hostname.c @@ -48,11 +48,11 @@ expand_hostname(krb5_context context, const char *host) if (ret) krb5_err(context, 1, ret, "krb5_expand_hostname(%s)", host); - free(h); - if (debug_flag) printf("hostname: %s -> %s\n", host, h); + free(h); + ret = krb5_expand_hostname_realms(context, host, &h, &r); if (ret) krb5_err(context, 1, ret, "krb5_expand_hostname_realms(%s)", host); diff --git a/third_party/heimdal/lib/krb5/test_rfc3961.c b/third_party/heimdal/lib/krb5/test_rfc3961.c index f1255948fc46..ed8ee9b5f3f4 100644 --- a/third_party/heimdal/lib/krb5/test_rfc3961.c +++ b/third_party/heimdal/lib/krb5/test_rfc3961.c @@ -133,6 +133,7 @@ time_hmac_evp(krb5_context context, size_t size, int iterations) free(buf); krb5_free_keyblock_contents(context, &key); + krb5_crypto_destroy(context, crypto); } static void diff --git a/third_party/heimdal/lib/krb5/test_set_kvno0.c b/third_party/heimdal/lib/krb5/test_set_kvno0.c index 526c240f1c4b..0c7e6b447ae8 100644 --- a/third_party/heimdal/lib/krb5/test_set_kvno0.c +++ b/third_party/heimdal/lib/krb5/test_set_kvno0.c @@ -119,8 +119,11 @@ main(int argc, char **argv) during = "decode_Ticket"; memset(&t, 0, sizeof (t)); ret = decode_Ticket(cred.ticket.data, cred.ticket.length, &t, &len); - if (ret == ASN1_MISSING_FIELD) + if (ret == ASN1_MISSING_FIELD) { + krb5_free_cred_contents(context, &cred); + memset(&cred, 0, sizeof (cred)); continue; + } if (ret) goto err; if (t.enc_part.kvno) { *t.enc_part.kvno = 0; diff --git a/third_party/heimdal/lib/krb5/ticket.c b/third_party/heimdal/lib/krb5/ticket.c index 11e4e84963b2..e2f2ab2085c6 100644 --- a/third_party/heimdal/lib/krb5/ticket.c +++ b/third_party/heimdal/lib/krb5/ticket.c @@ -204,13 +204,38 @@ krb5_ticket_get_flags(krb5_context context, return TicketFlags2int(ticket->ticket.flags); } +/* + * Find an authz-data element in the given `ad'. If `failp', then validate any + * containing AD-KDC-ISSUED's keyed checksum with the `sessionkey' (if given). + * + * All AD-KDC-ISSUED will be validated (if requested) even when `type' is + * `KRB5_AUTHDATA_KDC_ISSUED'. + * + * Only the first matching element will be output (via `data'). + * + * Note that all AD-KDC-ISSUEDs found while traversing the authz-data will be + * validated, though only the first one will be returned. + * + * XXX We really need a better interface though. First, forget AD-AND-OR -- + * just remove it. Second, probably forget AD-KDC-ISSUED, but still, between + * that, the PAC, and the CAMMAC, we need an interface that can: + * + * a) take the derived keys instead of the service key or the session key, + * b) can indicate whether the element was marked critical, + * c) can indicate whether the element was authenticated to the KDC, + * d) can iterate over all the instances found (if more than one is found). + * + * Also, we need to know here if the authz-data is from a Ticket or from an + * Authenticator -- if the latter then we must refuse to find AD-KDC-ISSUED / + * PAC / CAMMAC or anything of the sort, ever. + */ static int find_type_in_ad(krb5_context context, int type, - krb5_data *data, + krb5_data *data, /* optional */ krb5_boolean *found, - krb5_boolean failp, - krb5_keyblock *sessionkey, + krb5_boolean failp, /* validate AD-KDC-ISSUED */ + krb5_keyblock *sessionkey, /* ticket session key */ const AuthorizationData *ad, int level) { @@ -233,14 +258,19 @@ find_type_in_ad(krb5_context context, */ for (i = 0; i < ad->len; i++) { if (!*found && ad->val[i].ad_type == type) { - ret = der_copy_octet_string(&ad->val[i].ad_data, data); - if (ret) { - krb5_set_error_message(context, ret, - N_("malloc: out of memory", "")); - goto out; - } + if (data) { + ret = der_copy_octet_string(&ad->val[i].ad_data, data); + if (ret) { + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto out; + } + } *found = TRUE; - continue; + if (type != KRB5_AUTHDATA_KDC_ISSUED || + !failp || !sessionkey || !sessionkey->keyvalue.length) + continue; + /* else go on to validate the AD-KDC-ISSUED's keyed checksum */ } switch (ad->val[i].ad_type) { case KRB5_AUTHDATA_IF_RELEVANT: { @@ -263,7 +293,6 @@ find_type_in_ad(krb5_context context, goto out; break; } -#if 0 /* XXX test */ case KRB5_AUTHDATA_KDC_ISSUED: { AD_KDCIssued child; @@ -278,7 +307,7 @@ find_type_in_ad(krb5_context context, ret); goto out; } - if (failp) { + if (failp && sessionkey && sessionkey->keyvalue.length) { krb5_boolean valid; krb5_data buf; size_t len; @@ -306,7 +335,12 @@ find_type_in_ad(krb5_context context, free_AD_KDCIssued(&child); goto out; } - } + } else if (failp) { + krb5_clear_error_message(context); + ret = ENOENT; + free_AD_KDCIssued(&child); + goto out; + } ret = find_type_in_ad(context, type, data, found, failp, sessionkey, &child.elements, level + 1); free_AD_KDCIssued(&child); @@ -314,7 +348,6 @@ find_type_in_ad(krb5_context context, goto out; break; } -#endif case KRB5_AUTHDATA_AND_OR: if (!failp) break; @@ -338,7 +371,8 @@ find_type_in_ad(krb5_context context, out: if (ret) { if (*found) { - krb5_data_free(data); + if (data) + krb5_data_free(data); *found = 0; } } @@ -355,7 +389,8 @@ _krb5_get_ad(krb5_context context, krb5_boolean found = FALSE; krb5_error_code ret; - krb5_data_zero(data); + if (data) + krb5_data_zero(data); if (ad == NULL) { krb5_set_error_message(context, ENOENT, @@ -399,7 +434,8 @@ krb5_ticket_get_authorization_data_type(krb5_context context, krb5_error_code ret; krb5_boolean found = FALSE; - krb5_data_zero(data); + if (data) + krb5_data_zero(data); ad = ticket->ticket.authorization_data; if (ticket->ticket.authorization_data == NULL) { @@ -752,9 +788,9 @@ _krb5_extract_ticket(krb5_context context, /* compare client and save */ ret = _krb5_principalname2krb5_principal(context, - &tmp_principal, - rep->kdc_rep.cname, - rep->kdc_rep.crealm); + &tmp_principal, + rep->kdc_rep.cname, + rep->kdc_rep.crealm); if (ret) goto out; @@ -785,12 +821,19 @@ _krb5_extract_ticket(krb5_context context, creds->client = tmp_principal; /* check server referral and save principal */ - ret = _krb5_principalname2krb5_principal (context, - &tmp_principal, - rep->enc_part.sname, - rep->enc_part.srealm); + ret = _krb5_kdcrep2krb5_principal(context, &tmp_principal, &rep->enc_part); if (ret) goto out; + + tmp_principal->nameattrs->peer_realm = + calloc(1, sizeof(tmp_principal->nameattrs->peer_realm[0])); + if (tmp_principal->nameattrs->peer_realm == NULL) { + ret = krb5_enomem(context); + goto out; + } + ret = copy_Realm(&creds->client->realm, tmp_principal->nameattrs->peer_realm); + if (ret) goto out; + if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ ret = check_server_referral(context, rep, diff --git a/third_party/heimdal/lib/krb5/transited.c b/third_party/heimdal/lib/krb5/transited.c index 35c00e65add4..484fd398c296 100644 --- a/third_party/heimdal/lib/krb5/transited.c +++ b/third_party/heimdal/lib/krb5/transited.c @@ -274,13 +274,17 @@ decode_realms(krb5_context context, } if(tr[i] == ','){ tmp = malloc(tr + i - start + 1); - if(tmp == NULL) + if(tmp == NULL) { + free_realms(*realms); + *realms = NULL; return krb5_enomem(context); + } memcpy(tmp, start, tr + i - start); tmp[tr + i - start] = '\0'; r = make_realm(tmp); if(r == NULL){ free_realms(*realms); + *realms = NULL; return krb5_enomem(context); } *realms = append_realm(*realms, r); @@ -289,7 +293,8 @@ decode_realms(krb5_context context, } tmp = malloc(tr + i - start + 1); if(tmp == NULL){ - free(*realms); + free_realms(*realms); + *realms = NULL; return krb5_enomem(context); } memcpy(tmp, start, tr + i - start); @@ -297,6 +302,7 @@ decode_realms(krb5_context context, r = make_realm(tmp); if(r == NULL){ free_realms(*realms); + *realms = NULL; return krb5_enomem(context); } *realms = append_realm(*realms, r); @@ -353,8 +359,6 @@ krb5_domain_x500_decode(krb5_context context, { char **R; R = malloc((*num_realms + 1) * sizeof(*R)); - if (R == NULL) - return krb5_enomem(context); *realms = R; while(r){ *R++ = r->realm; @@ -362,6 +366,8 @@ krb5_domain_x500_decode(krb5_context context, free(r); r = p; } + if (*realms == NULL) + return krb5_enomem(context); } return 0; } @@ -621,11 +627,12 @@ krb5_check_transited(krb5_context context, return ret; for (i = 0; i < num_realms; i++) { - for (j = 0; j < num_capath; ++j) { + for (j = 0; j < num_capath && capath[j]; ++j) { + /* `capath[j]' can't be NULL, but compilers be dumb */ if (strcmp(realms[i], capath[j]) == 0) break; } - if (j == num_capath) { + if (j == num_capath || !capath[j]) { _krb5_free_capath(context, capath); krb5_set_error_message (context, KRB5KRB_AP_ERR_ILL_CR_TKT, N_("no transit allowed " diff --git a/third_party/heimdal/lib/krb5/verify_user.c b/third_party/heimdal/lib/krb5/verify_user.c index 663196b29b15..c6ead8e42b2d 100644 --- a/third_party/heimdal/lib/krb5/verify_user.c +++ b/third_party/heimdal/lib/krb5/verify_user.c @@ -40,7 +40,7 @@ verify_common (krb5_context context, krb5_keytab keytab, krb5_boolean secure, const char *service, - krb5_creds cred) + krb5_creds *cred) { krb5_error_code ret; krb5_principal server; @@ -56,7 +56,7 @@ verify_common (krb5_context context, krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, secure); ret = krb5_verify_init_creds(context, - &cred, + cred, server, keytab, NULL, @@ -71,12 +71,11 @@ verify_common (krb5_context context, if(ret == 0){ ret = krb5_cc_initialize(context, id, principal); if(ret == 0){ - ret = krb5_cc_store_cred(context, id, &cred); + ret = krb5_cc_store_cred(context, id, cred); } if(ccache == NULL) krb5_cc_close(context, id); } - krb5_free_cred_contents(context, &cred); return ret; } @@ -172,10 +171,12 @@ verify_user_opt_int(krb5_context context, if(ret) return ret; #define OPT(V, D) ((vopt && (vopt->V)) ? (vopt->V) : (D)) - return verify_common (context, principal, OPT(ccache, NULL), + ret = verify_common (context, principal, OPT(ccache, NULL), OPT(keytab, NULL), vopt ? vopt->secure : TRUE, - OPT(service, "host"), cred); + OPT(service, "host"), &cred); #undef OPT + krb5_free_cred_contents(context, &cred); + return ret; } KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL diff --git a/third_party/heimdal/lib/krb5/version-script.map b/third_party/heimdal/lib/krb5/version-script.map index ce2783c35752..f6278e9ecbf6 100644 --- a/third_party/heimdal/lib/krb5/version-script.map +++ b/third_party/heimdal/lib/krb5/version-script.map @@ -24,6 +24,8 @@ HEIMDAL_KRB5_2.0 { krb5_appdefault_time; krb5_append_addresses; krb5_auth_con_addflags; + krb5_auth_con_add_AuthorizationData; + krb5_auth_con_add_AuthorizationDataIfRelevant; krb5_auth_con_free; krb5_auth_con_genaddrs; krb5_auth_con_generatelocalsubkey; @@ -493,6 +495,7 @@ HEIMDAL_KRB5_2.0 { krb5_pac_add_buffer; krb5_pac_free; krb5_pac_get_buffer; + _krb5_pac_get_buffer_by_name; krb5_pac_get_kdc_checksum_info; krb5_pac_get_types; krb5_pac_init; @@ -739,6 +742,7 @@ HEIMDAL_KRB5_2.0 { krb5_cccol_cursor_new; krb5_cccol_cursor_next; krb5_cccol_cursor_free; + krb5_cccol_get_default_ccname; # com_err error tables initialize_krb5_error_table_r; @@ -828,6 +832,8 @@ HEIMDAL_KRB5_2.0 { _krb5_plugin_run_f; _krb5_principal2principalname; _krb5_principalname2krb5_principal; + _krb5_kdcrep2krb5_principal; + _krb5_ticket2krb5_principal; _krb5_put_int; _krb5_s4u2self_to_checksumdata; _krb5_HMAC_MD5_checksum; @@ -842,6 +848,7 @@ HEIMDAL_KRB5_2.0 { krb5_init_creds_init; krb5_init_creds_set_service; krb5_init_creds_set_fast_anon_pkinit; + _krb5_init_creds_set_fast_anon_pkinit_optimistic; krb5_init_creds_set_fast_ccache; krb5_init_creds_set_keytab; krb5_init_creds_set_kdc_hostname; diff --git a/third_party/heimdal/lib/ntlm/digest.c b/third_party/heimdal/lib/ntlm/digest.c index a1d6b5f3a649..761e1f497fcb 100644 --- a/third_party/heimdal/lib/ntlm/digest.c +++ b/third_party/heimdal/lib/ntlm/digest.c @@ -471,7 +471,7 @@ heim_digest_generate_challenge(heim_digest_t context) break; case HEIM_DIGEST_TYPE_AUTO: context->type = HEIM_DIGEST_TYPE_RFC2831; - /* FALLTHROUGH */ + fallthrough; case HEIM_DIGEST_TYPE_RFC2831: asprintf(&challenge, "realm=\"%s\",nonce=\"%s\",qop=\"%s\",algorithm=md5-sess,charset=utf-8,maxbuf=%s", context->serverRealm, context->serverNonce, context->serverQOP, context->serverMaxbuf); diff --git a/third_party/heimdal/lib/ntlm/ntlm.c b/third_party/heimdal/lib/ntlm/ntlm.c index 9670a9718301..d75752ea0007 100644 --- a/third_party/heimdal/lib/ntlm/ntlm.c +++ b/third_party/heimdal/lib/ntlm/ntlm.c @@ -354,7 +354,7 @@ ret_string(krb5_storage *sp, int ucs2, size_t len, char **s) utf8len += 1; *s = malloc(utf8len); - if (s == NULL) { + if (*s == NULL) { ret = ENOMEM; goto out; } @@ -1324,7 +1324,10 @@ heim_ntlm_v2_base_session(void *key, size_t len, /* Note: key is the NTLMv2 key */ HMAC_CTX_init(&c); - HMAC_Init_ex(&c, key, len, EVP_md5(), NULL); + if (HMAC_Init_ex(&c, key, len, EVP_md5(), NULL) == 0) { + HMAC_CTX_cleanup(&c); + return ENOMEM; + } HMAC_Update(&c, ntlmResponse->data, 16); HMAC_Final(&c, session->data, &hmaclen); HMAC_CTX_cleanup(&c); @@ -1443,7 +1446,7 @@ heim_ntlm_build_ntlm2_master(void *key, size_t len, ret = heim_ntlm_v2_base_session(key, len, blob, &sess); if (ret) - return ret; + return ret; ret = heim_ntlm_keyex_wrap(&sess, session, master); heim_ntlm_free_buf(&sess); @@ -1523,25 +1526,26 @@ heim_ntlm_ntlmv2_key(const void *key, size_t len, { int ret; unsigned int hmaclen; + struct ntlm_buf buf; HMAC_CTX c; HMAC_CTX_init(&c); - HMAC_Init_ex(&c, key, len, EVP_md5(), NULL); - { - struct ntlm_buf buf; - /* uppercase username and turn it into ucs2-le */ - ret = ascii2ucs2le(username, 1, &buf); - if (ret) - goto out; - HMAC_Update(&c, buf.data, buf.length); - free(buf.data); - /* turn target into ucs2-le */ - ret = ascii2ucs2le(target, upper_case_target, &buf); - if (ret) - goto out; - HMAC_Update(&c, buf.data, buf.length); - free(buf.data); + if (HMAC_Init_ex(&c, key, len, EVP_md5(), NULL) == 0) { + ret = ENOMEM; + goto out; } + /* uppercase username and turn it into ucs2-le */ + ret = ascii2ucs2le(username, 1, &buf); + if (ret) + goto out; + HMAC_Update(&c, buf.data, buf.length); + free(buf.data); + /* turn target into ucs2-le */ + ret = ascii2ucs2le(target, upper_case_target, &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); @@ -1599,6 +1603,7 @@ heim_ntlm_calculate_lm2(const void *key, size_t len, struct ntlm_buf *answer) { unsigned char clientchallenge[8]; + krb5_error_code ret; if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1) return HNTLM_ERR_RAND; @@ -1612,12 +1617,12 @@ heim_ntlm_calculate_lm2(const void *key, size_t len, return ENOMEM; answer->length = 24; - heim_ntlm_derive_ntlm2_sess(ntlmv2, clientchallenge, 8, - serverchallenge, answer->data); - - memcpy(((unsigned char *)answer->data) + 16, clientchallenge, 8); + ret = heim_ntlm_derive_ntlm2_sess(ntlmv2, clientchallenge, 8, + serverchallenge, answer->data); + if (ret == 0) + memcpy(((unsigned char *)answer->data) + 16, clientchallenge, 8); - return 0; + return ret; } @@ -1695,7 +1700,10 @@ heim_ntlm_calculate_ntlm2(const void *key, size_t len, krb5_storage_free(sp); sp = NULL; - heim_ntlm_derive_ntlm2_sess(ntlmv2, data.data, data.length, serverchallenge, ntlmv2answer); + ret = heim_ntlm_derive_ntlm2_sess(ntlmv2, data.data, data.length, + serverchallenge, ntlmv2answer); + if (ret) + return ret; sp = krb5_storage_emem(); if (sp == NULL) { @@ -1809,10 +1817,13 @@ verify_ntlm2(const void *key, size_t len, goto out; } - heim_ntlm_derive_ntlm2_sess(ntlmv2, - ((unsigned char *)answer->data) + 16, answer->length - 16, - serverchallenge, - serveranswer); + ret = heim_ntlm_derive_ntlm2_sess(ntlmv2, + ((unsigned char *)answer->data) + 16, + answer->length - 16, + serverchallenge, + serveranswer); + if (ret) + goto out; if (memcmp(serveranswer, clientanswer, 16) != 0) { heim_ntlm_free_buf(infotarget); @@ -1995,7 +2006,7 @@ heim_ntlm_calculate_ntlm2_sess_hash(const unsigned char clnt_nonce[8], * @ingroup ntlm_core */ -void +int heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey[16], const unsigned char *clnt_nonce, size_t clnt_nonce_length, const unsigned char svr_chal[8], @@ -2006,10 +2017,14 @@ heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey[16], /* HMAC(Ksession, serverchallenge || clientchallenge) */ HMAC_CTX_init(&c); - HMAC_Init_ex(&c, sessionkey, 16, EVP_md5(), NULL); + if (HMAC_Init_ex(&c, sessionkey, 16, EVP_md5(), NULL) == 0) { + HMAC_CTX_cleanup(&c); + return ENOMEM; + } HMAC_Update(&c, svr_chal, 8); HMAC_Update(&c, clnt_nonce, clnt_nonce_length); HMAC_Final(&c, derivedkey, &hmaclen); HMAC_CTX_cleanup(&c); memset(&c, 0, sizeof(c)); + return 0; } diff --git a/third_party/heimdal/lib/otp/otp_md.c b/third_party/heimdal/lib/otp/otp_md.c index 1d6fe9594373..9338a204def5 100644 --- a/third_party/heimdal/lib/otp/otp_md.c +++ b/third_party/heimdal/lib/otp/otp_md.c @@ -92,8 +92,6 @@ otp_md_init (OtpKey key, char *p; int len; - ctx = EVP_MD_CTX_create(); - len = strlen(pwd) + strlen(seed); p = malloc (len + 1); if (p == NULL) @@ -102,6 +100,8 @@ otp_md_init (OtpKey key, strlwr (p); strlcat (p, pwd, len + 1); + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, md, NULL); EVP_DigestUpdate(ctx, p, len); EVP_DigestFinal_ex(ctx, res, NULL); diff --git a/third_party/heimdal/lib/roken/Makefile.am b/third_party/heimdal/lib/roken/Makefile.am index a6168f944d47..35d753204e79 100644 --- a/third_party/heimdal/lib/roken/Makefile.am +++ b/third_party/heimdal/lib/roken/Makefile.am @@ -21,7 +21,7 @@ AM_CPPFLAGS += -I$(DBHEADER) endif bin_PROGRAMS = rkvis rkbase32 rkbase64 -noinst_PROGRAMS = snprintf-test resolve-test rkpty test-detach test-auxval rtbl +noinst_PROGRAMS = snprintf-test resolve-test rkpty test-detach test-auxval rtbl timeval CHECK_LOCAL = snprintf-test resolve-test rkpty make-roken @@ -40,6 +40,7 @@ check_PROGRAMS = \ parse_time-test \ snprintf-test \ strpftime-test \ + timeval \ tsearch-test TESTS = $(check_PROGRAMS) @@ -89,6 +90,9 @@ else vis_h = vis.h endif +timeval_SOURCES = timeval.c +timeval_CPPFLAGS = -DTEST + rkvis_SOURCES = vis.c $(vis_h) vis-extras.h rkvis_CPPFLAGS = -DTEST diff --git a/third_party/heimdal/lib/roken/base32-test.c b/third_party/heimdal/lib/roken/base32-test.c index bea2866e47d3..e30c193c478e 100644 --- a/third_party/heimdal/lib/roken/base32-test.c +++ b/third_party/heimdal/lib/roken/base32-test.c @@ -66,7 +66,8 @@ main(int argc, char **argv) for(t = tests; t->data; t++) { char *str; int len; - len = rk_base32_encode(t->data, t->len, &str, t->preserve_order); + + (void) rk_base32_encode(t->data, t->len, &str, t->preserve_order); if (strcmp(str, t->result) != 0) { fprintf(stderr, "failed test %d: %s != %s\n", numtest, str, t->result); diff --git a/third_party/heimdal/lib/roken/base32.c b/third_party/heimdal/lib/roken/base32.c index 638ec2925f2e..ef74336d70a6 100644 --- a/third_party/heimdal/lib/roken/base32.c +++ b/third_party/heimdal/lib/roken/base32.c @@ -100,10 +100,10 @@ rk_base32_encode(const void *data, int size, char **str, enum rk_base32_flags fl p[6] = chars[(c & 0x0000000000000003e0ULL) >> 5]; p[7] = chars[(c & 0x00000000000000001fULL) >> 0]; switch (i - size) { - case 4: p[2] = p[3] = '='; /*fallthrough*/ - case 3: p[4] = '='; /*fallthrough*/ - case 2: p[5] = p[6] = '='; /*fallthrough*/ - case 1: p[7] = '='; /*fallthrough*/ + case 4: p[2] = p[3] = '='; fallthrough; + case 3: p[4] = '='; fallthrough; + case 2: p[5] = p[6] = '='; fallthrough; + case 1: p[7] = '='; fallthrough; default: break; } p += 8; @@ -271,7 +271,7 @@ main(int argc, char **argv) } else { void *d; - if ((ret = rk_undumpdata(argv[0], &d, &bufsz))) + if ((errno = rk_undumpdata(argv[0], &d, &bufsz))) err(1, "Could not read %s", argv[0]); buflen = bufsz; buf = d; @@ -298,7 +298,7 @@ main(int argc, char **argv) if (fwrite(d, ret, 1, stdout) != 1) err(1, "Could not write decoded data"); free(d); - } else { + } else if (buf) { /* buf can be NULL if we read from an empty file */ char *e; if ((ret = rk_base32_encode(buf, buflen, &e, flags)) < 0) diff --git a/third_party/heimdal/lib/roken/base64-test.c b/third_party/heimdal/lib/roken/base64-test.c index 86cccbb1d4f9..8fb3f528001f 100644 --- a/third_party/heimdal/lib/roken/base64-test.c +++ b/third_party/heimdal/lib/roken/base64-test.c @@ -58,7 +58,8 @@ main(int argc, char **argv) for(t = tests; t->data; t++) { char *str; int len; - len = rk_base64_encode(t->data, t->len, &str); + + (void) rk_base64_encode(t->data, t->len, &str); if(strcmp(str, t->result) != 0) { fprintf(stderr, "failed test %d: %s != %s\n", numtest, str, t->result); diff --git a/third_party/heimdal/lib/roken/base64.c b/third_party/heimdal/lib/roken/base64.c index a6dacdd1d294..582d183bcf73 100644 --- a/third_party/heimdal/lib/roken/base64.c +++ b/third_party/heimdal/lib/roken/base64.c @@ -214,7 +214,7 @@ main(int argc, char **argv) err(1, "Could not read stdin"); } else { void *d; - if ((ret = rk_undumpdata(argv[0], &d, &bufsz))) + if ((errno = rk_undumpdata(argv[0], &d, &bufsz))) err(1, "Could not read %s", argv[0]); buflen = bufsz; buf = d; @@ -241,7 +241,7 @@ main(int argc, char **argv) if (fwrite(d, ret, 1, stdout) != 1) err(1, "Could not write decoded data"); free(d); - } else { + } else if (buf) { /* buf can be NULL if we read from an empty file */ char *e; if ((ret = rk_base64_encode(buf, buflen, &e)) < 0) diff --git a/third_party/heimdal/lib/roken/copyhostent.c b/third_party/heimdal/lib/roken/copyhostent.c index 4ed630210fc8..9b9dba2aea59 100644 --- a/third_party/heimdal/lib/roken/copyhostent.c +++ b/third_party/heimdal/lib/roken/copyhostent.c @@ -40,7 +40,7 @@ */ ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL -copyhostent (const struct hostent *h) +rk_copyhostent(const struct hostent *h) { struct hostent *res; char **p; @@ -96,4 +96,3 @@ copyhostent (const struct hostent *h) } return res; } - diff --git a/third_party/heimdal/lib/roken/detach.c b/third_party/heimdal/lib/roken/detach.c index 36e6cda1e027..4a00682511fa 100644 --- a/third_party/heimdal/lib/roken/detach.c +++ b/third_party/heimdal/lib/roken/detach.c @@ -75,7 +75,8 @@ roken_detach_prep(int argc, char **argv, char *special_arg) if (pipefds[1] == -1) err(1, "Out of memory"); #else - fcntl(pipefds[1], F_SETFD, fcntl(pipefds[1], F_GETFD & ~(O_CLOEXEC))); + (void) fcntl(pipefds[1], F_SETFD, + fcntl(pipefds[1], F_GETFD & ~(O_CLOEXEC))); #endif if (snprintf(fildes, sizeof(fildes), "%d", pipefds[1]) >= sizeof(fildes)) diff --git a/third_party/heimdal/lib/roken/dirent-test.c b/third_party/heimdal/lib/roken/dirent-test.c index f1035a1aed6a..dc4518ad5b04 100644 --- a/third_party/heimdal/lib/roken/dirent-test.c +++ b/third_party/heimdal/lib/roken/dirent-test.c @@ -28,7 +28,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * **********************************************************************/ - +#include #include #include #include @@ -148,7 +148,7 @@ int teardown_test(void) strcmp(dirname + len + 1 - sizeof(TESTDIR)/sizeof(char), TESTDIR) == 0) { - /* fallthrough */ + fallthrough; } else { /* did we create the directory? */ @@ -162,7 +162,7 @@ int teardown_test(void) fprintf(stderr, "Can't change to test directory. Aborting cleanup.\n"); return -1; } else { - /* fallthrough */ + fallthrough; } } else { return -1; diff --git a/third_party/heimdal/lib/roken/environment.c b/third_party/heimdal/lib/roken/environment.c index 64c354d62bbd..a14f27b8a931 100644 --- a/third_party/heimdal/lib/roken/environment.c +++ b/third_party/heimdal/lib/roken/environment.c @@ -62,7 +62,8 @@ find_var(char **env, char *assignment, size_t len) static int read_env_file(FILE *F, char ***env, int *assigned) { - int idx = 0; + size_t alloced = 0; + size_t idx = 0; int i; char **l; char buf[BUFSIZ], *p, *r; @@ -71,8 +72,11 @@ read_env_file(FILE *F, char ***env, int *assigned) *assigned = 0; - for(idx = 0; *env != NULL && (*env)[idx] != NULL; idx++); l = *env; + for (idx = 0; l != NULL && l[idx] != NULL; idx++) + ; + if (l) + alloced = idx + 1; /* This is somewhat more relaxed on what it accepts then * Wietses sysv_environ from K4 was... @@ -90,7 +94,11 @@ read_env_file(FILE *F, char ***env, int *assigned) continue; if((i = find_var(l, p, r - p + 1)) >= 0) { - char *val = strdup(p); + char *val; + + if ((size_t)i >= alloced) + continue; /* Doesn't happen (fix scan-build noise) */ + val = strdup(p); if(val == NULL) { ret = ENOMEM; break; @@ -114,6 +122,7 @@ read_env_file(FILE *F, char ***env, int *assigned) break; } l[++idx] = NULL; + alloced = idx + 1; (*assigned)++; } if(ferror(F)) diff --git a/third_party/heimdal/lib/roken/fnmatch.c b/third_party/heimdal/lib/roken/fnmatch.c index 7dfe492179d1..74f35283d357 100644 --- a/third_party/heimdal/lib/roken/fnmatch.c +++ b/third_party/heimdal/lib/roken/fnmatch.c @@ -129,7 +129,7 @@ rk_fnmatch(const char *pattern, const char *string, int flags) --pattern; } } - /* FALLTHROUGH */ + fallthrough; default: if (c != *string++) return (FNM_NOMATCH); diff --git a/third_party/heimdal/lib/roken/freeaddrinfo.c b/third_party/heimdal/lib/roken/freeaddrinfo.c index 7132e95dd38d..80a7487b8d5e 100644 --- a/third_party/heimdal/lib/roken/freeaddrinfo.c +++ b/third_party/heimdal/lib/roken/freeaddrinfo.c @@ -40,7 +40,7 @@ */ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL -freeaddrinfo(struct addrinfo *ai) +rk_freeaddrinfo(struct addrinfo *ai) { struct addrinfo *tofree; diff --git a/third_party/heimdal/lib/roken/freehostent.c b/third_party/heimdal/lib/roken/freehostent.c index 61fbb223b5ec..05dd0fe385ce 100644 --- a/third_party/heimdal/lib/roken/freehostent.c +++ b/third_party/heimdal/lib/roken/freehostent.c @@ -40,7 +40,7 @@ */ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL -freehostent (struct hostent *h) +rk_freehostent(struct hostent *h) { char **p; diff --git a/third_party/heimdal/lib/roken/getaddrinfo.c b/third_party/heimdal/lib/roken/getaddrinfo.c index c8ed95413fe3..12a26a712259 100644 --- a/third_party/heimdal/lib/roken/getaddrinfo.c +++ b/third_party/heimdal/lib/roken/getaddrinfo.c @@ -366,10 +366,10 @@ get_nodes (const char *nodename, */ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -getaddrinfo(const char *nodename, - const char *servname, - const struct addrinfo *hints, - struct addrinfo **res) +rk_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res) { int ret; int port = 0; @@ -409,6 +409,6 @@ getaddrinfo(const char *nodename, ret = get_null (hints, port, protocol, socktype, res); } if (ret) - freeaddrinfo (*res); + rk_freeaddrinfo(*res); return ret; } diff --git a/third_party/heimdal/lib/roken/getcap.c b/third_party/heimdal/lib/roken/getcap.c deleted file mode 100644 index a8dd94bef9a9..000000000000 --- a/third_party/heimdal/lib/roken/getcap.c +++ /dev/null @@ -1,996 +0,0 @@ -/* $NetBSD: getcap.c,v 1.29 1999/03/29 09:27:29 abs Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Casey Leedom of Lawrence Livermore National Laboratory. - * - * 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 University 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 REGENTS 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 REGENTS 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 - -#include "roken.h" - -#include -#include -#if defined(HAVE_DB_185_H) -#include -#elif defined(HAVE_DB_H) -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#define BFRAG 1024 -#define ESC ('[' & 037) /* ASCII ESC */ -#define MAX_RECURSION 32 /* maximum getent recursion */ -#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ - -#define RECOK (char)0 -#define TCERR (char)1 -#define SHADOW (char)2 - -static size_t topreclen; /* toprec length */ -static char *toprec; /* Additional record specified by cgetset() */ -static int gottoprec; /* Flag indicating retrieval of toprecord */ - -#ifdef USE_DB -static int cdbget (DB *, char **, const char *); -#endif -static int getent (char **, size_t *, char **, int, const char *, int, char *); -static int nfcmp (char *, char *); - - -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetset(const char *ent); -ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL cgetcap(char *buf, const char *cap, int type); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetent(char **buf, char **db_array, const char *name); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetmatch(const char *buf, const char *name); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetclose(void); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetstr(char *buf, const char *cap, char **str); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetustr(char *buf, const char *cap, char **str); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetnum(char *buf, const char *cap, long *num); -/* - * Cgetset() allows the addition of a user specified buffer to be added - * to the database array, in effect "pushing" the buffer on top of the - * virtual database. 0 is returned on success, -1 on failure. - */ -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -cgetset(const char *ent) -{ - const char *source, *check; - char *dest; - - if (ent == NULL) { - if (toprec) - free(toprec); - toprec = NULL; - topreclen = 0; - return (0); - } - topreclen = strlen(ent); - if ((toprec = malloc (topreclen + 1)) == NULL) { - errno = ENOMEM; - return (-1); - } - gottoprec = 0; - - source=ent; - dest=toprec; - while (*source) { /* Strip whitespace */ - *dest++ = *source++; /* Do not check first field */ - while (*source == ':') { - check=source+1; - while (*check && (isspace((unsigned char)*check) || - (*check=='\\' && isspace((unsigned char)check[1])))) - ++check; - if( *check == ':' ) - source=check; - else - break; - - } - } - *dest=0; - - return (0); -} - -/* - * Cgetcap searches the capability record buf for the capability cap with - * type `type'. A pointer to the value of cap is returned on success, NULL - * if the requested capability couldn't be found. - * - * Specifying a type of ':' means that nothing should follow cap (:cap:). - * In this case a pointer to the terminating ':' or NUL will be returned if - * cap is found. - * - * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) - * return NULL. - */ -ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL -cgetcap(char *buf, const char *cap, int type) -{ - char *bp; - const char *cp; - - bp = buf; - for (;;) { - /* - * Skip past the current capability field - it's either the - * name field if this is the first time through the loop, or - * the remainder of a field whose name failed to match cap. - */ - for (;;) - if (*bp == '\0') - return (NULL); - else - if (*bp++ == ':') - break; - - /* - * Try to match (cap, type) in buf. - */ - for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) - continue; - if (*cp != '\0') - continue; - if (*bp == '@') - return (NULL); - if (type == ':') { - if (*bp != '\0' && *bp != ':') - continue; - return(bp); - } - if (*bp != type) - continue; - bp++; - return (*bp == '@' ? NULL : bp); - } - /* NOTREACHED */ -} - -/* - * Cgetent extracts the capability record name from the NULL terminated file - * array db_array and returns a pointer to a malloc'd copy of it in buf. - * Buf must be retained through all subsequent calls to cgetcap, cgetnum, - * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, - * -1 if the requested record couldn't be found, -2 if a system error was - * encountered (couldn't open/read a file, etc.), and -3 if a potential - * reference loop is detected. - */ -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -cgetent(char **buf, char **db_array, const char *name) -{ - size_t dummy; - - return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); -} - -/* - * Getent implements the functions of cgetent. If fd is non-negative, - * *db_array has already been opened and fd is the open file descriptor. We - * do this to save time and avoid using up file descriptors for tc= - * recursions. - * - * Getent returns the same success/failure codes as cgetent. On success, a - * pointer to a malloc'ed capability record with all tc= capabilities fully - * expanded and its length (not including trailing ASCII NUL) are left in - * *cap and *len. - * - * Basic algorithm: - * + Allocate memory incrementally as needed in chunks of size BFRAG - * for capability buffer. - * + Recurse for each tc=name and interpolate result. Stop when all - * names interpolated, a name can't be found, or depth exceeds - * MAX_RECURSION. - */ -static int -getent(char **cap, size_t *len, char **db_array, int fd, - const char *name, int depth, char *nfield) -{ - char *r_end, *rp = NULL, **db_p; /* pacify gcc */ - int myfd = 0, eof, foundit; - char *record; - int tc_not_resolved; - - /* - * Return with ``loop detected'' error if we've recursed more than - * MAX_RECURSION times. - */ - if (depth > MAX_RECURSION) - return (-3); - - /* - * Check if we have a top record from cgetset(). - */ - if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { - size_t tmplen = topreclen + BFRAG; - if ((record = malloc (tmplen)) == NULL) { - errno = ENOMEM; - return (-2); - } - (void)strlcpy(record, toprec, tmplen); - db_p = db_array; - rp = record + topreclen + 1; - r_end = rp + BFRAG; - goto tc_exp; - } - /* - * Allocate first chunk of memory. - */ - if ((record = malloc(BFRAG)) == NULL) { - errno = ENOMEM; - return (-2); - } - r_end = record + BFRAG; - foundit = 0; - /* - * Loop through database array until finding the record. - */ - - for (db_p = db_array; *db_p != NULL; db_p++) { - eof = 0; - - /* - * Open database if not already open. - */ - - if (fd >= 0) { - (void)lseek(fd, (off_t)0, SEEK_SET); - } else { -#ifdef USE_DB - char pbuf[_POSIX_PATH_MAX]; - char *cbuf; - size_t clen; - int retval; - DB *capdbp; - - (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); - if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) - != NULL) { - free(record); - retval = cdbget(capdbp, &record, name); - /* record is no longer for us to free here */ - if (retval < 0) { - /* no record available */ - (void)capdbp->close(capdbp); - return (retval); - } - /* save the data; close frees it */ - clen = strlen(record); - cbuf = malloc(clen + 1); - if (cbuf == NULL) - return (-2); - memmove(cbuf, record, clen + 1); - if (capdbp->close(capdbp) < 0) { - free(cbuf); - return (-2); - } - *len = clen; - *cap = cbuf; - return (retval); - } else -#endif - { - fd = open(*db_p, O_RDONLY, 0); - if (fd < 0) { - /* No error on unfound file. */ - continue; - } - myfd = 1; - } - } - /* - * Find the requested capability record ... - */ - { - char buf[BUFSIZ]; - char *b_end, *bp, *cp; - int c, slash; - - /* - * Loop invariants: - * There is always room for one more character in record. - * R_end always points just past end of record. - * Rp always points just past last character in record. - * B_end always points just past last character in buf. - * Bp always points at next character in buf. - * Cp remembers where the last colon was. - */ - b_end = buf; - bp = buf; - cp = 0; - slash = 0; - for (;;) { - - /* - * Read in a line implementing (\, newline) - * line continuation. - */ - rp = record; - for (;;) { - if (bp >= b_end) { - int n; - - n = read(fd, buf, sizeof(buf)); - if (n <= 0) { - if (myfd) - (void)close(fd); - if (n < 0) { - free(record); - return (-2); - } else { - fd = -1; - eof = 1; - break; - } - } - b_end = buf+n; - bp = buf; - } - - c = *bp++; - if (c == '\n') { - if (slash) { - slash = 0; - rp--; - continue; - } else - break; - } - if (slash) { - slash = 0; - cp = 0; - } - if (c == ':') { - /* - * If the field was `empty' (i.e. - * contained only white space), back up - * to the colon (eliminating the - * field). - */ - if (cp) - rp = cp; - else - cp = rp; - } else if (c == '\\') { - slash = 1; - } else if (c != ' ' && c != '\t') { - /* - * Forget where the colon was, as this - * is not an empty field. - */ - cp = 0; - } - *rp++ = c; - - /* - * Enforce loop invariant: if no room - * left in record buffer, try to get - * some more. - */ - if (rp >= r_end) { - u_int pos; - char *tmp; - size_t newsize; - - pos = rp - record; - newsize = r_end - record + BFRAG; - tmp = realloc(record, newsize); - if (tmp == NULL) { - errno = ENOMEM; - if (myfd) - (void)close(fd); - free(record); - return (-2); - } - record = tmp; - r_end = record + newsize; - rp = record + pos; - } - } - /* Eliminate any white space after the last colon. */ - if (cp) - rp = cp + 1; - /* Loop invariant lets us do this. */ - *rp++ = '\0'; - - /* - * If encountered eof check next file. - */ - if (eof) - break; - - /* - * Toss blank lines and comments. - */ - if (*record == '\0' || *record == '#') - continue; - - /* - * See if this is the record we want ... - */ - if (cgetmatch(record, name) == 0) { - if (nfield == NULL || !nfcmp(nfield, record)) { - foundit = 1; - break; /* found it! */ - } - } - } - } - if (foundit) - break; - } - - if (!foundit) { - free(record); - return (-1); - } - - /* - * Got the capability record, but now we have to expand all tc=name - * references in it ... - */ - tc_exp: { - char *newicap, *s; - size_t ilen, newilen; - int diff, iret, tclen; - char *icap, *scan, *tc, *tcstart, *tcend; - - /* - * Loop invariants: - * There is room for one more character in record. - * R_end points just past end of record. - * Rp points just past last character in record. - * Scan points at remainder of record that needs to be - * scanned for tc=name constructs. - */ - scan = record; - tc_not_resolved = 0; - for (;;) { - if ((tc = cgetcap(scan, "tc", '=')) == NULL) - break; - - /* - * Find end of tc=name and stomp on the trailing `:' - * (if present) so we can use it to call ourselves. - */ - s = tc; - for (;;) - if (*s == '\0') - break; - else - if (*s++ == ':') { - *(s - 1) = '\0'; - break; - } - tcstart = tc - 3; - tclen = s - tcstart; - tcend = s; - - iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, - NULL); - newicap = icap; /* Put into a register. */ - newilen = ilen; - if (iret != 0) { - /* an error */ - if (iret < -1) { - if (myfd) - (void)close(fd); - free(record); - return (iret); - } - if (iret == 1) - tc_not_resolved = 1; - /* couldn't resolve tc */ - if (iret == -1) { - *(s - 1) = ':'; - scan = s - 1; - tc_not_resolved = 1; - continue; - - } - } - /* not interested in name field of tc'ed record */ - s = newicap; - for (;;) - if (*s == '\0') - break; - else - if (*s++ == ':') - break; - newilen -= s - newicap; - newicap = s; - - /* make sure interpolated record is `:'-terminated */ - s += newilen; - if (*(s-1) != ':') { - *s = ':'; /* overwrite NUL with : */ - newilen++; - } - - /* - * Make sure there's enough room to insert the - * new record. - */ - diff = newilen - tclen; - if (diff >= r_end - rp) { - u_int pos, tcpos, tcposend; - size_t newsize; - char *tmp; - - pos = rp - record; - newsize = r_end - record + diff + BFRAG; - tcpos = tcstart - record; - tcposend = tcend - record; - tmp = realloc(record, newsize); - if (tmp == NULL) { - errno = ENOMEM; - if (myfd) - (void)close(fd); - free(icap); - free(record); - return (-2); - } - record = tmp; - r_end = record + newsize; - rp = record + pos; - tcstart = record + tcpos; - tcend = record + tcposend; - } - - /* - * Insert tc'ed record into our record. - */ - s = tcstart + newilen; - memmove(s, tcend, (size_t)(rp - tcend)); - memmove(tcstart, newicap, newilen); - rp += diff; - free(icap); - - /* - * Start scan on `:' so next cgetcap works properly - * (cgetcap always skips first field). - */ - scan = s-1; - } - - } - /* - * Close file (if we opened it), give back any extra memory, and - * return capability, length and success. - */ - if (myfd) - (void)close(fd); - *len = rp - record - 1; /* don't count NUL */ - if (r_end > rp) { - char *tmp = realloc(record, (size_t)(rp - record)); - if (tmp == NULL) { - errno = ENOMEM; - free(record); - return (-2); - } - record = tmp; - } - - *cap = record; - if (tc_not_resolved) - return (1); - return (0); -} - -#ifdef USE_DB -static int -cdbget(DB *capdbp, char **bp, const char *name) -{ - DBT key; - DBT data; - - /* LINTED key is not modified */ - key.data = (char *)name; - key.size = strlen(name); - - for (;;) { - /* Get the reference. */ - switch(capdbp->get(capdbp, &key, &data, 0)) { - case -1: - return (-2); - case 1: - return (-1); - } - - /* If not an index to another record, leave. */ - if (((char *)data.data)[0] != SHADOW) - break; - - key.data = (char *)data.data + 1; - key.size = data.size - 1; - } - - *bp = (char *)data.data + 1; - return (((char *)(data.data))[0] == TCERR ? 1 : 0); -} -#endif /* USE_DB */ - -/* - * Cgetmatch will return 0 if name is one of the names of the capability - * record buf, -1 if not. - */ -int -cgetmatch(const char *buf, const char *name) -{ - const char *np, *bp; - - /* - * Start search at beginning of record. - */ - bp = buf; - for (;;) { - /* - * Try to match a record name. - */ - np = name; - for (;;) - if (*np == '\0') { - if (*bp == '|' || *bp == ':' || *bp == '\0') - return (0); - else - break; - } else - if (*bp++ != *np++) - break; - - /* - * Match failed, skip to next name in record. - */ - bp--; /* a '|' or ':' may have stopped the match */ - for (;;) - if (*bp == '\0' || *bp == ':') - return (-1); /* match failed totally */ - else - if (*bp++ == '|') - break; /* found next name */ - } -} - -static FILE *pfp; -static int slash; -static char **dbp; - -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -cgetclose(void) -{ - if (pfp != NULL) { - (void)fclose(pfp); - pfp = NULL; - } - dbp = NULL; - gottoprec = 0; - slash = 0; - return(0); -} - -/* - * Cgetstr retrieves the value of the string capability cap from the - * capability record pointed to by buf. A pointer to a decoded, NUL - * terminated, malloc'd copy of the string is returned in the char * - * pointed to by str. The length of the string not including the trailing - * NUL is returned on success, -1 if the requested string capability - * couldn't be found, -2 if a system error was encountered (storage - * allocation failure). - */ -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -cgetstr(char *buf, const char *cap, char **str) -{ - u_int m_room; - const char *bp; - char *mp; - int len; - char *mem, *nmem; - - *str = NULL; - - /* - * Find string capability cap - */ - bp = cgetcap(buf, cap, '='); - if (bp == NULL) - return (-1); - - /* - * Conversion / storage allocation loop ... Allocate memory in - * chunks SFRAG in size. - */ - if ((mem = malloc(SFRAG)) == NULL) { - errno = ENOMEM; - return (-2); /* couldn't even allocate the first fragment */ - } - m_room = SFRAG; - mp = mem; - - while (*bp != ':' && *bp != '\0') { - /* - * Loop invariants: - * There is always room for one more character in mem. - * Mp always points just past last character in mem. - * Bp always points at next character in buf. - */ - if (*bp == '^') { - bp++; - if (*bp == ':' || *bp == '\0') - break; /* drop unfinished escape */ - *mp++ = *bp++ & 037; - } else if (*bp == '\\') { - bp++; - if (*bp == ':' || *bp == '\0') - break; /* drop unfinished escape */ - if ('0' <= *bp && *bp <= '7') { - int n, i; - - n = 0; - i = 3; /* maximum of three octal digits */ - do { - n = n * 8 + (*bp++ - '0'); - } while (--i && '0' <= *bp && *bp <= '7'); - *mp++ = n; - } - else switch (*bp++) { - case 'b': case 'B': - *mp++ = '\b'; - break; - case 't': case 'T': - *mp++ = '\t'; - break; - case 'n': case 'N': - *mp++ = '\n'; - break; - case 'f': case 'F': - *mp++ = '\f'; - break; - case 'r': case 'R': - *mp++ = '\r'; - break; - case 'e': case 'E': - *mp++ = ESC; - break; - case 'c': case 'C': - *mp++ = ':'; - break; - default: - /* - * Catches '\', '^', and - * everything else. - */ - *mp++ = *(bp-1); - break; - } - } else - *mp++ = *bp++; - m_room--; - - /* - * Enforce loop invariant: if no room left in current - * buffer, try to get some more. - */ - if (m_room == 0) { - size_t size = mp - mem; - - if ((nmem = realloc(mem, size + SFRAG)) == NULL) { - free(mem); - return (-2); - } - mem = nmem; - m_room = SFRAG; - mp = mem + size; - } - } - *mp++ = '\0'; /* loop invariant let's us do this */ - m_room--; - len = mp - mem - 1; - - /* - * Give back any extra memory and return value and success. - */ - if (m_room != 0) { - if ((nmem = realloc(mem, (size_t)(mp - mem))) == NULL) { - free(mem); - return (-2); - } - mem = nmem; - } - *str = mem; - return (len); -} - -/* - * Cgetustr retrieves the value of the string capability cap from the - * capability record pointed to by buf. The difference between cgetustr() - * and cgetstr() is that cgetustr does not decode escapes but rather treats - * all characters literally. A pointer to a NUL terminated malloc'd - * copy of the string is returned in the char pointed to by str. The - * length of the string not including the trailing NUL is returned on success, - * -1 if the requested string capability couldn't be found, -2 if a system - * error was encountered (storage allocation failure). - */ -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -cgetustr(char *buf, const char *cap, char **str) -{ - u_int m_room; - const char *bp; - char *mp; - int len; - char *mem; - - /* - * Find string capability cap - */ - if ((bp = cgetcap(buf, cap, '=')) == NULL) - return (-1); - - /* - * Conversion / storage allocation loop ... Allocate memory in - * chunks SFRAG in size. - */ - if ((mem = malloc(SFRAG)) == NULL) { - errno = ENOMEM; - return (-2); /* couldn't even allocate the first fragment */ - } - m_room = SFRAG; - mp = mem; - - while (*bp != ':' && *bp != '\0') { - /* - * Loop invariants: - * There is always room for one more character in mem. - * Mp always points just past last character in mem. - * Bp always points at next character in buf. - */ - *mp++ = *bp++; - m_room--; - - /* - * Enforce loop invariant: if no room left in current - * buffer, try to get some more. - */ - if (m_room == 0) { - size_t size = mp - mem; - - if ((mem = realloc(mem, size + SFRAG)) == NULL) - return (-2); - m_room = SFRAG; - mp = mem + size; - } - } - *mp++ = '\0'; /* loop invariant let's us do this */ - m_room--; - len = mp - mem - 1; - - /* - * Give back any extra memory and return value and success. - */ - if (m_room != 0) { - char *tmp = realloc(mem, (size_t)(mp - mem)); - if (tmp == NULL) { - free(mem); - return (-2); - } - mem = tmp; - } - *str = mem; - return (len); -} - -/* - * Cgetnum retrieves the value of the numeric capability cap from the - * capability record pointed to by buf. The numeric value is returned in - * the long pointed to by num. 0 is returned on success, -1 if the requested - * numeric capability couldn't be found. - */ -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -cgetnum(char *buf, const char *cap, long *num) -{ - long n; - int base, digit; - const char *bp; - - /* - * Find numeric capability cap - */ - bp = cgetcap(buf, cap, '#'); - if (bp == NULL) - return (-1); - - /* - * Look at value and determine numeric base: - * 0x... or 0X... hexadecimal, - * else 0... octal, - * else decimal. - */ - if (*bp == '0') { - bp++; - if (*bp == 'x' || *bp == 'X') { - bp++; - base = 16; - } else - base = 8; - } else - base = 10; - - /* - * Conversion loop ... - */ - n = 0; - for (;;) { - if ('0' <= *bp && *bp <= '9') - digit = *bp - '0'; - else if ('a' <= *bp && *bp <= 'f') - digit = 10 + *bp - 'a'; - else if ('A' <= *bp && *bp <= 'F') - digit = 10 + *bp - 'A'; - else - break; - - if (digit >= base) - break; - - n = n * base + digit; - bp++; - } - - /* - * Return value and success. - */ - *num = n; - return (0); -} - - -/* - * Compare name field of record. - */ -static int -nfcmp(char *nf, char *rec) -{ - char *cp, tmp; - int ret; - - for (cp = rec; *cp != ':'; cp++) - ; - - tmp = *(cp + 1); - *(cp + 1) = '\0'; - ret = strcmp(nf, rec); - *(cp + 1) = tmp; - - return (ret); -} diff --git a/third_party/heimdal/lib/roken/getipnodebyaddr.c b/third_party/heimdal/lib/roken/getipnodebyaddr.c index 7d4095f1d840..afebe9149500 100644 --- a/third_party/heimdal/lib/roken/getipnodebyaddr.c +++ b/third_party/heimdal/lib/roken/getipnodebyaddr.c @@ -41,7 +41,7 @@ */ ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL -getipnodebyaddr (const void *src, size_t len, int af, int *error_num) +rk_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) { struct hostent *tmp; diff --git a/third_party/heimdal/lib/roken/getipnodebyname.c b/third_party/heimdal/lib/roken/getipnodebyname.c index 2ff282707c23..ee430c76eb65 100644 --- a/third_party/heimdal/lib/roken/getipnodebyname.c +++ b/third_party/heimdal/lib/roken/getipnodebyname.c @@ -45,7 +45,7 @@ static int h_errno = NO_RECOVERY; */ ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL -getipnodebyname (const char *name, int af, int flags, int *error_num) +rk_getipnodebyname(const char *name, int af, int flags, int *error_num) { struct hostent *tmp; diff --git a/third_party/heimdal/lib/roken/getnameinfo.c b/third_party/heimdal/lib/roken/getnameinfo.c index b23ad01ebdd9..9d118600f264 100644 --- a/third_party/heimdal/lib/roken/getnameinfo.c +++ b/third_party/heimdal/lib/roken/getnameinfo.c @@ -92,10 +92,10 @@ doit (int af, */ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -getnameinfo(const struct sockaddr *sa, socklen_t salen, - char *host, size_t hostlen, - char *serv, size_t servlen, - int flags) +rk_getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, + int flags) { switch (sa->sa_family) { #ifdef HAVE_IPV6 diff --git a/third_party/heimdal/lib/roken/getuserinfo.c b/third_party/heimdal/lib/roken/getuserinfo.c index 76cd78241be9..7fd2ca9f151f 100644 --- a/third_party/heimdal/lib/roken/getuserinfo.c +++ b/third_party/heimdal/lib/roken/getuserinfo.c @@ -53,12 +53,12 @@ roken_get_shell(char *shell, size_t shellsz) char *p; #ifndef WIN32 - char user[128]; - const char *username = roken_get_username(user, sizeof(user)); +#ifdef HAVE_GETPWNAM_R size_t buflen = 2048; if (sysconf(_SC_GETPW_R_SIZE_MAX) > 0) buflen = sysconf(_SC_GETPW_R_SIZE_MAX); +#endif if (issuid()) return "/bin/sh"; @@ -76,8 +76,11 @@ roken_get_shell(char *shell, size_t shellsz) struct passwd pwd; struct passwd *pwdp; char buf[buflen]; + char user[128]; + const char *username = roken_get_username(user, sizeof(user)); - if (getpwnam_r(username, &pwd, buf, buflen, &pwdp) == 0 && + if (username && + getpwnam_r(username, &pwd, buf, buflen, &pwdp) == 0 && pwdp != NULL && pwdp->pw_shell != NULL) { if (strlcpy(shell, pwdp->pw_shell, shellsz) < shellsz) return shell; @@ -133,14 +136,14 @@ roken_get_homedir(char *home, size_t homesz) } return home; } - /* Fallthru to return NULL */ + fallthrough; #else - char user[128]; - const char *username = roken_get_username(user, sizeof(user)); +#ifdef HAVE_GETPWNAM_R size_t buflen = 2048; if (sysconf(_SC_GETPW_R_SIZE_MAX) > 0) buflen = sysconf(_SC_GETPW_R_SIZE_MAX); +#endif if (issuid()) { errno = 0; @@ -156,12 +159,15 @@ roken_get_homedir(char *home, size_t homesz) } #ifdef HAVE_GETPWNAM_R - if (username) { + { + char user[128]; + const char *username = roken_get_username(user, sizeof(user)); struct passwd pwd; struct passwd *pwdp; char buf[buflen]; - if (getpwnam_r(username, &pwd, buf, buflen, &pwdp) == 0 && + if (username && + getpwnam_r(username, &pwd, buf, buflen, &pwdp) == 0 && pwdp != NULL && pwdp->pw_dir != NULL) { if (strlcpy(home, pwdp->pw_dir, homesz) < homesz) return home; @@ -255,8 +261,13 @@ roken_get_username(char *user, size_t usersz) } } #else +#ifdef HAVE_GETPWUID_R size_t buflen = 2048; + if (sysconf(_SC_GETPW_R_SIZE_MAX) > 0) + buflen = sysconf(_SC_GETPW_R_SIZE_MAX); +#endif + p = secure_getenv("USER"); if (p == NULL || p[0] == '\0') p = secure_getenv("LOGNAME"); @@ -268,9 +279,6 @@ roken_get_username(char *user, size_t usersz) } #ifdef HAVE_GETPWUID_R - if (sysconf(_SC_GETPW_R_SIZE_MAX) > 0) - buflen = sysconf(_SC_GETPW_R_SIZE_MAX); - { struct passwd pwd; struct passwd *pwdp; diff --git a/third_party/heimdal/lib/roken/hex-test.c b/third_party/heimdal/lib/roken/hex-test.c index a81422e1f4a5..01f21c821d1a 100644 --- a/third_party/heimdal/lib/roken/hex-test.c +++ b/third_party/heimdal/lib/roken/hex-test.c @@ -43,7 +43,7 @@ main(int argc, char **argv) int numtest = 1; struct test { void *data; - size_t len; + ssize_t len; const char *result; } *t, tests[] = { { "", 0 , "" }, @@ -55,26 +55,35 @@ main(int argc, char **argv) { "abcdef", 6, "616263646566" }, { "abcdefg", 7, "61626364656667" }, { "=", 1, "3D" }, + /* Embedded NUL, non-ASCII / binary */ + { "\0\x01\x1a\xad\xf1\xff", 6, "00011AADF1FF" }, + /* Invalid encodings */ + { "", -1, "00.11AADF1FF" }, + { "", -1, "000x1AADF1FF" }, + { "", -1, "00011?ADF1FF" }, { NULL, 0, NULL } }; for(t = tests; t->data; t++) { + ssize_t len; char *str; - int len; - len = hex_encode(t->data, t->len, &str); - if(strcmp(str, t->result) != 0) { - fprintf(stderr, "failed test %d: %s != %s\n", numtest, - str, t->result); - numerr++; - } - free(str); + + if (t->len > -1) { + (void) hex_encode(t->data, t->len, &str); + if (strcmp(str, t->result) != 0) { + fprintf(stderr, "failed test %d: %s != %s\n", numtest, + str, t->result); + numerr++; + } + free(str); + } str = strdup(t->result); len = strlen(str); len = hex_decode(t->result, str, len); - if(len != t->len) { - fprintf(stderr, "failed test %d: len %lu != %lu\n", numtest, - (unsigned long)len, (unsigned long)t->len); + if (len != t->len) { + fprintf(stderr, "failed test %d: len %lu != %ld\n", numtest, + (long)len, (long)t->len); numerr++; - } else if(memcmp(str, t->data, t->len) != 0) { + } else if (t->len > -1 && memcmp(str, t->data, t->len) != 0) { fprintf(stderr, "failed test %d: data\n", numtest); numerr++; } diff --git a/third_party/heimdal/lib/roken/hex.c b/third_party/heimdal/lib/roken/hex.c index c66b324f7900..cc47fa4d52de 100644 --- a/third_party/heimdal/lib/roken/hex.c +++ b/third_party/heimdal/lib/roken/hex.c @@ -39,14 +39,15 @@ static const char hexchar[16] = "0123456789ABCDEF"; -static int +static inline int pos(char c) { - const char *p; - c = toupper((unsigned char)c); - for (p = hexchar; *p; p++) - if (*p == c) - return p - hexchar; + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return 10 + c - 'A'; + if (c >= 'a' && c <= 'f') + return 10 + c - 'a'; return -1; } @@ -86,6 +87,7 @@ hex_decode(const char *str, void *data, size_t len) size_t l; unsigned char *p = data; size_t i; + int d; l = strlen(str); @@ -94,11 +96,19 @@ hex_decode(const char *str, void *data, size_t len) return -1; if (l & 1) { - p[0] = pos(str[0]); + if ((d = pos(str[0])) == -1) + return -1; + p[0] = d; str++; p++; } - for (i = 0; i < l / 2; i++) - p[i] = pos(str[i * 2]) << 4 | pos(str[(i * 2) + 1]); + for (i = 0; i < l / 2; i++) { + if ((d = pos(str[i * 2])) == -1) + return -1; + p[i] = d << 4; + if ((d = pos(str[(i * 2) + 1])) == -1) + return -1; + p[i] |= d; + } return i + (l & 1); } diff --git a/third_party/heimdal/lib/roken/mergesort_r.c b/third_party/heimdal/lib/roken/mergesort_r.c index 2d551a607a21..39b0301c4543 100644 --- a/third_party/heimdal/lib/roken/mergesort_r.c +++ b/third_party/heimdal/lib/roken/mergesort_r.c @@ -85,7 +85,7 @@ static void insertionsort(u_char *, size_t, size_t, cmp_t, void *); */ /* Assumption: PSIZE is a power of 2. */ #define EVAL(p) (u_char **) \ - ((((u_char *)p + PSIZE - 1 - (u_char *) 0) & ~(PSIZE - 1))) + ((((uintptr_t)p + PSIZE - 1) & ~(PSIZE - 1))) /* * Arguments are as for qsort_r, except thunk is moved to the last @@ -114,7 +114,7 @@ mergesort_r(void *base, size_t nmemb, size_t size, cmp_t cmp, void *thunk) * Stupid subtraction for the Cray. */ iflag = 0; - if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) + if (!(size % ISIZE) && !(((uintptr_t)base) % ISIZE)) iflag = 1; if ((list2 = malloc(nmemb * size + PSIZE)) == NULL) diff --git a/third_party/heimdal/lib/roken/ndbm_wrap.c b/third_party/heimdal/lib/roken/ndbm_wrap.c index f7b87f1203e9..f8403da44ab2 100644 --- a/third_party/heimdal/lib/roken/ndbm_wrap.c +++ b/third_party/heimdal/lib/roken/ndbm_wrap.c @@ -36,6 +36,8 @@ #include "ndbm_wrap.h" #if defined(HAVE_DBHEADER) #include +#elif defined(HAVE_DB6_DB_H) +#include #elif defined(HAVE_DB5_DB_H) #include #elif defined(HAVE_DB4_DB_H) diff --git a/third_party/heimdal/lib/roken/net_write.c b/third_party/heimdal/lib/roken/net_write.c index 1e8361999ea8..e66f56b75952 100644 --- a/third_party/heimdal/lib/roken/net_write.c +++ b/third_party/heimdal/lib/roken/net_write.c @@ -71,7 +71,7 @@ net_write (rk_socket_t fd, const void *buf, size_t nbytes) return nbytes; } -#else +#else /* defined(_WIN32) */ ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL net_write(rk_socket_t sock, const void *buf, size_t nbytes) @@ -102,6 +102,7 @@ net_write(rk_socket_t sock, const void *buf, size_t nbytes) count = send (sock, cbuf, rem, 0); #endif if (count < 0) { +#ifdef SOCKET_IS_NOT_AN_FD if (!use_write) { switch (rk_SOCK_ERRNO) { case WSAEINTR: @@ -111,7 +112,9 @@ net_write(rk_socket_t sock, const void *buf, size_t nbytes) default: return count; } - } else { + } else +#endif + { switch (errno) { case EINTR: continue; diff --git a/third_party/heimdal/lib/roken/resolve-test.c b/third_party/heimdal/lib/roken/resolve-test.c index 25cc98aafe3a..581600a5937d 100644 --- a/third_party/heimdal/lib/roken/resolve-test.c +++ b/third_party/heimdal/lib/roken/resolve-test.c @@ -159,7 +159,7 @@ test_rk_dns_srv_order(size_t run) if (rr->u.srv->priority < prio0 || (rr->u.srv->priority != prio0 && (i % 4 != 0 || rr->u.srv->priority > prio0 + 1))) { - printf("SRV RR order run %lu failed\n", run); + printf("SRV RR order run %zu failed\n", run); fail = 1; } prio0 = rr->u.srv->priority; diff --git a/third_party/heimdal/lib/roken/roken-common.h b/third_party/heimdal/lib/roken/roken-common.h index f05f88668f3d..035b99b8b973 100644 --- a/third_party/heimdal/lib/roken/roken-common.h +++ b/third_party/heimdal/lib/roken/roken-common.h @@ -472,6 +472,12 @@ vstrcollect(va_list *ap); ROKEN_LIB_FUNCTION char ** ROKEN_LIB_CALL strcollect(char *first, ...); +ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL +rk_time_add(time_t, time_t); + +ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL +rk_time_sub(time_t, time_t); + #define timevalfix rk_timevalfix ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL timevalfix(struct timeval *t1); diff --git a/third_party/heimdal/lib/roken/roken.h.in b/third_party/heimdal/lib/roken/roken.h.in index e1aa6b7b60c0..e1902f582dcb 100644 --- a/third_party/heimdal/lib/roken/roken.h.in +++ b/third_party/heimdal/lib/roken/roken.h.in @@ -356,7 +356,12 @@ ROKEN_CPP_START #define fsync _commit -/* The MSVC implementation of snprintf is not C99 compliant. */ +#define _PIPE_BUFFER_SZ 8192 +#define pipe(fds) _pipe((fds), _PIPE_BUFFER_SZ, O_BINARY); + +#define ftruncate(fd, sz) _chsize((fd), (sz)) + +#if !defined(HAVE_UCRT) #define snprintf rk_snprintf #define vsnprintf rk_vsnprintf #define vasnprintf rk_vasnprintf @@ -364,11 +369,6 @@ ROKEN_CPP_START #define asnprintf rk_asnprintf #define asprintf rk_asprintf -#define _PIPE_BUFFER_SZ 8192 -#define pipe(fds) _pipe((fds), _PIPE_BUFFER_SZ, O_BINARY); - -#define ftruncate(fd, sz) _chsize((fd), (sz)) - ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_snprintf (char *str, size_t sz, const char *format, ...); @@ -386,6 +386,7 @@ rk_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_vsnprintf (char *str, size_t sz, const char *format, va_list args); +#endif /* !defined(HAVE_UCRT) */ /* missing stat.h predicates */ @@ -716,13 +717,6 @@ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL mkostemp(char *, int); ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL mkdtemp(char *); #endif -#ifndef HAVE_CGETENT -#define cgetent rk_cgetent -#define cgetstr rk_cgetstr -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetent(char **, char **, const char *); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetstr(char *, const char *, char **); -#endif - #ifndef HAVE_INITGROUPS #define initgroups rk_initgroups ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL initgroups(const char *, gid_t); @@ -912,27 +906,27 @@ ROKEN_LIB_VARIABLE extern int opterr; #ifndef HAVE_GETIPNODEBYNAME #define getipnodebyname rk_getipnodebyname -ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL -getipnodebyname (const char *, int, int, int *); #endif +ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL +rk_getipnodebyname(const char *, int, int, int *); #ifndef HAVE_GETIPNODEBYADDR #define getipnodebyaddr rk_getipnodebyaddr -ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL -getipnodebyaddr (const void *, size_t, int, int *); #endif +ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL +rk_getipnodebyaddr(const void *, size_t, int, int *); #ifndef HAVE_FREEHOSTENT #define freehostent rk_freehostent -ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL -freehostent (struct hostent *); #endif +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +rk_freehostent(struct hostent *); #ifndef HAVE_COPYHOSTENT #define copyhostent rk_copyhostent -ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL -copyhostent (const struct hostent *); #endif +ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL +rk_copyhostent(const struct hostent *); #ifndef HAVE_SOCKLEN_T typedef int socklen_t; @@ -998,27 +992,27 @@ struct addrinfo { #ifndef HAVE_GETADDRINFO #define getaddrinfo rk_getaddrinfo -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -getaddrinfo(const char *, - const char *, - const struct addrinfo *, - struct addrinfo **); #endif +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_getaddrinfo(const char *, + const char *, + const struct addrinfo *, + struct addrinfo **); #ifndef HAVE_GETNAMEINFO #define getnameinfo rk_getnameinfo -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -getnameinfo(const struct sockaddr *, socklen_t, - char *, size_t, - char *, size_t, - int); #endif +ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +rk_getnameinfo(const struct sockaddr *, socklen_t, + char *, size_t, + char *, size_t, + int); #ifndef HAVE_FREEADDRINFO #define freeaddrinfo rk_freeaddrinfo -ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL -freeaddrinfo(struct addrinfo *); #endif +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +rk_freeaddrinfo(struct addrinfo *); #ifndef HAVE_GAI_STRERROR #define gai_strerror rk_gai_strerror diff --git a/third_party/heimdal/lib/roken/snprintf.c b/third_party/heimdal/lib/roken/snprintf.c index 620875f379c8..3da48962ee3a 100644 --- a/third_party/heimdal/lib/roken/snprintf.c +++ b/third_party/heimdal/lib/roken/snprintf.c @@ -515,7 +515,7 @@ xyzprintf (struct snprintf_state *state, const char *char_format, va_list ap) } case '\0' : --format; - /* FALLTHROUGH */ + fallthrough; case '%' : (*state->append_char)(state, c); ++len; diff --git a/third_party/heimdal/lib/roken/socket.c b/third_party/heimdal/lib/roken/socket.c index 9feb343f5083..a790e082d822 100644 --- a/third_party/heimdal/lib/roken/socket.c +++ b/third_party/heimdal/lib/roken/socket.c @@ -221,16 +221,16 @@ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL socket_set_portrange (rk_socket_t sock, int restr, int af) { #if defined(IP_PORTRANGE) - if (af == AF_INET) { - int on = restr ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; - setsockopt (sock, IPPROTO_IP, IP_PORTRANGE, &on, sizeof(on)); - } + if (af == AF_INET) { + int on = restr ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; + (void) setsockopt(sock, IPPROTO_IP, IP_PORTRANGE, &on, sizeof(on)); + } #endif #if defined(IPV6_PORTRANGE) - if (af == AF_INET6) { - int on = restr ? IPV6_PORTRANGE_HIGH : IPV6_PORTRANGE_DEFAULT; - setsockopt (sock, IPPROTO_IPV6, IPV6_PORTRANGE, &on, sizeof(on)); - } + if (af == AF_INET6) { + int on = restr ? IPV6_PORTRANGE_HIGH : IPV6_PORTRANGE_DEFAULT; + (void) setsockopt(sock, IPPROTO_IPV6, IPV6_PORTRANGE, &on, sizeof(on)); + } #endif } @@ -243,7 +243,7 @@ socket_set_debug (rk_socket_t sock) { #if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT) int on = 1; - setsockopt (sock, SOL_SOCKET, SO_DEBUG, (void *) &on, sizeof (on)); + (void) setsockopt(sock, SOL_SOCKET, SO_DEBUG, (void *) &on, sizeof (on)); #endif } @@ -255,7 +255,7 @@ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL socket_set_tos (rk_socket_t sock, int tos) { #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) - setsockopt (sock, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(int)); + (void) setsockopt (sock, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(int)); #endif } @@ -289,7 +289,8 @@ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL socket_set_reuseaddr (rk_socket_t sock, int val) { #if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT) - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(val)); + (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val, + sizeof(val)); #endif } @@ -301,7 +302,8 @@ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL socket_set_ipv6only (rk_socket_t sock, int val) { #if defined(IPV6_V6ONLY) && defined(HAVE_SETSOCKOPT) - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val, sizeof(val)); + (void) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val, + sizeof(val)); #endif } @@ -312,7 +314,8 @@ socket_set_ipv6only (rk_socket_t sock, int val) ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL socket_set_keepalive(rk_socket_t sock, int val) { - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&val, sizeof(val)); + (void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&val, + sizeof(val)); } /** diff --git a/third_party/heimdal/lib/roken/strftime.c b/third_party/heimdal/lib/roken/strftime.c index 447c1554337f..9a951dd30080 100644 --- a/third_party/heimdal/lib/roken/strftime.c +++ b/third_party/heimdal/lib/roken/strftime.c @@ -36,6 +36,11 @@ #include "strpftime-test.h" #endif +#if defined(_WIN32) +# define timezone _timezone +# define tzname _tzname +#endif + static const char *abb_weekdays[] = { "Sun", "Mon", @@ -372,7 +377,7 @@ strftime (char *buf, size_t maxsize, const char *format, break; case '\0' : --format; - /* FALLTHROUGH */ + fallthrough; case '%' : ret = snprintf (buf, maxsize - n, "%%"); diff --git a/third_party/heimdal/lib/roken/strptime.c b/third_party/heimdal/lib/roken/strptime.c index 75c27a328773..86216d2d6dcc 100644 --- a/third_party/heimdal/lib/roken/strptime.c +++ b/third_party/heimdal/lib/roken/strptime.c @@ -424,7 +424,7 @@ strptime (const char *buf, const char *format, struct tm *timeptr) abort (); case '\0' : --format; - /* FALLTHROUGH */ + fallthrough; case '%' : if (*buf == '%') ++buf; diff --git a/third_party/heimdal/lib/roken/strtoll.c b/third_party/heimdal/lib/roken/strtoll.c index 0d895d54a255..96c1b250974d 100644 --- a/third_party/heimdal/lib/roken/strtoll.c +++ b/third_party/heimdal/lib/roken/strtoll.c @@ -38,6 +38,8 @@ #include "roken.h" +#ifndef HAVE_STRTOLL + /* #include */ #include @@ -150,3 +152,4 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return ret; } +#endif /* !HAVE_STRTOLL */ diff --git a/third_party/heimdal/lib/roken/strtoull.c b/third_party/heimdal/lib/roken/strtoull.c index 94530e574d12..0516e18f9135 100644 --- a/third_party/heimdal/lib/roken/strtoull.c +++ b/third_party/heimdal/lib/roken/strtoull.c @@ -38,6 +38,8 @@ #include "roken.h" +#ifndef HAVE_STRTOULL + /* #include */ #include @@ -124,3 +126,4 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return (acc); } +#endif /* !HAVE_STRTOULL */ diff --git a/third_party/heimdal/lib/roken/test-getuserinfo.c b/third_party/heimdal/lib/roken/test-getuserinfo.c index b3f15214b56a..4feae177aed6 100644 --- a/third_party/heimdal/lib/roken/test-getuserinfo.c +++ b/third_party/heimdal/lib/roken/test-getuserinfo.c @@ -50,7 +50,8 @@ main(void) char buf2[MAX_PATH * 2]; int ret = 0; if (!issuid() && getuid() != 0) { - const char *s, *s2; + const char *s = NULL; + const char *s2 = NULL; if (getenv("USER") != NULL && strlen(getenv("USER")) != 0 && (s = roken_get_username(buf, sizeof(buf))) == NULL) { diff --git a/third_party/heimdal/lib/roken/test-mini_inetd.c b/third_party/heimdal/lib/roken/test-mini_inetd.c index 079ace266a1f..7ab996ae8b4c 100644 --- a/third_party/heimdal/lib/roken/test-mini_inetd.c +++ b/third_party/heimdal/lib/roken/test-mini_inetd.c @@ -144,7 +144,7 @@ test_simple_echo_client(void) } if (rv != strlen(test_strings[i])) { - fprintf (stderr, "[%s] Data length mismatch %d != %d\n", prog, rv, strlen(test_strings[i])); + fprintf (stderr, "[%s] Data length mismatch %d != %zu\n", prog, rv, strlen(test_strings[i])); rk_closesocket(s); return 1; } diff --git a/third_party/heimdal/lib/roken/timeval.c b/third_party/heimdal/lib/roken/timeval.c index 38b1f7ce9c34..3012513ee7d1 100644 --- a/third_party/heimdal/lib/roken/timeval.c +++ b/third_party/heimdal/lib/roken/timeval.c @@ -39,6 +39,93 @@ #include "roken.h" +ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL +rk_time_add(time_t t, time_t delta) +{ + if (delta == 0) + return t; + +#ifdef TIME_T_SIGNED + /* Signed overflow is UB in C */ +#if SIZEOF_TIME_T == 4 + if (t >= 0 && delta > 0 && INT32_MAX - t < delta) + /* Time left to hit INT32_MAX is less than what we want to add */ + return INT32_MAX; + else if (t == INT32_MIN && delta < 0) + /* Avoid computing -t when t == INT32_MIN! */ + return INT32_MIN; + else if (t < 0 && delta < 0 && INT32_MIN + (-t) > delta) + /* Time left to hit INT32_MIN is less than what we want to subtract */ + return INT32_MIN; + else + return t + delta; +#elif SIZEOF_TIME_T == 8 + if (t >= 0 && delta > 0 && INT64_MAX - t < delta) + return INT64_MAX; + else if (t == INT64_MIN && delta < 0) + /* Avoid computing -t when t == INT64_MIN! */ + return INT64_MIN; + else if (t < 0 && delta < 0 && INT64_MIN + (-t) > delta) + return INT64_MIN; + else + return t + delta; +#else +#error "Unexpected sizeof(time_t)" +#endif +#else + + /* Unsigned overflow is defined in C */ +#if SIZEOF_TIME_T == 4 + if (t + delta < t) + return UINT32_MAX; +#elif SIZEOF_TIME_T == 8 + if (t + delta < t) + return UINT64_MAX; +#else +#error "Unexpected sizeof(time_t)" +#endif +#endif + return t + delta; +} + +ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL +rk_time_sub(time_t t, time_t delta) +{ + if (delta == 0) + return t; +#ifdef TIME_T_SIGNED + if (delta > 0) + return rk_time_add(t, -delta); +#if SIZEOF_TIME_T == 4 + if (delta == INT32_MIN) { + if (t < 0) { + t = t + INT32_MAX; + return t + 1; + } + return INT32_MAX; + } + /* Safe to compute -delta, so use rk_time_add() to add -delta */ + return rk_time_add(t, -delta); +#elif SIZEOF_TIME_T == 8 + if (delta == INT64_MIN) { + if (t < 0) { + t = t + INT64_MAX; + return t + 1; + } + return INT64_MAX; + } + return rk_time_add(t, -delta); +#else +#error "Unexpected sizeof(time_t)" +#endif +#else + /* Both t and delta are non-negative. */ + if (delta > t) + return 0; +#endif + return t - delta; +} + /* * Make `t1' consistent. */ @@ -47,11 +134,11 @@ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL timevalfix(struct timeval *t1) { if (t1->tv_usec < 0) { - t1->tv_sec--; - t1->tv_usec += 1000000; + t1->tv_sec = rk_time_sub(t1->tv_sec, 1); + t1->tv_usec = 1000000; } if (t1->tv_usec >= 1000000) { - t1->tv_sec++; + t1->tv_sec = rk_time_add(t1->tv_sec, 1); t1->tv_usec -= 1000000; } } @@ -63,7 +150,7 @@ timevalfix(struct timeval *t1) ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL timevaladd(struct timeval *t1, const struct timeval *t2) { - t1->tv_sec += t2->tv_sec; + t1->tv_sec = rk_time_add(t1->tv_sec, t2->tv_sec); t1->tv_usec += t2->tv_usec; timevalfix(t1); } @@ -75,7 +162,125 @@ timevaladd(struct timeval *t1, const struct timeval *t2) ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL timevalsub(struct timeval *t1, const struct timeval *t2) { - t1->tv_sec -= t2->tv_sec; + t1->tv_sec = rk_time_sub(t1->tv_sec, t2->tv_sec); t1->tv_usec -= t2->tv_usec; timevalfix(t1); } + +#ifdef TEST +int +main(int argc, char **argv) +{ + time_t t, delta, r; + int e = 0; + + if (argc == 0) + return 0; /* Apparently POSIX and Linux allow this case */ + + argc--; + argv++; + + while (argc > 0) { + int64_t n; + time_t a; + char *ends; + + if (argc < 3) + errx(1, "Usage: [TIME +|- DELTA [== TIME]]"); + + errno = 0; + n = strtoll(argv[0], &ends, 0); + if (errno) + err(1, "Time value is invalid"); + if (*ends != '\0') + errx(1, "Time value is invalid"); + t = n; + + n = strtoll(argv[2], &ends, 0); + if (errno) + err(1, "Delta value is invalid"); + if (*ends != '\0') + errx(1, "Delta value is invalid"); + delta = n; + + if (argv[1][0] == '+' && argv[1][1] == '\0') + r = rk_time_add(t, delta); + else if (argv[1][0] == '-' && argv[1][1] == '\0') + r = rk_time_sub(t, delta); + else + errx(1, "Operator must be a + or a - arithmetic operator"); + + if (delta == 0 && r != t) { + warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[0]); + e = 1; + } + if (t == 0 && r != delta) { + warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[2]); + e = 1; + } + + if (argc > 4 && strcmp(argv[3], "==") == 0) { + n = strtoll(argv[4], &ends, 0); + if (errno) + err(1, "Time value is invalid"); + if (*ends != '\0') + errx(1, "Time value is invalid"); + a = n; + if (a != r) { + warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[4]); + e = 1; + } + argc -= 5; + argv += 5; + } else { +#ifdef TIME_T_SIGNED + printf("%s %s %s == %lld\n", argv[0], argv[1], argv[2], + (long long)r); +#else + printf("%s %s %s == %llu\n", argv[0], argv[1], argv[2], + (unsigned long long)r); +#endif + argc -= 3; + argv += 3; + } + } + +#define CHECK(e) do { if (!(e)) errx(1, "Expression not true: " #e "!"); } while (0) +#ifdef TIME_T_SIGNED +#if SIZEOF_TIME_T == 4 + CHECK(rk_time_add(INT32_MIN, -1) == INT32_MIN); + CHECK(rk_time_sub(INT32_MIN, 1) == INT32_MIN); + CHECK(rk_time_sub(-1, INT32_MAX) == INT32_MIN); + CHECK(rk_time_add(INT32_MAX, 0) == INT32_MAX); + CHECK(rk_time_add(INT32_MAX, 1) == INT32_MAX); + CHECK(rk_time_add(1, INT32_MAX) == INT32_MAX); + CHECK(rk_time_add(0, INT32_MAX) == INT32_MAX); +#elif SIZEOF_TIME_T == 8 + CHECK(rk_time_add(INT64_MIN, -1) == INT64_MIN); + CHECK(rk_time_sub(INT64_MIN, 1) == INT64_MIN); + CHECK(rk_time_sub(-1, INT64_MAX) == INT64_MIN); + CHECK(rk_time_add(INT64_MAX, 0) == INT64_MAX); + CHECK(rk_time_add(INT64_MAX, 1) == INT64_MAX); + CHECK(rk_time_add(1, INT64_MAX) == INT64_MAX); + CHECK(rk_time_add(0, INT64_MAX) == INT64_MAX); +#endif + CHECK(rk_time_add(0, -1) == -1); + CHECK(rk_time_sub(0, 1) == -1); +#else +#if SIZEOF_TIME_T == 4 + CHECK(rk_time_add(UINT32_MAX, 0) == UINT32_MAX); + CHECK(rk_time_add(UINT32_MAX, 1) == UINT32_MAX); + CHECK(rk_time_add(1, UINT32_MAX) == UINT32_MAX); + CHECK(rk_time_add(0, UINT32_MAX) == UINT32_MAX); +#elif SIZEOF_TIME_T == 8 + CHECK(rk_time_add(UINT64_MAX, 0) == UINT64_MAX); + CHECK(rk_time_add(UINT64_MAX, 1) == UINT64_MAX); + CHECK(rk_time_add(1, UINT64_MAX) == UINT64_MAX); + CHECK(rk_time_add(0, UINT64_MAX) == UINT64_MAX); +#endif +#endif + CHECK(rk_time_add(0, 1) == 1); + CHECK(rk_time_add(1, 0) == 1); + return e; +} +#endif diff --git a/third_party/heimdal/lib/roken/version-script.map b/third_party/heimdal/lib/roken/version-script.map index 3307341c0494..be1713e82610 100644 --- a/third_party/heimdal/lib/roken/version-script.map +++ b/third_party/heimdal/lib/roken/version-script.map @@ -2,7 +2,6 @@ HEIMDAL_ROKEN_2.0 { global: arg_printusage; arg_printusage_i18n; - cgetcap; cgetclose; cgetmatch; cgetnum; @@ -40,8 +39,6 @@ HEIMDAL_ROKEN_2.0 { rk_bswap16; rk_bswap32; rk_bswap64; - rk_cgetent; - rk_cgetstr; rk_cloexec; rk_cloexec_dir; rk_cloexec_file; @@ -164,6 +161,8 @@ HEIMDAL_ROKEN_2.0 { rk_tdelete; rk_tfind; rk_timegm; + rk_time_add; + rk_time_sub; rk_timevaladd; rk_timevalfix; rk_timevalsub; diff --git a/third_party/heimdal/lib/roken/vis.c b/third_party/heimdal/lib/roken/vis.c index c598967fb72a..0fe44ae35023 100644 --- a/third_party/heimdal/lib/roken/vis.c +++ b/third_party/heimdal/lib/roken/vis.c @@ -377,12 +377,12 @@ rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra if (flag & VIS_HTTPSTYLE) { for (start = dst; len > 0; len--) { c = *src++; - dst = do_hvis(dst, c, flag, len ? *src : '\0', nextra); + dst = do_hvis(dst, c, flag, *src, nextra); } } else { for (start = dst; len > 0; len--) { c = *src++; - dst = do_svis(dst, c, flag, len ? *src : '\0', nextra); + dst = do_svis(dst, c, flag, *src, nextra); } } free(nextra); @@ -440,16 +440,18 @@ rk_strrasvisx(char **out, return -1; } if (have < want) { - if ((s = realloc(*out, want)) == NULL) + if ((s = realloc(s, want)) == NULL) return -1; *outsz = want; *out = s; } + if (*out == NULL) { + errno = EINVAL; + return -1; + } **out = '\0'; /* Makes source debugging nicer, that's all */ - if ((r = strsvisx(*out, csrc, len, flag, extra)) < 0) - return r; - errno = *out ? errno : EINVAL; - return *out ? r : -1; + r = strsvisx(*out, csrc, len, flag, extra); + return r; } #if !HAVE_VIS @@ -641,6 +643,7 @@ main(int argc, char **argv) } free(nextra); + free(s); return 0; } #endif diff --git a/third_party/heimdal/lib/sl/Makefile.am b/third_party/heimdal/lib/sl/Makefile.am index 152b86a330a2..1213d8c9df97 100644 --- a/third_party/heimdal/lib/sl/Makefile.am +++ b/third_party/heimdal/lib/sl/Makefile.am @@ -8,7 +8,7 @@ endif AM_CPPFLAGS += $(ROKEN_RENAME) -YFLAGS = -d +YFLAGS = -d -o slc-gram.c LFLAGS = @FLEXNOUNPUTARGS@ include_HEADERS = sl.h diff --git a/third_party/heimdal/lib/sl/sl.c b/third_party/heimdal/lib/sl/sl.c index 03f577b5f594..b78f9f675b25 100644 --- a/third_party/heimdal/lib/sl/sl.c +++ b/third_party/heimdal/lib/sl/sl.c @@ -460,6 +460,8 @@ sl_did_you_mean(SL_cmd *cmds, const char *match) for (n = 0, c = cmds; c->name; c++, n++) ; + if (n == 0) + return; metrics = calloc(n, sizeof(metrics[0])); if (metrics == NULL) return; diff --git a/third_party/heimdal/lib/sl/slc-gram.y b/third_party/heimdal/lib/sl/slc-gram.y index 767ffc833c86..38045c10048a 100644 --- a/third_party/heimdal/lib/sl/slc-gram.y +++ b/third_party/heimdal/lib/sl/slc-gram.y @@ -689,6 +689,7 @@ gen_wrapper(struct assignment *as) cprint(1, "return 0;\n"); cprint(0, "}\n"); cprint(0, "\n"); + free(n); } char cname[PATH_MAX]; diff --git a/third_party/heimdal/lib/wind/idn-lookup.c b/third_party/heimdal/lib/wind/idn-lookup.c index 1bc63a33dd8a..378c912a392d 100644 --- a/third_party/heimdal/lib/wind/idn-lookup.c +++ b/third_party/heimdal/lib/wind/idn-lookup.c @@ -156,7 +156,9 @@ main(int argc, char **argv) if (argc == 0) usage(1); - for (i = 0; i < argc; ++i) - lookup(argv[i]); + for (i = 0; i < argc; ++i) { + if (argv[i][0]) /* Quiet lint */ + lookup(argv[i]); + } return 0; } diff --git a/third_party/heimdal/lib/wind/utf8.c b/third_party/heimdal/lib/wind/utf8.c index d69db0c0cec1..452b7b260d84 100644 --- a/third_party/heimdal/lib/wind/utf8.c +++ b/third_party/heimdal/lib/wind/utf8.c @@ -205,18 +205,20 @@ wind_ucs4utf8(const uint32_t *in, size_t in_len, char *out, size_t *out_len) case 4: out[3] = (ch | 0x80) & 0xbf; ch = ch >> 6; - /* FALLTHROUGH */ + fallthrough; case 3: out[2] = (ch | 0x80) & 0xbf; ch = ch >> 6; - /* FALLTHROUGH */ + fallthrough; case 2: out[1] = (ch | 0x80) & 0xbf; ch = ch >> 6; - /* FALLTHROUGH */ + fallthrough; case 1: out[0] = ch | first_char[len - 1]; - /* FALLTHROUGH */ + fallthrough; + default: + break; } } out += len; @@ -484,14 +486,16 @@ wind_ucs2utf8(const uint16_t *in, size_t in_len, char *out, size_t *out_len) case 3: out[2] = (ch | 0x80) & 0xbf; ch = ch >> 6; - /* FALLTHROUGH */ + fallthrough; case 2: out[1] = (ch | 0x80) & 0xbf; ch = ch >> 6; - /* FALLTHROUGH */ + fallthrough; case 1: out[0] = ch | first_char[len - 1]; - /* FALLTHROUGH */ + fallthrough; + default: + break; } out += len; } diff --git a/third_party/heimdal/packages/windows/installer/NTMakefile b/third_party/heimdal/packages/windows/installer/NTMakefile index ad63ae04f4c8..2923e649b969 100644 --- a/third_party/heimdal/packages/windows/installer/NTMakefile +++ b/third_party/heimdal/packages/windows/installer/NTMakefile @@ -133,7 +133,13 @@ clean:: ###################################################################### # Runtime modules -!if [ $(PERL) $(SRC)\cf\w32-detect-vc-version.pl $(CC) ]==16 +!if [ $(PERL) $(SRC)\cf\w32-detect-vc-version.pl $(CC) ]==19 +VCVER=VC2019 +!elseif [ $(PERL) $(SRC)\cf\w32-detect-vc-version.pl $(CC) ]==18 +VCVER=VC2018 +!elseif [ $(PERL) $(SRC)\cf\w32-detect-vc-version.pl $(CC) ]==17 +VCVER=VC2017 +!elseif [ $(PERL) $(SRC)\cf\w32-detect-vc-version.pl $(CC) ]==16 VCVER=VC100 !elseif [ $(PERL) $(SRC)\cf\w32-detect-vc-version.pl $(CC) ]==15 VCVER=VC90 @@ -164,22 +170,27 @@ MMDIR=$(SystemDrive)\Program Files (x86)\Common Files\Merge Modules !endif !endif -!if exist("$(MMDIR)") - -RUNTIMEMODULE32="$(MMDIR)\Microsoft_$(VCVER)_$(CRTNAME)_x86.msm" -!if "$(VCVER)"=="VC100" -RUNTIMEMODULE64="$(MMDIR)\Microsoft_$(VCVER)_$(CRTNAME)_x64.msm" +# +# Don't specify a runtime module when the Universal C Runtime +# is available. +# +!if "$(APPVER)"=="10.0" +RUNTIMEMODULE32="" +RUNTIMEMODULE64="" !else +! if exist("$(MMDIR)") +RUNTIMEMODULE32="$(MMDIR)\Microsoft_$(VCVER)_$(CRTNAME)_x86.msm" +! if "$(VCVER)"=="VC90" || "$(VCVER)"=="VC80" RUNTIMEMODULE64="$(MMDIR)\Microsoft_$(VCVER)_$(CRTNAME)_x86_x64.msm" -!endif - -!else +! else +RUNTIMEMODULE64="$(MMDIR)\Microsoft_$(VCVER)_$(CRTNAME)_x64.msm" +! endif +! else RUNTIMEMODULE32="$(MSSDK)\Redist\VC\microsoft.vcxx.crt.x86_msm.msm" RUNTIMEMODULE64="$(MSSDK)\Redist\VC\microsoft.vcxx.crt.x64_msm.msm" - +! endif !endif - ###################################################################### # Heimdal installer diff --git a/third_party/heimdal/packages/windows/installer/heimdal-installer.wxs b/third_party/heimdal/packages/windows/installer/heimdal-installer.wxs index 0b6000d1bfa0..8ac6cc665fdb 100644 --- a/third_party/heimdal/packages/windows/installer/heimdal-installer.wxs +++ b/third_party/heimdal/packages/windows/installer/heimdal-installer.wxs @@ -99,9 +99,10 @@ - - + + + @@ -127,9 +128,10 @@ - - + + + @@ -370,12 +372,12 @@ - + - + @@ -393,7 +395,7 @@ - + diff --git a/third_party/heimdal/tests/bin/setup-env.in b/third_party/heimdal/tests/bin/setup-env.in index 954a2c1d5f5f..c9291d08bf20 100644 --- a/third_party/heimdal/tests/bin/setup-env.in +++ b/third_party/heimdal/tests/bin/setup-env.in @@ -28,6 +28,7 @@ kadmin="${TESTS_ENVIRONMENT} ${top_builddir}/kadmin/kadmin" kadmind="${TESTS_ENVIRONMENT} ${top_builddir}/kadmin/kadmind" kdc="${TESTS_ENVIRONMENT} ${top_builddir}/kdc/kdc" kdc_tester="${TESTS_ENVIRONMENT} ${top_builddir}/kdc/kdc-tester" +kcm="${TESTS_ENVIRONMENT} ${top_builddir}/kcm/kcm" test_csr_authorizer="${TESTS_ENVIRONMENT} ${top_builddir}/kdc/test_csr_authorizer" test_kdc_ca="${TESTS_ENVIRONMENT} ${top_builddir}/kdc/test_kdc_ca" test_token_validator="${TESTS_ENVIRONMENT} ${top_builddir}/kdc/test_token_validator" diff --git a/third_party/heimdal/tests/gss/Makefile.am b/third_party/heimdal/tests/gss/Makefile.am index ca40ae26bd2d..2de36bfe24cf 100644 --- a/third_party/heimdal/tests/gss/Makefile.am +++ b/third_party/heimdal/tests/gss/Makefile.am @@ -95,7 +95,9 @@ EXTRA_DIST = \ check-spnego.in \ check-ntlm.in \ check-context.in \ + check-negoex.in \ ntlm-user-file.txt \ krb5.conf.in \ + include-krb5.conf \ new_clients_k5.conf.in \ mech.in diff --git a/third_party/heimdal/tests/gss/check-basic.in b/third_party/heimdal/tests/gss/check-basic.in index d4916bd46d4b..c5151c4c94f1 100644 --- a/third_party/heimdal/tests/gss/check-basic.in +++ b/third_party/heimdal/tests/gss/check-basic.in @@ -94,10 +94,10 @@ echo "Doing database check" ${kadmin} check ${R} || exit 1 echo Starting kdc -${kdc} --testing --detach || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` -trap "kill ${kdcpid}; echo signal killing kdc; exit 1;" EXIT +trap "kill -9 ${kdcpid}; echo signal killing kdc; cat messages.log; exit 1;" EXIT exitcode=0 diff --git a/third_party/heimdal/tests/gss/check-context.in b/third_party/heimdal/tests/gss/check-context.in index 42ea15eecb9c..46c058d068b4 100644 --- a/third_party/heimdal/tests/gss/check-context.in +++ b/third_party/heimdal/tests/gss/check-context.in @@ -115,10 +115,10 @@ ${kadmin} check ${R} || exit 1 echo u1 > ${objdir}/foopassword echo Starting kdc -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` -trap "kill ${kdcpid}; echo signal killing kdc; exit 1;" EXIT +trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT testfailed="echo test failed; cat messages.log; exit 1" @@ -245,6 +245,14 @@ for mech in krb5 krb5iov spnego spnegoiov; do { eval "$testfailed"; } done +echo "======test authz-data (krb5)" +${context} --mech-type=krb5 \ + --mutual \ + --wrapunwrap \ + --on-behalf-of=foo@BAR.TEST.H5L.SE \ + --name-type=hostbased-service host@lucid.test.h5l.se || + { eval "$testfailed"; } + echo "======dce-style" for mech in krb5 krb5iov spnego; do iov="" diff --git a/third_party/heimdal/tests/gss/check-gssmask.in b/third_party/heimdal/tests/gss/check-gssmask.in index 44769eff5840..539e2e94e527 100644 --- a/third_party/heimdal/tests/gss/check-gssmask.in +++ b/third_party/heimdal/tests/gss/check-gssmask.in @@ -93,10 +93,10 @@ echo "Doing database check" ${kadmin} check ${R} || exit 1 echo Starting kdc -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` -trap "kill ${kdcpid}; echo signal killing kdc; exit 1;" EXIT +trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT exitcode=0 diff --git a/third_party/heimdal/tests/gss/check-ntlm.in b/third_party/heimdal/tests/gss/check-ntlm.in index f5bf3446ae61..f953630d09db 100644 --- a/third_party/heimdal/tests/gss/check-ntlm.in +++ b/third_party/heimdal/tests/gss/check-ntlm.in @@ -107,10 +107,10 @@ echo u1 > ${objdir}/foopassword echo ds > ${objdir}/barpassword echo Starting kdc -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` -trap "kill ${kdcpid}; echo signal killing kdc; exit 1;" EXIT +trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT exitcode=0 diff --git a/third_party/heimdal/tests/gss/check-spnego.in b/third_party/heimdal/tests/gss/check-spnego.in index 3cf560896021..d6e4d8331529 100644 --- a/third_party/heimdal/tests/gss/check-spnego.in +++ b/third_party/heimdal/tests/gss/check-spnego.in @@ -106,10 +106,10 @@ echo u1 > ${objdir}/foopassword echo ds > ${objdir}/barpassword echo Starting kdc -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` -trap "kill ${kdcpid}; echo signal killing kdc; exit 1;" EXIT +trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT exitcode=0 diff --git a/third_party/heimdal/tests/gss/krb5.conf.in b/third_party/heimdal/tests/gss/krb5.conf.in index b8e04b65159e..aae031db645e 100644 --- a/third_party/heimdal/tests/gss/krb5.conf.in +++ b/third_party/heimdal/tests/gss/krb5.conf.in @@ -18,6 +18,21 @@ include @srcdirabs@/include-krb5.conf } [kdc] + enable-digest = true + allow-anonymous = true + digests_allowed = chap-md5,digest-md5,ntlm-v1,ntlm-v1-session,ntlm-v2,ms-chap-v2 + strict-nametypes = true + synthetic_clients = true + enable_gss_preauth = true + gss_mechanisms_allowed = sanon-x25519 + enable-pkinit = true + pkinit_identity = FILE:@srcdir@/../../lib/hx509/data/kdc.crt,@srcdir@/../../lib/hx509/data/kdc.key + pkinit_anchors = FILE:@srcdir@/../../lib/hx509/data/ca.crt + pkinit_pool = FILE:@srcdir@/../../lib/hx509/data/sub-ca.crt +# pkinit_revoke = CRL:@srcdir@/../../lib/hx509/data/crl1.crl + pkinit_mappings_file = @srcdir@/pki-mapping + pkinit_allow_proxy_certificate = true + database = { dbname = @objdir@/current-db realm = TEST.H5L.SE diff --git a/third_party/heimdal/tests/java/check-kinit.in b/third_party/heimdal/tests/java/check-kinit.in index 04043ca02e21..820334474095 100644 --- a/third_party/heimdal/tests/java/check-kinit.in +++ b/third_party/heimdal/tests/java/check-kinit.in @@ -90,7 +90,7 @@ ${kadmin} add -p kaka --use-defaults ${server}@${R} || exit 1 ${kadmin} ext -k ${keytab} ${server}@${R} || exit 1 echo Starting kdc -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/Makefile.am b/third_party/heimdal/tests/kdc/Makefile.am index a07f776eb23c..f61a7e853077 100644 --- a/third_party/heimdal/tests/kdc/Makefile.am +++ b/third_party/heimdal/tests/kdc/Makefile.am @@ -4,6 +4,7 @@ noinst_DATA = \ an2ln-db.txt \ kdc-tester4.json \ krb5.conf \ + krb5-kcm.conf \ krb5-cccol.conf \ krb5-authz.conf \ krb5-authz2.conf \ @@ -204,6 +205,13 @@ krb5.conf: krb5.conf.in Makefile -e 's,[@]kdc[@],,g' < $(srcdir)/krb5.conf.in > krb5.conf.tmp && \ mv krb5.conf.tmp krb5.conf +krb5-kcm.conf: krb5-kcm.conf.in Makefile + $(do_subst) \ + -e 's,[@]WEAK[@],false,g' \ + -e 's,[@]dk[@],,g' \ + -e 's,[@]kdc[@],,g' < $(srcdir)/krb5-kcm.conf.in > krb5-kcm.conf.tmp && \ + mv krb5-kcm.conf.tmp krb5-kcm.conf + krb5-cccol.conf: krb5-cccol.conf.in Makefile $(do_subst) \ -e 's,[@]WEAK[@],false,g' \ @@ -383,23 +391,23 @@ EXTRA_DIST = \ NTMakefile \ an2ln-db.txt \ check-authz.in \ + check-bx509.in \ check-canon.in \ check-cc.in \ check-delegation.in \ check-des.in \ check-digest.in \ check-fast.in \ + check-hdb-mitdb.in \ + check-httpkadmind.in \ check-iprop.in \ check-kadmin.in \ - check-kinit.in \ - check-hdb-mitdb.in \ - check-kdc.in \ check-kdc-weak.in \ + check-kdc.in \ check-keys.in \ + check-kinit.in \ check-kpasswdd.in \ check-pkinit.in \ - check-bx509.in \ - check-httpkadmind.in \ check-referral.in \ check-tester.in \ check-uu.in \ @@ -409,23 +417,25 @@ EXTRA_DIST = \ hdb-mitdb.mkey \ heimdal.acl \ iprop-acl \ + k5login/foo \ + k5login/mapped_user1 \ kdc-tester1.json \ kdc-tester2.json \ kdc-tester3.json \ kdc-tester4.json.in \ - krb5-pkinit.conf.in \ - krb5-bx509.conf.in \ - krb5-httpkadmind.conf.in \ - krb5.conf.in \ krb5-authz.conf.in \ krb5-authz2.conf.in \ + krb5-bx509.conf.in \ krb5-canon.conf.in \ krb5-canon2.conf.in \ + krb5-cccol.conf.in \ krb5-hdb-mitdb.conf.in \ + krb5-httpkadmind.conf.in \ + krb5-pkinit.conf.in \ + krb5.conf.in \ krb5.conf.keys.in \ - k5login/foo \ - ntlm-user-file.txt \ leaks-kill.sh \ + ntlm-user-file.txt \ pki-mapping \ uuserver.txt \ wait-kdc.sh diff --git a/third_party/heimdal/tests/kdc/check-bx509.in b/third_party/heimdal/tests/kdc/check-bx509.in index 1cef2e0e766d..b50239d84400 100644 --- a/third_party/heimdal/tests/kdc/check-bx509.in +++ b/third_party/heimdal/tests/kdc/check-bx509.in @@ -428,7 +428,7 @@ ${kadmin} add -r --use-defaults HTTP/${otherserver}@${R} || exit 1 ${kadmin} ext_keytab -r -k $ukeytab foo@${R} || exit 1 echo "Starting kdc"; -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid} ${bx509pid}; echo signal killing kdc and bx509d; exit 1;" EXIT @@ -590,7 +590,8 @@ KRB5CCNAME=$cache $gsstoken HTTP@$server | KRB5_KTNAME="$keytab" $gsstoken -r || { echo "Trivial offline CA test failed (gss-token)"; exit 2; } # Check that we get up to three tixaddrs k/v in the log -grep 'REQ.*numtixaddrs=4 tixaddrs=IPv4:8.8.8.8 tixaddrs=IPv4:8.9.10.11 tixaddrs=IPv4:11.11.11.11.*wrongaddr=yes' ${objdir}/messages.log || +grep 'REQ.*wrongaddr=true' ${objdir}/messages.log | + grep 'tixaddrs=IPv4:11.11.11.11' || { echo "KDC not warning about requests from wrong address"; exit 2; } echo "Fetching a Negotiate token" diff --git a/third_party/heimdal/tests/kdc/check-canon.in b/third_party/heimdal/tests/kdc/check-canon.in index 0bb5a413f3cf..18b83a9b7a69 100644 --- a/third_party/heimdal/tests/kdc/check-canon.in +++ b/third_party/heimdal/tests/kdc/check-canon.in @@ -99,7 +99,7 @@ ${kadmin} check ${R3} || exit 1 echo foo > ${objdir}/foopassword echo "Starting kdc" ; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-cc.in b/third_party/heimdal/tests/kdc/check-cc.in index ce95b300664a..46e846a10ea1 100644 --- a/third_party/heimdal/tests/kdc/check-cc.in +++ b/third_party/heimdal/tests/kdc/check-cc.in @@ -86,9 +86,16 @@ ${kadmin} check ${R} || exit 1 echo foo > ${objdir}/foopassword echo Starting kdc ; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` +echo Starting kcm ; > messages.log +${kcm} -s ${objdir} --detach || { echo "kcm failed to start"; cat messages.log; exit 1; } +kcmpid=`getpid kcm` + +HEIM_IPC_DIR=${objdir} +export HEIM_IPC_DIR + trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT ec=0 @@ -133,6 +140,41 @@ ${klist} -l | grep foo@ >/dev/null && { ec=1 ; eval "${testfailed}"; } echo "check that bar is gone" ${klist} -l | grep bar@ >/dev/null && { ec=1 ; eval "${testfailed}"; } +echo "getting tickets (KCM)"; > messages.log +KRB5_CONFIG="${objdir}/krb5-kcm.conf" +export KRB5_CONFIG +unset KRB5CCNAME +${kinit} --default-for-principal foo@${R} +${kinit} --default-for-principal bar@${R} +${kinit} bar@${R} +${klist} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} | grep foo@${R} > /dev/null && { ec=1 ; eval "${testfailed}"; } +${klist} -l | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} -l | grep foo@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} -c KCM: | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +KRB5CCNAME=KCM: ${klist} | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +if [ -n "$BASH_VERSION" ]; then + ${klist} -c KCM:${UID} | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } + ${klist} -c KCM:${UID}: | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } + KRB5CCNAME=KCM:${UID} ${klist} | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } + KRB5CCNAME=KCM:${UID}: ${klist} | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +fi +${kdestroy} -A +${klist} 2>/dev/null && { ec=1 ; eval "${testfailed}"; } +${klist} -l | grep bar@${R} > /dev/null && { ec=1 ; eval "${testfailed}"; } +${klist} -l | grep foo@${R} > /dev/null && { ec=1 ; eval "${testfailed}"; } +${kinit} bar@${R} +${kinit} --default-for-principal foo@${R} +${klist} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} | grep foo@${R} > /dev/null && { ec=1 ; eval "${testfailed}"; } +${klist} -l | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} -l | grep foo@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${klist} -c KCM: | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +KRB5CCNAME=KCM: ${klist} | grep bar@${R} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${kdestroy} -A + echo "getting tickets (DIR)"; > messages.log KRB5_CONFIG="${objdir}/krb5-cccol.conf" export KRB5_CONFIG @@ -150,6 +192,9 @@ ${klist} -l | grep "bar@TEST.H5L.SE.*FILE:${objdir}/cc_dir/tkt.bar@TEST.H5L.SE" > /dev/null || { ec=1 ; eval "${testfailed}"; } +echo "killing kcm (${kcmpid})" +sh ${leaks_kill} kcm $kcmpid || exit 1 + echo "killing kdc (${kdcpid})" sh ${leaks_kill} kdc $kdcpid || exit 1 diff --git a/third_party/heimdal/tests/kdc/check-delegation.in b/third_party/heimdal/tests/kdc/check-delegation.in index 8657946168ad..fdff0f6a0f0f 100644 --- a/third_party/heimdal/tests/kdc/check-delegation.in +++ b/third_party/heimdal/tests/kdc/check-delegation.in @@ -102,7 +102,7 @@ ${kadmin} check ${R4} || exit 1 echo foo > ${objdir}/foopassword echo Starting kdc; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-des.in b/third_party/heimdal/tests/kdc/check-des.in index d45b119dfa5d..144613df4f99 100644 --- a/third_party/heimdal/tests/kdc/check-des.in +++ b/third_party/heimdal/tests/kdc/check-des.in @@ -96,7 +96,7 @@ ${kadmin} check ${R} || exit 1 echo foo > ${objdir}/foopassword echo Starting kdc; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-digest.in b/third_party/heimdal/tests/kdc/check-digest.in index 1623783eba6d..d934f4e28983 100644 --- a/third_party/heimdal/tests/kdc/check-digest.in +++ b/third_party/heimdal/tests/kdc/check-digest.in @@ -95,7 +95,7 @@ echo $password > ${objdir}/foopassword echo "Starting kdc" ; > messages.log env ${HEIM_MALLOC_DEBUG} ${kdc} --detach --testing || - { echo "kdc failed to start"; exit 1; } + { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; cat messages.log; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-fast.in b/third_party/heimdal/tests/kdc/check-fast.in index 136bf3ed62b0..3fbda813a63b 100644 --- a/third_party/heimdal/tests/kdc/check-fast.in +++ b/third_party/heimdal/tests/kdc/check-fast.in @@ -88,7 +88,7 @@ echo bar > ${objdir}/barpassword echo Starting kdc ; > messages.log env MallocStackLogging=1 MallocStackLoggingNoCompact=1 MallocErrorAbort=1 MallocLogFile=${objdir}/malloc-log \ -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; cat messages.log; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-hdb-mitdb.in b/third_party/heimdal/tests/kdc/check-hdb-mitdb.in index e9de58799a31..a241aeb4a8ff 100644 --- a/third_party/heimdal/tests/kdc/check-hdb-mitdb.in +++ b/third_party/heimdal/tests/kdc/check-hdb-mitdb.in @@ -85,7 +85,7 @@ echo foo > ${objdir}/foopassword echo Starting kdc ; > messages.log env MallocStackLogging=1 MallocStackLoggingNoCompact=1 MallocErrorAbort=1 MallocLogFile=${objdir}/malloc-log \ -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-httpkadmind.in b/third_party/heimdal/tests/kdc/check-httpkadmind.in index b593925a3524..f57f2af85928 100644 --- a/third_party/heimdal/tests/kdc/check-httpkadmind.in +++ b/third_party/heimdal/tests/kdc/check-httpkadmind.in @@ -519,7 +519,7 @@ ${hxtool} issue-certificate \ { echo "Failed to make PKINIT client cert"; exit 1; } echo "Starting kdc needed for httpkadmind authentication to kadmind" -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` echo "Starting httpkadmind with remote HDBs only" diff --git a/third_party/heimdal/tests/kdc/check-iprop.in b/third_party/heimdal/tests/kdc/check-iprop.in index 212968779435..524379393faa 100644 --- a/third_party/heimdal/tests/kdc/check-iprop.in +++ b/third_party/heimdal/tests/kdc/check-iprop.in @@ -314,7 +314,7 @@ cleanup() { trap cleanup EXIT echo Starting kdc ; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` echo "starting master" ; > messages.log diff --git a/third_party/heimdal/tests/kdc/check-kadmin.in b/third_party/heimdal/tests/kdc/check-kadmin.in index 3d3f41003d86..45d679ceb4a4 100644 --- a/third_party/heimdal/tests/kdc/check-kadmin.in +++ b/third_party/heimdal/tests/kdc/check-kadmin.in @@ -97,7 +97,7 @@ ${kadmin} -l cpw --pruneall --random-key pruneall@${R} || exit 1 echo "$foopassword" > ${objdir}/foopassword echo Starting kdc ; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid} ${kadmpid}" EXIT diff --git a/third_party/heimdal/tests/kdc/check-kdc.in b/third_party/heimdal/tests/kdc/check-kdc.in index 75626f6ce853..e53293b2427f 100644 --- a/third_party/heimdal/tests/kdc/check-kdc.in +++ b/third_party/heimdal/tests/kdc/check-kdc.in @@ -78,6 +78,8 @@ server=host/datan.test.h5l.se server2=host/computer.example.com server3=host/refer-me-out.test.h5l.se server4=host/no-auth-data-reqd.test.h5l.se +server5=host/a-host.refer-all-out.test.h5l.se +namespace=WELLKNOWN/HOSTBASED-NAMESPACE/_/refer-all-out.test.h5l.se serverip=host/10.11.12.13 serveripname=host/ip.test.h5l.org serveripname2=host/10.11.12.14 @@ -240,6 +242,9 @@ ${kadmin} add -p foo --use-defaults referral-placeholder@${R5} || exit 1 ${kadmin} add_alias referral-placeholder@${R5} ${server3}@${R} || exit 1 ${kadmin5} add -p kaka --use-defaults ${server3}@${R5} || exit 1 ${kadmin5} ext -k ${keytab} ${server3}@${R5} || exit 1 +${kadmin} add_alias referral-placeholder@${R5} ${namespace}@${R} || exit 1 +${kadmin5} add -p kaka --use-defaults ${server5}@${R5} || exit 1 +${kadmin5} ext -k ${keytab} ${server5}@${R5} || exit 1 ${kadmin} add -p kaka --use-defaults ${serverip}@${R} || exit 1 ${kadmin} ext -k ${keytab} ${serverip}@${R} || exit 1 ${kadmin} add -p kaka --use-defaults ${serveripname}@${R} || exit 1 @@ -364,7 +369,7 @@ echo notfoo > ${objdir}/notfoopassword echo Starting kdc ; > messages.log env MallocStackLogging=1 MallocStackLoggingNoCompact=1 MallocErrorAbort=1 MallocLogFile=${objdir}/malloc-log \ ${kdc} --detach --testing || - { echo "kdc failed to start"; exit 1; } + { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` echo Starting kpasswdd; > messages.log @@ -444,6 +449,8 @@ echo "Getting x-realm tickets with capaths for $R -> $R5" ${kgetcred} foo@${R5} || { ec=1 ; eval "${testfailed}"; } echo "Testing HDB referral entry" ${kgetcred} --canonicalize ${server3}@${R} || { ec=1 ; eval "${testfailed}"; } +echo "Testing HDB namespace referral entry" +${kgetcred} --canonicalize ${server5}@${R} || { ec=1 ; eval "${testfailed}"; } ${klist} ${kdestroy} diff --git a/third_party/heimdal/tests/kdc/check-kinit.in b/third_party/heimdal/tests/kdc/check-kinit.in index 35ec6deadbfa..c6cb23ff6f8c 100644 --- a/third_party/heimdal/tests/kdc/check-kinit.in +++ b/third_party/heimdal/tests/kdc/check-kinit.in @@ -107,7 +107,7 @@ if (($# == 0)); then echo foo > ${objdir}/foopassword echo Starting kdc ; > messages.log - ${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } + ${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-kpasswdd.in b/third_party/heimdal/tests/kdc/check-kpasswdd.in index 4f63ce240fad..39f12e1be8c3 100644 --- a/third_party/heimdal/tests/kdc/check-kpasswdd.in +++ b/third_party/heimdal/tests/kdc/check-kpasswdd.in @@ -103,7 +103,7 @@ echo foo > ${objdir}/foopassword echo Starting kdc ; > messages.log env ${HEIM_MALLOC_DEBUG} ${kdc} --detach --testing || - { echo "kdc failed to start"; exit 1; } + { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` echo Starting kpasswdd diff --git a/third_party/heimdal/tests/kdc/check-pkinit.in b/third_party/heimdal/tests/kdc/check-pkinit.in index baa9fb306916..9f90fd040f9a 100644 --- a/third_party/heimdal/tests/kdc/check-pkinit.in +++ b/third_party/heimdal/tests/kdc/check-pkinit.in @@ -199,7 +199,7 @@ echo foo > ${objdir}/foopassword echo Starting kdc ; > messages.log KRB5_CONFIG="${objdir}/krb5-pkinit2.conf" -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap 'kill -9 ${kdcpid}; echo signal killing kdc; cat ca.crt kdc.crt pkinit.crt pkinit-synthetic.crt; exit 1;' EXIT @@ -232,7 +232,7 @@ ${kdestroy} echo "Restarting kdc ($kdcpid)" sh ${leaks_kill} kdc $kdcpid || ec=1 KRB5_CONFIG="${objdir}/krb5-pkinit.conf" -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` echo "Trying pk-init (principal in cert)"; > messages.log diff --git a/third_party/heimdal/tests/kdc/check-referral.in b/third_party/heimdal/tests/kdc/check-referral.in index d028e39ef1fa..73c26c368caa 100644 --- a/third_party/heimdal/tests/kdc/check-referral.in +++ b/third_party/heimdal/tests/kdc/check-referral.in @@ -105,7 +105,7 @@ ${kadmin} check ${R2} || exit 1 echo foo > ${objdir}/foopassword echo Starting kdc ; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/check-tester.in b/third_party/heimdal/tests/kdc/check-tester.in index dba154c299b9..83b48baf27fa 100644 --- a/third_party/heimdal/tests/kdc/check-tester.in +++ b/third_party/heimdal/tests/kdc/check-tester.in @@ -46,6 +46,9 @@ testfailed="echo test failed; cat messages.log; exit 1" # If there is no useful db support compiled in, disable test ${have_db} || exit 77 +# Do not run in GutHub valgrind builds -- too slow / not necessary +[ -n "$CHECK_TESTER_NO_VALGRIND" ] && exit 77 + R=TEST.H5L.SE keytabfile=${objdir}/server.keytab diff --git a/third_party/heimdal/tests/kdc/check-uu.in b/third_party/heimdal/tests/kdc/check-uu.in index 7e819a14ad0d..ef831ca4d94a 100644 --- a/third_party/heimdal/tests/kdc/check-uu.in +++ b/third_party/heimdal/tests/kdc/check-uu.in @@ -86,7 +86,7 @@ ${kadmin} check ${R} || exit 1 echo foo > ${objdir}/foopassword echo Starting kdc ; > messages.log -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill -9 ${kdcpid} ${uuspid}; echo signal killing kdc; exit 1;" EXIT diff --git a/third_party/heimdal/tests/kdc/krb5-kcm.conf.in b/third_party/heimdal/tests/kdc/krb5-kcm.conf.in new file mode 100644 index 000000000000..bdcca073cc02 --- /dev/null +++ b/third_party/heimdal/tests/kdc/krb5-kcm.conf.in @@ -0,0 +1,165 @@ +[libdefaults] + default_realm = TEST.H5L.SE TEST2.H5L.SE + default_ccache_name = KCM:%{uid} + no-addresses = TRUE + allow_weak_crypto = @WEAK@ + dns_lookup_kdc = no + dns_lookup_realm = no + + +[appdefaults] + pkinit_anchors = FILE:@srcdir@/../../lib/hx509/data/ca.crt + reconnect-min = 2s + reconnect-backoff = 2s + reconnect-max = 10s + +[realms] + TEST.H5L.SE = { + kdc = localhost:@port@ + admin_server = localhost:@admport@ + kpasswd_server = localhost:@pwport@ + } + SUB.TEST.H5L.SE = { + kdc = localhost:@port@ + } + TEST2.H5L.SE = { + kdc = localhost:@port@ + kpasswd_server = localhost:@pwport@ + } + TEST3.H5L.SE = { + kdc = localhost:@port@ + } + TEST4.H5L.SE = { + kdc = localhost:@port@ + } + SOME-REALM5.FR = { + kdc = localhost:@port@ + } + SOME-REALM6.US = { + kdc = localhost:@port@ + } + SOME-REALM7.UK = { + kdc = localhost:@port@ + } + SOME-REALM8.UK = { + kdc = localhost:@port@ + } + TEST-HTTP.H5L.SE = { + kdc = http/localhost:@port@ + } + H1.TEST.H5L.SE = { + kdc = localhost:@port@ + } + H2.TEST.H5L.SE = { + kdc = localhost:@port@ + } + H3.H2.TEST.H5L.SE = { + kdc = localhost:@port@ + } + H4.H2.TEST.H5L.SE = { + kdc = localhost:@port@ + } + +[domain_realm] + .test.h5l.se = TEST.H5L.SE + .sub.test.h5l.se = SUB.TEST.H5L.SE + .h1.test.h5l.se = H1.TEST.H5L.SE + .h2.test.h5l.se = H2.TEST.H5L.SE + .h3.h2.test.h5l.se = H3.H2.TEST.H5L.SE + .h4.h2.test.h5l.se = H4.H2.TEST.H5L.SE + .example.com = TEST2.H5L.SE + localhost = TEST.H5L.SE + .localdomain = TEST.H5L.SE + localdomain = TEST.H5L.SE + .localdomain6 = TEST.H5L.SE + localdomain6 = TEST.H5L.SE + + +[kdc] + enable-digest = true + allow-anonymous = true + digests_allowed = chap-md5,digest-md5,ntlm-v1,ntlm-v1-session,ntlm-v2,ms-chap-v2 + strict-nametypes = true + + enable-http = true + + enable-pkinit = true + pkinit_identity = FILE:@srcdir@/../../lib/hx509/data/kdc.crt,@srcdir@/../../lib/hx509/data/kdc.key + pkinit_anchors = FILE:@srcdir@/../../lib/hx509/data/ca.crt + pkinit_pool = FILE:@srcdir@/../../lib/hx509/data/sub-ca.crt +# pkinit_revoke = CRL:@srcdir@/../../lib/hx509/data/crl1.crl + pkinit_mappings_file = @srcdir@/pki-mapping + pkinit_allow_proxy_certificate = true + + database = { + label = { + dbname = @db_type@:@objdir@/current-db@kdc@ + realm = TEST.H5L.SE + mkey_file = @objdir@/mkey.file + acl_file = @srcdir@/heimdal.acl + log_file = @objdir@/current@kdc@.log + } + label2 = { + dbname = @db_type@:@objdir@/current-db@kdc@ + realm = TEST2.H5L.SE + mkey_file = @objdir@/mkey.file + acl_file = @srcdir@/heimdal.acl + log_file = @objdir@/current@kdc@.log + } + label3 = { + dbname = sqlite:@objdir@/current-db@kdc@.sqlite3 + realm = SOME-REALM5.FR + mkey_file = @objdir@/mkey.file + acl_file = @srcdir@/heimdal.acl + log_file = @objdir@/current@kdc@.log + } + } + + signal_socket = @objdir@/signal + iprop-stats = @objdir@/iprop-stats + iprop-acl = @srcdir@/iprop-acl + log-max-size = 40000 + +[hdb] + db-dir = @objdir@ + +[logging] + kdc = 0-/FILE:@objdir@/messages.log + krb5 = 0-/FILE:@objdir@/messages.log + default = 0-/FILE:@objdir@/messages.log + +# If you are doing preformance measurements on OSX you want to change +# the kdc LOG line from = to - below to keep the FILE open and avoid +# open/write/close which is blocking (rdar:// ) on OSX. +# kdc = 0-/FILE=@objdir@/messages.log + +[kadmin] + save-password = true + default_key_rules = { + */des3-only@* = des3-cbc-sha1:pw-salt + */aes-only@* = aes256-cts-hmac-sha1-96:pw-salt + } + @dk@ + +[capaths] + TEST.H5L.SE = { + TEST2.H5L.SE = . + SOME-REALM5.FR = 1 + TEST3.H5L.SE = TEST2.H5L.SE + TEST4.H5L.SE = TEST2.H5L.SE + TEST4.H5L.SE = TEST3.H5L.SE + SOME-REALM6.US = SOME-REALM5.FR + SOME-REALM7.UK = SOME-REALM6.US + SOME-REALM7.UK = SOME-REALM5.FR + SOME-REALM8.UK = SOME-REALM6.US + } + H4.H2.TEST.H5L.SE = { + H1.TEST.H5L.SE = H3.H2.TEST.H5L.SE + H1.TEST.H5L.SE = H2.TEST.H5L.SE + H1.TEST.H5L.SE = TEST.H5L.SE + + TEST.H5L.SE = H3.H2.TEST.H5L.SE + TEST.H5L.SE = H2.TEST.H5L.SE + + H2.TEST.H5L.SE = H3.H2.TEST.H5L.SE + } diff --git a/third_party/heimdal/tests/kdc/krb5.conf.in b/third_party/heimdal/tests/kdc/krb5.conf.in index 19b4e3ef64ea..a85836d76b24 100644 --- a/third_party/heimdal/tests/kdc/krb5.conf.in +++ b/third_party/heimdal/tests/kdc/krb5.conf.in @@ -126,6 +126,9 @@ [hdb] db-dir = @objdir@ + enable_virtual_hostbased_princs = true + virtual_hostbased_princ_mindots = 1 + virtual_hostbased_princ_maxdots = 3 [logging] kdc = 0-/FILE:@objdir@/@messages@.log diff --git a/third_party/heimdal/tests/ldap/check-ldap.in b/third_party/heimdal/tests/ldap/check-ldap.in index b99c951032bb..f73eb6e1b88b 100644 --- a/third_party/heimdal/tests/ldap/check-ldap.in +++ b/third_party/heimdal/tests/ldap/check-ldap.in @@ -120,7 +120,7 @@ ${kadmin} list '*' > /dev/null || exit 1 echo "$foopassword" > ${objdir}/foopassword echo Starting kdc -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill ${kdcpid}; echo signal killing kdc; sh ${srcdir}/slapd-stop ; exit 1;" EXIT diff --git a/third_party/heimdal/tests/plugin/Makefile.am b/third_party/heimdal/tests/plugin/Makefile.am index 3fb1a2324b9b..5dd43ccb04da 100644 --- a/third_party/heimdal/tests/plugin/Makefile.am +++ b/third_party/heimdal/tests/plugin/Makefile.am @@ -29,10 +29,10 @@ krb5.conf: krb5.conf.in Makefile $(do_subst) < $(srcdir)/krb5.conf.in > krb5.conf.tmp mv krb5.conf.tmp krb5.conf -lib_LTLIBRARIES = windc.la +lib_LTLIBRARIES = kdc_test_plugin.la -windc_la_SOURCES = windc.c -windc_la_LDFLAGS = -module +kdc_test_plugin_la_SOURCES = kdc_test_plugin.c +kdc_test_plugin_la_LDFLAGS = -module CLEANFILES= \ $(TESTS) \ diff --git a/third_party/heimdal/tests/plugin/check-pac.in b/third_party/heimdal/tests/plugin/check-pac.in index 60ec21a31f36..85bf8cd9a98d 100644 --- a/third_party/heimdal/tests/plugin/check-pac.in +++ b/third_party/heimdal/tests/plugin/check-pac.in @@ -108,15 +108,15 @@ echo "Empty log" > messages.log echo Starting kdc -${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; } +${kdc} --detach --testing || { echo "kdc failed to start"; cat messages.log; exit 1; } kdcpid=`getpid kdc` trap "kill ${kdcpid}; echo signal killing kdc; exit 1;" EXIT ec=0 -echo "Check that WINDC module was loaded " -grep "windc init" messages.log >/dev/null || \ +echo "Check that KDC plugin module was loaded " +grep "kdc plugin init" messages.log >/dev/null || \ { ec=1 ; eval "${testfailed}"; } echo "Getting client initial tickets"; > messages.log diff --git a/third_party/heimdal/tests/plugin/kdc_test_plugin.c b/third_party/heimdal/tests/plugin/kdc_test_plugin.c new file mode 100644 index 000000000000..4fcf311fddfe --- /dev/null +++ b/third_party/heimdal/tests/plugin/kdc_test_plugin.c @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include + +static krb5_error_code KRB5_CALLCONV +init(krb5_context context, void **ctx) +{ + krb5_warnx(context, "kdc plugin init"); + *ctx = NULL; + return 0; +} + +static void KRB5_CALLCONV +fini(void *ctx) +{ +} + +static krb5_error_code KRB5_CALLCONV +pac_generate(void *ctx, + krb5_context context, + krb5_kdc_configuration *config, + hdb_entry *client, + hdb_entry *server, + const krb5_keyblock *pk_replykey, + uint64_t pac_attributes, + krb5_pac *pac) +{ + krb5_error_code ret; + krb5_data data; + + if ((pac_attributes & (KRB5_PAC_WAS_REQUESTED | + KRB5_PAC_WAS_GIVEN_IMPLICITLY)) == 0) { + *pac = NULL; + return 0; + } + + krb5_warnx(context, "pac generate"); + + data.data = "\x00\x01"; + data.length = 2; + + ret = krb5_pac_init(context, pac); + if (ret) + return ret; + + ret = krb5_pac_add_buffer(context, *pac, 1, &data); + if (ret) + return ret; + + return 0; +} + +static krb5_error_code KRB5_CALLCONV +pac_verify(void *ctx, + krb5_context context, + krb5_kdc_configuration *config, + const krb5_principal new_ticket_client, + const krb5_principal delegation_proxy, + hdb_entry * client, + hdb_entry * server, + hdb_entry * krbtgt, + krb5_pac *pac) +{ + krb5_error_code ret; + krb5_data data; + krb5_cksumtype cstype; + uint16_t rodc_id; + krb5_enctype etype; + Key *key; + + krb5_warnx(context, "pac_verify"); + + ret = krb5_pac_get_buffer(context, *pac, 1, &data); + if (ret) + return ret; + krb5_data_free(&data); + + ret = krb5_pac_get_kdc_checksum_info(context, *pac, &cstype, &rodc_id); + if (ret) + return ret; + + if (rodc_id == 0 || rodc_id != krbtgt->kvno >> 16) { + krb5_warnx(context, "Wrong RODCIdentifier"); + return EINVAL; + } + + ret = krb5_cksumtype_to_enctype(context, cstype, &etype); + if (ret) + return ret; + + ret = hdb_enctype2key(context, krbtgt, NULL, etype, &key); + if (ret) + return ret; + + return krb5_pac_verify(context, *pac, 0, NULL, NULL, &key->key); +} + +static void logit(const char *what, astgs_request_t r) +{ + krb5_context context = kdc_request_get_context((kdc_request_t)r); + const char *cname = kdc_request_get_cname((kdc_request_t)r); + const char *sname = kdc_request_get_sname((kdc_request_t)r); + + krb5_warnx(context, "%s: client %s server %s", + what, + cname ? cname : "", + sname ? sname : ""); +} + +static krb5_error_code KRB5_CALLCONV +client_access(void *ctx, astgs_request_t r) +{ + logit("client_access", r); + + return 0; +} + +static krb5_error_code KRB5_CALLCONV +finalize_reply(void *ctx, astgs_request_t r) +{ + heim_number_t n; + krb5_error_code ret; + + logit("finalize_reply", r); + + n = heim_number_create(1234); + if (n == NULL) + return ENOMEM; + + ret = kdc_request_set_attribute((kdc_request_t)r, + HSTR("org.h5l.tests.kdc-plugin"), n); + heim_release(n); + + return ret; +} + +static krb5_error_code KRB5_CALLCONV +audit(void *ctx, astgs_request_t r) +{ + krb5_error_code ret = kdc_request_get_error_code((kdc_request_t)r); + heim_number_t n; + + logit("audit", r); + + if (ret) + return 0; /* finalize_reply only called in success */ + + n = kdc_request_get_attribute((kdc_request_t)r, + HSTR("org.h5l.tests.kdc-plugin")); + + heim_assert(n && heim_number_get_int(n) == 1234, + "attribute not passed from finalize_reply"); + + if (n == NULL || heim_number_get_int(n) != 1234) + return EINVAL; /* return value is ignored, but for completeness */ + + return 0; +} + +static krb5plugin_kdc_ftable kdc_plugin = { + KRB5_PLUGIN_KDC_VERSION_10, + init, + fini, + pac_generate, + pac_verify, + client_access, + NULL, /* referral_policy */ + finalize_reply, + audit +}; + +static const krb5plugin_kdc_ftable *const kdc_plugins[] = { + &kdc_plugin +}; + +krb5_error_code KRB5_CALLCONV +kdc_plugin_load(krb5_context context, + krb5_get_instance_func_t *get_instance, + size_t *num_plugins, + const krb5plugin_kdc_ftable *const **plugins); + +static uintptr_t KRB5_CALLCONV +kdc_plugin_get_instance(const char *libname) +{ + if (strcmp(libname, "hdb") == 0) + return hdb_get_instance(libname); + else if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + + return 0; +} + +krb5_error_code KRB5_CALLCONV +kdc_plugin_load(krb5_context context, + krb5_get_instance_func_t *get_instance, + size_t *num_plugins, + const krb5plugin_kdc_ftable *const **plugins) +{ + *get_instance = kdc_plugin_get_instance; + *num_plugins = sizeof(kdc_plugins) / sizeof(kdc_plugins[0]); + *plugins = kdc_plugins; + + return 0; +} diff --git a/third_party/heimdal/tests/plugin/krb5.conf.in b/third_party/heimdal/tests/plugin/krb5.conf.in index 8ab2f17177c1..d188c314b360 100644 --- a/third_party/heimdal/tests/plugin/krb5.conf.in +++ b/third_party/heimdal/tests/plugin/krb5.conf.in @@ -19,6 +19,21 @@ } [kdc] + enable-digest = true + allow-anonymous = true + digests_allowed = chap-md5,digest-md5,ntlm-v1,ntlm-v1-session,ntlm-v2,ms-chap-v2 + strict-nametypes = true + synthetic_clients = true + enable_gss_preauth = true + gss_mechanisms_allowed = sanon-x25519 + enable-pkinit = true + pkinit_identity = FILE:@srcdir@/../../lib/hx509/data/kdc.crt,@srcdir@/../../lib/hx509/data/kdc.key + pkinit_anchors = FILE:@srcdir@/../../lib/hx509/data/ca.crt + pkinit_pool = FILE:@srcdir@/../../lib/hx509/data/sub-ca.crt +# pkinit_revoke = CRL:@srcdir@/../../lib/hx509/data/crl1.crl + pkinit_mappings_file = @srcdir@/pki-mapping + pkinit_allow_proxy_certificate = true + database = { dbname = @objdir@/current-db realm = TEST.H5L.SE diff --git a/third_party/heimdal/tests/plugin/windc.c b/third_party/heimdal/tests/plugin/windc.c deleted file mode 100644 index 357148019ae8..000000000000 --- a/third_party/heimdal/tests/plugin/windc.c +++ /dev/null @@ -1,161 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static krb5_error_code KRB5_CALLCONV -windc_init(krb5_context context, void **ctx) -{ - krb5_warnx(context, "windc init"); - *ctx = NULL; - return 0; -} - -static void KRB5_CALLCONV -windc_fini(void *ctx) -{ -} - -static krb5_error_code KRB5_CALLCONV -pac_generate(void *ctx, krb5_context context, - struct hdb_entry_ex *client, - struct hdb_entry_ex *server, - const krb5_keyblock *pk_replykey, - uint64_t pac_attributes, - krb5_pac *pac) -{ - krb5_error_code ret; - krb5_data data; - - if ((pac_attributes & (KRB5_PAC_WAS_REQUESTED | - KRB5_PAC_WAS_GIVEN_IMPLICITLY)) == 0) { - *pac = NULL; - return 0; - } - - krb5_warnx(context, "pac generate"); - - data.data = "\x00\x01"; - data.length = 2; - - ret = krb5_pac_init(context, pac); - if (ret) - return ret; - - ret = krb5_pac_add_buffer(context, *pac, 1, &data); - if (ret) - return ret; - - return 0; -} - -static krb5_error_code KRB5_CALLCONV -pac_verify(void *ctx, krb5_context context, - const krb5_principal new_ticket_client, - const krb5_principal delegation_proxy, - struct hdb_entry_ex * client, - struct hdb_entry_ex * server, - struct hdb_entry_ex * krbtgt, - krb5_pac *pac) -{ - krb5_error_code ret; - krb5_data data; - krb5_cksumtype cstype; - uint16_t rodc_id; - krb5_enctype etype; - Key *key; - - krb5_warnx(context, "pac_verify"); - - ret = krb5_pac_get_buffer(context, *pac, 1, &data); - if (ret) - return ret; - krb5_data_free(&data); - - ret = krb5_pac_get_kdc_checksum_info(context, *pac, &cstype, &rodc_id); - if (ret) - return ret; - - if (rodc_id == 0 || rodc_id != krbtgt->entry.kvno >> 16) { - krb5_warnx(context, "Wrong RODCIdentifier"); - return EINVAL; - } - - ret = krb5_cksumtype_to_enctype(context, cstype, &etype); - if (ret) - return ret; - - ret = hdb_enctype2key(context, &krbtgt->entry, NULL, etype, &key); - if (ret) - return ret; - - return krb5_pac_verify(context, *pac, 0, NULL, NULL, &key->key); -} - -static void logit(const char *what, astgs_request_t r) -{ - krb5_warnx(r->context, "%s: client %s server %s", - what, - r->cname ? r->cname : "", - r->sname ? r->sname : ""); -} - -static krb5_error_code KRB5_CALLCONV -client_access(void *ctx, astgs_request_t r) -{ - logit("client_access", r); - return 0; -} - -static krb5_error_code KRB5_CALLCONV -finalize_reply(void *ctx, astgs_request_t r) -{ - logit("finalize_reply", r); - return 0; -} - -static krb5plugin_windc_ftable windc = { - KRB5_WINDC_PLUGING_MINOR, - windc_init, - windc_fini, - pac_generate, - pac_verify, - client_access, - finalize_reply -}; - -static const krb5plugin_windc_ftable *const windc_plugins[] = { - &windc -}; - -krb5_error_code KRB5_CALLCONV -windc_plugin_load(krb5_context context, - krb5_get_instance_func_t *get_instance, - size_t *num_plugins, - const krb5plugin_windc_ftable *const **plugins); - -static uintptr_t KRB5_CALLCONV -windc_get_instance(const char *libname) -{ - if (strcmp(libname, "hdb") == 0) - return hdb_get_instance(libname); - else if (strcmp(libname, "krb5") == 0) - return krb5_get_instance(libname); - - return 0; -} - -krb5_error_code KRB5_CALLCONV -windc_plugin_load(krb5_context context, - krb5_get_instance_func_t *get_instance, - size_t *num_plugins, - const krb5plugin_windc_ftable *const **plugins) -{ - *get_instance = windc_get_instance; - *num_plugins = sizeof(windc_plugins) / sizeof(windc_plugins[0]); - *plugins = windc_plugins; - - return 0; -} diff --git a/third_party/heimdal/windows/NTMakefile.sdk b/third_party/heimdal/windows/NTMakefile.sdk new file mode 100644 index 000000000000..a9f2b30dfdf3 --- /dev/null +++ b/third_party/heimdal/windows/NTMakefile.sdk @@ -0,0 +1,130 @@ +######################################################################## +# +# Copyright (c) 2021, PADL Software Pty Ltd. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - 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. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +# COPYRIGHT HOLDER 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. +# + +!if !defined(CPU) || "$(CPU)" == "" +CPU =AMD64 +!endif + +!if "$(CPU)" == "X86" || "$(CPU)" == "x86" +CPU =i386 +!endif + +!if !defined(APPVER) +APPVER =6.1 +!endif + +!if "$(APPVER)" == "5.0" +NMAKE_WINVER=0x0500 +!elseif "$(APPVER)" == "5.01" +NMAKE_WINVER=0x0501 +!elseif "$(APPVER)" == "5.02" +NMAKE_WINVER=0x0502 +!elseif "$(APPVER)" == "6.0" +NMAKE_WINVER=0x0600 +!elseif "$(APPVER)" == "6.1" +NMAKE_WINVER=0x0601 +!elseif "$(APPVER)" == "10.0" +NMAKE_WINVER=0x0A00 +!else +!error Unknown value for APPVER +!endif + +cc = cl +link = link +implib = lib + +cflags = -c -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -nologo -GS -W4 + +!if "$(CPU)" == "i386" +cflags = $(cflags) -D_X86_=1 +!endif +!if "$(CPU)" == "AMD64" +cflags = $(cflags) -D_AMD64_=1 +!endif +!if "$(CPU)" == "ARM" +cflags = $(cflags) -D_ARM_=1 +!endif +!if "$(CPU)" == "ARM64" +cflags = $(cflags) -D_ARM64_=1 +!endif + +cflags = $(cflags) -DWIN32 -D_WIN32 +!if "$(CPU)" == "AMD64" || "$(CPU)" == "ARM64" +cflags = $(cflags) -DWIN64 -D_WIN64 +!endif + +cflags = $(cflags) -D_WINNT -D_WIN32_WINNT=$(NMAKE_WINVER) +cflags = $(cflags) -DNTDDI_VERSION=$(NMAKE_WINVER)0000 +cflags = $(cflags) -D_WIN32_IE=$(NMAKE_WINVER) -DWINVER=$(NMAKE_WINVER) + +!ifdef NODEBUG +cdebug = -Ox -DNDEBUG +!else +cdebug = -Zi -Od -DDEBUG +!endif + +cvarsmt = -D_MT +cvarsdll = -D_MT -D_DLL +!ifdef NODEBUG +cvarsmt = $(cvarsmt) -MT +cvarsdll = $(cvarsdll) -MD +!else +cvarsmt = $(cvarsmt) -MTd +cvarsdll = $(cvarsdll) -MDd +!endif +cvars = $(cvarsmt) + +lflags = $(lflags) /INCREMENTAL:NO /NOLOGO +!ifdef NODEBUG +ldebug = /RELEASE +!else +ldebug = /DEBUG /DEBUGTYPE:cv +!endif + +!if "$(CPU)" == "i386" +dllentry = _DllMainCRTStartup@12 +!else +dllentry = _DllMainCRTStartup +!endif + +conlflags = $(lflags) -subsystem:console,$(APPVER) +guilflags = $(lflags) -subsystem:windows,$(APPVER) +dlllflags = $(lflags) -entry:$(dllentry) -dll + +baselibs = kernel32.lib ws2_32.lib mswsock.lib advapi32.lib +conlibs = $(baselibs) +conlibsmt = $(baselibs) +conlibsdll = $(baselibs) + +winlibs = $(baselibs) user32.lib gdi32.lib comdlg32.lib winspool.lib +guilibs = $(winlibs) +guilibsmt = $(winlibs) +guilibsdll = $(winlibs) diff --git a/third_party/heimdal/windows/NTMakefile.w32 b/third_party/heimdal/windows/NTMakefile.w32 index 47df51042a28..471e783912be 100644 --- a/third_party/heimdal/windows/NTMakefile.w32 +++ b/third_party/heimdal/windows/NTMakefile.w32 @@ -39,7 +39,7 @@ prep:: all:: prep -!include +!include "NTMakefile.sdk" !ifdef NODEBUG BUILD=rel @@ -207,6 +207,8 @@ EXEGUILINK_C = $(LINK) $(ldebug) $(guilflags) $(guilibsdll) $(libmach) DLLCONLINK_C = $(LINK) $(ldebug) $(dlllflags) $(conlibsdll) $(libmach) DLLGUILINK_C = $(LINK) $(ldebug) $(dlllflags) $(guilibsdll) $(libmach) +C2OBJ_C_MT = $(CC) $(cdebug) $(cflags) $(cvarsmt) $(AUXCFLAGS) $(intcflags) $(cdefines) $(cincdirs) $(cwarn) + !else # STATICRUNTIME C2OBJ_C = $(CC) $(cdebug) $(cflags) $(cvarsmt) $(AUXCFLAGS) $(intcflags) $(cdefines) $(cincdirs) $(cwarn) @@ -440,7 +442,7 @@ clean:: -$(RM) $(OBJ)\*.* !endif -.SUFFIXES: .c .cpp .hin .h .x .hx +.SUFFIXES: .c .cpp .hin .h .hx #---------------------------------------------------------------------- # Manifest handling @@ -574,6 +576,7 @@ DLLPREP_MERGE=\ # LIBASN1 =$(LIBDIR)\libasn1.lib +LIBASN1_S =$(LIBDIR)\libasn1_s.lib LIBCOMERR =$(LIBDIR)\libcom_err.lib LIBEDITLINE =$(LIBDIR)\libeditline.lib LIBGSSAPI =$(LIBDIR)\libgssapi.lib -- 2.25.1 From b60f45b9f1aebe64cf37d74ebf981071199033ad Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 14:09:52 +1300 Subject: [PATCH 08/22] third_party/heimdal_build: Add source files to build This is an adaptation to Heimdal: commit be708ca3cf98900c61919f8ff7ced4428b5d1f32 Author: Nicolas Williams Date: Wed Dec 22 17:01:12 2021 -0600 gsskrb5: Add simple name attributes support This adds Kerberos mechanism support for: - composite principal name export/import - getting rudimentary name attributes from GSS names using gss_get_name_attribute(): - all (raw) authorization data from the Ticket - all (raw) authorization data from the Authenticator - transit path - realm - component count - each component - gss_inquire_name() - gss_display_name_ext() (just for the hostbased service name type though) The test exercises almost all of the functionality, except for: - getting the PAC - getting authz-data from the Authenticator - getting the transit path TBD (much) later: - amend test_context to do minimal name attribute checks as well - gss_set_name_attribute() (to request authz-data) - gss_delete_name_attribute() - getting specific authorization data elements via URN fragments (as opposed to all of them) - parsing the PAC, extracting SIDs (each one as a separate value) - some configurable local policy (?) - plugin interface for additional local policy NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit f2ca9c5db7e1bb20cfc6705633b48c32b1496334) --- third_party/heimdal_build/wscript_build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/third_party/heimdal_build/wscript_build b/third_party/heimdal_build/wscript_build index cf7c2b9a3428..76e88bc103e0 100644 --- a/third_party/heimdal_build/wscript_build +++ b/third_party/heimdal_build/wscript_build @@ -549,6 +549,7 @@ if not bld.CONFIG_SET("USING_SYSTEM_GSSAPI"): lib/gssapi/krb5/inquire_names_for_mech.c lib/gssapi/krb5/indicate_mechs.c lib/gssapi/krb5/inquire_sec_context_by_oid.c + lib/gssapi/krb5/name_attrs.c lib/gssapi/krb5/export_sec_context.c lib/gssapi/krb5/import_sec_context.c lib/gssapi/krb5/duplicate_name.c @@ -658,6 +659,8 @@ if not bld.CONFIG_SET("USING_SYSTEM_GSSAPI"): lib/gssapi/mech/gss_release_name.c lib/gssapi/mech/gss_set_cred_option.c lib/gssapi/mech/gss_pseudo_random.c + lib/gssapi/mech/gss_authorize_localname.c + lib/gssapi/mech/gss_get_name_attribute.c lib/gssapi/mech/gssspi_exchange_meta_data.c lib/gssapi/mech/gssspi_query_mechanism_info.c lib/gssapi/mech/gssspi_query_meta_data.c -- 2.25.1 From a16c1210440a81f964d1940cd94c414a8aceecae Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 21 Feb 2022 20:28:42 +1300 Subject: [PATCH 09/22] s4:kdc: Refactor HDB API This is an adaptation to Heimdal: commit b1dcc1a47485165ada778ef3c3463cfc0779d183 Author: Luke Howard Date: Fri Dec 31 17:24:58 2021 +1100 kdc: refactor Samba-specific auditing API in terms of existing API Make Samba-specific HDB auth status API a wrapper on the existing auditing API, with a view towards unifying the two APIs in a future commit. The term "auth status" is replaced with "auth event", and the HDB auth_status method is replaced with a more general purpose audit method which has access to the entire request structure. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit a2f7987d58372cfc52bc5f9786c0719439956fee) --- source4/kdc/hdb-samba4.c | 94 +++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index 71260d3ed0ab..60b6f94a32d2 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -500,15 +500,10 @@ static void send_bad_password_netlogon(TALLOC_CTX *mem_ctx, irpc_handle, &req); } -static krb5_error_code hdb_samba4_auth_status(krb5_context context, - HDB *db, - hdb_entry_ex *entry, - const struct timeval *start_time, - const struct sockaddr *from_addr, - const char *original_client_name, - int hdb_auth_status, - const char *auth_details, - const char *pa_type) +static krb5_error_code hdb_samba4_audit(krb5_context context, + HDB *db, + hdb_entry_ex *entry, + hdb_request_t r) { struct samba_kdc_db_context *kdc_db_ctx = talloc_get_type_abort(db->hdb_db, struct samba_kdc_db_context); @@ -516,16 +511,47 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, struct ldb_dn *domain_dn = ldb_get_default_basedn(kdc_db_ctx->samdb); uint64_t logon_id = generate_random_u64(); + heim_object_t auth_details_obj = NULL; + const char *auth_details = NULL; + + heim_object_t hdb_auth_status_obj = NULL; + int hdb_auth_status; + + heim_object_t pa_type_obj = NULL; + const char *pa_type = NULL; + + struct auth_usersupplied_info ui; + + size_t sa_socklen = 0; + + hdb_auth_status_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_AUTH_EVENT_TYPE); + if (hdb_auth_status_obj == NULL) { + /* No status code found, so just return. */ + return 0; + } + + hdb_auth_status = heim_number_get_int(hdb_auth_status_obj); + + pa_type_obj = heim_audit_getkv((heim_svc_req_desc)r, "pa"); + if (pa_type_obj != NULL) { + pa_type = heim_string_get_utf8(pa_type_obj); + } + + auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_AUTH_EVENT_DETAILS); + if (auth_details_obj != NULL) { + auth_details = heim_string_get_utf8(auth_details_obj); + } + /* * Forcing this via the NTLM auth structure is not ideal, but * it is the most practical option right now, and ensures the * logs are consistent, even if some elements are always NULL. */ - struct auth_usersupplied_info ui = { + ui = (struct auth_usersupplied_info) { .mapped_state = true, .was_mapped = true, .client = { - .account_name = original_client_name, + .account_name = r->cname, .domain_name = NULL, }, .service_description = "Kerberos KDC", @@ -534,9 +560,7 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, .logon_id = logon_id }; - size_t sa_socklen = 0; - - switch (from_addr->sa_family) { + switch (r->addr->sa_family) { case AF_INET: sa_socklen = sizeof(struct sockaddr_in); break; @@ -548,7 +572,7 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, } switch (hdb_auth_status) { - case HDB_AUTHSTATUS_AUTHORIZATION_SUCCESS: + case HDB_AUTH_EVENT_CLIENT_AUTHORIZED: { TALLOC_CTX *frame = talloc_stackframe(); struct samba_kdc_entry *p = talloc_get_type(entry->ctx, @@ -568,13 +592,13 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, talloc_free(frame); break; } - case HDB_AUTHSTATUS_CLIENT_LOCKED_OUT: - case HDB_AUTHSTATUS_CORRECT_PASSWORD: - case HDB_AUTHSTATUS_WRONG_PASSWORD: - case HDB_AUTHSTATUS_GENERIC_SUCCESS: - case HDB_AUTHSTATUS_GENERIC_FAILURE: - case HDB_AUTHSTATUS_PKINIT_SUCCESS: - case HDB_AUTHSTATUS_PKINIT_FAILURE: + case HDB_AUTH_EVENT_CLIENT_LOCKED_OUT: + case HDB_AUTH_EVENT_LTK_PREAUTH_SUCCEEDED: + case HDB_AUTH_EVENT_LTK_PREAUTH_FAILED: + case HDB_AUTH_EVENT_OTHER_PREAUTH_SUCCEEDED: + case HDB_AUTH_EVENT_OTHER_PREAUTH_FAILED: + case HDB_AUTH_EVENT_PKINIT_SUCCEEDED: + case HDB_AUTH_EVENT_PKINIT_FAILED: { TALLOC_CTX *frame = talloc_stackframe(); struct samba_kdc_entry *p = talloc_get_type(entry->ctx, @@ -589,7 +613,7 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, NTSTATUS status; int ret; - ret = tsocket_address_bsd_from_sockaddr(frame, from_addr, + ret = tsocket_address_bsd_from_sockaddr(frame, r->addr, sa_socklen, &remote_host); if (ret != 0) { @@ -613,7 +637,7 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, } ui.auth_description = auth_description; - if (hdb_auth_status == HDB_AUTHSTATUS_WRONG_PASSWORD) { + if (hdb_auth_status == HDB_AUTH_EVENT_LTK_PREAUTH_FAILED) { authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn); status = NT_STATUS_WRONG_PASSWORD; /* @@ -624,17 +648,17 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, if (kdc_db_ctx->rodc) { send_bad_password_netlogon(frame, kdc_db_ctx, &ui); } - } else if (hdb_auth_status == HDB_AUTHSTATUS_CLIENT_LOCKED_OUT) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_CLIENT_LOCKED_OUT) { status = NT_STATUS_ACCOUNT_LOCKED_OUT; - } else if (hdb_auth_status == HDB_AUTHSTATUS_CORRECT_PASSWORD) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_LTK_PREAUTH_SUCCEEDED) { status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTHSTATUS_GENERIC_SUCCESS) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_OTHER_PREAUTH_SUCCEEDED) { status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTHSTATUS_GENERIC_FAILURE) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_OTHER_PREAUTH_FAILED) { status = NT_STATUS_GENERIC_COMMAND_FAILED; - } else if (hdb_auth_status == HDB_AUTHSTATUS_PKINIT_SUCCESS) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_PKINIT_SUCCEEDED) { status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTHSTATUS_PKINIT_FAILURE) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_PKINIT_FAILED) { status = NT_STATUS_PKINIT_FAILURE; } else { status = NT_STATUS_INTERNAL_ERROR; @@ -642,7 +666,7 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, log_authentication_event(kdc_db_ctx->msg_ctx, kdc_db_ctx->lp_ctx, - start_time, + &r->tv_start, &ui, status, domain_name, @@ -651,12 +675,12 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, TALLOC_FREE(frame); break; } - case HDB_AUTHSTATUS_CLIENT_UNKNOWN: + case HDB_AUTH_EVENT_CLIENT_UNKNOWN: { struct tsocket_address *remote_host; int ret; TALLOC_CTX *frame = talloc_stackframe(); - ret = tsocket_address_bsd_from_sockaddr(frame, from_addr, + ret = tsocket_address_bsd_from_sockaddr(frame, r->addr, sa_socklen, &remote_host); if (ret != 0) { @@ -673,7 +697,7 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, log_authentication_event(kdc_db_ctx->msg_ctx, kdc_db_ctx->lp_ctx, - start_time, + &r->tv_start, &ui, NT_STATUS_NO_SUCH_USER, NULL, NULL, @@ -736,7 +760,7 @@ NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx, (*db)->hdb__del = NULL; (*db)->hdb_destroy = hdb_samba4_destroy; - (*db)->hdb_auth_status = hdb_samba4_auth_status; + (*db)->hdb_audit = hdb_samba4_audit; (*db)->hdb_check_constrained_delegation = hdb_samba4_check_constrained_delegation; (*db)->hdb_check_pkinit_ms_upn_match = hdb_samba4_check_pkinit_ms_upn_match; (*db)->hdb_check_client_matches_target_service = hdb_samba4_check_client_matches_target_service; -- 2.25.1 From 71b41ea2e3f6c830aa4b077f9cb7c57161adbc0d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 21 Feb 2022 20:45:45 +1300 Subject: [PATCH 10/22] s4:kdc: Adapt to removal of auth event details This is an adaptation to Heimdal: commit e15e711b13e2fb33f4480a054cba60b6c4c0183b Author: Luke Howard Date: Sat Jan 1 18:05:51 2022 +1100 kdc: remove auth_event_details audit key The auth event details audit key (formerly, parameter to auth_status) contained, variously, an encryption type name; a PKINIT client certificate name; or, a GSS initiator name. Audit these instead using individual keys that reflect the values' contents. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 7989ef0aa7b75b2e5af7be445fc64cbf49b2985c) --- source4/kdc/hdb-samba4.c | 42 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index 60b6f94a32d2..2f9d51d3c04a 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -45,6 +45,7 @@ #include "../lib/tsocket/tsocket.h" #include "librpc/gen_ndr/ndr_winbind_c.h" #include "lib/messaging/irpc.h" +#include "hdb.h" static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode) { @@ -514,6 +515,8 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, heim_object_t auth_details_obj = NULL; const char *auth_details = NULL; + char *etype_str = NULL; + heim_object_t hdb_auth_status_obj = NULL; int hdb_auth_status; @@ -524,7 +527,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, size_t sa_socklen = 0; - hdb_auth_status_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_AUTH_EVENT_TYPE); + hdb_auth_status_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_AUTH_EVENT); if (hdb_auth_status_obj == NULL) { /* No status code found, so just return. */ return 0; @@ -537,9 +540,37 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, pa_type = heim_string_get_utf8(pa_type_obj); } - auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_AUTH_EVENT_DETAILS); - if (auth_details_obj != NULL) { - auth_details = heim_string_get_utf8(auth_details_obj); + switch (hdb_auth_status) { + case HDB_AUTH_EVENT_PKINIT_SUCCEEDED: + case HDB_AUTH_EVENT_PKINIT_FAILED: + auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PKINIT_CLIENT_CERT); + if (auth_details_obj != NULL) { + auth_details = heim_string_get_utf8(auth_details_obj); + } + break; + + case HDB_AUTH_EVENT_GSS_PA_SUCCEEDED: + case HDB_AUTH_EVENT_GSS_PA_FAILED: + auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_GSS_INITIATOR); + if (auth_details_obj != NULL) { + auth_details = heim_string_get_utf8(auth_details_obj); + } + break; + + default: + { + heim_object_t etype_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PA_ETYPE); + if (etype_obj != NULL) { + int etype = heim_number_get_int(etype_obj); + + krb5_error_code ret = krb5_enctype_to_string(r->context, etype, &etype_str); + if (ret == 0) { + auth_details = etype_str; + } else { + auth_details = "unknown enctype"; + } + } + } } /* @@ -706,6 +737,9 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, break; } } + + free(etype_str); + return 0; } -- 2.25.1 From 69ba5464c00969d2e6a8a7af3eaab54c8545143f Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 12:16:49 +1300 Subject: [PATCH 11/22] s4:kdc: Add 'not authorised' auth events This is an adaptation to Heimdal: commit d683780b1d728bf8c5b794a1f66842e5a25bd360 Author: Luke Howard Date: Sat Jan 1 23:44:05 2022 +1100 kdc: separate PKINIT/GSS authorization failure Create a new audit event for PKINIT/GSS authorization (impersonation) failure NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 0d37a1928100e229bea46701b41d4efa72e10266) --- source4/kdc/hdb-samba4.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index 2f9d51d3c04a..1d273bf8da08 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -543,6 +543,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, switch (hdb_auth_status) { case HDB_AUTH_EVENT_PKINIT_SUCCEEDED: case HDB_AUTH_EVENT_PKINIT_FAILED: + case HDB_AUTH_EVENT_PKINIT_NOT_AUTHORIZED: auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PKINIT_CLIENT_CERT); if (auth_details_obj != NULL) { auth_details = heim_string_get_utf8(auth_details_obj); @@ -551,6 +552,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, case HDB_AUTH_EVENT_GSS_PA_SUCCEEDED: case HDB_AUTH_EVENT_GSS_PA_FAILED: + case HDB_AUTH_EVENT_GSS_PA_NOT_AUTHORIZED: auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_GSS_INITIATOR); if (auth_details_obj != NULL) { auth_details = heim_string_get_utf8(auth_details_obj); -- 2.25.1 From 0641f24f253f8c52cea84f2fc24fb84fe85cd4df Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 21 Feb 2022 19:25:06 +1300 Subject: [PATCH 12/22] s4:kdc: Add referral policy callback This is now used instead of a configuration option. This is an adaption to Heimdal: commit 3fa47f5a1a422e178d968a8ec0d59889eaa71548 Author: Luke Howard Date: Sun Jan 2 21:51:43 2022 +1100 kdc: add referral_policy callback to windc plugin Add a referral policy hook to the TGS as a more elegant way of resolving referral detection for Samba). The hook can either rewrite the server_princ in the request, or it can return an error to disable built-in referral processing. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit a5799cea037a4613ba4d1073fff6e6151ed06c76) --- source4/kdc/kdc-heimdal.c | 2 -- source4/kdc/wdc-samba4.c | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c index 2abb5eab9253..46fd8e61946a 100644 --- a/source4/kdc/kdc-heimdal.c +++ b/source4/kdc/kdc-heimdal.c @@ -408,8 +408,6 @@ static void kdc_post_fork(struct task_server *task, struct process_details *pd) kdc_config->svc_use_strongest_session_key = false; kdc_config->use_strongest_server_key = true; - kdc_config->autodetect_referrals = false; - kdc_config->force_include_pa_etype_salt = true; /* diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index e670f3226c53..4ba2f7938f56 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -28,6 +28,7 @@ #include "sdb.h" #include "sdb_hdb.h" #include "librpc/gen_ndr/auth.h" +#include /* * Given the right private pointer from hdb_samba4, @@ -952,6 +953,12 @@ static void samba_wdc_plugin_fini(void *ptr) return; } +static krb5_error_code samba_wdc_referral_policy(void *priv, + astgs_request_t r) +{ + return r->error_code; +} + struct krb5plugin_windc_ftable windc_plugin_table = { .minor_version = KRB5_WINDC_PLUGIN_MINOR, .init = samba_wdc_plugin_init, @@ -960,6 +967,7 @@ struct krb5plugin_windc_ftable windc_plugin_table = { .client_access = samba_wdc_check_client_access, .finalize_reply = samba_wdc_finalize_reply, .pac_generate = samba_wdc_get_pac, + .referral_policy = samba_wdc_referral_policy, }; -- 2.25.1 From 96057ac8a943cc5fac96abc422d29f70820a754d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 14:39:13 +1300 Subject: [PATCH 13/22] s4:kdc: Rename windc to kdc plugin This is an adaptation to Heimdal: commit fcff5933ade652343d7c169659da92fac0e6e0d4 Author: Luke Howard Date: Mon Jan 3 11:10:18 2022 +1100 kdc: rename windc to kdc plugin Rename the "windc" plugin API to the more general "kdc" plugin API, for two reasons: the Heimdal KDC uses the Windows PAC even when not emulating a domain controller, and the plugin API has accreted methods that are not specific to emulating a domain controller (such as referral_policy and finalize_reply). NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 83586e8f5846fff7a8bbe47e743e03166b559584) --- source4/kdc/kdc-glue.h | 2 +- source4/kdc/kdc-heimdal.c | 14 +++++++------- source4/kdc/wdc-samba4.c | 4 ++-- third_party/heimdal_build/krb5/kdc-plugin.h | 1 + third_party/heimdal_build/krb5/windc_plugin.h | 1 - third_party/heimdal_build/wscript_build | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 third_party/heimdal_build/krb5/kdc-plugin.h delete mode 100644 third_party/heimdal_build/krb5/windc_plugin.h diff --git a/source4/kdc/kdc-glue.h b/source4/kdc/kdc-glue.h index 3b85468c499e..2e58fcda1398 100644 --- a/source4/kdc/kdc-glue.h +++ b/source4/kdc/kdc-glue.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "kdc/samba_kdc.h" #include "kdc/kdc-server.h" diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c index 46fd8e61946a..96322cd1bb76 100644 --- a/source4/kdc/kdc-heimdal.c +++ b/source4/kdc/kdc-heimdal.c @@ -42,7 +42,7 @@ NTSTATUS server_service_kdc_init(TALLOC_CTX *); -extern struct krb5plugin_windc_ftable windc_plugin_table; +extern struct krb5plugin_kdc_ftable kdc_plugin_table; /** Wrapper for krb5_kdc_process_krb5_request, converting to/from Samba @@ -470,19 +470,19 @@ static void kdc_post_fork(struct task_server *task, struct process_details *pd) return; } - /* Register WinDC hooks */ + /* Register KDC hooks */ ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, - PLUGIN_TYPE_DATA, "windc", - &windc_plugin_table); + PLUGIN_TYPE_DATA, "kdc", + &kdc_plugin_table); if(ret) { - task_server_terminate(task, "kdc: failed to register windc plugin", true); + task_server_terminate(task, "kdc: failed to register kdc plugin", true); return; } - ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context); + ret = krb5_kdc_plugin_init(kdc->smb_krb5_context->krb5_context); if(ret) { - task_server_terminate(task, "kdc: failed to init windc plugin", true); + task_server_terminate(task, "kdc: failed to init kdc plugin", true); return; } diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 4ba2f7938f56..f4ac075e2d46 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -959,8 +959,8 @@ static krb5_error_code samba_wdc_referral_policy(void *priv, return r->error_code; } -struct krb5plugin_windc_ftable windc_plugin_table = { - .minor_version = KRB5_WINDC_PLUGIN_MINOR, +struct krb5plugin_kdc_ftable kdc_plugin_table = { + .minor_version = KRB5_KDC_PLUGIN_MINOR, .init = samba_wdc_plugin_init, .fini = samba_wdc_plugin_fini, .pac_verify = samba_wdc_reget_pac, diff --git a/third_party/heimdal_build/krb5/kdc-plugin.h b/third_party/heimdal_build/krb5/kdc-plugin.h new file mode 100644 index 000000000000..1b99a8d6a73b --- /dev/null +++ b/third_party/heimdal_build/krb5/kdc-plugin.h @@ -0,0 +1 @@ +#include "../../heimdal/kdc/kdc-plugin.h" diff --git a/third_party/heimdal_build/krb5/windc_plugin.h b/third_party/heimdal_build/krb5/windc_plugin.h deleted file mode 100644 index 538b617d90d8..000000000000 --- a/third_party/heimdal_build/krb5/windc_plugin.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../heimdal/kdc/windc_plugin.h" diff --git a/third_party/heimdal_build/wscript_build b/third_party/heimdal_build/wscript_build index 76e88bc103e0..d43237b0c3bd 100644 --- a/third_party/heimdal_build/wscript_build +++ b/third_party/heimdal_build/wscript_build @@ -439,7 +439,7 @@ if not bld.CONFIG_SET("USING_SYSTEM_KDC"): directory='lib/asn1' ) - KDC_SOURCE='kdc/default_config.c kdc/fast.c kdc/kerberos5.c kdc/krb5tgs.c kdc/pkinit.c kdc/pkinit-ec.c kdc/log.c kdc/misc.c kdc/digest.c kdc/process.c kdc/windc.c kdc/kx509.c kdc/gss_preauth.c' + KDC_SOURCE='kdc/default_config.c kdc/fast.c kdc/kerberos5.c kdc/krb5tgs.c kdc/pkinit.c kdc/pkinit-ec.c kdc/log.c kdc/misc.c kdc/digest.c kdc/process.c kdc/kdc-plugin.c kdc/kx509.c kdc/gss_preauth.c' HEIMDAL_LIBRARY('kdc', source=KDC_SOURCE, includes='../heimdal/kdc', -- 2.25.1 From c80636c3ff5b442f95db3e6752c13bba50826c26 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 15:48:12 +1300 Subject: [PATCH 14/22] s4:kdc: Adapt to removal of auth audit event types This is an adaptation to Heimdal: commit 06f8985c55fcd23e3efe0017ed2480c5b3c4524f Author: Luke Howard Date: Wed Jan 5 09:42:03 2022 +1100 hdb: consolidate preauth audit event types Instead of having distinct preauth success/failure events for different mechanisms, have a single event; the mechanism can be disambiguated by querying the HDB_REQUEST_KV_PA_NAME key. Note: there is still an explicit event for long-term key-based success/failure in order to help the backend implement lockout. Audit failure (HDB_AUTH_EVENT_PREAUTH_FAILED) in the main preauth loop, rather than in each mechanism. Success is still audited in the mechanism to allow client pre-authentication success to be noted even if something subsequent (e.g. encoding a reply, memory allocation) fails. The generic catch-all for success remains. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit f234361abea4166ce4e10cfa4e7f4096b83480a9) --- source4/kdc/hdb-samba4.c | 71 ++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index 1d273bf8da08..94809b9c9149 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -540,40 +540,27 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, pa_type = heim_string_get_utf8(pa_type_obj); } - switch (hdb_auth_status) { - case HDB_AUTH_EVENT_PKINIT_SUCCEEDED: - case HDB_AUTH_EVENT_PKINIT_FAILED: - case HDB_AUTH_EVENT_PKINIT_NOT_AUTHORIZED: - auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PKINIT_CLIENT_CERT); - if (auth_details_obj != NULL) { - auth_details = heim_string_get_utf8(auth_details_obj); - } - break; - - case HDB_AUTH_EVENT_GSS_PA_SUCCEEDED: - case HDB_AUTH_EVENT_GSS_PA_FAILED: - case HDB_AUTH_EVENT_GSS_PA_NOT_AUTHORIZED: + auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PKINIT_CLIENT_CERT); + if (auth_details_obj != NULL) { + auth_details = heim_string_get_utf8(auth_details_obj); + } else { auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_GSS_INITIATOR); if (auth_details_obj != NULL) { auth_details = heim_string_get_utf8(auth_details_obj); - } - break; - - default: - { - heim_object_t etype_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PA_ETYPE); - if (etype_obj != NULL) { - int etype = heim_number_get_int(etype_obj); - - krb5_error_code ret = krb5_enctype_to_string(r->context, etype, &etype_str); - if (ret == 0) { - auth_details = etype_str; - } else { - auth_details = "unknown enctype"; + } else { + heim_object_t etype_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PA_ETYPE); + if (etype_obj != NULL) { + int etype = heim_number_get_int(etype_obj); + + krb5_error_code ret = krb5_enctype_to_string(r->context, etype, &etype_str); + if (ret == 0) { + auth_details = etype_str; + } else { + auth_details = "unknown enctype"; + } } } } - } /* * Forcing this via the NTLM auth structure is not ideal, but @@ -626,12 +613,10 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, break; } case HDB_AUTH_EVENT_CLIENT_LOCKED_OUT: - case HDB_AUTH_EVENT_LTK_PREAUTH_SUCCEEDED: - case HDB_AUTH_EVENT_LTK_PREAUTH_FAILED: - case HDB_AUTH_EVENT_OTHER_PREAUTH_SUCCEEDED: - case HDB_AUTH_EVENT_OTHER_PREAUTH_FAILED: - case HDB_AUTH_EVENT_PKINIT_SUCCEEDED: - case HDB_AUTH_EVENT_PKINIT_FAILED: + case HDB_AUTH_EVENT_VALIDATED_LONG_TERM_KEY: + case HDB_AUTH_EVENT_WRONG_LONG_TERM_KEY: + case HDB_AUTH_EVENT_PREAUTH_SUCCEEDED: + case HDB_AUTH_EVENT_PREAUTH_FAILED: { TALLOC_CTX *frame = talloc_stackframe(); struct samba_kdc_entry *p = talloc_get_type(entry->ctx, @@ -670,7 +655,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, } ui.auth_description = auth_description; - if (hdb_auth_status == HDB_AUTH_EVENT_LTK_PREAUTH_FAILED) { + if (hdb_auth_status == HDB_AUTH_EVENT_WRONG_LONG_TERM_KEY) { authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn); status = NT_STATUS_WRONG_PASSWORD; /* @@ -683,16 +668,16 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, } } else if (hdb_auth_status == HDB_AUTH_EVENT_CLIENT_LOCKED_OUT) { status = NT_STATUS_ACCOUNT_LOCKED_OUT; - } else if (hdb_auth_status == HDB_AUTH_EVENT_LTK_PREAUTH_SUCCEEDED) { - status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTH_EVENT_OTHER_PREAUTH_SUCCEEDED) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_VALIDATED_LONG_TERM_KEY) { status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTH_EVENT_OTHER_PREAUTH_FAILED) { - status = NT_STATUS_GENERIC_COMMAND_FAILED; - } else if (hdb_auth_status == HDB_AUTH_EVENT_PKINIT_SUCCEEDED) { + } else if (hdb_auth_status == HDB_AUTH_EVENT_PREAUTH_SUCCEEDED) { status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTH_EVENT_PKINIT_FAILED) { - status = NT_STATUS_PKINIT_FAILURE; + } else if (hdb_auth_status == HDB_AUTH_EVENT_PREAUTH_FAILED) { + if (pa_type != NULL && strncmp(pa_type, "PK-INIT", strlen("PK-INIT")) == 0) { + status = NT_STATUS_PKINIT_FAILURE; + } else { + status = NT_STATUS_GENERIC_COMMAND_FAILED; + } } else { status = NT_STATUS_INTERNAL_ERROR; } -- 2.25.1 From 2976a541545c32e9f9517c2f2fd6a10dfea51119 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 15:53:34 +1300 Subject: [PATCH 15/22] third_party/heimdal_build: Add SFU source file This is an adaptation to Heimdal: commit 0287558838de79313e38026d2f0905ffc987d0b8 Author: Luke Howard Date: Fri Dec 24 13:49:55 2021 +1100 kdc: move Services for User implementation out of krb5tgs.c Move the Services for User (SFU/S4U) implementation -- protocol transition and constrained delegation -- into its own compilation unit, with an interface that only takes an astgs_request_t, so it can be easily factored out into a plugin module in the future. This refactoring is also careful to update all client names in the request structure after the SFU/S4U validation has successfully completed. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit b9f4ea8bdb70476d6cc6df962bf6b28805588ed5) --- third_party/heimdal_build/wscript_build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/heimdal_build/wscript_build b/third_party/heimdal_build/wscript_build index d43237b0c3bd..69aeb1201918 100644 --- a/third_party/heimdal_build/wscript_build +++ b/third_party/heimdal_build/wscript_build @@ -439,7 +439,7 @@ if not bld.CONFIG_SET("USING_SYSTEM_KDC"): directory='lib/asn1' ) - KDC_SOURCE='kdc/default_config.c kdc/fast.c kdc/kerberos5.c kdc/krb5tgs.c kdc/pkinit.c kdc/pkinit-ec.c kdc/log.c kdc/misc.c kdc/digest.c kdc/process.c kdc/kdc-plugin.c kdc/kx509.c kdc/gss_preauth.c' + KDC_SOURCE='kdc/default_config.c kdc/fast.c kdc/kerberos5.c kdc/krb5tgs.c kdc/pkinit.c kdc/pkinit-ec.c kdc/mssfu.c kdc/log.c kdc/misc.c kdc/digest.c kdc/process.c kdc/kdc-plugin.c kdc/kx509.c kdc/gss_preauth.c' HEIMDAL_LIBRARY('kdc', source=KDC_SOURCE, includes='../heimdal/kdc', -- 2.25.1 From 938268374dd260aaf4ab5b2bef68cf14c17f65e4 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 15:56:32 +1300 Subject: [PATCH 16/22] s4:kdc: Explicitly set plugin minor version This is an adaptation to Heimdal: commit 7cc4b7a9e624f5eecfbb38607d4cc0870a895671 Author: Luke Howard Date: Wed Jan 5 13:08:11 2022 +1100 kdc: KDC plugin API contract notes Add some notes about the KDC plugin API contract, and require plugins to explicitly indicate which version of the API they support (remove the macro alias for the current version). NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 675f913e54d8fddb9173c1e67b9d14885cc1d878) --- source4/kdc/wdc-samba4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index f4ac075e2d46..3366726597e7 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -960,7 +960,7 @@ static krb5_error_code samba_wdc_referral_policy(void *priv, } struct krb5plugin_kdc_ftable kdc_plugin_table = { - .minor_version = KRB5_KDC_PLUGIN_MINOR, + .minor_version = KRB5_PLUGIN_KDC_VERSION_8, .init = samba_wdc_plugin_init, .fini = samba_wdc_plugin_fini, .pac_verify = samba_wdc_reget_pac, -- 2.25.1 From 5b0bc8884d54fff294375e7e20f9fba5cd6b9afe Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 21 Feb 2022 19:12:28 +1300 Subject: [PATCH 17/22] third_party/heimdal_build: Don't generate .x source files This is an adaptation to Heimdal: commit 9427796f1a65906f12768b28abdb5a928222f3c6 Author: Jeffrey Altman Date: Wed Jan 5 15:45:23 2022 -0500 Generate .x source files as .c source files The generated .x source and .hx header files are plain C source files. Generate them as .c source files and avoid unnecessary file copying and special makefile rules. Change-Id: Ifc4bbe3c46dd357fdd642040ad964c7cfe1d395c NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 7cb68fdba75c362cdfd8f3bf08bcd9c22bbe4556) --- third_party/heimdal_build/wscript_build | 47 +++++-------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/third_party/heimdal_build/wscript_build b/third_party/heimdal_build/wscript_build index 69aeb1201918..3ea1fc93653f 100644 --- a/third_party/heimdal_build/wscript_build +++ b/third_party/heimdal_build/wscript_build @@ -40,10 +40,10 @@ def HEIMDAL_ASN1(name, source, bld.set_group('build_source') out_files = heimdal_paths([ - "%s/asn1_%s_asn1.x" % (directory, bname), - "%s/%s_asn1.hx" % (directory, bname), - "%s/%s_asn1-priv.hx" % (directory, bname), - "%s/%s_asn1_oids.x" % (directory, bname), + "%s/asn1_%s_asn1.c" % (directory, bname), + "%s/%s_asn1.h" % (directory, bname), + "%s/%s_asn1-priv.h" % (directory, bname), + "%s/%s_asn1_oids.c" % (directory, bname), ]) # the ${TGT[0].parent.abspath(env)} expression gives us the parent directory of @@ -81,7 +81,7 @@ def HEIMDAL_ASN1(name, source, deps = 'asn1_compile' t = bld(rule=asn1_rule, - ext_out = '.x', + ext_out = '.c', before = 'c', update_outputs = True, shell = True, @@ -97,40 +97,9 @@ def HEIMDAL_ASN1(name, source, t.env.OPTION_FILE = "--option-file='%s'" % \ os.path.normpath(os.path.join(bld.path.abspath(), option_file)) - cfile = out_files[0][0:-2] + '.c' - hfile = out_files[1][0:-3] + '.h' - hpriv = out_files[2][0:-3] + '.h' - - # now generate a .c file from the .x file - t = bld(rule='''( echo '#include "config.h"' && cat ${SRC} ) > ${TGT}''', - source = out_files[0], - target = cfile, - shell = True, - update_outputs=True, - ext_out = '.c', - ext_in = '.x', - depends_on = name + '_ASN1', - name = name + '_C') - - # and generate a .h file from the .hx file - t = bld(rule='cp ${SRC} ${TGT}', - source = out_files[1], - ext_out = '.c', - ext_in = '.x', - update_outputs=True, - target = hfile, - depends_on = name + '_ASN1', - name = name + '_H') - - # and generate a .h file from the .hx file - t = bld(rule='cp ${SRC} ${TGT}', - source = out_files[2], - ext_out = '.c', - ext_in = '.x', - update_outputs=True, - target = hpriv, - depends_on = name + '_ASN1', - name = name + '_PRIV_H') + cfile = out_files[0] + hfile = out_files[1] + hpriv = out_files[2] bld.set_group('main') -- 2.25.1 From c80dafc0e32af599b3f7b1f5b346b5dc773c2bef Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 16:30:27 +1300 Subject: [PATCH 18/22] s4:kdc: Increment plugin minor version This is an adaptation to Heimdal: commit 40e4a4df09c2d6c3ba7bf14df1dee74a0bc18110 Author: Luke Howard Date: Mon Jan 10 12:50:37 2022 +1100 kdc: use astgs_request_t for client/server name (TGS) Store the client and server principal name from the TGT and request (respectively) in the astgs_request_t rather than using local variables. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 068f2bf117ab9968011fdb8d60b98bb37d529658) --- source4/kdc/wdc-samba4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 3366726597e7..9356979dd7dc 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -960,7 +960,7 @@ static krb5_error_code samba_wdc_referral_policy(void *priv, } struct krb5plugin_kdc_ftable kdc_plugin_table = { - .minor_version = KRB5_PLUGIN_KDC_VERSION_8, + .minor_version = KRB5_PLUGIN_KDC_VERSION_9, .init = samba_wdc_plugin_init, .fini = samba_wdc_plugin_fini, .pac_verify = samba_wdc_reget_pac, -- 2.25.1 From 8e81e7f5b3938773d7ff87627b63d960a2677a1c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 22 Feb 2022 19:41:14 +1300 Subject: [PATCH 19/22] s4:kdc: Adapt to hdb_entry_ex removal Rather than having a 'free_entry' member that can be called to free an hdb_entry, we now implement the free function in HDB. We perform the free only if the context pointer is non-NULL. We also remove the ZERO_STRUCTP() in sdb_entry_to_hdb_entry(), as the context pointer is now part of the 'hdb_entry' structure itself, and this would undesirably zero it out. This is an adaptation to Heimdal commits: commit c5551775e204d00c7ee8055ab6ddbba7e0590584 Author: Luke Howard Date: Fri Jan 7 12:15:55 2022 +1100 hdb: decorate HDB_entry with context member Decorate HDB_entry with context and move free_entry callback into HDB structure itself. Requires updating hdb_free_entry() signature to include HDB parameter. A follow-up commit will consolidate hdb_entry_ex (which has a single hdb_entry member) into hdb_entry. commit 0e8c4ccc6ee0123ea39e53e8917fc3f6bb74e8c8 Author: Luke Howard Date: Fri Jan 7 12:54:40 2022 +1100 hdb: eliminate hdb_entry_ex Remove hdb_entry_ex and revert to the original design of hdb_entry (except with an additional context member in hdb_entry which is managed by the free_entry method in HDB). NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 94d387abd5031c12989f925ee5eb733432402d1d) --- source4/kdc/hdb-samba4.c | 51 +++++++++++++++------- source4/kdc/kdc-glue.c | 4 +- source4/kdc/kdc-glue.h | 2 +- source4/kdc/kdc-heimdal.c | 6 +-- source4/kdc/sdb_to_hdb.c | 26 +++-------- source4/kdc/wdc-samba4.c | 58 +++++++++++++------------ third_party/heimdal_build/wscript_build | 5 +-- 7 files changed, 77 insertions(+), 75 deletions(-) diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index 94809b9c9149..90cd3a78de8f 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -79,7 +79,7 @@ static krb5_error_code hdb_samba4_rename(krb5_context context, HDB *db, const ch return HDB_ERR_DB_INUSE; } -static krb5_error_code hdb_samba4_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) +static krb5_error_code hdb_samba4_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return HDB_ERR_DB_INUSE; } @@ -93,6 +93,24 @@ static krb5_error_code hdb_samba4_set_sync(krb5_context context, struct HDB *db, return 0; } +static void hdb_samba4_free_entry_context(krb5_context context, struct HDB *db, hdb_entry *entry) +{ + /* + * This function is now called for every HDB entry, not just those with + * 'context' set, so we have to check that the context is not NULL. + */ + if (entry->context != NULL) { + /* this function is called only from hdb_free_entry(). + * Make sure we neutralize the destructor or we will + * get a double free later when hdb_free_entry() will + * try to call free_hdb_entry() */ + talloc_set_destructor(entry->context, NULL); + + /* now proceed to free the talloc part */ + talloc_free(entry->context); + } +} + static int hdb_samba4_fill_fast_cookie(krb5_context context, struct samba_kdc_db_context *kdc_db_ctx) { @@ -131,7 +149,7 @@ static int hdb_samba4_fill_fast_cookie(krb5_context context, static krb5_error_code hdb_samba4_fetch_fast_cookie(krb5_context context, struct samba_kdc_db_context *kdc_db_ctx, - hdb_entry_ex *entry_ex) + hdb_entry *entry_ex) { krb5_error_code ret = SDB_ERR_NOENTRY; TALLOC_CTX *mem_ctx; @@ -219,7 +237,7 @@ static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, krb5_kvno kvno, - hdb_entry_ex *entry_ex) + hdb_entry *entry_ex) { struct samba_kdc_db_context *kdc_db_ctx; struct sdb_entry_ex sdb_entry_ex = {}; @@ -273,7 +291,7 @@ static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db, } static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsigned flags, - hdb_entry_ex *entry) + hdb_entry *entry) { struct samba_kdc_db_context *kdc_db_ctx; struct sdb_entry_ex sdb_entry_ex = {}; @@ -302,7 +320,7 @@ static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsign } static krb5_error_code hdb_samba4_nextkey(krb5_context context, HDB *db, unsigned flags, - hdb_entry_ex *entry) + hdb_entry *entry) { struct samba_kdc_db_context *kdc_db_ctx; struct sdb_entry_ex sdb_entry_ex = {}; @@ -338,7 +356,7 @@ static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db) static krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db, - hdb_entry_ex *entry, + hdb_entry *entry, krb5_const_principal target_principal) { struct samba_kdc_db_context *kdc_db_ctx; @@ -347,7 +365,7 @@ hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db, kdc_db_ctx = talloc_get_type_abort(db->hdb_db, struct samba_kdc_db_context); - skdc_entry = talloc_get_type_abort(entry->ctx, + skdc_entry = talloc_get_type_abort(entry->context, struct samba_kdc_entry); ret = samba_kdc_check_s4u2proxy(context, kdc_db_ctx, @@ -374,7 +392,7 @@ hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db, static krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db, - hdb_entry_ex *entry, + hdb_entry *entry, krb5_const_principal certificate_principal) { struct samba_kdc_db_context *kdc_db_ctx; @@ -383,7 +401,7 @@ hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db, kdc_db_ctx = talloc_get_type_abort(db->hdb_db, struct samba_kdc_db_context); - skdc_entry = talloc_get_type_abort(entry->ctx, + skdc_entry = talloc_get_type_abort(entry->context, struct samba_kdc_entry); ret = samba_kdc_check_pkinit_ms_upn_match(context, kdc_db_ctx, @@ -410,14 +428,14 @@ hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db, static krb5_error_code hdb_samba4_check_client_matches_target_service(krb5_context context, HDB *db, - hdb_entry_ex *client_entry, - hdb_entry_ex *server_target_entry) + hdb_entry *client_entry, + hdb_entry *server_target_entry) { struct samba_kdc_entry *skdc_client_entry - = talloc_get_type_abort(client_entry->ctx, + = talloc_get_type_abort(client_entry->context, struct samba_kdc_entry); struct samba_kdc_entry *skdc_server_target_entry - = talloc_get_type_abort(server_target_entry->ctx, + = talloc_get_type_abort(server_target_entry->context, struct samba_kdc_entry); return samba_kdc_check_client_matches_target_service(context, @@ -503,7 +521,7 @@ static void send_bad_password_netlogon(TALLOC_CTX *mem_ctx, static krb5_error_code hdb_samba4_audit(krb5_context context, HDB *db, - hdb_entry_ex *entry, + hdb_entry *entry, hdb_request_t r) { struct samba_kdc_db_context *kdc_db_ctx = talloc_get_type_abort(db->hdb_db, @@ -595,7 +613,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, case HDB_AUTH_EVENT_CLIENT_AUTHORIZED: { TALLOC_CTX *frame = talloc_stackframe(); - struct samba_kdc_entry *p = talloc_get_type(entry->ctx, + struct samba_kdc_entry *p = talloc_get_type(entry->context, struct samba_kdc_entry); struct netr_SendToSamBase *send_to_sam = NULL; @@ -619,7 +637,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, case HDB_AUTH_EVENT_PREAUTH_FAILED: { TALLOC_CTX *frame = talloc_stackframe(); - struct samba_kdc_entry *p = talloc_get_type(entry->ctx, + struct samba_kdc_entry *p = talloc_get_type(entry->context, struct samba_kdc_entry); struct dom_sid *sid = samdb_result_dom_sid(frame, p->msg, "objectSid"); @@ -766,6 +784,7 @@ NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx, (*db)->hdb_dbc = NULL; (*db)->hdb_open = hdb_samba4_open; (*db)->hdb_close = hdb_samba4_close; + (*db)->hdb_free_entry_context = hdb_samba4_free_entry_context; (*db)->hdb_fetch_kvno = hdb_samba4_fetch_kvno; (*db)->hdb_store = hdb_samba4_store; (*db)->hdb_firstkey = hdb_samba4_firstkey; diff --git a/source4/kdc/kdc-glue.c b/source4/kdc/kdc-glue.c index c6cc61ad02d7..671e506b8cc1 100644 --- a/source4/kdc/kdc-glue.c +++ b/source4/kdc/kdc-glue.c @@ -34,7 +34,7 @@ int kdc_check_pac(krb5_context context, DATA_BLOB srv_sig, struct PAC_SIGNATURE_DATA *kdc_sig, - struct hdb_entry_ex *ent) + hdb_entry *ent) { krb5_enctype etype; int ret; @@ -52,7 +52,7 @@ int kdc_check_pac(krb5_context context, } } - ret = hdb_enctype2key(context, &ent->entry, NULL, etype, &key); + ret = hdb_enctype2key(context, ent, NULL, etype, &key); if (ret != 0) { return ret; diff --git a/source4/kdc/kdc-glue.h b/source4/kdc/kdc-glue.h index 2e58fcda1398..47642e124320 100644 --- a/source4/kdc/kdc-glue.h +++ b/source4/kdc/kdc-glue.h @@ -50,5 +50,5 @@ NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx, int kdc_check_pac(krb5_context krb5_context, DATA_BLOB server_sig, struct PAC_SIGNATURE_DATA *kdc_sig, - hdb_entry_ex *ent); + hdb_entry *ent); #endif diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c index 96322cd1bb76..ddf3b649da2d 100644 --- a/source4/kdc/kdc-heimdal.c +++ b/source4/kdc/kdc-heimdal.c @@ -191,7 +191,7 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, (krb5_kdc_configuration *)kdc->private_data; enum ndr_err_code ndr_err; int ret; - hdb_entry_ex ent; + hdb_entry ent; krb5_principal principal; @@ -235,7 +235,7 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, &ent); if (ret != 0) { - hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); + hdb_free_entry(kdc->smb_krb5_context->krb5_context, kdc_config->db[0], &ent); krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal); return NT_STATUS_LOGON_FAILURE; @@ -247,7 +247,7 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, ret = kdc_check_pac(kdc->smb_krb5_context->krb5_context, srv_sig, &kdc_sig, &ent); - hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); + hdb_free_entry(kdc->smb_krb5_context->krb5_context, kdc_config->db[0], &ent); krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal); if (ret != 0) { diff --git a/source4/kdc/sdb_to_hdb.c b/source4/kdc/sdb_to_hdb.c index e5cc84a7e637..e2d6e40c837e 100644 --- a/source4/kdc/sdb_to_hdb.c +++ b/source4/kdc/sdb_to_hdb.c @@ -180,8 +180,6 @@ static int sdb_entry_to_hdb_entry(krb5_context context, unsigned int i; int rc; - ZERO_STRUCTP(h); - rc = krb5_copy_principal(context, s->principal, &h->principal); @@ -311,28 +309,15 @@ error: static int samba_kdc_hdb_entry_destructor(struct samba_kdc_entry *p) { - struct hdb_entry_ex *entry_ex = p->entry_ex; - free_hdb_entry(&entry_ex->entry); + hdb_entry *entry_ex = p->entry_ex; + free_hdb_entry(entry_ex); return 0; } -static void samba_kdc_free_hdb_entry(krb5_context context, - struct hdb_entry_ex *entry_ex) -{ - /* this function is called only from hdb_free_entry(). - * Make sure we neutralize the destructor or we will - * get a double free later when hdb_free_entry() will - * try to call free_hdb_entry() */ - talloc_set_destructor(entry_ex->ctx, NULL); - - /* now proceed to free the talloc part */ - talloc_free(entry_ex->ctx); -} - int sdb_entry_ex_to_hdb_entry_ex(krb5_context context, const struct sdb_entry_ex *s, - struct hdb_entry_ex *h) + hdb_entry *h) { struct samba_kdc_entry *skdc_entry; @@ -341,12 +326,11 @@ int sdb_entry_ex_to_hdb_entry_ex(krb5_context context, if (s->ctx != NULL) { skdc_entry = talloc_get_type(s->ctx, struct samba_kdc_entry); - h->ctx = skdc_entry; - h->free_entry = samba_kdc_free_hdb_entry; + h->context = skdc_entry; talloc_set_destructor(skdc_entry, samba_kdc_hdb_entry_destructor); } - return sdb_entry_to_hdb_entry(context, &s->entry, &h->entry); + return sdb_entry_to_hdb_entry(context, &s->entry, h); } diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 9356979dd7dc..6325627318ea 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -37,8 +37,9 @@ * For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO. */ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context, - struct hdb_entry_ex *client, - struct hdb_entry_ex *server, + krb5_kdc_configuration *config, + hdb_entry *client, + hdb_entry *server, const krb5_keyblock *pk_reply_key, uint64_t pac_attributes, krb5_pac *pac) @@ -55,11 +56,11 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context, krb5_error_code ret; NTSTATUS nt_status; struct samba_kdc_entry *skdc_entry = - talloc_get_type_abort(client->ctx, + talloc_get_type_abort(client->context, struct samba_kdc_entry); bool is_krbtgt; - mem_ctx = talloc_named(client->ctx, 0, "samba_get_pac context"); + mem_ctx = talloc_named(client->context, 0, "samba_get_pac context"); if (!mem_ctx) { return ENOMEM; } @@ -68,7 +69,7 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context, cred_ndr_ptr = &cred_ndr; } - is_krbtgt = krb5_principal_is_krbtgt(context, server->entry.principal); + is_krbtgt = krb5_principal_is_krbtgt(context, server->principal); nt_status = samba_kdc_get_pac_blobs(mem_ctx, skdc_entry, &logon_blob, @@ -112,17 +113,17 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context, static krb5_error_code samba_wdc_reget_pac2(krb5_context context, const krb5_principal delegated_proxy_principal, - struct hdb_entry_ex *client, - struct hdb_entry_ex *server, - struct hdb_entry_ex *krbtgt, + hdb_entry *client, + hdb_entry *server, + hdb_entry *krbtgt, krb5_pac *pac, krb5_cksumtype ctype) { struct samba_kdc_entry *server_skdc_entry = - talloc_get_type_abort(server->ctx, + talloc_get_type_abort(server->context, struct samba_kdc_entry); struct samba_kdc_entry *krbtgt_skdc_entry = - talloc_get_type_abort(krbtgt->ctx, + talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry); TALLOC_CTX *mem_ctx = talloc_named(server_skdc_entry, 0, @@ -157,7 +158,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, if (client != NULL) { struct samba_kdc_entry *client_skdc_entry = NULL; - client_skdc_entry = talloc_get_type_abort(client->ctx, + client_skdc_entry = talloc_get_type_abort(client->context, struct samba_kdc_entry); /* @@ -214,7 +215,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, return ret; } } - ret = hdb_enctype2key(context, &krbtgt->entry, NULL, etype, &key); + ret = hdb_enctype2key(context, krbtgt, NULL, etype, &key); if (ret != 0) { talloc_free(mem_ctx); return ret; @@ -241,7 +242,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, nt_status = samba_kdc_update_delegation_info_blob(mem_ctx, context, *pac, - server->entry.principal, + server->principal, delegated_proxy_principal, deleg_blob); if (!NT_STATUS_IS_OK(nt_status)) { @@ -261,7 +262,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; } - client_skdc_entry = talloc_get_type_abort(client->ctx, + client_skdc_entry = talloc_get_type_abort(client->context, struct samba_kdc_entry); nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry, @@ -485,7 +486,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, goto out; } - is_krbtgt = krb5_principal_is_krbtgt(context, server->entry.principal); + is_krbtgt = krb5_principal_is_krbtgt(context, server->principal); if (!is_untrusted && !is_krbtgt) { /* @@ -663,19 +664,20 @@ out: /* Resign (and reform, including possibly new groups) a PAC */ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, + krb5_kdc_configuration *config, const krb5_principal client_principal, const krb5_principal delegated_proxy_principal, - struct hdb_entry_ex *client, - struct hdb_entry_ex *server, - struct hdb_entry_ex *krbtgt, + hdb_entry *client, + hdb_entry *server, + hdb_entry *krbtgt, krb5_pac *pac) { struct samba_kdc_entry *krbtgt_skdc_entry = - talloc_get_type_abort(krbtgt->ctx, + talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry); krb5_error_code ret; krb5_cksumtype ctype = CKSUMTYPE_NONE; - struct hdb_entry_ex signing_krbtgt_hdb; + hdb_entry signing_krbtgt_hdb; if (delegated_proxy_principal) { uint16_t rodc_id; @@ -726,7 +728,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, * different KDC than the one that issued the header * ticket. */ - if (rodc_id != krbtgt->entry.kvno >> 16) { + if (rodc_id != krbtgt->kvno >> 16) { struct sdb_entry_ex signing_krbtgt_sdb; /* @@ -745,7 +747,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, */ ret = samba_kdc_fetch(context, krbtgt_skdc_entry->kdc_db_ctx, - krbtgt->entry.principal, + krbtgt->principal, SDB_F_GET_KRBTGT | SDB_F_CANON, 0, &signing_krbtgt_sdb); @@ -779,7 +781,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, ctype); if (krbtgt == &signing_krbtgt_hdb) { - hdb_free_entry(context, &signing_krbtgt_hdb); + hdb_free_entry(context, config->db[0], &signing_krbtgt_hdb); } return ret; @@ -844,9 +846,9 @@ static krb5_error_code samba_wdc_check_client_access(void *priv, char *workstation; NTSTATUS nt_status; - kdc_entry = talloc_get_type(r->client->ctx, struct samba_kdc_entry); - password_change = (r->server && r->server->entry.flags.change_pw); - workstation = get_netbios_name((TALLOC_CTX *)r->client->ctx, + kdc_entry = talloc_get_type(r->client->context, struct samba_kdc_entry); + password_change = (r->server && r->server->flags.change_pw); + workstation = get_netbios_name((TALLOC_CTX *)r->client->context, r->req.req_body.addresses); nt_status = samba_kdc_check_client_access(kdc_entry, @@ -905,7 +907,7 @@ static krb5_error_code samba_wdc_finalize_reply(void *priv, struct samba_kdc_entry *server_kdc_entry; uint32_t supported_enctypes; - server_kdc_entry = talloc_get_type(r->server->ctx, struct samba_kdc_entry); + server_kdc_entry = talloc_get_type(r->server->context, struct samba_kdc_entry); /* * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata @@ -960,7 +962,7 @@ static krb5_error_code samba_wdc_referral_policy(void *priv, } struct krb5plugin_kdc_ftable kdc_plugin_table = { - .minor_version = KRB5_PLUGIN_KDC_VERSION_9, + .minor_version = KRB5_PLUGIN_KDC_VERSION_10, .init = samba_wdc_plugin_init, .fini = samba_wdc_plugin_fini, .pac_verify = samba_wdc_reget_pac, diff --git a/third_party/heimdal_build/wscript_build b/third_party/heimdal_build/wscript_build index 3ea1fc93653f..a395430c28fb 100644 --- a/third_party/heimdal_build/wscript_build +++ b/third_party/heimdal_build/wscript_build @@ -433,10 +433,7 @@ if not bld.CONFIG_SET("USING_SYSTEM_HEIMNTLM"): if not bld.CONFIG_SET("USING_SYSTEM_HDB"): HEIMDAL_ASN1('HEIMDAL_HDB_ASN1', 'lib/hdb/hdb.asn1', directory='lib/asn1', - options="--sequence=HDB-extensions \ - --sequence=HDB-Ext-KeyRotation \ - --sequence=HDB-Ext-KeySet \ - --sequence=Keys", + option_file="lib/hdb/hdb.opt", template=False, includes='../heimdal/lib/asn1') -- 2.25.1 From 7284183c5959540dc4f33b56dc0be55fbb46c63d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 23 Feb 2022 09:53:27 +1300 Subject: [PATCH 20/22] s4:kdc: Adapt to removal of publicly accessible request structure members We now have to use the accessor functions instead. This is an adaptation to Heimdal: commit ec24edf7005c340018450a202d27ca75fcf322d4 Author: Luke Howard Date: Thu Jan 20 09:15:24 2022 +1100 kdc: add accessor functions for KDC request structure Add accessor functions for use by Samba and other plugin developers. Documentation is in kdc/kdc-accessors.h. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 9399a15fabb5a1b8470b1069a098132e2fdb7f0f) --- source4/kdc/wdc-samba4.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 6325627318ea..dfca27175a21 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -846,13 +846,14 @@ static krb5_error_code samba_wdc_check_client_access(void *priv, char *workstation; NTSTATUS nt_status; - kdc_entry = talloc_get_type(r->client->context, struct samba_kdc_entry); - password_change = (r->server && r->server->flags.change_pw); - workstation = get_netbios_name((TALLOC_CTX *)r->client->context, - r->req.req_body.addresses); + + kdc_entry = talloc_get_type(kdc_request_get_client(r)->context, struct samba_kdc_entry); + password_change = (kdc_request_get_server(r) && kdc_request_get_server(r)->flags.change_pw); + workstation = get_netbios_name((TALLOC_CTX *)kdc_request_get_client(r)->context, + kdc_request_get_req(r)->req_body.addresses); nt_status = samba_kdc_check_client_access(kdc_entry, - r->cname, + kdc_request_get_cname((kdc_request_t)r), workstation, password_change); @@ -861,12 +862,12 @@ static krb5_error_code samba_wdc_check_client_access(void *priv, return ENOMEM; } - if (r->rep.padata) { + if (kdc_request_get_rep(r)->padata) { int ret; krb5_data kd; samba_kdc_build_edata_reply(nt_status, &kd); - ret = krb5_padata_add(r->context, r->rep.padata, + ret = krb5_padata_add(kdc_request_get_context((kdc_request_t)r), kdc_request_get_rep(r)->padata, KRB5_PADATA_PW_SALT, kd.data, kd.length); if (ret != 0) { @@ -907,37 +908,32 @@ static krb5_error_code samba_wdc_finalize_reply(void *priv, struct samba_kdc_entry *server_kdc_entry; uint32_t supported_enctypes; - server_kdc_entry = talloc_get_type(r->server->context, struct samba_kdc_entry); + server_kdc_entry = talloc_get_type(kdc_request_get_server(r)->context, struct samba_kdc_entry); /* * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata * type to indicate what encryption types the server supports. */ supported_enctypes = server_kdc_entry->supported_enctypes; - if (r->req.req_body.kdc_options.canonicalize && supported_enctypes != 0) { + if (kdc_request_get_req(r)->req_body.kdc_options.canonicalize && supported_enctypes != 0) { krb5_error_code ret; - krb5_data kd; - if (r->ek.encrypted_pa_data == NULL) { - r->ek.encrypted_pa_data = calloc(1, sizeof *(r->ek.encrypted_pa_data)); - if (r->ek.encrypted_pa_data == NULL) { - return ENOMEM; - } - } + PA_DATA md; - ret = samba_kdc_build_supported_etypes(supported_enctypes, &kd); + ret = samba_kdc_build_supported_etypes(supported_enctypes, &md.padata_value); if (ret != 0) { return ret; } - ret = krb5_padata_add(r->context, r->ek.encrypted_pa_data, - KRB5_PADATA_SUPPORTED_ETYPES, - kd.data, kd.length); + + md.padata_type = KRB5_PADATA_SUPPORTED_ETYPES; + + ret = kdc_request_add_encrypted_padata(r, &md); if (ret != 0) { /* * So we do not leak the allocated * memory on kd in the error case */ - krb5_data_free(&kd); + krb5_data_free(&md.padata_value); } } @@ -958,7 +954,7 @@ static void samba_wdc_plugin_fini(void *ptr) static krb5_error_code samba_wdc_referral_policy(void *priv, astgs_request_t r) { - return r->error_code; + return kdc_request_get_error_code((kdc_request_t)r); } struct krb5plugin_kdc_ftable kdc_plugin_table = { -- 2.25.1 From ddc5452be081ab5546e56b93b97ed3d8d1a6c117 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 2 Mar 2022 10:00:17 +1300 Subject: [PATCH 21/22] s4-kdc: Adapt to move from HDB auditing to KDC auditing constants This is to adapt to: commit 6530021f09a5cab631be19a1b5898a0ba6b32f16 Author: Luke Howard Date: Thu Jan 13 14:37:29 2022 +1100 kdc: move auth event definitions into KDC header Move KDC auth event macro definitions out of hdb.h and into a new KDC header, kdc-audit.h. NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Andrew Bartlett Reviewed-by: Joseph Sutton (cherry picked from commit c9b0b4bfc4e2e0b08b21f39bf56fd5395d66d66f) --- source4/kdc/hdb-samba4.c | 33 +++++++++++++++++---------------- source4/kdc/wscript_build | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index 90cd3a78de8f..c2f55329cec6 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -46,6 +46,7 @@ #include "librpc/gen_ndr/ndr_winbind_c.h" #include "lib/messaging/irpc.h" #include "hdb.h" +#include static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode) { @@ -545,7 +546,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, size_t sa_socklen = 0; - hdb_auth_status_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_AUTH_EVENT); + hdb_auth_status_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_AUTH_EVENT); if (hdb_auth_status_obj == NULL) { /* No status code found, so just return. */ return 0; @@ -558,15 +559,15 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, pa_type = heim_string_get_utf8(pa_type_obj); } - auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PKINIT_CLIENT_CERT); + auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_PKINIT_CLIENT_CERT); if (auth_details_obj != NULL) { auth_details = heim_string_get_utf8(auth_details_obj); } else { - auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_GSS_INITIATOR); + auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_GSS_INITIATOR); if (auth_details_obj != NULL) { auth_details = heim_string_get_utf8(auth_details_obj); } else { - heim_object_t etype_obj = heim_audit_getkv((heim_svc_req_desc)r, HDB_REQUEST_KV_PA_ETYPE); + heim_object_t etype_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_PA_ETYPE); if (etype_obj != NULL) { int etype = heim_number_get_int(etype_obj); @@ -610,7 +611,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, } switch (hdb_auth_status) { - case HDB_AUTH_EVENT_CLIENT_AUTHORIZED: + case KDC_AUTH_EVENT_CLIENT_AUTHORIZED: { TALLOC_CTX *frame = talloc_stackframe(); struct samba_kdc_entry *p = talloc_get_type(entry->context, @@ -630,11 +631,11 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, talloc_free(frame); break; } - case HDB_AUTH_EVENT_CLIENT_LOCKED_OUT: - case HDB_AUTH_EVENT_VALIDATED_LONG_TERM_KEY: - case HDB_AUTH_EVENT_WRONG_LONG_TERM_KEY: - case HDB_AUTH_EVENT_PREAUTH_SUCCEEDED: - case HDB_AUTH_EVENT_PREAUTH_FAILED: + case KDC_AUTH_EVENT_CLIENT_LOCKED_OUT: + case KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY: + case KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY: + case KDC_AUTH_EVENT_PREAUTH_SUCCEEDED: + case KDC_AUTH_EVENT_PREAUTH_FAILED: { TALLOC_CTX *frame = talloc_stackframe(); struct samba_kdc_entry *p = talloc_get_type(entry->context, @@ -673,7 +674,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, } ui.auth_description = auth_description; - if (hdb_auth_status == HDB_AUTH_EVENT_WRONG_LONG_TERM_KEY) { + if (hdb_auth_status == KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY) { authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn); status = NT_STATUS_WRONG_PASSWORD; /* @@ -684,13 +685,13 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, if (kdc_db_ctx->rodc) { send_bad_password_netlogon(frame, kdc_db_ctx, &ui); } - } else if (hdb_auth_status == HDB_AUTH_EVENT_CLIENT_LOCKED_OUT) { + } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_LOCKED_OUT) { status = NT_STATUS_ACCOUNT_LOCKED_OUT; - } else if (hdb_auth_status == HDB_AUTH_EVENT_VALIDATED_LONG_TERM_KEY) { + } else if (hdb_auth_status == KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY) { status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTH_EVENT_PREAUTH_SUCCEEDED) { + } else if (hdb_auth_status == KDC_AUTH_EVENT_PREAUTH_SUCCEEDED) { status = NT_STATUS_OK; - } else if (hdb_auth_status == HDB_AUTH_EVENT_PREAUTH_FAILED) { + } else if (hdb_auth_status == KDC_AUTH_EVENT_PREAUTH_FAILED) { if (pa_type != NULL && strncmp(pa_type, "PK-INIT", strlen("PK-INIT")) == 0) { status = NT_STATUS_PKINIT_FAILURE; } else { @@ -711,7 +712,7 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, TALLOC_FREE(frame); break; } - case HDB_AUTH_EVENT_CLIENT_UNKNOWN: + case KDC_AUTH_EVENT_CLIENT_UNKNOWN: { struct tsocket_address *remote_host; int ret; diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build index 95cd88bdfb6e..26a68e9c37c4 100644 --- a/source4/kdc/wscript_build +++ b/source4/kdc/wscript_build @@ -48,7 +48,7 @@ if bld.CONFIG_GET('SAMBA_USES_MITKDC'): bld.SAMBA_LIBRARY('HDB_SAMBA4', source='hdb-samba4.c hdb-samba4-plugin.c', - deps='ldb auth4_sam common_auth samba-credentials hdb db-glue samba-hostconfig com_err sdb_hdb RPC_NDR_WINBIND', + deps='ldb auth4_sam common_auth samba-credentials hdb kdc db-glue samba-hostconfig com_err sdb_hdb RPC_NDR_WINBIND', includes=kdc_include, private_library=True, enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL') -- 2.25.1 From 4fcc8998882586ff6b338afc803050d6d6b7d961 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 2 Mar 2022 10:10:08 +1300 Subject: [PATCH 22/22] s4:kdc: hdb_samba4_audit() is only called once per request So we need to restructure the logic a bit. NOTE: This commit finally works again! BUG: https://bugzilla.samba.org/show_bug.cgi?id=14995 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Joseph Sutton Autobuild-Date(master): Tue Mar 1 23:28:22 UTC 2022 on sn-devel-184 (cherry picked from commit 791be84c3eecb95e03611458e2305bae272ba267) --- source4/kdc/hdb-samba4.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index c2f55329cec6..6e87345e2c31 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -629,13 +629,9 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, reset_bad_password_netlogon(frame, kdc_db_ctx, send_to_sam); } talloc_free(frame); - break; } - case KDC_AUTH_EVENT_CLIENT_LOCKED_OUT: - case KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY: - case KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY: - case KDC_AUTH_EVENT_PREAUTH_SUCCEEDED: - case KDC_AUTH_EVENT_PREAUTH_FAILED: + FALL_THROUGH; + default: { TALLOC_CTX *frame = talloc_stackframe(); struct samba_kdc_entry *p = talloc_get_type(entry->context, @@ -674,7 +670,11 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, } ui.auth_description = auth_description; - if (hdb_auth_status == KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY) { + if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_AUTHORIZED) { + status = NT_STATUS_OK; + } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_TIME_SKEW) { + status = NT_STATUS_TIME_DIFFERENCE_AT_DC; + } else if (hdb_auth_status == KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY) { authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn); status = NT_STATUS_WRONG_PASSWORD; /* @@ -687,10 +687,12 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, } } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_LOCKED_OUT) { status = NT_STATUS_ACCOUNT_LOCKED_OUT; - } else if (hdb_auth_status == KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY) { - status = NT_STATUS_OK; - } else if (hdb_auth_status == KDC_AUTH_EVENT_PREAUTH_SUCCEEDED) { - status = NT_STATUS_OK; + } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED) { + if (pa_type != NULL && strncmp(pa_type, "PK-INIT", strlen("PK-INIT")) == 0) { + status = NT_STATUS_PKINIT_NAME_MISMATCH; + } else { + status = NT_STATUS_ACCOUNT_RESTRICTION; + } } else if (hdb_auth_status == KDC_AUTH_EVENT_PREAUTH_FAILED) { if (pa_type != NULL && strncmp(pa_type, "PK-INIT", strlen("PK-INIT")) == 0) { status = NT_STATUS_PKINIT_FAILURE; @@ -698,6 +700,8 @@ static krb5_error_code hdb_samba4_audit(krb5_context context, status = NT_STATUS_GENERIC_COMMAND_FAILED; } } else { + DBG_ERR("Unhandled hdb_auth_status=%d => INTERNAL_ERROR\n", + hdb_auth_status); status = NT_STATUS_INTERNAL_ERROR; } -- 2.25.1