/* * lib/krb5/krb/ser_ctx.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * ser_ctx.c - Routines to deal with serializing the krb5_context and * krb5_os_context structures. */ #include "k5-int.h" /* * Routines to deal with externalizing the krb5_context: * krb5_context_size(); * krb5_context_externalize(); * krb5_context_internalize(); * * Routines to deal with externalizing the krb5_os_context: * krb5_oscontext_size(); * krb5_oscontext_externalize(); * krb5_oscontext_internalize(); * * Routines to deal with externalizing the profile. * profile_ser_size(); * profile_ser_externalize(); * profile_ser_internalize(); * * Interface to initialize serializing of krb5_context and krb5_os_context: * krb5_ser_context_init(); */ static krb5_error_code krb5_context_size (krb5_context, krb5_pointer, size_t *); static krb5_error_code krb5_context_externalize (krb5_context, krb5_pointer, krb5_octet **, size_t *); static krb5_error_code krb5_context_internalize (krb5_context,krb5_pointer *, krb5_octet **, size_t *); static krb5_error_code krb5_oscontext_size (krb5_context, krb5_pointer, size_t *); static krb5_error_code krb5_oscontext_externalize (krb5_context, krb5_pointer, krb5_octet **, size_t *); static krb5_error_code krb5_oscontext_internalize (krb5_context,krb5_pointer *, krb5_octet **, size_t *); #ifndef _KERNEL krb5_error_code profile_ser_size (krb5_context, krb5_pointer, size_t *); krb5_error_code profile_ser_externalize (krb5_context, krb5_pointer, krb5_octet **, size_t *); krb5_error_code profile_ser_internalize (krb5_context,krb5_pointer *, krb5_octet **, size_t *); #endif /* Local data */ static const krb5_ser_entry krb5_context_ser_entry = { KV5M_CONTEXT, /* Type */ krb5_context_size, /* Sizer routine */ krb5_context_externalize, /* Externalize routine */ krb5_context_internalize /* Internalize routine */ }; static const krb5_ser_entry krb5_oscontext_ser_entry = { KV5M_OS_CONTEXT, /* Type */ krb5_oscontext_size, /* Sizer routine */ krb5_oscontext_externalize, /* Externalize routine */ krb5_oscontext_internalize /* Internalize routine */ }; #ifndef _KERNEL static const krb5_ser_entry krb5_profile_ser_entry = { PROF_MAGIC_PROFILE, /* Type */ profile_ser_size, /* Sizer routine */ profile_ser_externalize, /* Externalize routine */ profile_ser_internalize /* Internalize routine */ }; #endif /* * krb5_context_size() - Determine the size required to externalize the * krb5_context. */ static krb5_error_code krb5_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) { krb5_error_code kret; size_t required; krb5_context context; /* * The KRB5 context itself requires: * krb5_int32 for KV5M_CONTEXT * krb5_int32 for sizeof(default_realm) * strlen(default_realm) for default_realm. * krb5_int32 for n_in_tkt_ktypes*sizeof(krb5_int32) * nktypes*sizeof(krb5_int32) for in_tkt_ktypes. * krb5_int32 for n_tgs_ktypes*sizeof(krb5_int32) * nktypes*sizeof(krb5_int32) for tgs_ktypes. * krb5_int32 for clockskew * krb5_int32 for kdc_req_sumtype * krb5_int32 for ap_req_sumtype * krb5_int32 for safe_sumtype * krb5_int32 for kdc_default_options * krb5_int32 for library_options * krb5_int32 for profile_secure * krb5_int32 for fcc_default_format * krb5_int32 for scc_default_format * <> for os_context * <> for db_context * <> for profile * krb5_int32 for trailer. */ kret = EINVAL; if ((context = (krb5_context) arg)) { /* Calculate base length */ required = (14 * sizeof(krb5_int32) + (context->in_tkt_ktype_count * sizeof(krb5_int32)) + (context->tgs_ktype_count * sizeof(krb5_int32))); if (context->default_realm) required += strlen(context->default_realm); /* Calculate size required by os_context, if appropriate */ if (context->os_context) kret = krb5_size_opaque(kcontext, KV5M_OS_CONTEXT, (krb5_pointer) context->os_context, &required); /* Calculate size required by db_context, if appropriate */ if (!kret && context->db_context) kret = krb5_size_opaque(kcontext, KV5M_DB_CONTEXT, (krb5_pointer) context->db_context, &required); /* Finally, calculate size required by profile, if appropriate */ if (!kret && context->profile) kret = krb5_size_opaque(kcontext, PROF_MAGIC_PROFILE, (krb5_pointer) context->profile, &required); } if (!kret) *sizep += required; return(kret); } /* * krb5_context_externalize() - Externalize the krb5_context. */ static krb5_error_code krb5_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain) { krb5_error_code kret; krb5_context context; size_t required; krb5_octet *bp; size_t remain; int i; required = 0; bp = *buffer; remain = *lenremain; context = (krb5_context) arg; if (!context) return (EINVAL); KRB5_VERIFY_MAGIC(context, KV5M_CONTEXT); if ((kret = krb5_context_size(kcontext, arg, &required))) return (kret); if (required > remain) return (ENOMEM); /* First write our magic number */ kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain); if (kret) return (kret); /* Now sizeof default realm */ kret = krb5_ser_pack_int32((context->default_realm) ? (krb5_int32) strlen(context->default_realm) : 0, &bp, &remain); if (kret) return (kret); /* Now default_realm bytes */ if (context->default_realm) { kret = krb5_ser_pack_bytes((krb5_octet *) context->default_realm, strlen(context->default_realm), &bp, &remain); if (kret) return (kret); } /* Now number of initial ticket ktypes */ kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktype_count, &bp, &remain); if (kret) return (kret); /* Now serialize ktypes */ for (i=0; iin_tkt_ktype_count; i++) { kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktypes[i], &bp, &remain); if (kret) return (kret); } /* Now number of default ktypes */ kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktype_count, &bp, &remain); if (kret) return (kret); /* Now serialize ktypes */ for (i=0; itgs_ktype_count; i++) { kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktypes[i], &bp, &remain); if (kret) return (kret); } /* Now allowable clockskew */ kret = krb5_ser_pack_int32((krb5_int32) context->clockskew, &bp, &remain); if (kret) return (kret); /* Now kdc_req_sumtype */ kret = krb5_ser_pack_int32((krb5_int32) context->kdc_req_sumtype, &bp, &remain); if (kret) return (kret); /* Now default ap_req_sumtype */ kret = krb5_ser_pack_int32((krb5_int32) context->default_ap_req_sumtype, &bp, &remain); if (kret) return (kret); /* Now default safe_sumtype */ kret = krb5_ser_pack_int32((krb5_int32) context->default_safe_sumtype, &bp, &remain); if (kret) return (kret); /* Now kdc_default_options */ kret = krb5_ser_pack_int32((krb5_int32) context->kdc_default_options, &bp, &remain); if (kret) return (kret); /* Now library_options */ kret = krb5_ser_pack_int32((krb5_int32) context->library_options, &bp, &remain); if (kret) return (kret); /* Now profile_secure */ kret = krb5_ser_pack_int32((krb5_int32) context->profile_secure, &bp, &remain); if (kret) return (kret); /* Now fcc_default_format */ kret = krb5_ser_pack_int32((krb5_int32) context->fcc_default_format, &bp, &remain); if (kret) return (kret); /* Now scc_default_format */ kret = krb5_ser_pack_int32((krb5_int32) context->scc_default_format, &bp, &remain); if (kret) return (kret); /* Now handle os_context, if appropriate */ if (context->os_context) { kret = krb5_externalize_opaque(kcontext, KV5M_OS_CONTEXT, (krb5_pointer) context->os_context, &bp, &remain); if (kret) return (kret); } /* Now handle database context, if appropriate */ if (context->db_context) { kret = krb5_externalize_opaque(kcontext, KV5M_DB_CONTEXT, (krb5_pointer) context->db_context, &bp, &remain); if (kret) return (kret); } /* Finally, handle profile, if appropriate */ if (context->profile) { kret = krb5_externalize_opaque(kcontext, PROF_MAGIC_PROFILE, (krb5_pointer) context->profile, &bp, &remain); if (kret) return (kret); } /* * If we were successful, write trailer then update the pointer and * remaining length; */ kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain); if (kret) return (kret); *buffer = bp; *lenremain = remain; return (0); } /* * krb5_context_internalize() - Internalize the krb5_context. */ static krb5_error_code krb5_context_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain) { krb5_error_code kret; krb5_context context; krb5_int32 ibuf; krb5_octet *bp; size_t remain; int i; bp = *buffer; remain = *lenremain; /* Read our magic number */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) return (EINVAL); if (ibuf != KV5M_CONTEXT) return (EINVAL); /* Get memory for the context */ context = (krb5_context) MALLOC(sizeof(struct _krb5_context)); if (!context) return (ENOMEM); (void) memset(context, 0, sizeof(struct _krb5_context)); /* Get the size of the default realm */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; if (ibuf) { context->default_realm = (char *) MALLOC((size_t) ibuf+1); if (!context->default_realm) { kret = ENOMEM; goto cleanup; } kret = krb5_ser_unpack_bytes((krb5_octet *) context->default_realm, (size_t) ibuf, &bp, &remain); if (kret) goto cleanup; context->default_realm[ibuf] = '\0'; } /* Get the number of in_tkt_ktypes */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->in_tkt_ktype_count = (int) ibuf; context->in_tkt_ktypes = (krb5_enctype *) MALLOC(sizeof(krb5_enctype) * (context->in_tkt_ktype_count+1)); if (!context->in_tkt_ktypes) { kret = ENOMEM; goto cleanup; } (void) memset(context->in_tkt_ktypes, 0, (sizeof(krb5_enctype) * (context->in_tkt_ktype_count + 1))); for (i=0; iin_tkt_ktype_count; i++) { if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->in_tkt_ktypes[i] = (krb5_enctype) ibuf; } /* Get the number of tgs_ktypes */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->tgs_ktype_count = (int) ibuf; context->tgs_ktypes = (krb5_enctype *) MALLOC(sizeof(krb5_enctype) * (context->tgs_ktype_count+1)); if (!context->tgs_ktypes) { kret = ENOMEM; goto cleanup; } (void) memset(context->tgs_ktypes, 0, (sizeof(krb5_enctype) * (context->tgs_ktype_count + 1))); for (i=0; itgs_ktype_count; i++) { if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->tgs_ktypes[i] = (krb5_enctype) ibuf; } /* Allowable checksum */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->clockskew = (krb5_deltat) ibuf; /* kdc_req_sumtype */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->kdc_req_sumtype = (krb5_cksumtype) ibuf; /* default ap_req_sumtype */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->default_ap_req_sumtype = (krb5_cksumtype) ibuf; /* default_safe_sumtype */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->default_safe_sumtype = (krb5_cksumtype) ibuf; /* kdc_default_options */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->kdc_default_options = (krb5_flags) ibuf; /* library_options */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->library_options = (krb5_flags) ibuf; /* profile_secure */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->profile_secure = (krb5_boolean) ibuf; /* fcc_default_format */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->fcc_default_format = (int) ibuf; /* scc_default_format */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; context->scc_default_format = (int) ibuf; /* Attempt to read in the os_context. It's an array now, but we still treat it in most places as a separate object with a pointer. */ { krb5_os_context osp = 0; kret = krb5_internalize_opaque(kcontext, KV5M_OS_CONTEXT, (krb5_pointer *) &osp, &bp, &remain); if (kret && (kret != EINVAL) && (kret != ENOENT)) goto cleanup; /* Put the newly allocated data into the krb5_context structure where we're really keeping it these days. */ if (osp) *context->os_context = *osp; free(osp); } /* Attempt to read in the db_context */ kret = krb5_internalize_opaque(kcontext, KV5M_DB_CONTEXT, (krb5_pointer *) &context->db_context, &bp, &remain); if (kret && (kret != EINVAL) && (kret != ENOENT)) goto cleanup; #ifndef _KERNEL /* Attempt to read in the profile */ kret = krb5_internalize_opaque(kcontext, PROF_MAGIC_PROFILE, (krb5_pointer *) &context->profile, &bp, &remain); #endif if (kret && (kret != EINVAL) && (kret != ENOENT)) goto cleanup; /* Finally, find the trailer */ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) goto cleanup; if (ibuf != KV5M_CONTEXT) { kret = EINVAL; goto cleanup; } context->magic = KV5M_CONTEXT; *buffer = bp; *lenremain = remain; *argp = (krb5_pointer) context; return 0; cleanup: if (context) krb5_free_context(context); return(kret); } /* * krb5_oscontext_size() - Determine the size required to externalize * the krb5_os_context. */ /*ARGSUSED*/ static krb5_error_code krb5_oscontext_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) { /* * We need five 32-bit integers: * two for header and trailer * one each for time_offset, usec_offset and os_flags */ *sizep += (5*sizeof(krb5_int32)); return(0); } /* * krb5_oscontext_externalize() - Externalize the krb5_os_context. */ static krb5_error_code krb5_oscontext_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain) { krb5_error_code kret; krb5_os_context os_ctx; size_t required; krb5_octet *bp; size_t remain; required = 0; bp = *buffer; remain = *lenremain; kret = EINVAL; if ((os_ctx = (krb5_os_context) arg)) { kret = ENOMEM; if (!krb5_oscontext_size(kcontext, arg, &required) && (required <= remain)) { (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain); (void) krb5_ser_pack_int32(os_ctx->time_offset, &bp, &remain); (void) krb5_ser_pack_int32(os_ctx->usec_offset, &bp, &remain); (void) krb5_ser_pack_int32(os_ctx->os_flags, &bp, &remain); (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain); /* Handle any other OS context here */ kret = 0; if (!kret) { *buffer = bp; *lenremain = remain; } } } return(kret); } /* * krb5_oscontext_internalize() - Internalize the krb5_os_context. */ /*ARGSUSED*/ static krb5_error_code krb5_oscontext_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain) { krb5_error_code kret; krb5_os_context os_ctx; krb5_int32 ibuf; krb5_octet *bp; size_t remain; bp = *buffer; remain = *lenremain; kret = EINVAL; os_ctx = (krb5_os_context) NULL; /* Read our magic number */ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) ibuf = 0; if (ibuf == KV5M_OS_CONTEXT) { kret = ENOMEM; /* Get memory for the context */ if ((os_ctx = (krb5_os_context) MALLOC(sizeof(struct _krb5_os_context))) && (remain >= 4*sizeof(krb5_int32))) { (void) memset(os_ctx, 0, sizeof(struct _krb5_os_context)); os_ctx->magic = KV5M_OS_CONTEXT; /* Read out our context */ (void) krb5_ser_unpack_int32(&os_ctx->time_offset, &bp, &remain); (void) krb5_ser_unpack_int32(&os_ctx->usec_offset, &bp, &remain); (void) krb5_ser_unpack_int32(&os_ctx->os_flags, &bp, &remain); (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); if (ibuf == KV5M_OS_CONTEXT) { os_ctx->magic = KV5M_OS_CONTEXT; kret = 0; *buffer = bp; *lenremain = remain; } else kret = EINVAL; } } if (!kret) { *argp = (krb5_pointer) os_ctx; } else { if (os_ctx) FREE(os_ctx, sizeof(struct _krb5_os_context)); } return(kret); } /* * Register the context serializers. */ krb5_error_code KRB5_CALLCONV krb5_ser_context_init(krb5_context kcontext) { krb5_error_code kret; kret = krb5_register_serializer(kcontext, &krb5_context_ser_entry); if (!kret) kret = krb5_register_serializer(kcontext, &krb5_oscontext_ser_entry); /* Profile nformation need not be serialzied when we are importing the * context into kernel. Besides the function pointers to file access * routines can't be used in the kernel. * Any info needed from the profile is already a part of the * exported context obviating the need for importer to know about * profile config files. */ #ifndef _KERNEL if (!kret) kret = krb5_register_serializer(kcontext, &krb5_profile_ser_entry); #endif return(kret); }