155682Smarkm/* 2178825Sdfr * Copyright (c) 1997-2005 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "ktutil_locl.h" 3555682Smarkm 36178825SdfrRCSID("$Id: change.c 15578 2005-07-07 20:44:48Z lha $"); 3755682Smarkm 38178825Sdfrstatic krb5_error_code 39178825Sdfrchange_entry (krb5_keytab keytab, 40120945Snectar krb5_principal principal, krb5_kvno kvno, 4155682Smarkm const char *realm, const char *admin_server, int server_port) 4255682Smarkm{ 4355682Smarkm krb5_error_code ret; 4455682Smarkm kadm5_config_params conf; 4555682Smarkm void *kadm_handle; 4655682Smarkm char *client_name; 4755682Smarkm krb5_keyblock *keys; 4855682Smarkm int num_keys; 4955682Smarkm int i; 5055682Smarkm 51120945Snectar ret = krb5_unparse_name (context, principal, &client_name); 5255682Smarkm if (ret) { 5378527Sassar krb5_warn (context, ret, "krb5_unparse_name"); 54178825Sdfr return ret; 5555682Smarkm } 5655682Smarkm 5755682Smarkm memset (&conf, 0, sizeof(conf)); 5855682Smarkm 59178825Sdfr if(realm == NULL) 60178825Sdfr realm = krb5_principal_get_realm(context, principal); 61178825Sdfr conf.realm = strdup(realm); 62178825Sdfr if (conf.realm == NULL) { 63178825Sdfr free (client_name); 64178825Sdfr krb5_set_error_string(context, "malloc failed"); 65178825Sdfr return ENOMEM; 66178825Sdfr } 6755682Smarkm conf.mask |= KADM5_CONFIG_REALM; 6855682Smarkm 6955682Smarkm if (admin_server) { 70178825Sdfr conf.admin_server = strdup(admin_server); 71178825Sdfr if (conf.admin_server == NULL) { 72178825Sdfr free(client_name); 73178825Sdfr free(conf.realm); 74178825Sdfr krb5_set_error_string(context, "malloc failed"); 75178825Sdfr return ENOMEM; 76178825Sdfr } 7755682Smarkm conf.mask |= KADM5_CONFIG_ADMIN_SERVER; 7855682Smarkm } 7955682Smarkm 8055682Smarkm if (server_port) { 8155682Smarkm conf.kadmind_port = htons(server_port); 8255682Smarkm conf.mask |= KADM5_CONFIG_KADMIND_PORT; 8355682Smarkm } 8455682Smarkm 8555682Smarkm ret = kadm5_init_with_skey_ctx (context, 8655682Smarkm client_name, 8755682Smarkm keytab_string, 8855682Smarkm KADM5_ADMIN_SERVICE, 8955682Smarkm &conf, 0, 0, 9055682Smarkm &kadm_handle); 91178825Sdfr free(conf.admin_server); 92178825Sdfr free(conf.realm); 9355682Smarkm if (ret) { 94178825Sdfr krb5_warn (context, ret, 95178825Sdfr "kadm5_c_init_with_skey_ctx: %s:", client_name); 96178825Sdfr free (client_name); 97178825Sdfr return ret; 9855682Smarkm } 99120945Snectar ret = kadm5_randkey_principal (kadm_handle, principal, &keys, &num_keys); 10055682Smarkm kadm5_destroy (kadm_handle); 10155682Smarkm if (ret) { 102178825Sdfr krb5_warn(context, ret, "kadm5_randkey_principal: %s:", client_name); 103178825Sdfr free (client_name); 104178825Sdfr return ret; 10555682Smarkm } 106178825Sdfr free (client_name); 10755682Smarkm for (i = 0; i < num_keys; ++i) { 10855682Smarkm krb5_keytab_entry new_entry; 10955682Smarkm 110120945Snectar new_entry.principal = principal; 11155682Smarkm new_entry.timestamp = time (NULL); 112120945Snectar new_entry.vno = kvno + 1; 11355682Smarkm new_entry.keyblock = keys[i]; 11455682Smarkm 11555682Smarkm ret = krb5_kt_add_entry (context, keytab, &new_entry); 11655682Smarkm if (ret) 11755682Smarkm krb5_warn (context, ret, "krb5_kt_add_entry"); 11855682Smarkm krb5_free_keyblock_contents (context, &keys[i]); 11955682Smarkm } 120178825Sdfr return ret; 12155682Smarkm} 12255682Smarkm 12355682Smarkm/* 12455682Smarkm * loop over all the entries in the keytab (or those given) and change 12555682Smarkm * their keys, writing the new keys 12655682Smarkm */ 12755682Smarkm 128120945Snectarstruct change_set { 129120945Snectar krb5_principal principal; 130120945Snectar krb5_kvno kvno; 131120945Snectar}; 132120945Snectar 13355682Smarkmint 134178825Sdfrkt_change (struct change_options *opt, int argc, char **argv) 13555682Smarkm{ 13655682Smarkm krb5_error_code ret; 13778527Sassar krb5_keytab keytab; 13855682Smarkm krb5_kt_cursor cursor; 13955682Smarkm krb5_keytab_entry entry; 140120945Snectar int i, j, max; 141120945Snectar struct change_set *changeset; 142178825Sdfr int errors = 0; 14355682Smarkm 14490926Snectar if((keytab = ktutil_open_keytab()) == NULL) 14578527Sassar return 1; 14678527Sassar 14755682Smarkm j = 0; 148120945Snectar max = 0; 149120945Snectar changeset = NULL; 15055682Smarkm 15155682Smarkm ret = krb5_kt_start_seq_get(context, keytab, &cursor); 15255682Smarkm if(ret){ 153178825Sdfr krb5_warn(context, ret, "%s", keytab_string); 15478527Sassar goto out; 15555682Smarkm } 15655682Smarkm 15755682Smarkm while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) { 158120945Snectar int add = 0; 15955682Smarkm 160120945Snectar for (i = 0; i < j; ++i) { 161120945Snectar if (krb5_principal_compare (context, changeset[i].principal, 162120945Snectar entry.principal)) { 163120945Snectar if (changeset[i].kvno < entry.vno) 164120945Snectar changeset[i].kvno = entry.vno; 16555682Smarkm break; 166120945Snectar } 167120945Snectar } 168178825Sdfr if (i < j) { 169178825Sdfr krb5_kt_free_entry (context, &entry); 17055682Smarkm continue; 171178825Sdfr } 17255682Smarkm 173178825Sdfr if (argc == 0) { 174120945Snectar add = 1; 17555682Smarkm } else { 176178825Sdfr for (i = 0; i < argc; ++i) { 17755682Smarkm krb5_principal princ; 17855682Smarkm 17955682Smarkm ret = krb5_parse_name (context, argv[i], &princ); 18055682Smarkm if (ret) { 181178825Sdfr krb5_warn (context, ret, "%s", argv[i]); 18255682Smarkm continue; 18355682Smarkm } 184120945Snectar if (krb5_principal_compare (context, princ, entry.principal)) 185120945Snectar add = 1; 186120945Snectar 18755682Smarkm krb5_free_principal (context, princ); 18855682Smarkm } 18955682Smarkm } 190120945Snectar 191120945Snectar if (add) { 19255682Smarkm if (j >= max) { 19355682Smarkm void *tmp; 19455682Smarkm 195120945Snectar max = max(max * 2, 1); 196120945Snectar tmp = realloc (changeset, max * sizeof(*changeset)); 19755682Smarkm if (tmp == NULL) { 19855682Smarkm krb5_kt_free_entry (context, &entry); 19955682Smarkm krb5_warnx (context, "realloc: out of memory"); 200120945Snectar ret = ENOMEM; 20155682Smarkm break; 20255682Smarkm } 203120945Snectar changeset = tmp; 20455682Smarkm } 205120945Snectar ret = krb5_copy_principal (context, entry.principal, 206120945Snectar &changeset[j].principal); 20755682Smarkm if (ret) { 20855682Smarkm krb5_warn (context, ret, "krb5_copy_principal"); 20955682Smarkm krb5_kt_free_entry (context, &entry); 21055682Smarkm break; 21155682Smarkm } 212120945Snectar changeset[j].kvno = entry.vno; 21355682Smarkm ++j; 21455682Smarkm } 21555682Smarkm krb5_kt_free_entry (context, &entry); 21655682Smarkm } 217178825Sdfr krb5_kt_end_seq_get(context, keytab, &cursor); 218120945Snectar 219120945Snectar if (ret == KRB5_KT_END) { 220178825Sdfr ret = 0; 221120945Snectar for (i = 0; i < j; i++) { 222120945Snectar if (verbose_flag) { 223120945Snectar char *client_name; 224120945Snectar 225120945Snectar ret = krb5_unparse_name (context, changeset[i].principal, 226120945Snectar &client_name); 227120945Snectar if (ret) { 228120945Snectar krb5_warn (context, ret, "krb5_unparse_name"); 229120945Snectar } else { 230120945Snectar printf("Changing %s kvno %d\n", 231120945Snectar client_name, changeset[i].kvno); 232120945Snectar free(client_name); 233120945Snectar } 234120945Snectar } 235178825Sdfr ret = change_entry (keytab, 236178825Sdfr changeset[i].principal, changeset[i].kvno, 237178825Sdfr opt->realm_string, 238178825Sdfr opt->admin_server_string, 239178825Sdfr opt->server_port_integer); 240178825Sdfr if (ret != 0) 241178825Sdfr errors = 1; 242120945Snectar } 243178825Sdfr } else 244178825Sdfr errors = 1; 245120945Snectar for (i = 0; i < j; i++) 246120945Snectar krb5_free_principal (context, changeset[i].principal); 247120945Snectar free (changeset); 248120945Snectar 24978527Sassar out: 25078527Sassar krb5_kt_close(context, keytab); 251178825Sdfr return errors; 25255682Smarkm} 253