1 /* $NetBSD: ext.c,v 1.3 2023/06/19 21:41:41 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "kadmin_locl.h" 37 #include "kadmin-commands.h" 38 39 struct ext_keytab_data { 40 krb5_keytab keytab; 41 int random_key_flag; 42 }; 43 44 static int 45 do_ext_keytab(krb5_principal principal, void *data) 46 { 47 krb5_error_code ret; 48 kadm5_principal_ent_rec princ; 49 struct ext_keytab_data *e = data; 50 krb5_keytab_entry *keys = NULL; 51 krb5_keyblock *k = NULL; 52 size_t i; 53 int n_k = 0; 54 uint32_t mask; 55 char *unparsed = NULL; 56 57 mask = KADM5_PRINCIPAL; 58 if (!e->random_key_flag) 59 mask |= KADM5_KVNO | KADM5_KEY_DATA; 60 61 ret = kadm5_get_principal(kadm_handle, principal, &princ, mask); 62 if (ret) 63 return ret; 64 65 ret = krb5_unparse_name(context, principal, &unparsed); 66 if (ret) 67 goto out; 68 69 if (!e->random_key_flag) { 70 if (princ.n_key_data == 0) { 71 krb5_warnx(context, "principal has no keys, or user lacks " 72 "get-keys privilege for %s", unparsed); 73 goto out; 74 } 75 /* 76 * kadmin clients and servers from master between 1.5 and 1.6 77 * can have corrupted a principal's keys in the HDB. If some 78 * are bogus but not all are, then that must have happened. 79 * 80 * If all keys are bogus then the server may be a pre-1.6, 81 * post-1.5 server and the client lacks get-keys privilege, or 82 * the keys are corrupted. We can't tell here. 83 */ 84 if (kadm5_all_keys_are_bogus(princ.n_key_data, princ.key_data)) { 85 krb5_warnx(context, "user lacks get-keys privilege for %s", 86 unparsed); 87 goto out; 88 } 89 if (kadm5_some_keys_are_bogus(princ.n_key_data, princ.key_data)) { 90 krb5_warnx(context, "some keys for %s are corrupted in the HDB", 91 unparsed); 92 } 93 keys = calloc(sizeof(*keys), princ.n_key_data); 94 if (keys == NULL) { 95 ret = krb5_enomem(context); 96 goto out; 97 } 98 for (i = 0; i < princ.n_key_data; i++) { 99 krb5_key_data *kd = &princ.key_data[i]; 100 101 /* Don't extract bogus keys */ 102 if (kadm5_all_keys_are_bogus(1, kd)) 103 continue; 104 105 keys[i].principal = princ.principal; 106 keys[i].vno = kd->key_data_kvno; 107 keys[i].keyblock.keytype = kd->key_data_type[0]; 108 keys[i].keyblock.keyvalue.length = kd->key_data_length[0]; 109 keys[i].keyblock.keyvalue.data = kd->key_data_contents[0]; 110 keys[i].timestamp = time(NULL); 111 n_k++; 112 } 113 } else if (e->random_key_flag) { 114 ret = kadm5_randkey_principal(kadm_handle, principal, &k, &n_k); 115 if (ret) 116 goto out; 117 118 keys = calloc(sizeof(*keys), n_k); 119 if (keys == NULL) { 120 ret = krb5_enomem(context); 121 goto out; 122 } 123 for (i = 0; i < n_k; i++) { 124 keys[i].principal = principal; 125 keys[i].vno = princ.kvno + 1; /* XXX get entry again */ 126 keys[i].keyblock = k[i]; 127 keys[i].timestamp = time(NULL); 128 } 129 } 130 131 if (n_k == 0) 132 krb5_warn(context, ret, "no keys written to keytab for %s", unparsed); 133 134 for (i = 0; i < n_k; i++) { 135 ret = krb5_kt_add_entry(context, e->keytab, &keys[i]); 136 if (ret) 137 krb5_warn(context, ret, "krb5_kt_add_entry(%lu)", (unsigned long)i); 138 } 139 140 out: 141 kadm5_free_principal_ent(kadm_handle, &princ); 142 if (k) { 143 for (i = 0; i < n_k; i++) 144 memset(k[i].keyvalue.data, 0, k[i].keyvalue.length); 145 free(k); 146 } 147 free(unparsed); 148 free(keys); 149 return ret; 150 } 151 152 int 153 ext_keytab(struct ext_keytab_options *opt, int argc, char **argv) 154 { 155 krb5_error_code ret; 156 int i; 157 struct ext_keytab_data data; 158 159 if (opt->keytab_string == NULL) 160 ret = krb5_kt_default(context, &data.keytab); 161 else 162 ret = krb5_kt_resolve(context, opt->keytab_string, &data.keytab); 163 164 if(ret){ 165 krb5_warn(context, ret, "krb5_kt_resolve"); 166 return 1; 167 } 168 169 data.random_key_flag = opt->random_key_flag; 170 171 for(i = 0; i < argc; i++) { 172 ret = foreach_principal(argv[i], do_ext_keytab, "ext", &data); 173 if (ret) 174 break; 175 } 176 177 krb5_kt_close(context, data.keytab); 178 179 return ret != 0; 180 } 181