Cygnus Network Security Programmer's Guide---Applications Interface for Unix and PC's by Cygnus Support.  CNS includes documentation and software developed at the Massachusetts Institute of Technology, which includes this copyright information: Copyright © 1989 by the Massachusetts Institute of Technology

     Export of software employing encryption from the United States of America is assumed to 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.  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.  Copyright © 1991, 1992, 1994, 1995 Cygnus Support.  Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.  Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.

CNS Programmer's Guide
**********************

Introduction
************

Cygnus Support developed Cygnus Network Security (CNS) to provide strong system access security, with minimal impact on users' ease of access. Using Kerberos Version 4 encryption and client-server technology, CNS assures that user identities can be checked securely without transmitting unencrypted passwords over the Net.

This document describes the application programmer interface for CNS. The interface is identical on Unix, the MacOS, and MS-Windows.  Some facilities beyond the common subset are available on some of these operating systems.  These are documented in separate chapters.

The reader is hereby warned that the U.S. Government may impose limits on the export of the software described herein.  Check with a good lawyer before exporting the software or making it available to non-citizens.

CNS Common Kerberos Library API
*******************************

This section describes the standard application programmer interface to Kerberos.  It provides facilities for configuration, shared credentials, high-level operations, and transformation routines.  Though most of the suites in this section are available on all platforms, there are a few that have not yet been ported to particular machines.  This is noted where applicable.

Kerberos Principals
===================

Kerberos principals are the users and application servers that act within Kerberos.  Each principal has a Kerberos principal name.  A Kerberos principal name contains three parts: name, instance and realm.

For a user, the principal name is the user name.  For an application server, the principal name is the name of the service being provided (e.g., the CNS rlogin, rsh and rcp programs use the principal name rcmd).

A principal instance is usually null for users, though some users may have privileged instances such as root or admin.  For an application server, the instance is the name of the machine on which it runs (e.g., the rlogin service running on the machine abc uses the name rcmd.abc, while on the machine xyz it uses rcmd.xyz).  The instance name for an application server is not the complete domain name, but just the first element (that is, the machine abc.company.org uses an instance name of just abc).

A principal realm is simply the Kerberos realm in which the principal is defined.

The Kerberos principal name is separated from the instance (if not null) by a period.  The realm (if not the local realm) follows the principal name and instance and is preceded by an `@' sign.  The following are examples of valid Kerberos names:

     gumby
     ambar.admin
     eichin@CYGNUS.COM
     raeburn.root@CYGNUS.COM
     rcmd.oursun@CYGNUS.COM

It is possible for principals to be under-specified.  If an INSTANCE is missing, it is assumed to be null.  If REALM is missing, it is assumed to be the local realm as determined by krb_get_lrealm.  The canonical form is a complete NAME[.INSTANCE][@REALM].

Principal names may not contain the `.' or `@' characters.  Instance names may not contain the `@' character.

krb.h---include file
====================

     #include "krb.h"

This include file declares data structures and function prototypes for all Kerberos operations.  Any program module that uses Kerberos facilities should #include this file.

To provide application portability among Unix, Macintosh, and MS-Windows, krb.h can declare various other system interfaces in addition to the minimal Kerberos V4 interface.  These interfaces are controlled by #ifdefs, which must be set in the application source code before the #include "krb.h".  They are:

DEFINE_SOCKADDR
     Defines symbols necessary for network programming using sockets, including struct sockaddr_in.

NEED_TIME_H
     Defines symbols necessary for getting time-of-day from the C library.

The network programming interface uses ordinary sockets on Unix, WinSock 1.1 on MS-Windows, and a fake socket implementation on Macintosh built on top of MacTCP.  We defined some of our own infrastructure where putting the WinSock coding into a Unix program would not be appropriate. They are as follows:

SOCKET_INITIALIZE()
     Must be called before any other socket calls.

SOCKET_CLEANUP()
     Must be called after finishing socket calls.

SOCKET_ERRNO
     Returns the error code from the last socket call.

SOCKET_SET_ERRNO(x)
     Sets the error code to be returned by SOCKET_ERRNO.

SOCKET_NFDS(f)
     Returns a suitable first argument for select(), given a file descriptor to be selected upon.

SOCKET_READ(fd, b, l)
     Equivalent to Unix read on a socket.

SOCKET_WRITE(fd, b, l)
     Equivalent to Unix write on a socket.

SOCKET_EINTR
     The error code returned when an I/O operation was interrupted (equivalent to EINTR on Unix).

Generic Operations
==================

These operations deal with the overall operation of Kerberos, or with error handling.

krb_start_session
-----------------

int krb_start_session(char *cache_name);

Begins a Kerberos session (an interaction with the ticket cache). In some implementations, the Kerberos support may destroy the tickets obtained by various applications when all the applications exit, for improved security on single-user machines.  Applications should neither depend on this behavior nor depend on its absence.

If cache_name is a null pointer, the default shared ticket cache is used (the usual case).  If cache_name is non-null, then a named-ticket cache may be used.  If an implementation does not implemented named caches, then the cache_name parameter is ignored.

In some environments, krb_start_session also locates and initializes the Kerberos driver or library as well as preparing an interaction with the ticket cache.

Each application should call krb_start_session once, and should also call krb_end_session before it ends.

krb_end_session
---------------

int krb_end_session(char *cache_name);

Ends a Kerberos session (an interaction with the ticket cache). In some implementations, the Kerberos support may destroy the tickets obtained by various applications when all the applications exit, for improved security on single-user machines.  Applications should neither depend on this behavior nor depend on its absence.

If cache_name is a null pointer, the default shared ticket cache session is ended (the usual case).  If cache_name is non-null, then a named ticket cache session may be ended.  If a driver does not implement named caches, then the cache_name parameter is ignored.

krb_end_session must be called if and only if the application previously called krb_start_session. krb_start_session and krb_end_session must be called in pairs.

kname_parse
-----------

int kname_parse (char *name, char *instance, char *realm, char *fullname);

This routine parses FULLNAME into the three fields NAME, INSTANCE, and REALM, which should point to memory of sizes ANAME_SZ, INST_SZ, and REALM_SZ bytes respectively. These fields must be initialized by the caller, since each remains unchanged if FULLNAME does not include that field.  Callers typically initialize them to null strings or to the local realm name.

It returns an error code based on the parse.  Only the syntax of the name is checked, not its validity in a database or on the network.

krb_get_err_text
----------------

char * krb_get_err_text (int error_code);

This returns the ASCII text string description associated with a Kerberos error code, as returned by many Kerberos functions.

Configuration suite
===================

These routines deal with extracting configuration information stored in the system.  This includes the default realm, Key Distribution Center (KDC) servers (krb.conf) and host/realm mappings (krb.realms).

krb_get_lrealm
--------------

int krb_get_lrealm(char *realm, int n);

This operation fills in the name of the default or local realm. REALM must be at least REALM_SZ (40) bytes long.  The value of N must always be `1', for historical reasons.

On Unix machines, this information is currently stored in a file called /usr/kerberos/lib/krb.conf.  In MS-Windows, it is in krb.conf, in the directory \windows\krb.rea.  On the Macintosh, it is stored in the ``Kerberos Client'' Preferences file.

krb_realmofhost
---------------

char * krb_realmofhost(char *host);

Returns the Kerberos realm of the host HOST. HOST should be the fully-qualified domain-style primary host name of the host in question.

REALM must be at least REALM_SZ (40) bytes long.

