diff options
Diffstat (limited to 'third_party/heimdal/lib')
287 files changed, 9431 insertions, 4522 deletions
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 <literal>`. + +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 : "<unknown error>"); + } +``` + +## 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: + + - `<module>_asn1.h` + + This file defines all the exported types from the given ASN.1 module as C + types. + + - `<module>_asn1-priv.h` + + This file defines all the non-exported types from the given ASN.1 module as + C types. + + - `<module>_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_<Type>.c` or `asn1_<module>_asn1.c` + + If `--one-code-file` is used, then the implementation of the module will be + in a file named `asn1_<module>_asn1.c`, otherwise the implementation of each + type in the module will be in `asn1_<Type>.c`. + + - `<module>_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). + + - `<module>_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`. + + - `<module>_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 <type> BooleanType %type <type> ChoiceType %type <type> ConstrainedType +%type <type> UnconstrainedType %type <type> EnumeratedType %type <type> IntegerType %type <type> NullType @@ -288,6 +289,7 @@ static unsigned long idcounter; %type <constraint_spec> Constraint %type <constraint_spec> ConstraintSpec +%type <constraint_spec> SubtypeConstraint %type <constraint_spec> GeneralConstraint %type <constraint_spec> ContentsConstraint %type <constraint_spec> UserDefinedConstraint @@ -295,7 +297,6 @@ static unsigned long idcounter; %type <constraint_spec> 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 <stdio.h>\n" "#include <stdlib.h>\n" "#include <time.h>\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 : "<unknown type>"); /* 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_<fieldName> */ "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 <com_err.h> #include <vis.h> #include <vis-extras.h> +#include <heimbase.h> #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 <string.h> -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 <heimbase.h> + /* * 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 <assert.h> #include <stdarg.h> #include <vis.h> +#include <base64.h> 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 @@ -809,18 +853,196 @@ heim_audit_addkv_timediff(heim_svc_req_desc r, const char *k, } 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) : "<unprintable>"); + 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) : "<unprintable>"); + 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 : "<unknown>", r->sname ? r->sname : "<unknown>", - 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 <string.h> -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 @@ -153,6 +153,13 @@ 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 * with the mechanism proposed by SPNEGO [7] for negotiating protocol @@ -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#<digit>" -> 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#<N>" -> 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 * @@ -198,19 +220,14 @@ 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 <config.h> -#include <krb5-types.h> +#include <roken.h> -#include <sys/types.h> +#include <krb5-types.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <ctype.h> -#include <dlfcn.h> -#include <errno.h> #include <heimbase.h> #include <gssapi_asn1.h> #include <der.h> -#include <roken.h> - #include <gssapi.h> #include <gssapi_mech.h> #include <gssapi_krb5.h> 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; @@ -135,6 +136,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, gss_cred_id_t init_cred, @@ -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 <gssapi.h> #include <gssapi_krb5.h> #include <gssapi_spnego.h> +#include <krb5_asn1.h> #include <err.h> #include <getarg.h> +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<TAB>'"); 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 <hdb_err.h> +#include <heimbase-svc.h> #include <heim_asn1.h> #include <hdb_asn1.h> + +#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 @@ -164,20 +106,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 * * The HDB structure is what the KDC and kadmind framework uses to @@ -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, "<unknown error: %d>", 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 : "<unknown>", 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> STRING %token <string> 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), "<unknown-time>"); 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, "<error-formatting-time>"); + 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 <heimbasepriv.h> 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}:<subsidiary> + * - <something not starting with %{UID}:> + * - <empty string> + * - <NULL> + * + * 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 : "<unknown>", + 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 <libintl.h> +#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 <heimbasepriv.h> #include <wind.h> +#include <assert.h> 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 <assert.h> 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 <config.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -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 <config.h> - -#include "roken.h" - -#include <sys/types.h> -#include <ctype.h> -#if defined(HAVE_DB_185_H) -#include <db_185.h> -#elif defined(HAVE_DB_H) -#include <db.h> -#endif -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#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 <db.h> +#elif defined(HAVE_DB6_DB_H) +#include <db6/db.h> #elif defined(HAVE_DB5_DB_H) #include <db5/db.h> #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 <sys/cdefs.h> */ #include <limits.h> @@ -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 <sys/cdefs.h> */ #include <limits.h> @@ -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; } |