git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@17460 ec53bebd-3082-4978-b11e-865c3cabbd6b
		
			
				
	
	
		
			643 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			643 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
@c $Id$
 | 
						|
 | 
						|
@node Programming with Kerberos, Migration, Windows 2000 compatability, Top
 | 
						|
@chapter Programming with Kerberos
 | 
						|
 | 
						|
First you need to know how the Kerberos model works, go read the
 | 
						|
introduction text (@pxref{What is Kerberos?}).
 | 
						|
 | 
						|
@menu
 | 
						|
* Kerberos 5 API Overview::     
 | 
						|
* Walkthrough of a sample Kerberos 5 client::  
 | 
						|
* Validating a password in a server application::  
 | 
						|
* API differences to MIT Kerberos::  
 | 
						|
* File formats::
 | 
						|
@end menu
 | 
						|
 | 
						|
@node Kerberos 5 API Overview, Walkthrough of a sample Kerberos 5 client, Programming with Kerberos, Programming with Kerberos
 | 
						|
@section Kerberos 5 API Overview
 | 
						|
 | 
						|
All functions are documented in manual pages.  This section tries to
 | 
						|
give an overview of the major components used in Kerberos library, and
 | 
						|
point to where to look for a specific function.
 | 
						|
 | 
						|
@subsection Kerberos context
 | 
						|
 | 
						|
A kerberos context (@code{krb5_context}) holds all per thread state. All global variables that
 | 
						|
are context specific are stored in this structure, including default
 | 
						|
encryption types, credential cache (for example, a ticket file), and default realms.
 | 
						|
 | 
						|
See the manual pages for @manpage{krb5_context,3} and
 | 
						|
@manpage{krb5_init_context,3}.
 | 
						|
 | 
						|
@subsection Kerberos authentication context
 | 
						|
 | 
						|
Kerberos authentication context (@code{krb5_auth_context}) holds all
 | 
						|
context related to an authenticated connection, in a similar way to the
 | 
						|
kerberos context that holds the context for the thread or process.
 | 
						|
 | 
						|
The @code{krb5_auth_context} is used by various functions that are
 | 
						|
directly related to authentication between the server/client. Example of
 | 
						|
data that this structure contains are various flags, addresses of client
 | 
						|
and server, port numbers, keyblocks (and subkeys), sequence numbers,
 | 
						|
replay cache, and checksum types.
 | 
						|
 | 
						|
See the manual page for @manpage{krb5_auth_context,3}.
 | 
						|
 | 
						|
@subsection Kerberos principal
 | 
						|
 | 
						|
The Kerberos principal is the structure that identifies a user or
 | 
						|
service in Kerberos. The structure that holds the principal is the
 | 
						|
@code{krb5_principal}. There are function to extract the realm and
 | 
						|
elements of the principal, but most applications have no reason to
 | 
						|
inspect the content of the structure.
 | 
						|
 | 
						|
The are several ways to create a principal (with different degree of
 | 
						|
portability), and one way to free it.
 | 
						|
 | 
						|
See manual page for @manpage{krb5_principal,3} for more information
 | 
						|
about the functions.
 | 
						|
 | 
						|
@subsection Credential cache
 | 
						|
 | 
						|
A credential cache holds the tickets for a user. A given user can have
 | 
						|
several credential caches, one for each realm where the user have the
 | 
						|
initial tickets (the first krbtgt).
 | 
						|
 | 
						|
The credential cache data can be stored internally in different way, each of them for
 | 
						|
different proposes.  File credential (FILE) caches and processes based
 | 
						|
(KCM) caches are for permanent storage. While memory caches (MEMORY)
 | 
						|
are local caches to the local process.
 | 
						|
 | 
						|
Caches are opened with @manpage{krb5_cc_resolve,3} or created with
 | 
						|
@manpage{krb5_cc_gen_unique,3}.
 | 
						|
 | 
						|
If the cache needs to be opened again (using
 | 
						|
@manpage{krb5_cc_resolve,3}) @manpage{krb5_cc_close,3} will close the
 | 
						|
