summaryrefslogtreecommitdiff
path: root/third_party/heimdal/admin/add.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/admin/add.c')
-rw-r--r--third_party/heimdal/admin/add.c178
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;
}