1/*
2 * Copyright (c) 2008 Kungliga Tekniska H�gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2009 Apple Inc. 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 "kadm5_locl.h"
37
38#define LARGETIME 0x1fffffff
39
40#define CHECK(x)							\
41	do {								\
42		int __r;						\
43		if ((__r = (x))) {					\
44			abort();					\
45		}							\
46	} while(0)
47
48#define INSIST(x) CHECK(!(x))
49
50
51krb5_error_code
52_kadm5_xdr_store_data_xdr(krb5_storage *sp, krb5_data data)
53{
54    krb5_error_code ret;
55    ssize_t sret;
56    size_t res;
57
58    ret = krb5_store_data(sp, data);
59    if (ret)
60	return ret;
61    res = 4 - (data.length % 4);
62    if (res != 4) {
63	static const char zero[4] = { 0, 0, 0, 0 };
64
65	sret = krb5_storage_write(sp, zero, res);
66	if(sret < 0 || (size_t)sret != res)
67	    return (sret < 0)? errno : krb5_storage_get_eof_code(sp);
68    }
69    return 0;
70}
71
72krb5_error_code
73_kadm5_xdr_ret_data_xdr(krb5_storage *sp, krb5_data *data)
74{
75    krb5_error_code ret;
76    ssize_t sret;
77
78    ret = krb5_ret_data(sp, data);
79    if (ret)
80	return ret;
81
82    if ((data->length % 4) != 0) {
83	char buf[4];
84	size_t res;
85
86	res = 4 - (data->length % 4);
87	if (res != 4) {
88	    sret = krb5_storage_read(sp, buf, res);
89	    if(sret < 0 || (size_t)sret != res)
90		return (sret < 0)? errno : krb5_storage_get_eof_code(sp);
91	}
92    }
93    return 0;
94}
95
96krb5_error_code
97_kadm5_xdr_ret_auth_opaque(krb5_storage *msg, struct _kadm5_xdr_opaque_auth *ao)
98{
99    krb5_error_code ret;
100    ret = krb5_ret_uint32(msg, &ao->flavor);
101    if (ret) return ret;
102    ret = _kadm5_xdr_ret_data_xdr(msg, &ao->data);
103    return ret;
104}
105
106krb5_error_code
107_kadm5_xdr_store_auth_opaque(krb5_storage *msg, struct _kadm5_xdr_opaque_auth *ao)
108{
109    krb5_error_code ret;
110    ret = krb5_store_uint32(msg, ao->flavor);
111    if (ret) return ret;
112    ret = _kadm5_xdr_store_data_xdr(msg, ao->data);
113    return ret;
114}
115
116krb5_error_code
117_kadm5_xdr_ret_gcred(krb5_data *data, struct _kadm5_xdr_gcred *gcred)
118{
119    krb5_storage *sp;
120
121    memset(gcred, 0, sizeof(*gcred));
122
123    sp = krb5_storage_from_data(data);
124    INSIST(sp != NULL);
125
126    CHECK(krb5_ret_uint32(sp, &gcred->version));
127    CHECK(krb5_ret_uint32(sp, &gcred->proc));
128    CHECK(krb5_ret_uint32(sp, &gcred->seq_num));
129    CHECK(krb5_ret_uint32(sp, &gcred->service));
130    CHECK(_kadm5_xdr_ret_data_xdr(sp, &gcred->handle));
131
132    krb5_storage_free(sp);
133
134    return 0;
135}
136
137krb5_error_code
138_kadm5_xdr_store_gcred(struct _kadm5_xdr_gcred *gcred, krb5_data *data)
139{
140    krb5_error_code ret;
141    krb5_storage *sp;
142
143    krb5_data_zero(data);
144
145    sp = krb5_storage_emem();
146    INSIST(sp != NULL);
147
148    CHECK(krb5_store_uint32(sp, gcred->version));
149    CHECK(krb5_store_uint32(sp, gcred->proc));
150    CHECK(krb5_store_uint32(sp, gcred->seq_num));
151    CHECK(krb5_store_uint32(sp, gcred->service));
152    CHECK(_kadm5_xdr_store_data_xdr(sp, gcred->handle));
153
154    ret = krb5_storage_to_data(sp, data);
155    krb5_storage_free(sp);
156
157    return ret;
158}
159
160
161krb5_error_code
162_kadm5_xdr_store_gss_init_res(krb5_storage *sp, krb5_data handle,
163		   OM_uint32 maj_stat, OM_uint32 min_stat,
164		   uint32_t seq_window, gss_buffer_t gout)
165{
166    krb5_error_code ret;
167    krb5_data out;
168
169    out.data = gout->value;
170    out.length = gout->length;
171
172    ret = _kadm5_xdr_store_data_xdr(sp, handle);
173    if (ret) return ret;
174    ret = krb5_store_uint32(sp, maj_stat);
175    if (ret) return ret;
176    ret = krb5_store_uint32(sp, min_stat);
177    if (ret) return ret;
178    ret = krb5_store_uint32(sp, seq_window);
179    if (ret) return ret;
180    ret = _kadm5_xdr_store_data_xdr(sp, out);
181    return ret;
182}
183
184krb5_error_code
185_kadm5_xdr_ret_gss_init_res(krb5_storage *sp, krb5_data *handle,
186			    OM_uint32 *maj_stat, OM_uint32 *min_stat,
187			    uint32_t *seq_window, krb5_data *out)
188{
189    krb5_error_code ret;
190
191    ret = _kadm5_xdr_ret_data_xdr(sp, handle);
192    if (ret) return ret;
193    ret = krb5_ret_uint32(sp, maj_stat);
194    if (ret) return ret;
195    ret = krb5_ret_uint32(sp, min_stat);
196    if (ret) return ret;
197    ret = krb5_ret_uint32(sp, seq_window);
198    if (ret) return ret;
199    ret = _kadm5_xdr_ret_data_xdr(sp, out);
200    return ret;
201}
202
203
204krb5_error_code
205_kadm5_xdr_ret_gacred(krb5_data *data, struct _kadm5_xdr_gacred *gacred)
206{
207    krb5_storage *sp;
208
209    memset(gacred, 0, sizeof(*gacred));
210
211    sp = krb5_storage_from_data(data);
212    INSIST(sp != NULL);
213
214    CHECK(krb5_ret_uint32(sp, &gacred->version));
215    CHECK(krb5_ret_uint32(sp, &gacred->auth_msg));
216    CHECK(_kadm5_xdr_ret_data_xdr(sp, &gacred->handle));
217
218    krb5_storage_free(sp);
219
220    return 0;
221}
222
223
224krb5_error_code
225_kadm5_xdr_store_string_xdr(krb5_storage *sp, const char *str)
226{
227    krb5_data c;
228    if (str) {
229	c.data = rk_UNCONST(str);
230	c.length = strlen(str) + 1;
231    } else
232	krb5_data_zero(&c);
233
234    return _kadm5_xdr_store_data_xdr(sp, c);
235}
236
237krb5_error_code
238_kadm5_xdr_ret_string_xdr(krb5_storage *sp, char **str)
239{
240    krb5_data c;
241    *str = NULL;
242    CHECK(_kadm5_xdr_ret_data_xdr(sp, &c));
243    if (c.length) {
244	*str = malloc(c.length + 1);
245	INSIST(*str != NULL);
246	memcpy(*str, c.data, c.length);
247	(*str)[c.length] = '\0';
248    }
249    krb5_data_free(&c);
250    return 0;
251}
252
253krb5_error_code
254_kadm5_xdr_store_principal_xdr(krb5_context context,
255		    krb5_storage *sp,
256		    krb5_principal p)
257{
258    char *str;
259    CHECK(krb5_unparse_name(context, p, &str));
260    CHECK(_kadm5_xdr_store_string_xdr(sp, str));
261    free(str);
262    return 0;
263}
264
265krb5_error_code
266_kadm5_xdr_ret_principal_xdr(krb5_context context,
267		  krb5_storage *sp,
268		  krb5_principal *p)
269{
270    char *str;
271    *p = NULL;
272    CHECK(_kadm5_xdr_ret_string_xdr(sp, &str));
273    if (str) {
274	CHECK(krb5_parse_name(context, str, p));
275	free(str);
276    }
277    return 0;
278}
279
280krb5_error_code
281_kadm5_xdr_store_principal_ent(krb5_context context,
282		    krb5_storage *sp,
283		    kadm5_principal_ent_rec *ent)
284{
285    int32_t t;
286    size_t i;
287
288    CHECK(_kadm5_xdr_store_principal_xdr(context, sp, ent->principal));
289    CHECK(krb5_store_uint32(sp, (uint32_t)ent->princ_expire_time));
290    CHECK(krb5_store_uint32(sp, (uint32_t)ent->pw_expiration));
291    CHECK(krb5_store_uint32(sp, (uint32_t)ent->last_pwd_change));
292    t = (int32_t)ent->max_life;
293    if (t == 0)
294	t = LARGETIME;
295    CHECK(krb5_store_uint32(sp, t));
296    CHECK(krb5_store_int32(sp, ent->mod_name == NULL));
297    if (ent->mod_name)
298	CHECK(_kadm5_xdr_store_principal_xdr(context, sp, ent->mod_name));
299    CHECK(krb5_store_uint32(sp, (uint32_t)ent->mod_date));
300    CHECK(krb5_store_uint32(sp, ent->attributes));
301    CHECK(krb5_store_uint32(sp, ent->kvno));
302    CHECK(krb5_store_uint32(sp, ent->mkvno));
303    CHECK(_kadm5_xdr_store_string_xdr(sp, ent->policy));
304    CHECK(krb5_store_int32(sp, ent->aux_attributes));
305    t = (int32_t)ent->max_renewable_life;
306    if (t == 0)
307	t = LARGETIME;
308    CHECK(krb5_store_int32(sp, t));
309    CHECK(krb5_store_int32(sp, (int32_t)ent->last_success));
310    CHECK(krb5_store_int32(sp, (int32_t)ent->last_failed));
311    CHECK(krb5_store_int32(sp, ent->fail_auth_count));
312    CHECK(krb5_store_int32(sp, ent->n_key_data));
313    CHECK(krb5_store_int32(sp, ent->n_tl_data));
314    CHECK(krb5_store_int32(sp, ent->n_tl_data == 0));
315    if (ent->n_tl_data) {
316	krb5_tl_data *tp;
317
318	for (tp = ent->tl_data; tp; tp = tp->tl_data_next) {
319	    krb5_data c;
320	    c.length = tp->tl_data_length;
321	    c.data = tp->tl_data_contents;
322
323	    CHECK(krb5_store_int32(sp, 0)); /* last item */
324	    CHECK(krb5_store_int32(sp, tp->tl_data_type));
325	    CHECK(_kadm5_xdr_store_data_xdr(sp, c));
326	}
327	CHECK(krb5_store_int32(sp, 1)); /* last item */
328    }
329
330    CHECK(krb5_store_int32(sp, ent->n_key_data));
331    for (i = 0; i < (size_t)ent->n_key_data; i++) {
332	CHECK(krb5_store_uint32(sp, 2));
333	CHECK(krb5_store_uint32(sp, ent->kvno));
334	CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[0]));
335	CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[1]));
336    }
337
338    return 0;
339}
340
341krb5_error_code
342_kadm5_xdr_ret_principal_ent(krb5_context context,
343			       krb5_storage *sp,
344			       kadm5_principal_ent_rec *ent)
345{
346    uint32_t flag, num, dataver;
347    size_t i;
348
349    memset(ent, 0, sizeof(*ent));
350
351    CHECK(_kadm5_xdr_ret_principal_xdr(context, sp, &ent->principal));
352    CHECK(krb5_ret_uint32(sp, &flag));
353    ent->princ_expire_time = flag;
354    CHECK(krb5_ret_uint32(sp, &flag));
355    ent->pw_expiration = flag;
356    CHECK(krb5_ret_uint32(sp, &flag));
357    ent->last_pwd_change = flag;
358    CHECK(krb5_ret_uint32(sp, &flag));
359    ent->max_life = flag;
360    if (ent->max_life >= LARGETIME)
361	ent->max_life = 0;
362    CHECK(krb5_ret_uint32(sp, &flag));
363    if (flag == 0) {
364	CHECK(_kadm5_xdr_ret_principal_xdr(context, sp, &ent->mod_name));
365    }
366    CHECK(krb5_ret_uint32(sp, &flag));
367    ent->mod_date = flag;
368    CHECK(krb5_ret_uint32(sp, &flag));
369    ent->attributes = flag;
370    CHECK(krb5_ret_uint32(sp, &flag));
371    ent->kvno = flag;
372    CHECK(krb5_ret_uint32(sp, &flag));
373    ent->mkvno = flag;
374    CHECK(_kadm5_xdr_ret_string_xdr(sp, &ent->policy));
375    CHECK(krb5_ret_uint32(sp, &flag));
376    ent->aux_attributes = flag;
377    CHECK(krb5_ret_uint32(sp, &flag));
378    ent->max_renewable_life = flag;
379    if (ent->max_renewable_life >= LARGETIME)
380	ent->max_renewable_life = 0;
381    CHECK(krb5_ret_uint32(sp, &flag));
382    ent->last_success = flag;
383    CHECK(krb5_ret_uint32(sp, &flag));
384    ent->last_failed = flag;
385    CHECK(krb5_ret_uint32(sp, &flag));
386    ent->fail_auth_count = flag;
387    CHECK(krb5_ret_uint32(sp, &flag));
388    ent->n_key_data = flag;
389    CHECK(krb5_ret_uint32(sp, &flag));
390    ent->n_tl_data = flag;
391    CHECK(krb5_ret_uint32(sp, &flag));
392    if (flag == 0) {
393	krb5_tl_data **tp = &ent->tl_data;
394	size_t count = 0;
395
396	while(1) {
397	    krb5_data c;
398	    CHECK(krb5_ret_uint32(sp, &flag)); /* last item */
399	    if (flag)
400		break;
401	    *tp = calloc(1, sizeof(**tp));
402	    INSIST(*tp != NULL);
403	    CHECK(krb5_ret_uint32(sp, &flag));
404	    (*tp)->tl_data_type = flag;
405	    CHECK(_kadm5_xdr_ret_data_xdr(sp, &c));
406	    (*tp)->tl_data_length = c.length;
407	    (*tp)->tl_data_contents = c.data;
408	    tp = &(*tp)->tl_data_next;
409
410	    count++;
411
412	    INSIST(count < 2000);
413	}
414	INSIST((size_t)ent->n_tl_data == count);
415    } else {
416	INSIST(ent->n_tl_data == 0);
417    }
418
419    CHECK(krb5_ret_uint32(sp, &num));
420    INSIST(num == (uint32_t)ent->n_key_data);
421
422    ent->key_data = calloc(num, sizeof(ent->key_data[0]));
423    INSIST(ent->key_data != NULL);
424
425    for (i = 0; i < num; i++) {
426	CHECK(krb5_ret_uint32(sp, &dataver));
427	CHECK(krb5_ret_uint32(sp, &flag));
428	ent->kvno = flag;
429
430	CHECK(krb5_ret_uint32(sp, &flag));
431	ent->key_data[i].key_data_type[0] = flag;
432
433	if (dataver > 1) {
434	    CHECK(krb5_ret_uint32(sp, &flag));
435	    ent->key_data[i].key_data_type[1] = flag;
436	}
437    }
438
439    return 0;
440}
441