handle, but not the remove the cache. @manpage{krb5_cc_destroy,3} will
 | 
						|
zero out the cache, remove the cache so it can no longer be
 | 
						|
referenced.
 | 
						|
 | 
						|
See also manual page for @manpage{krb5_ccache,3}
 | 
						|
 | 
						|
@subsection Kerberos errors
 | 
						|
 | 
						|
Kerberos errors are based on the com_err library.  All error codes are
 | 
						|
32-bit signed numbers, the first 24 bits define what subsystem the
 | 
						|
error originates from, and last 8 bits are 255 error codes within the
 | 
						|
library.  Each error code have fixed string associated with it.  For
 | 
						|
example, the error-code -1765328383 have the symbolic name
 | 
						|
KRB5KDC_ERR_NAME_EXP, and associated error string ``Client's entry in
 | 
						|
database has expired''.
 | 
						|
 | 
						|
This is a great improvement compared to just getting one of the unix
 | 
						|
error-codes back.  However, Heimdal have an extention to pass back
 | 
						|
customised errors messages.  Instead of getting ``Key table entry not
 | 
						|
found'', the user might back ``failed to find
 | 
						|
host/host.example.com@@EXAMLE.COM(kvno 3) in keytab /etc/krb5.keytab
 | 
						|
(des-cbc-crc)''.  This improves the chance that the user find the
 | 
						|
cause of the error so you should use the customised error message
 | 
						|
whenever its available.
 | 
						|
 | 
						|
See also manual page for @manpage{krb5_get_error_string,3} and
 | 
						|
@manpage{krb5_get_err_text,3}.
 | 
						|
 | 
						|
@subsection Keytab management
 | 
						|
 | 
						|
A keytab is a storage for locally stored keys. Heimdal includes keytab
 | 
						|
support for Kerberos 5 keytabs, Kerberos 4 srvtab, AFS-KeyFile's,
 | 
						|
and for storing keys in memory.
 | 
						|
 | 
						|
Keytabs are used for servers and long-running services.
 | 
						|
 | 
						|
See also manual page for @manpage{krb5_keytab,3}
 | 
						|
 | 
						|
@subsection Kerberos crypto
 | 
						|
 | 
						|
Heimdal includes a implementation of the Kerberos crypto framework,
 | 
						|
all crypto operations.
 | 
						|
 | 
						|
See also manual page for @manpage{krb5_crypto_init,3},
 | 
						|
@manpage{krb5_keyblock,3}, @manpage{krb5_create_checksum,3}, 
 | 
						|
and @manpage{krb5_encrypt,3}.
 | 
						|
 | 
						|
@node Walkthrough of a sample Kerberos 5 client, Validating a password in a server application, Kerberos 5 API Overview, Programming with Kerberos
 | 
						|
@section Walkthrough of a sample Kerberos 5 client
 | 
						|
 | 
						|
This example contains parts of a sample TCP Kerberos 5 clients, if you
 | 
						|
want a real working client, please look in @file{appl/test} directory in
 | 
						|
the Heimdal distribution.
 | 
						|
 | 
						|
All Kerberos error-codes that are returned from kerberos functions in
 | 
						|
this program are passed to @code{krb5_err}, that will print a
 | 
						|
descriptive text of the error code and exit. Graphical programs can
 | 
						|
convert error-code to a human readable error-string with the
 | 
						|
@manpage{krb5_get_err_text,3} function.
 | 
						|
 | 
						|
Note that you should not use any Kerberos function before
 | 
						|
@code{krb5_init_context()} have completed successfully. That is the
 | 
						|
reason @code{err()} is used when @code{krb5_init_context()} fails.
 | 
						|
 | 
						|
First the client needs to call @code{krb5_init_context} to initialise
 | 
						|
the Kerberos 5 library. This is only needed once per thread
 | 
						|
in the program. If the function returns a non-zero value it indicates
 | 
						|
that either the Kerberos implementation is failing or its disabled on
 | 
						|
this host.
 | 
						|
 | 
						|
@example
 | 
						|
#include <krb5.h>
 | 
						|
 | 
						|
int
 | 
						|
main(int argc, char **argv)
 | 
						|
