1/*	$NetBSD: mod.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
39static void
40add_tl(kadm5_principal_ent_rec *princ, int type, krb5_data *data)
41{
42    krb5_tl_data *tl, **ptl;
43
44    tl = ecalloc(1, sizeof(*tl));
45    tl->tl_data_next = NULL;
46    tl->tl_data_type = type;
47    tl->tl_data_length = data->length;
48    tl->tl_data_contents = data->data;
49
50    princ->n_tl_data++;
51    ptl = &princ->tl_data;
52    while (*ptl != NULL)
53	ptl = &(*ptl)->tl_data_next;
54    *ptl = tl;
55
56    return;
57}
58
59static void
60add_constrained_delegation(krb5_context contextp,
61			   kadm5_principal_ent_rec *princ,
62			   struct getarg_strings *strings)
63{
64    krb5_error_code ret;
65    HDB_extension ext;
66    krb5_data buf;
67    size_t size = 0;
68
69    memset(&ext, 0, sizeof(ext));
70    ext.mandatory = FALSE;
71    ext.data.element = choice_HDB_extension_data_allowed_to_delegate_to;
72
73    if (strings->num_strings == 1 && strings->strings[0][0] == '\0') {
74	ext.data.u.allowed_to_delegate_to.val = NULL;
75	ext.data.u.allowed_to_delegate_to.len = 0;
76    } else {
77	krb5_principal p;
78	int i;
79
80	ext.data.u.allowed_to_delegate_to.val =
81	    calloc(strings->num_strings,
82		   sizeof(ext.data.u.allowed_to_delegate_to.val[0]));
83	ext.data.u.allowed_to_delegate_to.len = strings->num_strings;
84
85	for (i = 0; i < strings->num_strings; i++) {
86	    ret = krb5_parse_name(contextp, strings->strings[i], &p);
87	    if (ret)
88		abort();
89	    ret = copy_Principal(p, &ext.data.u.allowed_to_delegate_to.val[i]);
90	    if (ret)
91		abort();
92	    krb5_free_principal(contextp, p);
93	}
94    }
95
96    ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length,
97		       &ext, &size, ret);
98    free_HDB_extension(&ext);
99    if (ret)
100	abort();
101    if (buf.length != size)
102	abort();
103
104    add_tl(princ, KRB5_TL_EXTENSION, &buf);
105}
106
107static void
108add_aliases(krb5_context contextp, kadm5_principal_ent_rec *princ,
109	    struct getarg_strings *strings)
110{
111    krb5_error_code ret = 0;
112    HDB_extension ext;
113    krb5_data buf;
114    krb5_principal p;
115    size_t size = 0;
116    int i;
117
118    memset(&ext, 0, sizeof(ext));
119    ext.mandatory = FALSE;
120    ext.data.element = choice_HDB_extension_data_aliases;
121    ext.data.u.aliases.case_insensitive = 0;
122
123    if (strings->num_strings == 1 && strings->strings[0][0] == '\0') {
124	ext.data.u.aliases.aliases.val = NULL;
125	ext.data.u.aliases.aliases.len = 0;
126    } else {
127	ext.data.u.aliases.aliases.val =
128	    calloc(strings->num_strings,
129		   sizeof(ext.data.u.aliases.aliases.val[0]));
130	ext.data.u.aliases.aliases.len = strings->num_strings;
131
132	for (i = 0; ret == 0 && i < strings->num_strings; i++) {
133	    ret = krb5_parse_name(contextp, strings->strings[i], &p);
134            if (ret)
135                krb5_err(contextp, 1, ret, "Could not parse alias %s",
136                         strings->strings[i]);
137            if (ret == 0)
138                ret = copy_Principal(p, &ext.data.u.aliases.aliases.val[i]);
139            if (ret)
140                krb5_err(contextp, 1, ret, "Could not copy parsed alias %s",
141                         strings->strings[i]);
142	    krb5_free_principal(contextp, p);
143	}
144    }
145
146    ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length,
147		       &ext, &size, ret);
148    free_HDB_extension(&ext);
149    if (ret)
150	abort();
151    if (buf.length != size)
152	abort();
153
154    add_tl(princ, KRB5_TL_EXTENSION, &buf);
155}
156
157static void
158add_pkinit_acl(krb5_context contextp, kadm5_principal_ent_rec *princ,
159	       struct getarg_strings *strings)
160{
161    krb5_error_code ret;
162    HDB_extension ext;
163    krb5_data buf;
164    size_t size = 0;
165    int i;
166
167    memset(&ext, 0, sizeof(ext));
168    ext.mandatory = FALSE;
169    ext.data.element = choice_HDB_extension_data_pkinit_acl;
170    ext.data.u.aliases.case_insensitive = 0;
171
172    if (strings->num_strings == 1 && strings->strings[0][0] == '\0') {
173	ext.data.u.pkinit_acl.val = NULL;
174	ext.data.u.pkinit_acl.len = 0;
175    } else {
176	ext.data.u.pkinit_acl.val =
177	    calloc(strings->num_strings,
178		   sizeof(ext.data.u.pkinit_acl.val[0]));
179	ext.data.u.pkinit_acl.len = strings->num_strings;
180
181	for (i = 0; i < strings->num_strings; i++) {
182	    ext.data.u.pkinit_acl.val[i].subject = estrdup(strings->strings[i]);
183	}
184    }
185
186    ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length,
187		       &ext, &size, ret);
188    free_HDB_extension(&ext);
189    if (ret)
190	abort();
191    if (buf.length != size)
192	abort();
193
194    add_tl(princ, KRB5_TL_EXTENSION, &buf);
195}
196
197static void
198add_kvno_diff(krb5_context contextp, kadm5_principal_ent_rec *princ,
199	      int is_svc_diff, krb5_kvno kvno_diff)
200{
201    krb5_error_code ret;
202    HDB_extension ext;
203    krb5_data buf;
204    size_t size = 0;
205
206    if (kvno_diff < 0)
207	return;
208    if (kvno_diff > 2048)
209	kvno_diff = 2048;
210
211    if (is_svc_diff) {
212	ext.data.element = choice_HDB_extension_data_hist_kvno_diff_svc;
213	ext.data.u.hist_kvno_diff_svc = (unsigned int)kvno_diff;
214    } else {
215	ext.data.element = choice_HDB_extension_data_hist_kvno_diff_clnt;
216	ext.data.u.hist_kvno_diff_clnt = (unsigned int)kvno_diff;
217    }
218    ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length,
219		       &ext, &size, ret);
220    if (ret)
221	abort();
222    if (buf.length != size)
223	abort();
224
225    add_tl(princ, KRB5_TL_EXTENSION, &buf);
226}
227
228static int
229do_mod_entry(krb5_principal principal, void *data)
230{
231    krb5_error_code ret;
232    kadm5_principal_ent_rec princ;
233    int mask = 0;
234    struct modify_options *e = data;
235
236    memset (&princ, 0, sizeof(princ));
237    ret = kadm5_get_principal(kadm_handle, principal, &princ,
238			      KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
239			      KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
240			      KADM5_PRINC_EXPIRE_TIME |
241			      KADM5_PW_EXPIRATION);
242    if(ret)
243	return ret;
244
245    if(e->max_ticket_life_string ||
246       e->max_renewable_life_string ||
247       e->expiration_time_string ||
248       e->pw_expiration_time_string ||
249       e->attributes_string ||
250       e->policy_string ||
251       e->kvno_integer != -1 ||
252       e->constrained_delegation_strings.num_strings ||
253       e->alias_strings.num_strings ||
254       e->pkinit_acl_strings.num_strings ||
255       e->hist_kvno_diff_clnt_integer != -1 ||
256       e->hist_kvno_diff_svc_integer != -1) {
257	ret = set_entry(context, &princ, &mask,
258			e->max_ticket_life_string,
259			e->max_renewable_life_string,
260			e->expiration_time_string,
261			e->pw_expiration_time_string,
262			e->attributes_string,
263			e->policy_string);
264	if(e->kvno_integer != -1) {
265	    princ.kvno = e->kvno_integer;
266	    mask |= KADM5_KVNO;
267	}
268	if (e->constrained_delegation_strings.num_strings) {
269	    add_constrained_delegation(context, &princ,
270				       &e->constrained_delegation_strings);
271	    mask |= KADM5_TL_DATA;
272	}
273	if (e->alias_strings.num_strings) {
274	    add_aliases(context, &princ, &e->alias_strings);
275	    mask |= KADM5_TL_DATA;
276	}
277	if (e->pkinit_acl_strings.num_strings) {
278	    add_pkinit_acl(context, &princ, &e->pkinit_acl_strings);
279	    mask |= KADM5_TL_DATA;
280	}
281	if (e->hist_kvno_diff_clnt_integer != -1) {
282	    add_kvno_diff(context, &princ, 0, e->hist_kvno_diff_clnt_integer);
283	    mask |= KADM5_TL_DATA;
284	}
285	if (e->hist_kvno_diff_svc_integer != -1) {
286	    add_kvno_diff(context, &princ, 1, e->hist_kvno_diff_svc_integer);
287	    mask |= KADM5_TL_DATA;
288	}
289    } else
290	ret = edit_entry(&princ, &mask, NULL, 0);
291    if(ret == 0) {
292	ret = kadm5_modify_principal(kadm_handle, &princ, mask);
293	if(ret)
294	    krb5_warn(context, ret, "kadm5_modify_principal");
295    }
296
297    kadm5_free_principal_ent(kadm_handle, &princ);
298    return ret;
299}
300
301int
302mod_entry(struct modify_options *opt, int argc, char **argv)
303{
304    krb5_error_code ret = 0;
305    int i;
306
307    for(i = 0; i < argc; i++) {
308	ret = foreach_principal(argv[i], do_mod_entry, "mod", opt);
309	if (ret)
310	    break;
311    }
312    return ret != 0;
313}
314
315