diff options
Diffstat (limited to 'third_party/heimdal/lib')
91 files changed, 2366 insertions, 570 deletions
diff --git a/third_party/heimdal/lib/asn1/asn1_compile.1 b/third_party/heimdal/lib/asn1/asn1_compile.1 index a7953df5fa1..9af27672c2a 100644 --- a/third_party/heimdal/lib/asn1/asn1_compile.1 +++ b/third_party/heimdal/lib/asn1/asn1_compile.1 @@ -330,6 +330,11 @@ to form the names of the files generated. .It Fl Fl option-file=FILE Take additional command-line options from .Ar FILE . +The options file must have one command-line option per-line, but +leading whitespace is ignored, and lines that start with a hash +symbol +.Sq ( # ) +are comments and are ignored. .It Fl Fl original-order Attempt to preserve the original order of type definition in the ASN.1 module. diff --git a/third_party/heimdal/lib/asn1/gen_copy.c b/third_party/heimdal/lib/asn1/gen_copy.c index bec6f8b059f..c6d420a2f16 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; + HEIM_FALLTHROUGH; case TBoolean: case TEnumerated : fprintf(codefile, "*(%s) = *(%s);\n", to, from); diff --git a/third_party/heimdal/lib/asn1/gen_free.c b/third_party/heimdal/lib/asn1/gen_free.c index 0507d542180..53b7bfe7b90 100644 --- a/third_party/heimdal/lib/asn1/gen_free.c +++ b/third_party/heimdal/lib/asn1/gen_free.c @@ -56,7 +56,7 @@ free_type (const char *name, const Type *t, int preserve) free_primitive ("heim_integer", name); break; } - /* fallthrough; */ + /* HEIM_FALLTHROUGH; */ case TBoolean: case TEnumerated : case TNull: diff --git a/third_party/heimdal/lib/asn1/main.c b/third_party/heimdal/lib/asn1/main.c index bcfdad62e2e..569b4782b4d 100644 --- a/third_party/heimdal/lib/asn1/main.c +++ b/third_party/heimdal/lib/asn1/main.c @@ -409,8 +409,16 @@ main(int argc, char **argv) sz = 2; while (fgets(buf, sizeof(buf), opt) != NULL) { + size_t buflen, ws; + buf[strcspn(buf, "\n\r")] = '\0'; + buflen = strlen(buf); + if ((ws = strspn(buf, " \t"))) + memmove(buf, buf + ws, buflen -= ws); + if (buf[0] == '\0' || buf[0] == '#') + continue; + if (len + 1 >= sz) { arg = realloc(arg, (sz + (sz>>1) + 2) * sizeof(arg[0])); if (arg == NULL) { diff --git a/third_party/heimdal/lib/asn1/template.c b/third_party/heimdal/lib/asn1/template.c index 7a19e7477e3..31eb66004ec 100644 --- a/third_party/heimdal/lib/asn1/template.c +++ b/third_party/heimdal/lib/asn1/template.c @@ -2549,7 +2549,9 @@ _asn1_print(const struct asn1_template *t, } default: break; } - if (nnames) + if (nnames && + (t->tt & A1_OP_MASK) != A1_OP_TYPE_DECORATE_EXTERN && + (t->tt & A1_OP_MASK) != A1_OP_TYPE_DECORATE) r = rk_strpoolprintf(r, ",%s\"%s\":", indents ? indents : "", (const char *)(tnames++)->ptr); diff --git a/third_party/heimdal/lib/base/heimbase.h b/third_party/heimdal/lib/base/heimbase.h index 3706fc8710d..5d5c4e3b75e 100644 --- a/third_party/heimdal/lib/base/heimbase.h +++ b/third_party/heimdal/lib/base/heimbase.h @@ -134,6 +134,28 @@ typedef struct heim_config_binding heim_config_section; * CF-like, JSON APIs */ +typedef enum heim_tid_enum { + HEIM_TID_NUMBER = 0, + HEIM_TID_NULL = 1, + HEIM_TID_BOOL = 2, + HEIM_TID_TAGGED_UNUSED2 = 3, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED3 = 4, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED4 = 5, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED5 = 6, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED6 = 7, /* reserved for tagged object types */ + HEIM_TID_MEMORY = 128, + HEIM_TID_ARRAY = 129, + HEIM_TID_DICT = 130, + HEIM_TID_STRING = 131, + HEIM_TID_AUTORELEASE = 132, + HEIM_TID_ERROR = 133, + HEIM_TID_DATA = 134, + HEIM_TID_DB = 135, + HEIM_TID_PA_AUTH_MECH = 136, + HEIM_TID_PAC = 137, + HEIM_TID_USER = 255 +} heim_tid; + typedef void * heim_object_t; typedef unsigned int heim_tid_t; typedef heim_object_t heim_bool_t; @@ -463,7 +485,13 @@ typedef enum heim_json_flags { HEIM_JSON_F_STRICT = 31, HEIM_JSON_F_CNULL2JSNULL = 32, HEIM_JSON_F_TRY_DECODE_DATA = 64, - HEIM_JSON_F_ONE_LINE = 128 + HEIM_JSON_F_ONE_LINE = 128, + HEIM_JSON_F_ESCAPE_NON_ASCII = 256, + HEIM_JSON_F_NO_ESCAPE_NON_ASCII = 512, + /* The default is to indent with one tab */ + HEIM_JSON_F_INDENT2 = 1024, + HEIM_JSON_F_INDENT4 = 2048, + HEIM_JSON_F_INDENT8 = 4096, } heim_json_flags_t; heim_object_t heim_json_create(const char *, size_t, heim_json_flags_t, diff --git a/third_party/heimdal/lib/base/heimbasepriv.h b/third_party/heimdal/lib/base/heimbasepriv.h index b9f63e56b6a..45ffb12d70e 100644 --- a/third_party/heimdal/lib/base/heimbasepriv.h +++ b/third_party/heimdal/lib/base/heimbasepriv.h @@ -47,29 +47,6 @@ typedef heim_string_t (*heim_type_description)(void *); typedef struct heim_type_data *heim_type_t; -enum { - HEIM_TID_NUMBER = 0, - HEIM_TID_NULL = 1, - HEIM_TID_BOOL = 2, - HEIM_TID_TAGGED_UNUSED2 = 3, /* reserved for tagged object types */ - HEIM_TID_TAGGED_UNUSED3 = 4, /* reserved for tagged object types */ - HEIM_TID_TAGGED_UNUSED4 = 5, /* reserved for tagged object types */ - HEIM_TID_TAGGED_UNUSED5 = 6, /* reserved for tagged object types */ - HEIM_TID_TAGGED_UNUSED6 = 7, /* reserved for tagged object types */ - HEIM_TID_MEMORY = 128, - HEIM_TID_ARRAY = 129, - HEIM_TID_DICT = 130, - HEIM_TID_STRING = 131, - HEIM_TID_AUTORELEASE = 132, - HEIM_TID_ERROR = 133, - HEIM_TID_DATA = 134, - HEIM_TID_DB = 135, - HEIM_TID_PA_AUTH_MECH = 136, - HEIM_TID_PAC = 137, - HEIM_TID_USER = 255 - -}; - struct heim_type_data { heim_tid_t tid; const char *name; diff --git a/third_party/heimdal/lib/base/json.c b/third_party/heimdal/lib/base/json.c index 2ef371b975e..c7ef0658850 100644 --- a/third_party/heimdal/lib/base/json.c +++ b/third_party/heimdal/lib/base/json.c @@ -37,10 +37,12 @@ #include <ctype.h> #include <base64.h> +#ifndef WIN32 +#include <langinfo.h> +#endif + static heim_base_once_t heim_json_once = HEIM_BASE_ONCE_INIT; static heim_string_t heim_tid_data_uuid_key = NULL; -static const char base64_chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static void json_init_once(void *arg) @@ -66,7 +68,7 @@ struct heim_strbuf { }; static int -base2json(heim_object_t, struct twojson *); +base2json(heim_object_t, struct twojson *, int); static void indent(struct twojson *j) @@ -74,8 +76,18 @@ indent(struct twojson *j) size_t i = j->indent; if (j->flags & HEIM_JSON_F_ONE_LINE) return; - while (i--) - j->out(j->ctx, "\t"); + if (j->flags & HEIM_JSON_F_INDENT2) + while (i--) + j->out(j->ctx, " "); + else if (j->flags & HEIM_JSON_F_INDENT4) + while (i--) + j->out(j->ctx, " "); + else if (j->flags & HEIM_JSON_F_INDENT8) + while (i--) + j->out(j->ctx, " "); + else + while (i--) + j->out(j->ctx, "\t"); } static void @@ -90,7 +102,7 @@ array2json(heim_object_t value, void *ctx, int *stop) j->out(j->ctx, NULL); /* eat previous '\n' if possible */ j->out(j->ctx, ",\n"); } - j->ret = base2json(value, j); + j->ret = base2json(value, j, 0); } static void @@ -105,19 +117,77 @@ dict2json(heim_object_t key, heim_object_t value, void *ctx) j->out(j->ctx, NULL); /* eat previous '\n' if possible */ j->out(j->ctx, ",\n"); } - j->ret = base2json(key, j); - if (j->ret) - return; - j->out(j->ctx, " : \n"); - j->indent++; - j->ret = base2json(value, j); + j->ret = base2json(key, j, 0); if (j->ret) return; - j->indent--; + switch (heim_get_tid(value)) { + case HEIM_TID_ARRAY: + case HEIM_TID_DICT: + case HEIM_TID_DATA: + j->out(j->ctx, ":\n"); + j->indent++; + j->ret = base2json(value, j, 0); + if (j->ret) + return; + j->indent--; + break; + default: + j->out(j->ctx, ": "); + j->ret = base2json(value, j, 1); + break; + } +} + +#ifndef WIN32 +static void +init_is_utf8(void *ptr) +{ + *(int *)ptr = strcasecmp("utf-8", nl_langinfo(CODESET)) == 0; +} +#endif + +int +heim_locale_is_utf8(void) +{ +#ifdef WIN32 + return 0; /* XXX Implement */ +#else + static int locale_is_utf8 = -1; + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; + + heim_base_once_f(&once, &locale_is_utf8, init_is_utf8); + return locale_is_utf8; +#endif +} + +static void +out_escaped_bmp(struct twojson *j, const unsigned char *p, int nbytes) +{ + unsigned char e[sizeof("\\u0000")]; + unsigned codepoint; + + if (nbytes == 2) + codepoint = ((p[0] & 0x1f) << 6) | (p[1] & 0x3f); + else if (nbytes == 3) + codepoint = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f); + else + abort(); + e[0] = '\\'; + e[1] = 'u'; + e[2] = codepoint >> 12; + e[2] += (e[2] < 10) ? '0' : ('A' - 10); + e[3] = (codepoint >> 8) & 0x0f; + e[3] += (e[3] < 10) ? '0' : ('A' - 10); + e[4] = (codepoint >> 4) & 0x0f; + e[4] += (e[4] < 10) ? '0' : ('A' - 10); + e[5] = codepoint & 0x0f; + e[5] += (e[5] < 10) ? '0' : ('A' - 10); + e[6] = '\0'; + j->out(j->ctx, (char *)e); } static int -base2json(heim_object_t obj, struct twojson *j) +base2json(heim_object_t obj, struct twojson *j, int skip_indent) { heim_tid_t type; int first = 0; @@ -166,12 +236,186 @@ base2json(heim_object_t obj, struct twojson *j) j->first = first; break; - case HEIM_TID_STRING: - indent(j); + case HEIM_TID_STRING: { + const unsigned char *s = (const unsigned char *)heim_string_get_utf8(obj); + const unsigned char *p; + unsigned int c, cp, ctop, cbot; + char e[sizeof("\\u0123\\u3210")]; + int good; + size_t i; + + if (!skip_indent) + indent(j); j->out(j->ctx, "\""); - j->out(j->ctx, heim_string_get_utf8(obj)); + for (p = s; (c = *p); p++) { + switch (c) { + /* ASCII control characters w/ C-like escapes */ + case '\b': j->out(j->ctx, "\\b"); continue; + case '\f': j->out(j->ctx, "\\f"); continue; + case '\n': j->out(j->ctx, "\\n"); continue; + case '\r': j->out(j->ctx, "\\r"); continue; + case '\t': j->out(j->ctx, "\\t"); continue; + /* Other must-escape non-control ASCII characters */ + case '"': j->out(j->ctx, "\\\""); continue; + case '\\': j->out(j->ctx, "\\\\"); continue; + default: break; + } + + /* + * JSON string encoding is... complex. + * + * Invalid UTF-8 w/ HEIM_JSON_F_STRICT_STRINGS set -> return 1 + * + * Invalid UTF-8 w/o HEIM_JSON_F_STRICT_STRINGS set -> pass + * through, a sort of Heimdal WTF-8, but not _the_ WTF-8. + */ + if (c < 0x20) { + /* ASCII control character w/o C-like escape */ + e[0] = '\\'; + e[1] = 'u'; + e[2] = '0'; + e[3] = '0'; + e[4] = "0123456789ABCDEF"[c>>4]; + e[5] = "0123456789ABCDEF"[c & 0x0f]; + e[6] = '\0'; + j->out(j->ctx, e); + continue; + } + if (c < 0x80) { + /* ASCII */ + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } + if ((c & 0xc0) == 0x80) { + /* UTF-8 bare non-leading byte */ + if (!(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } + return 1; + } + if ((c & 0xe0) == 0xc0) { + /* UTF-8 leading byte of two-byte sequence */ + good = 1; + for (i = 1; i < 2 && good && p[i]; i++) { + if ((p[i] & 0xc0) != 0x80) + good = 0; + } + if (i != 2) + good = 0; + if (!good && !(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } else if (!good) { + return 1; + } + if (j->flags & HEIM_JSON_F_ESCAPE_NON_ASCII) { + out_escaped_bmp(j, p, 2); + p += 1; + continue; + } + e[0] = c; + e[1] = p[1]; + e[2] = '\0'; + j->out(j->ctx, e); + p += 1; + continue; + } + if ((c & 0xf0) == 0xe0) { + /* UTF-8 leading byte of three-byte sequence */ + good = 1; + for (i = 1; i < 3 && good && p[i]; i++) { + if ((p[i] & 0xc0) != 0x80) + good = 0; + } + if (i != 3) + good = 0; + if (!good && !(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } else if (!good) { + return 1; + } + if (j->flags & HEIM_JSON_F_ESCAPE_NON_ASCII) { + out_escaped_bmp(j, p, 3); + p += 2; + continue; + } + e[0] = c; + e[1] = p[1]; + e[2] = p[2]; + e[3] = '\0'; + j->out(j->ctx, e); + p += 2; + continue; + } + + if (c > 0xf7) { + /* Invalid UTF-8 leading byte */ + if (!(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } + return 1; + } + + /* + * A codepoint > U+FFFF, needs encoding a la UTF-16 surrogate + * pair because JSON takes after JS which uses UTF-16. Ugly. + */ + cp = c & 0x7; + good = 1; + for (i = 1; i < 4 && good && p[i]; i++) { + if ((p[i] & 0xc0) == 0x80) + cp = (cp << 6) | (p[i] & 0x3f); + else + good = 0; + } + if (i != 4) + good = 0; + if (!good && !(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } else if (!good) { + return 1; + } + p += 3; + + cp -= 0x10000; + ctop = 0xD800 + (cp >> 10); + cbot = 0xDC00 + (cp & 0x3ff); + + e[0 ] = '\\'; + e[1 ] = 'u'; + e[2 ] = "0123456789ABCDEF"[(ctop ) >> 12]; + e[3 ] = "0123456789ABCDEF"[(ctop & 0x0f00) >> 8]; + e[4 ] = "0123456789ABCDEF"[(ctop & 0x00f0) >> 4]; + e[5 ] = "0123456789ABCDEF"[(ctop & 0x000f) ]; + e[6 ] = '\\'; + e[7 ] = 'u'; + e[8 ] = "0123456789ABCDEF"[(cbot ) >> 12]; + e[9 ] = "0123456789ABCDEF"[(cbot & 0x0f00) >> 8]; + e[10] = "0123456789ABCDEF"[(cbot & 0x00f0) >> 4]; + e[11] = "0123456789ABCDEF"[(cbot & 0x000f) ]; + e[12] = '\0'; + j->out(j->ctx, e); + continue; + } j->out(j->ctx, "\""); break; + } case HEIM_TID_DATA: { heim_dict_t d; @@ -220,7 +464,7 @@ base2json(heim_object_t obj, struct twojson *j) heim_release(d); return ENOMEM; } - ret = base2json(d, j); + ret = base2json(d, j, 0); heim_release(d); if (ret) return ret; @@ -230,17 +474,20 @@ base2json(heim_object_t obj, struct twojson *j) case HEIM_TID_NUMBER: { char num[32]; - indent(j); + if (!skip_indent) + indent(j); snprintf(num, sizeof (num), "%d", heim_number_get_int(obj)); j->out(j->ctx, num); break; } case HEIM_TID_NULL: - indent(j); + if (!skip_indent) + indent(j); j->out(j->ctx, "null"); break; case HEIM_TID_BOOL: - indent(j); + if (!skip_indent) + indent(j); j->out(j->ctx, heim_bool_val(obj) ? "true" : "false"); break; default: @@ -255,9 +502,6 @@ heim_base2json(heim_object_t obj, void *ctx, heim_json_flags_t flags, { struct twojson j; - if (flags & HEIM_JSON_F_STRICT_STRINGS) - return ENOTSUP; /* Sorry, not yet! */ - heim_base_once_f(&heim_json_once, NULL, json_init_once); j.indent = 0; @@ -267,7 +511,11 @@ heim_base2json(heim_object_t obj, void *ctx, heim_json_flags_t flags, j.ret = 0; j.first = 1; - return base2json(obj, &j); + if (!(flags & HEIM_JSON_F_NO_ESCAPE_NON_ASCII) && + !heim_locale_is_utf8()) + j.flags |= HEIM_JSON_F_ESCAPE_NON_ASCII; + + return base2json(obj, &j, 0); } @@ -342,93 +590,425 @@ parse_number(struct parse_ctx *ctx) return heim_number_create(number * neg); } +/* + * Read 4 hex digits from ctx->p. + * + * If we don't have enough, rewind ctx->p and return -1 . + */ +static int +unescape_unicode(struct parse_ctx *ctx) +{ + int c = 0; + int i; + + for (i = 0; i < 4 && ctx->p < ctx->pend; i++, ctx->p++) { + if (*ctx->p >= '0' && *ctx->p <= '9') { + c = (c << 4) + (*ctx->p - '0'); + } else if (*ctx->p >= 'A' && *ctx->p <= 'F') { + c = (c << 4) + (10 + *ctx->p - 'A'); + } else if (*ctx->p >= 'a' && *ctx->p <= 'f') { + c = (c << 4) + (10 + *ctx->p - 'a'); + } else { + ctx->p -= i; + return -1; + } + } + return c; +} + +static int +encode_utf8(struct parse_ctx *ctx, char **pp, char *pend, int c) +{ + char *p = *pp; + + if (c < 0x80) { + /* ASCII */ + if (p >= pend) return 0; + *(p++) = c; + *pp = p; + return 1; + } + if (c < 0x800) { + /* 2 code unit UTF-8 sequence */ + if (p >= pend) return 0; + *(p++) = 0xc0 | ((c >> 6) ); + if (p == pend) return 0; + *(p++) = 0x80 | ((c ) & 0x3f); + *pp = p; + return 1; + } + if (c < 0x10000) { + /* 3 code unit UTF-8 sequence */ + if (p >= pend) return 0; + *(p++) = 0xe0 | ((c >> 12) ); + if (p == pend) return 0; + *(p++) = 0x80 | ((c >> 6) & 0x3f); + if (p == pend) return 0; + *(p++) = 0x80 | ((c) & 0x3f); + *pp = p; + return 1; + } + if (c < 0x110000) { + /* 4 code unit UTF-8 sequence */ + if (p >= pend) return 0; + *(p++) = 0xf0 | ((c >> 18) ); + if (p == pend) return 0; + *(p++) = 0x80 | ((c >> 12) & 0x3f); + if (p == pend) return 0; + *(p++) = 0x80 | ((c >> 6) & 0x3f); + if (p == pend) return 0; + *(p++) = 0x80 | ((c) & 0x3f); + *pp = p; + return 1; + } + return 0; +} + +static heim_string_t +parse_string_error(struct parse_ctx *ctx, + char *freeme, + const char *msg) +{ + free(freeme); + ctx->error = heim_error_create(EINVAL, "%s at %lu", msg, ctx->lineno); + return NULL; +} + static heim_string_t parse_string(struct parse_ctx *ctx) { const uint8_t *start; - int quote = 0; - - if (ctx->flags & HEIM_JSON_F_STRICT_STRINGS) { - ctx->error = heim_error_create(EINVAL, "Strict JSON string encoding " - "not yet supported"); - return NULL; + heim_object_t o; + size_t alloc_len = 0; + size_t need = 0; + char *p0, *p, *pend; + int strict = ctx->flags & HEIM_JSON_F_STRICT_STRINGS; + int binary = 0; + + if (*ctx->p != '"') + return parse_string_error(ctx, NULL, + "Expected a JSON string but found " + "something else"); + start = ++(ctx->p); + + /* Estimate how many bytes we need to allocate */ + p0 = p = pend = NULL; + for (need = 1; ctx->p < ctx->pend; ctx->p++) { + need++; + if (*ctx->p == '\\') + ctx->p++; + else if (*ctx->p == '"') + break; } + if (ctx->p == ctx->pend) + return parse_string_error(ctx, NULL, "Unterminated JSON string"); - if (*ctx->p != '"') { - ctx->error = heim_error_create(EINVAL, "Expected a JSON string but " - "found something else at line %lu", - ctx->lineno); - return NULL; + ctx->p = start; + while (ctx->p < ctx->pend) { + const unsigned char *p_save; + int32_t ctop, cbot; + + if (*ctx->p == '"') { + ctx->p++; + break; + } + + /* Allocate or resize our output buffer if need be */ + if (need || p == pend) { + char *tmp; + + /* + * Work out how far p is into p0 to re-esablish p after + * the realloc() + */ + size_t p0_to_p_len = (p - p0); + + tmp = realloc(p0, alloc_len + need + 5 /* slop? */); + + if (tmp == NULL) { + ctx->error = heim_error_create_enomem(); + free(p0); + return NULL; + } + alloc_len += need + 5; + + /* + * We have two pointers, p and p0, we want to keep them + * pointing into the same memory after the realloc() + */ + p = tmp + p0_to_p_len; + p0 = tmp; + pend = p0 + alloc_len; + + need = 0; + } + + if (*ctx->p != '\\') { + unsigned char c = *ctx->p; + + /* + * Not backslashed -> consume now. + * + * NOTE: All cases in this block must continue or return w/ error. + */ + + /* Check for unescaped ASCII control characters */ + if (c == '\n') { + if (strict) + return parse_string_error(ctx, p0, + "Unescaped newline in JSON string"); + /* Count the newline but don't add it to the decoding */ + ctx->lineno++; + } else if (strict && *ctx->p <= 0x1f) { + return parse_string_error(ctx, p0, "Unescaped ASCII control character"); + } else if (c == 0) { + binary = 1; + } + if (!strict || c < 0x80) { + /* ASCII, or not strict -> no need to validate */ + *(p++) = c; + ctx->p++; + continue; + } + + /* + * Being strict for parsing means we want to detect malformed UTF-8 + * sequences. + * + * If not strict then we just go on below and add to `p' whatever + * bytes we find in `ctx->p' as we find them. + * + * For each two-byte sequence we need one more byte in `p[]'. For + * each three-byte sequence we need two more bytes in `p[]'. + * + * Setting `need' and looping will cause `p0' to be grown. + * + * NOTE: All cases in this block must continue or return w/ error. + */ + if ((c & 0xe0) == 0xc0) { + /* Two-byte UTF-8 encoding */ + if (pend - p < 2) { + need = 2; + continue; /* realloc p0 */ + } + + *(p++) = c; + ctx->p++; + if (ctx->p == ctx->pend) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + c = *(ctx->p++); + if ((c & 0xc0) != 0x80) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + *(p++) = c; + continue; + } + if ((c & 0xf0) == 0xe0) { + /* Three-byte UTF-8 encoding */ + if (pend - p < 3) { + need = 3; + continue; /* realloc p0 */ + } + + *(p++) = c; + ctx->p++; + if (ctx->p == ctx->pend) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + c = *(ctx->p++); + if ((c & 0xc0) != 0x80) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + *(p++) = c; + c = *(ctx->p++); + if ((c & 0xc0) != 0x80) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + *(p++) = c; + continue; + } + if ((c & 0xf8) == 0xf0) + return parse_string_error(ctx, p0, "UTF-8 sequence not " + "encoded as escaped UTF-16"); + if ((c & 0xc0) == 0x80) + return parse_string_error(ctx, p0, + "Invalid UTF-8 " + "(bare continuation code unit)"); + + return parse_string_error(ctx, p0, "Not UTF-8"); + } + + /* Backslash-quoted character */ + ctx->p++; + if (ctx->p == ctx->pend) { + ctx->error = + heim_error_create(EINVAL, + "Unterminated JSON string at line %lu", + ctx->lineno); + free(p0); + return NULL; + } + switch (*ctx->p) { + /* Simple escapes */ + case 'b': *(p++) = '\b'; ctx->p++; continue; + case 'f': *(p++) = '\f'; ctx->p++; continue; + case 'n': *(p++) = '\n'; ctx->p++; continue; + case 'r': *(p++) = '\r'; ctx->p++; continue; + case 't': *(p++) = '\t'; ctx->p++; continue; + case '"': *(p++) = '"'; ctx->p++; continue; + case '\\': *(p++) = '\\'; ctx->p++; continue; + /* Escaped Unicode handled below */ + case 'u': + /* + * Worst case for !strict we need 11 bytes for a truncated non-BMP + * codepoint escape. Call it 12. + */ + if (strict) + need = 4; + else + need = 12; + if (pend - p < need) { + /* Go back to the backslash, realloc, try again */ + ctx->p--; + continue; + } + + need = 0; + ctx->p++; + break; + default: + if (!strict) { + *(p++) = *ctx->p; + ctx->p++; + continue; + } + ctx->error = + heim_error_create(EINVAL, + "Invalid backslash escape at line %lu", + ctx->lineno); + free(p0); + return NULL; + } + + /* Unicode code point */ + if (pend - p < 12) { + need = 12; + ctx->p -= 2; /* for "\\u" */ + continue; /* This will cause p0 to be realloc'ed */ + } + p_save = ctx->p; + ctop = cbot = -3; + ctop = unescape_unicode(ctx); + if (ctop == -1 && strict) + return parse_string_error(ctx, p0, "Invalid escaped Unicode"); + if (ctop == -1) { + /* + * Not strict; tolerate bad input. + * + * Output "\\u" and then loop to treat what we expected to be four + * digits as if they were not part of an escaped Unicode codepoint. + */ + ctx->p = p_save; + if (p < pend) + *(p++) = '\\'; + if (p < pend) + *(p++) = 'u'; + continue; + } + if (ctop == 0) { + *(p++) = '\0'; + binary = 1; + continue; + } + if (ctop < 0xd800) { + if (!encode_utf8(ctx, &p, pend, ctop)) + return parse_string_error(ctx, p0, + "Internal JSON string parse error"); + continue; + } + + /* + * We parsed the top escaped codepoint of a surrogate pair encoding + * of a non-BMP Unicode codepoint. What follows must be another + * escaped codepoint. + */ + if (ctx->p < ctx->pend && ctx->p[0] == '\\') + ctx->p++; + else + ctop = -1; + if (ctop > -1 && ctx->p < ctx->pend && ctx->p[0] == 'u') + ctx->p++; + else + ctop = -1; + if (ctop > -1) { + /* Parse the hex digits of the bottom half of the surrogate pair */ + cbot = unescape_unicode(ctx); + if (cbot == -1 || cbot < 0xdc00) + ctop = -1; + } + if (ctop == -1) { + if (strict) + return parse_string_error(ctx, p0, + "Invalid surrogate pair"); + + /* + * Output "\\u", rewind, output the digits of `ctop'. + * + * When we get to what should have been the bottom half of the + * pair we'll necessarily fail to parse it as a normal escaped + * Unicode codepoint, and once again, rewind and output its digits. + */ + if (p < pend) + *(p++) = '\\'; + if (p < pend) + *(p++) = 'u'; + ctx->p = p_save; + continue; + } + + /* Finally decode the surrogate pair then encode as UTF-8 */ + ctop -= 0xd800; + cbot -= 0xdc00; + if (!encode_utf8(ctx, &p, pend, 0x10000 + ((ctop << 10) | (cbot & 0x3ff)))) + return parse_string_error(ctx, p0, + "Internal JSON string parse error"); } - start = ++ctx->p; - while (ctx->p < ctx->pend) { - if (*ctx->p == '\n') { - ctx->lineno++; - } else if (*ctx->p == '\\') { - if (ctx->p + 1 == ctx->pend) - goto out; - ctx->p++; - quote = 1; - } else if (*ctx->p == '"') { - heim_object_t o; - - if (quote) { - char *p0, *p; - p = p0 = malloc(ctx->p - start); - if (p == NULL) - goto out; - while (start < ctx->p) { - if (*start == '\\') { - start++; - /* XXX validate quoted char */ - } - *p++ = *start++; - } - o = heim_string_create_with_bytes(p0, p - p0); - free(p0); - } else { - o = heim_string_create_with_bytes(start, ctx->p - start); - if (o == NULL) { - ctx->error = heim_error_create_enomem(); - return NULL; - } - - /* If we can decode as base64, then let's */ - if (ctx->flags & HEIM_JSON_F_TRY_DECODE_DATA) { - void *buf; - size_t len; - const char *s; - - s = heim_string_get_utf8(o); - len = strlen(s); - - if (len >= 4 && strspn(s, base64_chars) >= len - 2) { - buf = malloc(len); - if (buf == NULL) { - heim_release(o); - ctx->error = heim_error_create_enomem(); - return NULL; - } - len = rk_base64_decode(s, buf); - if (len == -1) { - free(buf); - return o; - } - heim_release(o); - o = heim_data_ref_create(buf, len, free); - } - } - } - ctx->p += 1; + if (p0 == NULL) + return heim_string_create(""); - return o; - } - ctx->p += 1; + /* NUL-terminate for rk_base64_decode() and plain paranoia */ + if (p0 != NULL && p == pend) { + /* + * Work out how far p is into p0 to re-esablish p after + * the realloc() + */ + size_t p0_to_pend_len = (pend - p0); + char *tmp = realloc(p0, 1 + p0_to_pend_len); + + if (tmp == NULL) { + ctx->error = heim_error_create_enomem(); + free(p0); + return NULL; + } + /* + * We have three pointers, p, pend (which are the same) + * and p0, we want to keep them pointing into the same + * memory after the realloc() + */ + p = tmp + p0_to_pend_len; + + pend = p + 1; + p0 = tmp; } - out: - ctx->error = heim_error_create(EINVAL, "ran out of string"); - return NULL; + *(p++) = '\0'; + + /* If there's embedded NULs, it's not a C string */ + if (binary) { + o = heim_data_ref_create(p0, (p - 1) - p0, free); + return o; + } + + /* Sadly this will copy `p0' */ + o = heim_string_create_with_bytes(p0, p - p0); + free(p0); + return o; } static int @@ -809,3 +1389,83 @@ heim_json_copy_serialize(heim_object_t obj, heim_json_flags_t flags, heim_error_ } return str; } + +struct heim_eq_f_ctx { + heim_dict_t other; + int ret; +}; + +static void +heim_eq_dict_iter_f(heim_object_t key, heim_object_t val, void *d) +{ + struct heim_eq_f_ctx *ctx = d; + heim_object_t other_val; + + if (!ctx->ret) + return; + + /* + * This doesn't work if the key is an array or a dict, which, anyways, + * isn't allowed in JSON, though we allow it. + */ + other_val = heim_dict_get_value(ctx->other, key); + ctx->ret = heim_json_eq(val, other_val); +} + +int +heim_json_eq(heim_object_t a, heim_object_t b) +{ + heim_tid_t atid, btid; + + if (a == b) + return 1; + if (a == NULL || b == NULL) + return 0; + atid = heim_get_tid(a); + btid = heim_get_tid(b); + if (atid != btid) + return 0; + switch (atid) { + case HEIM_TID_ARRAY: { + size_t len = heim_array_get_length(b); + size_t i; + + if (heim_array_get_length(a) != len) + return 0; + for (i = 0; i < len; i++) { + if (!heim_json_eq(heim_array_get_value(a, i), + heim_array_get_value(b, i))) + return 0; + } + return 1; + } + case HEIM_TID_DICT: { + struct heim_eq_f_ctx ctx; + + ctx.other = b; + ctx.ret = 1; + heim_dict_iterate_f(a, &ctx, heim_eq_dict_iter_f); + + if (ctx.ret) { + ctx.other = a; + heim_dict_iterate_f(b, &ctx, heim_eq_dict_iter_f); + } + return ctx.ret; + } + case HEIM_TID_STRING: + return strcmp(heim_string_get_utf8(a), heim_string_get_utf8(b)) == 0; + case HEIM_TID_DATA: { + return heim_data_get_length(a) == heim_data_get_length(b) && + memcmp(heim_data_get_ptr(a), heim_data_get_ptr(b), + heim_data_get_length(a)) == 0; + } + case HEIM_TID_NUMBER: + return heim_number_get_long(a) == heim_number_get_long(b); + case HEIM_TID_NULL: + case HEIM_TID_BOOL: + return heim_bool_val(a) == heim_bool_val(b); + default: + break; + } + return 0; +} diff --git a/third_party/heimdal/lib/base/log.c b/third_party/heimdal/lib/base/log.c index 24295b5adbc..1d79c7e45b9 100644 --- a/third_party/heimdal/lib/base/log.c +++ b/third_party/heimdal/lib/base/log.c @@ -1051,7 +1051,8 @@ heim_audit_trail(heim_svc_req_desc r, heim_error_code ret, const char *retname) break; default: /* Wish we had a com_err number->symbolic name function */ - (void) snprintf(retvalbuf, sizeof(retvalbuf), "UNKNOWN-%d", ret); + (void) snprintf(retvalbuf, sizeof(retvalbuf), "UNKNOWN-%d", + ret ? ret : r->error_code); retval = retvalbuf; break; } diff --git a/third_party/heimdal/lib/base/string.c b/third_party/heimdal/lib/base/string.c index f942447163d..5e79e00b18c 100644 --- a/third_party/heimdal/lib/base/string.c +++ b/third_party/heimdal/lib/base/string.c @@ -153,7 +153,8 @@ heim_string_create_with_bytes(const void *data, size_t len) s = _heim_alloc_object(&_heim_string_object, len + 1); if (s) { - memcpy(s, data, len); + if (len) + memcpy(s, data, len); ((char *)s)[len] = '\0'; } return s; @@ -238,7 +239,7 @@ heim_string_t __heim_string_constant(const char *_str) { static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER; - static heim_base_once_t once; + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; static heim_dict_t dict = NULL; heim_string_t s, s2; diff --git a/third_party/heimdal/lib/base/test_base.c b/third_party/heimdal/lib/base/test_base.c index be6c860e26b..6d0668663af 100644 --- a/third_party/heimdal/lib/base/test_base.c +++ b/third_party/heimdal/lib/base/test_base.c @@ -53,6 +53,7 @@ #include <sys/stat.h> #ifndef WIN32 #include <sys/file.h> +#include <locale.h> #endif #ifdef HAVE_IO_H #include <io.h> @@ -244,26 +245,318 @@ test_json(void) }; char *s; size_t i, k; - heim_object_t o, o2; + heim_object_t o, o2, o3; heim_string_t k1 = heim_string_create("k1"); o = heim_json_create("\"string\"", 10, 0, NULL); heim_assert(o != NULL, "string"); heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); heim_assert(strcmp("string", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* + * Test string escaping: + * + * - C-like must-escapes + * - ASCII control character must-escapes + * - surrogate pairs + * + * We test round-tripping. First we parse, then we serialize, then parse, + * then compare the second parse to the first for equality. + * + * We do compare serialized forms in spite of their not being canonical. + * That means that some changes to serialization can cause failures here. + */ + o = heim_json_create("\"" + "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */ + "\x1e" /* ASCII control character w/o C-like escape */ + "\\u00e1" /* á */ + "\\u07ff" + "\\u0801" + "\\u8001" + "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */ + "\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\b\f\n\r\t" + "\x1e" + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xA0\x81" + "\xe8\x80\x81" + "\xf0\x9d\x84\x9e", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001Eá߿ࠁ老\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create("\"" + "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */ + "\x1e" /* ASCII control character w/o C-like escape */ + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xa0\x81" + "\xE8\x80\x81" + "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */ + "\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\b\f\n\r\t" + "\x1e" + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xA0\x81" + "\xe8\x80\x81" + "\xf0\x9d\x84\x9e", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001Eá߿ࠁ老\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* + * Test HEIM_JSON_F_ESCAPE_NON_ASCII. + * + * Also test that we get escaped non-ASCII because we're in a not-UTF-8 + * locale, since we setlocale(LC_ALL, "C"), so we should escape non-ASCII + * by default. + */ + o = heim_json_create("\"" + "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */ + "\x1e" /* ASCII control character w/o C-like escape */ + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xa0\x81" + "\xE8\x80\x81" + "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */ + "\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\b\f\n\r\t" + "\x1e" + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xA0\x81" + "\xe8\x80\x81" + "\xf0\x9d\x84\x9e", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001E\\u00E1\\u07FF\\u0801\\u8001" + "\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + heim_release(o2); + o2 = heim_json_copy_serialize(o, HEIM_JSON_F_STRICT, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001E\\u00E1\\u07FF\\u0801\\u8001" + "\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test rejection of unescaped ASCII control characters */ + o = heim_json_create("\"\b\\f\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "strict parse accepted bad input"); + o = heim_json_create("\"\b\x1e\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "strict parse accepted bad input"); + + o = heim_json_create("\"\b\\f\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("\b\f", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\"", heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test bogus backslash escape */ + o = heim_json_create("\"" + "\\ " + "\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted"); + o = heim_json_create("\"" + "\\ " + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp(" ", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\" \"", heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test truncated surrogate encoding (bottom code unit) */ + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD834\\udd" + "\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted"); + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD834\\udd" + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\xe8\x80\x81" + "\\uD834\\udd", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"老\\\\uD834\\\\udd\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test truncated surrogate encodings (top code unit) */ + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD83" + "\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted"); + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD83" + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\xe8\x80\x81" + "\\uD83", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"老\\\\uD83\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); + /* + * Test handling of truncated UTF-8 multi-byte sequences. + */ + o = heim_json_create("\"" + "\xE8\x80" + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("\xe8\x80", + heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(o2 == NULL, "malformed string serialized"); + o2 = heim_json_copy_serialize(o, HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o3 == NULL, "malformed string accepted (not strict)"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(strcmp("\xe8\x80", + heim_string_get_utf8(o3)) == 0, "wrong string"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test handling of unescaped / embedded newline */ + o = heim_json_create("\"\n\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted (strict)"); + o = heim_json_create("\"\n\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("\n", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, HEIM_JSON_F_STRICT, NULL); + heim_assert(o2 != NULL, "string not serialized"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o3 != NULL, "string not accepted"); + heim_assert(strcmp("\n", heim_string_get_utf8(o3)) == 0, "wrong string"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test handling of embedded NULs (must decode as data, not string) */ + o = heim_json_create("\"\\u0000\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o != NULL, "string with NULs rejected"); + heim_assert(heim_get_tid(o) == heim_data_get_type_id(), "data-tid"); + heim_assert(heim_data_get_length(o) == 1, "wrong data length"); + heim_assert(((const char *)heim_data_get_ptr(o))[0] == '\0', + "wrong data NUL"); + o2 = heim_json_copy_serialize(o, 0, NULL); + heim_assert(o2 != NULL, "data not serialized"); + heim_release(o2); + heim_release(o); + + /* + * Note that the trailing ']' is not part of the JSON text (which is just a + * string). + */ o = heim_json_create(" \"foo\\\"bar\" ]", 10, 0, NULL); heim_assert(o != NULL, "string"); heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); heim_assert(strcmp("foo\"bar", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); o = heim_json_create(" { \"key\" : \"value\" }", 10, 0, NULL); heim_assert(o != NULL, "dict"); heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); + /* + * heim_json_eq() can't handle dicts with dicts as keys, so we don't check + * for round-tripping here + */ o = heim_json_create("{ { \"k1\" : \"s1\", \"k2\" : \"s2\" } : \"s3\", " "{ \"k3\" : \"s4\" } : -1 }", 10, 0, NULL); heim_assert(o != NULL, "dict"); @@ -281,6 +574,11 @@ test_json(void) o2 = heim_dict_copy_value(o, k1); heim_assert(heim_get_tid(o2) == heim_string_get_type_id(), "string-tid"); heim_release(o2); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); o = heim_json_create(" { \"k1\" : { \"k2\" : \"s2\" } }", 10, 0, NULL); @@ -289,6 +587,11 @@ test_json(void) o2 = heim_dict_copy_value(o, k1); heim_assert(heim_get_tid(o2) == heim_dict_get_type_id(), "dict-tid"); heim_release(o2); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); o = heim_json_create("{ \"k1\" : 1 }", 10, 0, NULL); @@ -297,26 +600,51 @@ test_json(void) o2 = heim_dict_copy_value(o, k1); heim_assert(heim_get_tid(o2) == heim_number_get_type_id(), "number-tid"); heim_release(o2); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); o = heim_json_create("-10", 10, 0, NULL); heim_assert(o != NULL, "number"); heim_assert(heim_get_tid(o) == heim_number_get_type_id(), "number-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); o = heim_json_create("99", 10, 0, NULL); heim_assert(o != NULL, "number"); heim_assert(heim_get_tid(o) == heim_number_get_type_id(), "number-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); o = heim_json_create(" [ 1 ]", 10, 0, NULL); heim_assert(o != NULL, "array"); heim_assert(heim_get_tid(o) == heim_array_get_type_id(), "array-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); o = heim_json_create(" [ -1 ]", 10, 0, NULL); heim_assert(o != NULL, "array"); heim_assert(heim_get_tid(o) == heim_array_get_type_id(), "array-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); for (i = 0; i < (sizeof (j) / sizeof (j[0])); i++) { @@ -325,6 +653,11 @@ test_json(void) fprintf(stderr, "Failed to parse this JSON: %s\n", j[i]); return 1; } + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); heim_release(o); /* Simple fuzz test */ for (k = strlen(j[i]) - 1; k > 0; k--) { @@ -945,6 +1278,11 @@ main(int argc, char **argv) { int res = 0; +#ifndef WIN32 + setlocale(LC_ALL, "C"); + heim_assert(!heim_locale_is_utf8(), "setlocale(LC_ALL, \"C\") failed?"); +#endif + res |= test_memory(); res |= test_mutex(); res |= test_rwlock(); diff --git a/third_party/heimdal/lib/base/version-script.map b/third_party/heimdal/lib/base/version-script.map index 928e8619995..9493ee69236 100644 --- a/third_party/heimdal/lib/base/version-script.map +++ b/third_party/heimdal/lib/base/version-script.map @@ -146,7 +146,9 @@ HEIMDAL_BASE_1.0 { heim_json_copy_serialize; heim_json_create; heim_json_create_with_bytes; + heim_json_eq; heim_load_plugins; + heim_locale_is_utf8; heim_log; heim_log_msg; _heim_make_permanent; diff --git a/third_party/heimdal/lib/gssapi/Makefile.am b/third_party/heimdal/lib/gssapi/Makefile.am index a69ebffb04e..3cb8437db28 100644 --- a/third_party/heimdal/lib/gssapi/Makefile.am +++ b/third_party/heimdal/lib/gssapi/Makefile.am @@ -264,10 +264,6 @@ dist_libgssapi_la_SOURCES = \ $(sanonsrc) nodist_libgssapi_la_SOURCES = \ - gkrb5_err.c \ - gkrb5_err.h \ - negoex_err.c \ - negoex_err.h \ $(BUILT_SOURCES) libgssapi_la_DEPENDENCIES = version-script.map @@ -333,7 +329,13 @@ $(test_context_OBJECTS): $(BUILTHEADERS) $(libgssapi_la_OBJECTS): $(srcdir)/version-script.map -BUILT_SOURCES = $(spnego_files) $(gssapi_files) +BUILT_SOURCES = \ + $(spnego_files) \ + $(gssapi_files) \ + gkrb5_err.c \ + gkrb5_err.h \ + negoex_err.c \ + negoex_err.h $(libgssapi_la_OBJECTS): gkrb5_err.h negoex_err.h gkrb5_err.h: $(srcdir)/krb5/gkrb5_err.et diff --git a/third_party/heimdal/lib/gssapi/gss-token.c b/third_party/heimdal/lib/gssapi/gss-token.c index 844fa4d3820..f3f90521c3b 100644 --- a/third_party/heimdal/lib/gssapi/gss-token.c +++ b/third_party/heimdal/lib/gssapi/gss-token.c @@ -235,10 +235,9 @@ write_and_free_token(gss_buffer_t out, int negotiate) printf("\n"); if (len < inc) inc = len; - ret = rk_base64_encode(p, inc, &outstr); - if (ret < 0) { + if (rk_base64_encode(p, inc, &outstr) < 0) { fprintf(stderr, "Out of memory.\n"); - ret = 1; + ret = errno; goto bail; } ret = 0; @@ -247,6 +246,7 @@ write_and_free_token(gss_buffer_t out, int negotiate) p += inc; len -= inc; } while (len > 0); + ret = 0; bail: gss_release_buffer(&min, out); diff --git a/third_party/heimdal/lib/gssapi/krb5/8003.c b/third_party/heimdal/lib/gssapi/krb5/8003.c index 3e213363534..bf7da11c754 100644 --- a/third_party/heimdal/lib/gssapi/krb5/8003.c +++ b/third_party/heimdal/lib/gssapi/krb5/8003.c @@ -259,7 +259,7 @@ _gsskrb5_verify_8003_checksum( } if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS - && (memcmp(p, zeros, sizeof(zeros)) != 0 || client_asserted_cb)) { + && (ct_memcmp(p, zeros, sizeof(zeros)) != 0 || client_asserted_cb)) { if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) { *minor_status = 0; return GSS_S_BAD_BINDINGS; 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 62b26ed7eb9..a705d03a875 100644 --- a/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c +++ b/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c @@ -932,7 +932,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context time_rec); if (ret != GSS_S_COMPLETE) break; - fallthrough; + HEIM_FALLTHROUGH; case INITIATOR_RESTART: ret = init_auth_restart(minor_status, cred, diff --git a/third_party/heimdal/lib/gssapi/netlogon/crypto.c b/third_party/heimdal/lib/gssapi/netlogon/crypto.c index 0fc8f019d64..6147eec55e0 100644 --- a/third_party/heimdal/lib/gssapi/netlogon/crypto.c +++ b/third_party/heimdal/lib/gssapi/netlogon/crypto.c @@ -588,7 +588,7 @@ _netlogon_unwrap_iov(OM_uint32 *minor_status, /* [MS-NRPC] 3.3.4.2.2.10: verify signature */ _netlogon_digest(ctx, sig, iov, iov_count, checksum); - if (memcmp(sig->Checksum, checksum, _netlogon_checksum_length(sig)) != 0) + if (ct_memcmp(sig->Checksum, checksum, _netlogon_checksum_length(sig)) != 0) return GSS_S_BAD_SIG; HEIMDAL_MUTEX_lock(&ctx->Mutex); diff --git a/third_party/heimdal/lib/gssapi/ntlm/crypto.c b/third_party/heimdal/lib/gssapi/ntlm/crypto.c index efa71d911dc..d1a115ff8e3 100644 --- a/third_party/heimdal/lib/gssapi/ntlm/crypto.c +++ b/third_party/heimdal/lib/gssapi/ntlm/crypto.c @@ -230,7 +230,7 @@ v2_verify_message(gss_buffer_t in, if (ret) return ret; - if (memcmp(checksum, out, 16) != 0) + if (ct_memcmp(checksum, out, 16) != 0) return GSS_S_BAD_MIC; return GSS_S_COMPLETE; diff --git a/third_party/heimdal/lib/hcrypto/des.c b/third_party/heimdal/lib/hcrypto/des.c index ac174180fb9..32f87b47137 100644 --- a/third_party/heimdal/lib/hcrypto/des.c +++ b/third_party/heimdal/lib/hcrypto/des.c @@ -851,7 +851,7 @@ DES_string_to_key(const char *str, DES_cblock *key) k[7] ^= 0xF0; DES_set_key(key, &ks); DES_cbc_cksum(s, key, len, &ks, key); - memset(&ks, 0, sizeof(ks)); + memset_s(&ks, sizeof(ks), 0, sizeof(ks)); DES_set_odd_parity(key); if (DES_is_weak_key(key)) k[7] ^= 0xF0; diff --git a/third_party/heimdal/lib/hcrypto/dh.c b/third_party/heimdal/lib/hcrypto/dh.c index 5d2d214f752..b3b25e5186d 100644 --- a/third_party/heimdal/lib/hcrypto/dh.c +++ b/third_party/heimdal/lib/hcrypto/dh.c @@ -145,7 +145,7 @@ DH_free(DH *dh) free_if(dh->counter); #undef free_if - memset(dh, 0, sizeof(*dh)); + memset_s(dh, sizeof(*dh), 0, sizeof(*dh)); free(dh); } diff --git a/third_party/heimdal/lib/hcrypto/dsa.c b/third_party/heimdal/lib/hcrypto/dsa.c index bbb34601c31..eac0ae6498e 100644 --- a/third_party/heimdal/lib/hcrypto/dsa.c +++ b/third_party/heimdal/lib/hcrypto/dsa.c @@ -70,7 +70,7 @@ DSA_free(DSA *dsa) free_if(dsa->r); #undef free_if - memset(dsa, 0, sizeof(*dsa)); + memset_s(dsa, sizeof(*dsa), 0, sizeof(*dsa)); free(dsa); } diff --git a/third_party/heimdal/lib/hcrypto/engine.c b/third_party/heimdal/lib/hcrypto/engine.c index 3dae960fd0c..6a79b7c9907 100644 --- a/third_party/heimdal/lib/hcrypto/engine.c +++ b/third_party/heimdal/lib/hcrypto/engine.c @@ -87,7 +87,7 @@ ENGINE_finish(ENGINE *engine) if (engine->dso_handle) dlclose(engine->dso_handle); - memset(engine, 0, sizeof(*engine)); + memset_s(engine, sizeof(*engine), 0, sizeof(*engine)); engine->references = -1; diff --git a/third_party/heimdal/lib/hcrypto/evp-openssl.c b/third_party/heimdal/lib/hcrypto/evp-openssl.c index a651184c6ea..ca02862bf68 100644 --- a/third_party/heimdal/lib/hcrypto/evp-openssl.c +++ b/third_party/heimdal/lib/hcrypto/evp-openssl.c @@ -204,7 +204,7 @@ get_EVP_CIPHER_once_cb(void *d) */ ossl_evp = EVP_get_cipherbynid(arg->nid); if (ossl_evp == NULL) { - (void) memset(hc_evp, 0, sizeof(*hc_evp)); + (void) memset_s(hc_evp, sizeof(*hc_evp), 0, sizeof(*hc_evp)); #if HCRYPTO_FALLBACK *arg->hc_memoizep = arg->fallback; #endif @@ -348,7 +348,7 @@ get_EVP_MD_once_cb(void *d) *arg->ossl_memoizep = ossl_evp = EVP_get_digestbynid(arg->nid); if (ossl_evp == NULL) { - (void) memset(hc_evp, 0, sizeof(*hc_evp)); + (void) memset_s(hc_evp, sizeof(*hc_evp), 0, sizeof(*hc_evp)); #if HCRYPTO_FALLBACK *arg->hc_memoizep = arg->fallback; #endif diff --git a/third_party/heimdal/lib/hcrypto/evp.c b/third_party/heimdal/lib/hcrypto/evp.c index 9cced4c536c..320e85283f7 100644 --- a/third_party/heimdal/lib/hcrypto/evp.c +++ b/third_party/heimdal/lib/hcrypto/evp.c @@ -189,12 +189,12 @@ EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) HC_DEPRECATED if (!ret) return ret; } else if (ctx->md) { - memset(ctx->ptr, 0, ctx->md->ctx_size); + memset_s(ctx->ptr, ctx->md->ctx_size, 0, ctx->md->ctx_size); } ctx->md = NULL; ctx->engine = NULL; free(ctx->ptr); - memset(ctx, 0, sizeof(*ctx)); + memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx)); return 1; } @@ -607,7 +607,7 @@ EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) } if (c->cipher_data) { if (c->cipher) - memset(c->cipher_data, 0, c->cipher->ctx_size); + memset_s(c->cipher_data, c->cipher->ctx_size, 0, c->cipher->ctx_size); free(c->cipher_data); c->cipher_data = NULL; } @@ -905,7 +905,7 @@ EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, void *out, int *outlen, /* fill in local buffer and encrypt */ memcpy(ctx->buf + ctx->buf_len, in, left); ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); - memset(ctx->buf, 0, blocksize); + memset_s(ctx->buf, blocksize, 0, blocksize); if (ret != 1) return ret; @@ -966,7 +966,7 @@ EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, void *out, int *outlen) /* zero fill local buffer */ memset(ctx->buf + ctx->buf_len, 0, left); ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); - memset(ctx->buf, 0, blocksize); + memset_s(ctx->buf, blocksize, 0, blocksize); if (ret != 1) return ret; diff --git a/third_party/heimdal/lib/hcrypto/hmac.c b/third_party/heimdal/lib/hcrypto/hmac.c index 6b387ae90dc..adccee76b26 100644 --- a/third_party/heimdal/lib/hcrypto/hmac.c +++ b/third_party/heimdal/lib/hcrypto/hmac.c @@ -46,17 +46,17 @@ void HMAC_CTX_cleanup(HMAC_CTX *ctx) { if (ctx->buf) { - memset(ctx->buf, 0, ctx->key_length); + memset_s(ctx->buf, ctx->key_length, 0, ctx->key_length); free(ctx->buf); ctx->buf = NULL; } if (ctx->opad) { - memset(ctx->opad, 0, EVP_MD_block_size(ctx->md)); + memset_s(ctx->opad, EVP_MD_block_size(ctx->md), 0, EVP_MD_block_size(ctx->md)); free(ctx->opad); ctx->opad = NULL; } if (ctx->ipad) { - memset(ctx->ipad, 0, EVP_MD_block_size(ctx->md)); + memset_s(ctx->ipad, EVP_MD_block_size(ctx->md), 0, EVP_MD_block_size(ctx->md)); free(ctx->ipad); ctx->ipad = NULL; } diff --git a/third_party/heimdal/lib/hcrypto/md2.c b/third_party/heimdal/lib/hcrypto/md2.c index da41e6d83ee..0170d416a1c 100644 --- a/third_party/heimdal/lib/hcrypto/md2.c +++ b/third_party/heimdal/lib/hcrypto/md2.c @@ -133,6 +133,6 @@ MD2_Final (void *res, struct md2 *m) MD2_Update(m, pad, 16); memcpy(res, m->state, MD2_DIGEST_LENGTH); - memset(m, 0, sizeof(*m)); + memset_s(m, sizeof(*m), 0, sizeof(*m)); return 1; } diff --git a/third_party/heimdal/lib/hcrypto/passwd_dlg.c b/third_party/heimdal/lib/hcrypto/passwd_dlg.c index 037fa7436a4..30721160a2a 100644 --- a/third_party/heimdal/lib/hcrypto/passwd_dlg.c +++ b/third_party/heimdal/lib/hcrypto/passwd_dlg.c @@ -77,11 +77,11 @@ pwd_dialog(char *buf, int size) { case IDOK: strlcpy(buf, passwd, size); - memset (passwd, 0, sizeof(passwd)); + memset_s (passwd, sizeof(passwd), 0, sizeof(passwd)); return 0; case IDCANCEL: default: - memset (passwd, 0, sizeof(passwd)); + memset_s (passwd, sizeof(passwd), 0, sizeof(passwd)); return 1; } } diff --git a/third_party/heimdal/lib/hcrypto/rand-fortuna.c b/third_party/heimdal/lib/hcrypto/rand-fortuna.c index 313b86f83cf..74ba12396fd 100644 --- a/third_party/heimdal/lib/hcrypto/rand-fortuna.c +++ b/third_party/heimdal/lib/hcrypto/rand-fortuna.c @@ -336,7 +336,7 @@ add_entropy(FState * st, const unsigned char *data, unsigned len) st->pool0_bytes += len; memset_s(hash, sizeof(hash), 0, sizeof(hash)); - memset_s(&md, sizeof(hash), 0, sizeof(md)); + memset_s(&md, sizeof(md), 0, sizeof(md)); } /* diff --git a/third_party/heimdal/lib/hcrypto/rc2.c b/third_party/heimdal/lib/hcrypto/rc2.c index 02b684cbd4b..53d32cf0417 100644 --- a/third_party/heimdal/lib/hcrypto/rc2.c +++ b/third_party/heimdal/lib/hcrypto/rc2.c @@ -105,7 +105,7 @@ RC2_set_key(RC2_KEY *key, int len, const unsigned char *data, int bits) for (j = 0; j < 64; j++) key->data[j] = k[(j * 2) + 0] | (k[(j * 2) + 1] << 8); - memset(k, 0, sizeof(k)); + memset_s(k, sizeof(k), 0, sizeof(k)); } #define ROT16L(w,n) ((w<<n)|(w>>(16-n))) diff --git a/third_party/heimdal/lib/hcrypto/rsa.c b/third_party/heimdal/lib/hcrypto/rsa.c index 6172b25413f..31470d0069a 100644 --- a/third_party/heimdal/lib/hcrypto/rsa.c +++ b/third_party/heimdal/lib/hcrypto/rsa.c @@ -160,7 +160,7 @@ RSA_free(RSA *rsa) free_if(rsa->iqmp); #undef free_if - memset(rsa, 0, sizeof(*rsa)); + memset_s(rsa, sizeof(*rsa), 0, sizeof(*rsa)); free(rsa); } @@ -426,7 +426,7 @@ RSA_verify(int type, const unsigned char *from, unsigned int flen, return -4; } - if (flen != di.digest.length || memcmp(di.digest.data, from, flen) != 0) { + if (flen != di.digest.length || ct_memcmp(di.digest.data, from, flen) != 0) { free_DigestInfo(&di); return -5; } diff --git a/third_party/heimdal/lib/hdb/Makefile.am b/third_party/heimdal/lib/hdb/Makefile.am index 89ab15d9d3e..4a559953243 100644 --- a/third_party/heimdal/lib/hdb/Makefile.am +++ b/third_party/heimdal/lib/hdb/Makefile.am @@ -17,7 +17,9 @@ endif BUILT_SOURCES = \ $(gen_files_hdb) \ hdb_err.c \ - hdb_err.h + hdb_err.h \ + $(srcdir)/hdb-protos.h \ + $(srcdir)/hdb-private.h gen_files_hdb = \ asn1_Event.c \ diff --git a/third_party/heimdal/lib/hdb/common.c b/third_party/heimdal/lib/hdb/common.c index a92cc1372db..56e582abaa8 100644 --- a/third_party/heimdal/lib/hdb/common.c +++ b/third_party/heimdal/lib/hdb/common.c @@ -181,6 +181,7 @@ fetch_entry_or_alias(krb5_context context, ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL); if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) { *entry = eoa.u.entry; + entry->aliased = 0; } else if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias) { krb5_data_free(&key); ret = hdb_principal2key(context, eoa.u.alias.principal, &key); @@ -192,6 +193,7 @@ fetch_entry_or_alias(krb5_context context, /* No alias chaining */ ret = hdb_value2entry(context, &value, entry); krb5_free_principal(context, eoa.u.alias.principal); + entry->aliased = 1; } else if (ret == 0) ret = ENOTSUP; if (ret == 0 && enterprise_principal) { @@ -203,6 +205,7 @@ fetch_entry_or_alias(krb5_context context, entry->flags.force_canonicalize = 1; } +#if 0 /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */ if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias && (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) { @@ -211,6 +214,7 @@ fetch_entry_or_alias(krb5_context context, free_HDB_entry(entry); ret = HDB_ERR_NOENTRY; } +#endif krb5_free_principal(context, enterprise_principal); krb5_data_free(&value); @@ -219,11 +223,58 @@ fetch_entry_or_alias(krb5_context context, return ret; } +/* + * We have only one type of aliases in our HDB entries, but we really need two: + * hard and soft. + * + * Hard aliases should be treated as if they were distinct principals with the + * same keys. + * + * Soft aliases should be treated as configuration to issue referrals, and they + * can only result in referrals to other realms. + * + * Rather than add a type of aliases, we'll use a convention where the form of + * the target of the alias indicates whether the alias is hard or soft. + * + * TODO We could also use an attribute of the aliased entry. + */ +static int +is_soft_alias_p(krb5_context context, + krb5_const_principal principal, + unsigned int flags, + hdb_entry *h) +{ + /* Target is a WELLKNOWN/REFERRALS/TARGET/... -> soft alias */ + if (krb5_principal_get_num_comp(context, h->principal) >= 3 && + strcmp(krb5_principal_get_comp_string(context, h->principal, 0), + KRB5_WELLKNOWN_NAME) == 0 && + strcmp(krb5_principal_get_comp_string(context, h->principal, 1), + "REFERRALS") == 0 && + strcmp(krb5_principal_get_comp_string(context, h->principal, 2), + "TARGET") == 0) + return 1; + + /* + * Pre-8.0 we had only soft aliases for a while, and one site used aliases + * of referrals-targetNN@TARGET-REALM. + */ + if (krb5_principal_get_num_comp(context, h->principal) == 1 && + strncmp("referrals-target", + krb5_principal_get_comp_string(context, h->principal, 0), + sizeof("referrals-target") - 1) == 0) + return 1; + + /* All other cases are hard aliases */ + return 0; +} + krb5_error_code _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, krb5_kvno kvno, hdb_entry *entry) { krb5_error_code ret; + int soft_aliased = 0; + int same_realm; ret = fetch_entry_or_alias(context, db, principal, flags, entry); if (ret) @@ -278,7 +329,54 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, } } - return 0; + if (!entry->aliased) + return 0; + + soft_aliased = is_soft_alias_p(context, principal, flags, entry); + + /* Never return HDB_ERR_WRONG_REALM to kadm5 or other non-KDC callers */ + if ((flags & HDB_F_ADMIN_DATA)) + return 0; + + same_realm = krb5_realm_compare(context, principal, entry->principal); + + if (entry->aliased && !soft_aliased) { + /* + * This is a hard alias. We'll make the entry's name be the same as + * the alias. + * + * Except, we allow for disabling this for same-realm aliases, mainly + * for our tests. + */ + if (same_realm && + krb5_config_get_bool_default(context, NULL, FALSE, "hdb", + "same_realm_aliases_are_soft", NULL)) + return 0; + + /* EPNs are always soft */ + if (principal->name.name_type != KRB5_NT_ENTERPRISE_PRINCIPAL) { + krb5_free_principal(context, entry->principal); + ret = krb5_copy_principal(context, principal, &entry->principal); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + } + return 0; + } + + /* Same realm -> not a referral, therefore this is a hard alias */ + if (same_realm) { + if (soft_aliased) { + /* Soft alias to the same realm?! No. */ + hdb_free_entry(context, db, entry); + return HDB_ERR_NOENTRY; + } + return 0; + } + + /* Not same realm && not hard alias */ + return HDB_ERR_WRONG_REALM; } static krb5_error_code @@ -313,6 +411,8 @@ hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key) if (code == 0) { code = db->hdb__del(context, db, akey); krb5_data_free(&akey); + if (code == HDB_ERR_NOENTRY) + code = 0; } if (code) { free_HDB_entry(&oldentry); @@ -348,6 +448,12 @@ hdb_add_aliases(krb5_context context, HDB *db, if (code == 0) { code = db->hdb__put(context, db, flags, key, value); krb5_data_free(&key); + if (code == HDB_ERR_EXISTS) + /* + * Assuming hdb_check_aliases() was called, this must be a + * duplicate in the alias list. + */ + code = 0; } krb5_data_free(&value); if (code) @@ -750,6 +856,10 @@ derive_keys_for_kr(krb5_context context, * (t - krp->epoch < 0) is better than (krp->epoch < t), making us more * tolerant of signed 32-bit time_t here near 2038. Of course, we have * signed 32-bit time_t dragons elsewhere. + * + * We don't need to check for n == 0 && rotation_period_offset < 0 because + * only derive_keys_for_current_kr() calls us with non-zero rotation period + * offsets, and it will never call us in that case. */ if (t - krp->epoch < 0) return 0; /* This KR is not relevant yet */ @@ -758,6 +868,37 @@ derive_keys_for_kr(krb5_context context, set_time = krp->epoch + krp->period * n; kvno = krp->base_kvno + n; + /* + * Since this principal is virtual, or has virtual keys, we're going to + * derive a "password expiration time" for it in order to help httpkadmind + * and other tools figure out when to request keys again. + * + * The kadm5 representation of principals does not include the set_time of + * keys/keysets, so we can't have httpkadmind derive a Cache-Control from + * that without adding yet another "TL data". Since adding TL data is a + * huge pain, we'll just use the `pw_end' field of `HDB_entry' to + * communicate when this principal's keys will change next. + */ + if (h->pw_end[0] == 0) { + KerberosTime used = (t - krp->epoch) % krp->period; + KerberosTime left = krp->period - used; + + /* + * If `h->pw_end[0]' == 0 then this must be the current period of the + * current KR we're deriving keys for. See upstairs. + * + * If there's more than a quarter of this time period left, then we'll + * set `h->pw_end[0]' to one quarter before the end of this time + * period. Else we'll set it to 1/4 after (we'll be including the next + * set of derived keys, so there's no harm in waiting that long to + * refetch). + */ + if (left > krp->period >> 2) + h->pw_end[0] = set_time + krp->period - (krp->period >> 2); + else + h->pw_end[0] = set_time + krp->period + (krp->period >> 2); + } + /* * Do not waste cycles computing keys not wanted or needed. @@ -1092,6 +1233,11 @@ derive_keys(krb5_context context, "because last key rotation period " "marks deletion", p); + /* See `derive_keys_for_kr()' */ + if (h->pw_end == NULL && + (h->pw_end = calloc(1, sizeof(h->pw_end[0]))) == NULL) + ret = krb5_enomem(context); + /* * Derive and set in `h' its current kvno and current keys. * @@ -1140,6 +1286,12 @@ derive_keys(krb5_context context, if (ret == 0 && *h->max_life > kr.val[current_kr].period >> 1) *h->max_life = kr.val[current_kr].period >> 1; + if (ret == 0 && h->pw_end[0] == 0) + /* Shouldn't happen */ + h->pw_end[0] = kr.val[current_kr].epoch + + kr.val[current_kr].period * + (1 + (t - kr.val[current_kr].epoch) / kr.val[current_kr].period); + free_HDB_Ext_KeyRotation(&kr); free_HDB_Ext_KeySet(&base_keys); free(p); @@ -1506,6 +1658,10 @@ fetch_it(krb5_context context, * of labels. */ ret = db->hdb_fetch_kvno(context, db, tmpprinc, flags, kvno, ent); + if (ret == 0 && nsprinc && ent->flags.invalid) { + free_HDB_entry(ent); + ret = HDB_ERR_NOENTRY; + } if (ret != HDB_ERR_NOENTRY || hdots == 0 || hdots < mindots || !tmp || !do_search) break; @@ -1561,7 +1717,9 @@ fetch_it(krb5_context context, * If unencrypted keys were requested, derive them. There may not be any * key derivation to do, but that's decided in derive_keys(). */ - if (ret == 0) { + if (ret == 0 || ret == HDB_ERR_WRONG_REALM) { + krb5_error_code save_ret = ret; + /* Fix the principal name if namespaced */ ret = fix_princ_name(context, princ, nsprinc, ent); @@ -1572,6 +1730,8 @@ fetch_it(krb5_context context, /* Pick the best kvno for this principal at the given time */ if (ret == 0) ret = pick_kvno(context, db, flags, t, kvno, ent); + if (ret == 0) + ret = save_ret; } out: @@ -1603,7 +1763,7 @@ out: * @param kvno Key version number (use zero to mean "current") * @param h Output HDB entry * - * @return Zero on success, an error code otherwise. + * @return Zero or HDB_ERR_WRONG_REALM on success, an error code otherwise. */ krb5_error_code hdb_fetch_kvno(krb5_context context, @@ -1615,24 +1775,25 @@ hdb_fetch_kvno(krb5_context context, krb5uint32 kvno, hdb_entry *h) { - krb5_error_code ret = HDB_ERR_NOENTRY; + krb5_error_code ret; + krb5_timestamp now; + + krb5_timeofday(context, &now); flags |= kvno ? HDB_F_KVNO_SPECIFIED : 0; /* XXX is this needed */ - if (t == 0) - krb5_timeofday(context, &t); - ret = fetch_it(context, db, principal, flags, t, etype, kvno, h); + ret = fetch_it(context, db, principal, flags, t ? t : now, etype, kvno, h); + if (ret == 0 && t == 0 && h->flags.virtual && + h->pw_end && h->pw_end[0] < now) { + /* + * This shouldn't happen! + * + * Do not allow h->pw_end[0] to be in the past for virtual principals + * outside testing. This is just to prevent the AS/TGS from failing. + */ + h->pw_end[0] = now + 3600; + } if (ret == HDB_ERR_NOENTRY) krb5_set_error_message(context, ret, "no such entry found in hdb"); - - /* - * This check is to support aliases in HDB; the force_canonicalize - * check is to allow HDB backends to support realm name canon - * independently of principal aliases (used by Samba). - */ - if (ret == 0 && !(flags & HDB_F_ADMIN_DATA) && - !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/hdb-mdb.c b/third_party/heimdal/lib/hdb/hdb-mdb.c index 6aa5201eb8a..dd1f27453d5 100644 --- a/third_party/heimdal/lib/hdb/hdb-mdb.c +++ b/third_party/heimdal/lib/hdb/hdb-mdb.c @@ -146,7 +146,7 @@ my_mdb_env_create_and_open(krb5_context context, { struct keep_it_open *p, *n; MDB_txn *txn = NULL; - unsigned int flags = MDB_NOSUBDIR; + unsigned int flags = MDB_NOSUBDIR | MDB_NOTLS; struct stat st; size_t mapsize = 0; int max_readers; diff --git a/third_party/heimdal/lib/hdb/hdb.asn1 b/third_party/heimdal/lib/hdb/hdb.asn1 index 9eb96be73d0..abc75f742cc 100644 --- a/third_party/heimdal/lib/hdb/hdb.asn1 +++ b/third_party/heimdal/lib/hdb/hdb.asn1 @@ -59,6 +59,8 @@ HDBFlags ::= BIT STRING { force-canonicalize(30), -- force the KDC to return the canonical -- principal irrespective of the setting -- of the canonicalize KDC option + -- (principals cannot have this flag + -- set when stored into the HDB) do-not-store(31) -- Not to be modified and stored in HDB } diff --git a/third_party/heimdal/lib/hdb/hdb.opt b/third_party/heimdal/lib/hdb/hdb.opt index 626f8c7b07a..a96eb632e52 100644 --- a/third_party/heimdal/lib/hdb/hdb.opt +++ b/third_party/heimdal/lib/hdb/hdb.opt @@ -3,3 +3,7 @@ --sequence=HDB-Ext-KeySet --sequence=Keys --decorate=HDB_entry:void:context?::: +# The `aliased` field is for indicating whether a name used in an HDB +# lookup was an alias. This could be useful to applications when hard +# aliasing is implemented in an HDB backend, as it should be. +--decorate=HDB_entry:int:aliased::: diff --git a/third_party/heimdal/lib/hdb/keytab.c b/third_party/heimdal/lib/hdb/keytab.c index b1aa0207c97..df16cb782fa 100644 --- a/third_party/heimdal/lib/hdb/keytab.c +++ b/third_party/heimdal/lib/hdb/keytab.c @@ -223,10 +223,9 @@ hdb_get_entry(krb5_context context, HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, 0, 0, kvno, &ent); - if(ret == HDB_ERR_NOENTRY) { + if (ret == HDB_ERR_WRONG_REALM || ret == HDB_ERR_NOENTRY) ret = KRB5_KT_NOTFOUND; - goto out; - }else if(ret) + if (ret) goto out; if(kvno && (krb5_kvno)ent.kvno != kvno) { diff --git a/third_party/heimdal/lib/hx509/cert.c b/third_party/heimdal/lib/hx509/cert.c index 33805b8ed1a..3dda886edc5 100644 --- a/third_party/heimdal/lib/hx509/cert.c +++ b/third_party/heimdal/lib/hx509/cert.c @@ -2443,7 +2443,7 @@ hx509_verify_path(hx509_context context, type = EE_CERT; } } - fallthrough; + HEIM_FALLTHROUGH; case EE_CERT: /* * If there where any proxy certificates in the chain diff --git a/third_party/heimdal/lib/hx509/cms.c b/third_party/heimdal/lib/hx509/cms.c index d2728a38c2f..c770b813262 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; + HEIM_FALLTHROUGH; case CMS_ID_NAME: { hx509_name name; diff --git a/third_party/heimdal/lib/hx509/file.c b/third_party/heimdal/lib/hx509/file.c index a22f6252cfa..e1fbe7c0688 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; + HEIM_FALLTHROUGH; case INHEADER: if (buf[0] == '\0') { where = INDATA; diff --git a/third_party/heimdal/lib/hx509/hxtool.1 b/third_party/heimdal/lib/hx509/hxtool.1 new file mode 100644 index 00000000000..377500784ec --- /dev/null +++ b/third_party/heimdal/lib/hx509/hxtool.1 @@ -0,0 +1,207 @@ +.\" Copyright (c) 2022 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 22, 2022 +.Dt HXTOOL 1 +.Os HEIMDAL +.Sh NAME +.Nm hxtool +.Nd PKIX command-line utility +.Sh SYNOPSIS +.Nm +.Bk -words +.Oo Fl Fl version Oc +.Oo Fl Fl help Oc +.Op Ar sub-command +.Ek +.Sh DESCRIPTION +.Nm +is a utility for making certificate sigining requests (CSRs), +displaying CSRs, signing certificates, etc. +are given, then the value will be parsed and displayed using just +the self-describing nature of DER. +.Pp +All sub-commands have their own help message, shown when invoked +with the +.Fl Fl help +or +.Fl h +option. +.Pp +Supported commands: +.Bl -tag -width Ds -offset indent +.It help +.It list-oids +.It verify +.It print +.It validate +.It certificate-copy, cc +.It ocsp-fetch +.It ocsp-verify +.It ocsp-print +.It revoke-print +.It generate-key +.It request-create +.It request-print +.It query +.It info +.It random-data +.It crypto-available +.It crypto-select +.It hex +.It certificate-sign, cert-sign, issue-certificate, ca +.It crl-sign +.El +Other sub-commands reported by the +.Nm help +sub-command are not stable or fully supported at this time. +.Sh CERTIFICATE STORES +Stores of certificates and/or keys have string names that can be +used with +.Nm 's +commands. +Sub-commands use these certificate store names to refer to files +and tokens where keys and/or certificates are to be found or +written. +For example, +.Sq FILE:/path/to/some/file . +.Pp +Use the +.Nm certificate-copy +command to copy certificates from one store to another. +This is useful for, e.g., converting DER files to PEM or +vice-versa. +.Pp +Heimdal supports a variety of certificate and key store types: +.Bl -tag -width Ds -offset indent +.It PEM-FILE:/path +If writing, PEM will be written. +If reading, PEM will be expected. +.It DER-FILE:/path +If writing, DER will be written. +If reading, DER will be expected. +.It FILE:/path +If writing, PEM will be written. +If reading, PEM or DER will be detected. +.It PKCS12:/path +Barely supported at this time. +.It DIR:/path +OpenSSL-style hashed directory of trust anchors. +.It MEMORY:name +An in-memory only store, usually never used in +.NM 's +commands. +.It KEYCHAIN:system-anchors +On OS X this refers to the system's trust anchors. +.It KEYCHAIN:FILE:/path +On OS X this refers to an OS X keychain at the given path. +.It NULL: +An empty store. +.It PKCS11:/path/to/shared/object,slot=NUMBER +Loads the given PKCS#11 provider object and uses the token at the +given slot number. +.El +.Sh CERTIFICATES +You can validate a certificate with the +.Nm validate +sub-command, or verify a certificate and its certification path +with the +.Nm verify +sub-command. +.Pp +You can display a certificate using the +.Nm print +sub-command: +.Pp +.Nm print +.Oo options Oc +.Ar STORE +.Pp +Options: +.Bl -tag -width Ds -offset indent +.Op Fl Fl content +.Op Fl Fl info +.Op Fl Fl never-fail +.Op Fl Fl pass=password +.Op Fl Fl raw-json +.El +.Pp +The +.Fl Fl pass=password +option is for PKCS#12 and PKCS#11 stores, and if needed and not +given, will be prompted for. +Note that it's not secure to pass passwords as command-line +arguments on multi-tenant systems. +.Pp +The +.Fl Fl raw-json +option prints the certificate(s) in the given +.Ar STORE +as a JSON dump of their DER using an experimental (i.e., +unstable) schema. +.Sh KEYS +The +.Nm generate-key +sub-command will generate a key. +.Sh CERTIFICATE SIGNING REQUESTS +The +.Nm request-create +sub-command will create a CSR. +The +.Nm request-print +sub-command will display a CSR. +.Sh CERTIFICATE ISSUANCE / CERTIFICATION AUTHORITY +The +.Nm certificate-sign +sub-command will issue a certificate. +See its usage message. +.Sh ONLINE CERTIFICATE STATUS PROTOCOL +The +.Nm ocsp-fetch +sub-command will fetch OCSP Responses for the given +certificates. +.Pp +The +.Nm ocsp-verify +sub-command will verify OCSP Responses. +.Pp +The +.Nm ocsp-print +sub-command will display OCSP Responses. +.Sh CERTIFICATE REVOCATION LIST +The +.Nm crl-sign +sub-command will add certificates to a certificate revocation +list. +.Sh SEE ALSO +.Xr openssl 1 diff --git a/third_party/heimdal/lib/hx509/hxtool.c b/third_party/heimdal/lib/hx509/hxtool.c index 1bcfdfa44e9..aa9e279c81c 100644 --- a/third_party/heimdal/lib/hx509/hxtool.c +++ b/third_party/heimdal/lib/hx509/hxtool.c @@ -2076,39 +2076,33 @@ hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv) } if (opt->generate_key_string) { - struct hx509_generate_private_context *keyctx; + /* + * Note that we used to set isCA in the key gen context. Now that we + * use get_key() we no longer set isCA in the key gen context. But + * nothing uses that field of the key gen context. + */ + get_key(opt->certificate_private_key_string, + opt->generate_key_string, + opt->key_bits_integer, + &cert_key); - ret = _hx509_generate_private_key_init(context, - &asn1_oid_id_pkcs1_rsaEncryption, - &keyctx); + ret = hx509_private_key2SPKI(context, cert_key, &spki); if (ret) - hx509_err(context, 1, ret, "generate private key"); - - if (opt->issue_ca_flag) - _hx509_generate_private_key_is_ca(context, keyctx); - - if (opt->key_bits_integer) - _hx509_generate_private_key_bits(context, keyctx, - opt->key_bits_integer); + errx(1, "hx509_private_key2SPKI: %d\n", ret); - ret = _hx509_generate_private_key(context, keyctx, - &cert_key); - _hx509_generate_private_key_free(&keyctx); + if (opt->self_signed_flag) + private_key = cert_key; + } else if (opt->certificate_private_key_string) { + ret = read_private_key(opt->certificate_private_key_string, &cert_key); if (ret) - hx509_err(context, 1, ret, "generate private key"); + err(1, "read_private_key for certificate"); ret = hx509_private_key2SPKI(context, cert_key, &spki); if (ret) errx(1, "hx509_private_key2SPKI: %d\n", ret); - if (opt->self_signed_flag) - private_key = cert_key; - } - - if (opt->certificate_private_key_string) { - ret = read_private_key(opt->certificate_private_key_string, &cert_key); - if (ret) - err(1, "read_private_key for certificate"); + if (opt->self_signed_flag) + private_key = cert_key; } if (opt->subject_string) { @@ -2319,7 +2313,31 @@ hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv) hx509_err(context, 1, ret, "hx509_ca_sign"); } - if (cert_key) { + /* Copy the private key to the output store, maybe */ + if (cert_key && opt->generate_key_string && + !opt->certificate_private_key_string) { + /* + * Yes: because we're generating the key and --certificate-private-key + * was not given. + */ + ret = _hx509_cert_assign_key(cert, cert_key); + if (ret) + hx509_err(context, 1, ret, "_hx509_cert_assign_key"); + } else if (opt->certificate_private_key_string && opt->certificate_string && + strcmp(opt->certificate_private_key_string, + opt->certificate_string) == 0) { + /* + * Yes: because we're re-writing the store whence the private key. We + * would lose the key otherwise. + */ + ret = _hx509_cert_assign_key(cert, cert_key); + if (ret) + hx509_err(context, 1, ret, "_hx509_cert_assign_key"); + } else if (opt->self_signed_flag && opt->ca_private_key_string && + opt->certificate_string && + strcmp(opt->ca_private_key_string, + opt->certificate_string) == 0) { + /* Yes: same as preceding */ ret = _hx509_cert_assign_key(cert, cert_key); if (ret) hx509_err(context, 1, ret, "_hx509_cert_assign_key"); diff --git a/third_party/heimdal/lib/hx509/req.c b/third_party/heimdal/lib/hx509/req.c index 2b3f46d532a..c8fa42e5f99 100644 --- a/third_party/heimdal/lib/hx509/req.c +++ b/third_party/heimdal/lib/hx509/req.c @@ -1046,7 +1046,7 @@ authorize_feat(hx509_request req, abitstring a, size_t n, int idx) switch (ret) { case 0: req->nauthorized++; - fallthrough; + HEIM_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; + HEIM_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; + HEIM_FALLTHROUGH; default: return HX509_SAN_TYPE_UNSUPPORTED; } } @@ -1360,7 +1360,7 @@ 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; + HEIM_FALLTHROUGH; case HX509_SAN_TYPE_MS_UPN: { int ret; diff --git a/third_party/heimdal/lib/ipc/server.c b/third_party/heimdal/lib/ipc/server.c index 40601b9744f..b0b2fa1cb66 100644 --- a/third_party/heimdal/lib/ipc/server.c +++ b/third_party/heimdal/lib/ipc/server.c @@ -122,26 +122,19 @@ mach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply) { struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; heim_ipc_message_inband_t replyin; - mach_msg_type_number_t replyinCnt; - heim_ipc_message_outband_t replyout; - mach_msg_type_number_t replyoutCnt; - kern_return_t kr; + mach_msg_type_number_t replyinCnt = 0; + heim_ipc_message_outband_t replyout = 0; + mach_msg_type_number_t replyoutCnt = 0; if (returnvalue) { /* on error, no reply */ - replyinCnt = 0; - replyout = 0; replyoutCnt = 0; - kr = KERN_SUCCESS; } else if (reply->length < 2048) { replyinCnt = reply->length; memcpy(replyin, reply->data, replyinCnt); - replyout = 0; replyoutCnt = 0; - kr = KERN_SUCCESS; } else { - replyinCnt = 0; - kr = vm_read(mach_task_self(), - (vm_address_t)reply->data, reply->length, - (vm_address_t *)&replyout, &replyoutCnt); + vm_read(mach_task_self(), + (vm_address_t)reply->data, reply->length, + (vm_address_t *)&replyout, &replyoutCnt); } mheim_ripc_call_reply(s->reply_port, returnvalue, @@ -159,31 +152,24 @@ mach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply) { struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; heim_ipc_message_inband_t replyin; - mach_msg_type_number_t replyinCnt; - heim_ipc_message_outband_t replyout; - mach_msg_type_number_t replyoutCnt; - kern_return_t kr; + mach_msg_type_number_t replyinCnt = 0; + heim_ipc_message_outband_t replyout = 0; + mach_msg_type_number_t replyoutCnt = 0; if (returnvalue) { /* on error, no reply */ - replyinCnt = 0; - replyout = 0; replyoutCnt = 0; - kr = KERN_SUCCESS; } else if (reply->length < 2048) { replyinCnt = reply->length; memcpy(replyin, reply->data, replyinCnt); - replyout = 0; replyoutCnt = 0; - kr = KERN_SUCCESS; } else { - replyinCnt = 0; - kr = vm_read(mach_task_self(), - (vm_address_t)reply->data, reply->length, - (vm_address_t *)&replyout, &replyoutCnt); + vm_read(mach_task_self(), + (vm_address_t)reply->data, reply->length, + (vm_address_t *)&replyout, &replyoutCnt); } - kr = mheim_aipc_acall_reply(s->reply_port, returnvalue, - replyin, replyinCnt, - replyout, replyoutCnt); + mheim_aipc_acall_reply(s->reply_port, returnvalue, + replyin, replyinCnt, + replyout, replyoutCnt); heim_ipc_free_cred(s->cred); free(s->req.data); free(s); @@ -700,6 +686,7 @@ maybe_close(struct client *c) dispatch_release(c->out); #endif close(c->fd); /* ref count fd close */ + free(c->inmsg); free(c); return 1; } @@ -1382,4 +1369,3 @@ heim_ipc_main(void) process_loop(); #endif } - diff --git a/third_party/heimdal/lib/kadm5/ad.c b/third_party/heimdal/lib/kadm5/ad.c index 58ccf32eacd..b9b9c9023b9 100644 --- a/third_party/heimdal/lib/kadm5/ad.c +++ b/third_party/heimdal/lib/kadm5/ad.c @@ -1066,6 +1066,33 @@ kadm5_ad_get_principals(void *server_handle, } static kadm5_ret_t +kadm5_ad_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + kadm5_ad_context *context = server_handle; + +#ifdef OPENLDAP + kadm5_ret_t ret; + + ret = ad_get_cred(context, NULL); + if (ret) + return ret; + + ret = _kadm5_ad_connect(server_handle); + if (ret) + return ret; + + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#else + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +static kadm5_ret_t kadm5_ad_get_privs(void *server_handle, uint32_t*privs) { kadm5_ad_context *context = server_handle; @@ -1169,7 +1196,7 @@ kadm5_ad_modify_principal(void *server_handle, if (entry->attributes & KRB5_KDB_REQUIRES_HW_AUTH) i |= UF_SMARTCARD_REQUIRED; else - i &= UF_SMARTCARD_REQUIRED; + i &= ~UF_SMARTCARD_REQUIRED; if (entry->attributes & KRB5_KDB_DISALLOW_SVR) i &= ~UF_WORKSTATION_TRUST_ACCOUNT; else @@ -1388,6 +1415,9 @@ set_funcs(kadm5_ad_context *c) SET(c, lock); SET(c, unlock); SETNOTIMP(c, setkey_principal_3); + SETNOTIMP(c, prune_principal); + SET(c, iter_principals); + SET(c, dup_context); } kadm5_ret_t @@ -1456,6 +1486,12 @@ kadm5_ad_init_with_password_ctx(krb5_context context, } kadm5_ret_t +kadm5_ad_dup_context(void *in, void **out) +{ + return ENOTSUP; +} + +kadm5_ret_t kadm5_ad_init_with_password(const char *client_name, const char *password, const char *service_name, diff --git a/third_party/heimdal/lib/kadm5/common_glue.c b/third_party/heimdal/lib/kadm5/common_glue.c index 9993b0a349e..210bf93b91c 100644 --- a/third_party/heimdal/lib/kadm5/common_glue.c +++ b/third_party/heimdal/lib/kadm5/common_glue.c @@ -39,6 +39,12 @@ RCSID("$Id$"); #define __CALLABLE(F) (((kadm5_common_context*)server_handle)->funcs.F != 0) kadm5_ret_t +kadm5_dup_context(void *server_handle, void **dup_server_handle) +{ + return __CALL(dup_context, (server_handle, dup_server_handle)); +} + +kadm5_ret_t kadm5_chpass_principal(void *server_handle, krb5_principal princ, const char *password) @@ -223,6 +229,15 @@ kadm5_get_principals(void *server_handle, } kadm5_ret_t +kadm5_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + return __CALL(iter_principals, (server_handle, expression, cb, cbdata)); +} + +kadm5_ret_t kadm5_get_privs(void *server_handle, uint32_t *privs) { diff --git a/third_party/heimdal/lib/kadm5/context_s.c b/third_party/heimdal/lib/kadm5/context_s.c index 0c154ecfef0..5c9b3e31c81 100644 --- a/third_party/heimdal/lib/kadm5/context_s.c +++ b/third_party/heimdal/lib/kadm5/context_s.c @@ -112,6 +112,8 @@ set_funcs(kadm5_server_context *c) SET(c, lock); SET(c, unlock); SET(c, setkey_principal_3); + SET(c, iter_principals); + SET(c, dup_context); } #ifndef NO_UNIX_SOCKETS @@ -250,6 +252,8 @@ _kadm5_s_init_context(kadm5_server_context **ctx, krb5_add_et_list (context, initialize_kadm5_error_table_r); #define is_set(M) (params && params->mask & KADM5_CONFIG_ ## M) + if (params) + (*ctx)->config.mask = params->mask; if (is_set(REALM)) { (*ctx)->config.realm = strdup(params->realm); if ((*ctx)->config.realm == NULL) @@ -275,9 +279,9 @@ _kadm5_s_init_context(kadm5_server_context **ctx, return krb5_enomem(context); } - find_db_spec(*ctx); - - ret = _kadm5_s_init_hooks(*ctx); + ret = find_db_spec(*ctx); + if (ret == 0) + ret = _kadm5_s_init_hooks(*ctx); if (ret != 0) { kadm5_s_destroy(*ctx); *ctx = NULL; diff --git a/third_party/heimdal/lib/kadm5/create_s.c b/third_party/heimdal/lib/kadm5/create_s.c index 1c2ab15f30d..e603497ace2 100644 --- a/third_party/heimdal/lib/kadm5/create_s.c +++ b/third_party/heimdal/lib/kadm5/create_s.c @@ -50,6 +50,14 @@ get_default(kadm5_server_context *context, krb5_principal princ, ret = kadm5_s_get_principal(context, def_principal, def, KADM5_PRINCIPAL_NORMAL_MASK); krb5_free_principal (context->context, def_principal); + + if (ret) { + /* Copy defaults from kadmin/init.c */ + memset(def, 0, sizeof(*def)); + def->max_life = 24 * 60 * 60; + def->max_renewable_life = 7 * def->max_life; + def->attributes = KRB5_KDB_DISALLOW_ALL_TIX; + } return ret; } diff --git a/third_party/heimdal/lib/kadm5/destroy_s.c b/third_party/heimdal/lib/kadm5/destroy_s.c index fc86e5960e6..0558b45c577 100644 --- a/third_party/heimdal/lib/kadm5/destroy_s.c +++ b/third_party/heimdal/lib/kadm5/destroy_s.c @@ -42,10 +42,12 @@ RCSID("$Id$"); static void destroy_config (kadm5_config_params *c) { - free (c->realm); - free (c->dbname); - free (c->acl_file); - free (c->stash_file); + if (!c) + return; + free(c->realm); + free(c->dbname); + free(c->acl_file); + free(c->stash_file); } /* @@ -55,6 +57,8 @@ destroy_config (kadm5_config_params *c) static void destroy_kadm5_log_context (kadm5_log_context *c) { + if (!c) + return; free(c->log_file); if (c->socket_fd != rk_INVALID_SOCKET) rk_closesocket(c->socket_fd); diff --git a/third_party/heimdal/lib/kadm5/get_c.c b/third_party/heimdal/lib/kadm5/get_c.c index 5b2bcca762a..1c1fd9dce80 100644 --- a/third_party/heimdal/lib/kadm5/get_c.c +++ b/third_party/heimdal/lib/kadm5/get_c.c @@ -89,7 +89,7 @@ kadm5_c_get_principal(void *server_handle, out_keep_error: if (ret == 0) - kadm5_ret_principal_ent(sp, ent); + ret = kadm5_ret_principal_ent(sp, ent); krb5_storage_free(sp); krb5_data_free(&reply); return ret; diff --git a/third_party/heimdal/lib/kadm5/get_princs_c.c b/third_party/heimdal/lib/kadm5/get_princs_c.c index 4998223d260..93d7ce7ed1b 100644 --- a/third_party/heimdal/lib/kadm5/get_princs_c.c +++ b/third_party/heimdal/lib/kadm5/get_princs_c.c @@ -66,7 +66,7 @@ kadm5_c_get_principals(void *server_handle, ret = krb5_store_int32(sp, kadm_get_princs); if (ret) goto out; - ret = krb5_store_int32(sp, expression != NULL); + ret = krb5_store_int32(sp, expression != NULL ? 1 : 0); if (ret) goto out; if (expression) { @@ -117,3 +117,187 @@ kadm5_c_get_principals(void *server_handle, krb5_data_free(&reply); return ret; } + +kadm5_ret_t +kadm5_c_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + size_t i; + + ret = _kadm5_connect(server_handle, 0 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_get_princs); + if (ret) + goto out; + + /* + * Our protocol has an int boolean for this operation to indicate whether + * there's an expression. What we'll do here is that instead of sending + * just false or trueish, for online iteration we'll send a number other + * than 0 or 1 -- a magic value > 0 and < INT_MAX. + * + * In response we'll expect multiple replies, each with up to some small + * number of principal names. See kadmin/server.c. + */ + ret = krb5_store_int32(sp, 0x55555555); + if (ret) + goto out; + ret = krb5_store_string(sp, expression ? expression : ""); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data (&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + if (ret) + goto out; + + ret = krb5_ret_int32(sp, &tmp); + if (ret) + goto out; + + if (tmp < 0) { + size_t n = -tmp; + int more = 1; + int stop = 0; + + /* The server supports online iteration, hooray! */ + + while (more) { + /* + * We expect any number of chunks, each having `n' names, except + * the last one would have fewer than `n' (possibly zero, even). + * + * After that we expect one more reply with just a final return + * code. + */ + krb5_data_free(&reply); + krb5_storage_free(sp); + sp = NULL; + ret = _kadm5_client_recv(context, &reply); + if (ret == 0 && (sp = krb5_storage_from_data(&reply)) == NULL) + ret = krb5_enomem(context->context); + if (ret) + goto out; + + /* Every chunk begins with a status code */ + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + if (ret) + goto out; + + /* We expect up to -tmp principals per reply */ + for (i = 0; i < n; i++) { + char *princ = NULL; + + ret = krb5_ret_string(sp, &princ); + if (ret == HEIM_ERR_EOF) { + /* This was the last reply */ + more = 0; + ret = 0; + break; + } + if (ret) + goto out; + if (!stop) { + stop = cb(cbdata, princ); + if (stop) { + /* + * Tell the server to stop. + * + * We use a NOP for this, but with a payload that says + * "don't reply to the NOP" just in case the NOP + * arrives and is processed _after_ the LISTing has + * finished. + */ + krb5_storage_free(sp); + if ((sp = krb5_storage_emem()) && + krb5_store_int32(sp, kadm_nop) == 0 && + krb5_store_int32(sp, 0)) + (void) _kadm5_client_send(context, sp); + } + } + free(princ); + } + + if (!more) { + if (ret == 0) + ret = stop; + break; + } + } + /* Get the final result code */ + krb5_data_free(&reply); + krb5_storage_free(sp); + sp = NULL; + ret = _kadm5_client_recv(context, &reply); + if (ret == 0 && (sp = krb5_storage_from_data(&reply)) == NULL) + ret = krb5_enomem(context->context); + if (ret) + goto out; + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + if (!stop) { + /* + * Send our "interrupt" after the last chunk if we hand't + * interrupted already. + */ + krb5_storage_free(sp); + if ((sp = krb5_storage_emem()) && + krb5_store_int32(sp, kadm_nop) == 0) + (void) _kadm5_client_send(context, sp); + } + } else { + size_t n = tmp; + + /* Old server -- listing not online */ + for (i = 0; i < n; i++) { + char *princ = NULL; + + ret = krb5_ret_string(sp, &princ); + if (ret) + goto out; + cb(cbdata, princ); + free(princ); + } + } + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/get_princs_s.c b/third_party/heimdal/lib/kadm5/get_princs_s.c index 27fac2bbb0b..14d3907d759 100644 --- a/third_party/heimdal/lib/kadm5/get_princs_s.c +++ b/third_party/heimdal/lib/kadm5/get_princs_s.c @@ -39,17 +39,27 @@ struct foreach_data { const char *exp; char *exp2; char **princs; - int count; + size_t nalloced; + size_t count; }; static krb5_error_code add_princ(krb5_context context, struct foreach_data *d, char *princ) { - char **tmp; - tmp = realloc(d->princs, (d->count + 1) * sizeof(*tmp)); - if (tmp == NULL) - return krb5_enomem(context); - d->princs = tmp; + + if (d->count == INT_MAX) + return ERANGE; + if (d->nalloced == d->count) { + size_t n = d->nalloced + (d->nalloced >> 1) + 128; /* No O(N^2) pls */ + char **tmp; + + if (SIZE_MAX / sizeof(*tmp) <= n) + return ERANGE; + if ((tmp = realloc(d->princs, n * sizeof(*tmp))) == NULL) + return krb5_enomem(context); + d->princs = tmp; + d->nalloced = n; + } d->princs[d->count++] = princ; return 0; } @@ -84,7 +94,7 @@ kadm5_s_get_principals(void *server_handle, { struct foreach_data d; kadm5_server_context *context = server_handle; - kadm5_ret_t ret; + kadm5_ret_t ret = 0; if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); @@ -94,33 +104,103 @@ kadm5_s_get_principals(void *server_handle, } } d.exp = expression; - { + d.exp2 = NULL; + if (expression) { krb5_realm r; int aret; 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) { - ret = krb5_enomem(context->context); - goto out; - } + if (ret == 0) { + aret = asprintf(&d.exp2, "%s@%s", expression, r); + free(r); + if (aret == -1 || d.exp2 == NULL) + ret = krb5_enomem(context->context); + } } d.princs = NULL; + d.nalloced = 0; d.count = 0; - ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, foreach, &d); + if (ret == 0) + ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, + foreach, &d); if (ret == 0) ret = add_princ(context->context, &d, NULL); - if (ret == 0){ + if (d.count >= INT_MAX) + *count = INT_MAX; + else + *count = d.count - 1; + if (ret == 0) *princs = d.princs; - *count = d.count - 1; - } else - kadm5_free_name_list(context, d.princs, &d.count); + else + kadm5_free_name_list(context, d.princs, count); + free(d.exp2); + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + return _kadm5_error_code(ret); +} + +struct foreach_online_data { + const char *exp; + char *exp2; + int (*cb)(void *, const char *); + void *cbdata; +}; + +static krb5_error_code +foreach_online(krb5_context context, HDB *db, hdb_entry *ent, void *data) +{ + struct foreach_online_data *d = data; + krb5_error_code ret; + char *princ = NULL; + + ret = krb5_unparse_name(context, ent->principal, &princ); + if (ret == 0) { + if (!d->exp || + fnmatch(d->exp, princ, 0) == 0 || fnmatch(d->exp2, princ, 0) == 0) + ret = d->cb(d->cbdata, princ); + free(princ); + } + return ret; +} + +kadm5_ret_t +kadm5_s_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + struct foreach_online_data d; + kadm5_server_context *context = server_handle; + kadm5_ret_t ret = 0; + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); + if (ret) { + krb5_warn(context->context, ret, "opening database"); + return ret; + } + } + d.exp = expression; + d.exp2 = NULL; + d.cb = cb; + d.cbdata = cbdata; + if (expression) { + krb5_realm r; + int aret; + + ret = krb5_get_default_realm(context->context, &r); + if (ret == 0) { + aret = asprintf(&d.exp2, "%s@%s", expression, r); + free(r); + if (aret == -1 || d.exp2 == NULL) + ret = krb5_enomem(context->context); + } + } + if (ret == 0) + ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, + foreach_online, &d); free(d.exp2); - out: if (!context->keep_open) context->db->hdb_close(context->context, context->db); 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 5d585d1a295..ffbb639581c 100644 --- a/third_party/heimdal/lib/kadm5/init_c.c +++ b/third_party/heimdal/lib/kadm5/init_c.c @@ -78,6 +78,8 @@ set_funcs(kadm5_client_context *c) SET(c, lock); SET(c, unlock); SETNOTIMP(c, setkey_principal_3); + SET(c, iter_principals); + SET(c, dup_context); } kadm5_ret_t @@ -192,6 +194,56 @@ _kadm5_c_init_context(kadm5_client_context **ctx, return 0; } +kadm5_ret_t +kadm5_c_dup_context(void *vin, void **out) +{ + krb5_error_code ret; + kadm5_client_context *in = vin; + krb5_context context = in->context; + kadm5_client_context *ctx; + + *out = NULL; + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return krb5_enomem(in->context); + + + memset(ctx, 0, sizeof(*ctx)); + set_funcs(ctx); + ctx->readonly_kadmind_port = in->readonly_kadmind_port; + ctx->kadmind_port = in->kadmind_port; + + ret = krb5_copy_context(context, &(ctx->context)); + if (ret == 0) { + ctx->my_context = TRUE; + ret = krb5_add_et_list(ctx->context, initialize_kadm5_error_table_r); + } + if (ret == 0 && (ctx->realm = strdup(in->realm)) == NULL) + ret = krb5_enomem(context); + if (ret == 0 && + (ctx->admin_server = strdup(in->admin_server)) == NULL) + ret = krb5_enomem(context); + if (in->readonly_admin_server && + (ctx->readonly_admin_server = strdup(in->readonly_admin_server)) == NULL) + ret = krb5_enomem(context); + if (in->keytab && (ctx->keytab = strdup(in->keytab)) == NULL) + ret = krb5_enomem(context); + if (in->ccache) { + char *fullname = NULL; + + ret = krb5_cc_get_full_name(context, in->ccache, &fullname); + if (ret == 0) + ret = krb5_cc_resolve(context, fullname, &ctx->ccache); + free(fullname); + } + ctx->sock = -1; + if (ret == 0) + *out = ctx; + else + kadm5_c_destroy(ctx); + return ret; +} + static krb5_error_code get_kadm_ticket(krb5_context context, krb5_ccache id, diff --git a/third_party/heimdal/lib/kadm5/init_s.c b/third_party/heimdal/lib/kadm5/init_s.c index 1b1d7f2ff58..35402d88a52 100644 --- a/third_party/heimdal/lib/kadm5/init_s.c +++ b/third_party/heimdal/lib/kadm5/init_s.c @@ -109,6 +109,21 @@ kadm5_s_init_with_context(krb5_context context, } kadm5_ret_t +kadm5_s_dup_context(void *vin, void **out) +{ + kadm5_server_context *in = vin; + kadm5_ret_t ret; + char *p = NULL; + + ret = krb5_unparse_name(in->context, in->caller, &p); + if (ret == 0) + ret = kadm5_s_init_with_context(in->context, p, NULL, + &in->config, 0, 0, out); + free(p); + return ret; +} + +kadm5_ret_t kadm5_s_init_with_password_ctx(krb5_context context, const char *client_name, const char *password, diff --git a/third_party/heimdal/lib/kadm5/iprop.8 b/third_party/heimdal/lib/kadm5/iprop.8 index b881c441a1a..41aac061829 100644 --- a/third_party/heimdal/lib/kadm5/iprop.8 +++ b/third_party/heimdal/lib/kadm5/iprop.8 @@ -68,6 +68,8 @@ .Oo Fl r Ar string \*(Ba Xo Fl Fl realm= Ns Ar string Xc Oc .Oo Fl d Ar file \*(Ba Xo Fl Fl database= Ns Ar file Xc Oc .Oo Fl k Ar kspec \*(Ba Xo Fl Fl keytab= Ns Ar kspec Xc Oc +.Oo Xo Fl Fl no-keytab Xc Oc +.Oo Xo Fl Fl cache= Ns Ar cspec Xc Oc .Op Fl Fl statusfile= Ns Ar file .Op Fl Fl hostname= Ns Ar hostname .Op Fl Fl port= Ns Ar port @@ -125,10 +127,40 @@ This should normally be defined as in .Pa /etc/services or another source of the services database. -The master and slaves -must each have access to a keytab with keys for the -.Nm iprop -service principal on the local host. +.Pp +The +.Nm ipropd-master +and +.Nm ipropd-slave +programs require acceptor and initiator credentials, +respectively, for host-based principals for the +.Ar iprop +service and the fully-qualified hostnames of the hosts on which +they run. +.Pp +The +.Nm ipropd-master +program uses, by default, the HDB-backed keytab +.Ar HDBGET: , +though a file-based keytab can also be specified. +.Pp +The +.Nm ipropd-slave +program uses the default keytab, which is specified by the +.Ev KRB5_KTNAME +environment variable, or the value of the +.Ar default_keytab_name +configuration parameter in the +.Ar [libdefaults] +section. +However, if the +.Fl Fl no-keytab +option is given, then +.Nm ipropd-slave +will use the given or default credentials cache, and it will +expect that cache to be kept fresh externally (such as by the +.Nm kinit +program). .Pp There is a keep-alive feature logged in the master's .Pa slave-stats @@ -150,6 +182,11 @@ Supported options for Keytab for authenticating .Nm ipropd-slave clients. +.It Fl Fl cache= Ns Ar cspec +If the keytab given is the empty string then credentials will be +used from the default credentials cache, or from the +.Ar cspec +if given. .It Fl d Ar file , Fl Fl database= Ns Ar file Database (default per KDC) .It Fl Fl slave-stats-file= Ns Ar file @@ -201,6 +238,7 @@ in the database directory, or in the directory named by the .Ev HEIM_PIDFILE_DIR environment variable. .Sh SEE ALSO +.Xr kinit 1 , .Xr krb5.conf 5 , .Xr hprop 8 , .Xr hpropd 8 , diff --git a/third_party/heimdal/lib/kadm5/ipropd_slave.c b/third_party/heimdal/lib/kadm5/ipropd_slave.c index 2b1be00ea60..f92b20c8569 100644 --- a/third_party/heimdal/lib/kadm5/ipropd_slave.c +++ b/third_party/heimdal/lib/kadm5/ipropd_slave.c @@ -39,6 +39,9 @@ static const char *config_name = "ipropd-slave"; static int verbose; static int async_hdb = 0; +static int no_keytab_flag; +static char *ccache_str; +static char *keytab_str; static krb5_log_facility *log_facility; static char five_min[] = "5 min"; @@ -115,8 +118,7 @@ connect_to_master (krb5_context context, const char *master, } static void -get_creds(krb5_context context, const char *keytab_str, - krb5_ccache *cache, const char *serverhost) +get_creds(krb5_context context, krb5_ccache *cache, const char *serverhost) { krb5_keytab keytab; krb5_principal client; @@ -127,13 +129,33 @@ get_creds(krb5_context context, const char *keytab_str, char keytab_buf[256]; int aret; + if (no_keytab_flag) { + /* We're using an externally refreshed ccache */ + if (*cache == NULL) { + if (ccache_str == NULL) + ret = krb5_cc_default(context, cache); + else + ret = krb5_cc_resolve(context, ccache_str, cache); + if (ret) + krb5_err(context, 1, ret, "Could not resolve the default cache"); + } + return; + } + if (keytab_str == NULL) { ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf)); - if (ret) - krb5_err (context, 1, ret, "krb5_kt_default_name"); - keytab_str = keytab_buf; + if (ret == 0) { + keytab_str = keytab_buf; + } else { + krb5_warn(context, ret, "Using HDBGET: as the default keytab"); + keytab_str = "HDBGET:"; + } } + if (*cache) + krb5_cc_destroy(context, *cache); + *cache = NULL; + ret = krb5_kt_resolve(context, keytab_str, &keytab); if(ret) krb5_err(context, 1, ret, "%s", keytab_str); @@ -690,7 +712,6 @@ static char *status_file; static char *config_file; static int version_flag; static int help_flag; -static char *keytab_str; static char *port_str; static int detach_from_console; static int daemon_child = -1; @@ -699,8 +720,12 @@ static struct getargs args[] = { { "config-file", 'c', arg_string, &config_file, NULL, NULL }, { "realm", 'r', arg_string, &realm, NULL, NULL }, { "database", 'd', arg_string, &database, "database", "file"}, + { "no-keytab", 0, arg_flag, &no_keytab_flag, + "use externally refreshed cache", NULL }, + { "ccache", 0, arg_string, &ccache_str, + "client credentials", "CCACHE" }, { "keytab", 'k', arg_string, &keytab_str, - "keytab to get authentication from", "kspec" }, + "client credentials keytab", "KEYTAB" }, { "time-lost", 0, arg_string, &server_time_lost, "time before server is considered lost", "time" }, { "status-file", 0, arg_string, &status_file, @@ -740,7 +765,7 @@ main(int argc, char **argv) kadm5_server_context *server_context; kadm5_config_params conf; int master_fd; - krb5_ccache ccache; + krb5_ccache ccache = NULL; krb5_principal server; char **files; int optidx = 0; @@ -858,7 +883,7 @@ main(int argc, char **argv) if (ret) krb5_err(context, 1, ret, "db->close"); - get_creds(context, keytab_str, &ccache, master); + get_creds(context, &ccache, master); ret = krb5_sname_to_principal (context, master, IPROP_NAME, KRB5_NT_SRV_HST, &server); @@ -923,8 +948,7 @@ main(int argc, char **argv) if (auth_context) { krb5_auth_con_free(context, auth_context); auth_context = NULL; - krb5_cc_destroy(context, ccache); - get_creds(context, keytab_str, &ccache, master); + get_creds(context, &ccache, master); } if (verbose) krb5_warnx(context, "authenticating to master"); diff --git a/third_party/heimdal/lib/kadm5/libkadm5srv-exports.def b/third_party/heimdal/lib/kadm5/libkadm5srv-exports.def index 72ba4174c1f..56366ae2046 100644 --- a/third_party/heimdal/lib/kadm5/libkadm5srv-exports.def +++ b/third_party/heimdal/lib/kadm5/libkadm5srv-exports.def @@ -15,6 +15,7 @@ EXPORTS kadm5_delete_policy kadm5_delete_principal kadm5_destroy + kadm5_dup_context kadm5_flush kadm5_free_key_data kadm5_free_name_list @@ -32,6 +33,7 @@ EXPORTS kadm5_init_with_password_ctx kadm5_init_with_skey kadm5_init_with_skey_ctx + kadm5_iter_principals kadm5_lock kadm5_modify_policy kadm5_modify_principal diff --git a/third_party/heimdal/lib/kadm5/private.h b/third_party/heimdal/lib/kadm5/private.h index 88c2f2823d2..1cb8e3918f5 100644 --- a/third_party/heimdal/lib/kadm5/private.h +++ b/third_party/heimdal/lib/kadm5/private.h @@ -68,6 +68,8 @@ struct kadm_func { int, krb5_key_salt_tuple *, krb5_keyblock *, int); kadm5_ret_t (*prune_principal) (void *, krb5_principal, int); + kadm5_ret_t (*iter_principals) (void*, const char*, int (*)(void *, const char *), void *); + kadm5_ret_t (*dup_context) (void*, void **); }; typedef struct kadm5_hook_context { diff --git a/third_party/heimdal/lib/kadm5/version-script-client.map b/third_party/heimdal/lib/kadm5/version-script-client.map index 4d89fabf308..baae30b1173 100644 --- a/third_party/heimdal/lib/kadm5/version-script-client.map +++ b/third_party/heimdal/lib/kadm5/version-script-client.map @@ -11,6 +11,7 @@ HEIMDAL_KADM5_CLIENT_1.0 { kadm5_c_create_principal; kadm5_c_delete_principal; kadm5_c_destroy; + kadm5_c_dup_context; kadm5_c_flush; kadm5_c_get_principal; kadm5_c_get_principals; @@ -21,6 +22,8 @@ HEIMDAL_KADM5_CLIENT_1.0 { kadm5_c_init_with_password_ctx; kadm5_c_init_with_skey; kadm5_c_init_with_skey_ctx; + kadm5_c_iter_principals; + kadm5_c_get_privs; kadm5_c_modify_principal; kadm5_c_prune_principal; kadm5_c_randkey_principal; @@ -30,6 +33,7 @@ HEIMDAL_KADM5_CLIENT_1.0 { kadm5_create_principal; kadm5_delete_principal; kadm5_destroy; + kadm5_dup_context; kadm5_flush; kadm5_free_key_data; kadm5_free_name_list; @@ -43,6 +47,7 @@ HEIMDAL_KADM5_CLIENT_1.0 { kadm5_init_with_password_ctx; kadm5_init_with_skey; kadm5_init_with_skey_ctx; + kadm5_iter_principals; kadm5_modify_principal; kadm5_randkey_principal; kadm5_randkey_principal_3; diff --git a/third_party/heimdal/lib/kadm5/version-script.map b/third_party/heimdal/lib/kadm5/version-script.map index e4b4100f334..6de88fc2217 100644 --- a/third_party/heimdal/lib/kadm5/version-script.map +++ b/third_party/heimdal/lib/kadm5/version-script.map @@ -16,6 +16,7 @@ HEIMDAL_KAMD5_SERVER_1.0 { kadm5_create_principal_3; kadm5_delete_principal; kadm5_destroy; + kadm5_dup_context; kadm5_decrypt_key; kadm5_delete_policy; kadm5_flush; @@ -35,6 +36,7 @@ HEIMDAL_KAMD5_SERVER_1.0 { kadm5_init_with_password_ctx; kadm5_init_with_skey; kadm5_init_with_skey_ctx; + kadm5_iter_principals; kadm5_lock; kadm5_modify_principal; kadm5_modify_policy; diff --git a/third_party/heimdal/lib/kafs/kafs_locl.h b/third_party/heimdal/lib/kafs/kafs_locl.h index 6f34ca63170..f4e2f64b407 100644 --- a/third_party/heimdal/lib/kafs/kafs_locl.h +++ b/third_party/heimdal/lib/kafs/kafs_locl.h @@ -96,7 +96,6 @@ #endif #ifdef KRB5 #include "crypto-headers.h" -#include <krb5-v4compat.h> typedef struct credentials CREDENTIALS; #endif /* KRB5 */ #ifndef NO_AFS diff --git a/third_party/heimdal/lib/kafs/rxkad_kdf.c b/third_party/heimdal/lib/kafs/rxkad_kdf.c index 5af391ed99b..b542e8916b5 100644 --- a/third_party/heimdal/lib/kafs/rxkad_kdf.c +++ b/third_party/heimdal/lib/kafs/rxkad_kdf.c @@ -209,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; + HEIM_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 c1345c28a5a..ecce461dd89 100644 --- a/third_party/heimdal/lib/krb5/Makefile.am +++ b/third_party/heimdal/lib/krb5/Makefile.am @@ -193,7 +193,6 @@ dist_libkrb5_la_SOURCES = \ keytab_keyfile.c \ keytab_memory.c \ krb5_locl.h \ - krb5-v4compat.h \ krcache.c \ krbhst.c \ kuserok.c \ diff --git a/third_party/heimdal/lib/krb5/NTMakefile b/third_party/heimdal/lib/krb5/NTMakefile index 40ca0fb0bcc..993e76fcc23 100644 --- a/third_party/heimdal/lib/krb5/NTMakefile +++ b/third_party/heimdal/lib/krb5/NTMakefile @@ -2,19 +2,19 @@ # # Copyright (c) 2009 - 2017, Secure Endpoints Inc. # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: -# +# # - Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. -# +# # - Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS @@ -27,7 +27,7 @@ # 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. -# +# RELDIR=lib\krb5 @@ -184,7 +184,6 @@ INCFILES= \ $(INCDIR)\krb5_locl.h \ $(INCDIR)\krb5-protos.h \ $(INCDIR)\krb5-private.h \ - $(INCDIR)\krb5-v4compat.h \ $(INCDIR)\crypto.h \ $(INCDIR)\an2ln_plugin.h \ $(INCDIR)\ccache_plugin.h \ @@ -267,7 +266,6 @@ dist_libkrb5_la_SOURCES = \ keytab_keyfile.c \ keytab_memory.c \ krb5_locl.h \ - krb5-v4compat.h \ krbhst.c \ kuserok.c \ kx509.c \ diff --git a/third_party/heimdal/lib/krb5/aname_to_localname.c b/third_party/heimdal/lib/krb5/aname_to_localname.c index 11f270d4978..8515c306e69 100644 --- a/third_party/heimdal/lib/krb5/aname_to_localname.c +++ b/third_party/heimdal/lib/krb5/aname_to_localname.c @@ -420,6 +420,7 @@ an2ln_def_plug_an2ln(void *plug_ctx, krb5_context context, heim_dict_set_value(db_options, HSTR("read-only"), heim_number_create(1)); dbh = heim_db_create(NULL, an2ln_db_fname, db_options, &error); + heim_release(db_options); if (dbh == NULL) { krb5_set_error_message(context, heim_error_get_code(error), N_("Couldn't open aname2lname-text-db", "")); diff --git a/third_party/heimdal/lib/krb5/changepw.c b/third_party/heimdal/lib/krb5/changepw.c index 12f0b154689..1982925bf06 100644 --- a/third_party/heimdal/lib/krb5/changepw.c +++ b/third_party/heimdal/lib/krb5/changepw.c @@ -384,7 +384,7 @@ process_reply (krb5_context context, ap_rep_data.data = reply + 6; ap_rep_data.length = (reply[4] << 8) | (reply[5]); - if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) { + if (len - 6 < ap_rep_data.length) { str2data (result_string, "client: wrong AP len in reply"); *result_code = KRB5_KPASSWD_MALFORMED; return 0; diff --git a/third_party/heimdal/lib/krb5/context.c b/third_party/heimdal/lib/krb5/context.c index 4040a983518..d6ddd902d64 100644 --- a/third_party/heimdal/lib/krb5/context.c +++ b/third_party/heimdal/lib/krb5/context.c @@ -545,7 +545,7 @@ copy_etypes (krb5_context context, KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_copy_context(krb5_context context, krb5_context *out) { - krb5_error_code ret; + krb5_error_code ret = 0; krb5_context p; *out = NULL; @@ -554,81 +554,80 @@ krb5_copy_context(krb5_context context, krb5_context *out) if (p == NULL) return krb5_enomem(context); - if ((p->hcontext = heim_context_init()) == NULL) { - ret = ENOMEM; - goto out; - } + p->cc_ops = NULL; + p->etypes = NULL; + p->kt_types = NULL; + p->cfg_etypes = NULL; + p->etypes_des = NULL; + p->default_realms = NULL; + p->extra_addresses = NULL; + p->ignore_addresses = NULL; - heim_context_set_log_utc(p->hcontext, context->log_utc); - - if (context->default_cc_name && - (p->default_cc_name = strdup(context->default_cc_name)) == NULL) { + if ((p->hcontext = heim_context_init()) == NULL) ret = ENOMEM; - goto out; + + if (ret == 0) { + heim_context_set_log_utc(p->hcontext, context->log_utc); + ret = _krb5_config_copy(context, context->cf, &p->cf); } - if (context->default_cc_name_env && - (p->default_cc_name_env = - strdup(context->default_cc_name_env)) == NULL) { - ret = ENOMEM; - goto out; + if (ret == 0) + ret = init_context_from_config_file(p); + if (ret == 0 && context->default_cc_name) { + free(p->default_cc_name); + if ((p->default_cc_name = strdup(context->default_cc_name)) == NULL) + ret = ENOMEM; } - if (context->configured_default_cc_name && - (p->configured_default_cc_name = - strdup(context->configured_default_cc_name)) == NULL) { - ret = ENOMEM; - goto out; + if (ret == 0 && context->default_cc_name_env) { + free(p->default_cc_name_env); + if ((p->default_cc_name_env = + strdup(context->default_cc_name_env)) == NULL) + ret = ENOMEM; + } + if (ret == 0 && context->configured_default_cc_name) { + free(context->configured_default_cc_name); + if ((p->configured_default_cc_name = + strdup(context->configured_default_cc_name)) == NULL) + ret = ENOMEM; } - if (context->etypes) { + if (ret == 0 && context->etypes) { + free(p->etypes); ret = copy_etypes(context, context->etypes, &p->etypes); - if (ret) - goto out; } - if (context->cfg_etypes) { + if (ret == 0 && context->cfg_etypes) { + free(p->cfg_etypes); ret = copy_etypes(context, context->cfg_etypes, &p->cfg_etypes); - if (ret) - goto out; } - if (context->etypes_des) { + if (ret == 0 && context->etypes_des) { + free(p->etypes_des); ret = copy_etypes(context, context->etypes_des, &p->etypes_des); - if (ret) - goto out; } - if (context->default_realms) { + if (ret == 0 && context->default_realms) { + krb5_free_host_realm(context, p->default_realms); ret = krb5_copy_host_realm(context, context->default_realms, &p->default_realms); - if (ret) - goto out; } - ret = _krb5_config_copy(context, context->cf, &p->cf); - if (ret) - goto out; - /* XXX should copy */ - _krb5_init_ets(p); - - cc_ops_copy(p, context); - kt_ops_copy(p, context); - - ret = krb5_set_extra_addresses(p, context->extra_addresses); - if (ret) - goto out; - ret = krb5_set_extra_addresses(p, context->ignore_addresses); - if (ret) - goto out; - - ret = _krb5_copy_send_to_kdc_func(p, context); - if (ret) - goto out; - - *out = p; - - return 0; - - out: - krb5_free_context(p); + if (ret == 0) + _krb5_init_ets(p); + + if (ret == 0) + ret = cc_ops_copy(p, context); + if (ret == 0) + ret = kt_ops_copy(p, context); + if (ret == 0) + ret = krb5_set_extra_addresses(p, context->extra_addresses); + if (ret == 0) + ret = krb5_set_extra_addresses(p, context->ignore_addresses); + if (ret == 0) + ret = _krb5_copy_send_to_kdc_func(p, context); + + if (ret == 0) + *out = p; + else + krb5_free_context(p); return ret; } diff --git a/third_party/heimdal/lib/krb5/convert_creds.c b/third_party/heimdal/lib/krb5/convert_creds.c index fc371c63776..56261b29fa6 100644 --- a/third_party/heimdal/lib/krb5/convert_creds.c +++ b/third_party/heimdal/lib/krb5/convert_creds.c @@ -32,7 +32,6 @@ */ #include "krb5_locl.h" -#include "krb5-v4compat.h" #ifndef HEIMDAL_SMALLER @@ -58,7 +57,6 @@ krb524_convert_creds_kdc(krb5_context context, struct credentials *v4creds) KRB5_DEPRECATED_FUNCTION("Use X instead") { - memset(v4creds, 0, sizeof(*v4creds)); krb5_set_error_message(context, EINVAL, N_("krb524_convert_creds_kdc not supported", "")); return EINVAL; @@ -86,7 +84,6 @@ krb524_convert_creds_kdc_ccache(krb5_context context, struct credentials *v4creds) KRB5_DEPRECATED_FUNCTION("Use X instead") { - memset(v4creds, 0, sizeof(*v4creds)); krb5_set_error_message(context, EINVAL, N_("krb524_convert_creds_kdc_ccache not supported", "")); return EINVAL; diff --git a/third_party/heimdal/lib/krb5/kcm.c b/third_party/heimdal/lib/krb5/kcm.c index a75fc03f985..f20fc51936f 100644 --- a/third_party/heimdal/lib/krb5/kcm.c +++ b/third_party/heimdal/lib/krb5/kcm.c @@ -238,8 +238,7 @@ kcm_alloc(krb5_context context, if (residual) { /* KCM cache names must start with {UID} or {UID}: */ - if (residual[0] != '0') - plen = strspn(residual, "0123456789"); + plen = strspn(residual, "0123456789"); if (plen && residual[plen] != ':' && residual[plen] != '\0') plen = 0; /* diff --git a/third_party/heimdal/lib/krb5/keytab.c b/third_party/heimdal/lib/krb5/keytab.c index 559d640f002..bcb3ed83733 100644 --- a/third_party/heimdal/lib/krb5/keytab.c +++ b/third_party/heimdal/lib/krb5/keytab.c @@ -883,7 +883,8 @@ krb5_kt_add_entry(krb5_context context, id->prefix); return KRB5_KT_NOWRITE; } - entry->timestamp = time(NULL); + if (entry->timestamp == 0) + entry->timestamp = time(NULL); return (*id->add)(context, id,entry); } diff --git a/third_party/heimdal/lib/krb5/krb5-v4compat.h b/third_party/heimdal/lib/krb5/krb5-v4compat.h deleted file mode 100644 index 2992976e655..00000000000 --- a/third_party/heimdal/lib/krb5/krb5-v4compat.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifndef __KRB5_V4COMPAT_H__ -#define __KRB5_V4COMPAT_H__ - -#include "krb_err.h" - -/* - * This file must only be included with v4 compat glue stuff in - * heimdal sources. - * - * It MUST NOT be installed. - */ - -#define KRB_PROT_VERSION 4 - -#define AUTH_MSG_KDC_REQUEST (1<<1) -#define AUTH_MSG_KDC_REPLY (2<<1) -#define AUTH_MSG_APPL_REQUEST (3<<1) -#define AUTH_MSG_APPL_REQUEST_MUTUAL (4<<1) -#define AUTH_MSG_ERR_REPLY (5<<1) -#define AUTH_MSG_PRIVATE (6<<1) -#define AUTH_MSG_SAFE (7<<1) -#define AUTH_MSG_APPL_ERR (8<<1) -#define AUTH_MSG_KDC_FORWARD (9<<1) -#define AUTH_MSG_KDC_RENEW (10<<1) -#define AUTH_MSG_DIE (63<<1) - -/* General definitions */ -#define KSUCCESS 0 -#define KFAILURE 255 - -/* */ - -#define MAX_KTXT_LEN 1250 - -#define ANAME_SZ 40 -#define REALM_SZ 40 -#define SNAME_SZ 40 -#define INST_SZ 40 - -struct ktext { - unsigned int length; /* Length of the text */ - unsigned char dat[MAX_KTXT_LEN]; /* The data itself */ - uint32_t mbz; /* zero to catch runaway strings */ -}; - -struct credentials { - char service[ANAME_SZ]; /* Service name */ - char instance[INST_SZ]; /* Instance */ - char realm[REALM_SZ]; /* Auth domain */ - char session[8]; /* Session key */ - int lifetime; /* Lifetime */ - int kvno; /* Key version number */ - struct ktext ticket_st; /* The ticket itself */ - int32_t issue_date; /* The issue time */ - char pname[ANAME_SZ]; /* Principal's name */ - char pinst[INST_SZ]; /* Principal's instance */ -}; - -#define TKTLIFENUMFIXED 64 -#define TKTLIFEMINFIXED 0x80 -#define TKTLIFEMAXFIXED 0xBF -#define TKTLIFENOEXPIRE 0xFF -#define MAXTKTLIFETIME (30*24*3600) /* 30 days */ -#ifndef NEVERDATE -#define NEVERDATE ((time_t)0x7fffffffL) -#endif - -#define KERB_ERR_NULL_KEY 10 - -#define CLOCK_SKEW 5*60 - -#ifndef TKT_ROOT -#define TKT_ROOT "%{TEMP}/tkt" -#endif - -struct _krb5_krb_auth_data { - int8_t k_flags; /* Flags from ticket */ - char *pname; /* Principal's name */ - char *pinst; /* His Instance */ - char *prealm; /* His Realm */ - uint32_t checksum; /* Data checksum (opt) */ - krb5_keyblock session; /* Session Key */ - unsigned char life; /* Life of ticket */ - uint32_t time_sec; /* Time ticket issued */ - uint32_t address; /* Address in ticket */ -}; - -KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL -_krb5_krb_life_to_time (int, int); - -KRB5_LIB_FUNCTION int KRB5_LIB_CALL -_krb5_krb_time_to_life (time_t, time_t); - -KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -_krb5_krb_tf_setup (krb5_context, struct credentials *, - const char *, int); - -KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -_krb5_krb_dest_tkt(krb5_context, const char *); - -#define krb_time_to_life _krb5_krb_time_to_life -#define krb_life_to_time _krb5_krb_life_to_time - -#endif /* __KRB5_V4COMPAT_H__ */ diff --git a/third_party/heimdal/lib/krb5/pac.c b/third_party/heimdal/lib/krb5/pac.c index c8f355c8179..b923981908d 100644 --- a/third_party/heimdal/lib/krb5/pac.c +++ b/third_party/heimdal/lib/krb5/pac.c @@ -882,6 +882,7 @@ verify_logonname(krb5_context context, } ret = krb5_storage_read(sp, s, len); if (ret != len) { + free(s); krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name"); return EINVAL; @@ -894,8 +895,10 @@ verify_logonname(krb5_context context, unsigned int flags = WIND_RW_LE; ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); - if (ucs2 == NULL) + if (ucs2 == NULL) { + free(s); return krb5_enomem(context); + } ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); free(s); diff --git a/third_party/heimdal/lib/krb5/pkinit.c b/third_party/heimdal/lib/krb5/pkinit.c index c9a6e3e8f8b..0501728d3e5 100644 --- a/third_party/heimdal/lib/krb5/pkinit.c +++ b/third_party/heimdal/lib/krb5/pkinit.c @@ -109,7 +109,7 @@ integer_to_BN(krb5_context context, const char *field, const heim_integer *f) } static krb5_error_code -select_dh_group(krb5_context context, DH *dh, unsigned long bits, +select_dh_group(krb5_context context, DH *dh, unsigned long min_bits, struct krb5_dh_moduli **moduli) { const struct krb5_dh_moduli *m; @@ -118,25 +118,25 @@ select_dh_group(krb5_context context, DH *dh, unsigned long bits, krb5_set_error_message(context, EINVAL, N_("Did not find a DH group parameter " "matching requirement of %lu bits", ""), - bits); + min_bits); return EINVAL; } - if (bits == 0) { + if (min_bits == 0) { m = moduli[1]; /* XXX */ if (m == NULL) m = moduli[0]; /* XXX */ } else { int i; for (i = 0; moduli[i] != NULL; i++) { - if (bits < moduli[i]->bits) + if (moduli[i]->bits >= min_bits) break; } if (moduli[i] == NULL) { krb5_set_error_message(context, EINVAL, N_("Did not find a DH group parameter " "matching requirement of %lu bits", ""), - bits); + min_bits); return EINVAL; } m = moduli[i]; @@ -2164,7 +2164,7 @@ static const char *default_moduli_rfc3526_MODP_group14 = /* name */ "rfc3526-MODP-group14 " /* bits */ - "1760 " + "2048 " /* p */ "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" diff --git a/third_party/heimdal/lib/krb5/send_to_kdc.c b/third_party/heimdal/lib/krb5/send_to_kdc.c index 086f2edcd5d..a854e5c4ae9 100644 --- a/third_party/heimdal/lib/krb5/send_to_kdc.c +++ b/third_party/heimdal/lib/krb5/send_to_kdc.c @@ -1192,7 +1192,7 @@ krb5_sendto_context(krb5_context context, break; } action = KRB5_SENDTO_KRBHST; - fallthrough; + HEIM_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; + HEIM_FALLTHROUGH; case KRB5_SENDTO_TIMEOUT: /* diff --git a/third_party/heimdal/lib/krb5/store.c b/third_party/heimdal/lib/krb5/store.c index 79f8e3adbab..8b966f83e79 100644 --- a/third_party/heimdal/lib/krb5/store.c +++ b/third_party/heimdal/lib/krb5/store.c @@ -1002,6 +1002,8 @@ krb5_ret_string(krb5_storage *sp, { int ret; krb5_data data; + + *string = NULL; ret = krb5_ret_data(sp, &data); if(ret) return ret; diff --git a/third_party/heimdal/lib/libedit/config.h.in b/third_party/heimdal/lib/libedit/config.h.in index 059e5abc6a4..a9dbc475598 100644 --- a/third_party/heimdal/lib/libedit/config.h.in +++ b/third_party/heimdal/lib/libedit/config.h.in @@ -48,8 +48,8 @@ /* Define to 1 if you have the <limits.h> header file. */ #undef HAVE_LIMITS_H -/* Define to 1 if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H +/* Define to 1 if you have the <minix/config.h> header file. */ +#undef HAVE_MINIX_CONFIG_H /* Define to 1 if you have the <ncurses.h> header file. */ #undef HAVE_NCURSES_H @@ -67,6 +67,9 @@ /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H @@ -120,6 +123,9 @@ /* Define to 1 if you have the <vfork.h> header file. */ #undef HAVE_VFORK_H +/* Define to 1 if you have the <wchar.h> header file. */ +#undef HAVE_WCHAR_H + /* Define to 1 if you have the `wcsdup' function. */ #undef HAVE_WCSDUP @@ -160,48 +166,106 @@ /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# undef _DARWIN_C_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif -/* Enable threading extensions on Solaris. */ +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# undef _HPUX_ALT_XOPEN_SOCKET_API +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +# undef _MINIX +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# undef _NETBSD_SOURCE +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# undef _OPENBSD_SOURCE +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +# undef _POSIX_SOURCE +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +# undef _POSIX_1_SOURCE +#endif +/* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# undef __STDC_WANT_IEC_60559_BFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# undef __STDC_WANT_IEC_60559_DFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# undef __STDC_WANT_IEC_60559_TYPES_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# undef __STDC_WANT_LIB_EXT2__ +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# undef __STDC_WANT_MATH_SPEC_FUNCS__ +#endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +# undef _XOPEN_SOURCE #endif /* Version number of package */ #undef VERSION -/* Define to 1 if on MINIX. */ -#undef _MINIX - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -#undef _POSIX_1_SOURCE - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -#undef _POSIX_SOURCE - /* Define to empty if `const' does not conform to ANSI C. */ #undef const -/* Define to `int' if <sys/types.h> does not define. */ +/* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to `unsigned int' if <sys/types.h> does not define. */ diff --git a/third_party/heimdal/lib/ntlm/digest.c b/third_party/heimdal/lib/ntlm/digest.c index 761e1f497fc..42c39ff23e1 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; + HEIM_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 d75752ea000..7384e18076f 100644 --- a/third_party/heimdal/lib/ntlm/ntlm.c +++ b/third_party/heimdal/lib/ntlm/ntlm.c @@ -682,7 +682,7 @@ heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data) krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); CHECK_SIZE(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); - CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); + CHECK(ct_memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); CHECK(krb5_ret_uint32(in, &type), 0); CHECK(type, 1); CHECK(krb5_ret_uint32(in, &data->flags), 0); @@ -844,7 +844,7 @@ heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2) krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); CHECK_SIZE(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); - CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); + CHECK(ct_memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); CHECK(krb5_ret_uint32(in, &type), 0); CHECK(type, 2); @@ -1001,7 +1001,7 @@ heim_ntlm_decode_type3(const struct ntlm_buf *buf, krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE); CHECK_SIZE(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig)); - CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); + CHECK(ct_memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0); CHECK(krb5_ret_uint32(in, &type), 0); CHECK(type, 3); CHECK(ret_sec_buffer(in, &lm), 0); @@ -1825,7 +1825,7 @@ verify_ntlm2(const void *key, size_t len, if (ret) goto out; - if (memcmp(serveranswer, clientanswer, 16) != 0) { + if (ct_memcmp(serveranswer, clientanswer, 16) != 0) { heim_ntlm_free_buf(infotarget); return HNTLM_ERR_AUTH; } diff --git a/third_party/heimdal/lib/otp/otp_verify.c b/third_party/heimdal/lib/otp/otp_verify.c index 8a1c743cc83..373f9295a5e 100644 --- a/third_party/heimdal/lib/otp/otp_verify.c +++ b/third_party/heimdal/lib/otp/otp_verify.c @@ -49,7 +49,7 @@ otp_verify_user_1 (OtpContext *ctx, const char *passwd) } memcpy (key2, key1, sizeof(key1)); ctx->alg->next (key2); - if (memcmp (ctx->key, key2, sizeof(key2)) == 0) { + if (ct_memcmp (ctx->key, key2, sizeof(key2)) == 0) { --ctx->n; memcpy (ctx->key, key1, sizeof(key1)); return 0; diff --git a/third_party/heimdal/lib/roken/Makefile.am b/third_party/heimdal/lib/roken/Makefile.am index 35d753204e7..f6d038f3f6e 100644 --- a/third_party/heimdal/lib/roken/Makefile.am +++ b/third_party/heimdal/lib/roken/Makefile.am @@ -201,7 +201,7 @@ libroken_la_LIBADD = @LTLIBOBJS@ $(LIB_crypt) $(LIB_pidfile) $(LTLIBOBJS) $(libroken_la_OBJECTS): roken.h $(XHEADERS) -BUILT_SOURCES = roken.h $(err_h) $(fnmatch_h) $(ifadds_h) $(search_h) $(vis_h) +BUILT_SOURCES = roken.h $(err_h) $(fnmatch_h) $(ifaddrs_h) $(search_h) $(vis_h) ## these are controlled by configure XHEADERS = $(err_h) $(fnmatch_h) $(ifaddrs_h) $(search_h) $(vis_h) diff --git a/third_party/heimdal/lib/roken/base32.c b/third_party/heimdal/lib/roken/base32.c index ef74336d70a..4ec86ae90f1 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] = '='; HEIM_FALLTHROUGH; + case 3: p[4] = '='; HEIM_FALLTHROUGH; + case 2: p[5] = p[6] = '='; HEIM_FALLTHROUGH; + case 1: p[7] = '='; HEIM_FALLTHROUGH; default: break; } p += 8; diff --git a/third_party/heimdal/lib/roken/dirent-test.c b/third_party/heimdal/lib/roken/dirent-test.c index dc4518ad5b0..2c6b5055be7 100644 --- a/third_party/heimdal/lib/roken/dirent-test.c +++ b/third_party/heimdal/lib/roken/dirent-test.c @@ -148,7 +148,7 @@ int teardown_test(void) strcmp(dirname + len + 1 - sizeof(TESTDIR)/sizeof(char), TESTDIR) == 0) { - fallthrough; + HEIM_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; + HEIM_FALLTHROUGH; } } else { return -1; diff --git a/third_party/heimdal/lib/roken/fnmatch.c b/third_party/heimdal/lib/roken/fnmatch.c index 74f35283d35..34da19f2cb1 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; + HEIM_FALLTHROUGH; default: if (c != *string++) return (FNM_NOMATCH); diff --git a/third_party/heimdal/lib/roken/getaddrinfo.c b/third_party/heimdal/lib/roken/getaddrinfo.c index 12a26a71225..47affba59f5 100644 --- a/third_party/heimdal/lib/roken/getaddrinfo.c +++ b/third_party/heimdal/lib/roken/getaddrinfo.c @@ -188,7 +188,7 @@ get_null (const struct addrinfo *hints, struct addrinfo *first = NULL; struct addrinfo **current = &first; int family = PF_UNSPEC; - int ret; + int ret = EAI_FAMILY; if (hints != NULL) family = hints->ai_family; @@ -216,7 +216,7 @@ get_null (const struct addrinfo *hints, ¤t, const_v4, &v4_addr, NULL); } *res = first; - return 0; + return ret; } static int diff --git a/third_party/heimdal/lib/roken/getuserinfo.c b/third_party/heimdal/lib/roken/getuserinfo.c index 7fd2ca9f151..09f4c73155a 100644 --- a/third_party/heimdal/lib/roken/getuserinfo.c +++ b/third_party/heimdal/lib/roken/getuserinfo.c @@ -136,7 +136,7 @@ roken_get_homedir(char *home, size_t homesz) } return home; } - fallthrough; + HEIM_FALLTHROUGH; #else #ifdef HAVE_GETPWNAM_R size_t buflen = 2048; diff --git a/third_party/heimdal/lib/roken/parse_units.c b/third_party/heimdal/lib/roken/parse_units.c index d76578abfe0..017eedf376b 100644 --- a/third_party/heimdal/lib/roken/parse_units.c +++ b/third_party/heimdal/lib/roken/parse_units.c @@ -275,8 +275,7 @@ acc_flags(uint64_t res, int64_t val, uint64_t mult) } ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL -parse_flags (const char *s, const struct units *units, - int orig) +parse_flags(const char *s, const struct units *units, uint64_t orig) { return parse_something_unsigned (s, units, NULL, acc_flags, orig, 1); } diff --git a/third_party/heimdal/lib/roken/parse_units.h b/third_party/heimdal/lib/roken/parse_units.h index c5b6f2030a8..d17897dda60 100644 --- a/third_party/heimdal/lib/roken/parse_units.h +++ b/third_party/heimdal/lib/roken/parse_units.h @@ -97,8 +97,8 @@ ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL print_units_table (const struct units *units, FILE *f); ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL -parse_flags (const char *s, const struct units *units, - int orig); +parse_flags(const char *s, const struct units *units, + uint64_t orig); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL unparse_units(int64_t num, const struct units *units, char *s, size_t len); diff --git a/third_party/heimdal/lib/roken/snprintf.c b/third_party/heimdal/lib/roken/snprintf.c index 3da48962ee3..c8afedb2620 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; + HEIM_FALLTHROUGH; case '%' : (*state->append_char)(state, c); ++len; diff --git a/third_party/heimdal/lib/roken/strftime.c b/third_party/heimdal/lib/roken/strftime.c index 9a951dd3008..7be930755ca 100644 --- a/third_party/heimdal/lib/roken/strftime.c +++ b/third_party/heimdal/lib/roken/strftime.c @@ -377,7 +377,7 @@ strftime (char *buf, size_t maxsize, const char *format, break; case '\0' : --format; - fallthrough; + HEIM_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 86216d2d6dc..b9345c08323 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; + HEIM_FALLTHROUGH; case '%' : if (*buf == '%') ++buf; diff --git a/third_party/heimdal/lib/sl/slc-gram.y b/third_party/heimdal/lib/sl/slc-gram.y index 38045c10048..eed7fc10f04 100644 --- a/third_party/heimdal/lib/sl/slc-gram.y +++ b/third_party/heimdal/lib/sl/slc-gram.y @@ -686,7 +686,7 @@ gen_wrapper(struct assignment *as) (*th->free)(s); free(s); } - cprint(1, "return 0;\n"); + cprint(1, "return 1;\n"); cprint(0, "}\n"); cprint(0, "\n"); free(n); diff --git a/third_party/heimdal/lib/wind/utf8.c b/third_party/heimdal/lib/wind/utf8.c index 452b7b260d8..4559109f3fd 100644 --- a/third_party/heimdal/lib/wind/utf8.c +++ b/third_party/heimdal/lib/wind/utf8.c @@ -205,18 +205,18 @@ 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; + HEIM_FALLTHROUGH; case 3: out[2] = (ch | 0x80) & 0xbf; ch = ch >> 6; - fallthrough; + HEIM_FALLTHROUGH; case 2: out[1] = (ch | 0x80) & 0xbf; ch = ch >> 6; - fallthrough; + HEIM_FALLTHROUGH; case 1: out[0] = ch | first_char[len - 1]; - fallthrough; + HEIM_FALLTHROUGH; default: break; } @@ -486,14 +486,14 @@ 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; + HEIM_FALLTHROUGH; case 2: out[1] = (ch | 0x80) & 0xbf; ch = ch >> 6; - fallthrough; + HEIM_FALLTHROUGH; case 1: out[0] = ch | first_char[len - 1]; - fallthrough; + HEIM_FALLTHROUGH; default: break; } |