cf/largefile.m4: Fix build with autoconf-2.72
[heimdal.git] / admin / add.c
blob5f3d584590439a7224eaa4121a82f9dae01f5d6c
1 /*
2 * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "ktutil_locl.h"
35 #include <heimbase.h>
36 #include <base64.h>
38 RCSID("$Id$");
40 static char *
41 readstring(const char *prompt, char *buf, size_t len)
43 printf("%s", prompt);
44 if (fgets(buf, len, stdin) == NULL)
45 return NULL;
46 buf[strcspn(buf, "\r\n")] = '\0';
47 return buf;
50 int
51 kt_add(struct add_options *opt, int argc, char **argv)
53 krb5_error_code ret;
54 krb5_keytab keytab;
55 krb5_keytab_entry entry;
56 char buf[1024];
57 krb5_enctype enctype;
59 if((keytab = ktutil_open_keytab()) == NULL)
60 return 1;
62 memset(&entry, 0, sizeof(entry));
63 if(opt->principal_string == NULL) {
64 if(readstring("Principal: ", buf, sizeof(buf)) == NULL)
65 return 1;
66 opt->principal_string = buf;
68 ret = krb5_parse_name(context, opt->principal_string, &entry.principal);
69 if(ret) {
70 krb5_warn(context, ret, "%s", opt->principal_string);
71 goto out;
73 if(opt->enctype_string == NULL) {
74 if(readstring("Encryption type: ", buf, sizeof(buf)) == NULL) {
75 ret = 1;
76 goto out;
78 opt->enctype_string = buf;
80 ret = krb5_string_to_enctype(context, opt->enctype_string, &enctype);
81 if(ret) {
82 int t;
83 if(sscanf(opt->enctype_string, "%d", &t) == 1)
84 enctype = t;
85 else {
86 krb5_warn(context, ret, "%s", opt->enctype_string);
87 goto out;
90 if(opt->kvno_integer == -1) {
91 if(readstring("Key version: ", buf, sizeof(buf)) == NULL) {
92 ret = 1;
93 goto out;
95 if(sscanf(buf, "%u", &opt->kvno_integer) != 1)
96 goto out;
98 if(opt->password_string == NULL && opt->random_flag == 0) {
99 if(UI_UTIL_read_pw_string(buf, sizeof(buf), "Password: ",
100 UI_UTIL_FLAG_VERIFY)) {
101 ret = 1;
102 goto out;
104 opt->password_string = buf;
106 if(opt->password_string) {
107 if (opt->hex_flag) {
108 size_t len;
109 void *data;
111 len = (strlen(opt->password_string) + 1) / 2;
113 data = malloc(len);
114 if (data == NULL) {
115 krb5_warn(context, ENOMEM, "malloc");
116 goto out;
119 if ((size_t)hex_decode(opt->password_string, data, len) != len) {
120 free(data);
121 krb5_warn(context, ENOMEM, "hex decode failed");
122 goto out;
125 ret = krb5_keyblock_init(context, enctype,
126 data, len, &entry.keyblock);
127 free(data);
128 } else if (!opt->salt_flag) {
129 krb5_salt salt;
130 krb5_data pw;
132 salt.salttype = KRB5_PW_SALT;
133 salt.saltvalue.data = NULL;
134 salt.saltvalue.length = 0;
135 pw.data = (void*)opt->password_string;
136 pw.length = strlen(opt->password_string);
137 ret = krb5_string_to_key_data_salt(context, enctype, pw, salt,
138 &entry.keyblock);
139 } else {
140 ret = krb5_string_to_key(context, enctype, opt->password_string,
141 entry.principal, &entry.keyblock);
143 memset (opt->password_string, 0, strlen(opt->password_string));
144 } else {
145 ret = krb5_generate_random_keyblock(context, enctype, &entry.keyblock);
147 if(ret) {
148 krb5_warn(context, ret, "add");
149 goto out;
151 entry.vno = opt->kvno_integer;
152 entry.timestamp = time (NULL);
153 ret = krb5_kt_add_entry(context, keytab, &entry);
154 if(ret)
155 krb5_warn(context, ret, "add");
156 out:
157 krb5_kt_free_entry(context, &entry);
158 if (ret == 0) {
159 ret = krb5_kt_close(context, keytab);
160 if (ret)
161 krb5_warn(context, ret, "Could not write the keytab");
162 } else {
163 krb5_kt_close(context, keytab);
165 return ret != 0;
168 /* We might be reading from a pipe, so we can't use rk_undumpdata() */
169 static char *
170 read_file(FILE *f)
172 size_t alloced;
173 size_t len = 0;
174 size_t bytes;
175 char *res, *end, *p;
177 if ((res = malloc(1024)) == NULL)
178 err(1, "Out of memory");
179 alloced = 1024;
181 end = res + alloced;
182 p = res;
183 do {
184 if (p == end) {
185 char *tmp;
187 if ((tmp = realloc(res, alloced + (alloced > 1))) == NULL)
188 err(1, "Out of memory");
189 alloced += alloced > 1;
190 p = tmp + len;
191 res = tmp;
192 end = res + alloced;
194 bytes = fread(p, 1, end - p, f);
195 len += bytes;
196 p += bytes;
197 } while (bytes && !feof(f) && !ferror(f));
199 if (ferror(f))
200 errx(1, "Could not read all input");
201 if (p == end) {
202 char *tmp;
204 if ((tmp = strndup(res, len)) == NULL)
205 err(1, "Out of memory");
206 free(res);
207 res = tmp;
209 if (strlen(res) != len)
210 err(1, "Embedded NULs in input!");
211 return res;
214 static void
215 json2keytab_entry(heim_dict_t d, krb5_keytab kt, size_t idx)
217 krb5_keytab_entry e;
218 krb5_error_code ret;
219 heim_object_t v;
220 uint64_t u;
221 int64_t i;
222 char *buf = NULL;
224 memset(&e, 0, sizeof(e));
226 v = heim_dict_get_value(d, HSTR("timestamp"));
227 if (heim_get_tid(v) != HEIM_TID_NUMBER)
228 goto bad;
229 u = heim_number_get_long(v);
230 e.timestamp = u;
231 if (u != (uint64_t)e.timestamp)
232 goto bad;
234 v = heim_dict_get_value(d, HSTR("kvno"));
235 if (heim_get_tid(v) != HEIM_TID_NUMBER)
236 goto bad;
237 i = heim_number_get_long(v);
238 e.vno = i;
239 if (i != (int64_t)e.vno)
240 goto bad;
242 v = heim_dict_get_value(d, HSTR("enctype_number"));
243 if (heim_get_tid(v) != HEIM_TID_NUMBER)
244 goto bad;
245 i = heim_number_get_long(v);
246 e.keyblock.keytype = i;
247 if (i != (int64_t)e.keyblock.keytype)
248 goto bad;
250 v = heim_dict_get_value(d, HSTR("key"));
251 if (heim_get_tid(v) != HEIM_TID_STRING)
252 goto bad;
254 const char *s = heim_string_get_utf8(v);
255 int declen;
257 if ((buf = malloc(strlen(s))) == NULL)
258 err(1, "Out of memory");
259 declen = rk_base64_decode(s, buf);
260 if (declen < 0)
261 goto bad;
262 e.keyblock.keyvalue.data = buf;
263 e.keyblock.keyvalue.length = declen;
266 v = heim_dict_get_value(d, HSTR("principal"));
267 if (heim_get_tid(v) != HEIM_TID_STRING)
268 goto bad;
269 ret = krb5_parse_name(context, heim_string_get_utf8(v), &e.principal);
270 if (ret == 0)
271 ret = krb5_kt_add_entry(context, kt, &e);
273 /* For now, ignore aliases; besides, they're never set anywhere in-tree */
275 if (ret)
276 krb5_warn(context, ret,
277 "Could not parse or write keytab entry %lu",
278 (unsigned long)idx);
279 bad:
280 krb5_free_principal(context, e.principal);
281 free(buf);
285 kt_import(void *opt, int argc, char **argv)
287 krb5_error_code ret;
288 krb5_keytab kt;
289 heim_object_t o;
290 heim_error_t json_err = NULL;
291 heim_json_flags_t flags = HEIM_JSON_F_STRICT;
292 FILE *f = argc == 0 ? stdin : fopen(argv[0], "r");
293 size_t alen, i;
294 char *json;
296 if (f == NULL)
297 err(1, "Could not open file %s", argv[0]);
299 json = read_file(f);
300 fclose(f);
301 o = heim_json_create(json, 10, flags, &json_err);
302 free(json);
303 if (o == NULL) {
304 if (json_err != NULL) {
305 o = heim_error_copy_string(json_err);
306 if (o)
307 errx(1, "Could not parse JSON: %s", heim_string_get_utf8(o));
309 errx(1, "Could not parse JSON");
312 if (heim_get_tid(o) != HEIM_TID_ARRAY)
313 errx(1, "JSON text must be an array");
315 alen = heim_array_get_length(o);
316 if (alen == 0)
317 errx(1, "Empty JSON array; not overwriting keytab");
319 if ((kt = ktutil_open_keytab()) == NULL)
320 err(1, "Could not open keytab");
322 for (i = 0; i < alen; i++) {
323 heim_object_t e = heim_array_get_value(o, i);
325 if (heim_get_tid(e) != HEIM_TID_DICT)
326 warnx("Element %ld of JSON text array is not an object", (long)i);
327 else
328 json2keytab_entry(heim_array_get_value(o, i), kt, i);
330 ret = krb5_kt_close(context, kt);
331 if (ret)
332 krb5_warn(context, ret, "Could not write the keytab");
333 return ret != 0;