1 1.1 elric /* $NetBSD: change.c,v 1.3 2023/06/19 21:41:38 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 1997-2005 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #include "ktutil_locl.h" 37 1.1 elric 38 1.1 elric __RCSID("$NetBSD: change.c,v 1.3 2023/06/19 21:41:38 christos Exp $"); 39 1.1 elric 40 1.1 elric static krb5_error_code 41 1.1 elric change_entry (krb5_keytab keytab, 42 1.1 elric krb5_principal principal, krb5_kvno kvno, 43 1.1 elric const char *realm, const char *admin_server, int server_port) 44 1.1 elric { 45 1.1 elric krb5_error_code ret; 46 1.1 elric kadm5_config_params conf; 47 1.1 elric void *kadm_handle; 48 1.1 elric char *client_name; 49 1.1 elric krb5_keyblock *keys; 50 1.1 elric int num_keys; 51 1.1 elric int i; 52 1.1 elric 53 1.1 elric ret = krb5_unparse_name (context, principal, &client_name); 54 1.1 elric if (ret) { 55 1.1 elric krb5_warn (context, ret, "krb5_unparse_name"); 56 1.1 elric return ret; 57 1.1 elric } 58 1.1 elric 59 1.1 elric memset (&conf, 0, sizeof(conf)); 60 1.1 elric 61 1.1 elric if(realm == NULL) 62 1.1 elric realm = krb5_principal_get_realm(context, principal); 63 1.1 elric conf.realm = strdup(realm); 64 1.1 elric if (conf.realm == NULL) { 65 1.1 elric free (client_name); 66 1.1 elric krb5_set_error_message(context, ENOMEM, "malloc failed"); 67 1.1 elric return ENOMEM; 68 1.1 elric } 69 1.1 elric conf.mask |= KADM5_CONFIG_REALM; 70 1.1 elric 71 1.1 elric if (admin_server) { 72 1.1 elric conf.admin_server = strdup(admin_server); 73 1.1 elric if (conf.admin_server == NULL) { 74 1.1 elric free(client_name); 75 1.1 elric free(conf.realm); 76 1.1 elric krb5_set_error_message(context, ENOMEM, "malloc failed"); 77 1.1 elric return ENOMEM; 78 1.2 christos } 79 1.1 elric conf.mask |= KADM5_CONFIG_ADMIN_SERVER; 80 1.1 elric } 81 1.1 elric 82 1.1 elric if (server_port) { 83 1.1 elric conf.kadmind_port = htons(server_port); 84 1.1 elric conf.mask |= KADM5_CONFIG_KADMIND_PORT; 85 1.1 elric } 86 1.1 elric 87 1.1 elric ret = kadm5_init_with_skey_ctx (context, 88 1.1 elric client_name, 89 1.1 elric keytab_string, 90 1.1 elric KADM5_ADMIN_SERVICE, 91 1.1 elric &conf, 0, 0, 92 1.1 elric &kadm_handle); 93 1.1 elric free(conf.admin_server); 94 1.1 elric free(conf.realm); 95 1.1 elric if (ret) { 96 1.1 elric krb5_warn (context, ret, 97 1.1 elric "kadm5_c_init_with_skey_ctx: %s:", client_name); 98 1.1 elric free (client_name); 99 1.1 elric return ret; 100 1.1 elric } 101 1.1 elric ret = kadm5_randkey_principal (kadm_handle, principal, &keys, &num_keys); 102 1.1 elric kadm5_destroy (kadm_handle); 103 1.1 elric if (ret) { 104 1.1 elric krb5_warn(context, ret, "kadm5_randkey_principal: %s:", client_name); 105 1.1 elric free (client_name); 106 1.1 elric return ret; 107 1.1 elric } 108 1.1 elric free (client_name); 109 1.1 elric for (i = 0; i < num_keys; ++i) { 110 1.1 elric krb5_keytab_entry new_entry; 111 1.1 elric 112 1.1 elric new_entry.principal = principal; 113 1.1 elric new_entry.timestamp = time (NULL); 114 1.1 elric new_entry.vno = kvno + 1; 115 1.1 elric new_entry.keyblock = keys[i]; 116 1.1 elric 117 1.1 elric ret = krb5_kt_add_entry (context, keytab, &new_entry); 118 1.1 elric if (ret) 119 1.1 elric krb5_warn (context, ret, "krb5_kt_add_entry"); 120 1.1 elric krb5_free_keyblock_contents (context, &keys[i]); 121 1.1 elric } 122 1.1 elric return ret; 123 1.1 elric } 124 1.1 elric 125 1.1 elric /* 126 1.1 elric * loop over all the entries in the keytab (or those given) and change 127 1.1 elric * their keys, writing the new keys 128 1.1 elric */ 129 1.1 elric 130 1.1 elric struct change_set { 131 1.1 elric krb5_principal principal; 132 1.1 elric krb5_kvno kvno; 133 1.1 elric }; 134 1.1 elric 135 1.1 elric int 136 1.1 elric kt_change (struct change_options *opt, int argc, char **argv) 137 1.1 elric { 138 1.1 elric krb5_error_code ret; 139 1.1 elric krb5_keytab keytab; 140 1.1 elric krb5_kt_cursor cursor; 141 1.1 elric krb5_keytab_entry entry; 142 1.1 elric int i, j, max; 143 1.1 elric struct change_set *changeset; 144 1.1 elric int errors = 0; 145 1.1 elric 146 1.1 elric if((keytab = ktutil_open_keytab()) == NULL) 147 1.1 elric return 1; 148 1.1 elric 149 1.1 elric j = 0; 150 1.1 elric max = 0; 151 1.1 elric changeset = NULL; 152 1.1 elric 153 1.1 elric ret = krb5_kt_start_seq_get(context, keytab, &cursor); 154 1.1 elric if(ret){ 155 1.1 elric krb5_warn(context, ret, "%s", keytab_string); 156 1.1 elric goto out; 157 1.1 elric } 158 1.1 elric 159 1.1 elric while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) { 160 1.1 elric int add = 0; 161 1.1 elric 162 1.1 elric for (i = 0; i < j; ++i) { 163 1.1 elric if (krb5_principal_compare (context, changeset[i].principal, 164 1.1 elric entry.principal)) { 165 1.1 elric if (changeset[i].kvno < entry.vno) 166 1.1 elric changeset[i].kvno = entry.vno; 167 1.1 elric break; 168 1.1 elric } 169 1.1 elric } 170 1.1 elric if (i < j) { 171 1.1 elric krb5_kt_free_entry (context, &entry); 172 1.1 elric continue; 173 1.1 elric } 174 1.1 elric 175 1.1 elric if (argc == 0) { 176 1.1 elric add = 1; 177 1.1 elric } else { 178 1.1 elric for (i = 0; i < argc; ++i) { 179 1.1 elric krb5_principal princ; 180 1.1 elric 181 1.1 elric ret = krb5_parse_name (context, argv[i], &princ); 182 1.1 elric if (ret) { 183 1.1 elric krb5_warn (context, ret, "%s", argv[i]); 184 1.1 elric continue; 185 1.1 elric } 186 1.1 elric if (krb5_principal_compare (context, princ, entry.principal)) 187 1.1 elric add = 1; 188 1.1 elric 189 1.1 elric krb5_free_principal (context, princ); 190 1.1 elric } 191 1.1 elric } 192 1.1 elric 193 1.1 elric if (add) { 194 1.1 elric if (j >= max) { 195 1.1 elric void *tmp; 196 1.1 elric 197 1.1 elric max = max(max * 2, 1); 198 1.1 elric tmp = realloc (changeset, max * sizeof(*changeset)); 199 1.1 elric if (tmp == NULL) { 200 1.1 elric krb5_kt_free_entry (context, &entry); 201 1.1 elric krb5_warnx (context, "realloc: out of memory"); 202 1.1 elric ret = ENOMEM; 203 1.1 elric break; 204 1.1 elric } 205 1.1 elric changeset = tmp; 206 1.1 elric } 207 1.1 elric ret = krb5_copy_principal (context, entry.principal, 208 1.1 elric &changeset[j].principal); 209 1.1 elric if (ret) { 210 1.1 elric krb5_warn (context, ret, "krb5_copy_principal"); 211 1.1 elric krb5_kt_free_entry (context, &entry); 212 1.1 elric break; 213 1.1 elric } 214 1.1 elric changeset[j].kvno = entry.vno; 215 1.1 elric ++j; 216 1.1 elric } 217 1.1 elric krb5_kt_free_entry (context, &entry); 218 1.1 elric } 219 1.1 elric krb5_kt_end_seq_get(context, keytab, &cursor); 220 1.1 elric 221 1.1 elric if (ret == KRB5_KT_END) { 222 1.1 elric for (i = 0; i < j; i++) { 223 1.1 elric if (verbose_flag) { 224 1.1 elric char *client_name; 225 1.1 elric 226 1.1 elric ret = krb5_unparse_name (context, changeset[i].principal, 227 1.1 elric &client_name); 228 1.1 elric if (ret) { 229 1.1 elric krb5_warn (context, ret, "krb5_unparse_name"); 230 1.1 elric } else { 231 1.1 elric printf("Changing %s kvno %d\n", 232 1.1 elric client_name, changeset[i].kvno); 233 1.1 elric free(client_name); 234 1.1 elric } 235 1.1 elric } 236 1.1 elric ret = change_entry (keytab, 237 1.1 elric changeset[i].principal, changeset[i].kvno, 238 1.1 elric opt->realm_string, 239 1.1 elric opt->admin_server_string, 240 1.1 elric opt->server_port_integer); 241 1.1 elric if (ret != 0) 242 1.1 elric errors = 1; 243 1.1 elric } 244 1.1 elric } else 245 1.1 elric errors = 1; 246 1.1 elric for (i = 0; i < j; i++) 247 1.1 elric krb5_free_principal (context, changeset[i].principal); 248 1.1 elric free (changeset); 249 1.1 elric 250 1.1 elric out: 251 1.1 elric krb5_kt_close(context, keytab); 252 1.1 elric return errors; 253 1.1 elric } 254