@{
 | 
						|
        krb5_context context;
 | 
						|
 | 
						|
        if (krb5_context(&context))
 | 
						|
                errx (1, "krb5_context");
 | 
						|
@end example
 | 
						|
 | 
						|
Now the client wants to connect to the host at the other end. The
 | 
						|
preferred way of doing this is using @manpage{getaddrinfo,3} (for
 | 
						|
operating system that have this function implemented), since getaddrinfo
 | 
						|
is neutral to the address type and can use any protocol that is available.
 | 
						|
 | 
						|
@example
 | 
						|
        struct addrinfo *ai, *a;
 | 
						|
        struct addrinfo hints;
 | 
						|
        int error;
 | 
						|
 | 
						|
        memset (&hints, 0, sizeof(hints));
 | 
						|
        hints.ai_socktype = SOCK_STREAM;
 | 
						|
        hints.ai_protocol = IPPROTO_TCP;
 | 
						|
 | 
						|
        error = getaddrinfo (hostname, "pop3", &hints, &ai);
 | 
						|
        if (error)
 | 
						|
                errx (1, "%s: %s", hostname, gai_strerror(error));
 | 
						|
 | 
						|
        for (a = ai; a != NULL; a = a->ai_next) @{
 | 
						|
                int s;
 | 
						|
 | 
						|
                s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
 | 
						|
                if (s < 0)
 | 
						|
                        continue;
 | 
						|
                if (connect (s, a->ai_addr, a->ai_addrlen) < 0) @{
 | 
						|
                        warn ("connect(%s)", hostname);
 | 
						|
                            close (s);
 | 
						|
                            continue;
 | 
						|
                @}
 | 
						|
                freeaddrinfo (ai);
 | 
						|
                ai = NULL;
 | 
						|
        @}
 | 
						|
        if (ai) @{
 | 
						|
                    freeaddrinfo (ai);
 | 
						|
                    errx ("failed to contact %s", hostname);
 | 
						|
        @}
 | 
						|
@end example
 | 
						|
 | 
						|
Before authenticating, an authentication context needs to be
 | 
						|
created. This context keeps all information for one (to be) authenticated
 | 
						|
connection (see @manpage{krb5_auth_context,3}).
 | 
						|
 | 
						|
@example
 | 
						|
        status = krb5_auth_con_init (context, &auth_context);
 | 
						|
        if (status)
 | 
						|
                krb5_err (context, 1, status, "krb5_auth_con_init");
 | 
						|
@end example
 | 
						|
 | 
						|
For setting the address in the authentication there is a help function
 | 
						|
@code{krb5_auth_con_setaddrs_from_fd} that does everything that is needed
 | 
						|
when given a connected file descriptor to the socket.
 | 
						|
 | 
						|
@example
 | 
						|
        status = krb5_auth_con_setaddrs_from_fd (context,
 | 
						|
                                                 auth_context,
 | 
						|
                                                 &sock);
 | 
						|
        if (status)
 | 
						|
                krb5_err (context, 1, status, 
 | 
						|
                          "krb5_auth_con_setaddrs_from_fd");
 | 
						|
@end example
 | 
						|
 | 
						|
The next step is to build a server principal for the service we want
 | 
						|
to connect to. (See also @manpage{krb5_sname_to_principal,3}.)
 | 
						|
 | 
						|
@example
 | 
						|
        status = krb5_sname_to_principal (context,
 | 
						|
                                          hostname,
 | 
						|
                                          service,
 | 
						|
                                          KRB5_NT_SRV_HST,
 | 
						|
                                          &server);
 | 
						|
        if (status)
 | 
						|
                krb5_err (context, 1, status, "krb5_sname_to_principal");
 | 
						|
@end example
 | 
						|
 | 
						|
The client principal is not passed to @manpage{krb5_sendauth,3}
 | 
						|
function, this causes the @code{krb5_sendauth} function to try to figure it
 | 
						|
out itself.
 | 
						|
 | 
						|
The server program is using the function @manpage{krb5_recvauth,3} to
 | 
						|
receive the Kerberos 5 authenticator.
 | 
						|
 | 
						|
In this case, mutual authentication will be tried. That means that the server
 | 
						|
will authenticate to the client. Using mutual authentication
 | 
						|
is good since it enables the user to verify that they are talking to the
 | 
						|
right server (a server that knows the key).
 | 
						|
 | 
						|
If you are using a non-blocking socket you will need to do all work of
 | 
						|
@code{krb5_sendauth} yourself. Basically you need to send over the
 | 
						|
authenticator from @manpage{krb5_mk_req,3} and, in case of mutual
 | 
						|
authentication, verifying the result from the server with
 | 
						|
@manpage{krb5_rd_rep,3}.
 | 
						|
 | 
						|
@example
 | 
						|
        status = krb5_sendauth (context,
 | 
						|
                                &auth_context,
 | 
						|
                                &sock,
 | 
						|
                                VERSION,
 | 
						|
                                NULL,
 | 
						|
                                server,
 | 
						|
                                AP_OPTS_MUTUAL_REQUIRED,
 | 
						|
                                NULL,
 | 
						|
                                NULL,
 | 
						|
                                NULL,
 | 
						|
                                NULL,
 | 
						|
                                NULL,
 | 
						|
                                NULL);
 | 
						|
        if (status)
 | 
						|
                krb5_err (context, 1, status, "krb5_sendauth");
 | 
						|
@end example
 | 
						|
 | 
						|
Once authentication has been performed, it is time to send some
 | 
						|
data. First we create a krb5_data structure, then we sign it with
 | 
						|
@manpage{krb5_mk_safe,3} using the @code{auth_context} that contains the
 | 
						|
session-key that was exchanged in the
 | 
						|
@manpage{krb5_sendauth,3}/@manpage{krb5_recvauth,3} authentication
 | 
						|
sequence.
 | 
						|
 | 
						|
@example
 | 
						|
        data.data   = "hej";
 | 
						|
        data.length = 3;
 | 
						|
 | 
						|
        krb5_data_zero (&packet);
 | 
						|
 | 
						|
        status = krb5_mk_safe (context,
 | 
						|
                               auth_context,
 | 
						|
                               &data,
 | 
						|
                               &packet,
 | 
						|
                               NULL);
 | 
						|
        if (status)
 | 
						|
                krb5_err (context, 1, status, "krb5_mk_safe");
 | 
						|
@end example
 | 
						|
 | 
						|
And send it over the network.
 | 
						|
 | 
						|
@example
 | 
						|
        len = packet.length;
 | 
						|
        net_len = htonl(len);
 | 
						|
 | 
						|
        if (krb5_net_write (context, &sock, &net_len, 4) != 4)
 | 
						|
                err (1, "krb5_net_write");
 | 
						|
        if (krb5_net_write (context, &sock, packet.data, len) != len)
 | 
						|
                err (1, "krb5_net_write");
 | 
						|
@end example
 | 
						|
 | 
						|
To send encrypted (and signed) data @manpage{krb5_mk_priv,3} should be
 | 
						|
used instead. @manpage{krb5_mk_priv,3} works the same way as
 | 
						|
@manpage{krb5_mk_safe,3}, with the exception that it encrypts the data
 | 
						|
in addition to signing it.
 | 
						|
 | 
						|
@example
 | 
						|
        data.data   = "hemligt";
 | 
						|
        data.length = 7;
 | 
						|
 | 
						|
        krb5_data_free (&packet);
 | 
						|
 | 
						|
        status = krb5_mk_priv (context,
 | 
						|
                               auth_context,
 | 
						|
                               &data,
 | 
						|
                               &packet,
 | 
						|
                               NULL);
 | 
						|
        if (status)
 | 
						|
                krb5_err (context, 1, status, "krb5_mk_priv");
 | 
						|
@end example
 | 
						|
 | 
						|
And send it over the network.
 | 
						|
 | 
						|
@example
 | 
						|
        len = packet.length;
 | 
						|
        net_len = htonl(len);
 | 
						|
 | 
						|
        if (krb5_net_write (context, &sock, &net_len, 4) != 4)
 | 
						|
                err (1, "krb5_net_write");
 | 
						|
        if (krb5_net_write (context, &sock, packet.data, len) != len)
 | 
						|
                err (1, "krb5_net_write");
 | 
						|
 | 
						|
@end example
 | 
						|
 | 
						|
The server is using @manpage{krb5_rd_safe,3} and
 | 
						|
@manpage{krb5_rd_priv,3} to verify the signature and decrypt the packet.
 | 
						|
 | 
						|
@node Validating a password in a server application, API differences to MIT Kerberos, Walkthrough of a sample Kerberos 5 client, Programming with Kerberos
 | 
						|
@section Validating a password in an application
 | 
						|
 | 
						|
See the manual page for @manpage{krb5_verify_user,3}.
 | 
						|
 | 
						|
@node API differences to MIT Kerberos, File formats, Validating a password in a server application, Programming with Kerberos
 | 
						|
@section API differences to MIT Kerberos
 | 
						|
 | 
						|
This section is somewhat disorganised, but so far there is no overall
 | 
						|
structure to the differences, though some of the have their root in
 | 
						|
that Heimdal uses an ASN.1 compiler and MIT doesn't.
 | 
						|
 | 
						|
@subsection Principal and realms
 | 
						|
 | 
						|
Heimdal stores the realm as a @code{krb5_realm}, that is a @code{char *}.
 | 
						|
MIT Kerberos uses a @code{krb5_data} to store a realm.
 | 
						|
 | 
						|
In Heimdal @code{krb5_principal} doesn't contain the component
 | 
						|
@code{name_type}; it's instead stored in component
 | 
						|
@code{name.name_type}. To get and set the nametype in Heimdal, use
 | 
						|
@manpage{krb5_principal_get_type,3} and
 | 
						|
@manpage{krb5_principal_set_type,3}.
 | 
						|
 | 
						|
For more information about principal and realms, see
 | 
						|
@manpage{krb5_principal,3}.
 | 
						|
 | 
						|
@subsection Error messages
 | 
						|
 | 
						|
To get the error string, Heimdal uses
 | 
						|
@manpage{krb5_get_error_string,3} or, if @code{NULL} is returned,
 | 
						|
@manpage{krb5_get_err_text,3}. This is to return custom error messages
 | 
						|
(like ``Can't find host/datan.example.com@@EXAMPLE.COM in
 | 
						|
/etc/krb5.conf.'' instead of a ``Key table entry not found'' that
 | 
						|
@manpage{error_message,3} returns.
 | 
						|
 | 
						|
Heimdal uses a threadsafe(r) version of the com_err interface; the
 | 
						|
global @code{com_err} table isn't initialised.  Then
 | 
						|
@manpage{error_message,3} returns quite a boring error string (just
 | 
						|
the error code itself).
 | 
						|
 | 
						|
 | 
						|
@c @node Why you should use GSS-API for new applications, Walkthrough of a sample GSS-API client, Validating a password in a server application, Programming with Kerberos
 | 
						|
@c @section Why you should use GSS-API for new applications
 | 
						|
@c 
 | 
						|
@c SSPI, bah, bah, microsoft, bah, bah, almost GSS-API.
 | 
						|
@c 
 | 
						|
@c It would also be possible for other mechanisms then Kerberos, but that
 | 
						|
@c doesn't exist any other GSS-API implementations today.
 | 
						|
@c 
 | 
						|
@c @node Walkthrough of a sample GSS-API client, , Why you should use GSS-API for new applications, Programming with Kerberos
 | 
						|
@c @section Walkthrough of a sample GSS-API client
 | 
						|
@c 
 | 
						|
@c Write about how gssapi_clent.c works.
 | 
						|
 | 
						|
@node File formats,  , API differences to MIT Kerberos, Programming with Kerberos
 | 
						|
@section File formats
 | 
						|
 | 
						|
This section documents the diffrent file formats that are used in
 | 
						|
Heimdal and other Kerberos implementations.
 | 
						|
 | 
						|
@subsection keytab
 | 
						|
 | 
						|
The keytab binary format is not a standard format. The format has
 | 
						|
evolved and may continue to. It is however understood by several
 | 
						|
Kerberos implementations including Heimdal, MIT, Sun's Java ktab and
 | 
						|
are created by the ktpass.exe utility from Windows. So it has
 | 
						|
established itself as the defacto format for storing Kerberos keys.
 | 
						|
 | 
						|
The following C-like structure definitions illustrate the MIT keytab
 | 
						|
file format. All values are in network byte order. All text is ASCII.
 | 
						|
 | 
						|
@example
 | 
						|
  keytab @{
 | 
						|
      uint16_t file_format_version;                    /* 0x502 */
 | 
						|
      keytab_entry entries[*];
 | 
						|
  @};
 | 
						|
 | 
						|
  keytab_entry @{
 | 
						|
      int32_t size;
 | 
						|
      uint16_t num_components;   /* subtract 1 if version 0x501 */
 | 
						|
      counted_octet_string realm;
 | 
						|
      counted_octet_string components[num_components];
 | 
						|
      uint32_t name_type;       /* not present if version 0x501 */
 | 
						|
      uint32_t timestamp;
 | 
						|
      uint8_t vno8;
 | 
						|
      keyblock key;
 | 
						|
      uint32_t vno; /* only present if >= 4 bytes left in entry */
 | 
						|
  @};
 | 
						|
 | 
						|
  counted_octet_string @{
 | 
						|
      uint16_t length;
 | 
						|
      uint8_t data[length];
 | 
						|
  @};
 | 
						|
 | 
						|
  keyblock @{
 | 
						|
      uint16_t type;
 | 
						|
      counted_octet_string;
 | 
						|
  @};
 | 
						|
@end example
 | 
						|
 | 
						|
All numbers are stored in network byteorder (big endian) format.
 | 
						|
 | 
						|
The keytab file format begins with the 16 bit file_format_version which
 | 
						|
at the time this document was authored is 0x502. The format of older
 | 
						|
keytabs is described at the end of this document.
 | 
						|
 | 
						|
The file_format_version is immediately followed by an array of
 | 
						|
keytab_entry structures which are prefixed with a 32 bit size indicating
 | 
						|
the number of bytes that follow in the entry. Note that the size should be
 | 
						|
evaluated as signed. This is because a negative value indicates that the
 | 
						|
entry is in fact empty (e.g. it has been deleted) and that the negative
 | 
						|
value of that negative value (which is of course a positive value) is
 | 
						|
the offset to the next keytab_entry. Based on these size values alone
 | 
						|
the entire keytab file can be traversed.
 | 
						|
 | 
						|
The size is followed by a 16 bit num_components field indicating the
 | 
						|
number of counted_octet_string components in the components array.
 | 
						|
 | 
						|
The num_components field is followed by a counted_octet_string
 | 
						|
representing the realm of the principal.
 | 
						|
 | 
						|
A counted_octet_string is simply an array of bytes prefixed with a 16
 | 
						|
bit length. For the realm and name components, the counted_octet_string
 | 
						|
bytes are ASCII encoded text with no zero terminator.
 | 
						|
 | 
						|
Following the realm is the components array that represents the name of
 | 
						|
the principal. The text of these components may be joined with slashs
 | 
						|
to construct the typical SPN representation. For example, the service
 | 
						|
principal HTTP/www.foo.net@@FOO.NET would consist of name components
 | 
						|
"HTTP" followed by "www.foo.net".
 | 
						|
 | 
						|
Following the components array is the 32 bit name_type (e.g. 1 is
 | 
						|
KRB5_NT_PRINCIPAL, 2 is KRB5_NT_SRV_INST, 5 is KRB5_NT_UID, etc). In
 | 
						|
practice the name_type is almost certainly 1 meaning KRB5_NT_PRINCIPAL.
 | 
						|
 | 
						|
The 32 bit timestamp indicates the time the key was established for that
 | 
						|
principal. The value represents the number of seconds since Jan 1, 1970.
 | 
						|
 | 
						|
The 8 bit vno8 field is the version number of the key. This value is
 | 
						|
overridden by the 32 bit vno field if it is present. The vno8 field is
 | 
						|
filled with the lower 8 bits of the 32 bit protocol kvno field.
 | 
						|
 | 
						|
The keyblock structure consists of a 16 bit value indicating the
 | 
						|
encryption type and is a counted_octet_string containing the key.  The
 | 
						|
encryption type is the same as the Kerberos standard (e.g. 3 is
 | 
						|
des-cbc-md5, 23 is arcfour-hmac-md5, etc).
 | 
						|
 | 
						|
The last field of the keytab_entry structure is optional. If the size of
 | 
						|
the keytab_entry indicates that there are at least 4 bytes remaining,
 | 
						|
a 32 bit value representing the key version number is present. This
 | 
						|
value supersedes the 8 bit vno8 value preceeding the keyblock.
 | 
						|
 | 
						|
Older keytabs with a file_format_version of 0x501 are different in
 | 
						|
three ways:
 | 
						|
 | 
						|
@table @asis
 | 
						|
@item All integers are in host byte order [1].
 | 
						|
@item The num_components field is 1 too large (i.e. after decoding, decrement by 1).
 | 
						|
@item The 32 bit name_type field is not present.
 | 
						|
@end table
 | 
						|
 | 
						|
[1] The file_format_version field should really be treated as two
 | 
						|
separate 8 bit quantities representing the major and minor version
 | 
						|
number respectively.
 | 
						|
 | 
						|
@subsection Heimdal database dump file
 | 
						|
 | 
						|
Format of the Heimdal text dump file as of Heimdal 0.6.3:
 | 
						|
 | 
						|
Each line in the dump file is one entry in the database.
 | 
						|
 | 
						|
Each field of a line is separated by one or more spaces, with the
 | 
						|
exception of fields consisting of principals containing spaces, where
 | 
						|
space can be quoted with \ and \ is quoted by \.
 | 
						|
 | 
						|
Fields and their types are:
 | 
						|
 | 
						|
@example
 | 
						|
	Quoted princial (quote character is \) [string]
 | 
						|
	Keys [keys]
 | 
						|
	Created by [event]
 | 
						|
	Modified by [event optional]
 | 
						|
	Valid start time [time optional]
 | 
						|
	Valid end time [time optional]
 | 
						|
	Password end valid time [time optional]
 | 
						|
	Max lifetime of ticket [time optional]
 | 
						|
	Max renew time of ticket [integer optional]
 | 
						|
	Flags [hdb flags]
 | 
						|
	Generation number [generation optional]
 | 
						|
	Extensions [extentions optional]
 | 
						|
@end example
 | 
						|
 | 
						|
Fields following these silently are ignored.
 | 
						|
 | 
						|
All optional fields will be skipped if they fail to parse (or comprise
 | 
						|
the optional field marker of "-", w/o quotes).
 | 
						|
 | 
						|
Example:
 | 
						|
 | 
						|
@example
 | 
						|
fred@@EXAMPLE.COM 27:1:16:e8b4c8fc7e60b9e641dcf4cff3f08a701d982a2f89ba373733d26ca59ba6c789666f6b8bfcf169412bb1e5dceb9b33cda29f3412:-:1:3:4498a933881178c744f4232172dcd774c64e81fa6d05ecdf643a7e390624a0ebf3c7407a:-:1:2:b01934b13eb795d76f3a80717d469639b4da0cfb644161340ef44fdeb375e54d684dbb85:-:1:1:ea8e16d8078bf60c781da90f508d4deccba70595258b9d31888d33987cd31af0c9cced2e:- 20020415130120:admin@@EXAMPLE.COM 20041221112428:fred@@EXAMPLE.COM - - - 86400 604800 126 20020415130120:793707:28 -
 | 
						|
@end example
 | 
						|
 | 
						|
Encoding of types are as follows:
 | 
						|
 | 
						|
@table @asis
 | 
						|
@item keys
 | 
						|
 | 
						|
@example
 | 
						|
kvno:[masterkvno:keytype:keydata:salt]@{zero or more separated by :@}
 | 
						|
@end example
 | 
						|
 | 
						|
kvno is the key version number.
 | 
						|
 | 
						|
keydata is hex-encoded
 | 
						|
 | 
						|
masterkvno is the kvno of the database master key.  If this field is
 | 
						|
empty, the kadmin load and merge operations will encrypt the key data
 | 
						|
with the master key if there is one.  Otherwise the key data will be
 | 
						|
imported asis.
 | 
						|
 | 
						|
salt is encoded as "-" (no/default salt) or
 | 
						|
 | 
						|
@example
 | 
						|
salt-type /
 | 
						|
salt-type / "string"
 | 
						|
salt-type / hex-encoded-data
 | 
						|
@end example
 | 
						|
 | 
						|
keytype is the protocol enctype number; see enum ENCTYPE in
 | 
						|
include/krb5_asn1.h for values.
 | 
						|
 | 
						|
Example:
 | 
						|
@example
 | 
						|
27:1:16:e8b4c8fc7e60b9e641dcf4cff3f08a701d982a2f89ba373733d26ca59ba6c789666f6b8bfcf169412bb1e5dceb9b33cda29f3412:-:1:3:4498a933881178c744f4232172dcd774c64e81fa6d05ecdf643a7e390624a0ebf3c7407a:-:1:2:b01934b13eb795d76f3a80717d469639b4da0cfb644161340ef44fdeb375e54d684dbb85:-:1:1:ea8e16d8078bf60c781da90f508d4deccba70595258b9d31888d33987cd31af0c9cced2e:-
 | 
						|
@end example
 | 
						|
 | 
						|
 | 
						|
@example
 | 
						|
kvno=27,@{key: masterkvno=1,keytype=des3-cbc-sha1,keydata=..., default salt@}...
 | 
						|
@end example
 | 
						|
 | 
						|
@item time
 | 
						|
	
 | 
						|
Format of the time is: YYYYmmddHHMMSS, corresponding to strftime
 | 
						|
format "%Y%m%d%k%M%S".
 | 
						|
 | 
						|
Time is expressed in UTC.
 | 
						|
 | 
						|
Time can be optional (using -), when the time 0 is used.
 | 
						|
 | 
						|
Example:
 | 
						|
 | 
						|
@example
 | 
						|
20041221112428
 | 
						|
@end example
 | 
						|
 | 
						|
@item event
 | 
						|
 | 
						|
@example
 | 
						|
	time:principal
 | 
						|
@end example
 | 
						|
 | 
						|
time is as given in format time
 | 
						|
 | 
						|
principal is a string.  Not quoting it may not work in earlier
 | 
						|
versions of Heimdal.
 | 
						|
 | 
						|
Example:
 | 
						|
@example
 | 
						|
20041221112428:bloggs@@EXAMPLE.COM
 | 
						|
@end example
 | 
						|
 | 
						|
@item hdb flags
 | 
						|
 | 
						|
Integer encoding of HDB flags, see HDBFlags in lib/hdb/hdb.asn1. Each
 | 
						|
bit in the integer is the same as the bit in the specification.
 | 
						|
 | 
						|
@item generation:
 | 
						|
 | 
						|
@example
 | 
						|
time:usec:gen
 | 
						|
@end example
 | 
						|
 | 
						|
 | 
						|
usec is a the microsecond, integer.
 | 
						|
gen is generation number, integer.
 | 
						|
 | 
						|
The generation can be defaulted (using '-') or the empty string
 | 
						|
 | 
						|
@item extensions:
 | 
						|
 | 
						|
@example
 | 
						|
first-hex-encoded-HDB-Extension[:second-...]
 | 
						|
@end example
 | 
						|
 | 
						|
HDB-extension is encoded the DER encoded HDB-Extension from
 | 
						|
lib/hdb/hdb.asn1. Consumers HDB extensions should be aware that
 | 
						|
unknown entires needs to be preserved even thought the ASN.1 data
 | 
						|
content might be unknown. There is a critical flag in the data to show
 | 
						|
to the KDC that the entry MUST be understod if the entry is to be
 | 
						|
used.
 | 
						|
 | 
						|
@end table
 |