From 51569b3152a952d07fddaa3a70d60c920618c704 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 1 Mar 2022 14:17:54 +1300 Subject: 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 --- third_party/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 +- .../heimdal/kdc/altsecid_gss_preauth_authorizer.c | 85 +- third_party/heimdal/kdc/bx509d.c | 170 ++- third_party/heimdal/kdc/ca.c | 4 +- third_party/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 +- .../heimdal/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/kdc-audit.h | 67 + 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/rx.h | 79 -- third_party/heimdal/kdc/set_dbinfo.c | 2 +- third_party/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 + third_party/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 +- third_party/heimdal/lib/base/version-script.map | 7 + third_party/heimdal/lib/com_err/Makefile.am | 2 +- third_party/heimdal/lib/gss_preauth/pa_client.c | 3 +- third_party/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 +- third_party/heimdal/lib/gssapi/gssapi/gssapi.h | 16 +- .../heimdal/lib/gssapi/gssapi/gssapi_krb5.h | 2 + .../heimdal/lib/gssapi/krb5/accept_sec_context.c | 140 +-- third_party/heimdal/lib/gssapi/krb5/acquire_cred.c | 52 +- third_party/heimdal/lib/gssapi/krb5/arcfour.c | 13 +- third_party/heimdal/lib/gssapi/krb5/copy_ccache.c | 5 +- .../heimdal/lib/gssapi/krb5/export_sec_context.c | 2 +- third_party/heimdal/lib/gssapi/krb5/external.c | 19 +- third_party/heimdal/lib/gssapi/krb5/import_name.c | 35 +- .../heimdal/lib/gssapi/krb5/init_sec_context.c | 41 +- third_party/heimdal/lib/gssapi/krb5/name_attrs.c | 1171 ++++++++++++++++++ third_party/heimdal/lib/gssapi/krb5/store_cred.c | 5 +- third_party/heimdal/lib/gssapi/krb5/test_kcred.c | 6 +- .../heimdal/lib/gssapi/libgssapi-exports.def | 2 +- .../heimdal/lib/gssapi/mech/gss_compare_name.c | 10 +- third_party/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 +- third_party/heimdal/lib/gssapi/mech/gss_krb5.c | 7 +- .../heimdal/lib/gssapi/mech/gss_mech_switch.c | 47 +- .../heimdal/lib/gssapi/mech/gss_pname_to_uid.c | 4 + third_party/heimdal/lib/gssapi/mech/mech_locl.h | 11 +- .../heimdal/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 +- .../heimdal/lib/gssapi/ntlm/delete_sec_context.c | 6 + .../heimdal/lib/gssapi/ntlm/init_sec_context.c | 22 +- third_party/heimdal/lib/gssapi/ntlm/kdc.c | 1 + third_party/heimdal/lib/gssapi/sanon/import_name.c | 25 +- .../heimdal/lib/gssapi/spnego/accept_sec_context.c | 1 + third_party/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 ++++++- third_party/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 +- .../lib/hcrypto/libtommath/bn_s_mp_rand_platform.c | 2 +- .../heimdal/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 +- third_party/heimdal/lib/hdb/libhdb-exports.def | 1 - third_party/heimdal/lib/hdb/ndbm.c | 53 +- third_party/heimdal/lib/hdb/print.c | 20 +- third_party/heimdal/lib/hdb/test_concurrency.c | 58 +- third_party/heimdal/lib/hdb/test_namespace.c | 162 ++- third_party/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 +- third_party/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 +- third_party/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 --------------- third_party/heimdal/lib/roken/getipnodebyaddr.c | 2 +- third_party/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 + third_party/heimdal/lib/roken/test-getuserinfo.c | 3 +- third_party/heimdal/lib/roken/test-mini_inetd.c | 2 +- third_party/heimdal/lib/roken/timeval.c | 215 +++- third_party/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 +- .../heimdal/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 +- third_party/heimdal/tests/gss/check-context.in | 12 +- third_party/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 +- third_party/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 +- third_party/heimdal/tests/kdc/check-hdb-mitdb.in | 2 +- third_party/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 +- third_party/heimdal/tests/kdc/check-kpasswdd.in | 2 +- third_party/heimdal/tests/kdc/check-pkinit.in | 4 +- third_party/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 +- third_party/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 +- third_party/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 +- 429 files changed, 14558 insertions(+), 7431 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 create mode 100644 third_party/heimdal/kdc/kdc-audit.h 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/rx.h 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 (limited to 'third_party/heimdal') diff --git a/third_party/heimdal/.github/workflows/build.yml b/third_party/heimdal/.github/workflows/build.yml deleted file mode 100644 index c9d4d9e7981..00000000000 --- 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 2a09f94ac80..e5b52468af5 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 7fb69fdf4e0..b9bdcf4995e 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 bf9fca2a7be..5e49fd0e1a4 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 a46d484c18f..b9d0e830d38 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 f2ade9425ea..05078ee8e1f 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 35c548979a6..44b59fe5eb9 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 ecef93965ac..fd4f174988e 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 1ca6a1f61bb..deb7d303c66 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 5d2a39dd7c4..baf13ecff5f 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 64a2b1279fa..6e046990b16 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 bb1e12123e5..fa56c4c59a6 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 1b134f5b77f..90921fe46b9 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 00000000000..bc2c3f034ce --- /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 00000000000..bd753b34d7d --- /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 cf5e3a88c99..c0b4510b629 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 380412ec7a0..4c0afd9b7c3 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 1dfcb1860b5..2c2ef834e7a 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 37a2275c283..8c0b746ba5c 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 6d36ced6c3f..45a5888f721 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 16dd2250c20..43ebe706947 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 326b67b7cc9..6abdb15c911 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 2d03bf26420..5521181d27c 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 b3d6d581d9b..e2dc303b8dc 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 0ababf4f197..d128ab7f49e 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 1e5cd6117dc..4b89ca6eedd 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 d254add4482..2f3c1c1bcd7 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 089ee8b0d80..a066f56ea38 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 01725d96e20..adb2e28518a 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 35766aa1bfc..a884e11e96b 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 8b025e112f8..8a3725e3c49 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 0817b7c93aa..0eeaf508da8 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 401b6a9f6ba..b0e852931c6 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 10bbea84057..444950623f0 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 971c24793c0..f62f8b96dcc 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 9541c6efcb4..7c7b2dd7ce4 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 6ddb9dfa865..1ae10f1af7c 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 cbe16948c06..52f20202e7f 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 785de43f872..c33623038ce 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 02624dfd1c8..b11812769b6 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 09c94b6e8dd..061d4e97267 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 713af7f8650..0895f48f051 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 c36bbe9c6c6..31f17623d01 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 54382a842bf..c7f57251f7c 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 58eb7577141..aca65b104ae 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 961ced0db9a..d48ea584bc8 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 2f30744bf31..064c424b7c2 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 0d92ca7fc89..4402c44677f 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 68fe01594f8..93742e5ddd5 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 507cb195af3..e217b9dadfa 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 975f24cb269..ba8c8ad7ba5 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 fa20519d73a..52bc37c4296 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 627dc74f458..01f8f7b54a6 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 3a4f4c551db..4ea76dbe7e2 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 a8652891f53..092b4a75a4b 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 d4cd650284b..25cab3096b7 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 ce62a29afcc..d8a2a24fd94 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 69bd5fc1ae5..293e59da47b 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 6f4d56ae95c..ffe49c8bdfd 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 2746e1d8fcc..acf66bcd614 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 880a6f74640..c1db11b978e 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 426bf6ed7fd..59c39ea4784 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 31b44e28a59..9056b05a8d2 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 fd9df08e8d7..fa06a1fd401 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 3dfb365186a..0e31b4044c3 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 fad3919a2a6..7d77e7f812a 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 00000000000..81c03d2f222 --- /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/kdc-audit.h b/third_party/heimdal/kdc/kdc-audit.h new file mode 100644 index 00000000000..4b2203f2267 --- /dev/null +++ b/third_party/heimdal/kdc/kdc-audit.h @@ -0,0 +1,67 @@ +/* + * 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_AUDIT_H +#define HEIMDAL_KDC_KDC_AUDIT_H 1 + +/* + * KDC auditing + */ + +/* 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 */ + +/* + * 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 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 /* 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 00000000000..8759893a956 --- /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 00000000000..efe8dd6abe0 --- /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 af4e55c356d..29190f7837f 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 cbf4f511738..e3709ada6b0 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 e7b86151def..8418a91a0a4 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 ee7e56c5f27..b30d321f6f1 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 c9878dd6af5..39d42106e01 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 bba2b11d0f0..6ec1a548aca 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 bc3ca9deca6..6efd94e3a12 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 a4ed75bfb6a..3cc929e6025 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 895f1c9c6e4..bfb0f54ff89 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 e6a5c5c2340..b48503d26a0 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 3e4b47d7e1b..32cf5dc65ce 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 00000000000..9e67aad3319 --- /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 ad5db1e3ca4..20250c6dc89 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 b355e4c8830..f01178983f3 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 23a0fe0102d..cf8ab060ec9 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/rx.h b/third_party/heimdal/kdc/rx.h deleted file mode 100644 index f914e93e6ef..00000000000 --- a/third_party/heimdal/kdc/rx.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 1997 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 __RX_H__ -#define __RX_H__ - -/* 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 */ - -enum rx_header_flag { - HF_CLIENT_INITIATED = 1, - HF_REQ_ACK = 2, - HF_LAST = 4, - HF_MORE = 8 -}; - -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 */ -}; - -#define RX_HEADER_SIZE 28 - -#endif /* __RX_H__ */ diff --git a/third_party/heimdal/kdc/set_dbinfo.c b/third_party/heimdal/kdc/set_dbinfo.c index 93ded4ec2ae..683eaaf7be4 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 1ae9efd676c..2300eb53299 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 1b603dece58..4b9c62e5a5d 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 12b873c039b..4d80c96a034 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 cdb50e47752..858fdfa7b21 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 4b27e6943cc..9067bb6e43f 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 eb834cd6cfd..00000000000 --- 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 ae0c6d181ea..00000000000 --- 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 344688e296e..e04eebe46e1 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 1196c16dc67..2dd71bf7ab8 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 92eb770990c..4982f8a796a 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 04a16fb6ade..35b4295fb36 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 0b22e715095..6ac4b45426a 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 5dbabcaad85..b33c3c28a7a 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 d897a8e7451..3bb3b700dbd 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 8218a6f096f..b1a097a8d6f 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 00000000000..89c452a031c --- /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 94d24fc47eb..eb0308ee13c 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 eca92bd3853..19255c6cf71 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 a00dde72227..9c4e6979569 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 e75734ea26c..07c4461e3e9 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 74cf314f16e..a7953df5fa1 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 39c43341aa6..40c37fbbb94 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 290cb86310e..f6f6ec0e5c4 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 97d11899739..6ea1f812651 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 15fd2bcff92..a8956a74bd2 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 f49f5e8edf9..6b5c71c39f5 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 00000000000..df8c4747b6b --- /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 21132c8d1a4..ef5bd6990de 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 854131e2ab4..2084cef5f08 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 55ba6262359..c12f8170025 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 5f40fba1615..8fbd6f3da1c 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 5a494d23aca..253ac5aca6f 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 8e323188fff..10153c60379 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 243aa2b0cca..bec6f8b059f 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 739f9d85f70..93d412f6335 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 b0123a8be17..d61dc2e6d50 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 6c9424cbf35..0507d542180 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 24f16528c63..424e5de5d5e 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 ccef2acd231..f37f1490320 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 af1e44ee68b..883eab4b671 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 baaec52f5f8..639ec5af2d2 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 5acc596d39c..a8bd85c522f 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 ade5e2d0bfd..15d3a37beba 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 64db63ab2ec..bcfdad62e2e 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 63155efbd07..db11b114282 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 b88386223b3..8a24e251565 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 7f5670f3456..7a19e7477e3 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 a76152712d9..08c7dcd93ee 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 500ee4ec811..755eba01bfb 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 b34f9de4880..994fa7d38e4 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 27896217268..268cc018df6 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 4aa6efc6677..cefdde0c1bb 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 cd750386acc..b206ff6d766 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 8d73846b2bb..86be109ffc5 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 31017a01191..59c39137b72 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 8ae65de4981..6ba3bea412d 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 5c787ba2ce5..a562833a91a 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 df382b99887..cf249917e8f 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 1f0abd622e5..083917fb806 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 8aacdb9187d..1e6805a25e7 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 c0c94e2649b..3706fc8710d 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 8f8fad0fc8c..b9f63e56b6a 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 904d0c3ba12..818ac8398d5 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 c259f69971d..8833c8b1523 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 df225a939c2..631a3386c83 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 5384998080a..f942447163d 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 fba675cf488..be6c860e26b 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 0cd0c8444cb..928e8619995 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 8c027c74da9..14e8e66fcdc 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 1159e63c2a4..de2d7b5cbe6 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 c2287ca707a..00efde72d66 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 744232e2e35..a69ebffb04e 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 8d5784f17f1..ffba9d52be0 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 1ead3e15b32..844fa4d3820 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 4214acc0e5f..726543f5a38 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 74d5109aa19..818042fa773 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 f125573c137..3f8e2740e21 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 6b625160668..211dcaa7f75 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 9093b7a1d36..8931b32e1c9 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 182421581a8..fc0b9b12872 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 981baed6edd..c2984153752 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 91947025cc7..e58df18c5f0 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 77449612d05..f4ee2313c16 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 c7dfdc85166..62b26ed7eb9 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 00000000000..11fc2ef969f --- /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 311686dc13a..6d727b4e289 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 3cbba243f0b..c90a1443bc6 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 b8f9e75c4bc..6077c8e26f4 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 fd2523fd8e3..97ef57898da 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 3ba2dd84621..00561ce928e 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 05a05f508de..c0309809f74 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 d7559981dc5..54930bf4645 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 0acae853324..39b717e3dc2 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 0f6d14209af..78c305689f0 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 60fe376a914..372e72dd5da 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 72fd9de4624..5046faed026 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 0d74091e054..d451b87c4a7 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 d6300006b21..6a3e8899ee7 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 84a710c69e6..57940156cb5 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 a8c670c50b2..efa71d911dc 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 41c30b76f1a..57587a020db 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 1063db19b0f..be9c987c4ca 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 e5c25596aa6..1bce00fc5d6 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 189308d96ea..1a228b69e1a 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 8cb4211da26..c4ac7455cf6 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 13e28bb59fd..3f8aa5c3e7b 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 30fb5cb231f..7446d15e0df 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 866ee78ecf1..abfe390449d 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 e195313505c..933635e78c0 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 be266da773c..7f482b53624 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 1c610829feb..bb36f745190 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 15bf78738ad..62297b145f1 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 9f5c648ec94..ac174180fb9 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 774f0e1176a..720662199f9 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 0447c4f4838..5d2d214f752 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 9cea2482176..3dae960fd0c 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 23838709c8e..9cced4c536c 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 6cdf4e97a4e..6b387ae90dc 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 2c7d9b8803a..cc99c879fb9 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 a42fc70d908..6f91b64f503 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 55c69390eef..79879c35039 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 7b29a4ce948..9049fa81f91 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 bc2cdfe6e03..e7b99fce289 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 2852bd4d6b8..1d5b73e60e5 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 c99b2b6cbe9..6172b25413f 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 063a461cc16..36a5626a708 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 562e5aa4dd0..4b655f262c8 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 342aaffbe96..89ab15d9d3e 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 5ad9d9c5742..f4801f7c54e 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 251eb9b7714..a92cc1372db 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 6e415b95f16..5fcce7b8e8b 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 0daa25bbec4..9d0c0a97d9a 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 ec52d35dcba..48683ef1607 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 f3cb8fbe61d..c9b469cb1a8 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 1dbb00d3e5f..6a2876c51d7 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 cabda277f4e..6aa5201eb8a 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 1ae013157c2..7436f39edbb 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 3cab9178965..4bb2f8e8553 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 f6490783a6c..9eb96be73d0 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 3978048ad17..56c403842e6 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 97ca70c0a7e..0f2c92151e5 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 00000000000..626f8c7b07a --- /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 ae0b067f79b..457e5daf7a7 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 83cc851d91f..b1aa0207c97 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 a124f93f645..72a7fb7aaad 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 4e3a340fe55..52c52c890dc 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 0d1e2855217..7f253588189 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 9c95e6390f4..35c01f59f59 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 6aaecc083ec..a4c44ba190e 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 0846f733743..058060dae0c 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 e32da3b93c3..214dabf0e83 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 807621c21d1..3d62b93fa57 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 0d99a748fc6..33805b8ed1a 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 453762bd10f..d2728a38c2f 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 dd6222687af..7b46809816c 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 77e721064ef..8d368ed9c4d 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 d3ebd1bf648..aee4f79e747 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 1b5ca3eae71..a22f6252cfa 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 43c4713d116..1bcfdfa44e9 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 ef346505022..f25cdf4e419 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 b22093cd452..880668b4561 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 9b6a156af6c..7d67716b953 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 544001ebc0d..3309913f357 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 f0a7c218657..2b3f46d532a 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 c2f2e00cc29..18b2f8f8f96 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 7e9d4f26d9c..09f641d7c05 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 0a1445ba523..75f675579c7 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 9338b141e17..6915175618e 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 839a596388a..40601b9744f 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 0b4ee656604..58ccf32eacd 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 e0d63d2ef42..c89448f4882 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 b5674f19ab6..0c154ecfef0 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 42125e28a7e..1c2ab15f30d 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 6942148dbb5..aa9fdb4fc0a 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 677bda6d897..24a7983b6e1 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 f7182d7ec88..27fac2bbb0b 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 56aec67a223..0c87343d2e1 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 a0a3443898a..5d585d1a295 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 926c23510e9..1b1d7f2ff58 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 9c18f832e13..a2ad51e7d08 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 be0adc1b380..1decfe3333d 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 a27d8f75a38..b3f7d8105ea 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 cd9a6f57a3b..2b1be00ea60 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 376cecd9e40..4f66426c4ca 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 c66bcd75ae6..9d24233ba6e 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 cb2e1fd1dec..2159caf5517 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 e5d77f6cfd7..96133f242a9 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 ace0687613c..cb0ec86ae57 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 9bb83cd14a1..cb3696720f9 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 1052042af05..9143318176b 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 1f458258592..c30c5d82934 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 2f8eda54c09..584c194dd18 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 dd23aef7665..50d4878ae6c 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 6033f2958b4..0077016f624 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 ae33ff18299..b400626075c 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 174fa3a6189..5af391ed99b 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 99171e727ce..c1345c28a5a 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 d3202513098..40ca0fb0bcc 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 5bc97626324..63d56c400bf 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 b53c179b72e..d3196148287 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 4d235fff431..864c9cde884 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 7bca78ab606..01522dd593a 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 6df8defbce9..16eda2f6f73 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 43c762b7699..8b43b63706c 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 1920796ffc3..75083f82840 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 51faf8de99d..4040a983518 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 a16b83cb0e0..a03cdca2ebc 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 524b2e78681..2fb4f0620f7 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 eafc4520b9e..abfa0531f0e 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 22183efcafb..af88aed9156 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 bcd07e3c2d8..0efa162702c 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 371b07ff583..b4444e5a2cd 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 0e42f51bc21..da86b375f83 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 a1f4dfcfcf7..a0402350d0f 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 dcca7cc5eec..617446c3634 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 08d4f4217e4..30dff35893b 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 07047461ee7..767d94cf7fe 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 3072cbf5f6b..ec757797866 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 d6a1a9345dc..c19fc699281 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 4ad5deba090..e42fcf10bc1 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 760abf5c59d..a75fc03f985 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 6ec14b8e171..559d640f002 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 595966ed387..61b5d6d29cf 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 cb865a794c0..af3ac86faf0 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 bac94b5f7df..1013a78d873 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 3950bd30a4e..e78edcac9af 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 6b74653f565..7045c5bb601 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 873734fce77..cd388ecfaaa 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 adb8e00e6dc..3688d6ad7ce 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 dbf81850ea3..9e992216153 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 bd5991fcbf8..7525739f66c 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 245f4b1bf43..191a0c48c86 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 4ccc415a261..fdd5674c3b8 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 33e62e5b0d2..41e858f8058 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 cd9a6d6d310..2bdeae8ecd1 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 0198400d9eb..c9a6e3e8f8b 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 ee25f6acb59..6080e462341 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 b2497397840..f8d57362310 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 bd0b68b9cfb..371037c8403 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 d9c442bb27d..2fec8afd104 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 38aaa25024e..033128ed803 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 554f377125e..7a39664946b 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 704b095b535..086f2edcd5d 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 37e06dec3e8..4a12067c68b 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 6a287bdf950..79f8e3adbab 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 da66e5fa75e..6a3908f7463 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 80323e1d8f2..dddaa924578 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 120143e51e7..36775adef1b 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 c3aaef3606a..0fd10783397 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 213bb0780d9..0ca582eaaca 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 fbdb5c9c322..f722353f664 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 f1255948fc4..ed8ee9b5f3f 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 526c240f1c4..0c7e6b447ae 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 11e4e84963b..e2f2ab2085c 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 35c00e65add..484fd398c29 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 663196b29b1..c6ead8e42b2 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 ce2783c3575..f6278e9ecbf 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 a1d6b5f3a64..761e1f497fc 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 9670a971830..d75752ea000 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 1d6fe959437..9338a204def 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 a6168f944d4..35d753204e7 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 bea2866e47d..e30c193c478 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 638ec2925f2..ef74336d70a 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 86cccbb1d4f..8fb3f528001 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 a6dacdd1d29..582d183bcf7 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 4ed630210fc..9b9dba2aea5 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 36e6cda1e02..4a00682511f 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 f1035a1aed6..dc4518ad5b0 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 64c354d62bb..a14f27b8a93 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 7dfe492179d..74f35283d35 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 7132e95dd38..80a7487b8d5 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 61fbb223b5e..05dd0fe385c 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 c8ed95413fe..12a26a71225 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 a8dd94bef9a..00000000000 --- 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 7d4095f1d84..afebe914950 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 2ff282707c2..ee430c76eb6 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 b23ad01ebdd..9d118600f26 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 76cd78241be..7fd2ca9f151 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 a81422e1f4a..01f21c821d1 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 c66b324f790..cc47fa4d52d 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 2d551a607a2..39b0301c454 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 f7b87f1203e..f8403da44ab 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 1e8361999ea..e66f56b7595 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 25cc98aafe3..581600a5937 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 f05f88668f3..035b99b8b97 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 e1aa6b7b60c..e1902f582dc 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 620875f379c..3da48962ee3 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 9feb343f508..a790e082d82 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 447c1554337..9a951dd3008 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 75c27a32877..86216d2d6dc 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 0d895d54a25..96c1b250974 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 94530e574d1..0516e18f913 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 b3f15214b56..4feae177aed 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 079ace266a1..7ab996ae8b4 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 38b1f7ce9c3..3012513ee7d 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 3307341c049..be1713e8261 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 c598967fb72..0fe44ae3502 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 152b86a330a..1213d8c9df9 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 03f577b5f59..b78f9f675b2 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 767ffc833c8..38045c10048 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 1bc63a33dd8..378c912a392 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 d69db0c0cec..452b7b260d8 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 ad63ae04f4c..2923e649b96 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 0b6000d1bfa..8ac6cc665fd 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 954a2c1d5f5..c9291d08bf2 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 ca40ae26bd2..2de36bfe24c 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 d4916bd46d4..c5151c4c94f 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 42ea15eecb9..46c058d068b 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 44769eff584..539e2e94e52 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 f5bf3446ae6..f953630d09d 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 3cf56089602..d6e4d833152 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 b8e04b65159..aae031db645 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 04043ca02e2..82033447409 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 a07f776eb23..f61a7e85307 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 1cef2e0e766..b50239d8440 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 0bb5a413f3c..18b83a9b7a6 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 ce95b300664..46e846a10ea 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 8657946168a..fdff0f6a0f0 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 d45b119dfa5..144613df4f9 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 1623783eba6..d934f4e2898 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 136bf3ed62b..3fbda813a63 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 e9de58799a3..a241aeb4a8f 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 b593925a352..f57f2af8592 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 21296877943..524379393fa 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 3d3f41003d8..45d679ceb4a 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 75626f6ce85..e53293b2427 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 35ec6deadbf..c6cb23ff6f8 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 4f63ce240fa..39f12e1be8c 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 baa9fb30691..9f90fd040f9 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 d028e39ef1f..73c26c368ca 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 dba154c299b..83b48baf27f 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 7e819a14ad0..ef831ca4d94 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 00000000000..bdcca073cc0 --- /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 19b4e3ef64e..a85836d76b2 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 b99c951032b..f73eb6e1b88 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 3fb1a2324b9..5dd43ccb04d 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 60ec21a31f3..85bf8cd9a98 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 00000000000..4fcf311fddf --- /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 8ab2f17177c..d188c314b36 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 357148019ae..00000000000 --- 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 00000000000..a9f2b30dfdf --- /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 47df51042a2..471e783912b 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 -- cgit v1.2.1