155682Smarkm/* 2233294Sstas * Copyright (c) 1997-2005 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "ktutil_locl.h" 3555682Smarkm 36233294SstasRCSID("$Id$"); 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); 64233294Sstas krb5_set_error_message(context, ENOMEM, "malloc failed"); 65178825Sdfr return ENOMEM; 66178825Sdfr } 6755682Smarkm conf.mask |= KADM5_CONFIG_REALM; 68233294Sstas 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); 74233294Sstas krb5_set_error_message(context, ENOMEM, "malloc failed"); 75178825Sdfr return ENOMEM; 76233294Sstas } 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; 143233294Sstas 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 225233294Sstas ret = krb5_unparse_name (context, changeset[i].principal, 226120945Snectar &client_name); 227120945Snectar if (ret) { 228120945Snectar krb5_warn (context, ret, "krb5_unparse_name"); 229120945Snectar } else { 230233294Sstas printf("Changing %s kvno %d\n", 231120945Snectar client_name, changeset[i].kvno); 232120945Snectar free(client_name); 233120945Snectar } 234120945Snectar } 235233294Sstas ret = change_entry (keytab, 236178825Sdfr changeset[i].principal, changeset[i].kvno, 237233294Sstas opt->realm_string, 238233294Sstas 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