On Unix machines, this information is currently stored in a file called /usr/kerberos/lib/krb.realms.  In MS-Windows, it is stored in a file called krb.rea, whose name is contained in the kerberos.ini file.  In Macintosh, it is stored in the ``Kerberos Client'' Preferences file.  In order to prevent certain security attacks, this routine must either have a priori knowledge of a host's realm, or obtain such information securely.

The format of the translation file on Unix is described in the Cygnus Network Security---User and Administrator Documentation for CNS Version 1, manual.  If HOST exactly matches a host_name line, the corresponding realm is returned.  Otherwise, if the domain portion of HOST matches a domain_name line, the corresponding realm is returned.  If HOST contains a domain, but no translation is found, HOST'S domain is converted to upper-case and returned.  If HOST contains no discernible domain, or an error occurs, the local realm name, as supplied by krb_get_lrealm, is returned.

krb_get_krbhst
--------------

int krb_get_krbhst(char *host, char *realm, int n);

krb_get_krbhst fills in HOST with the hostname of the Nth host running a Kerberos key distribution center (KDC) for realm REALM.  HOST must be large enough to hold any hostname. (You can get a portable definition of MAXHOSTNAMELEN by using #define DEFINE_SOCKADDR before including "krb.h").

If the host is successfully filled in, the routine returns KSUCCESS.  If the configuration information is unavailable, and N equals `1', then the routine fills in HOST with kerberos.REALM and returns KSUCCESS.  If there are fewer than N hosts running a Kerberos KDC for the requested realm, or the configuration information is malformed, the routine returns KFAILURE.

To locate all key distribution centers, the application can re-call with a larger N as long as the result continues to be KSUCCESS.

On Unix machines, this information is currently stored in an ASCII configuration file called /usr/kerberos/lib/krb.conf and described in the Cygnus Network Security---User and Administrator Documentation for CNS Version 1, manual.  In MS-Windows, it is krb.conf.  The default location for krb.conf is in \windows\krb.rea.  Macintosh, it is stored in the ``Kerberos Client'' Preferences file.

krb_get_admhst
--------------

extern int krb_get_admhst(char *host, char *realm, int n);

krb_get_admhst fills in HOST with the hostname of the Nth host running a Kerberos KDC database administration server for realm REALM.  If the configuration information is unavailable or is malformed, or there are fewer than N hosts running a Kerberos KDC database administration server, the routine returns KFAILURE.

HOST must be large enough to hold any hostname (MAXHOSTNAMELEN from <sys/param.h>).

On Unix machines, this information is currently stored in a file called /usr/kerberos/lib/krb.conf.  In MS-Windows, it is krb.conf.  The default location for krb.conf is in \windows\krb.rea.  Macintosh, it is stored in the ``Kerberos Client'' Preferences file.

krb_get_default_user
--------------------

char * krb_get_default_user(void);

Returns the default USER as configured, if the Kerberos implementation has the concept of a default USER NAME.  The result may include a user name, an instance field, and possibly a realm name.

On Unix machines, the result is the current logged-in user name. In MS-Windows and Macintosh, it is the last name set with krb_set_default_user.

krb_set_default_user
--------------------

int krb_set_default_user(char *user);

Sets the default USER name to be used in future Kerberos interactions with the user.  This call can be used by applications to override the default USER configured in the Kerberos implementation.  On some platforms, this setting persists after reboots.

Credential suite
================

These routines give access to credentials which are saved for the duration of the user's interaction with their computer.  The storage for these credentials is called the credentials cache, or in older parlance inherited from the first implementation, a ticket file.

krb_get_cred
------------

int krb_get_cred (char *service, char *instance, char *realm, struct credentials *credp);

Retrieves a given credential (specified by the triple of SERVICE, INSTANCE, and REALM) from the current ticket cache.  The resulting credential is stored through the argument pointer CREDP.

The result is an error code.

krb_get_cred searches the caller's ticket cache for a ticket for the given service, instance, and realm; and, if a ticket is found, fills in the given CREDENTIALS structure with the ticket information.  If the ticket is found, krb_get_cred returns GC_OK. If the ticket file cannot be found, cannot be read, does not belong to the user (other than root), is not a regular file, or is in the wrong mode, the error GC_TKFIL is returned.

krb_save_credentials
--------------------

int krb_save_credentials ((char *service, char *instance, char *realm, C_Block session, int lifetime, int kvno, KTEXT ticket, long issue_date))

Saves the given credential into the current ticket cache.

krb_get_num_cred
----------------

int krb_get_num_cred(void)

Returns the number of credentials in the current ticket cache, or `-1' if an error occurs.

krb_get_nth_cred
----------------

int krb_get_nth_cred(char *name, char *instance, char *realm, int n)

Retrieves the Nth (where N starts at zero) credential from the current ticket cache and returns its name, instance and realm through the supplied char *s, which must point to memory areas at least NAME_SZ, INST_SZ, and REALM_SZ bytes long. The result is a Kerberos error code or KSUCCESS.  The full credential may then be obtained by using krb_get_cred.

krb_get_tf_fullname
-------------------

int krb_get_tf_fullname (char *tktfile, char *name, char *instance, char *realm)

Returns the name, instance, and realm of the principal in the current credential cache (also known as a ticket file).  The ticket file name is the first parameter.  The default name is used if the argument is a null pointer.  Name, instance, and realm must point to areas of memory at least NAME_SZ, INST_SZ, and REALM_SZ bytes long. The result is KSUCCESS or a Kerberos error code.

dest_tkt
--------

int dest_tkt(void);

Destroys all the credentials in the current ticket cache. The result is KSUCCESS or a Kerberos error code.

High-level Suite
================

This library supports network authentication and various related operations. The following calls form the high-level Kerberos suite.

krb_mk_auth
-----------

int krb_mk_auth(long options, KTEXT ticket, char *service, char *instance, char *realm, unsigned KRBINT32 checksum, char *version, KTEXT buf);

Generates an authenticator that is equivalent to that used by the standard Kerberos V4 KRB_SENDAUTH routine.

Using initial tickets stored in the current ticket cache, it gets a ticket (authenticator) for the service SERVICE on the host INSTANCE, in the realm REALM.  SERVICE should be the single component name for the service (pop, rcmd, etc). INSTANCE should be the name of the application server host; krb_mk_auth normally canonicalizes it using krb_get_phost.

The OPTIONS available are

KOPT_DONT_CANON
     Don't canonicalize instance as a hostname.  (If this option is not chosen, krb_get_phost is called to canonicalize it.)

KOPT_DONT_MK_REQ
     Don't request server ticket from Kerberos.  A ticket must be supplied in the TICKET argument.  (If this option is not chosen, and there is no ticket for the given server in the ticket cache, one will be fetched using krb_mk_req and returned in TICKET.)

KOPT_DO_MUTUAL
     Do mutual authentication, requiring that the receiving server return the CHECKSUM+1 encrypted in the session key.  The mutual authentication is done using krb_mk_priv on the other side (see recvauth.c) and krb_rd_priv on this side.

CHECKSUM is an application-provided checksum that is cryptographically transmitted in the authenticator; if the application needs no checksum securely transferred, use zero.  The VERSION argument allows the client program to pass an application-specific version string that the server program can then match against its own version string.  The resulting byte string, which should be transmitted to the application's server, is placed into the buffer buf.

If doing mutual authentication, the application should then read a response from the application server, using application-dependent means, and call krb_check_auth to check its validity.

To make a call that is compatible with the Unix sendauth and recvauth calls requires some work.  See the source code in lib/krb/sendauth.c for full details.  sendauth compatibility is deprecated because it involves sending binary data across an otherwise application-controlled TCP socket.  Instead, the application should control the manner in which the authenticator gets from the client to the server, using a protocol harmonious with the rest of the traffic on that socket.

Transformation Suite
====================

These routines create authenticated messages which can be passed between clients and servers.

The KTEXT structure is used to pass around text of varying lengths.  It consists of a buffer for the data, and a length. krb_rd_req takes an argument of this type containing the authenticator, and krb_mk_req returns the authenticator in a structure of this type.  KTEXT itself is really a pointer to the structure.  The actual structure is of type KTEXT_ST.

The AUTH_DAT structure is filled in by krb_rd_req.  It must be allocated before calling krb_rd_req, and a pointer to it is passed.  The structure is filled in with data obtained from Kerberos. The MSG_DAT structure is filled in by either krb_rd_priv, krb_rd_safe, or krb_rd_err.  It must be allocated before the call and a pointer to it is passed. The structure is filled in with data obtained from Kerberos.

Note that the caller of krb_rd_req, krb_rd_priv, and krb_rd_safe must check time order and for replay attempts.

krb_mk_req
----------

int krb_mk_req(KTEXT authent, char *service_name, char *instance, char *realm, long int xsum);

Generates an authenticator for the service SERVICE_NAME on the host INSTANCE, in realm REALM.  Using initial tickets stored in the default ticket cache, it connects to the Key Distribution Center to retrieve a service ticket.  SERVICE_NAME should be the single component name for the service (pop, discuss, etc). INSTANCE should be the unqualified name of the application server host, perhaps as obtained by a call to krb_get_phost.  XSUM is a checksum that is cryptographically transmitted in the authenticator.

krb_mk_req takes a pointer to a text structure in which an authenticator is to be built.  It also takes the name, instance, and realm of the service to be used and an optional checksum.  It is up to the application to decide how to generate the checksum. krb_mk_req then retrieves a ticket for the desired service and creates an authenticator.  The authenticator is built in AUTHENT and is accessible to the calling procedure.  It is up to the application to get the authenticator to the service where it is read by krb_rd_req.  Unless an attacker possesses the session key contained in the ticket, it cannot modify the authenticator.  Thus, the checksum can be used to verify the authenticity of the other data that pass through a connection.

krb_rd_req
----------

int krb_rd_req(KTEXT AUTHENT,char *SERVICE, char *INSTANCE, long FROM_ADDR, AUTH_DAT *AD, char *FILENAME)

krb_rd_req takes an authenticator of type KTEXT, a service name, an instance, the address of the host originating the request, and a pointer to a structure of type AUTH_DAT which is filled in with information obtained from the authenticator.  Optionally, it also takes the name of the file in which it finds the secret key(s) for the service.  If the supplied instance contains *, then the first service key with the same service name found in the service key file is used, and the INSTANCE argument is filled in with the chosen instance.  This means that the caller must provide space for such an instance name.

If the last argument is an empty string, krb_rd_req uses the file /etc/krb-srvtab to find its keys.  If the last argument is NULL, it assumes that the key in the authenticator has been set by krb_set_key and does not look further.

This routine is used to find out information about the principal when a request has been made to a service.  It is up to the application protocol to get the authenticator from the client to the service.  The routine then passes the authenticator to krb_rd_req to extract the desired information.

krb_rd_req returns zero (RD_AP_OK) upon successful authentication.  If a packet were forged, modified, or replayed, authentication fails.  If authentication fails, a non-zero value is returned indicating the particular problem encountered.  See krb.h for the list of error codes.

krb_mk_priv
-----------

krb_mk_priv(char *in, char *out, unsigned KRB_INT32 in_length, Key_schedule schedule, C_Block *key, struct sockaddr_in *sender, struct sockaddr_in *receiver);

long krb_mk_priv(u_char *IN, u_char *OUT, u_long IN_LENGTH, des_cblock KEY, des_key_schedule SCHEDULE; struct sockaddr_in *SENDER, struct sockaddr_in *RECEIVER);

krb_mk_priv creates an encrypted, authenticated message from any arbitrary application data, pointed to by IN and IN_LENGTH bytes long.  The private session key, pointed to by KEY and the key schedule, SCHEDULE, are used to encrypt the data and some header information using PCBC encryption.  SENDER and RECEIVER point to the Internet address of the two parties.  In addition to providing privacy, this protocol message protects against modifications, insertions or replays.  The encapsulated message and header are placed in the area pointed to by OUT, which should be able to hold in_length + 32 bytes.  The routine returns the length of the output, or `-1' indicating an error.

krb_rd_priv
-----------

int krb_rd_priv(char *in, unsigned KRB_INT32 in_length, char *schedule, char *key, struct sockaddr *sender, struct sockaddr *receiver, MSG_DAT *msg_data);

long krb_rd_priv(u_char *IN, u_long IN_LENGTH, Key_schedule SCHEDULE, des_cblock KEY, struct sockaddr_in *SENDER, struct sockaddr_in *RECEIVER, MSG_DAT *MSG_DATA);

This routine is used to decrypt and authenticate a message created by krb_mk_priv.  IN points to the beginning of the received message, the length of which is specified in IN_LENGTH.  The private session key, pointed to by KEY, is used to decrypt and verify the received message.  If SCHEDULE is non-null, SCHEDULE points to the calculated key schedule for the key.  The routine fills in fields in the MSG_DATA structure with information retrieved from the message.

krb_rd_priv decrypts and authenticates a received krb_mk_priv message.  The private session key, pointed to by KEY, and the key schedule, SCHEDULE, are used to decrypt and verify the received message.  MSG_DATA is a pointer to a MSG_DAT struct.  The routine fills in the app_data field with a pointer to the decrypted application data, app_length with the length of the app_data field, time_sec and time_5ms with the timestamps in the message, and swap with a `1' if the byte order of the receiver is different than that of the sender.  (The application must still determine if it is appropriate to byte-swap application data; the Kerberos protocol fields are already taken care of).  The routine returns zero if okay, or a Kerberos error code.  Modified messages and old messages cause errors, but the caller must check the time sequence of messages.

krb_mk_safe
-----------

krb_mk_safe(unsigned char *in, unsigned char *out, unsigned KRB_INT32 in_length, C_Block *key, struct sockaddr_in *sender, struct sockaddr_in *receiver);

long krb_mk_safe(u_char *IN, u_char *OUT, u_long IN_LENGTH, des_cblock KEY, struct sockaddr_in *SENDER, struct sockaddr_in *RECEIVER);

This routine makes an authenticated, but unencrypted message from any arbitrary application data, pointed to by IN and IN_LENGTH bytes long.  The private session key, pointed to by KEY, is used to seed the QUAD_CKSUM checksum algorithm used as part of the authentication. SENDER and RECEIVER point to the Internet addresses of the two parties.  The encapsulated message and header are placed in the area pointed to by OUT.  This area should be to hold IN_LENGTH + 32 bytes.  The routine returns the length of the output, or `-1' indicating an error.

This message does not provide privacy, but does protect (via detection) against modifications, insertions or replays.  The authentication provided by this routine is not as strong as that provided by krb_mk_priv or by computing the checksum using cbc_cksum instead, both of which authenticate via DES.

krb_rd_safe
-----------

long krb_rd_safe(u_char *IN, u_long IN_LENGTH, des_cblock KEY, struct sockaddr_in *SENDER, struct sockaddr_in *RECEIVER, MSG_DAT *MSG_DATA)

This routine is used to authenticate a message created by krb_mk_safe.  IN points to the beginning of the received message, whose length is specified in IN_LENGTH.  The private session key, pointed to by KEY, is used to verify the authentication checksum of the received message.

MSG_DATA is a pointer to a MSG_DAT struct, defined in krb.h. The routine fills in these MSG_DAT fields: the app_data field with a pointer to the application data, app_length with the length of the app_data field, time_sec and time_5ms with the timestamps in the message, and swap with a `1' if the byte order of the receiver is different than that of the sender.  (The application must still determine if it is appropriate to byteswap application data; the Kerberos protocol fields are already taken care of).

The routine returns zero if okay, or a Kerberos error code.  Modified messages and old messages cause errors, but the caller must check the time sequence of messages.

Encryption suite
================

The Kerberos library supports various DES encryption related operations.  It differs from the crypt, setkey, and encrypt library routines in that it provides a true DES encryption, without modifying the algorithm, and executes much faster.

For each key that may be simultaneously active, create a des_key_schedule struct.  Next, create key schedules (from the 8-byte keys) as needed, via des_key_sched, prior to using the encryption or checksum routines.  Then set up the input and output areas (lengths are restricted to be multiples of eight bytes).  Finally, invoke the encryption/decryption routine, des_cbc_encrypt or des_pcbc_encrypt.

A des_cblock struct is an 8-byte block used as the fundamental unit for DES data and keys, and is defined as:

     typedef unsigned char des_cblock[8];

and a des_key_schedule is defined as:

     typedef struct des_ks_struct
     	{des_cblock _;}
     des_key_schedule[16];

des_key_sched
-------------

des_key_sched(des_cblock *key, des_key_schedule *schedule);

This routine calculates a key schedule from the input KEY, and outputs the schedule into SCHEDULE.  The key schedule may then be used in subsequent encryption/decryption operations. The user must overwrite or clear all keys and schedules as soon as no longer needed, to discourage their disclosure in memory dumps.

des_cbc_encrypt
---------------

int des_cbc_encrypt(des_cblock *INPUT,des_cblock *OUTPUT, long LENGTH, des_key_schedule SCHEDULE, des_cblock *IVEC, int ENCRYPT)

This routine encrypts or decrypts data using DES CBC mode.  The data pointed to by DATA, of length DATA_LEN, are encrypted with the pre-calculated key schedule SCHEDULE and initialization vector IVEC, and placed in DATA_OUT.  If ENCRYPT_FLAG is zero, then decryption is performed.  If ENCRYPT_FLAG is `1', then encryption is performed.

This routine encrypts or decrypts a block of data using the cipher-block-chaining (CBC) mode of DES.

If the ENCRYPT argument is non-zero, the routine CBC-encrypts the cleartext data pointed to by the INPUT argument.  This is done into the ciphertext pointed to by the OUTPUT argument, using the key schedule provided by the SCHEDULE argument, and initialization vector provided by the IVEC argument. If the LENGTH argument is not an integral multiple of eight bytes, the last block is zero filled (highest addresses).  The output is always an integral multiple of eight bytes.

If ENCRYPT is zero, the routine CBC decrypts the ciphertext data pointed to by the INPUT argument.  The result is put into cleartext pointed to by the OUTPUT argument.  This is done using the key schedule provided by the SCHEDULE argument, and initialization vector provided by the IVEC argument.  Decryption always operates on integral multiples of 8 bytes, so it rounds the length provided up to the appropriate multiple.  Consequently, it always produces the rounded-up number of bytes of output cleartext. The application must determine if the output cleartext was zero-padded due to original cleartext lengths that were not integral multiples of 8.

No errors or meaningful values are returned.  void is not used for compatibility with older compilers.

A characteristic of CBC mode is that changing even a single bit of the cleartext affects all the subsequent ciphertext.  This makes cryptanalysis much more difficult.  However, modifying a single bit of the ciphertext, then decrypting, only affects the resulting cleartext from the modified block and the succeeding block.  The des_pcbc_encrypt routine was designed to detect modifications. However, because of problems, CBC mode in no longer recommended.

des_string_to_key
-----------------

int des_string_to_key (char *string, char *key);

This routine converts an arbitrary length null-terminated STRING to an 8-byte DES key KEY, with odd byte parity.  A one-way function is used to convert the string to a key, making it very difficult to reconstruct the string from the key.  No meaningful value is returned. void is not used for compatibility with older compilers.

Stream functions
================

Kstream Overview
----------------

The kstream suite provides similar functions to the Standard I/O Library (stdio).  It permits you to create encrypted and plaintext (unencrypted) I/O streams.  You can create a kstream, read from it or write to it, and destroy it.  You also have some control of buffering.  At this time, the kstream suite is not available for the Mac.

The encryption system used (if any) is determined at the time of creation.  There are several create routines provided.

kstream_create_rlogin_from_fd
     creates a kstream using the same encryption mechanism that the CNS rlogin program uses on a file descriptor passed as an argument

kstream_create_rcp_from_fd
     is the same as the rlogin version except that rcp pads short blocks in a different way than rlogin.

kstream_create_from_fd
     is a generic creation routine which takes a kstream_crypt_ctl_block which is simply a vector of pointers to functions for encryption, decryption, initialization, and cleanup.

After creating a kstream, you simply call kstream_read or kstream_write just as you would normally call read or write.  kstream_flush explicitly flushes any buffered data out to the underlying file descriptor.  kstream_set_buffer_mode is used to turn buffering on or off; it defaults to on, but interactive applications such as rlogin explicitly turn it off.

     kstream kstream_create_from_fd (int fd,
     				const struct kstream_crypt_ctl_block *ctl,
     				kstream_ptr data);

      kstream_create_rlogin_from_fd (int fd, void* sched,
     				       unsigned char (*ivec)[8]);
     kstream kstream_create_rcp_from_fd (int fd, void* sched,
     				    unsigned char (*ivec)[8]);

     int kstream_write (kstream, void*, size_t);
     int kstream_read (kstream, void*, size_t);
     int kstream_flush (kstream);
     int kstream_destroy (kstream);
     void kstream_set_buffer_mode (kstream, int);

Sample implementation of a stream encryption package
----------------------------------------------------

First, a brief description of the stream protocols in use.

The data stream consists of four bytes representing a net-order (MSB first) integer, followed by enough data to produce that many cleartext bytes.  This means the size of those data must be rounded up to a multiple of 8.  For blocks of less than eight bytes, most software pads on the LEFT with random values.

There are some internal routines whose behavior should be considered carefully.  Start from the top, in the kstream_crypt_ctl_block entries.

init
     simply takes a kstream and kstream_des_init_block (which is just a key and an 8 byte initialization vector) and stuffs them into the private data of the kstream. The buffers and lengths are initialized to zero, and no_right_justify is cleared.

rcp_init
     is the same as init except no_right_justify is set, since rcp and rlogin use subtly different protocols.

encrypt
     gets a pair of kstream_data_blocks (just a pointer and length) for output and input. Since we can always encrypt and send the data we have, this routine just comes up with padding and then calls do_encrypt to put the data into the outgoing stream.  It returns the number of successfully encrypted bytes (in this case, all of them.)

decrypt
     also gets a pair of kstream_data_blocks. Here, we do not necessarily have enough data to decrypt the block.  We need at least four bytes even to read the length (and if we do not get that, we ask for at least 12 total just so we have a chance).  If we are doing an rlogin, we also filter out extra characters that can slip in before the length.

destroy
     frees the output buffer, wipes the private data and then frees that memory also.

do_encrypt
     is not in the vector.  It does the actual encryption work.  This routine handles blocks of any size up to 16 bytes, or any multiple of 8 over that.  It makes the padding a little easier to write it this way. Handling sizes between 8 and 16 is an annoyance, but rlogin actually relies on being able to send 12 bytes in one block.

CNS Unix Applications Programming Interface
*******************************************

On Unix systems, the full set of Common API functions are available. In addition, the following Unix-specific (or server-specific) functions are also available.

These application programming interfaces are only available on Unix.  They are typically used to write servers, or have not yet been ported to other platforms.

Access Control Lists
====================

ACL overview
------------

     cc FILES -lacl -lkrb
     #include "krb.h"
     acl_canonicalize_principal(char *PRINCIPAL, char *buf)
     acl_check(char *ACL, char *PRINCIPAL)
     acl_exact_match(char *ACL, char *PRINCIPAL)
     acl_add(char *ACL, char *PRINCIPAL)
     acl_delete(char *ACL, char *PRINCIPAL)
     acl_initialize(char *ACL_FILE, int MODE)

An access control list (ACL) is a list of principals.  Each principal is represented by a text string which cannot contain whitespace.  The library allows application programs to refer to named access control lists to test membership and to atomically add and delete principals using a natural and intuitive interface.  At present, the names of access control lists are required to be Unix filenames, and refer to human-readable Unix files.

acl_canonicalize_principal
--------------------------

acl_canonicalize_principal stores the canonical form of principal in buf.  buf must contain enough space to store a principal, given the limits on the sizes of NAME, INSTANCE, and REALM specified as ANAME_SZ, INST_SZ, and REALM_SZ, respectively, in /usr/kerberos/include/krb.h.

acl_check
---------

acl_check returns nonzero if PRINCIPAL appears in the ACL. Returns zero if PRINCIPAL does not appear in ACL, or if an error occurs.  Canonicalizes PRINCIPAL before checking, and allows the ACL to contain wildcards.  The only supported wildcards are entries of the form NAME.*@REALM, *.*@REALM, and *.*@*.  An asterisk matches any value in the component field. For example, jtkohl.*@* would match principal jtkohl, with any INSTANCE and any REALM.

acl_exact_match
---------------

acl_exact_match performs like acl_check, but does no canonicalization or wildcard matching.

acl_add
-------

acl_add atomically adds PRINCIPAL to the ACL.  Returns zero if successful, nonzero if unsuccessful.  It is considered a failure if PRINCIPAL is already in the ACL.  This routine canonicalizes PRINCIPAL, but treats wildcards literally.

acl_delete
----------

acl_delete atomically deletes PRINCIPAL from the ACL. Returns zero if successful, nonzero if unsuccessful.  It is considered a failure if PRINCIPAL is not already in the ACL.  This routine canonicalizes PRINCIPAL, but treats wildcards literally.

acl_initialize
--------------

acl_initialize initializes ACL_FILE.  If the file ACL_FILE does not exist, acl_initialize creates it with mode mode.  If the file ACL_FILE exists, acl_initialize removes all members. Returns zero if successful, nonzero unsuccessful. WARNING: MODE argument is likely to change with the eventual introduction of an ACL service.

ACL concurrency note
--------------------

If there is concurrency (two or more people using these functions), there is a very small chance of acl_add or acl_delete erroneously reporting an error.  This is an unavoidable side effect when using lock files for concurrency control rather than flock(2), which is not supported by NFS.  The current implementation caches ACLs in memory in a hash table for increased efficiency in checking membership; one effect of the caching scheme is that one file descriptor is kept open for each ACL cached, up to a maximum of 8.

Error Reporting
===============

com_err
-------

     #include <com_err.h>
     void com_err (const char WHOAMI, long CODE,
     	const char *FORMAT, ...);
     PROC = set_com_err_hook (PROC);
     void (* PROC ) (const char *, long, const char *,
     	va_list);
     PROC = reset_com_err_hook ();
     void initialize_XXXX_error_table ();

com_err displays an error message on the standard error stream stderr (see stdio(3S)) composed of the WHOAMI string, which should specify the program name or some sub-portion of a program, followed by an error message generated from the code value (derived from compile_et), and a string produced using the string and any following arguments, in the same style as fprintf(3). The behavior of com_err can be modified using set_com_err_hook; this defines a procedure which is called with the arguments passed to com_err, instead of the default internal procedure which sends the formatted text to error output.  Thus the error messages from a program can all easily be diverted to another form of diagnostic logging, such as syslog(3). reset_com_err_hook may be used to restore the behavior of com_err to its default form.  Both procedures return the previous hook value.  These hook procedures must have the declaration given for PROC above.  The initialize_XXXX_error_table routine is generated mechanically by compile_et (see compile_et) from a source file containing names and associated strings.  Each table has a name of up to four characters, which is used in place of the XXXX in the name of the routine. These routines should be called before any of the corresponding error codes are used, so that the com_err library recognizes error codes from these tables when they are used.  The com_err.h header file should be included in any source file that uses routines from the com_err library; executable files must be linked using -lcom_err in order to cause the com_err library to be included.

compile_et
----------

compile_et converts a table listing error-code names and associated messages into a C source file suitable for use with the com_err library (see com_err).  The source file name must end with a suffix of .et; the file consists of a declaration supplying the name (up to four characters long) of the error-code table:

     error_table NAME

followed by up to 256 entries of the form:

     error_code NAME, "STRING"

and a final

     end

to indicate the end of the table.  The name of the table is used to construct the name of a subroutine initialize_XXXX_error_table which must be called in order for the com_err library to recognize the error table.  The various error codes defined are assigned sequentially increasing numbers (starting with a large number computed as a hash function of the name of the table); thus for compatibility it is suggested that new codes be added only to the end of an existing table, and that no codes be removed from tables.  The names defined in the table are placed into a C header file with preprocessor directives defining them as integer constants of up to 32 bits in magnitude.  A C source file is also generated which should be compiled and linked with the object files which reference these error codes; it contains the text of the messages and the initialization subroutine.  Both C files have names derived from that of the original source file, with the .et suffix replaced by .c and .h.  A # in the source file is treated as a comment character, and all remaining text to the end of the source line is ignored.

Encryption
==========

Encryption overview
-------------------

This library supports various DES encryption related operations.  It differs from the Unix crypt, setkey, and encrypt library routines in that it provides a true DES encryption, without modifying the algorithm, and executes much faster.  To use, create a des_key_schedule struct, defined in des.h for each key that may be simultaneously active.  Next, create key schedules (from the 8-byte keys) as needed, via des_set_key, prior to using the encryption or checksum routines. Then setup the input and output areas (note that lengths are restricted to be multiples of eight bytes). Finally, invoke the encryption/decryption routines, des_ecb_encrypt or des_cbc_encrypt or des_pcbc_encrypt, or, to generate a cryptographic checksum, use quad_cksum (fast) or des_cbc_cksum (slow).

     #include "des.h"
     int des_read_password(des_cblock *KEY, char *PROMPT, int
             VERIFY)
     int des_string_to_key(char *STR, des_cblock KEY)
     int des_random_key(des_cblock *KEY)
     int des_set_key(des_cblock *KEY, des_key_schedule SCHEDULE)
     int des_ecb_encrypt(des_cblock *INPUT,des_cblock *OUTPUT,
             des_key_schedule SCHEDULE,int ENCRYPT)
     int des_pcbc_encrypt(des_cblock *INPUT,des_cblock *OUTPUT, long
             LENGTH, des_key_schedule SCHEDULE,
     	des_cblock *IVEC, int ENCRYPT)
     unsigned long quad_cksum(des_cblock *INPUT,des_cblock *OUTPUT,
     	long LENGTH, int OUT_COUNT,
     	des_cblock *SEED)

des_read_password
-----------------

des_read_password writes the string specified by PROMPT to the standard output, turns off echo (if possible) and reads an input string from standard input until terminated with a newline.  If VERIFY is non-zero, it prompts and reads input again, for use in applications such as changing a password; both versions are compared, and the input is requested repeatedly until they match.  Then des_read_password converts the input string into a valid DES key, internally using the des_string_to_key routine.  The newly created key is copied to the area pointed to by the KEY argument. des_read_password returns a zero if no errors occurred, or a `-1' indicating that an error occurred trying to manipulate the terminal echo.

des_random_key
--------------

des_random_key generates a random DES encryption key (eight bytes), set to odd parity per FIPS specifications.  This routine uses the current time, process ID, and a counter as a seed for the random number generator.  The caller must supply space for the output key, pointed to by argument KEY, then after calling des_random_key should call the des_set_key routine when needed.  No meaningful value is returned.  void is not used for historical reasons.

This function is deprecated. des_init_random_number_generator should be used to set a key for the des_new_random_key generator, which is much stronger due to the use of DES and the use of a secret key. (Programs that operate directly on the database can use the master key; for client programs like ksrvutil it may be sufficient to use a current session key.)

des_set_key
-----------

des_set_key calculates a key schedule from all eight bytes of the input key, pointed to by the KEY argument, and outputs the schedule into the des_key_schedule indicated by the SCHEDULE argument. You must pass a valid eight byte key; no padding is done.  The key schedule may then be used in subsequent encryption/decryption/checksum operations.  Many key schedules may be cached for later use.  The user must clear keys and schedules as soon as no longer needed, to prevent their disclosure.  The routine also checks the key parity, and returns a zero if the key parity is correct (odd), a `-1' indicating a key parity error, or a `-2' indicating use of a weak key. If an error is returned, the key schedule was not created.

des_ecb_encrypt
---------------

des_ecb_encrypt is the basic DES encryption routine that encrypts or decrypts a single 8-byte block in electronic code book mode.  It always transforms the input data, pointed to by INPUT, into the output data, pointed to by the OUTPUT argument.  If the ENCRYPT argument is non-zero, the input (cleartext) is encrypted into the output (ciphertext) using the key_schedule specified by the SCHEDULE argument, previously set via des_set_key.  If ENCRYPT is zero, the input (now ciphertext) is decrypted into the output (now cleartext).  Input and output may overlap.  No meaningful value is returned.  void is not used for historical reasons.

des_pcbc_encrypt
----------------

des_pcbc_encrypt encrypts/decrypts using a modified block chaining mode.  Its calling sequence is identical to des_cbc_encrypt. It differs in its error propagation characteristics.  des_pcbc_encrypt is not recommended for most encryption purposes.  Modification of a single bit of the ciphertext affects all the subsequent (decrypted) cleartext.  Similarly, modifying a single bit of the cleartext affects all the subsequent (encrypted) ciphertext.  `PCBC' mode, on encryption, `XORs' both the cleartext of block N and the ciphertext resulting from block N with the cleartext for block N+1 prior to encrypting block N+1. However, this mode has been shown to have inherent weaknesses.

des_cbc_cksum
-------------

des_cbc_cksum produces an 8-byte cryptographic checksum by cipher-block-chain encrypting the cleartext data pointed to by the INPUT argument. All of the ciphertext output is discarded, except the last 8-byte ciphertext block, which is written into the area pointed to by the OUTPUT argument.  It uses the key schedule, provided by the SCHEDULE argument and initialization vector provided by the IVEC argument.  If the LENGTH argument is not an integral multiple of eight bytes, the last cleartext block is copied to a temp and zero filled at the highest addresses.  The output is ALWAYS eight bytes.  The routine also returns an unsigned long, which is the last (highest address) half of the 8 byte checksum computed.  This result is probably byte-order dependent.

quad_cksum
----------

quad_cksum produces a checksum by chaining quadratic operations on the cleartext data pointed to by the INPUT argument. The LENGTH argument specifies the length of the input---only exactly that many bytes are included for the checksum, without any padding.  The algorithm may be iterated over the same input data, if the OUT_COUNT argument is `2', `3' or `4', and the optional OUTPUT argument is a non-null pointer.  The default is one iteration, and it does not run more than four times.  Multiple iterations run more slowly, but provide a longer checksum, if desired. The SEED argument provides an 8-byte seed for the first iteration. If multiple iterations are requested, the results of one iteration are automatically used as the seed for the next iteration.  It returns both an unsigned long checksum value, and if the OUTPUT argument is not a null pointer, up to 16 bytes of the computed checksum are written into the output.

des_init_random_number_generator
--------------------------------

des_init_random_number_generator sets the key for the new random number generator. It also sets the initial sequence number from a microsecond clock, the host id, and process id if available.

des_new_random_key
------------------

des_new_random_key encrypts the sequence number with the previously selected key and advances the sequence number. This produces a key with strong unpredictablity (due to the use of DES and a secret key.) This function will only generate valid non-weak keys.

Authentication
==============

Authentication overview
-----------------------

     #include "krb.h"
     int krb_kntoln(AUTH_DAT *AD, char *LNAME);
     int krb_set_key(char *KEY, int CVT);
     int krb_get_cred(char *SERVICE, char *INSTANCE, char
     *REALM, CREDENTIALS *C);
     long krb_mk_err(u_char *OUT, long CODE, char *STRING);
     long krb_rd_err(u_char *IN, u_long LENGTH,
     		long CODE, MSG_DAT *MSG_DATA);

The following functions, which are built on top of the core Kerberos library, provide a convenient means for client and server programs to send authentication messages to one another through network connections.

     #define DEFINE_SOCKADDR
     #include "krb.h"
     int krb_sendauth(long OPTIONS, int FD, KTEXT KTEXT, char
     *SERVICE, char *INST, char *REALM, u_long CHECKSUM,
     MSG_DAT *msg_DATA,
     	CREDENTIALS *CRED,
     	Key_schedule SCHEDULE,
     	struct sockaddr_in *LADDR,
     	struct sockaddr_in *FADDR,
     	char *VERSION);
     int krb_recvauth(long OPTIONS, int FD, KTEXT KTEXT, char
     *SERVICE, char *INST,
     	struct sockaddr_in *LADDR,
     	struct sockaddr_in *FADDR,
     	AUTH_DAT *AUTH_DATA,
     	char *FILENAME,
     	Key_schedule SCHEDULE,
     	char *VERSION);
     int krb_net_write(int FD, char *buf, int FORMAT);
     int krb_net_read(int FD, char *buf, int FORMAT);

krb_kntoln
----------

krb_kntoln converts a Kerberos name (supplied in an AUTH_DAT structure) to a local Unix username.  If the instance is the null string and the realm is the local realm, then the name is copied to the LNAME argument.  If the realm is not the local realm or the instance is non-null, or some error occurs, KFAILURE is returned, otherwise KSUCCESS is returned.  The local name returned might be used by an application to change user IDs, directories, or other parameters.  This function is not an integral part of Kerberos, but is instead provided to support the use of Kerberos in existing utilities.

krb_set_key
-----------

krb_set_key takes as an argument a DES key.  It then creates a key schedule from it and saves the original key to be used as an initialization vector.  It is used to set the server's key which must be used to decrypt tickets.  If called with a non-zero second argument, krb_set_key first converts the input from a string of arbitrary length to a DES key by encrypting it with a one-way function.  In most cases it should not be necessary to call krb_set_key. The necessary keys are usually obtained and set inside krb_rd_req. krb_set_key is provided for those applications that do not wish to place the application keys on disk.

krb_mk_err
----------

krb_mk_err constructs an application level error message that may be used along with krb_mk_priv or krb_mk_safe. OUT is a pointer to the output buffer, CODE is an application specific error code, and STRING is an application specific error string.

krb_rd_err
----------

krb_rd_err unpacks a received krb_mk_err message. IN points to the beginning of the received message, whose length is specified in IN_LENGTH.  CODE is a pointer to a value to be filled in with the error value provided by the application. MSG_DATA is a pointer to a MSG_DAT struct, defined in krb.h. The routine fills in these MSG_DAT fields: the app_data field with a pointer to the application error text, app_length with the length of the app_data field, and swap with a `1' if the byte order of the receiver is different than that of the sender.  (The application must still determine if it is appropriate to byte-swap application data; the Kerberos protocol fields are already taken care of).  The routine returns zero if the error message has been successfully received, or a Kerberos error code.

krb_sendauth
------------

The krb_sendauth function sends an authenticated ticket from the client program to the server program by writing the ticket to a network socket.  The krb_recvauth function receives the ticket from the client by reading from a network socket.

krb_sendauth writes the ticket to the network socket specified by the file descriptor FD, returning KSUCCESS if the write proceeds successfully, and an error code if it does not.  The KTEXT argument should point to an allocated KTEXT_ST structure.  The SERVICE, INST, and REALM arguments specify the server program's Kerberos principal name, instance, and realm.  If you are writing a client that uses the local realm exclusively, you can set the REALM argument to NULL.  The VERSION argument allows the client program to pass an application-specific version string that the server program can then match against its own version string.  The version string can be up to KSEND_VNO_LEN (see krb.h) characters in length.  The CHECKSUM argument can be used to pass checksum information to the server program. The client program is responsible for specifying this information. This checksum information is difficult to corrupt because krb_sendauth passes it over the network in encrypted form.  The checksum argument is passed as the checksum argument to krb_mk_req.  You can set krb_sendauth's other arguments to NULL unless you want the client and server programs to mutually authenticate themselves. In the case of mutual authentication, the client authenticates itself to the server program, and demands that the server in turn authenticate itself to the client.

If you want mutual authentication, make sure that you read all pending data from the local socket before calling krb_sendauth.  Set krb_sendauth's options argument to KOPT_DO_MUTUAL (this macro is defined in the krb.h file); make sure that the LADDR argument points to the address of the local socket, and that FADDR points to the foreign socket's network address. krb_sendauth fills in the other arguments---MSG_DATA, CRED, and SCHEDULE---before sending the ticket to the server program. You must, however, allocate space for these arguments before calling the function.  krb_sendauth supports two other options: KOPT_DONT_MK_REQ, and KOPT_DONT_CANON.  If called with options set as KOPT_DONT_MK_REQ, krb_sendauth does not use the krb_mk_req function to retrieve the ticket from the Kerberos server.  The KTEXT argument must point to an existing ticket and authenticator (such as would be created by krb_mk_req), and the SERVICE, INST, and REALM arguments can be set to NULL.

krb_sendauth does not convert the service's instance to canonical form using krb_get_phost, if called with options set as KOPT_DONT_CANON.  If you want to call krb_sendauth with a multiple options specification, construct options as a bitwise-OR of the options you want to specify.

Note that krb_sendauth, krb_recvauth, krb_net_write, and krb_net_read do not work properly on sockets set to non-blocking I/O mode.

krb_recvauth
------------

The krb_recvauth function reads a ticket/authenticator pair from the socket pointed to by the FD argument.  Set the OPTIONS argument as a bitwise-OR of the options desired.  Currently only KOPT_DO_MUTUAL is useful to the receiver.

The ktext argument should point to an allocated KTEXT_ST structure.  krb_recvauth fills ktext with the ticket/authenticator pair read from FD, then passes it to krb_rd_req.  The SERVICE and INST arguments specify the expected service and instance for which the ticket was generated. They are also passed to krb_rd_req. The INST argument may be set to * if the caller wishes krb_mk_req to fill in the instance used (note that there must be space in the INST argument to hold a full instance name, see krb_mk_req.)  The FADDR argument should point to the address of the peer which is presenting the ticket.  It is also passed to krb_rd_req.  If the client and server plan to mutually authenticate one another, the LADDR argument should point to the local address of the file descriptor.  Otherwise you can set this argument to NULL.

The AUTH_DATA argument should point to an allocated AUTH_DAT area. It is passed to and filled in by krb_rd_req.  The checksum passed to the corresponding krb_sendauth is available as part of the filled-in AUTH_DAT area.  The FILENAME argument specifies the filename which the service program should use to obtain its service key. krb_recvauth passes filename to the krb_rd_req function. If you set this argument to null, krb_rd_req looks for the service key in the file /etc/krb-srvtab.  If the client and server are performing mutual authentication, the schedule argument should point to an allocated Key_schedule.  Otherwise it is ignored and may be NULL.  The VERSION argument should point to a character array of at least KSEND_VNO_LEN characters. It is filled in with the version string passed by the client to krb_sendauth.

Note that krb_sendauth, krb_recvauth, krb_net_write, and krb_net_read do not work properly on sockets set to non-blocking I/O mode.

krb_net_write and krb_net_read
------------------------------

The krb_net_write function emulates the write(2) system call, but guarantees that all data specified is written to FD before returning, unless an error condition occurs.  The krb_net_read function emulates the read(2) system call, but guarantees that the requested amount of data is read from FD before returning, unless an error condition occurs.

Note that krb_sendauth, krb_recvauth, krb_net_write, and krb_net_read do not work properly on sockets set to non-blocking I/O mode.

Realms
======

krb_get_phost
-------------

char *krb_get_phost(char *ALIAS)

krb_get_phost converts the hostname ALIAS (which can be either an official name or an alias) into the instance name to be used in obtaining Kerberos tickets for most services, including the Berkeley rcmd suite (rlogin, rcp, rsh).  The current convention is to return the first segment of the official domain-style name after conversion to lower case.

Ticket Files
============

These routines are the original interface to the credentials cache. This interface worked poorly on non-Unix platforms, so it has been superseded by the routines described in the Common API section.

This group of routines is provided to manipulate a Kerberos ticket file.  A ticket file has the following layout:

  * principal's name (a null-terminated string)

  * principal's instance (a null-terminated string)

  * CREDENTIAL_1

  * CREDENTIAL_2

  * ...

  * CREDENTIAL_N

  * EOF

CREDENTIAL_X consists of the following fixed-length fields from the CREDENTIALS structure (defined in "krb.h"):

     char service[ANAME_SZ]
     char instance[INST_SZ]
     char realm[REALM_SZ]
     des_cblock session
     int lifetime
     int kvno
     KTEXT_ST ticket_st
     long issue_date

tf_init
-------

tf_init must be called before the other ticket file routines.  It takes the name of the ticket file to use, and a read/write flag as an argument.  It tries to open the ticket file, checks the mode and if everything is okay, locks the file. If it is opened for reading, the lock is shared.  If it is opened for writing, the lock is exclusive. KSUCCESS is returned if all goes well, otherwise one of the following messages is returned:

NO_TKT_FIL
     - file was not there

TKT_FIL_ACC
     - file was in wrong mode, etc.

TKT_FIL_LCK
     - could not lock the file, even after a retry

tf_get_pname
------------

The tf_get_pname function reads the principal's name from a ticket file. It should only be called after tf_init has been called. The principal's name is filled into the PNAME parameter.  If all goes well, KSUCCESS is returned.  If tf_init is not called, TKT_FIL_INI is returned.  If the principal's name is null, or EOF is encountered, or the name is longer than ANAME_SZ, TKT_FIL_FMT is returned.

tf_get_pinst
------------

The tf_get_pinst reads the principal's instance from a ticket file. It should only be called after tf_init and tf_get_pname are called.  The principal's instance is filled into the PINST parameter.  If all goes well, KSUCCESS is returned. If tf_init is not called, TKT_FIL_INI is returned.  If EOF is encountered, or the name is longer than INST_SZ, TKT_FIL_FMT is returned.  Note that, unlike the principal name, the instance name may be null.

tf_get_cred
-----------

The tf_get_cred routine reads a CREDENTIALS record from a ticket file and fills in the given structure.  It should only be called after tf_init, tf_get_pname, and tf_get_pinst are called.  If all goes well, KSUCCESS is returned.  Possible error codes are:

TKT_FIL_INI
     - tf_init was not called first

TKT_FIL_FMT
     - bad format

EOF
     - end of file encountered

tf_close
--------

tf_close closes the ticket file and releases the lock on it.

Other
=====

krb_set_tkt_string
------------------

     #include "krb.h"
     void krb_set_tkt_string(char *FILENAME);

krb_set_tkt_string sets the name of the file that holds the user's cache of Kerberos server tickets and associated session keys. The string FILENAME passed in is copied into local storage.  Only MAXPATHLEN-1 characters of the filename are copied in for use as the cache file name.  This routine should be called during initialization, before other Kerberos routines are called; otherwise the routines which fetch the ticket cache file name may be called and return an undesired ticket file name until this routine is called.  The default ticket file name (unless the environment variable KRBTKFILE is set) is /tmp/tktUID), where UID denotes the user's ID, in decimal.

kuserok
-------

     #include "krb.h"
     kuserok(AUTH_DAT *AUTH_DATA, char *LOCALUSER);

kuserok determines whether a Kerberos principal described by the structure AUTH_DATA is authorized to login as user LOCALUSER according to the authorization file (~localuser/.klogin by default).  It returns zero if authorized, `1' if not authorized.  If there is no account for LOCALUSER on the local machine, authorization is not granted.  If there is no authorization file, and the Kerberos principal described by AUTH_DATA translates to LOCALUSER (using see krb_kntoln), authorization is granted. If the authorization file can not be accessed, or the file is not owned by LOCALUSER, authorization is denied.  Otherwise, the file is searched for a matching principal name, and realm.  If a match is found, authorization is granted, else authorization is denied.  The file entries are in the format:

     NAME.INSTANCE@REALM

with one entry per line.

CNS Macintosh Library API
*************************

This chapter documents Macintosh-specific aspects of the Cygnus Network Support Kerberos programming interface.

On the Macintosh, the standard Kerberos API is available, as documented in the common API section.  These standard routines are implemented as glue code which in turn calls a driver.  In the driver is more glue code which then calls the real routines.

We STRONGLY recommend that you write your programs to use the ordinary Kerberos subroutine call API.  The low-level Macintosh interface is not guaranteed to remain stable.  It's a lot easier to program with simple subroutine calls instead of I/O traps too.

Application programs which have unusual requirements can call the driver directly, though this is discouraged.  To call the driver directly, examine the file mac_stubs.c in the source code distribution of Cygnus Network Security, in the src/lib/krb directory.

The low-level Kerberos interface is designed to be compatible with the kclient program from Cornell, and borrows some code from the kclient and kconfig programs.  Programs written to work with the kclient Mac Kerberos driver will probably work with Cygnus Network Security's driver as well.  One feature of the kclient program that is not implemented by CNS is multiple named credential caches. Supporting this feature would have required changing the basic API for several Kerberos functions.

None of the CNS driver operations work asynchronously; the driver must be called synchronously.

Compiling and Linking your Macintosh Program
============================================

The Macintosh Kerberos driver is installed into the Extensions folder in the System Folder on the disk drive from which you boot. It installs itself into the system at boot time, putting a small icon along the bottom of the screen for a short time.  By the time the system comes up, the driver is ready for use.

The preferred way to use the driver is to #include "krb.h" in all of your source modules that call Kerberos routines.  Make sure that your program calls krb_start_session before calling any other Kerberos routines.  Compile and link your code with the mac_stubs.c file, which provides the short `stub' routines which translate the Common Kerberos Library API into the arcane calling conventions of Macintosh drivers.

If krb_start_session does not return KSUCCESS, it is unable to locate or initialize a Kerberos driver in your Macintosh. Check your Extensions folder to make sure that the driver is being installed on each reboot.  You must reboot after putting the driver in the Extensions folder as well.

MS-Windows Application Programmer Interface
*******************************************

This chapter documents Microsoft Windows-specific aspects of the Cygnus Network Support Kerberos programming interface.

On MS-Windows, the standard Kerberos API is available, as documented in the common API section.  These standard routines are implemented in a Dynamic Link Library called KERBEROS.DLL.

Due to the standard DLL calling conventions, all pointers passed to or returned from the MS-Windows Kerberos implementation are FAR pointers.  The interface file kerberos.h, which is included by the usual krb.h include file, provides function prototypes that cause any pointers arguments to be converted to FAR pointers.  You must ensure that any result values which are pointers are handled properly as FAR pointers.

Values which are specified as int are 16 bit numbers using MS-Windows compilers.

Compiling and Linking your MS-Windows Program
=============================================

The KERBEROS.DLL file can be installed anywhere on the search path.

The preferred way to use the driver is to #include "krb.h" in all of your source modules that call Kerberos routines.  Make sure that your program calls krb_start_session before calling any other Kerberos routines.  Link your code with the KERBEROS.LIB file, which causes calls to KERBEROS.DLL to occur when running the program.

Password changing calls
=======================

Due to the need to formally externalize calls from a DLL, a number of routines which are only used in kpasswd on UNIX are visible in the MS-Windows interface.  The routines are used by the CNS user interface program on Windows.  On Unix, these routines reside within the kadm library; they are not usually called by users.

     int kadm_change_pw (des_cblock key);

     int kadm_change_pw2 (des_cblock key, char *password,
     unsigned char **ret_st);

     int kadm_init_link (char *pwserv_name, char *krb_master,
     char *realm);

Ticket cache notification
=========================

This MS-Windows-specific API call gives an interactive application notification when the contents of the ticket cache change.  The call returns the number of the unique message which are sent to all top level windows after the ticket cache changes.  The CNS program uses this message to keep its display current.  The prototype is as follows:

     int krb_get_notification_message(void)

Timekeeping
===========

The Kerberos protocol uses timestamps based on an epoch in which time begins at 00:00 January 1, 1970.  All times expected and returned by the Kerberos API are in these units, independent of what the C library returns.  Note that Microsoft C 7.0 starts time at January 1, 1900, though they backed that change out in version 7.0.1.  Our code can run in either environment.

Kerberos reads time from the hardware clock using BIOS interrupt 0x1A.  This avoids problems with the software clock drifting as the system runs.

The local time zone is set by the TZ environment variable.