5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Copyright 1990,1991,1995 by the Massachusetts Institute of Technology.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * All Rights Reserved.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Export of this software from the United States of America may
505d05c73a6e56769f263d4803b22eddd168ee24gtb * require a specific license from the United States Government.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * It is the responsibility of any person or organization contemplating
505d05c73a6e56769f263d4803b22eddd168ee24gtb * export to obtain such a license before exporting.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
505d05c73a6e56769f263d4803b22eddd168ee24gtb * distribute this software and its documentation for any purpose and
505d05c73a6e56769f263d4803b22eddd168ee24gtb * without fee is hereby granted, provided that the above copyright
505d05c73a6e56769f263d4803b22eddd168ee24gtb * notice appear in all copies and that both that copyright notice and
505d05c73a6e56769f263d4803b22eddd168ee24gtb * this permission notice appear in supporting documentation, and that
505d05c73a6e56769f263d4803b22eddd168ee24gtb * the name of M.I.T. not be used in advertising or publicity pertaining
505d05c73a6e56769f263d4803b22eddd168ee24gtb * to distribution of the software without specific, written prior
505d05c73a6e56769f263d4803b22eddd168ee24gtb * permission. Furthermore if you modify this software you must label
505d05c73a6e56769f263d4803b22eddd168ee24gtb * your software as modified software and not distribute it in such a
505d05c73a6e56769f263d4803b22eddd168ee24gtb * fashion that it might be confused with the original M.I.T. software.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * M.I.T. makes no representations about the suitability of
505d05c73a6e56769f263d4803b22eddd168ee24gtb * this software for any purpose. It is provided "as is" without express
505d05c73a6e56769f263d4803b22eddd168ee24gtb * or implied warranty.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Information needed by internal routines of the file-based ticket
505d05c73a6e56769f263d4803b22eddd168ee24gtb * cache implementation.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Constants
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KRB5_KT_VNO_1 0x0501 /* krb v5, keytab version 1 (DCE compat) */
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KRB5_KT_VNO 0x0502 /* krb v5, keytab version 2 (standard) */
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KTFILENAME(id) (((krb5_ktfile_data *)(id)->data)->name)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KTFILEP(id) (((krb5_ktfile_data *)(id)->data)->openf)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KTFILEBUFP(id) (((krb5_ktfile_data *)(id)->data)->iobuf)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KTVERSION(id) (((krb5_ktfile_data *)(id)->data)->version)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KTLOCK(id) k5_mutex_lock(&((krb5_ktfile_data *)(id)->data)->lock)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KTUNLOCK(id) k5_mutex_unlock(&((krb5_ktfile_data *)(id)->data)->lock)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define KTCHECKLOCK(id) k5_mutex_assert_locked(&((krb5_ktfile_data *)(id)->data)->lock)
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery__krb5_principal_compare_case_ins(krb5_context context,
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery krb5_const_principal princ1, krb5_const_principal princ2);
505d05c73a6e56769f263d4803b22eddd168ee24gtb const char *,
505d05c73a6e56769f263d4803b22eddd168ee24gtb const char *,
505d05c73a6e56769f263d4803b22eddd168ee24gtb unsigned int);
505d05c73a6e56769f263d4803b22eddd168ee24gtb/* routines to be included on extended version (write routines) */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This is an implementation specific resolver. It returns a keytab id
505d05c73a6e56769f263d4803b22eddd168ee24gtb * initialized with file keytab routines.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_resolve(krb5_context context, const char *name, krb5_keytab *id)
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((data = (krb5_ktfile_data *)malloc(sizeof(krb5_ktfile_data))) == NULL) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb return(0);
505d05c73a6e56769f263d4803b22eddd168ee24gtb * "Close" a file-based keytab and invalidate the id. This means
505d05c73a6e56769f263d4803b22eddd168ee24gtb * free memory hidden in the structures.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This routine is responsible for freeing all memory allocated
505d05c73a6e56769f263d4803b22eddd168ee24gtb * for this keytab. There are no system resources that need
505d05c73a6e56769f263d4803b22eddd168ee24gtb * to be freed nor are there any open files.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This routine should undo anything done by krb5_ktfile_resolve().
505d05c73a6e56769f263d4803b22eddd168ee24gtb k5_mutex_destroy(&((krb5_ktfile_data *)id->data)->lock);
505d05c73a6e56769f263d4803b22eddd168ee24gtb return (0);
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This is the get_entry routine for the file based keytab implementation.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * It opens the keytab file, and either retrieves the entry or returns
505d05c73a6e56769f263d4803b22eddd168ee24gtb * an error.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_get_entry(krb5_context context, krb5_keytab id,
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Open the keyfile for reading */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * For efficiency and simplicity, we'll use a while true that
505d05c73a6e56769f263d4803b22eddd168ee24gtb * is exited with a break statement.
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry)))
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* by the time this loop exits, it must either free cur_entry,
505d05c73a6e56769f263d4803b22eddd168ee24gtb and copy new_entry there, or free new_entry. Otherwise, it
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* if the principal isn't the one requested, free new_entry
505d05c73a6e56769f263d4803b22eddd168ee24gtb and continue to the next. */
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery * Solaris Kerberos: MS Interop requires that case insensitive
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery * comparisons of service and host components are performed for key
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery * table lookup, etc. Only called if the private environment variable
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery * MS_INTEROP is defined.
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery if (!__krb5_principal_compare_case_ins(context, principal,
72f0806acd90f56fb47a8087c33cfeaec527fddaShawn Emery } else if (!krb5_principal_compare(context, principal,
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* if the enctype is not ignored and doesn't match, free new_entry
505d05c73a6e56769f263d4803b22eddd168ee24gtb and continue to the next */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Coerce the enctype of the output keyblock in case we
505d05c73a6e56769f263d4803b22eddd168ee24gtb * got an inexact match on the enctype.
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* if this is the first match, or if the new vno is
505d05c73a6e56769f263d4803b22eddd168ee24gtb bigger, free the current and keep the new. Otherwise,
505d05c73a6e56769f263d4803b22eddd168ee24gtb free the new. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* A 1.2.x keytab contains only the low 8 bits of the key
505d05c73a6e56769f263d4803b22eddd168ee24gtb version number. Since it can be much bigger, and thus
505d05c73a6e56769f263d4803b22eddd168ee24gtb the 8-bit value can wrap, we need some heuristics to
505d05c73a6e56769f263d4803b22eddd168ee24gtb figure out the "highest" numbered key if some numbers
505d05c73a6e56769f263d4803b22eddd168ee24gtb close to 255 and some near 0 are used.
505d05c73a6e56769f263d4803b22eddd168ee24gtb The heuristic here:
505d05c73a6e56769f263d4803b22eddd168ee24gtb If we have any keys with versions over 240, then assume
505d05c73a6e56769f263d4803b22eddd168ee24gtb that all version numbers 0-127 refer to 256+N instead.
505d05c73a6e56769f263d4803b22eddd168ee24gtb Not perfect, but maybe good enough? */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* if this kvno matches, free the current (will there ever
505d05c73a6e56769f263d4803b22eddd168ee24gtb be one?), keep the new, and break out. Otherwise, remember
505d05c73a6e56769f263d4803b22eddd168ee24gtb that we were here so we can return the right error, and
505d05c73a6e56769f263d4803b22eddd168ee24gtb free the new */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Yuck. The krb5-1.2.x keytab format only stores one byte
505d05c73a6e56769f263d4803b22eddd168ee24gtb for the kvno, so we're toast if the kvno requested is
505d05c73a6e56769f263d4803b22eddd168ee24gtb higher than that. Short-term workaround: only compare
505d05c73a6e56769f263d4803b22eddd168ee24gtb the low 8 bits. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((kerror = krb5_ktfileint_close(context, id)) != 0) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Get the name of the file containing a file-based keytab.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This routine returns the name of the name of the file associated with
505d05c73a6e56769f263d4803b22eddd168ee24gtb * this file-based keytab. name is zeroed and the filename is truncated
505d05c73a6e56769f263d4803b22eddd168ee24gtb * to fit in name if necessary. The name is prefixed with PREFIX:, so that
505d05c73a6e56769f263d4803b22eddd168ee24gtb * trt will happen if the name is passed back to resolve.
159d09a20817016f09b3ea28d1bdada4a336bb91Mark Phalan /* Solaris Kerberos */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* strcpy will NUL-terminate the destination */
505d05c73a6e56769f263d4803b22eddd168ee24gtb return(0);
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktfile_start_seq_get()
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktfile_get_next()
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor)
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((kerror = krb5_ktfileint_read_entry(context, id, &cur_entry))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktfile_end_get()
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * ser_ktf.c - Serialize keytab file context for subsequent reopen.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Routines to deal with externalizing krb5_keytab for [WR]FILE: variants.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_keytab_size();
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_keytab_externalize();
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_keytab_internalize();
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Serialization entry for this type.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_keytab_size() - Determine the size required to externalize
505d05c73a6e56769f263d4803b22eddd168ee24gtb * this krb5_keytab variant.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktf_keytab_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Saving FILE: variants of krb5_keytab requires at minimum:
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_int32 for KV5M_KEYTAB
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_int32 for length of keytab name.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_int32 for file status.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_int32 for file position.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_int32 for file position.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_int32 for version.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_int32 for KV5M_KEYTAB
505d05c73a6e56769f263d4803b22eddd168ee24gtb * The keytab name is formed as follows:
505d05c73a6e56769f263d4803b22eddd168ee24gtb * <prefix>:<name>
505d05c73a6e56769f263d4803b22eddd168ee24gtb * If there's no name, we use a default name so that we have something
505d05c73a6e56769f263d4803b22eddd168ee24gtb * to call krb5_keytab_resolve with.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_keytab_externalize() - Externalize the krb5_keytab.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktf_keytab_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Our identifier */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Calculate the length of the name */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Format the keytab name. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Fill in the file-specific keytab information. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb#if !defined(_WIN32)
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Put the length of the file name */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Put the name */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Put the file open flag */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Put the file position */
159d09a20817016f09b3ea28d1bdada4a336bb91Mark Phalan (void) krb5_ser_pack_int64(file_pos, &bp, &remain);
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Put the version */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Put the trailer */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_keytab_internalize() - Internalize the krb5_ktf_keytab.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktf_keytab_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Read our magic number */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Get the length of the keytab name */
505d05c73a6e56769f263d4803b22eddd168ee24gtb keytab->data = (void *) malloc(sizeof(krb5_ktfile_data));
159d09a20817016f09b3ea28d1bdada4a336bb91Mark Phalan (void) krb5_ser_unpack_int64(&foff, &bp, &remain);
505d05c73a6e56769f263d4803b22eddd168ee24gtb#if !defined(_WIN32)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This is an implementation specific resolver. It returns a keytab id
505d05c73a6e56769f263d4803b22eddd168ee24gtb * initialized with file keytab routines.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_wresolve(krb5_context context, const char *name, krb5_keytab *id)
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((data = (krb5_ktfile_data *)malloc(sizeof(krb5_ktfile_data))) == NULL) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb return(0);
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktfile_add()
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
505d05c73a6e56769f263d4803b22eddd168ee24gtb retval = krb5_ktfileint_write_entry(context, id, entry);
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktfile_remove()
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfile_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * For efficiency and simplicity, we'll use a while true that
505d05c73a6e56769f263d4803b22eddd168ee24gtb * is exited with a break statement.
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((kerror = krb5_ktfileint_internal_read_entry(context, id,
505d05c73a6e56769f263d4803b22eddd168ee24gtb krb5_principal_compare(context, entry->principal, cur_entry.principal)) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* found a match */
505d05c73a6e56769f263d4803b22eddd168ee24gtb kerror = krb5_ktfileint_delete_entry(context, id, delete_point);
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_ops
505d05c73a6e56769f263d4803b22eddd168ee24gtb "FILE", /* Prefix -- this string should not appear anywhere else! */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_ktf_writable_ops
505d05c73a6e56769f263d4803b22eddd168ee24gtb "WRFILE", /* Prefix -- this string should not appear anywhere else! */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * krb5_kt_dfl_ops
505d05c73a6e56769f263d4803b22eddd168ee24gtb "FILE", /* Prefix -- this string should not appear anywhere else! */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Copyright (c) Hewlett-Packard Company 1991
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Released to the Massachusetts Institute of Technology for inclusion
505d05c73a6e56769f263d4803b22eddd168ee24gtb * in the Kerberos source code distribution.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Copyright 1990,1991 by the Massachusetts Institute of Technology.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * All Rights Reserved.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Export of this software from the United States of America may
505d05c73a6e56769f263d4803b22eddd168ee24gtb * require a specific license from the United States Government.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * It is the responsibility of any person or organization contemplating
505d05c73a6e56769f263d4803b22eddd168ee24gtb * export to obtain such a license before exporting.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
505d05c73a6e56769f263d4803b22eddd168ee24gtb * distribute this software and its documentation for any purpose and
505d05c73a6e56769f263d4803b22eddd168ee24gtb * without fee is hereby granted, provided that the above copyright
505d05c73a6e56769f263d4803b22eddd168ee24gtb * notice appear in all copies and that both that copyright notice and
505d05c73a6e56769f263d4803b22eddd168ee24gtb * this permission notice appear in supporting documentation, and that
505d05c73a6e56769f263d4803b22eddd168ee24gtb * the name of M.I.T. not be used in advertising or publicity pertaining
505d05c73a6e56769f263d4803b22eddd168ee24gtb * to distribution of the software without specific, written prior
505d05c73a6e56769f263d4803b22eddd168ee24gtb * permission. Furthermore if you modify this software you must label
505d05c73a6e56769f263d4803b22eddd168ee24gtb * your software as modified software and not distribute it in such a
505d05c73a6e56769f263d4803b22eddd168ee24gtb * fashion that it might be confused with the original M.I.T. software.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * M.I.T. makes no representations about the suitability of
505d05c73a6e56769f263d4803b22eddd168ee24gtb * this software for any purpose. It is provided "as is" without express
505d05c73a6e56769f263d4803b22eddd168ee24gtb * or implied warranty.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This function contains utilities for the file based implementation of
505d05c73a6e56769f263d4803b22eddd168ee24gtb * the keytab. There are no public functions in this file.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * This file is the only one that has knowledge of the format of a
505d05c73a6e56769f263d4803b22eddd168ee24gtb * keytab file.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * The format is as follows:
505d05c73a6e56769f263d4803b22eddd168ee24gtb * <file format vno>
505d05c73a6e56769f263d4803b22eddd168ee24gtb * <record length>
505d05c73a6e56769f263d4803b22eddd168ee24gtb * principal timestamp vno key
505d05c73a6e56769f263d4803b22eddd168ee24gtb * <record length>
505d05c73a6e56769f263d4803b22eddd168ee24gtb * principal timestamp vno key
505d05c73a6e56769f263d4803b22eddd168ee24gtb * A length field (sizeof(krb5_int32)) exists between entries. When this
505d05c73a6e56769f263d4803b22eddd168ee24gtb * length is positive it indicates an active entry, when negative a hole.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * The length indicates the size of the block in the file (this may be
505d05c73a6e56769f263d4803b22eddd168ee24gtb * larger than the size of the next record, since we are using a first
505d05c73a6e56769f263d4803b22eddd168ee24gtb * fit algorithm for re-using holes and the first fit may be larger than
505d05c73a6e56769f263d4803b22eddd168ee24gtb * the entry we are writing). Another (compatible) implementation could
505d05c73a6e56769f263d4803b22eddd168ee24gtb * break up holes when allocating them to smaller entries to minimize
505d05c73a6e56769f263d4803b22eddd168ee24gtb * wasted space. (Such an implementation should also coalesce adjacent
505d05c73a6e56769f263d4803b22eddd168ee24gtb * holes to reduce fragmentation). This implementation does neither.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * There are no separators between fields of an entry.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * A principal is a length-encoded array of length-encoded strings. The
505d05c73a6e56769f263d4803b22eddd168ee24gtb * length is a krb5_int16 in each case. The specific format, then, is
505d05c73a6e56769f263d4803b22eddd168ee24gtb * multiple entries concatinated with no separators. An entry has this
505d05c73a6e56769f263d4803b22eddd168ee24gtb * exact format:
505d05c73a6e56769f263d4803b22eddd168ee24gtb * sizeof(krb5_int16) bytes for number of components in the principal;
505d05c73a6e56769f263d4803b22eddd168ee24gtb * then, each component listed in ordser.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * For each component, sizeof(krb5_int16) bytes for the number of bytes
505d05c73a6e56769f263d4803b22eddd168ee24gtb * in the component, followed by the component.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * sizeof(krb5_int32) for the principal type (for KEYTAB V2 and higher)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * sizeof(krb5_int32) bytes for the timestamp
505d05c73a6e56769f263d4803b22eddd168ee24gtb * sizeof(krb5_octet) bytes for the key version number
505d05c73a6e56769f263d4803b22eddd168ee24gtb * sizeof(krb5_int16) bytes for the enctype
505d05c73a6e56769f263d4803b22eddd168ee24gtb * sizeof(krb5_int32) bytes for the key length, followed by the key
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define krb5_kt_default_vno ((krb5_kt_vno)KRB5_KT_DEFAULT_VNO)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define xfwrite(a, b, c, d) fwrite((char *)a, b, (unsigned) c, d)
505d05c73a6e56769f263d4803b22eddd168ee24gtb#define xfread(a, b, c, d) fread((char *)a, b, (unsigned) c, d)
159d09a20817016f09b3ea28d1bdada4a336bb91Mark Phalan/* Solaris Kerberos */
159d09a20817016f09b3ea28d1bdada4a336bb91Mark Phalan/* Solaris Kerberos */
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((mode == KRB5_LOCKMODE_EXCLUSIVE) && (errno == ENOENT)) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* try making it first time around */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos - added dgettext */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Key table file '%s' not found"),
505d05c73a6e56769f263d4803b22eddd168ee24gtb if ((kerror = krb5_lock_file(context, fileno(KTFILEP(id)), mode))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* assume ANSI or BSD-style stdio */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* get the vno and verify it */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(&kt_vno, sizeof(kt_vno), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* gotta verify it instead... */
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_openr(krb5_context context, krb5_keytab id)
505d05c73a6e56769f263d4803b22eddd168ee24gtb return krb5_ktfileint_open(context, id, KRB5_LOCKMODE_SHARED);
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_openw(krb5_context context, krb5_keytab id)
505d05c73a6e56769f263d4803b22eddd168ee24gtb return krb5_ktfileint_open(context, id, KRB5_LOCKMODE_EXCLUSIVE);
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_close(krb5_context context, krb5_keytab id)
505d05c73a6e56769f263d4803b22eddd168ee24gtb kerror = krb5_unlock_file(context, fileno(KTFILEP(id)));
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_delete_entry(krb5_context context, krb5_keytab id, krb5_int32 delete_point)
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (size > 0) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(&minus_size, sizeof(minus_size), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb while (size > 0) {
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_internal_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *ret_entry, krb5_int32 *delete_point)
505d05c73a6e56769f263d4803b22eddd168ee24gtb register int i;
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* fseek to synchronise buffered I/O on the key table. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (size < 0) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb } while (size < 0);
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (size == 0) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* deal with guts of parsing... */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* first, int16 with #princ components */
505d05c73a6e56769f263d4803b22eddd168ee24gtb ret_entry->principal = (krb5_principal)malloc(sizeof(krb5_principal_data));
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* Now, get the realm data */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb krb5_princ_set_realm_length(context, ret_entry->principal, u_princ_size);
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (fread(tmpdata, 1, u_princ_size, KTFILEP(id)) != (size_t) princ_size) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb tmpdata[princ_size] = 0; /* Some things might be expecting null */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* termination... ``Be conservative in */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* what you send out'' */
505d05c73a6e56769f263d4803b22eddd168ee24gtb krb5_princ_set_realm_data(context, ret_entry->principal, tmpdata);
505d05c73a6e56769f263d4803b22eddd168ee24gtb for (i = 0; i < count; i++) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb princ = krb5_princ_component(context, ret_entry->principal, i);
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfread(princ->data, sizeof(char), u_princ_size, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* read in the principal type, if we can get it */
505d05c73a6e56769f263d4803b22eddd168ee24gtb ret_entry->principal->type = ntohl(ret_entry->principal->type);
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* read in the timestamp */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfread(&ret_entry->timestamp, sizeof(ret_entry->timestamp), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* read in the version number */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* key type */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfread(&enctype, sizeof(enctype), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* key contents */
505d05c73a6e56769f263d4803b22eddd168ee24gtb ret_entry->key.contents = (krb5_octet *)malloc(u_count);
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfread(ret_entry->key.contents, sizeof(krb5_octet), count,
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Reposition file pointer to the next inter-record length field.
505d05c73a6e56769f263d4803b22eddd168ee24gtb for (i = 0; i < krb5_princ_size(context, ret_entry->principal); i++) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb princ = krb5_princ_component(context, ret_entry->principal, i);
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entryp)
505d05c73a6e56769f263d4803b22eddd168ee24gtb return krb5_ktfileint_internal_read_entry(context, id, entryp, &delete_point);
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
505d05c73a6e56769f263d4803b22eddd168ee24gtb retval = krb5_ktfileint_size_entry(context, entry, &size_needed);
505d05c73a6e56769f263d4803b22eddd168ee24gtb retval = krb5_ktfileint_find_slot(context, id, &size_needed, &commit_point);
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* fseek to synchronise buffered I/O on the key table. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* XXX Without the weird setbuf crock, can we get rid of this now? */
505d05c73a6e56769f263d4803b22eddd168ee24gtb count = (krb5_int16) krb5_princ_size(context, entry->principal) + 1;
505d05c73a6e56769f263d4803b22eddd168ee24gtb count = htons((u_short) krb5_princ_size(context, entry->principal));
505d05c73a6e56769f263d4803b22eddd168ee24gtb size = krb5_princ_realm(context, entry->principal)->length;
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(krb5_princ_realm(context, entry->principal)->data, sizeof(char),
505d05c73a6e56769f263d4803b22eddd168ee24gtb krb5_princ_realm(context, entry->principal)->length, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb count = (krb5_int16) krb5_princ_size(context, entry->principal);
505d05c73a6e56769f263d4803b22eddd168ee24gtb for (i = 0; i < count; i++) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb princ = krb5_princ_component(context, entry->principal, i);
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(princ->data, sizeof(char), princ->length, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Write out the principal type
505d05c73a6e56769f263d4803b22eddd168ee24gtb princ_type = htonl(krb5_princ_type(context, entry->principal));
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(&princ_type, sizeof(princ_type), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Fill in the time of day the entry was written to the keytab.
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(×tamp, sizeof(timestamp), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* key version number */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* key type */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(&enctype, sizeof(enctype), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* key length */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (!xfwrite(&size_needed, sizeof(size_needed), 1, KTFILEP(id))) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Determine the size needed for a file entry for the given
505d05c73a6e56769f263d4803b22eddd168ee24gtb * keytab entry.
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_size_entry(krb5_context context, krb5_keytab_entry *entry, krb5_int32 *size_needed)
505d05c73a6e56769f263d4803b22eddd168ee24gtb count = (krb5_int16) krb5_princ_size(context, entry->principal);
505d05c73a6e56769f263d4803b22eddd168ee24gtb total_size += krb5_princ_realm(context, entry->principal)->length + (sizeof(krb5_int16));
505d05c73a6e56769f263d4803b22eddd168ee24gtb for (i = 0; i < count; i++) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb total_size += krb5_princ_component(context, entry->principal,i)->length
505d05c73a6e56769f263d4803b22eddd168ee24gtb + (sizeof(krb5_int16));
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Find and reserve a slot in the file for an entry of the needed size.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * The commit point will be set to the position in the file where the
505d05c73a6e56769f263d4803b22eddd168ee24gtb * the length (sizeof(krb5_int32) bytes) of this node should be written
505d05c73a6e56769f263d4803b22eddd168ee24gtb * when commiting the write. The file position left as a result of this
505d05c73a6e56769f263d4803b22eddd168ee24gtb * call is the position where the actual data should be written.
505d05c73a6e56769f263d4803b22eddd168ee24gtb * The size_needed argument may be adjusted if we find a hole that is
505d05c73a6e56769f263d4803b22eddd168ee24gtb * larger than the size needed. (Recall that size_needed will be used
505d05c73a6e56769f263d4803b22eddd168ee24gtb * to commit the write, but that this field must indicate the size of the
505d05c73a6e56769f263d4803b22eddd168ee24gtb * block in the file rather than the size of the actual entry)
505d05c73a6e56769f263d4803b22eddd168ee24gtbkrb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_needed, krb5_int32 *commit_point)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Skip over file version number
505d05c73a6e56769f263d4803b22eddd168ee24gtb while (!found) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Hit the end of file, reserve this slot.
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* fseek to synchronise buffered I/O on the key table. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* XXX Without the weird setbuf hack, can we nuke this now? */
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* We don't have to do this because htonl(0) == 0 */
505d05c73a6e56769f263d4803b22eddd168ee24gtb if (size > 0) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb } else if (!found) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb } else if (size > 0) {
505d05c73a6e56769f263d4803b22eddd168ee24gtb * The current hole is not large enough, so skip it
505d05c73a6e56769f263d4803b22eddd168ee24gtb /* fseek to synchronise buffered I/O on the key table. */
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Found the end of the file (marked by a 0 length buffer)
505d05c73a6e56769f263d4803b22eddd168ee24gtb * Make sure we zero any trailing data.