*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 (C) 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 (C) 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 *Note krb_get_lrealm: krb_realmofhost. 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 `#ifdef's, 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 *Note krb_get_lrealm: krb_realmofhost, 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 `'). 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'. XSUM 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_block's (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_block's. 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 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 *Note 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 *Note 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 *Note 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. 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. 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 *Note krb_get_phost: krb_realmofhost, 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 *Note 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 *note 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. Function Index ************** * Menu: * acl_add: acl_add. * acl_canonicalize_principal: acl_canonicalize_principal. * acl_check: acl_check. * acl_delete: acl_delete. * acl_exact_match: acl_exact_match. * acl_initialize: acl_initialize. * com_err: com_err. * dest_tkt: dest_tkt. * des_cbc_cksum: des_cbc_cksum. * des_cbc_encrypt: des_cbc_encrypt. * des_ecb_encrypt: des_ecb_encrypt. * des_key_sched: des_key_sched. * des_pcbc_encrypt: des_pcbc_encrypt. * des_random_key: des_random_key. * des_read_password: des_read_password. * des_set_key: des_set_key. * des_string_to_key: des_string_to_key. * kname_parse: kname_parse. * krb_end_session: krb_end_session. * krb_get_admhst: krb_get_admhst. * krb_get_cred: krb_get_cred. * krb_get_default_user: krb_get_default_user. * krb_get_err_text: krb_get_err_text. * krb_get_krbhst: krb_get_krbhst. * krb_get_lrealm: krb_get_lrealm. * krb_get_nth_cred: krb_get_nth_cred. * krb_get_num_cred: krb_get_num_cred. * krb_get_phost: Realms. * krb_get_tf_fullname: krb_get_tf_fullname. * krb_kntoln: krb_kntoln. * krb_mk_auth: krb_mk_auth. * krb_mk_err: krb_mk_err. * krb_mk_priv: krb_mk_priv. * krb_mk_req: krb_mk_req. * krb_mk_safe: krb_mk_safe. * krb_net_read: krb_net_write and krb_net_read. * krb_net_write: krb_net_write and krb_net_read. * krb_rd_err: krb_rd_err. * krb_rd_priv: krb_rd_priv. * krb_rd_req: krb_rd_req. * krb_rd_safe: krb_rd_safe. * krb_realmofhost: krb_realmofhost. * krb_recvauth: krb_recvauth. * krb_save_credentials: krb_save_credentials. * krb_sendauth: krb_sendauth. * krb_set_default_user: krb_set_default_user. * krb_set_key: krb_set_key. * krb_set_tkt_string: krb_set_tkt_string. * krb_start_session: krb_start_session. * kstream_create_from_fd: Kstream Overview. * kstream_create_rcp_from_fd: Kstream Overview. * kstream_create_rlogin_from_fd: Kstream Overview. * kuserok: kuserok. * quad_cksum: quad_cksum. * tf_close: tf_close. * tf_get_cred: tf_get_cred. * tf_get_pinst: tf_get_pinst. * tf_get_pname: tf_get_pname. * tf_init: tf_init.