1 /*
2 * lib/krb5/krb/ser_ctx.c
3 *
4 * Copyright 1995 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
28 /*
29 * ser_ctx.c - Routines to deal with serializing the krb5_context and
30 * krb5_os_context structures.
31 */
32 #include "k5-int.h"
33
34 /*
35 * Routines to deal with externalizing the krb5_context:
36 * krb5_context_size();
37 * krb5_context_externalize();
38 * krb5_context_internalize();
39 *
40 * Routines to deal with externalizing the krb5_os_context:
41 * krb5_oscontext_size();
42 * krb5_oscontext_externalize();
43 * krb5_oscontext_internalize();
44 *
45 * Routines to deal with externalizing the profile.
46 * profile_ser_size();
47 * profile_ser_externalize();
48 * profile_ser_internalize();
49 *
50 * Interface to initialize serializing of krb5_context and krb5_os_context:
51 * krb5_ser_context_init();
52 */
53 static krb5_error_code krb5_context_size
54 (krb5_context, krb5_pointer, size_t *);
55 static krb5_error_code krb5_context_externalize
56 (krb5_context, krb5_pointer, krb5_octet **, size_t *);
57 static krb5_error_code krb5_context_internalize
58 (krb5_context,krb5_pointer *, krb5_octet **, size_t *);
59 static krb5_error_code krb5_oscontext_size
60 (krb5_context, krb5_pointer, size_t *);
61 static krb5_error_code krb5_oscontext_externalize
62 (krb5_context, krb5_pointer, krb5_octet **, size_t *);
63 static krb5_error_code krb5_oscontext_internalize
64 (krb5_context,krb5_pointer *, krb5_octet **, size_t *);
65 #ifndef _KERNEL
66 krb5_error_code profile_ser_size
67 (krb5_context, krb5_pointer, size_t *);
68 krb5_error_code profile_ser_externalize
69 (krb5_context, krb5_pointer, krb5_octet **, size_t *);
70 krb5_error_code profile_ser_internalize
71 (krb5_context,krb5_pointer *, krb5_octet **, size_t *);
72 #endif
73 /* Local data */
74 static const krb5_ser_entry krb5_context_ser_entry = {
75 KV5M_CONTEXT, /* Type */
76 krb5_context_size, /* Sizer routine */
77 krb5_context_externalize, /* Externalize routine */
78 krb5_context_internalize /* Internalize routine */
79 };
80 static const krb5_ser_entry krb5_oscontext_ser_entry = {
81 KV5M_OS_CONTEXT, /* Type */
82 krb5_oscontext_size, /* Sizer routine */
83 krb5_oscontext_externalize, /* Externalize routine */
84 krb5_oscontext_internalize /* Internalize routine */
85 };
86 #ifndef _KERNEL
87 static const krb5_ser_entry krb5_profile_ser_entry = {
88 PROF_MAGIC_PROFILE, /* Type */
89 profile_ser_size, /* Sizer routine */
90 profile_ser_externalize, /* Externalize routine */
91 profile_ser_internalize /* Internalize routine */
92 };
93 #endif
94
95 /*
96 * krb5_context_size() - Determine the size required to externalize the
97 * krb5_context.
98 */
99 static krb5_error_code
krb5_context_size(krb5_context kcontext,krb5_pointer arg,size_t * sizep)100 krb5_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
101 {
102 krb5_error_code kret;
103 size_t required;
104 krb5_context context;
105
106 /*
107 * The KRB5 context itself requires:
108 * krb5_int32 for KV5M_CONTEXT
109 * krb5_int32 for sizeof(default_realm)
110 * strlen(default_realm) for default_realm.
111 * krb5_int32 for n_in_tkt_ktypes*sizeof(krb5_int32)
112 * nktypes*sizeof(krb5_int32) for in_tkt_ktypes.
113 * krb5_int32 for n_tgs_ktypes*sizeof(krb5_int32)
114 * nktypes*sizeof(krb5_int32) for tgs_ktypes.
115 * krb5_int32 for clockskew
116 * krb5_int32 for kdc_req_sumtype
117 * krb5_int32 for ap_req_sumtype
118 * krb5_int32 for safe_sumtype
119 * krb5_int32 for kdc_default_options
120 * krb5_int32 for library_options
121 * krb5_int32 for profile_secure
122 * krb5_int32 for fcc_default_format
123 * krb5_int32 for scc_default_format
124 * <> for os_context
125 * <> for db_context
126 * <> for profile
127 * krb5_int32 for trailer.
128 */
129 kret = EINVAL;
130 if ((context = (krb5_context) arg)) {
131 /* Calculate base length */
132 required = (14 * sizeof(krb5_int32) +
133 (context->in_tkt_ktype_count * sizeof(krb5_int32)) +
134 (context->tgs_ktype_count * sizeof(krb5_int32)));
135
136 if (context->default_realm)
137 required += strlen(context->default_realm);
138 /* Calculate size required by os_context, if appropriate */
139 if (context->os_context)
140 kret = krb5_size_opaque(kcontext,
141 KV5M_OS_CONTEXT,
142 (krb5_pointer) context->os_context,
143 &required);
144
145 /* Calculate size required by db_context, if appropriate */
146 if (!kret && context->db_context)
147 kret = krb5_size_opaque(kcontext,
148 KV5M_DB_CONTEXT,
149 (krb5_pointer) context->db_context,
150 &required);
151
152 /* Finally, calculate size required by profile, if appropriate */
153 if (!kret && context->profile)
154 kret = krb5_size_opaque(kcontext,
155 PROF_MAGIC_PROFILE,
156 (krb5_pointer) context->profile,
157 &required);
158 }
159 if (!kret)
160 *sizep += required;
161 return(kret);
162 }
163
164 /*
165 * krb5_context_externalize() - Externalize the krb5_context.
166 */
167 static krb5_error_code
krb5_context_externalize(krb5_context kcontext,krb5_pointer arg,krb5_octet ** buffer,size_t * lenremain)168 krb5_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
169 {
170 krb5_error_code kret;
171 krb5_context context;
172 size_t required;
173 krb5_octet *bp;
174 size_t remain;
175 int i;
176
177 required = 0;
178 bp = *buffer;
179 remain = *lenremain;
180 context = (krb5_context) arg;
181 if (!context)
182 return (EINVAL);
183 KRB5_VERIFY_MAGIC(context, KV5M_CONTEXT);
184
185 if ((kret = krb5_context_size(kcontext, arg, &required)))
186 return (kret);
187
188 if (required > remain)
189 return (ENOMEM);
190
191 /* First write our magic number */
192 kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
193 if (kret)
194 return (kret);
195
196 /* Now sizeof default realm */
197 kret = krb5_ser_pack_int32((context->default_realm) ?
198 (krb5_int32) strlen(context->default_realm) : 0,
199 &bp, &remain);
200 if (kret)
201 return (kret);
202
203 /* Now default_realm bytes */
204 if (context->default_realm) {
205 kret = krb5_ser_pack_bytes((krb5_octet *) context->default_realm,
206 strlen(context->default_realm),
207 &bp, &remain);
208 if (kret)
209 return (kret);
210 }
211
212 /* Now number of initial ticket ktypes */
213 kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktype_count,
214 &bp, &remain);
215 if (kret)
216 return (kret);
217
218 /* Now serialize ktypes */
219 for (i=0; i<context->in_tkt_ktype_count; i++) {
220 kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktypes[i],
221 &bp, &remain);
222 if (kret)
223 return (kret);
224 }
225
226 /* Now number of default ktypes */
227 kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktype_count,
228 &bp, &remain);
229 if (kret)
230 return (kret);
231
232 /* Now serialize ktypes */
233 for (i=0; i<context->tgs_ktype_count; i++) {
234 kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktypes[i],
235 &bp, &remain);
236 if (kret)
237 return (kret);
238 }
239
240 /* Now allowable clockskew */
241 kret = krb5_ser_pack_int32((krb5_int32) context->clockskew,
242 &bp, &remain);
243 if (kret)
244 return (kret);
245
246 /* Now kdc_req_sumtype */
247 kret = krb5_ser_pack_int32((krb5_int32) context->kdc_req_sumtype,
248 &bp, &remain);
249 if (kret)
250 return (kret);
251
252 /* Now default ap_req_sumtype */
253 kret = krb5_ser_pack_int32((krb5_int32) context->default_ap_req_sumtype,
254 &bp, &remain);
255 if (kret)
256 return (kret);
257
258 /* Now default safe_sumtype */
259 kret = krb5_ser_pack_int32((krb5_int32) context->default_safe_sumtype,
260 &bp, &remain);
261 if (kret)
262 return (kret);
263
264 /* Now kdc_default_options */
265 kret = krb5_ser_pack_int32((krb5_int32) context->kdc_default_options,
266 &bp, &remain);
267 if (kret)
268 return (kret);
269
270 /* Now library_options */
271 kret = krb5_ser_pack_int32((krb5_int32) context->library_options,
272 &bp, &remain);
273 if (kret)
274 return (kret);
275
276 /* Now profile_secure */
277 kret = krb5_ser_pack_int32((krb5_int32) context->profile_secure,
278 &bp, &remain);
279 if (kret)
280 return (kret);
281
282 /* Now fcc_default_format */
283 kret = krb5_ser_pack_int32((krb5_int32) context->fcc_default_format,
284 &bp, &remain);
285 if (kret)
286 return (kret);
287
288 /* Now scc_default_format */
289 kret = krb5_ser_pack_int32((krb5_int32) context->scc_default_format,
290 &bp, &remain);
291 if (kret)
292 return (kret);
293
294 /* Now handle os_context, if appropriate */
295 if (context->os_context) {
296 kret = krb5_externalize_opaque(kcontext, KV5M_OS_CONTEXT,
297 (krb5_pointer) context->os_context,
298 &bp, &remain);
299 if (kret)
300 return (kret);
301 }
302
303 /* Now handle database context, if appropriate */
304 if (context->db_context) {
305 kret = krb5_externalize_opaque(kcontext, KV5M_DB_CONTEXT,
306 (krb5_pointer) context->db_context,
307 &bp, &remain);
308 if (kret)
309 return (kret);
310 }
311
312 /* Finally, handle profile, if appropriate */
313 if (context->profile) {
314 kret = krb5_externalize_opaque(kcontext, PROF_MAGIC_PROFILE,
315 (krb5_pointer) context->profile,
316 &bp, &remain);
317 if (kret)
318 return (kret);
319 }
320
321 /*
322 * If we were successful, write trailer then update the pointer and
323 * remaining length;
324 */
325 kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
326 if (kret)
327 return (kret);
328
329 *buffer = bp;
330 *lenremain = remain;
331
332 return (0);
333 }
334
335 /*
336 * krb5_context_internalize() - Internalize the krb5_context.
337 */
338 static krb5_error_code
krb5_context_internalize(krb5_context kcontext,krb5_pointer * argp,krb5_octet ** buffer,size_t * lenremain)339 krb5_context_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
340 {
341 krb5_error_code kret;
342 krb5_context context;
343 krb5_int32 ibuf;
344 krb5_octet *bp;
345 size_t remain;
346 int i;
347
348 bp = *buffer;
349 remain = *lenremain;
350
351 /* Read our magic number */
352 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
353 return (EINVAL);
354
355 if (ibuf != KV5M_CONTEXT)
356 return (EINVAL);
357
358 /* Get memory for the context */
359 context = (krb5_context) MALLOC(sizeof(struct _krb5_context));
360 if (!context)
361 return (ENOMEM);
362 (void) memset(context, 0, sizeof(struct _krb5_context));
363
364 /* Get the size of the default realm */
365 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
366 goto cleanup;
367
368 if (ibuf) {
369 context->default_realm = (char *) MALLOC((size_t) ibuf+1);
370 if (!context->default_realm) {
371 kret = ENOMEM;
372 goto cleanup;
373 }
374
375 kret = krb5_ser_unpack_bytes((krb5_octet *) context->default_realm,
376 (size_t) ibuf, &bp, &remain);
377 if (kret)
378 goto cleanup;
379
380 context->default_realm[ibuf] = '\0';
381 }
382
383 /* Get the number of in_tkt_ktypes */
384 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
385 goto cleanup;
386
387 context->in_tkt_ktype_count = (int) ibuf;
388 context->in_tkt_ktypes = (krb5_enctype *) MALLOC(sizeof(krb5_enctype) *
389 (context->in_tkt_ktype_count+1));
390 if (!context->in_tkt_ktypes) {
391 kret = ENOMEM;
392 goto cleanup;
393 }
394 (void) memset(context->in_tkt_ktypes, 0, (sizeof(krb5_enctype) *
395 (context->in_tkt_ktype_count + 1)));
396
397 for (i=0; i<context->in_tkt_ktype_count; i++) {
398 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
399 goto cleanup;
400 context->in_tkt_ktypes[i] = (krb5_enctype) ibuf;
401 }
402
403 /* Get the number of tgs_ktypes */
404 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
405 goto cleanup;
406
407 context->tgs_ktype_count = (int) ibuf;
408 context->tgs_ktypes = (krb5_enctype *) MALLOC(sizeof(krb5_enctype) *
409 (context->tgs_ktype_count+1));
410 if (!context->tgs_ktypes) {
411 kret = ENOMEM;
412 goto cleanup;
413 }
414 (void) memset(context->tgs_ktypes, 0, (sizeof(krb5_enctype) *
415 (context->tgs_ktype_count + 1)));
416 for (i=0; i<context->tgs_ktype_count; i++) {
417 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
418 goto cleanup;
419 context->tgs_ktypes[i] = (krb5_enctype) ibuf;
420 }
421
422 /* Allowable checksum */
423 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
424 goto cleanup;
425 context->clockskew = (krb5_deltat) ibuf;
426
427 /* kdc_req_sumtype */
428 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
429 goto cleanup;
430 context->kdc_req_sumtype = (krb5_cksumtype) ibuf;
431
432 /* default ap_req_sumtype */
433 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
434 goto cleanup;
435 context->default_ap_req_sumtype = (krb5_cksumtype) ibuf;
436
437 /* default_safe_sumtype */
438 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
439 goto cleanup;
440 context->default_safe_sumtype = (krb5_cksumtype) ibuf;
441
442 /* kdc_default_options */
443 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
444 goto cleanup;
445 context->kdc_default_options = (krb5_flags) ibuf;
446
447 /* library_options */
448 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
449 goto cleanup;
450 context->library_options = (krb5_flags) ibuf;
451
452 /* profile_secure */
453 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
454 goto cleanup;
455 context->profile_secure = (krb5_boolean) ibuf;
456
457 /* fcc_default_format */
458 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
459 goto cleanup;
460 context->fcc_default_format = (int) ibuf;
461
462 /* scc_default_format */
463 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
464 goto cleanup;
465 context->scc_default_format = (int) ibuf;
466
467 /* Attempt to read in the os_context. It's an array now, but
468 we still treat it in most places as a separate object with
469 a pointer. */
470 {
471 krb5_os_context osp = 0;
472 kret = krb5_internalize_opaque(kcontext, KV5M_OS_CONTEXT,
473 (krb5_pointer *) &osp,
474 &bp, &remain);
475 if (kret && (kret != EINVAL) && (kret != ENOENT))
476 goto cleanup;
477 /* Put the newly allocated data into the krb5_context
478 structure where we're really keeping it these days. */
479 if (osp)
480 *context->os_context = *osp;
481 free(osp);
482 }
483
484 /* Attempt to read in the db_context */
485 kret = krb5_internalize_opaque(kcontext, KV5M_DB_CONTEXT,
486 (krb5_pointer *) &context->db_context,
487 &bp, &remain);
488 if (kret && (kret != EINVAL) && (kret != ENOENT))
489 goto cleanup;
490
491 #ifndef _KERNEL
492 /* Attempt to read in the profile */
493 kret = krb5_internalize_opaque(kcontext, PROF_MAGIC_PROFILE,
494 (krb5_pointer *) &context->profile,
495 &bp, &remain);
496 #endif
497 if (kret && (kret != EINVAL) && (kret != ENOENT))
498 goto cleanup;
499
500 /* Finally, find the trailer */
501 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
502 goto cleanup;
503
504 if (ibuf != KV5M_CONTEXT) {
505 kret = EINVAL;
506 goto cleanup;
507 }
508
509 context->magic = KV5M_CONTEXT;
510 *buffer = bp;
511 *lenremain = remain;
512 *argp = (krb5_pointer) context;
513
514 return 0;
515
516 cleanup:
517 if (context)
518 krb5_free_context(context);
519 return(kret);
520 }
521
522 /*
523 * krb5_oscontext_size() - Determine the size required to externalize
524 * the krb5_os_context.
525 */
526 /*ARGSUSED*/
527 static krb5_error_code
krb5_oscontext_size(krb5_context kcontext,krb5_pointer arg,size_t * sizep)528 krb5_oscontext_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
529 {
530 /*
531 * We need five 32-bit integers:
532 * two for header and trailer
533 * one each for time_offset, usec_offset and os_flags
534 */
535 *sizep += (5*sizeof(krb5_int32));
536 return(0);
537 }
538
539 /*
540 * krb5_oscontext_externalize() - Externalize the krb5_os_context.
541 */
542 static krb5_error_code
krb5_oscontext_externalize(krb5_context kcontext,krb5_pointer arg,krb5_octet ** buffer,size_t * lenremain)543 krb5_oscontext_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
544 {
545 krb5_error_code kret;
546 krb5_os_context os_ctx;
547 size_t required;
548 krb5_octet *bp;
549 size_t remain;
550
551 required = 0;
552 bp = *buffer;
553 remain = *lenremain;
554 kret = EINVAL;
555 if ((os_ctx = (krb5_os_context) arg)) {
556 kret = ENOMEM;
557 if (!krb5_oscontext_size(kcontext, arg, &required) &&
558 (required <= remain)) {
559 (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
560 (void) krb5_ser_pack_int32(os_ctx->time_offset, &bp, &remain);
561 (void) krb5_ser_pack_int32(os_ctx->usec_offset, &bp, &remain);
562 (void) krb5_ser_pack_int32(os_ctx->os_flags, &bp, &remain);
563 (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
564
565 /* Handle any other OS context here */
566 kret = 0;
567 if (!kret) {
568 *buffer = bp;
569 *lenremain = remain;
570 }
571 }
572 }
573 return(kret);
574 }
575
576 /*
577 * krb5_oscontext_internalize() - Internalize the krb5_os_context.
578 */
579 /*ARGSUSED*/
580 static krb5_error_code
krb5_oscontext_internalize(krb5_context kcontext,krb5_pointer * argp,krb5_octet ** buffer,size_t * lenremain)581 krb5_oscontext_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
582 {
583 krb5_error_code kret;
584 krb5_os_context os_ctx;
585 krb5_int32 ibuf;
586 krb5_octet *bp;
587 size_t remain;
588
589 bp = *buffer;
590 remain = *lenremain;
591 kret = EINVAL;
592 os_ctx = (krb5_os_context) NULL;
593 /* Read our magic number */
594 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
595 ibuf = 0;
596 if (ibuf == KV5M_OS_CONTEXT) {
597 kret = ENOMEM;
598
599 /* Get memory for the context */
600 if ((os_ctx = (krb5_os_context)
601 MALLOC(sizeof(struct _krb5_os_context))) &&
602 (remain >= 4*sizeof(krb5_int32))) {
603 (void) memset(os_ctx, 0, sizeof(struct _krb5_os_context));
604 os_ctx->magic = KV5M_OS_CONTEXT;
605
606 /* Read out our context */
607 (void) krb5_ser_unpack_int32(&os_ctx->time_offset, &bp, &remain);
608 (void) krb5_ser_unpack_int32(&os_ctx->usec_offset, &bp, &remain);
609 (void) krb5_ser_unpack_int32(&os_ctx->os_flags, &bp, &remain);
610 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
611
612 if (ibuf == KV5M_OS_CONTEXT) {
613 os_ctx->magic = KV5M_OS_CONTEXT;
614 kret = 0;
615 *buffer = bp;
616 *lenremain = remain;
617 } else
618 kret = EINVAL;
619 }
620 }
621 if (!kret) {
622 *argp = (krb5_pointer) os_ctx;
623 }
624 else {
625 if (os_ctx)
626 FREE(os_ctx, sizeof(struct _krb5_os_context));
627 }
628 return(kret);
629 }
630
631 /*
632 * Register the context serializers.
633 */
634 krb5_error_code KRB5_CALLCONV
krb5_ser_context_init(krb5_context kcontext)635 krb5_ser_context_init(krb5_context kcontext)
636 {
637 krb5_error_code kret;
638 kret = krb5_register_serializer(kcontext, &krb5_context_ser_entry);
639 if (!kret)
640 kret = krb5_register_serializer(kcontext, &krb5_oscontext_ser_entry);
641
642 /* Profile nformation need not be serialzied when we are importing the
643 * context into kernel. Besides the function pointers to file access
644 * routines can't be used in the kernel.
645
646 * Any info needed from the profile is already a part of the
647 * exported context obviating the need for importer to know about
648 * profile config files.
649
650 */
651
652 #ifndef _KERNEL
653 if (!kret)
654 kret = krb5_register_serializer(kcontext, &krb5_profile_ser_entry);
655 #endif
656 return(kret);
657 }
658