1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/ser_ctx.c - Serialize krb5_context structure */
3 /*
4 * Copyright 1995, 2007, 2008 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "k5-int.h"
28 #include "int-proto.h"
29
30 errcode_t profile_ser_size(profile_t, size_t *);
31 errcode_t profile_ser_externalize(profile_t, krb5_octet **, size_t *);
32 errcode_t profile_ser_internalize(profile_t *, krb5_octet **, size_t *);
33
34 static krb5_error_code size_oscontext(krb5_os_context os_ctx, size_t *sizep);
35 static krb5_error_code externalize_oscontext(krb5_os_context os_ctx,
36 krb5_octet **buffer,
37 size_t *lenremain);
38 static krb5_error_code internalize_oscontext(krb5_os_context *argp,
39 krb5_octet **buffer,
40 size_t *lenremain);
41
42 static inline unsigned int
etypes_len(krb5_enctype * list)43 etypes_len(krb5_enctype *list)
44 {
45 return (list == NULL) ? 0 : k5_count_etypes(list);
46 }
47
48 krb5_error_code
k5_size_context(krb5_context context,size_t * sizep)49 k5_size_context(krb5_context context, size_t *sizep)
50 {
51 krb5_error_code kret;
52 size_t required;
53
54 /*
55 * The KRB5 context itself requires:
56 * krb5_int32 for KV5M_CONTEXT
57 * krb5_int32 for sizeof(default_realm)
58 * strlen(default_realm) for default_realm.
59 * krb5_int32 for n_tgs_etypes*sizeof(krb5_int32)
60 * nktypes*sizeof(krb5_int32) for tgs_etypes.
61 * krb5_int32 for clockskew
62 * krb5_int32 for kdc_default_options
63 * krb5_int32 for library_options
64 * krb5_int32 for profile_secure
65 * krb5_int32 for fcc_default_format
66 * <> for os_context
67 * <> for profile
68 * krb5_int32 for trailer.
69 */
70 kret = EINVAL;
71 if (context != NULL) {
72 /* Calculate base length */
73 required = (9 * sizeof(krb5_int32) +
74 (etypes_len(context->tgs_etypes) * sizeof(krb5_int32)));
75
76 if (context->default_realm)
77 required += strlen(context->default_realm);
78
79 /* Calculate size required by os_context, if appropriate */
80 kret = size_oscontext(&context->os_context, &required);
81
82 /* Calculate size required by profile, if appropriate */
83 if (!kret && context->profile)
84 kret = profile_ser_size(context->profile, &required);
85 }
86 if (!kret)
87 *sizep += required;
88 return(kret);
89 }
90
91 krb5_error_code
k5_externalize_context(krb5_context context,krb5_octet ** buffer,size_t * lenremain)92 k5_externalize_context(krb5_context context,
93 krb5_octet **buffer, size_t *lenremain)
94 {
95 krb5_error_code kret;
96 size_t required;
97 krb5_octet *bp;
98 size_t remain;
99 unsigned int i;
100
101 required = 0;
102 bp = *buffer;
103 remain = *lenremain;
104 if (!context)
105 return (EINVAL);
106 if (context->magic != KV5M_CONTEXT)
107 return (KV5M_CONTEXT);
108
109 if ((kret = k5_size_context(context, &required)))
110 return (kret);
111
112 if (required > remain)
113 return (ENOMEM);
114
115 /* First write our magic number */
116 kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
117 if (kret)
118 return (kret);
119
120 /* Now sizeof default realm */
121 kret = krb5_ser_pack_int32((context->default_realm) ?
122 (krb5_int32) strlen(context->default_realm) : 0,
123 &bp, &remain);
124 if (kret)
125 return (kret);
126
127 /* Now default_realm bytes */
128 if (context->default_realm) {
129 kret = krb5_ser_pack_bytes((krb5_octet *) context->default_realm,
130 strlen(context->default_realm),
131 &bp, &remain);
132 if (kret)
133 return (kret);
134 }
135
136 /* Now number of default ktypes */
137 kret = krb5_ser_pack_int32(etypes_len(context->tgs_etypes), &bp, &remain);
138 if (kret)
139 return (kret);
140
141 /* Now serialize ktypes */
142 if (context->tgs_etypes) {
143 for (i = 0; context->tgs_etypes[i]; i++) {
144 kret = krb5_ser_pack_int32(context->tgs_etypes[i], &bp, &remain);
145 if (kret)
146 return (kret);
147 }
148 }
149
150 /* Now allowable clockskew */
151 kret = krb5_ser_pack_int32((krb5_int32) context->clockskew,
152 &bp, &remain);
153 if (kret)
154 return (kret);
155
156 /* Now kdc_default_options */
157 kret = krb5_ser_pack_int32((krb5_int32) context->kdc_default_options,
158 &bp, &remain);
159 if (kret)
160 return (kret);
161
162 /* Now library_options */
163 kret = krb5_ser_pack_int32((krb5_int32) context->library_options,
164 &bp, &remain);
165 if (kret)
166 return (kret);
167
168 /* Now profile_secure */
169 kret = krb5_ser_pack_int32((krb5_int32) context->profile_secure,
170 &bp, &remain);
171 if (kret)
172 return (kret);
173
174 /* Now fcc_default_format */
175 kret = krb5_ser_pack_int32((krb5_int32) context->fcc_default_format,
176 &bp, &remain);
177 if (kret)
178 return (kret);
179
180 /* Now handle os_context, if appropriate */
181 kret = externalize_oscontext(&context->os_context, &bp, &remain);
182 if (kret)
183 return (kret);
184
185 /* Finally, handle profile, if appropriate */
186 if (context->profile != NULL) {
187 kret = profile_ser_externalize(context->profile, &bp, &remain);
188 if (kret)
189 return (kret);
190 }
191
192 /*
193 * If we were successful, write trailer then update the pointer and
194 * remaining length;
195 */
196 kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
197 if (kret)
198 return (kret);
199
200 *buffer = bp;
201 *lenremain = remain;
202
203 return (0);
204 }
205
206 krb5_error_code
k5_internalize_context(krb5_context * argp,krb5_octet ** buffer,size_t * lenremain)207 k5_internalize_context(krb5_context *argp,
208 krb5_octet **buffer, size_t *lenremain)
209 {
210 krb5_error_code kret;
211 krb5_context context;
212 krb5_int32 ibuf;
213 krb5_octet *bp;
214 size_t remain;
215 unsigned int i, count;
216
217 bp = *buffer;
218 remain = *lenremain;
219
220 /* Read our magic number */
221 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
222 return (EINVAL);
223
224 if (ibuf != KV5M_CONTEXT)
225 return (EINVAL);
226
227 /* Get memory for the context */
228 context = (krb5_context) calloc(1, sizeof(struct _krb5_context));
229 if (!context)
230 return (ENOMEM);
231
232 /* Get the size of the default realm */
233 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
234 goto cleanup;
235
236 if (ibuf) {
237 context->default_realm = (char *) malloc((size_t) ibuf+1);
238 if (!context->default_realm) {
239 kret = ENOMEM;
240 goto cleanup;
241 }
242
243 kret = krb5_ser_unpack_bytes((krb5_octet *) context->default_realm,
244 (size_t) ibuf, &bp, &remain);
245 if (kret)
246 goto cleanup;
247
248 context->default_realm[ibuf] = '\0';
249 }
250
251 /* Get the tgs_etypes */
252 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
253 goto cleanup;
254 count = ibuf;
255 if (count > 0) {
256 context->tgs_etypes = calloc(count + 1, sizeof(krb5_enctype));
257 if (!context->tgs_etypes) {
258 kret = ENOMEM;
259 goto cleanup;
260 }
261 for (i = 0; i < count; i++) {
262 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
263 goto cleanup;
264 context->tgs_etypes[i] = ibuf;
265 }
266 context->tgs_etypes[count] = 0;
267 } else
268 context->tgs_etypes = NULL;
269
270 /* Allowable clockskew */
271 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
272 goto cleanup;
273 context->clockskew = (krb5_deltat) ibuf;
274
275 /* kdc_default_options */
276 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
277 goto cleanup;
278 context->kdc_default_options = (krb5_flags) ibuf;
279
280 /* library_options */
281 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
282 goto cleanup;
283 context->library_options = (krb5_flags) ibuf;
284
285 /* profile_secure */
286 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
287 goto cleanup;
288 context->profile_secure = (krb5_boolean) ibuf;
289
290 /* fcc_default_format */
291 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
292 goto cleanup;
293 context->fcc_default_format = (int) ibuf;
294
295 /* Attempt to read in the os_context. It's an array now, but
296 we still treat it in most places as a separate object with
297 a pointer. */
298 {
299 krb5_os_context osp = 0;
300 kret = internalize_oscontext(&osp, &bp, &remain);
301 if (kret && (kret != EINVAL) && (kret != ENOENT))
302 goto cleanup;
303 /* Put the newly allocated data into the krb5_context
304 structure where we're really keeping it these days. */
305 if (osp)
306 context->os_context = *osp;
307 free(osp);
308 }
309
310 /* Attempt to read in the profile */
311 kret = profile_ser_internalize(&context->profile, &bp, &remain);
312 if (kret && (kret != EINVAL) && (kret != ENOENT))
313 goto cleanup;
314
315 /* Finally, find the trailer */
316 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
317 goto cleanup;
318
319 if (ibuf != KV5M_CONTEXT) {
320 kret = EINVAL;
321 goto cleanup;
322 }
323
324 context->magic = KV5M_CONTEXT;
325 *buffer = bp;
326 *lenremain = remain;
327 *argp = context;
328
329 return 0;
330
331 cleanup:
332 if (context)
333 krb5_free_context(context);
334 return(kret);
335 }
336
337 krb5_error_code
size_oscontext(krb5_os_context os_ctx,size_t * sizep)338 size_oscontext(krb5_os_context os_ctx, size_t *sizep)
339 {
340 /*
341 * We need five 32-bit integers:
342 * two for header and trailer
343 * one each for time_offset, usec_offset and os_flags
344 */
345 *sizep += (5*sizeof(krb5_int32));
346 return(0);
347 }
348
349 krb5_error_code
externalize_oscontext(krb5_os_context os_ctx,krb5_octet ** buffer,size_t * lenremain)350 externalize_oscontext(krb5_os_context os_ctx,
351 krb5_octet **buffer, size_t *lenremain)
352 {
353 krb5_error_code kret;
354 size_t required;
355 krb5_octet *bp;
356 size_t remain;
357
358 required = 0;
359 bp = *buffer;
360 remain = *lenremain;
361 kret = EINVAL;
362 if (os_ctx != NULL) {
363 kret = ENOMEM;
364 if (!size_oscontext(os_ctx, &required) && required <= remain) {
365 (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
366 (void) krb5_ser_pack_int32(os_ctx->time_offset, &bp, &remain);
367 (void) krb5_ser_pack_int32(os_ctx->usec_offset, &bp, &remain);
368 (void) krb5_ser_pack_int32(os_ctx->os_flags, &bp, &remain);
369 (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
370
371 /* Handle any other OS context here */
372 kret = 0;
373 if (!kret) {
374 *buffer = bp;
375 *lenremain = remain;
376 }
377 }
378 }
379 return(kret);
380 }
381
382 static krb5_error_code
internalize_oscontext(krb5_os_context * argp,krb5_octet ** buffer,size_t * lenremain)383 internalize_oscontext(krb5_os_context *argp,
384 krb5_octet **buffer, size_t *lenremain)
385 {
386 krb5_error_code kret;
387 krb5_os_context os_ctx;
388 krb5_int32 ibuf;
389 krb5_octet *bp;
390 size_t remain;
391
392 bp = *buffer;
393 remain = *lenremain;
394 kret = EINVAL;
395 os_ctx = (krb5_os_context) NULL;
396 /* Read our magic number */
397 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
398 ibuf = 0;
399 if (ibuf == KV5M_OS_CONTEXT) {
400 kret = ENOMEM;
401
402 /* Get memory for the context */
403 if ((os_ctx = (krb5_os_context)
404 calloc(1, sizeof(struct _krb5_os_context))) &&
405 (remain >= 4*sizeof(krb5_int32))) {
406 os_ctx->magic = KV5M_OS_CONTEXT;
407
408 /* Read out our context */
409 (void) krb5_ser_unpack_int32(&os_ctx->time_offset, &bp, &remain);
410 (void) krb5_ser_unpack_int32(&os_ctx->usec_offset, &bp, &remain);
411 (void) krb5_ser_unpack_int32(&os_ctx->os_flags, &bp, &remain);
412 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
413
414 if (ibuf == KV5M_OS_CONTEXT) {
415 os_ctx->magic = KV5M_OS_CONTEXT;
416 kret = 0;
417 *buffer = bp;
418 *lenremain = remain;
419 } else
420 kret = EINVAL;
421 }
422 }
423 if (!kret) {
424 *argp = os_ctx;
425 }
426 else {
427 if (os_ctx)
428 free(os_ctx);
429 }
430 return(kret);
431 }
432