diff options
Diffstat (limited to 'third_party/heimdal/admin/add.c')
-rw-r--r-- | third_party/heimdal/admin/add.c | 178 |
1 files changed, 176 insertions, 2 deletions
diff --git a/third_party/heimdal/admin/add.c b/third_party/heimdal/admin/add.c index 13580b9bb57..5f1920ff8be 100644 --- a/third_party/heimdal/admin/add.c +++ b/third_party/heimdal/admin/add.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,6 +32,8 @@ */ #include "ktutil_locl.h" +#include <heimbase.h> +#include <base64.h> RCSID("$Id$"); @@ -153,6 +155,178 @@ kt_add(struct add_options *opt, int argc, char **argv) krb5_warn(context, ret, "add"); out: krb5_kt_free_entry(context, &entry); - krb5_kt_close(context, keytab); + if (ret == 0) { + ret = krb5_kt_close(context, keytab); + if (ret) + krb5_warn(context, ret, "Could not write the keytab"); + } else { + krb5_kt_close(context, keytab); + } + return ret != 0; +} + +/* We might be reading from a pipe, so we can't use rk_undumpdata() */ +static char * +read_file(FILE *f) +{ + size_t alloced; + size_t len = 0; + size_t bytes; + char *res, *end, *p; + + if ((res = malloc(1024)) == NULL) + err(1, "Out of memory"); + alloced = 1024; + + end = res + alloced; + p = res; + do { + if (p == end) { + char *tmp; + + if ((tmp = realloc(res, alloced + (alloced > 1))) == NULL) + err(1, "Out of memory"); + alloced += alloced > 1; + p = tmp + (p - res); + res = tmp; + end = res + alloced; + } + bytes = fread(p, 1, end - p, f); + len += bytes; + p += bytes; + } while (bytes && !feof(f) && !ferror(f)); + + if (ferror(f)) + errx(1, "Could not read all input"); + if (p == end) { + char *tmp; + + if ((tmp = strndup(res, len)) == NULL) + err(1, "Out of memory"); + free(res); + res = tmp; + } + if (strlen(res) != len) + err(1, "Embedded NULs in input!"); + return res; +} + +static void +json2keytab_entry(heim_dict_t d, krb5_keytab kt, size_t idx) +{ + krb5_keytab_entry e; + krb5_error_code ret; + heim_object_t v; + uint64_t u; + int64_t i; + char *buf = NULL; + + memset(&e, 0, sizeof(e)); + + v = heim_dict_get_value(d, HSTR("timestamp")); + if (heim_get_tid(v) != HEIM_TID_NUMBER) + goto bad; + u = heim_number_get_long(v); + e.timestamp = u; + if (u != (uint64_t)e.timestamp) + goto bad; + + v = heim_dict_get_value(d, HSTR("kvno")); + if (heim_get_tid(v) != HEIM_TID_NUMBER) + goto bad; + i = heim_number_get_long(v); + e.vno = i; + if (i != (int64_t)e.vno) + goto bad; + + v = heim_dict_get_value(d, HSTR("enctype_number")); + if (heim_get_tid(v) != HEIM_TID_NUMBER) + goto bad; + i = heim_number_get_long(v); + e.keyblock.keytype = i; + if (i != (int64_t)e.keyblock.keytype) + goto bad; + + v = heim_dict_get_value(d, HSTR("key")); + if (heim_get_tid(v) != HEIM_TID_STRING) + goto bad; + { + const char *s = heim_string_get_utf8(v); + int declen; + + if ((buf = malloc(strlen(s))) == NULL) + err(1, "Out of memory"); + declen = rk_base64_decode(s, buf); + if (declen < 0) + goto bad; + e.keyblock.keyvalue.data = buf; + e.keyblock.keyvalue.length = declen; + } + + v = heim_dict_get_value(d, HSTR("principal")); + if (heim_get_tid(v) != HEIM_TID_STRING) + goto bad; + ret = krb5_parse_name(context, heim_string_get_utf8(v), &e.principal); + if (ret == 0) + ret = krb5_kt_add_entry(context, kt, &e); + + /* For now, ignore aliases; besides, they're never set anywhere in-tree */ + + if (ret) + krb5_warn(context, ret, + "Could not parse or write keytab entry %lu", + (unsigned long)idx); +bad: + krb5_free_principal(context, e.principal); +} + +int +kt_import(void *opt, int argc, char **argv) +{ + krb5_error_code ret; + krb5_keytab kt; + heim_object_t o; + heim_error_t json_err = NULL; + heim_json_flags_t flags = HEIM_JSON_F_STRICT; + FILE *f = argc == 0 ? stdin : fopen(argv[0], "r"); + size_t alen, i; + char *json; + + if (f == NULL) + err(1, "Could not open file %s", argv[0]); + + json = read_file(f); + o = heim_json_create(json, 10, flags, &json_err); + free(json); + if (o == NULL) { + if (json_err != NULL) { + o = heim_error_copy_string(json_err); + if (o) + errx(1, "Could not parse JSON: %s", heim_string_get_utf8(o)); + } + errx(1, "Could not parse JSON"); + } + + if (heim_get_tid(o) != HEIM_TID_ARRAY) + errx(1, "JSON text must be an array"); + + alen = heim_array_get_length(o); + if (alen == 0) + errx(1, "Empty JSON array; not overwriting keytab"); + + if ((kt = ktutil_open_keytab()) == NULL) + err(1, "Could not open keytab"); + + for (i = 0; i < alen; i++) { + heim_object_t e = heim_array_get_value(o, i); + + if (heim_get_tid(e) != HEIM_TID_DICT) + warnx("Element %ld of JSON text array is not an object", (long)i); + else + json2keytab_entry(heim_array_get_value(o, i), kt, i); + } + ret = krb5_kt_close(context, kt); + if (ret) + krb5_warn(context, ret, "Could not write the keytab"); return ret != 0; } |