\documentstyle[12pt,fullpage,changebar,rcsid]{article}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Make _ actually generate an _, and allow line-breaking after it.
\let\underscore=\_
\catcode`_=13
\def_{\underscore\penalty75\relax}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\rcs$Id$

\setlength{\parskip}{.7\baselineskip}
\setlength{\parindent}{0pt}

\def\secure{OV*Secure}
\def\v#1{\verb+#1+}

\title{OV*Secure Admin \\ Functional Specifications\thanks{\rcsId} \\
\it{Openvision Confidential}}
\author{Barry Jaspan}

\pagestyle{myheadings}
\markboth{OPENVISION CONFIDENTIAL}{OPENVISION CONFIDENTIAL}

\begin{document}

\sloppy
\maketitle

{\setlength{\parskip}{0pt}\tableofcontents}

\section{Policies and Password Quality}

The Admin API Password Quality mechanism provides the following
controls.  Note that two strings are defined to be ``significantly
different'' if they differ by at least one character. The compare is not
case sensitive.

\begin{itemize}
\item A minimum length can be required; a password with
fewer than the specified number of characters will not be accepted.

\item A minimum number of character classes can be required; a
password that does not contain at least one character from at least
the specified number of character classes will not be accepted.  The
character classes are defined by islower(), isupper(), isdigit(),
ispunct(), and other.

\item Passwords can be required to be different from
previous passwords; a password that generates the same encryption key
as any of the principal's specified previous number of passwords will
not be accepted.  This comparison is performed on the encryption keys
generated from the passwords, not on the passwords themselves.

\item A single ``forbidden password'' dictionary can be specified for all
users; a password that is not significantly different from every word
in the dictionary will not be accepted.
\end{itemize}

\section{Multi-realm Operation}

The behavior of any function when called with a principal name that is
not in the host's local realm is currently undefined.

\section{Admin API requirements}

\subsection{Versioning}

The API will include a versioning system aimed at meeting the
following requirements:
\begin{description}
\item[R1] Admin API client applications will be source-code
	compatible, whenever possible, with newer versions of the
	Admin API. {\bf [high]}
\item[R2] Admin API client applications will be object-code and
	shared-library compatible, whenever possible, with newer
	versions of the Admin API. {\bf [low]}
\item[R3] Admin API client applications will be protocol compatible,
	whenever possible, with newer versions of the Admin server.
	I.e., a statically linked Admin API client application will be
	able to talk to an Admin server from a later version of
	Secure. {\bf [medium]}
\item[R4] Admin API client applications will be protocol compatible,
	whenever possible, with older versions of the Admin server.
	{\bf [lower than low]}
\item[R5] Changes to the Admin API structures or protocol will,
	whenever possible, require only localized changes to the Admin
	server source code and Admin API library implementation. {\bf
	[medium]}
\end{description}
The present implementation meets requirements R1, R2, and R3, and
partially meets requirement R5.  Requirement R4 is not addressed.

\section{Admin API functional specification}

This section describes the Admin API that can be used to maintain
principals and policies.  It describes the data structures used for
each function and the interpretation of each data type field, the
semantics of each API function, and the possible return codes.

The Admin API is intended to be used by remote clients using an RPC
interface.  It is implemented by the admin server running on the
Kerberos master server.  It may also be possible for a program running
on the Kerberos master server to use the Admin API directly, without
going through the admin server.

\subsection{Data Structures}

This section describes the data structures used by the Admin API that
are unique to \secure{}.  They are defined in $<$ovsec_admin/admin.h$>$.

\subsubsection{Principals, ovsec_kadm_principal_ent_t}
\label{sec:principal-structure}

A Kerberos principal entry is represented by a
ovsec_kadm_principal_ent_t.  It contains a subset of the information
stored in the master Kerberos database as well as the additional
information maintained by \secure{}.  In the current version, the only
additional information is the principal's policy and the
aux_attributes flags.

The principal may or may not have a policy enforced on it.  If the
POLICY bit (see section \ref{sec:masks}) is set in aux_attributes, the
policy field names the principal's policy.  If the POLICY bit is not
set in aux_attributes, no policy is enforced on the principal and the
value of the policy field is undefined.

\begin{figure}[htbp]
\begin{verbatim}
typedef struct _ovsec_kadm_principal_ent_t {
        krb5_principal principal;

        krb5_timestamp princ_expire_time;
        krb5_timestamp last_pwd_change;
        krb5_timestamp pw_expiration;
        krb5_deltat max_life;
        krb5_principal mod_name;
        krb5_timestamp mod_date;
        krb5_flags attributes;
        krb5_kvno kvno;
        krb5_kvno mkvno;

        char * policy;
        u_int32 aux_attributes;
} ovsec_kadm_principal_ent_rec, *ovsec_kadm_principal_ent_t;
\end{verbatim}
\caption{Definition of ovsec_kadm_principal_ent_t.}
\label{fig:princ-t}
\end{figure}

The fields of an ovsec_kadm_principal_ent_t are interpreted as
follows.

\begin{description}
\item[principal] The name of the principal; must conform to Kerberos
naming specifications.

\item[princ_expire_time] The expire time of the principal as a Kerberos
timestamp.  No Kerberos tickets will be issued for a principal after
its expire time.

\item[last_pwd_change] The time this principal's password was last
changed, as a Kerberos timestamp.

\item[pw_expiration] The expire time of the user's current password, as a
Kerberos timestamp.  No application service tickets will be issued for the
principal once the password expire time has passed.  Note that the user can
only obtain tickets for services that have the PW_CHANGE_SERVICE bit set in
the attributes field.

\item[max_life] The maximum lifetime of any Kerberos ticket issued to
this principal.

\item[attributes] A bitfield of attributes for use by the KDC.  
Note that only some are explicitly supported by \secure{}.

\begin{tabular}{clr}
{\bf Supported} & {\bf Name} & {\bf Value} \\
  & KRB5_KDB_DISALLOW_POSTDATED     & 0x00000001 \\
  & KRB5_KDB_DISALLOW_FORWARDABLE   & 0x00000002 \\
X & KRB5_KDB_DISALLOW_TGT_BASED     & 0x00000004 \\
  & KRB5_KDB_DISALLOW_RENEWABLE     & 0x00000008 \\
  & KRB5_KDB_DISALLOW_PROXIABLE     & 0x00000010 \\
  & KRB5_KDB_DISALLOW_DUP_SKEY      & 0x00000020 \\
X & KRB5_KDB_DISALLOW_ALL_TIX       & 0x00000040 \\
  & KRB5_KDB_REQUIRES_PRE_AUTH      & 0x00000080 \\
  & KRB5_KDB_REQUIRES_HW_AUTH       & 0x00000100 \\
X & KRB5_KDB_REQUIRES_PWCHANGE      & 0x00000200 \\
  & KRB5_KDB_DISALLOW_SVR           & 0x00001000 \\
X & KRB5_KDB_PWCHANGE_SERVICE       & 0x00002000
\end{tabular}

The interpretation of each bit is as follows.  For each of the bits
that disables a corresponding KDC_OPT option, the option is disabled
on an AS_REQ if the bit is set on either the client or the server, and
the option is disabled on TGS_REQ if the bit is set on the server (the
setting of the bit on the client is irrelevant for a TGS_REQ).

\begin{description}
\item[KRB5_KDB_DISALLOW_POSTDATED]  Disables the ALLOW_POSTDATED
and POSTDATED KDC options on AS_REQ and TGS_REQ.

\item[KRB5_KDB_DISALLOW_FORWARDABLE] Disables the FORWARDABLE KDC
option for AS_REQ and TGS_REQ.

\item[KRB5_KDB_DISALLOW_TGT_BASED] All TGS_REQ requests will fail for
a principal with this bit set.

\item[KRB5_KDB_DISALLOW_RENEWABLE] Disables the RENEWABLE KDC option for
AS_REQ and TGS_REQ.

\item[KRB5_KDB_DISALLOW_PROXIABLE] Disables the PROXIABLE KDC option on
AS_REQ and TGS_REQ.

\item[KRB5_KDB_DISALLOW_DUP_SKEY] Disables the ENC_TKT_IN_SKEY option on
TGS_REQ.

\item[KRB5_KDB_DISALLOW_ALL_TIX] All AS_REQ requests fail if this bit
is set for the client or the server, and all TGS_REQ requests fail if
this bit is set for the server.  Note that this bit can be set
automatically if the symbol KRBCONF_KDC_MODIFIES_KDC is defined and a
specified number of pre-authentication attempts fail.

\item[KRB5_KDB_REQUIRES_PRE_AUTH] Any AS_REQ will fail if this bit is
set and the padata field of the request is empty.  Any TGS_REQ will
fail if this bit is set and the TKT_FLAG_PRE_AUTH bit is not set in
the tgt.  Thus, it is possible to have the bit not set on the TGT but
to have a specific service require pre-authentication.

\item[KRB5_KDB_REQUIRES_HW_AUTH] Unclear.

\item[KRB5_KDB_REQUIRES_PWCHANGE] An AS_REQ will fail if this bit is
set on the client and the KRB5_KDC_PWCHANGE_SERVICE bit is not set on
the server.

\item[KRB5_KDB_DISALLOW_SVR] All AS_REQ and TGS_REQ request will fail
if the server has this bit set.

\item[KRB5_KDB_PWCHANGE_SERVICE] An request from a client whose
password has expired will succeed if this bit is set on the server.
Also see KRB5_KDC_REQUIRES_PWCHANGE.
\end{description}

\item[mod_name] The name of the Kerberos principal that most recently
modified this principal.

\item[mod_date] The time this principal was last modified, as a Kerberos
timestamp.

\item[kvno] The version of the principal's current key.

\item[mkvno] The version of the Kerberos Master Key in effect when
this principal's key was last changed.

\item[policy] If the POLICY bit is set in aux_attributes, the name
of the policy controlling this principal.

\item[aux_attributes]  A bitfield of flags for use by the
administration system.  Currently, the only valid flag is POLICY, and
it indicates whether or not the principal has a policy enforced on it.
\end{description}

\subsubsection{Policies, ovsec_kadm_policy_ent_t}
\label{sec:policy-fields}

If the POLICY bit is set in aux_attributes, the \v{policy} name field
in the ovsec_kadm_principal_ent_t structure refers to a password
policy entry defined in a \v{ovsec_kadm_policy_ent_t}.

\begin{verbatim}
typedef struct _ovsec_kadm_policy_ent_t {
        char *policy;

        u_int32 pw_min_life;
        u_int32 pw_max_life;
        u_int32 pw_min_length;
        u_int32 pw_min_classes;
        u_int32 pw_history_num;
        u_int32 policy_refcnt;
} ovsec_kadm_policy_ent_rec, *ovsec_kadm_policy_ent_t;
\end{verbatim}

The fields of an ovsec_kadm_policy_ent_t are interpreted as follows.
Note that a policy's values only apply to a principal using that
policy.

\begin{description}
\item[policy] The name of this policy, as a NULL-terminated string.
The ASCII characters between 32 (space) and 126 (tilde), inclusive,
are legal.

\item[pw_min_life] The minimum password lifetime, in seconds.
A principal cannot change its password before pw_min_life seconds have
passed since last_pwd_change.

\item[pw_max_life] The default duration, in seconds, used to compute
pw_expiration when a principal's password is changed.

\item[pw_min_length] The minimum password length, in characters.  A
principal cannot set its password to anything with fewer than this
number of characters.  This value must be greater than zero.

\item[pw_min_classes] The minimum number of character classes in the
password.  This value can only be 1, 2, 3, 4, or 5.  A principal cannot
set its password to anything with fewer than this number of character
classes in it.

\item[pw_history_num] The number of past passwords that are
stored for the principal; the minimum value is 1 and the maximum value
is 10.  A principal cannot set its password to any of its previous
pw_history_num passwords.  The first ``previous'' password is the
current password; thus, a principal with a policy can never reset its
password to its current value.

\item[policy_refcnt]  The number of principals currently using this policy.
A policy cannot be deleted unless this number is zero.
\end{description}

\subsubsection{Create/Modify Masks}
\label{sec:masks}

The API functions for creating and modifying principals and policies
allow for a relevant subset of the fields of the
ovsec_kadm_principal_ent_t and ovsec_kadm_policy_ent_t to be specified
or changed.  The chosen fields are determined by a bitmask that is
passed to the relevant function.  Each API function has different
rules for which mask values can be specified, and can specify whether
a given mask value is mandatory, optional, or forbidden.  Mandatory
fields must be present and forbidden fields must not be present or an
error is generated.  When creating a principal or policy, optional
fields have a default value if they are not specified; when modifying
a principal or policy, optional fields are unchanged if they are not
specified.  The values for forbidden fields are defined in the
function semantics.

The masks for principals are in table \ref{tab:princ-bits} and the
masks for policies are in table \ref{tab:policy-bits}.  They are
defined in $<$ovsec_admin/admin.h$>$. The
OVSEC_KADM_ prefix has been removed from the Name fields.  In the
Create and Modify fields, M means mandatory, F means forbidden, and O
means optional.  Create fields that are optional specify the default
value.  The notation ``K/M value'' means that the field inherits its
value from the corresponding field in the Kerberos master principal.

Note that the POLICY and POLICY_CLR bits are special.  When POLICY is
set, the policy is assigned to the principal.  When POLICY_CLR is
specified, the policy is unassigned to the principal and as a result
no policy controls the principal.

If the principal has a policy assigned, the POLICY bit is set in
aux_attributes.

\begin{table}[htbp]
\begin{tabular}{@{}lclll}
{\bf Name} & {\bf Value} & {\bf Field Affected} & {\bf Create} & 
        {\bf Modify} \\
PRINCIPAL               & 0x000001 & principal & M & F \\
PRINC_EXPIRE_TIME       & 0x000002 & princ_expire_time & O, K/M value & O \\
PW_EXPIRATION           & 0x000004 & pw_expiration & O, now+pw_max_life & O \\
LAST_PWD_CHANGE         & 0x000008 & last_pwd_change & F & F \\
ATTRIBUTES              & 0x000010 & attributes & O, 0 & O \\
MAX_LIFE                & 0x000020 & max_life & O, K/M value & O \\
MOD_TIME                & 0x000040 & mod_date & F & F \\
MOD_NAME                & 0x000080 & mod_name & F & F \\
KVNO                    & 0x000100 & kvno & O, 1 & O \\
MKVNO                   & 0x000200 & mkvno & F & F \\
AUX_ATTRIBUTES          & 0x000400 & aux_attributes & F & F \\
POLICY                  & 0x000800 & policy & O, none & O \\
POLICY_CLR              & 0x001000 & policy & F & O
\end{tabular}
\caption{Mask bits for creating/modifying principals.}
\label{tab:princ-bits}
\end{table}

\begin{table}[htbp]
\begin{tabular}{@{}lclll}
Name & Value & Field Affected & Create & Modify \\
POLICY                  & same     & policy & M & F \\
PW_MAX_LIFE             & 0x004000 & pw_max_life & O, 0 (infinite) & O \\
PW_MIN_LIFE             & 0x008000 & pw_min_life & O, 0 & O \\
PW_MIN_LENGTH           & 0x010000 & pw_min_length & O, 1 & O \\
PW_MIN_CLASSES          & 0x020000 & pw_min_classes & O, 1 & O \\
PW_HISTORY_NUM          & 0x040000 & pw_history_num & O, 0 & O \\
REF_COUNT               & 0x080000 & pw_refcnt & F & F
\end{tabular}
\caption{Mask bits for creating/modifying policies.}
\label{tab:policy-bits}
\end{table}

\subsection{Constants, Header Files, Libraries}

For release 1.0 and release 1.0.1, all of the files decribed in this
section are
rooted off of the ``stage'' directory in the build tree.  If we export
this interface in future releases they will move to the ``install''
tree. Include files are found under ``stage/include'', libraries under
``stage/lib''.

$<$ovsec_admin/admin.h$>$ includes a number of required header files,
including RPC, Kerberos 5, com_err, and \secure{} admin com_err
defines.  It contains prototypes for all ovsec_kadm routines mentioned
below, as well as all Admin API data structures, type definitions and
defines mentioned in this document.  The defines and their values
contained in the file include the following (whose OVSEC_KADM_
prefixes have been removed):
\begin{description}
\item[admin service principal] ADMIN_SERVICE (``ovsec_adm/admin'')
\item[admin history key] HIST_PRINCIPAL (``ovsec_adm/history'')
\item[change password principal] CHANGEPW_SERVICE (``ovsec_adm/changepw'')
\item[server acl file path] ACLFILE (``/krb5/ovsec_adm.acl'')
\item[dictionary] WORDFILE (``/krb5/ovsec_adm.dict'')
\end{description}

OVSEC_KADM errors are described in $<$ovsec_admin/kadm_err.h$>$, which
is included by $<$ovsec_admin/admin.h$>$.

The locations of the admin policy and principal databases, as well as
defines and type definitions for the databases, are defined in
$<$ovsec_admin/adb.h$>$.  Some of the defines in that file are:
\begin{description}
\item[admin policy database] POLICY_DB (``/krb5/ovsec_policy.db'')
\item[admin principal database] PRINCIPAL_DB (``/krb5/ovsec_principal.db'')
\end{description}

Client applications will link against libadmclnt.a and server programs
against libadmsrv.a.\footnote{In Secure 1.0, client applications
linked against libclient.a and libcommon.a, and server applications
linked against libsrv.a and libcommon.a.}  Client applications must
also link against: libgssapi_krb5.a, libkrb5.a, libisode.a,
libcrypto.a, librpclib.a, libcom_err.a, libdyn.a, and libdb.a.  Server
applications must also link against: libkdb5.a, libkrb5.a,
libcrypto.a, libdb.a, librpclib.a, libcom_err.a, and libdyn.a.

\subsection{Error Codes}

The error codes that can be returned by admin functions are listed
below.  Error codes indicated with a ``*'' can be returned by every
admin function and always have the same meaning; these codes are
omitted from the list presented with each function.  

The admin system guarantees that a function that returns an error code
has no other side effect.

The Admin system will use \v{com_err} for error codes.  Note that this
means \v{com_err} codes may be returned from functions that the admin
routines call (e.g. the kerberos library). Callers should not expect
that only OVSEC errors will be returned.  The Admin system error code
table name will be ``ovk'', and the offsets will be the same as the
order presented here. As mentioned above, the error table include file
will be $<$ovsec_admin/kadm_err.h$>$.

\begin{description}
\item[* OVSEC_KADM_FAILURE] Operation failed for unspecified reason
\item[* OVSEC_KADM_AUTH_GET] Operation requires ``get'' privilege
\item[* OVSEC_KADM_AUTH_ADD] Operation requires ``add'' privilege
\item[* OVSEC_KADM_AUTH_MODIFY] Operation requires ``modify'' privilege
\item[* OVSEC_KADM_AUTH_DELETE] Operation requires ``delete'' privilege
\item[* OVSEC_KADM_AUTH_INSUFFICIENT] Insufficient authorization for
operation
\item[* OVSEC_KADM_BAD_DB] Database inconsistency detected
\item[OVSEC_KADM_DUP] Principal or policy already exists
\item[OVSEC_KADM_RPC_ERROR] Communication failure with server
\item[OVSEC_KADM_NO_SRV] No administration server found for realm
\item[OVSEC_KADM_BAD_HIST_KEY] Password history principal key version
mismatch
\item[OVSEC_KADM_NOT_INIT] Connection to server not initialized
\item[OVSEC_KADM_UNK_PRINC]  Principal does not exist
\item[OVSEC_KADM_UNK_POLICY] Policy does not exist
\item[OVSEC_KADM_BAD_MASK] Invalid field mask for operation
\item[OVSEC_KADM_BAD_CLASS] Invalid number of character classes
\item[OVSEC_KADM_BAD_LENGTH] Invalid password length
\item[OVSEC_KADM_BAD_POLICY] Illegal policy name
\item[OVSEC_KADM_BAD_PRINCIPAL] Illegal principal name (XXX use krb5
error code?)
\item[OVSEC_KADM_BAD_AUX_ATTR] Invalid auxillary attributes
\item[OVSEC_KADM_BAD_HISTORY] Invalid password history count
\item[OVSEC_KADM_BAD_MIN_PASS_LIFE] Password minimum life is greater
then password maximum life
\item[OVSEC_KADM_PASS_Q_TOOSHORT] Password is too short
\item[OVSEC_KADM_PASS_Q_CLASS] Password does not contain enough
character classes
\item[OVSEC_KADM_PASS_Q_DICT] Password is in the password dictionary
\item[OVSEC_KADM_PASS_REUSE] Cannot resuse password
\item[OVSEC_KADM_PASS_TOOSOON] Current password's minimum life has not
expired
\item[OVSEC_KADM_POLICY_REF] Policy is in use
\item[OVSEC_KADM_INIT] Connection to server already initialized
\item[OVSEC_KADM_BAD_PASSWORD] Incorrect password
\item[OVSEC_KADM_PROTECT_PRINCIPAL] Cannot change protected principal
\item[* OVSEC_KADM_BAD_SERVER_HANDLE] Programmer error!  Bad Admin server handle
\item[* OVSEC_KADM_BAD_STRUCT_VERSION] Programmer error!  Bad API structure version
\item[* OVSEC_KADM_OLD_STRUCT_VERSION] API structure version specified by application is no longer supported (to fix, recompile application against current OpenV*Secure Admin API header files and libraries)
\item[* OVSEC_KADM_NEW_STRUCT_VERSION] API structure version specified by application is unknown to libraries (to fix, obtain current OpenV*Secure Admin API header files and libraries and recompile application)
\item[* OVSEC_KADM_BAD_API_VERSION] Programmer error!  Bad API version
\item[* OVSEC_KADM_OLD_LIB_API_VERSION] API version specified by application is no longer supported by libraries (to fix, update application to adhere to current API version and recompile)
\item[* OVSEC_KADM_OLD_SERVER_API_VERSION] API version specified by application is no longer supported by server (to fix, update application to adhere to current API version and recompile)
\item[* OVSEC_KADM_NEW_LIB_API_VERSION] API version specified by application is unknown to libraries (to fix, obtain current OpenV*Secure Admin API header files and libraries and recompile application)
\item[* OVSEC_KADM_NEW_SERVER_API_VERSION] API version specified by application is unknown to server (to fix, obtain and install newest OpenV*Secure Admin Server)
\end{description}

\subsection{Authentication and Authorization}
\label{sec:auth}

Two Kerberos principals exist for use in communicating with the Admin
system: ovsec_adm/admin and ovsec_adm/changepw.  Both principals
have the KRB5_KDB_DISALLOW_TGT_BASED bit set in their attributes so
that service tickets for them can only be acquired via a
password-based (AS_REQ) request.  Additionally, ovsec_adm/changepw
has the KRB5_KDB_PWCHANGE_SERVICE bit set so that a principal with an
expired password can still obtain a service ticket for it.

The Admin system accepts requests that are authenticated to either
service principal, but the sets of operations that can be performed by
a request authenticated to each service are different.  In particular,
only the functions chpass_principal, randkey_principal, get_principal,
and get_policy can be performed by a request authenticated to the
ovsec_adm/changepw service.  The function semantics descriptions below
give the precise details.

Each Admin API operation authenticated to the ovsec_adm/admin service
requires a specific authorization to run.  This version uses a simple
named privilege system with the following names and meanings:

The Authorization checks only happen if you are using the RPC mechanism.
If you are using the server-side API functions locally on the admin server,
the only authorization check is if you can access the approporiate local
files. 

\begin{description}
\item[Get] Able to examine the attributes (NOT key data) of principals
and policies. 
\item[Add] Able to add principals and policies.
\item[Modify] Able to modify attributes of existing principals and policies.
\item[Delete] Able to remove principals and policies.
\end{description}

Privileges are specified via an external configuration file on the
Kerberos master server (see section \ref{sec:acls}).

Table \ref{tab:func-overview} summarizes the authorization
requirements of each function.  Additionally, each API function
description identifies the privilege required to perform it.

\subsection{Function Overview}

The functions provided by the Admin API, and the authorization they
require, are listed in the table \ref{tab:func-overview}.  The
``ovsec_kadm_'' prefix has been removed from each function name.

The function semantics in the following sections omit details that are
the same for every function.

\begin{itemize}
\item The effects of every function are atomic.

\item Every function performs an authorization check and returns
the appropriate OVSEC_KADM_AUTH_* error code if the caller does not
have the required privilege.  No other information or error code is
ever returned to an unauthorized user.

\item Every function checks its arguments for NULL pointers or other
obviously invalid values, and returns EINVAL if any are detected.

\item Any function that performs a policy check uses the policy named
in the principal's policy field.  If the POLICY bit is not set in the
principal's aux_attributes field, however, the principal has no
policy, so the policy check is not performed.

\item Unless otherwise specified, all functions return OVSEC_KADM_OK.
\end{itemize}

\begin{table}[htbp]
\caption{Summary of functions and required authorization.}
\label{tab:func-overview}
\begin{tabular}{@{}llp{3.24in}}
\\
{\bf Function Name} & {\bf Authorization} & {\bf Operation} \\

init & none & Open a connection with the ovsec_kadm library.  OBSOLETE
but still provided---use init_with_password instead. \\
init_with_password & none & Open a connection with the ovsec_kadm
library using a password to obtain initial credentials. \\
init_with_skey & none & Open a connection with the ovsec_kadm library
using the keytab entry to obtain initial credentials. \\
destroy & none & Close the connection with the ovsec_kadm library. \\
create_principal & add & Create a new principal. \\
delete_principal & delete & Delete a principal. \\
modify_principal & modify & Modify the attributes of an existing
        principal (not password). \\
rename_principal & add and delete & Rename a principal. \\
get_principal & get\footnotemark & Retrieve a principal. \\
chpass_principal & modify\footnotemark[\thefootnote] &
         Change a principal's password. \\
chpass_principal_util & modify\footnotemark[\thefootnote] & Utility wrapper around chpass_principal. \\
randkey_principal & modify\footnotemark[\thefootnote] &
        Randomize a principal's key. \\
create_policy & add & Create a new policy. \\
delete_policy & delete & Delete a policy. \\
modify_policy & modify & Modify the attributes of a policy. \\
get_policy & get & Retrieve a policy. \\
free_principal_ent & none & Free the memory associated with an
                ovsec_kadm_principal_ent_t. \\
free_policy_ent & none & Free the memory associated with an
                ovsec_kadm_policy_ent_t. \\
get_privs & none & Return the caller's admin server privileges.
\end{tabular}
\end{table}
\footnotetext[\thefootnote]{These functions also allow a principal to
perform the operation on itself; see the function's semantics for
details.}

\subsection{ovsec_kadm_init_*}

\begin{verbatim}
ovsec_kadm_ret_t ovsec_kadm_init_with_password(char *client_name, char *pass,
                                 char *service_name, char *realm,
                                 unsigned long struct_version,
                                 unsigned long api_version,
                                 void **server_handle)

ovsec_kadm_ret_t ovsec_kadm_init_with_skey(char *client_name, char *keytab,
                                 char *service_name, char *realm,
                                 unsigned long struct_version,
                                 unsigned long api_version,
                                 void **server_handle)

ovsec_kadm_ret_t ovsec_kadm_init(char *client_name, char *pass,
                                 char *service_name, char *realm,
                                 unsigned long struct_version,
                                 unsigned long api_version,
                                 void **server_handle)
\end{verbatim}

AUTHORIZATION REQUIRED: none

NOTE: ovsec_kadm_init is an obsolete provided for backwards
compatibility.  It is identical to ovsec_kadm_init_with_password.

These three functions open a connection to the ovsec_kadm library and
initialize any neccessary state information.  They behave differently
when called from local and remote clients.  

For remote clients, the semantics are:

\begin{enumerate}
\item Initializes all the com_err error tables used by the Admin
system.

\item Acquires a Kerberos ticket for the specified service.

\begin{enumerate}
\item The ticket's client is client_name, which can be any valid
Kerberos principal.  If client_name does not include a realm, the
default realm of the local host is used
\item The ticket's service is service_name@realm.  service_name must
be one of the constants OVSEC_KADM_ADMIN_SERVICE or
OVSEC_KADM_CHANGEPW_SERVICE.
\item If realm is NULL, client_name's realm is used.

\item For init_with_password, the ticket is decoded with the password
pass, which must be client_name's password.  If pass is NULL or an
empty string, the user is prompted (via the tty) for a password.

\item For init_with_skey, the ticket is decoded with client_name's key
obtained from the keytab keytab.  If keytab is NULL or an empty string
the default keytab is used.
\end{enumerate}

\item Creates a GSS-API authenticated connection to the Admin server,
using the just-acquired Kerberos ticket.

\item Verifies that the struct_version and api_version specified by
the caller are valid and known to the library.

\item Sends the specified api_version to the server.

\item Upon successful completion, fills in server_handle with a handle
for this connection, to be used in all subsequent API calls.
\end{enumerate}

The caller should always specify OVSEC_KADM_STRUCT_VERSION for the
struct_version argument, a valid and supported API version constant
for the api_version argument (currently, theonly valid API version
constant is OVSEC_KADM_API_VERSION_1), and a valid pointer in which
the server handle will be stored.

Local clients, running on the KDC, may be useful. For now this is will
most likely be used for testing, but could in the future be the basis
for a command-line system that works both remotely and on the KDC
machine.  If any ovsec_kadm_init_* is invoked locally its semantics are:

\begin{enumerate}
\item Initializes all the com_err error tables used by the Admin
system.

\item Initializes direct access to the KDC database.  If pass (or
keytab) is NULL or an empty string, reads the master password from
/.k5.REALM-NAME (created by kstash).  Otherwise, the non-NULL password
is ignored and the user is prompted for it via the tty.

\item Initializes the dictionary (if present) for dictionary checks.

\item Parses client_name as a Kerberos principal.  client_name should
usually be specified as the name of the program.

\item Verifies that the struct_version and api_version specified by
the caller are valid.

\item Fills in server_handle with a handle containing all state
information (version numbers and client name) for this ``connection.''
\end{enumerate}
The service_name argument is not used.

RETURN CODES: 

\begin{description}
\item[OVSEC_KADM_NO_SRV] No Admin server can be found for the
specified realm.

\item[OVSEC_KADM_RPC_ERROR] The RPC connection to the server cannot be
initiated.

\item[OVSEC_KADM_BAD_PASSWORD] Incorrect password.
\end{description}

\subsection{ovsec_kadm_destroy}

\begin{verbatim}
ovsec_kadm_ret_t ovsec_kadm_destroy(void *server_handle)
\end{verbatim}

AUTHORIZATION REQUIRED: none

Close the connection to the Admin server and releases all related
resources.  This function behaves differently when called by local and
remote clients.

For remote clients, the semantics are:

\begin{enumerate}
\item Destroy the temporary credential cache created by
ovsec_kadm_init.

\item Tear down the GSS-API context negotiated with the server.

\item Close the RPC connection.

\item Free storage space associated with server_handle, after erasing
its magic number so it won't be mistaken for a valid handle by the
library later.
\end{enumerate}

For local clients, this function just frees the storage space
associated with server_handle after erasing its magic number.

RETURN CODES:

\subsection{ovsec_kadm_create_principal}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_create_principal(void *server_handle,
                            ovsec_kadm_principal_ent_t princ, u_int32 mask,
                            char *pw);
\end{verbatim}

AUTHORIZATION REQUIRED: add

\begin{enumerate}

\item Return OVSEC_KADM_BAD_MASK if the mask is invalid.
\item If the named principal exists, return OVSEC_KADM_DUP.
\item If the POLICY bit is set and the named policy does not exist,
return OVSEC_KADM_UNK_POLICY.
\item If OVSEC_KADM_POLICY bit is set in aux_attributes check to see if
the password does not meets quality standards, return the appropriate
OVSEC_KADM_PASS_Q_* error code if it fails.
\item Store the principal, set the key.  The key is generated with
Kerberos' string-to-key function, using the salt method specified on
the admin server's command line; see section \ref{sec:commandline}.
\item If the POLICY bit is set, increment the named policy's reference
count by one.

\item Set the pw_expiration field.
\begin{enumerate}
\item If the POLICY bit is not set, then
\begin{enumerate}
\item if the PW_EXPIRATION bit is set, set pw_expiration to the given
value, else
\item set pw_expiration to never.
\end{enumerate}
\item Otherwise, if the PW_EXPIRATION bit is set, set pw_expiration to
the sooner of the given value and now + pw_max_life.
\item Otherwise, set pw_expiration to now + pw_max_life.
\end{enumerate}

\item Set mod_date to now and set mod_name to caller.
\item Set last_pwd_change to now.
\end{enumerate}

RETURN CODES:

\begin{description}
\item[OVSEC_KADM_BAD_MASK] The field mask is invalid for a create
operation.
\item[OVSEC_KADM_DUP] Principal already exists.
\item[OVSEC_KADM_UNK_POLICY] Policy named in entry does not exist.
\item[OVSEC_KADM_PASS_Q_*] Specified password does not meet policy
standards.
\end{description}

\subsection{ovsec_kadm_delete_principal}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_delete_principal(void *server_handle, krb5_principal princ);
\end{verbatim}

AUTHORIZATION REQUIRED: delete 

\begin{enumerate}
\item Return OVSEC_KADM_UNK_PRINC if the principal does not exist.
\item If the POLICY bit is set in aux_attributes, decrement the named
policy's reference count by one.
\item Delete principal.
\end{enumerate}

RETURN CODES: 

\begin{description}
\item[OVSEC_KADM_UNK_PRINC] Principal does not exist.
\end{description}

\subsection{ovsec_kadm_modify_principal}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_modify_principal(void *server_handle,
                            ovsec_kadm_principal_ent_t princ, u_int32 mask);
\end{verbatim}

Modify the attributes of the principal named in
ovsec_kadm_principal_ent_t. This does not allow the principal to be
renamed or for its password to be changed.

AUTHORIZATION REQUIRED: modify

Although a principal's pw_expiration is usually computed based on its
policy and the time at which it changes its password, this function
also allows it to be specified explicitly.  This allows an
administrator, for example, to create a principal and assign it to a
policy with a pw_max_life of one month, but to declare that the new
principal must change its password away from its initial value
sometime within the first week.

\begin{enumerate}
\item Return OVSEC_KADM_UNK_PRINC if the principal does not exist.
\item Return OVSEC_KADM_BAD_MASK if the mask is invalid.
\item If POLICY bit is set but the new policy does not exist, return
OVSEC_KADM_UNK_POLICY.
\item If either the POLICY or POLICY_CLR bits are set, update the
corresponding bits in aux_attributes.

\item Update policy reference counts.
\begin{enumerate}
\item If the POLICY bit is set, then increment policy count on new
policy.
\item If the POLICY or POLICY_CLR bit is set, and the POLICY bit in
aux_attributes is set, decrement policy count on old policy.
\end{enumerate}

\item Set pw_expiration according to the new policy.
\begin{enumerate}
\item If the POLICY bit is not set in aux_attributes, then
\begin{enumerate}
\item if the PW_EXPIRATION bit is set, set pw_expiration to the given
value, else
\item set pw_expiration to never.
\end{enumerate}
\item Otherwise, if the PW_EXPIRATION bit is set, set pw_expiration to
the sooner of the given value and last_pwd_change + pw_max_life.
\item Otherwise, set pw_expiration to last_pwd_change + pw_max_life.
\end{enumerate}

\item Update the fields specified in the mask.
\item Update mod_name field to caller and mod_date to now.
\end{enumerate}

RETURN CODES:

\begin{description}
\item[OVSEC_KADM_UNK_PRINC] Entry does not exist.
\item[OVSEC_KADM_BAD_MASK] The mask is not valid for a modify
operation.
\item[OVSEC_KADM_UNK_POLICY] The POLICY bit is set but the new
policy does not exist.
\end{description}

\subsection{ovsec_kadm_rename_principal}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_rename_principal(void *server_handle, krb5_principal source,
                            krb5_principal target);
\end{verbatim}

AUTHORIZATION REQUIRED: add and delete

\begin{enumerate}
\item Check to see if source principal exists, if not return
OVSEC_KADM_UNK_PRINC error. 
\item Check to see if target exists, if so return OVSEC_KADM_DUP error.
\item Create the new principal named target, then delete the old
principal named source.  All of target's fields will be the same as
source's fields, except that mod_name and mod_date will be updated to
reflect the current caller and time.
\end{enumerate}

Note that since the principal name may have been used as the salt for
the principal's key, renaming the principal may render the principal's
current password useless; with the new salt, the key generated by
string-to-key on the password will suddenly be different.  Therefore,
an application that renames a principal must also require the user to
specify a new password for the principal (and administrators should
notify the affected party).

Note also that, by the same argument, renaming a principal will
invalidate that principal's password history information; since the
salt will be different, a user will be able to select a previous
password without error.

RETURN CODES: 

\begin{description}
\item[OVSEC_KADM_UNK_PRINC] Source principal does not exist.
\item[OVSEC_KADM_DUP] Target principal already exist.
\end{description}

\subsection{ovsec_kadm_chpass_principal}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_chpass_principal(void *server_handle, krb5_principal princ,
                            char *pw);
\end{verbatim}

AUTHORIZATION REQUIRED: modify, or the calling principal being the
same as the princ argument.  If the request is authenticated to the
ovsec_adm/changepw service, the modify privilege is disregarded.

Change a principal's password.  

This function enforces password policy and dictionary checks.  If the new
password specified is in the password dictionary, and the policy bit is set
OVSEC_KADM_PASS_DICT is returned.  If the principal's POLICY bit is set in
aux_attributes, compliance with each of the named policy fields is verified
and an appropriate error code is returned if verification fails.

Note that the policy checks are only be performed if the POLICY bit is
set in the principal's aux_attributes field.

\begin{enumerate}
\item Make sure principal exists, if not return OVSEC_KADM_UNK_PRINC error.
\item If caller does not have modify privilege, (now - last_pwd_change) $<$
pw_min_life, and the KRB5_KDB_REQUIRES_PWCHANGE bit is not set in the
principal's attributes, return OVSEC_KADM_PASS_TOOSOON.
\item If the principal your are trying to change is ovsec_adm/history
return OVSEC_KADM_PROTECT_PRINCIPAL.
\item If the password does not meet the quality
standards, return the appropriate OVSEC_KADM_PASS_Q_* error code.
\item Convert password to key.  The key is generated with
Kerberos' string-to-key function, using the salt method specified on
the admin server's command line; see section \ref{sec:commandline}.
\item If the new key is in the principal's password history, return
OVSEC_KADM_PASS_REUSE.
\item Store old key in history.
\item Update principal to have new key.
\item Increment principal's key version number by one.
\item If the POLICY bit is set, set pw_expiration to now +
max_pw_life.  If the POLICY bit is not set, set pw_expiration to
never.
\item If the KRB5_KDB_REQUIRES_PWCHANGE bit is set in the principal's
attributes, clear it.
\item Update last_pwd_change and mod_date to now, update mod_name to
caller.
\end{enumerate}

RETURN CODES:

\begin{description}
\item[OVSEC_KADM_UNK_PRINC] Principal does not exist.
\item[OVSEC_KADM_PASS_Q_*] Requested password does not meet quality
standards. 
\item[OVSEC_KADM_PASS_REUSE] Requested password is in user's
password history. 
\item[OVSEC_KADM_PASS_TOOSOON] Current password has not reached minimum life
\item[OVSEC_KADM_PROTECT_PRINCIPAL] Cannot change the password of a special principal
\end{description}


\subsection{ovsec_kadm_chpass_principal_util}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_chpass_principal_util(void *server_handle, krb5_principal princ,
                                 char *new_pw, char **pw_ret,
                                 char *msg_ret);
\end{verbatim}

AUTHORIZATION REQUIRED: modify, or the calling principal being the
same as the princ argument.  If the request is authenticated to the
ovsec_adm/changepw service, the modify privilege is disregarded.

This function is a wrapper around ovsec_kadm_chpass_principal. It can
read a new password from a user, change a principal's password, and
return detailed error messages.  msg_ret should point to a char buffer
in the caller's space of sufficient length for the error messages
described below. 1024 bytes is recommended.  It will also return the
new password to the caller if pw_ret is non-NULL.

\begin{enumerate}
\item If new_pw is NULL, this routine will prompt the user for the new
password (using the strings specified by OVSEC_KADM_PW_FIRST_PROMPT and
OVSEC_KADM_PW_SECOND_PROMPT) and read (without echoing) the password input.
Since it is likely that this will simply call krb5_read_password only
terminal-based applications will make use of the password reading
functionality. If the passwords don't match the string ``New passwords do
not match - password not changed.'' will be copied into msg_ret, and the
error code KRB5_LIBOS_BADPWDMATCH will be returned.  For other errors that
ocurr while reading the new password, copy the string ``<com_err message$>$
occurred while trying to read new password.'' followed by a blank line and
the string specified by CHPASS_UTIL_PASSWORD_NOT_CHANGED into msg_ret and
return the error code returned by krb5_read_password.

\item If pw_ret is non-NULL, and the password was prompted, set *pw_ret to
point to a static buffer containing the password.  If pw_ret is non-NULL
and the password was supplied, set *pw_ret to the supplied password.

\item Call ovsec_kadm_chpass_principal with princ, and new_pw.

\item If successful copy the string specified by CHPASS_UTIL_PASSWORD_CHANGED
into msg_ret and return zero.

\item For a policy related failure copy the appropriate message (from below) 
followed by a newline and ``Password not changed.'' into msg_ret
filling in the parameters from the principal's policy information. If
the policy information cannot be obtained copy the generic message if
one is specified below. Return the error code from
ovsec_kadm_chpass_principal.

Detailed messages:
\begin{description}

\item[PASS_Q_TOO_SHORT]
New password is too short. Please choose a
password which is more than $<$pw-min-len$>$ characters.

\item[PASS_Q_TOO_SHORT - generic]
New password is too short. Please choose a longer password.

\item[PASS_REUSE]
New password was used previously. Please choose a
different password.

\item[PASS_Q_CLASS]
New password does not have enough character classes. Classes include
lower class letters, upper case letters, digits, punctuation and all
other characters.  Please choose a password with at least
$<$min-classes$>$ character classes.

\item[PASS_Q_CLASS - generic]
New password does not have enough character classes. Classes include
lower class letters, upper case letters, digits, punctuation and all
other characters. 

\item[PASS_Q_DICT] 
New password was found in a dictionary of possible passwords and
therefore may be easily guessed.  Please choose another password. See
the kpasswd man page for help in choosing a good password.

\item[PASS_TOOSOON]
Password cannot be changed because it was changed too recently. Please
wait until $<$last-pw-change+pw-min-life$>$ before you change it. If you
need to change your password before then, contact your system
security administrator.

\item[PASS_TOOSOON - generic]
Password cannot be changed because it was changed too recently. If you
need to change your now please contact your system security
administrator.
\end{description}

\item For other errors copy the string ``$<$com_err message$>$
occurred while trying to change password.'' following by a blank line
and ``Password not changed.'' into msg_ret. Return the error code
returned by ovsec_kadm_chpass_principal.
\end{enumerate}


RETURN CODES:

\begin{description}
\item[KRB5_LIBOS_BADPWDMATCH] Typed new passwords did not match.
\item[OVSEC_KADM_UNK_PRINC] Principal does not exist.
\item[OVSEC_KADM_PASS_Q_*] Requested password does not meet quality
standards. 
\item[OVSEC_KADM_PASS_REUSE] Requested password is in user's
password history. 
\item[OVSEC_KADM_PASS_TOOSOON] Current password has not reached minimum
life. 
\end{description}


\subsection{ovsec_kadm_randkey_principal}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_randkey_principal(void *server_handle, krb5_principal princ,
                             krb5_keyblock **new_key)
\end{verbatim}

AUTHORIZATION REQUIRED: modify, or the calling principal being the
same as the princ argument.  If the request is authenticated to the
ovsec_adm/changepw service, the modify privilege is disregarded.

Generate and assign a new random key to the named principal, and
return the generated key in allocated storage.  The caller must free
the returned krb5_keyblock * with krb5_free_keyblock.

If the principal's POLICY bit is set in aux_attributes and the caller does
not have modify privilege , compliance with the password minimum life
specified by the policy is verified and an appropriate error code is returned
if verification fails. 

\begin{enumerate}
\item If the principal does not exist, return OVSEC_KADM_UNK_PRINC.
\item If caller does not have modify privilege, (now - last_pwd_change) $<$
pw_min_life, and the KRB5_KDB_REQUIRES_PWCHANGE bit is not set in the
principal's attributes, return OVSEC_KADM_PASS_TOOSOON.
\item If the principal you are trying to change is ovsec_adm/history return
OVSEC_KADM_PROTECT_PRINCIPAL.
\item Store old key in history.
\item Update principal to have new key.
\item Increment principal's key version number by one.
\item If the POLICY bit in aux_attributes is set, set pw_expiration to
now + max_pw_life.
\item If the KRB5_KDC_REQUIRES_PWCHANGE bit is set in the principal's
attributes, clear it.
\item Update last_pwd_change and mod_date to now, update mod_name to
caller.
\end{enumerate}

RETURN CODES:

\begin{description}
\item[OVSEC_KADM_UNK_PRINC] Principal does not exist.
\item[OVSEC_KADM_PASS_TOOSOON] The minimum lifetime for the current
key has not expired.
\item[OVSEC_KADM_PROTECT_PRINCIPAL] Cannot change the password of a special
principal
\end{description}

This function can also be used as part of a sequence to create a new
principal with a random key.  The steps to perform the operation
securely are

\begin{enumerate}
\item Create the principal with ovsec_kadm_create_principal with a
random password string and with the KRB5_KDB_DISALLOW_ALL_TIX bit set
in the attributes field.

\item Randomize the principal's key with ovsec_kadm_randkey_principal.

\item Call ovsec_kadm_modify_principal to reset the
KRB5_KDB_DISALLOW_ALL_TIX bit in the attributes field.
\end{enumerate}

The three steps are necessary to ensure secure creation.  Since an
attacker might be able to guess the initial password assigned by the
client program, the principal must be disabled until the key can be
truly randomized.

\subsection{ovsec_kadm_get_principal}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_get_principal(void *server_handle, krb5_principal princ, 
                         ovsec_kadm_principal_ent_t *ent);  
\end{verbatim}

Return the principal's attributes in allocated memory.  The caller
must free the returned entry with ovsec_kadm_free_principal_ent.
If an error is returned entry is set to NULL.

AUTHORIZATION REQUIRED: get, or the calling principal being the same
as the princ argument.  If the request is authenticated to the
ovsec_adm/changepw service, the get privilege is disregarded.


RETURN CODES:

\begin{description}
\item[OVSEC_KADM_UNK_PRINC] Principal does not exist.
\end{description}

\subsection{ovsec_kadm_create_policy}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_create_policy(void *server_handle,
                         ovsec_kadm_policy_ent_t policy, u_int32 mask); 
\end{verbatim}

Create a new policy.

AUTHORIZATION REQUIRED: add

\begin{enumerate}
\item Check to see if mask is valid, if not return OVSEC_KADM_BAD_MASK error.
\item Return OVSEC_KADM_BAD_POLICY if the policy name contains illegal
characters.

\item Check to see if the policy already exists, if so return
OVSEC_KADM_DUP error. 
\item If the PW_MIN_CLASSES bit is set and pw_min_classes is not 1, 2,
3, 4, or 5, return OVSEC_KADM_BAD_CLASS.
\item Create a new policy setting the appropriate fields determined
by the mask.
\end{enumerate}

RETURN CODES:

\begin{description}
\item[OVSEC_KADM_DUP] Policy already exists
\item[OVSEC_KADM_BAD_MASK] The mask is not valid for a create
operation.
\item[OVSEC_KADM_BAD_CLASS] The specified number of character classes
is invalid.
\item[OVSEC_KADM_BAD_POLICY] The policy name contains illegal characters.
\end{description}

\subsection{ovsec_kadm_delete_policy}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_delete_policy(void *server_handle, char *policy);
\end{verbatim}

Deletes a policy.

AUTHORIZATION REQUIRED: delete

\begin{enumerate}
\item Return OVSEC_KADM_BAD_POLICY if the policy name contains illegal
characters.
\item Return OVSEC_KADM_UNK_POLICY if the named policy does not exist.
\item Return OVSEC_KADM_POLICY_REF if the named policy's refcnt is not 0.
\item Delete policy.
\end{enumerate}

RETURN CODES:

\begin{description}
\item[OVSEC_KADM_BAD_POLICY] The policy name contains illegal characters.
\item[OVSEC_KADM_UNK_POLICY] Policy does not exist.
\item[OVSEC_KADM_POLICY_REF] Policy is being referenced. 
\end{description}

\subsection{ovsec_kadm_modify_policy}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_modify_policy(void *server_handle,
                         ovsec_kadm_policy_ent_t policy, u_int32 mask);
\end{verbatim}

Modify an existing policy.  Note that modifying a policy has no affect
on a principal using the policy until the next time the principal's
password is changed.

AUTHORIZATION REQUIRED: modify

\begin{enumerate}
\item Return OVSEC_KADM_BAD_POLICY if the policy name contains illegal
characters.
\item Check to see if mask is legal, if not return OVSEC_KADM_BAD_MASK error.
\item Check to see if policy exists, if not return
OVSEC_KADM_UNK_POLICY error.
\item If the PW_MIN_CLASSES bit is set and pw_min_classes is not 1, 2,
3, 4, or 5, return OVSEC_KADM_BAD_CLASS.
\item Update the fields specified in the mask.
\end{enumerate}

RETURN CODES: 

\begin{description}
\item[OVSEC_KADM_BAD_POLICY] The policy name contains illegal characters.
\item[OVSEC_KADM_UNK_POLICY] Policy not found.
\item[OVSEC_KADM_BAD_MASK] The mask is not valid for a modify
operation.
\item[OVSEC_KADM_BAD_CLASS] The specified number of character classes
is invalid.
\end{description}

\subsection{ovsec_kadm_get_policy}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_get_policy(void *server_handle, char *policy,
                      ovsec_kadm_policy_ent_t *ent); 
\end{verbatim}

AUTHORIZATION REQUIRED: get, or the calling principal's policy being
the same as the policy argument.  If the request is authenticated to
the ovsec_adm/changepw service, the get privilege is disregarded.
If an error is returned entry is set to NULL.

Return the policy's attributes in allocated memory.  The caller must
free the returned entry with ovsec_kadm_free_policy_ent.

RETURN CODES: 

\begin{description}
\item[OVSEC_KADM_BAD_POLICY] The policy name contains illegal characters.
\item[OVSEC_KADM_UNK_POLICY] Policy not found.
\end{description}

\subsection{ovsec_kadm_free_principal_ent, _policy_ent}

\begin{verbatim}
void ovsec_kadm_free_principal_ent(void *server_handle,
                                   ovsec_kadm_principal_ent_t princ);
\end{verbatim}

Free the memory that was allocated by a call to
ovsec_kadm_get_principal.  If the argument is NULL, the function
returns succesfully.

AUTHORIZATION REQUIRED: none (local operation)

\begin{verbatim}
void ovsec_kadm_free_policy_ent(ovsec_kadm_policy_ent_t policy);
\end{verbatim}

Free memory that was allocated by a call to ovsec_kadm_get_policy.  If
the argument is NULL, the function returns succesfully.

AUTHORIZATION REQUIRED: none (local operation)

\subsection{ovsec_kadm_get_privs}

\begin{verbatim}
ovsec_kadm_ret_t
ovsec_kadm_get_privs(void *server_handle, u_int32 *privs);
\end{verbatim}

Return the caller's admin server privileges in the integer pointed to
by the argument.  The Admin API does not define any way for a
principal's privileges to be set.  Note that this function will
probably be removed or drastically changed in future versions of this
system.

The returned value is a bitmask indicating the caller's privileges:

\begin{tabular}{llr}
{\bf Privilege} & {\bf Symbol} & {\bf Value} \\
Get & OVSEC_KADM_PRIV_GET & 0x01 \\
Add & OVSEC_KADM_PRIV_ADD & 0x02 \\
Modify & OVSEC_KADM_PRIV_MODIFY & 0x04 \\
Delete & OVSEC_KADM_PRIV_DELETE & 0x08
\end{tabular}

There is no guarantee that a caller will have a privilege indicated by
this function for any length of time; applications using this function
must still be prepared to handle all possible OVSEC_KADM_AUTH_* error
codes.

\section{Server}

The Admin API will be implemented by a server process running on the
same machine as the Kerberos server, and a client library to
communicate with the server.

\subsection{Command Line}
\label{sec:commandline}

The command line syntax of the admin server is

\begin{verbatim}
ovsec_adm_server [-m] [-r realm] [-createsalt normal|none]
        [-modifysalt normal|none|keep] 
\end{verbatim}

The -m argument specifies that the Kerberos master key should be read
from the keyboard instead of from the stash file.  If the stash file
does not exist and this argument is not specified, the server will
not start.

The -r argument specifies the Kerberos realm.  If this argument is not
specified, the host's default realm is used. 

The -createsalt and -modifysalt arguments control the type of salt
used when creating and modifying keys in the Kerberos database,
respectively.  ``normal'' means the standard V5 salt which uses the
principal and realm name.  ``none'' means no salt, which is compatible
with Kerberos V4.  ``keep'' means maintain the previous salt when a
key is changed.

If the either admin principal or policy databases are reloaded using
the tools described in section \ref{sec:tools}, the admin server must
be shut down during the process.  If the admin server is left running
during the import process, at best the server may use old information
and at worst the database may become inconsistent.

\subsection{Protocol and Port Number}

The admin server accepts TCP Sun RPC connections.  The port number
(which the server listens on, and which clients should use to contact
it) is determined by a three step process:

\begin{enumerate}
\item If ovsec_kadm/tcp exists in /etc/services, the specified port
number is used.

\item Otherwise, if kerberos_adm/tcp exists in /etc/services, the
specified port number is used.

\item Otherwise, port number 752 is used.
\end{enumerate}

\subsection{Key Table, Authorization ACLs}
\label{sec:acls}

The admin server's keytable is stored in /krb5/ovsec_adm.srvtab.  It
contains entries for the principals OVSEC_KADM_ADMIN_SERVICE and
OVSEC_KADM_CHANGEPW_SERVICE.

The admin server will use a simple ACL mechanism to grant privileges
to principals.  The file OVSEC_KADM_ACLFILE will contain a
list of principals and their privileges.  It is read at start-up, and
can only be reread by restarting the admin server.

The format of this file is:

\begin{itemize}
\item Blank lines or lines beginning with ``\#'' are ignored.

\item ACL entry lines contain two fields separated by any number of
spaces, tabs, or newlines, and are terminated with a semi-colon.  The
first field is a Kerberos name and the second field is the privilege
list.

\item The privilege list can contain a comma separated list of the
words ``get'', ``add'', ``modify'', and ``delete''.
\end{itemize}

The principal named in the first field of each ACL entry has the
privileges listed in the second field the ACL entry.

\subsection{Logging}

The Admin server will log various events via the syslog mechanism (see
the syslog(3) manual page).  The level depends on the notice, the
facility is LOG_LOCAL6, and notices are identified with the name
``ovsec_adm_server''.  Each syslog message described below begins with
a prefix including the time the message was logged, the host name of
the logging machine, and the pid of the logging process:

\begin{verbatim}
Nov 11 12:37:26 suan-la-chow-show ovsec_adm_server[9229]: <message>
\end{verbatim}

\subsubsection{Miscellaneous Messages}

When the server starts successfully and is ready to handle requests,
is logs the message ``starting'' at the LOG_INFO level.  When it exits
(due to a signal, for example) it logs the message ``finished,
exiting'' at the LOG_INFO level.

If the dictionary file does not exist, the server logs the message
``WARNING: Cannot find the dictionary file $<$name$>$, continuing
without one.'' at the LOG_ERR level and continues with dictionary
checking disabled.

If the server cannot register itself as an RPC server via the portmap
daemon, it logs the message ``Cannot register RPC service, failing.''
at the LOG_ERR level and exits with non-zero status.  This error can
happen if the portmapper is not running.

If the GSS-API authentication system cannot be initialized, the server
logs the message ``Cannot initialize GSS-API authentication,
failing.'' at the LOG_ERR level and exits with non-zero status.  This
error can happen if, for example, the file ovsec_adm.srvtab does not
exist or is incorrect.

\subsubsection{Request Messages}

In the event descriptions below, IP address refers to the originating
remote IP address, procedure name refers to the name of the API
function, client name refers to the authenticated name of the caller,
service name refers to the service the client authenticated to (see
section \ref{sec:auth}), primary argument refers to the name of the
principal or policy affected by the call,\footnote{The first release
only logs the primary argument, rather than logging the old and new
values of all fields.} and status refers to the com_err string
corresponding to the error code generated.  All of these messages are
logged at the LOG_NOTICE level.

\begin{itemize}
\item Unsuccessful authentication attempts (e.g.: failures during
GSS-API context establishment).  This error occurs inside the RPC; the
admin server is notified via a callback.

\begin{verbatim}
Authentication attempt failed: <IP address>, <GSS-API error strings>
\end{verbatim}

Example:  A buggy client attempts to authenticate to the admin server
as the existing but invalid service name ``mailserver@REALM.COM'':

\begin{verbatim}
Authentication attempt failed: 192.231.148.11, Miscellaneous error,
Wrong principal in request
\end{verbatim}

\item Authentication failure.  This error can occur both within the
RPC, while parsing the RPC call header, and while arguments are
decoded by the admin server.  It can be the result of a a garbled
{\it or retransmitted} packet, a replay attack, a packet-modification
attack, or a header/argument splicing attack.

\begin{verbatim}
WARNING! Forged/garbled request: <procedure name>, claimed client =
<client name>, service = <service name>, addr = <IP address>
\end{verbatim}

Example: An attacker attempts to replay a previously valid ``create
principal'' message from jon/admin@REALM.COM:

\begin{verbatim}
WARNING! Forged/garbled request: ovsec_kadm_create_principal, claimed
client = jon/admin@REALM.COM, service = admin@REALM.COM, addr =
192.231.148.12
\end{verbatim}

\item Unauthorized request.  This error occurs when a properly
authenticated caller attempts to perform an operation for which it is
not authorized.

\begin{verbatim}
Unauthorized request: <procedure name>, <primary argument>, client =
<client name>, service = <service name>, addr = <IP address>
\end{verbatim}

Example: An attacker cracker@REALM.COM attempts to modify the Kerberos
master principal:

\begin{verbatim}
Unauthorized request: ovsec_kadm_modify_principal, K/M@REALM.COM,
client = cracker@REALM.COM, service = admin@REALM.COM, addr =
192.231.148.12
\end{verbatim}

\item Authorized requests and miscellaneous errors.  A message is
logged when an authorized request succeeds or fails for any reason
other than those listed above.  In the case of success, the status is
``success''; otherwise, the status can be anything from ``no space
left on device'' (ENOSPC) to an OVSEC_KADM error such as ``principal
does not exist'' (OVSEC_KADM_UNK_PRINC).

\begin{verbatim}
Request: <procedure name>, <primary argument>, <status>, client =
<client name>, service = <service name>, addr = <IP address>
\end{verbatim}

Example: jon/admin@REALM.COM creates a new principal new@REALM.COM:

\begin{verbatim}
Request: ovsec_kadm_create_principal, new@REALM.COM, success,
client = jon/admin@REALM.COM, service = admin@REALM.COM, addr =
192.231.148.12
\end{verbatim}

Example: A buggy client program attempts to create a principal with a
NULL name:

\begin{verbatim}
Request: ovsec_kadm_create_principal, (null), Invalid argument, client
= jon/admin@REALM.COM, service = admin@REALM.COM, addr =
192.231.148.12
\end{verbatim}

Example: joe/user@REALM.COM changes its own password:

\begin{verbatim}
Request: ovsec_kadm_chpass_principal, joe/user@REALM.COM, success,
client = joe/user@REALM.COM, server = ovsec_adm/changepw@REALM.COM,
addr = 192.231.148.12
\end{verbatim}

Example: jon/admin@REALM.COM attempts to get a principal that does not
exist:

\begin{verbatim}
Request: ovsec_kadm_get_principal, does/not/exist@REALM.COM, principal
does not exist, client = jon/admin@REALM.COM, server =
admin@REALM.COM, addr = 192.231.148.12
\end{verbatim}

\end{itemize}

\subsection{Password Dictionary}

The Admin server's password dictionary is stored in
OVSEC_KADM_WORDFILE.  It is read once when the server starts.  It
contains a list of entries, separated by newlines.  An entry may
include any character except a newline and NULL, including spaces.
The dictionary does not need to be sorted.

\section{Tools}
\label{sec:tools}

Three tools will be provided to create and manage the admin databases.
This need only run on the admin server machine and do not need to
operate remotely.  The tools are:

\begin{description}
\item[ovsec_adm_create] create the admin service principal, the admin
history principal, the admin password-changing principal, and empty
admin policy database, and an admin principal database with an empty
entry for every exist principal.
\item[ovsec_adm_db_export/import] dump or load the admin policy and
principal databases
\item[ovsec_adm_check] check the KDC and admin databases for
inconsistencies and repair them.\footnote{Not yet implemented.}
\end{description}

The details of these tools are described in their own documents.

\end{document}
