2 * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 #include "ktutil_locl.h"
41 readstring(const char *prompt
, char *buf
, size_t len
)
44 if (fgets(buf
, len
, stdin
) == NULL
)
46 buf
[strcspn(buf
, "\r\n")] = '\0';
51 kt_add(struct add_options
*opt
, int argc
, char **argv
)
55 krb5_keytab_entry entry
;
59 if((keytab
= ktutil_open_keytab()) == NULL
)
62 memset(&entry
, 0, sizeof(entry
));
63 if(opt
->principal_string
== NULL
) {
64 if(readstring("Principal: ", buf
, sizeof(buf
)) == NULL
)
66 opt
->principal_string
= buf
;
68 ret
= krb5_parse_name(context
, opt
->principal_string
, &entry
.principal
);
70 krb5_warn(context
, ret
, "%s", opt
->principal_string
);
73 if(opt
->enctype_string
== NULL
) {
74 if(readstring("Encryption type: ", buf
, sizeof(buf
)) == NULL
) {
78 opt
->enctype_string
= buf
;
80 ret
= krb5_string_to_enctype(context
, opt
->enctype_string
, &enctype
);
83 if(sscanf(opt
->enctype_string
, "%d", &t
) == 1)
86 krb5_warn(context
, ret
, "%s", opt
->enctype_string
);
90 if(opt
->kvno_integer
== -1) {
91 if(readstring("Key version: ", buf
, sizeof(buf
)) == NULL
) {
95 if(sscanf(buf
, "%u", &opt
->kvno_integer
) != 1)
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
)) {
104 opt
->password_string
= buf
;
106 if(opt
->password_string
) {
111 len
= (strlen(opt
->password_string
) + 1) / 2;
115 krb5_warn(context
, ENOMEM
, "malloc");
119 if ((size_t)hex_decode(opt
->password_string
, data
, len
) != len
) {
121 krb5_warn(context
, ENOMEM
, "hex decode failed");
125 ret
= krb5_keyblock_init(context
, enctype
,
126 data
, len
, &entry
.keyblock
);
128 } else if (!opt
->salt_flag
) {
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
,
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
));
145 ret
= krb5_generate_random_keyblock(context
, enctype
, &entry
.keyblock
);
148 krb5_warn(context
, ret
, "add");
151 entry
.vno
= opt
->kvno_integer
;
152 entry
.timestamp
= time (NULL
);
153 ret
= krb5_kt_add_entry(context
, keytab
, &entry
);
155 krb5_warn(context
, ret
, "add");
157 krb5_kt_free_entry(context
, &entry
);
159 ret
= krb5_kt_close(context
, keytab
);
161 krb5_warn(context
, ret
, "Could not write the keytab");
163 krb5_kt_close(context
, keytab
);
168 /* We might be reading from a pipe, so we can't use rk_undumpdata() */
177 if ((res
= malloc(1024)) == NULL
)
178 err(1, "Out of memory");
187 if ((tmp
= realloc(res
, alloced
+ (alloced
> 1))) == NULL
)
188 err(1, "Out of memory");
189 alloced
+= alloced
> 1;
194 bytes
= fread(p
, 1, end
- p
, f
);
197 } while (bytes
&& !feof(f
) && !ferror(f
));
200 errx(1, "Could not read all input");
204 if ((tmp
= strndup(res
, len
)) == NULL
)
205 err(1, "Out of memory");
209 if (strlen(res
) != len
)
210 err(1, "Embedded NULs in input!");
215 json2keytab_entry(heim_dict_t d
, krb5_keytab kt
, size_t idx
)
224 memset(&e
, 0, sizeof(e
));
226 v
= heim_dict_get_value(d
, HSTR("timestamp"));
227 if (heim_get_tid(v
) != HEIM_TID_NUMBER
)
229 u
= heim_number_get_long(v
);
231 if (u
!= (uint64_t)e
.timestamp
)
234 v
= heim_dict_get_value(d
, HSTR("kvno"));
235 if (heim_get_tid(v
) != HEIM_TID_NUMBER
)
237 i
= heim_number_get_long(v
);
239 if (i
!= (int64_t)e
.vno
)
242 v
= heim_dict_get_value(d
, HSTR("enctype_number"));
243 if (heim_get_tid(v
) != HEIM_TID_NUMBER
)
245 i
= heim_number_get_long(v
);
246 e
.keyblock
.keytype
= i
;
247 if (i
!= (int64_t)e
.keyblock
.keytype
)
250 v
= heim_dict_get_value(d
, HSTR("key"));
251 if (heim_get_tid(v
) != HEIM_TID_STRING
)
254 const char *s
= heim_string_get_utf8(v
);
257 if ((buf
= malloc(strlen(s
))) == NULL
)
258 err(1, "Out of memory");
259 declen
= rk_base64_decode(s
, buf
);
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
)
269 ret
= krb5_parse_name(context
, heim_string_get_utf8(v
), &e
.principal
);
271 ret
= krb5_kt_add_entry(context
, kt
, &e
);
273 /* For now, ignore aliases; besides, they're never set anywhere in-tree */
276 krb5_warn(context
, ret
,
277 "Could not parse or write keytab entry %lu",
280 krb5_free_principal(context
, e
.principal
);
285 kt_import(void *opt
, int argc
, char **argv
)
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");
297 err(1, "Could not open file %s", argv
[0]);
301 o
= heim_json_create(json
, 10, flags
, &json_err
);
304 if (json_err
!= NULL
) {
305 o
= heim_error_copy_string(json_err
);
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
);
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
);
328 json2keytab_entry(heim_array_get_value(o
, i
), kt
, i
);
330 ret
= krb5_kt_close(context
, kt
);
332 krb5_warn(context
, ret
, "Could not write the keytab");