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