\documentstyle[times,fullpage,rcsid]{article}

\rcs$Id: api-unit-test.tex 17360 2005-08-25 23:41:34Z raeburn $

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

\newcommand{\test}[1]{\begin{description}
\setlength{\itemsep}{0pt}
#1
\end{description}

}

\newcommand{\numtest}[2]{\begin{description}
\setlength{\itemsep}{0pt}
\Number{#1}
#2
\end{description}

}

\newcommand{\Number}[1]{\item[Number:] #1}
\newcommand{\Reason}[1]{\item[Reason:] #1}
\newcommand{\Expected}[1]{\item[Expected:] #1}
\newcommand{\Conditions}[1]{\item[Conditions:] #1}
\newcommand{\Priority}[1]{\item[Priority:] #1}
\newcommand{\Status}[1]{\item[Status:] #1}
\newcommand{\Vtwonote}[1]{\item[V2 note:] #1}
\newcommand{\Version}[1]{\item[Version:] #1}
\newcommand{\Call}[1]{}
%\newcommand{\Call}[1]{\item[Call:] #1}
%\newcommand{\Number}[1]{}
%\newcommand{\Reason}[1]{}
%\newcommand{\Expected}[1]{}
%\newcommand{\Conditions}[1]{}
%\newcommand{\Priority}[1]{}

\title{KADM5 Admin API\\
Unit Test Description\footnote{\rcsId}}
\author{Jonathan I. Kamens}

\begin{document}

\maketitle

%\tableofcontents

\section{Introduction}

The following is a description of a black-box unit test of the KADM5
API.  Each API function is listed, followed by the tests that shoud be
performed on it.

The tests described here are based on the ``Kerberos Administration
System KADM5 API Functional Specifications'', revision 1.68.  This
document was originally written based on the OpenVision API functional
specifications, version 1.41, dated August 18, 1994, and many
indications of the original version remain.

All tests which test for success should verify, using some means other
than the return value of the function being tested, that the requested
operation was successfully performed.  For example: for init, test
that other operations can be performed after init; for destroy, test
that other operations can't be performed after destroy; for modify
functions, verify that all modifications to the database which should
have taken place did, and that the new, modified data is in effect;
for get operations, verify that the data retrieved is the data that
should actually be in the database.

The tests would be better if they compared the actual contents of the
database before and after each test, rather than relying on the KADM5
API to report the results of changes.

Similarly, all tests which test for failure should verify that the
no component of the requested operation took place.  For example: if
init fails, other operations should not work.  If a modify fails, all
data in the database should be the same as it was before the attempt
to modify, and the old data should still be what is enforced.
Furthermore, tests which test for failure should verify that the
failure code returned is correct for the specific failure condition
tested.

Most of the tests listed below should be run twice -- once locally on
the server after linking against the server API library, and once
talking to the server via authenticated Sun RPC after linking against
the client API library.  Tests which should only be run locally or via
RPC are labelled with a ``local'' or ``RPC''.

Furthermore, in addition to the tests labelled below, a test should be
implemented to verify that a client can't perform operations on the
server through the client API library when it's linked against
standard Sun RPC instead of OpenV*Secure's authenticated Sun RPC.
This will require a client with a modified version of ovsec_kadm_init
which doesn't call auth_gssapi_create.  This client should call this
modified ovsec_kadm_init and then call some other admin API function,
specifying arguments to both functions that would work if the
authenticated Sun RPC had been used, but shouldn't if authentication
wasn't used.  The test should verify that the API function call after
the init doesn't succeed.

There is also another test to see if all the API functions handle getting an
invalid server handle correctly. This is not done as part of the tests that
are run through the TCL program cause the TCL program has no way of
invalidating a server handle.  So there is a program that calls init and
changes the handle magic number, and then attempts to call each API function
with the corrupted server handle.

A number of tests have been added or changed to correspond with KADM5
API version 2.  Tests which are only performed against the newer
version specify the version number in the test description.

\section{ovsec_kadm_init}

\numtest{1}{
\Reason{An empty string realm is rejected.}
\Status{Implemented}
\Vtwonote{The empty string is now passed as the realm field of the
parameters structure.}
}

\numtest{2}{
\Reason{A realm containing invalid characters is rejected.}
\Status{Implemented}
\Vtwonote{The invalid character is now passed as the realm field of the
parameters structure.}
}

\numtest{2.5}{
\Reason{A non-existent realm is rejected.}
\Status{Implemented}
\Vtwonote{The non-existent realm is now passed as the realm field of the
parameters structure.}
}

\numtest{3}{
\Reason{A bad service name representing an existing principal
	(different from the client principal) is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{4}{
\Reason{A bad service name representing a non-existent
		principal is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{5}{
\Reason{A bad service name identical to the (existing) client
		name is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{6}{
\Reason{A null password causes password prompting.}
\Status{Implemented}
}

\numtest{7}{
\Reason{An empty-string causes password prompting}
\Status{Implemented}
}

\numtest{8}{
\Reason{An incorrect password which is the password of another
		user is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{9}{
\Reason{An incorrect password which isn't the password of any
		user is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{10}{
\Reason{A null client_name is rejected.}
\Status{Implemented}
}

% Empty string client name is legal.
%\numtest{11}{
%\Reason{An empty-string client_name is rejected.}
%}

\numtest{12}{
\Reason{A client_name referring to a non-existent principal in
		the default realm is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{13}{
\Reason{A client_name referring to a non-existent principal
		with the local realm specified explicitly is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{14}{
\Reason{A client_name referring to a non-existent principal in
	a nonexistent realm is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{15}{
\Reason{A client_name referring to an existing principal in a
	nonexistent realm is rejected.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{16}{
\Reason{Valid invocation.}
\Status{Implemented}
}

\numtest{17}{
\Reason{Valid invocation (explicit client realm).}
\Status{Implemented}
}

\numtest{18}{
\Reason{Valid invocation (CHANGEPW_SERVICE).}
\Status{Implemented}
}

\numtest{19}{
\Reason{Valid invocation (explicit service realm).}
\Status{Implemented}
\Vtwonote{The explicit realm is now passed as the realm field of the
configuration parameters.}
}

\numtest{20}{
\Reason{Valid invocation (database access allowed after init).}
\Status{Implemented}
}

%\numtest{21}{
%\Reason{Init fails when called twice in a row.}
%\Status{Implemented}
%}

\numtest{22}{
\Reason{A null password causes master-key prompting.}
\Conditions{local}
\Status{Implemented}
\Vtwonote{Obsolete.}
}

\numtest{22.5}{
\Reason{A empty string password causes master-key prompting.}
\Conditions{local}
\Status{Implemented}
\Vtwonote{Obsolete.}
}

%\numtest{23}{
%\Reason{A non-null password causes reading from the kstash.}
%\Conditions{local}
%\Status{Implemented}
%}

\numtest{24}{
\Reason{Null service name is ignored in local invocation.}
\Conditions{local}
\Status{Implemented}
}

\numtest{25}{
\Reason{Non-null service name is ignored in local invocation.}
\Conditions{local}
\Status{Implemented}
}

%\numtest{26}{
%\Reason{Can't do ``get'' operation before calling init.}
%\Status{Implemented}
%}

%\numtest{27}{
%\Reason{Can't do ``add'' operation before calling init.}
%\Status{Implemented}
%}

%\numtest{28}{
%\Reason{Can't do ``modify'' operation before calling init.}
%\Status{Implemented}
%}

%\numtest{29}{
%\Reason{Can't do ``delete'' operation before calling init.}
%\Status{Implemented}
%}

\numtest{30}{
\Reason{Can init after failed init attempt.}
\Conditions{local}
\Status{Implemented}
}

\numtest{31}{
\Priority{High}
\Reason{Return BAD_STRUCT_VERSION when the mask bits are set to invalid values}
\Status{Implemented}
}

\numtest{32}{
\Priority{High}
\Reason{Return BAD_STRUCT_VERSION when the mask bits are not set}
\Status{Implemented}
}

\numtest{33}{
\Priority{High}
\Reason{Return OLD_STRUCT_VERSION when attempting to use an old/unsupported
	structure version}
\Status{Implemented}
}

\numtest{34}{
\Priority{High}
\Reason{Return NEW_STRUCT_VERSION when attempting to use a newer version of
	of the structure then what is supported}
\Status{Implemented}
}

\numtest{35}{
\Priority{High}
\Reason{Return BAD_API_VERSION when the mask bits are set to invalid values}
\Status{Implemented}
}

\numtest{36}{
\Priority{High}
\Reason{Return BAD_API_VERSION when the mask bits are not set}
\Status{Implemented}
}

\numtest{37}{
\Priority{High}
\Reason{Return OLD_LIB_API_VERSION when using an old/unsuppored
	api version number}
\Conditions{RPC}	
\Status{Implemented}
}

\numtest{38}{
\Priority{High}
\Reason{Return OLD_SERVER_API_VERSION attempting to use an
	old/unsupported api version number}
\Conditions{local}	
\Status{Implemented}
}

\numtest{39}{
\Priority{High}
\Reason{Return NEW_LIB_API_VERSION when using a newer api
	version number then supported}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{40}{
\Priority{High}
\Reason{Return NEW_SERVER_API_VERSION when using a newer api version
	number then supported}
\Conditions{local}
\Status{Implemented}
}

\numtest{41}{
\Priority{High}
\Reason{Return BAD_XXX_VERSION when the API and the structure
	version numbers are reversed}
\Status{Implemented}
}

\numtest{42}{
\Priority{High}
\Reason{Succeeds when using valid api and struct version numbers and masks}
\Status{Implemented}
}

\numtest{43}{
\Priority{Low}
\Reason{Returns two different server handle when called twice with same info}
}

\numtest{44}{
\Priority{Low}
\Reason{Returns two different server handles when called twice with
	different  info}
}

\numtest{45}{
\Priority{Bug fix, secure-install/3390}
\Reason{Returns SECURE_PRINC_MISSING when ADMIN_SERVICE does not
exist.}
\Status{Implemented}
}

\numtest{46}{
\Priority{Bug fix, secure-install/3390}
\Reason{Returns SECURE_PRINC_MISSING when CHANGEPW_SERVICE does not
exist.}
\Status{Implemented}
}

\numtest{100}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the profile field of the configuration parameters, if
set.}
\Status{Implemented}
}

\numtest{101}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the kadmind_port field of the configuration parameters,
if set.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{102}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the admin_server field of the configuration parameters,
if set with only an admin server name.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{102.5}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the admin_server field of the configuratin parameters,
if set with a host name and port number.}
\Conditions{RPC}
}

\numtest{103}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the dbname field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{104}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the admin_dbname field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{105}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the admin_lockfile field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{106}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the mkey_from_kbd field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{107}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the stash_file field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{108}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the mkey_name field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{109}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the max_life field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{110}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the max_rlife field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{111}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the expiration field of the configuration parameters, if
set.}
\Status{Implemented}
\Conditions{local}
}

\numtest{112}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the flags field of the configuration parameters, if
set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{113}{
\Version{KADM5_API_VERSION_2}
\Reason{Obeys the keysalts and num_keysalts field of the configuration
parameters, if set.}
\Conditions{local}
\Status{Implemented}
}

\numtest{114}{
\Version{KADM5_API_VERSION_2}
\Reason{Returns KADM5_BAD_SERVER_PARAMS if any client-only parameters
are specified to server-side init.}
\Conditions{local}
\Status{Implemented}
}

\numtest{115}{
\Version{KADM5_API_VERSION_2}
\Reason{Returns KADM5_BAD_CLIENT_PARAMS if any client-only parameters
are specified to server-side init.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{116}{
\Version{KADM5_API_VERSION_2}
\Reason{Two calls to init with clients having different privileges
succeedes, and both clients maintain their correct privileges.}
\Priority{Bug fix}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{117}{
\Version{KADM5_API_VERSION_2}
\Reason{The max_life field defaults to value specified in the API
Functional Specification when kdc.conf is unreadable.}
\Priority{Bug fix, krb5-admin/18}
\Conditions{local}
\Status{Implemented}
}

\numtest{150}{
\Version{KADM5_API_VERSION_2}
\Reason{init_with_creds works when given an open ccache with a valid
credential for ADMIN_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{151}{
\Version{KADM5_API_VERSION_2}
\Reason{init_with_creds works when given an open ccache with a valid
credential for CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{152}{
\Version{KADM5_API_VERSION_2}
\Reason{init_with_creds fails with KRB5_FCC_NOFILE (was
  KADM5_GSS_ERROR) when given an open
ccache with no credentials.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{153}{
\Version{KADM5_API_VERSION_2}
\Reason{init_with_creds fails with KRB5_CC_NOTFOUND (was
  KADM5_GSS_ERROR) when given an open
ccache without credentials for ADMIN_SERVICE or CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{154}{
\Version{KADM5_API_VERSION_2}
\Reason{If the KRB5_KDC_PROFILE environment variable is set to a filename
that does not exist, init fails with ENOENT.}
\Conditions{RPC}
\Status{Implemented}
}

\section{ovsec_kadm_destroy}

\numtest{1}{
\Reason{Valid invocation.}
\Status{Implemented}
}

%\numtest{2}{
%\Reason{Valid invocation (``get'' not allowed after destroy).}
%\Status{Implemented}
%}

%\numtest{3}{
%\Reason{Valid invocation (``add'' not allowed after destroy).}
%\Status{Implemented}
%}

%\numtest{4}{
%\Reason{Valid invocation (``modify'' not allowed after destroy).}
%\Status{Implemented}
%}

%\numtest{5}{
%\Reason{Valid invocation (``delete'' not allowed after destroy).}
%\Status{Implemented}
%}

%\numtest{6}{
%\Reason{Fails if database not initialized.}
%\Status{Implemented}
%}

%\numtest{7}{
%\Reason{Fails if invoked twice in a row.}
%\Status{Implemented}
%}

\numtest{8}{
\Reason{Database can be reinitialized after destroy.}
\Status{Implemented}
}

\numtest{9}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{10}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{client}
}

\section{ovsec_kadm_create_principal}

%In the tests below, ``getu'' refers to a user who has only ``get'' access,
%''addu'' refers to a user who has only ``add'' access, ``modifyu'' refers to
%a user who has only ``modify'' access, and ``deleteu'' refers to a user
%who has only ``delete'' access. ``amu'' refers to a user with ``add'' and
%''modify'' access.  ``new_princ'' refers to a principal entry structure
%filled in as follows:
%
%	krb5_parse_name("newuser", \&new_princ.principal);
%	krb5_timeofday(\&new_princ.princ_expire_time);
%		new_princ.princ_expire_time += 130;
%	krb5_timeofday(\&new_princ.last_pwd_change);
%		new_princ.last_pwd_change += 140;
%	krb5_timeofday(\&new_princ.pw_expiration);
%		new_princ.pw_expiration += 150;
%	new_princ.max_life = 160;
%	krb5_parse_name("usera", \&new_princ.mod_name);
%	krb5_timeofday(\&new_princ.mod_date);
%		new_princ.mod_date += 170;
%	new_princ.attributes = 0xabcdabcd;
%	new_princ.kvno = 180;
%	new_princ.mkvno = 190;
%	new_princ.policy = null;
%	new_princ.aux_attributes = 0xdeadbeef;
%
%The offsets of 130 through 190 above are used to ensure that the
%fields are all known to be different from each other, so that
%accidentally switched fields can be detected.  Some of the fields in
%this structure may be changed by the tests, but they should clean up
%after themselves.

%\numtest{1}{
%\Reason{Fails if database not initialized.}
%\Status{Implemented}
%}

\numtest{2}{
\Reason{Fails on null princ argument.}
\Status{Implemented}
}

\numtest{3}{
\Reason{Fails on null password argument.}
\Status{Implemented}
}

\numtest{4}{
\Reason{Fails on empty-string password argument.}
\Status{Implemented}
}

\numtest{5}{
\Reason{Fails when mask contains undefined bit.}
\Status{Implemented}
}

\numtest{6}{
\Reason{Fails when mask contains LAST_PWD_CHANGE bit.}
\Status{Implemented}
}

\numtest{7}{
\Reason{Fails when mask contains MOD_TIME bit.}
\Status{Implemented}
}

\numtest{8}{
\Reason{Fails when mask contains MOD_NAME bit.}
\Status{Implemented}
}

\numtest{9}{
\Reason{Fails when mask contains MKVNO bit.}
\Status{Implemented}
}

\numtest{10}{
\Reason{Fails when mask contains AUX_ATTRIBUTES bit.}
\Status{Implemented}
}

\numtest{11}{
\Reason{Fails when mask contains POLICY_CLR bit.}
\Status{Implemented}
}

\numtest{12}{
\Reason{Fails for caller with no access bits.}
\Status{Implemented}
}

\numtest{13}{
\Reason{Fails when caller has ``get'' access and not ``add''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{14}{
\Reason{Fails when caller has ``modify'' access and not ``add''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{15}{
\Reason{Fails when caller has ``delete'' access and not ``add''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{16}{
\Reason{Fails when caller connected with CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{17}{
\Reason{Fails on attempt to create existing principal.}
\Status{Implemented}
}

\numtest{18}{
\Reason{Fails when password is too short.}
\Status{Implemented}
}

\numtest{19}{
\Reason{Fails when password has too few classes.}
\Status{Implemented}
}

\numtest{20}{
\Reason{Fails when password is in dictionary.}
\Status{Implemented}
}

\numtest{21}{
\Reason{Nonexistent policy is rejected.}
\Status{Implemented}
}

\numtest{22}{
\Reason{Fails on invalid principal name.}
\Status{Implemented}
}

\numtest{23}{
\Reason{Valid invocation.}
\Status{Implemented}
}

\numtest{24}{
\Reason{Succeeds when caller has ``add'' access and another one.}
\Status{Implemented}
}

%\numtest{25}{
%\Reason{Fails when password is too short, when override_qual is true.}
%}

%\numtest{26}{
%\Reason{Fails when password has too few classes, when
%		override_qual is true.}
%}

%\numtest{27}{
%\Reason{Fails when password is in dictionary, when override_qual is
%		true.}
%}

\numtest{28}{
\Reason{Succeeds when assigning policy.}
\Status{Implemented}
}

\numtest{29}{
\Priority{High}
\Reason{Allows 0 (never) for princ_expire_time.}
\Status{Implemented}
}

\numtest{30}{
\Reason{Allows 0 (never) for pw_expiration when there's no policy.}
\Status{Implemented}
}

\numtest{31}{
\Reason{Allows 0 (never) for pw_expiration when there's a policy with
	0 for pw_max_life.}
\Status{Implemented}
}

\numtest{32}{
\Reason{Accepts 0 (never) for pw_expiration when there's a policy with
	non-zero pw_max_life, and sets pw_expiration to zero.}
\Status{Implemented}	
}

\numtest{33}{
\Reason{Accepts and sets non-zero pw_expiration when no policy.}
\Status{Implemented}
}

\numtest{34}{
\Reason{Accepts and sets non-zero pw_expiration when there's a policy
	with zero pw_max_life.}
\Status{Implemented}	
}

\numtest{35}{
\Reason{Accepts and sets non-zero pw_expiration when there's a policy
	with pw_max_life later than the specified pw_expiration.}
\Status{Implemented}	
}

\numtest{36}{
\Reason{Accepts and sets non-zero pw_expiration greater than now_pw_max_life.}
\Status{Implemented}	
}

\numtest{37}{
\Priority{High}
\Reason{Sets pw_expiration to 0 (never) if there's no policy and no
	specified pw_expiration.}
\Status{Implemented}	
}

\numtest{38}{
\Priority{High}
\Reason{Sets pw_expiration to 0 (never) if it isn't specified and the
	policy has a 0 (never) pw_max_life.}
\Status{Implemented}	
}

\numtest{39}{
\Priority{High}
\Reason{Sets pw_expiration to now + pw_max_life if it isn't specified
	and the policy has a non-zero pw_max_life.}
\Status{Implemented}	
}

\numtest{40}{
\Priority{High}
\Reason{Allows 0 (forever) for max_life.}
\Status{Implemented}
}

\numtest{41}{
\Priority{High}
\Reason{Doesn't modify or free mod_name on success.}
}

\numtest{42}{
\Priority{High}
\Reason{Doesn't modify or free mod_name on failure.}
}

\numtest{43}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{44}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}


\section{ovsec_kadm_delete_principal}

%\numtest{1}{
%\Reason{Fails if database not initialized.}
%\Status{Implemented}
%}

\numtest{2}{
\Reason{Fails on null principal.}
\Status{Implemented}
}

% Empty string principal is legal.
%\numtest{3}{
%\Reason{Fails on empty-string principal.}
%}

% There is not invalid principal names
%\numtest{4}{
%\Reason{Fails on invalid principal name.}
%}

\numtest{5}{
\Priority{High}
\Reason{Fails on nonexistent principal.}
\Status{Implemented}
}

\numtest{6}{
\Priority{High}
\Reason{Fails when caller connected with CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{7}{
\Priority{High}
\Reason{Fails if caller has ``add'' access and not ``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{8}{
\Priority{High}
\Reason{Fails if caller has ``modify'' access and not ``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{9}{
\Priority{High}
\Reason{Fails if caller has ``get'' access and not ``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{10}{
\Priority{High}
\Reason{Fails if caller has no access bits.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{11}{
\Priority{High}
\Reason{Valid invocation.}
\Status{Implemented}
}

\numtest{12}{
\Priority{High}
\Reason{Valid invocation (on principal with policy).}
\Status{Implemented}
}

\numtest{13}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{14}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}


\section{ovsec_kadm_modify_principal}

%\numtest{1}{
%\Reason{Fails if database not initialized.}
%\Status{Implemented}
%}

\numtest{2}{
\Priority{High}
\Reason{Fails if user connected with CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{3}{
\Reason{Fails on mask with undefined bit set.}
\Status{Implemented}
}

\numtest{4}{
\Reason{Fails on mask with PRINCIPAL set.}
\Status{Implemented}
}

\numtest{5}{
\Priority{High}
\Reason{Fails on mask with LAST_PWD_CHANGE set.}
\Status{Implemented}
}

\numtest{6}{
\Reason{Fails on mask with MOD_TIME set.}
\Status{Implemented}
}

\numtest{7}{
\Reason{Fails on mask with MOD_NAME set.}
\Status{Implemented}
}

\numtest{8}{
\Reason{Fails on mask with MKVNO set.}
\Status{Implemented}
}

\numtest{9}{
\Priority{High}
\Reason{Fails on mask with AUX_ATTRIBUTES set.}
\Status{Implemented}
}

\numtest{10}{
\Reason{Fails on nonexistent principal.}
\Status{Implemented}
}

\numtest{11}{
\Priority{High}
\Reason{Fails for user with no access bits.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{12}{
\Priority{High}
\Reason{Fails for user with ``get'' access.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{13}{
\Priority{High}
\Reason{Fails for user with ``add'' access.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{14}{
\Priority{High}
\Reason{Fails for user with ``delete'' access.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{15}{
\Priority{High}
\Reason{Succeeds for user with ``modify'' access.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{16}{
\Reason{Succeeds for user with ``modify'' and another access.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{17}{
\Priority{High}
\Reason{Fails when nonexistent policy is specified.}
\Status{Implemented}
}

\numtest{18}{
\Priority{High}
\Reason{Succeeds when existent policy is specified.}
\Status{Implemented}
}

\numtest{19}{
\Reason{Updates policy count when setting policy from none.}
\Status{Implemented}
}

\numtest{20}{
\Reason{Updates policy count when clearing policy from set.}
\Status{Implemented}
}

\numtest{21}{
\Reason{Updates policy count when setting policy from other policy.}
\Status{Implemented}
}

\numtest{21.5}{
\Reason{Policy reference count remains unchanged when policy is
	changed to itself.}
\Status{Implemented.}
}

\numtest{22}{
\Reason{Allows 0 (never) for pw_expiration when there's no policy.}
\Status{Implemented}
}

\numtest{23}{
\Reason{Allows 0 (never) for pw_expiration when there's a policy with
	0 for pw_max_life.}
\Status{Implemented}
}

\numtest{24}{
\Reason{Accepts 0 (never) for pw_expiration when there's a policy with
	non-zero pw_max_life, but actually sets pw_expiration to
	last_pwd_change + pw_max_life.}
\Status{Implemented}
}

\numtest{25}{
\Reason{Accepts and sets non-zero pw_expiration when no policy.}
\Status{Implemented}
}

\numtest{26}{
\Reason{Accepts and sets non-zero pw_expiration when there's a policy
	with zero pw_max_life.}
\Status{Implemented}	
}

\numtest{27}{
\Reason{Accepts and sets non-zero pw_expiration when there's a policy
	with pw_max_life later than the specified pw_expiration.}
\Status{Implemented}	
}

\numtest{28}{
\Reason{Accepts non-zero pw_expiration and limits it to last_pwd_change +
	pw_max_life when it's later than last_pwd_change + non-zero
	pw_max_life in policy.}
\Status{Implemented}	
}

\numtest{29}{
\Priority{High}
\Reason{Sets pw_expiration to 0 (never) when a policy is cleared and
no pw_expiration is specified.}
\Status{Implemented}	
}

\numtest{30}{
\Priority{High}
\Reason{Sets pw_expiration to 0 (never) if it isn't specified and the
	new policy has a 0 (never) pw_max_life.}
\Status{Implemented}	
}

\numtest{31}{
\Priority{High}
\Reason{Sets pw_expiration to now + pw_max_life if it isn't specified
	and the new policy has a non-zero pw_max_life.}
\Status{Implemented}	
}

\numtest{32}{
\Priority{High}
\Reason{Accepts princ_expire_time change.}
\Status{Implemented}
}



\numtest{33}{
\Priority{High}
\Reason{Accepts attributes change.}
\Status{Implemented}
}

\numtest{33.25}{
\Priority{High}
\Reason{Accepts attributes change (KRB5_KDB_REQUIRES_PW_CHANGE).}
\Status{Implemented}
}

\numtest{33.5}{
\Priority{High}
\Reason{Accepts attributes change (KRB5_DISALLOW_TGT_BASE).}
\Status{Implemented}
}

\numtest{33.75}{
\Priority{High}
\Reason{Accepts attributes change (KRB5_PW_CHANGE_SERVICE).}
\Status{Implemented}
}

\numtest{34}{
\Priority{High}
\Reason{Accepts max_life change.}
\Status{Implemented}
}

\numtest{35}{
\Priority{High}
\Reason{Accepts kvno change.}
\Status{Implemented}
}

\numtest{36}{
\Reason{Behaves correctly when policy is set to the same as it was
	before.}
\Status{Implemented}	
}

\numtest{37}{
\Reason{Behaves properly when POLICY_CLR is specified and there was no
	policy before.}
\Status{Implemented}	
}

\numtest{38}{
\Priority{High}
\Reason{Accepts 0 (never) for princ_expire_time.}
\Status{Implemented}
}

\numtest{39}{
\Priority{High}
\Reason{Accepts 0 for max_life.}
\Status{Implemented}
}

\numtest{40}{
\Reason{Rejects null principal argument.}
\Status{Implemented}
}

\numtest{41}{
\Priority{High}
\Reason{Doesn't modify or free mod_name on success.}
}

\numtest{42}{
\Priority{High}
\Reason{Doesn't modify or free mod_name on failure.}
}

\numtest{43}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{44}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}

\numtest{100}{
\Version{KADM5_API_VERSION_2}
\Priority{bug-fix}
\Reason{Accepts max_rlife change.}
\Status{Implemented}
}

\numtest{101}{
\Version{KADM5_API_VERSION_2}
\Reason{Rejects last_success change.}
\Status{Implemented}
}

\numtest{102}{
\Version{KADM5_API_VERSION_2}
\Reason{Rejects last_failed change.}
\Status{Implemented}
}

\numtest{103}{
\Version{KADM5_API_VERSION_2}
\Reason{Rejects fail_auth_count change.}
\Status{Implemented}
}

\numtest{103.5}{
\Version{KADM5_API_VERSION_2}
\Reason{Rejects key_data change.}
\Status{Implemented}
}

\numtest{104}{
\Version{KADM5_API_VERSION_2}
\Reason{Accepts tl_data change when all types are greater than 256.}
\Status{Implemented}
}

\numtest{105}{
\Version{KADM5_API_VERSION_2}
\Reason{Returns KADM5_BAD_TL_TYPE when given tl_data with a type less
than 256.} 
\Status{Implemented}
}

\section{ovsec_kadm_rename_principal}

%\numtest{1}{
%\Reason{Fails if database not initialized.}
%\Status{Implemented}
%}

\numtest{2}{
\Priority{High}
\Reason{Fails if user connected with CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{3}{
\Priority{High}
\Reason{Fails for user with no access bits.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{4}{
\Reason{Fails for user with ``modify'' access and not ``add'' or
``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{5}{
\Reason{Fails for user with ``get'' access and not ``add'' or
``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{6}{
\Reason{Fails for user with ``modify'' and ``add'' but not ``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{7}{
\Reason{Fails for user with ``modify'' and ``delete'' but not ``add''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{8}{
\Reason{Fails for user with ``get'' and ``add'' but not ``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{9}{
\Reason{Fails for user with ``get'' and ``delete'' but not ``add.''}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{10}{
\Reason{Fails for user with ``modify'', ``get'' and ``add'', but not
	``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{11}{
\Reason{Fails for user with ``modify'', ``get'' and ``delete'', but
	not ``add''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{12}{
\Priority{High}
\Reason{Fails for user with ``add'' but not ``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{13}{
\Priority{High}
\Reason{Fails for user with ``delete'' but not ``add''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{14}{
\Priority{High}
\Reason{Succeeds for user with ``add'' and ``delete'', when that user
has non-name-based salt.}
\Status{Implemented}
}

\numtest{15}{
\Priority{High}
\Reason{Fails if target principal name exists.}
\Status{Implemented}
}

\numtest{16}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{17}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}

\numtest{18}{
\Priority{bug fix}
\Reason{Returns NO_RENAME_SALT when asked to rename a principal whose
salt depends on the principal name.}
\Status{Implemented}
}

\section{ovsec_kadm_chpass_principal}
\label{ovseckadmchpassprincipal}

\subsection{Quality/history enforcement tests}

This section lists a series of tests which will be run a number of
times, with various parameter settings (e.g., which access bits user
has, whether user connected with ADMIN_SERVICE or CHANGEPW_SERVICE,
etc.).  The table following the
list of tests gives the various parameter settings under which the
tests should be run, as well which should succeed and which should
fail for each choice of parameter settings.

\subsubsection{List of tests}

The test number of each of these tests is an offset from the base
given in the table below.

\numtest{1}{
\Priority{High}
\Reason{With history setting of 1, change password to itself.}
}

\numtest{2}{
\Reason{With history setting of 2 but no password changes since
	principal creation, change password to itself.}
}

\numtest{3}{
\Reason{With history setting of 2 and one password change since
	principal creation, change password to itself
	and directly previous password.}
}

\numtest{4}{
\Priority{High}
\Reason{With a history setting of 3 and no password changes,
	change password to itself.}
}

\numtest{5}{
\Priority{High}
\Reason{With a history setting of 3 and 1 password change,
	change password to itself or previous password.}
}

\numtest{6}{
\Priority{High}
\Reason{With a history setting of 3 and 2 password changes,
	change password to itself and the two previous passwords.}
}

\numtest{7}{
\Priority{High}
\Reason{Change to previously unused password when now -
	last_pwd_change $<$ pw_min_life.}
}

\numtest{8}{
\Priority{High}
\Reason{Change to previously unused password that doesn't contain enough
	character classes.}
}

\numtest{9}{
\Priority{High}
\Reason{Change to previously unused password that's too short.}
}

\numtest{10}{
\Priority{High}
\Reason{Change to previously unused password that's in the dictionary.}
}

\subsubsection{List of parameter settings}

In the table below, ``7 passes'' means that test 7 above passes and
the rest of the tests fail.

\begin{tabular}{llllll}
Base & Modify access? & Own password? & Service & Pass/Fail \\ \hline
0 & No & Yes & ADMIN & all fail \\
20 & No & Yes & CHANGEPW & all fail \\
40 & No & No & ADMIN & all fail \\
60 & No & No & CHANGEPW & all fail \\
80 & Yes & Yes & ADMIN & 7 passes \\
100 & Yes & Yes & CHANGEPW & all fail \\
120 & Yes & No & ADMIN & 7 passes \\
140 & Yes & No & CHANGEPW & all fail \\
\end{tabular}

\subsection{Other quality/history tests}

\numtest{161}{
\Priority{High}
\Reason{With history of 1, can change password to anything other than
	itself that doesn't conflict with other quality
	rules.}
}

\numtest{162}{
\Reason{With history of 2 and 2 password changes, can change password
	to original password.}
}

\numtest{163}{
\Priority{High}
\Reason{With history of 3 and 3 password changes, can change password
	to original password.}
}

\numtest{164}{
\Priority{High}
\Reason{Can change password when now - last_pwd_change $>$ pw_min_life.}
}

\numtest{165}{
\Priority{High}
\Reason{Can change password when it contains exactly the number of
	classes required by the policy.}
}

\numtest{166}{
\Priority{High}
\Reason{Can change password when it is exactly the length required by
	the policy.}
}

\numtest{167}{
\Priority{High}
\Reason{Can change password to a word that isn't in the dictionary.}
}


\subsection{Other tests}

%\numtest{168}{
%\Reason{Fails if database not initialized.}
%}

\numtest{169}{
\Reason{Fails for non-existent principal.}
}

\numtest{170}{
\Reason{Fails for null password.}
}

\numtest{171}{
\Priority{High}
\Reason{Fails for empty-string password.}
}

\numtest{172}{
\Priority{High}
\Reason{Pw_expiration is set to now + max_pw_life if policy exists and
	has non-zero max_pw_life.}
}

\numtest{173}{
\Priority{High}
\Reason{Pw_expiration is set to 0 if policy exists and has zero
	max_pw_life.}
}

\numtest{174}{
\Priority{High}
\Reason{Pw_expiration is set to 0 if no policy.}
}

\numtest{175}{
\Priority{High}
\Reason{KRB5_KDC_REQUIRES_PWCHANGE bit is cleared when password is
	successfully changed.}
}

\numtest{176}{
\Priority{High}
\Reason{Fails for user with no access bits, on other's password.}
}

\numtest{177}{
\Priority{High}
\Reason{Fails for user with ``get'' but not ``modify'' access, on
	other's password.}
}

\numtest{178}{
\Reason{Fails for user with ``delete'' but not ``modify'' access, on
	other's password.}
}

\numtest{179}{
\Reason{Fails for user with ``add'' but not ``modify'' access, on
	other's password.}
}

\numtest{180}{
\Reason{Succeeds for user with ``get'' and ``modify'' access, on
	other's password.}
\Status{Implemented}	
}

\numtest{180.5}{
\Priority{High}
\Reason{Succeeds for user with ``modify'' but not ``get'' access, on
	other's password.}
\Conditions{RPC}
\Status{Implemented}	
}
\numtest{180.625}{
\Priority{High}
\Reason{Fails for user with modify when connecting with CHANGEPW_SERVICE on
	others password}
\Conditions{RPC}
\Status{Implemented}
}
\numtest{180.75}{
\Priority{High}
\Reason{Fails for user with modify when connecting with CHANGEPW_SERVICE
	on other's password which has expired}
\Conditions{RPC}
\Status{Implemented}
}

%\numtest{181}{
%\Reason{Password that would succeed if override_qual were false fails
%	if override_qual is true.}
%\Expected{Returns CANNOT_OVERRIDE.}
%}

\numtest{182}{
\Priority{High}
\Reason{Can not change key of ovsec_adm/history principal.}
\Status{Implemented}
}

\numtest{183}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{184}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}

\numtest{200}{
\Version{KADM5_API_VERSION_2}
\Reason{Creates a key for the principal for each unique encryption
type/salt type in use.}
\Status{Implemented}
}

\section{ovsec_kadm_chpass_principal_util}

Rerun all the tests listed for ovsec_kadm_chpass_principal above in
Section \ref{ovseckadmchpassprincipal}.  Verify that they succeed
and fail in the same circumstances.  Also verify that in each failure
case, the error message returned in msg_ret is as specified in the
functional specification.

Also, run the following additional tests.

\numtest{1}{
\Reason{Null msg_ret is rejected.}
}

\numtest{2}{
\Priority{High}
\Reason{New password is put into pw_ret, when it's prompted for.}
}

\numtest{3}{
\Priority{High}
Reason{New password is put into pw_ret, when it's supplied by the
	caller.}
}

\numtest{4}{
\Priority{High}
\Reason{Successful invocation when pw_ret is null.}
}



\section{ovsec_kadm_randkey_principal}

\subsection{TOOSOON enforcement tests}

This test should be run a number of times, as indicated in the table
following it.  The table also indicates the expected result of each
run of the test.

\test{
\Reason{Change key when now - last_pwd_change $<$ pw_min_life.}
}

\subsubsection{List of parameter settings}

\begin{tabular}{llllll}
Number & Modify Access? & Own Key? & Service & Pass/Fail & Implemented? \\ \hline
1 & No & Yes & ADMIN & fail & Yes \\
3 & No & Yes & CHANGEPW & fail & Yes \\
5 & No & No & ADMIN & fail \\
7 & No & No & CHANGEPW & fail \\
9 & Yes & Yes & ADMIN & pass \\
11 & Yes & Yes & CHANGEPW & fail \\
13 & Yes & No & ADMIN & pass & Yes \\
15 & Yes & No & CHANGEPW & fail & Yes \\
\end{tabular}

\subsection{Other tests}

\numtest{17}{
\Reason{Fails if database not initialized.}
}

\numtest{18}{
\Reason{Fails for non-existent principal.}
}

\numtest{19}{
\Reason{Fails for null keyblock pointer.}
}

\numtest{20}{
\Priority{High}
\Reason{Pw_expiration is set to now + max_pw_life if policy exists and
	has non-zero max_pw_life.}
}

\numtest{21}{
\Priority{High}
\Reason{Pw_expiration is set to 0 if policy exists and has zero
	max_pw_life.}
}

\numtest{22}{
\Priority{High}
\Reason{Pw_expiration is set to 0 if no policy.}
}

\numtest{23}{
\Priority{High}
\Reason{KRB5_KDC_REQUIRES_PWCHANGE bit is cleared when key is
	successfully changed.}
}

\numtest{24}{
\Priority{High}
\Reason{Fails for user with no access bits, on other's password.}
}

\numtest{25}{
\Priority{High}
\Reason{Fails for user with ``get'' but not ``modify'' access, on
	other's password.}
\Vtwonote{Change-password instead of modify access.}
}

\numtest{26}{
\Reason{Fails for user with ``delete'' but not ``modify'' access, on
	other's password.}
\Vtwonote{Change-password instead of modify access.}
}

\numtest{27}{
\Reason{Fails for user with ``add'' but not ``modify'' access, on
	other's password.}
\Vtwonote{Change-password instead of modify access.}
}

\numtest{28}{
\Reason{Succeeds for user with ``get'' and ``modify'' access, on
	other's password.}
\Status{Implemented}
\Vtwonote{Change-password instead of modify access.}
}

\numtest{28.25}{
\Priority{High}
\Reason{Fails for user with get and modify access on others password
	When conneceted with CHANGEPW_SERVICE}
\Status{Implemented}
\Vtwonote{Change-password instead of modify access.}
}

\numtest{28.5}{
\Priority{High}
\Reason{Succeeds for user with ``modify'' but not ``get'' access, on
	other's password.}
\Status{Implemented}
\Vtwonote{Change-password instead of modify access.}
}

\numtest{29}{
\Reason{The new key that's assigned is truly random. XXX not sure how
	to test this.}
}

\numtest{30}{
\Reason{Succeeds for own key, no other access bits when connecting with CHANGEPW service}
\Status{Implemented}
}
\numtest{31}{
\Reason{Succeeds for own key, no other access bits when connecting with ADMIM service}
\Status{Implemented}
}

\numtest{32}{
\Reason{Cannot change ovsec_adm/history key}
\Status{Implemented}
}

\numtest{33}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{34}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}

\numtest{100}{
\Version{KADM5_API_VERSION_2}
\Reason{Returns a key for each unique encryption type specified in the
keysalts.}
}

\section{ovsec_kadm_get_principal}

\numtest{1}{
\Reason{Fails for null ent.}
\Status{Implemented}
}

\numtest{2}{
\Reason{Fails for non-existent principal.}
\Status{Implemented}
}

\numtest{3}{
\Priority{High}
\Reason{Fails for user with no access bits, retrieving other principal.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{4}{
\Priority{High}
\Reason{Fails for user with ``add'' but not ``get'', getting principal
	other than his own, using ADMIN_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{5}{
\Reason{Fails for user with ``modify'' but not ``get'', getting
	principal other than his own, using ADMIN_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{6}{
\Reason{Fails for user with ``delete'' but not ``get'', getting
	principal other than his own, using ADMIN_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{7}{
\Reason{Fails for user with ``delete'' but not ``get'', getting
	principal other than his own, using CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{8}{
\Priority{High}
\Reason{Fails for user with ``get'', getting principal other than his
	own, using CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{9}{
\Priority{High}
\Reason{Succeeds for user without ``get'', retrieving self, using
	ADMIN_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{10}{
\Reason{Succeeds for user without ``get'', retrieving self, using
	CHANGEPW_SERVICE.}
\Status{Implemented}	
}

\numtest{11}{
\Reason{Succeeds for user with ``get'', retrieving self, using
	ADMIN_SERVICE.}
\Status{Implemented}		
}

\numtest{12}{
\Reason{Succeeds for user with ``get'', retrieving self, using
	CHANGEPW_SERVICE.}
\Status{Implemented}		
}

\numtest{13}{
\Priority{High}
\Reason{Succeeds for user with ``get'', retrieving other user, using
	ADMIN_SERVICE.}
\Status{Implemented}		
}

\numtest{14}{
\Reason{Succeeds for user with ``get'' and ``modify'', retrieving
	other principal, using ADMIN_SERVICE.}
\Status{Implemented}		
}

\numtest{15}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{16}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}

\numtest{100}{
\Version{KADM5_API_VERSION_2}
\Reason{If KADM5_PRINCIPAL_NORMAL_MASK is specified, the key_data and
tl_data fields are NULL/zero.}
\Status{Implemented}
}

\numtest{101}{
\Version{KADM5_API_VERSION_2}
\Reason{If KADM5_KEY_DATA is specified, the key_data fields contain
data but the contents are all NULL.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{102}{
\Version{KADM5_API_VERSION_2}
\Reason{If KADM5_KEY_DATA is specified, the key_data fields contain
data and the contents are all non-NULL.}
\Conditions{local}
\Status{Implemented}
}

\numtest{103}{
\Version{KADM5_API_VERSION_2}
\Reason{If KADM5_TL_DATA is specified, the tl_data field contains the
correct tl_data and no entries whose type is less than 256.}
\Status{Implemented}
}


\section{ovsec_kadm_create_policy}

\numtest{1}{
\Reason{Fails for mask with undefined bit set.}
\Status{Implemented - untested}
}

\numtest{2}{
\Priority{High}
\Reason{Fails if caller connected with CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{3}{
\Reason{Fails for mask without POLICY bit set.}
\Status{Implemented - untested}
}

\numtest{4}{
\Reason{Fails for mask with REF_COUNT bit set.}
\Status{Implemented}
}

\numtest{5}{
\Reason{Fails for invalid policy name.}
\Status{Implemented - untested}
}

\numtest{6}{
\Priority{High}
\Reason{Fails for existing policy name.}
\Status{Implemented}
}

\numtest{7}{
\Reason{Fails for null policy name.}
\Status{Implemented - untested}
}

\numtest{8}{
\Priority{High}
\Reason{Fails for empty-string policy name.}
\Status{Implemented}
}

\numtest{9}{
\Priority{High}
\Reason{Accepts 0 for pw_min_life.}
\Status{Implemented}
}

\numtest{10}{
\Priority{High}
\Reason{Accepts non-zero for pw_min_life.}
\Status{Implemented}
}

\numtest{11}{
\Priority{High}
\Reason{Accepts 0 for pw_max_life.}
\Status{Implemented}
}

\numtest{12}{
\Priority{High}
\Reason{Accepts non-zero for pw_max_life.}
\Status{Implemented}
}

\numtest{13}{
\Priority{High}
\Reason{Rejects 0 for pw_min_length.}
\Status{Implemented}
}

\numtest{14}{
\Priority{High}
\Reason{Accepts non-zero for pw_min_length.}
\Status{Implemented}
}

\numtest{15}{
\Priority{High}
\Reason{Rejects 0 for pw_min_classes.}
\Status{Implemented}
}

\numtest{16}{
\Priority{High}
\Reason{Accepts 1 for pw_min_classes.}
\Status{Implemented}
}

\numtest{17}{
\Priority{High}
\Reason{Accepts 4 for pw_min_classes.}
\Status{Implemented}
}

\numtest{18}{
\Priority{High}
\Reason{Rejects 5 for pw_min_classes.}
\Status{Implemented}
}

\numtest{19}{
\Priority{High}
\Reason{Rejects 0 for pw_history_num.}
\Status{Implemented}
}

\numtest{20}{
\Priority{High}
\Reason{Accepts 1 for pw_history_num.}
\Status{Implemented}
}

\numtest{21}{
\Priority{High}
\Reason{Accepts 10 for pw_history_num.}
\Status{Implemented}
}

\numtest{21.5}{
\Reason{Rejects 11 for pw_history_num.}
\Status{Implemented - untested}
}

\numtest{22}{
\Priority{High}
\Reason{Fails for user with no access bits.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{23}{
\Priority{High}
\Reason{Fails for user with ``get'' but not ``add''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{24}{
\Reason{Fails for user with ``modify'' but not ``add.''}
\Conditions{RPC}
\Status{Implemented - untested}
}

\numtest{25}{
\Reason{Fails for user with ``delete'' but not ``add.''}
\Conditions{RPC}
\Status{Implemented - untested}
}

\numtest{26}{
\Priority{High}
\Reason{Succeeds for user with ``add.''}
\Status{Implemented}
}

\numtest{27}{
\Reason{Succeeds for user with ``get'' and ``add.''}
\Status{Implemented - untested}
}

\numtest{28}{
\Reason{Rejects null policy argument.}
\Status{Implemented - untested}
}

\numtest{29}{
\Reason{Rejects pw_min_life greater than pw_max_life.}
}

\numtest{30}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{31}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}


\section{ovsec_kadm_delete_policy}

\numtest{1}{
\Reason{Fails for null policy name.}
}

\numtest{2}{
\Priority{High}
\Reason{Fails for empty-string policy name.}
\Status{Implemented}
}

\numtest{3}{
\Reason{Fails for non-existent policy name.}
}

\numtest{4}{
\Reason{Fails for bad policy name.}
}

\numtest{5}{
\Priority{High}
\Reason{Fails if caller connected with CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{6}{
\Priority{High}
\Reason{Fails for user with no access bits.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{7}{
\Priority{High}
\Reason{Fails for user with ``add'' but not ``delete''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{8}{
\Reason{Fails for user with ``modify'' but not ``delete''.}
\Conditions{RPC}
}

\numtest{9}{
\Reason{Fails for user with ``get'' but not ``delete.''}
\Conditions{RPC}
}

\numtest{10}{
\Priority{High}
\Reason{Succeeds for user with only ``delete''.}
\Status{Implemented}
}

\numtest{11}{
\Reason{Succeeds for user with ``delete'' and ``add''.}
}

\numtest{12}{
\Priority{High}
\Reason{Fails for policy with non-zero reference count.}
\Status{Implemented}
}

\numtest{13}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{14}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}


\section{ovsec_kadm_modify_policy}

\numtest{1}{
\Reason{Fails for mask with undefined bit set.}
\Conditions{RPC}
}

\numtest{2}{
\Priority{High}
\Reason{Fails if caller connected with CHANGEPW_SERVICE.}
\Status{Implemented}
}

\numtest{3}{
\Reason{Fails for mask with POLICY bit set.}
}

\numtest{4}{
\Reason{Fails for mask with REF_COUNT bit set.}
\Status{Implemented}
}

\numtest{5}{
\Reason{Fails for invalid policy name.}
}

\numtest{6}{
\Reason{Fails for non-existent policy name.}
}

\numtest{7}{
\Reason{Fails for null policy name.}
}

\numtest{8}{
\Priority{High}
\Reason{Fails for empty-string policy name.}
\Status{Implemented}
}

\numtest{9}{
\Priority{High}
\Reason{Accepts 0 for pw_min_life.}
\Status{Implemented}
}

\numtest{10}{
\Priority{High}
\Reason{Accepts non-zero for pw_min_life.}
\Status{Implemented}
}

\numtest{11}{
\Priority{High}
\Reason{Accepts 0 for pw_max_life.}
\Status{Implemented}
}

\numtest{12}{
\Priority{High}
\Reason{Accepts non-zero for pw_max_life.}
\Status{Implemented}
}

\numtest{13}{
\Priority{High}
\Reason{Accepts 0 for pw_min_length.}
\Status{Implemented}
}

\numtest{14}{
\Priority{High}
\Reason{Accepts non-zero for pw_min_length.}
\Status{Implemented}
}

\numtest{15}{
\Priority{High}
\Reason{Rejects 0 for pw_min_classes.}
\Status{Implemented}
}

\numtest{16}{
\Priority{High}
\Reason{Accepts 1 for pw_min_classes.}
\Status{Implemented}
}

\numtest{17}{
\Priority{High}
\Reason{Accepts 4 for pw_min_classes.}
\Status{Implemented}
}

\numtest{18}{
\Priority{High}
\Reason{Rejects 5 for pw_min_classes.}
\Status{Implemented}
}

\numtest{19}{
\Priority{High}
\Reason{Rejects 0 for pw_history_num.}
\Status{Implemented}
}

\numtest{20}{
\Priority{High}
\Reason{Accepts 1 for pw_history_num.}
\Status{Implemented}
}

\numtest{21}{
\Priority{High}
\Reason{Accepts 10 for pw_history_num.}
\Status{Implemented}
}

\numtest{22}{
\Priority{High}
\Reason{Fails for user with no access bits.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{23}{
\Priority{High}
\Reason{Fails for user with ``get'' but not ``modify''.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{24}{
\Reason{Fails for user with ``add'' but not ``modify.''}
\Conditions{RPC}
}

\numtest{25}{
\Reason{Fails for user with ``delete'' but not ``modify.''}
\Conditions{RPC}
}

\numtest{26}{
\Priority{High}
\Reason{Succeeds for user with ``modify.''}
\Status{Implemented}
}

\numtest{27}{
\Reason{Succeeds for user with ``get'' and ``modify.''}
}

\numtest{28}{
\Reason{Rejects null policy argument.}
}

\numtest{29}{
\Reason{Rejects change which makes pw_min_life greater than
	pw_max_life.}
}

\numtest{30}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{31}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}

\section{ovsec_kadm_get_policy}

\numtest{1}{
\Reason{Fails for null policy.}
}

\numtest{2}{
\Reason{Fails for invalid policy name.}
}

\numtest{3}{
\Priority{High}
\Reason{Fails for empty-string policy name.}
\Status{Implemented}
}

\numtest{4}{
\Reason{Fails for non-existent policy name.}
}

\numtest{5}{
\Reason{Fails for null ent.}
}

\numtest{6}{
\Priority{High}
\Reason{Fails for user with no access bits trying to get other's
	policy, using ADMIN_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{7}{
\Priority{High}
\Reason{Fails for user with ``add'' but not ``get'' trying to get
	other's policy, using ADMIN_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{8}{
\Reason{Fails for user with ``modify'' but not ``get'' trying to get
	other's policy, using ADMIN_SERVICE.}
\Conditions{RPC}	
}

\numtest{9}{
\Reason{Fails for user with ``delete'' but not ``get'' trying to get
	other's policy, using ADMIN_SERVICE.}
\Conditions{RPC}	
}

\numtest{10}{
\Reason{Fails for user with ``delete'' but not ``get'' trying to get
	other's policy, using CHANGEPW_SERVICE.}
\Conditions{RPC}	
}

\numtest{11}{
\Priority{High}
\Reason{Succeeds for user with only ``get'', trying to get own policy,
	using ADMIN_SERVICE.}
\Status{Implemented}
}

\numtest{12}{
\Priority{High}
\Reason{Succeeds for user with only ``get'', trying to get own policy,
	using CHANGEPW_SERVICE.}
\Status{Implemented}	
}

\numtest{13}{
\Reason{Succeeds for user with ``add'' and ``get'', trying to get own
	policy, using ADMIN_SERVICE.}
}

\numtest{14}{
\Reason{Succeeds for user with ``add'' and ``get'', trying to get own
	policy, using CHANGEPW_SERVICE.}
}

\numtest{15}{
\Reason{Succeeds for user without ``get'', trying to get own policy,
	using ADMIN_SERVICE.}
}

\numtest{16}{
\Priority{High}
\Reason{Succeeds for user without ``get'', trying to get own policy,
	using CHANGEPW_SERVICE.}
\Status{Implemented}	
}

\numtest{17}{
\Priority{High}
\Reason{Succeeds for user with ``get'', trying to get other's policy,
	using ADMIN_SERVICE.}
\Status{Implemented}	
}

\numtest{18}{
\Priority{High}
\Reason{Fails for user with ``get'', trying to get other's policy,
	using CHANGEPW_SERVICE.}
\Conditions{RPC}
\Status{Implemented}
}

\numtest{19}{
\Reason{Succeeds for user with ``modify'' and ``get'', trying to get
	other's policy, using ADMIN_SERVICE.}
}

\numtest{20}{
\Reason{Fails for user with ``modify'' and ``get'', trying to get
	other's policy, using CHANGEPW_SERVICE.}
}

\numtest{21}{
\Priority{High}
\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in}
\Status{Implemented}
}

\numtest{22}{
\Priority{Low}
\Reason{Connects to correct server when mutliple handles exist}
\Conditions{RPC}
}


\section{ovsec_kadm_free_principal_ent}

In addition to the tests listed here, a memory-leak detector such as
TestCenter, Purify or dbmalloc should be used to verify that the
memory freed by this function is really freed.

\numtest{1}{
\Reason{Null princ succeeds.}
}

\numtest{2}{
\Reason{Non-null princ succeeds.}
}


\section{ovsec_kadm_free_policy_ent}

In addition to the tests listed here, a memory-leak detector such as
TestCenter, Purify or dbmalloc should be used to verify that the
memory freed by this function is really freed.

\numtest{1}{
\Reason{Null policy succeeds.}
}

\numtest{2}{
\Reason{Non-null policy succeeds.}
}



\section{ovsec_kadm_get_privs}

\numtest{1}{
\Reason{Fails for null pointer argument.}
}

This test should be run with the 16 possible combinations of access
bits (since there are 4 access bits, there are $2^4 = 16$ possible
combinations of them):

\numtest{2}{
\Priority{High}
\Reason{Returns correct bit mask for access bits of user.}
\Conditions{RPC}
}

This test should be run locally:

\numtest{3}{
\Priority{High}
\Reason{Returns 0x0f.}
\Conditions{local}
}

\end{document}
