Blame src/util/k5test.py

Packit fd8b60
# Copyright (C) 2010 by the Massachusetts Institute of Technology.
Packit fd8b60
# All rights reserved.
Packit fd8b60
Packit fd8b60
# Export of this software from the United States of America may
Packit fd8b60
#   require a specific license from the United States Government.
Packit fd8b60
#   It is the responsibility of any person or organization contemplating
Packit fd8b60
#   export to obtain such a license before exporting.
Packit fd8b60
#
Packit fd8b60
# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit fd8b60
# distribute this software and its documentation for any purpose and
Packit fd8b60
# without fee is hereby granted, provided that the above copyright
Packit fd8b60
# notice appear in all copies and that both that copyright notice and
Packit fd8b60
# this permission notice appear in supporting documentation, and that
Packit fd8b60
# the name of M.I.T. not be used in advertising or publicity pertaining
Packit fd8b60
# to distribution of the software without specific, written prior
Packit fd8b60
# permission.  Furthermore if you modify this software you must label
Packit fd8b60
# your software as modified software and not distribute it in such a
Packit fd8b60
# fashion that it might be confused with the original M.I.T. software.
Packit fd8b60
# M.I.T. makes no representations about the suitability of
Packit fd8b60
# this software for any purpose.  It is provided "as is" without express
Packit fd8b60
# or implied warranty.
Packit fd8b60
Packit fd8b60
"""A module for krb5 test scripts
Packit fd8b60
Packit fd8b60
To run test scripts during "make check" (if Python 2.5 or later is
Packit fd8b60
available), add rules like the following to Makefile.in:
Packit fd8b60
Packit fd8b60
    check-pytests::
Packit fd8b60
	$(RUNPYTEST) $(srcdir)/t_testname.py $(PYTESTFLAGS)
Packit fd8b60
Packit fd8b60
A sample test script:
Packit fd8b60
Packit fd8b60
    from k5test import *
Packit fd8b60
Packit fd8b60
    # Run a test program under a variety of configurations:
Packit fd8b60
    for realm in multipass_realms():
Packit fd8b60
        realm.run(['./testprog', 'arg'])
Packit fd8b60
Packit fd8b60
    # Run a test server and client under just the default configuration:
Packit fd8b60
    realm = K5Realm()
Packit fd8b60
    realm.start_server(['./serverprog'], 'starting...')
Packit fd8b60
    realm.run(['./clientprog', realm.host_princ])
Packit fd8b60
Packit fd8b60
    # Inform framework that tests completed successfully.
Packit fd8b60
    success('World peace and cure for cancer')
Packit fd8b60
Packit fd8b60
By default, the realm will have:
Packit fd8b60
Packit fd8b60
* The name KRBTEST.COM
Packit fd8b60
* Listener ports starting at 61000
Packit fd8b60
* krb5.conf and kdc.conf files
Packit fd8b60
* A fresh DB2 KDB
Packit fd8b60
* Running krb5kdc (but not kadmind)
Packit fd8b60
* Principals named realm.user_princ and realm.admin_princ; call
Packit fd8b60
  password('user') and password('admin') to get the password
Packit fd8b60
* Credentials for realm.user_princ in realm.ccache
Packit fd8b60
* Admin rights for realm.admin_princ in the kadmind acl file
Packit fd8b60
* A host principal named realm.host_princ with a random key
Packit fd8b60
* A keytab for the host principal in realm.keytab
Packit fd8b60
Packit fd8b60
The realm's behaviour can be modified with the following constructor
Packit fd8b60
keyword arguments:
Packit fd8b60
Packit fd8b60
* realm='realmname': Override the realm name
Packit fd8b60
Packit fd8b60
* portbase=NNN: Override the listener port base; currently three ports are
Packit fd8b60
  used
Packit fd8b60
Packit fd8b60
* testdir='dirname': Override the storage area for the realm's files
Packit fd8b60
  (path may be specified relative to the current working dir)
Packit fd8b60
Packit fd8b60
* krb5_conf={ ... }: krb5.conf options, expressed as a nested
Packit fd8b60
  dictionary, to be merged with the default krb5.conf settings.  A key
Packit fd8b60
  may be mapped to None to delete a setting from the defaults.  A key
Packit fd8b60
  may be mapped to a list in order to create multiple settings for the
Packit fd8b60
  same variable name.  Keys and values undergo the following template
Packit fd8b60
  substitutions:
Packit fd8b60
Packit fd8b60
    - $realm:    The realm name
Packit fd8b60
    - $testdir:  The realm storage directory (absolute path)
Packit fd8b60
    - $buildtop: The root of the build directory
Packit fd8b60
    - $srctop:   The root of the source directory
Packit fd8b60
    - $plugins:  The plugin directory in the build tree
Packit fd8b60
    - $hostname: The FQDN of the host
Packit fd8b60
    - $port0:    The first listener port (portbase)
Packit fd8b60
    - ...
Packit fd8b60
    - $port9:    The tenth listener port (portbase + 9)
Packit fd8b60
Packit fd8b60
  When choosing ports, note the following:
Packit fd8b60
Packit fd8b60
    - port0 is used in the default krb5.conf for the KDC
Packit fd8b60
    - port1 is used in the default krb5.conf for kadmind
Packit fd8b60
    - port2 is used in the default krb5.conf for kpasswd
Packit fd8b60
    - port3 is used in the default krb5.conf for kpropd
Packit fd8b60
    - port4 is used in the default krb5.conf for iprop (in kadmind)
Packit fd8b60
    - port5 is the return value of realm.server_port()
Packit fd8b60
Packit fd8b60
* kdc_conf={...}: kdc.conf options, expressed as a nested dictionary,
Packit fd8b60
  to be merged with the default kdc.conf settings.  The same
Packit fd8b60
  conventions and substitutions for krb5_conf apply.
Packit fd8b60
Packit fd8b60
* create_kdb=False: Don't create a KDB.  Implicitly disables all of
Packit fd8b60
  the other options since they all require a KDB.
Packit fd8b60
Packit fd8b60
* krbtgt_keysalt='enctype:salttype': After creating the KDB,
Packit fd8b60
  regenerate the krbtgt key using the specified key/salt combination,
Packit fd8b60
  using a kadmin.local cpw query.
Packit fd8b60
Packit fd8b60
* create_user=False: Don't create the user principal.  Implies
Packit fd8b60
  get_creds=False.
Packit fd8b60
Packit fd8b60
* create_host=False: Don't create the host principal or the associated
Packit fd8b60
  keytab.
Packit fd8b60
Packit fd8b60
* start_kdc=False: Don't start the KDC.  Implies get_creds=False.
Packit fd8b60
Packit fd8b60
* start_kadmind=True: Start kadmind.
Packit fd8b60
Packit fd8b60
* get_creds=False: Don't get user credentials.
Packit fd8b60
Packit fd8b60
* bdb_only=True: Use the DB2 KDB module even if K5TEST_LMDB is set in
Packit fd8b60
  the environment.
Packit fd8b60
Packit fd8b60
Scripts may use the following functions and variables:
Packit fd8b60
Packit fd8b60
* fail(message): Display message (plus leading marker and trailing
Packit fd8b60
  newline) and explanatory messages about debugging.
Packit fd8b60
Packit fd8b60
* success(message): Indicate that the test script has completed
Packit fd8b60
  successfully.  Suppresses the display of explanatory debugging
Packit fd8b60
  messages in the on-exit handler.  message should briefly summarize
Packit fd8b60
  the operations tested; it will only be displayed (with leading
Packit fd8b60
  marker and trailing newline) if the script is running verbosely.
Packit fd8b60
Packit fd8b60
* skipped(whatmsg, whymsg): Indicate that some tests were skipped.
Packit fd8b60
  whatmsg should concisely say what was skipped (e.g. "LDAP KDB
Packit fd8b60
  tests") and whymsg should give the reason (e.g. "because LDAP module
Packit fd8b60
  not built").
Packit fd8b60
Packit fd8b60
* skip_rest(message): Indicate that some tests were skipped, then exit
Packit fd8b60
  the current script.
Packit fd8b60
Packit fd8b60
* output(message, force_verbose=False): Place message (without any
Packit fd8b60
  added newline) in testlog, and write it to stdout if running
Packit fd8b60
  verbosely.
Packit fd8b60
Packit fd8b60
* mark(message): Place a divider message in the test output, to make
Packit fd8b60
  it easier to determine what part of the test script a command
Packit fd8b60
  invocation belongs to.  The last mark message will also be displayed
Packit fd8b60
  if a command invocation fails.  Do not include a newline in message.
Packit fd8b60
Packit fd8b60
* which(progname): Return the location of progname in the executable
Packit fd8b60
  path, or None if it is not found.
Packit fd8b60
Packit fd8b60
* password(name): Return a weakly random password based on name.  The
Packit fd8b60
  password will be consistent across calls with the same name.
Packit fd8b60
Packit fd8b60
* stop_daemon(proc): Stop a daemon process started with
Packit fd8b60
  realm.start_server() or realm.start_in_inetd().  Only necessary if
Packit fd8b60
  the port needs to be reused; daemon processes will be stopped
Packit fd8b60
  automatically when the script exits.
Packit fd8b60
Packit fd8b60
* multipass_realms(**keywords): This is an iterator function.  Yields
Packit fd8b60
  a realm for each of the standard test passes, each of which alters
Packit fd8b60
  the default configuration in some way to exercise different parts of
Packit fd8b60
  the krb5 code base.  keywords may contain any K5Realm initializer
Packit fd8b60
  keyword with the exception of krbtgt_keysalt, which will not be
Packit fd8b60
  honored.  If keywords contains krb5_conf and/or kdc_conf fragments,
Packit fd8b60
  they will be merged with the default and per-pass specifications.
Packit fd8b60
Packit fd8b60
* multidb_realms(**keywords): Yields a realm for multiple DB modules.
Packit fd8b60
  Currently DB2 and LMDB are included.  Ideally LDAP would be
Packit fd8b60
  included, but setting up a test LDAP server currently requires a
Packit fd8b60
  one-second delay, so all LDAP tests are currently confined to
Packit fd8b60
  t_kdb.py.  keywords may contain any K5Realm initializer.
Packit fd8b60
Packit fd8b60
* cross_realms(num, xtgts=None, args=None, **keywords): This function
Packit fd8b60
  returns a list of num realms, where each realm's configuration knows
Packit fd8b60
  how to contact all of the realms.  By default, each realm will
Packit fd8b60
  contain cross TGTs in both directions for all other realms; this
Packit fd8b60
  default may be overridden by specifying a collection of tuples in
Packit fd8b60
  the xtgts parameter, where each tuple is a pair of zero-based realm
Packit fd8b60
  indexes, indicating that the first realm can authenticate to the
Packit fd8b60
  second (i.e. krbtgt/secondrealm@firstrealm exists in both realm's
Packit fd8b60
  databases).  If args is given, it should be a list of keyword
Packit fd8b60
  arguments specific to each realm; these will be merged with the
Packit fd8b60
  global keyword arguments passed to cross_realms, with specific
Packit fd8b60
  arguments taking priority.
Packit fd8b60
Packit fd8b60
* buildtop: The top of the build directory (absolute path).
Packit fd8b60
Packit fd8b60
* srctop: The top of the source directory (absolute path).
Packit fd8b60
Packit fd8b60
* plugins: The plugin directory in the build tree (absolute path).
Packit fd8b60
Packit fd8b60
* hostname: This machine's fully-qualified domain name.
Packit fd8b60
Packit fd8b60
* null_input: A file opened to read /dev/null.
Packit fd8b60
Packit fd8b60
* args: Positional arguments left over after flags are processed.
Packit fd8b60
Packit fd8b60
* runenv: The contents of $srctop/runenv.py, containing a dictionary
Packit fd8b60
  'env' which specifies additional variables to be added to the realm
Packit fd8b60
  environment, and a variable 'tls_impl', which indicates which TLS
Packit fd8b60
  implementation (if any) is being used by libkrb5's support for
Packit fd8b60
  contacting KDCs and kpasswd servers over HTTPS.
Packit fd8b60
Packit fd8b60
* verbose: Whether the script is running verbosely.
Packit fd8b60
Packit fd8b60
* testpass: The command-line test pass argument.  The script does not
Packit fd8b60
  need to examine this argument in most cases; it will be honored in
Packit fd8b60
  multipass_realms().
Packit fd8b60
Packit fd8b60
* Pathname variables for programs within the build directory:
Packit fd8b60
  - krb5kdc
Packit fd8b60
  - kadmind
Packit fd8b60
  - kadmin
Packit fd8b60
  - kadminl (kadmin.local)
Packit fd8b60
  - kdb5_ldap_util
Packit fd8b60
  - kdb5_util
Packit fd8b60
  - ktutil
Packit fd8b60
  - kinit
Packit fd8b60
  - klist
Packit fd8b60
  - kswitch
Packit fd8b60
  - kvno
Packit fd8b60
  - kdestroy
Packit fd8b60
  - kpasswd
Packit fd8b60
  - t_inetd
Packit fd8b60
  - kproplog
Packit fd8b60
  - kpropd
Packit fd8b60
  - kprop
Packit fd8b60
Packit fd8b60
Scripts may use the following realm methods and attributes:
Packit fd8b60
Packit fd8b60
* realm.run(args, env=None, **keywords): Run a command in a specified
Packit fd8b60
  environment (or the realm's environment by default), obeying the
Packit fd8b60
  command-line debugging options.  Fail if the command does not return
Packit fd8b60
  0.  Log the command output appropriately, and return it as a single
Packit fd8b60
  multi-line string.  Keyword arguments can contain input='string' to
Packit fd8b60
  send an input string to the command, expected_code=N to expect a
Packit fd8b60
  return code other than 0, expected_msg=MSG to expect a substring in
Packit fd8b60
  the command output, and expected_trace=('a', 'b', ...) to expect an
Packit fd8b60
  ordered series of line substrings in the command's KRB5_TRACE
Packit fd8b60
  output, or return_trace=True to return a tuple of the command output
Packit fd8b60
  and the trace output.
Packit fd8b60
Packit fd8b60
* realm.kprop_port(): Returns a port number based on realm.portbase
Packit fd8b60
  intended for use by kprop and kpropd.
Packit fd8b60
Packit fd8b60
* realm.server_port(): Returns a port number based on realm.portbase
Packit fd8b60
  intended for use by server processes.
Packit fd8b60
Packit fd8b60
* realm.start_server(args, sentinel, env=None): Start a daemon
Packit fd8b60
  process.  Wait until sentinel appears as a substring of a line in
Packit fd8b60
  the server process's stdout or stderr (which are folded together).
Packit fd8b60
  Returns a subprocess.Popen object which can be passed to
Packit fd8b60
  stop_daemon() to stop the server, or used to read from the server's
Packit fd8b60
  output.
Packit fd8b60
Packit fd8b60
* realm.start_in_inetd(args, port=None, env=None): Begin a t_inetd
Packit fd8b60
  process which will spawn a server process after accepting a client
Packit fd8b60
  connection.  If port is not specified, realm.server_port() will be
Packit fd8b60
  used.  Returns a process object which can be passed to stop_daemon()
Packit fd8b60
  to stop the server.
Packit fd8b60
Packit fd8b60
* realm.create_kdb(): Create a new KDB.
Packit fd8b60
Packit fd8b60
* realm.start_kdc(args=[], env=None): Start a krb5kdc process.  Errors
Packit fd8b60
  if a KDC is already running.  If args is given, it contains a list
Packit fd8b60
  of additional krb5kdc arguments.
Packit fd8b60
Packit fd8b60
* realm.stop_kdc(): Stop the krb5kdc process.  Errors if no KDC is
Packit fd8b60
  running.
Packit fd8b60
Packit fd8b60
* realm.start_kadmind(env=None): Start a kadmind process.  Errors if a
Packit fd8b60
  kadmind is already running.
Packit fd8b60
Packit fd8b60
* realm.stop_kadmind(): Stop the kadmind process.  Errors if no
Packit fd8b60
  kadmind is running.
Packit fd8b60
Packit fd8b60
* realm.stop(): Stop any daemon processes running on behalf of the
Packit fd8b60
  realm.
Packit fd8b60
Packit fd8b60
* realm.addprinc(princname, password=None): Using kadmin.local, create
Packit fd8b60
  a principal in the KDB named princname, with either a random or
Packit fd8b60
  specified key.
Packit fd8b60
Packit fd8b60
* realm.extract_keytab(princname, keytab): Using kadmin.local, create
Packit fd8b60
  a keytab for princname in the filename keytab.  Uses the -norandkey
Packit fd8b60
  option to avoid re-randomizing princname's key.
Packit fd8b60
Packit fd8b60
* realm.kinit(princname, password=None, flags=[]): Acquire credentials
Packit fd8b60
  for princname using kinit, with additional flags [].  If password is
Packit fd8b60
  specified, it will be used as input to the kinit process; otherwise
Packit fd8b60
  flags must cause kinit not to need a password (e.g. by specifying a
Packit fd8b60
  keytab).
Packit fd8b60
Packit fd8b60
* realm.klist(client_princ, service_princ=None, ccache=None): Using
Packit fd8b60
  klist, list the credentials cache ccache (must be a filename;
Packit fd8b60
  self.ccache if not specified) and verify that the output shows
Packit fd8b60
  credentials for client_princ and service_princ (self.krbtgt_princ if
Packit fd8b60
  not specified).
Packit fd8b60
Packit fd8b60
* realm.klist_keytab(princ, keytab=None): Using klist, list keytab
Packit fd8b60
  (must be a filename; self.keytab if not specified) and verify that
Packit fd8b60
  the output shows the keytab name and principal name.
Packit fd8b60
Packit fd8b60
* realm.prep_kadmin(princname=None, password=None, flags=[]): Populate
Packit fd8b60
  realm.kadmin_ccache with a ticket which can be used to run kadmin.
Packit fd8b60
  If princname is not specified, realm.admin_princ and its default
Packit fd8b60
  password will be used.
Packit fd8b60
Packit fd8b60
* realm.run_kadmin(args, **keywords): Run the specified query in
Packit fd8b60
  kadmin, using realm.kadmin_ccache to authenticate.  Accepts the same
Packit fd8b60
  keyword arguments as run.
Packit fd8b60
Packit fd8b60
* realm.special_env(name, has_kdc_conf, krb5_conf=None,
Packit fd8b60
  kdc_conf=None): Create an environment with a modified krb5.conf
Packit fd8b60
  and/or kdc.conf.  The specified krb5_conf and kdc_conf fragments, if
Packit fd8b60
  any, will be merged with the realm's existing configuration.  If
Packit fd8b60
  has_kdc_conf is false, the new environment will have no kdc.conf.
Packit fd8b60
  The environment returned by this method can be used with realm.run()
Packit fd8b60
  or similar methods.
Packit fd8b60
Packit fd8b60
* realm.start_kpropd(env, args=[]): Start a kpropd process.  Pass an
Packit fd8b60
  environment created with realm.special_env() for the replica.  If
Packit fd8b60
  args is given, it contains a list of additional kpropd arguments.
Packit fd8b60
  Returns a handle to the kpropd process.
Packit fd8b60
Packit fd8b60
* realm.run_kpropd_once(env, args=[]): Run kpropd once, using the -t
Packit fd8b60
  flag.  Pass an environment created with realm.special_env() for the
Packit fd8b60
  replica.  If args is given, it contains a list of additional kpropd
Packit fd8b60
  arguments.  Returns the kpropd output.
Packit fd8b60
Packit fd8b60
* realm.realm: The realm's name.
Packit fd8b60
Packit fd8b60
* realm.testdir: The realm's storage directory (absolute path).
Packit fd8b60
Packit fd8b60
* realm.portbase: The realm's first listener port.
Packit fd8b60
Packit fd8b60
* realm.user_princ: The principal name user@<realmname>.
Packit fd8b60
Packit fd8b60
* realm.admin_princ: The principal name user/admin@<realmname>.
Packit fd8b60
Packit fd8b60
* realm.host_princ: The name of the host principal for this machine,
Packit fd8b60
  with realm.
Packit fd8b60
Packit fd8b60
* realm.nfs_princ: The name of the nfs principal for this machine,
Packit fd8b60
  with realm.
Packit fd8b60
Packit fd8b60
* realm.krbtgt_princ: The name of the krbtgt principal for the realm.
Packit fd8b60
Packit fd8b60
* realm.keytab: A keytab file in realm.testdir.  Initially contains a
Packit fd8b60
  host keytab unless disabled by the realm construction options.
Packit fd8b60
Packit fd8b60
* realm.client_keytab: A keytab file in realm.testdir.  Initially
Packit fd8b60
  nonexistent.
Packit fd8b60
Packit fd8b60
* realm.ccache: A ccache file in realm.testdir.  Initially contains
Packit fd8b60
  credentials for user unless disabled by the realm construction
Packit fd8b60
  options.
Packit fd8b60
Packit fd8b60
* realm.kadmin_ccache: The ccache file initialized by prep_kadmin and
Packit fd8b60
  used by run_kadmin.
Packit fd8b60
Packit fd8b60
* env: The realm's environment, extended from os.environ to point at
Packit fd8b60
  the realm's config files and the build tree's shared libraries.
Packit fd8b60
Packit fd8b60
When the test script is run, its behavior can be modified with
Packit fd8b60
command-line flags.  These are documented in the --help output.
Packit fd8b60
Packit fd8b60
"""
Packit fd8b60
Packit fd8b60
import atexit
Packit fd8b60
import fcntl
Packit fd8b60
import optparse
Packit fd8b60
import os
Packit fd8b60
import shlex
Packit fd8b60
import shutil
Packit fd8b60
import signal
Packit fd8b60
import socket
Packit fd8b60
import string
Packit fd8b60
import subprocess
Packit fd8b60
import sys
Packit fd8b60
import imp
Packit fd8b60
Packit fd8b60
# Used when most things go wrong (other than programming errors) so
Packit fd8b60
# that the user sees an error message rather than a Python traceback,
Packit fd8b60
# without help from the test script.  The on-exit handler will display
Packit fd8b60
# additional explanatory text.
Packit fd8b60
def fail(msg):
Packit fd8b60
    """Print a message and exit with failure."""
Packit fd8b60
    global _current_pass
Packit fd8b60
    print("*** Failure:", msg)
Packit fd8b60
    if _last_mark:
Packit fd8b60
        print("*** Last mark: %s" % _last_mark)
Packit fd8b60
    if _last_cmd:
Packit fd8b60
        print("*** Last command (#%d): %s" % (_cmd_index - 1, _last_cmd))
Packit fd8b60
    if _last_cmd_output:
Packit fd8b60
        print("*** Output of last command:")
Packit fd8b60
        sys.stdout.write(_last_cmd_output)
Packit fd8b60
    if _current_pass:
Packit fd8b60
        print("*** Failed in test pass:", _current_pass)
Packit fd8b60
    if _current_db:
Packit fd8b60
        print("*** Failed with db:", _current_db)
Packit fd8b60
    sys.exit(1)
Packit fd8b60
Packit fd8b60
Packit fd8b60
def success(msg):
Packit fd8b60
    global _success
Packit fd8b60
    _check_daemons()
Packit fd8b60
    output('*** Success: %s\n' % msg)
Packit fd8b60
    _success = True
Packit fd8b60
Packit fd8b60
Packit fd8b60
def mark(msg):
Packit fd8b60
    global _last_mark
Packit fd8b60
    output('\n====== %s ======\n' % msg)
Packit fd8b60
    _last_mark = msg
Packit fd8b60
Packit fd8b60
Packit fd8b60
def skipped(whatmsg, whymsg):
Packit fd8b60
    output('*** Skipping: %s: %s\n' % (whatmsg, whymsg), force_verbose=True)
Packit fd8b60
    f = open(os.path.join(buildtop, 'skiptests'), 'a')
Packit fd8b60
    f.write('Skipped %s: %s\n' % (whatmsg, whymsg))
Packit fd8b60
    f.close()
Packit fd8b60
Packit fd8b60
Packit fd8b60
def skip_rest(whatmsg, whymsg):
Packit fd8b60
    global _success
Packit fd8b60
    skipped(whatmsg, whymsg)
Packit fd8b60
    _check_daemons()
Packit fd8b60
    _success = True
Packit fd8b60
    sys.exit(0)
Packit fd8b60
Packit fd8b60
Packit fd8b60
def output(msg, force_verbose=False):
Packit fd8b60
    """Output a message to testlog, and to stdout if running verbosely."""
Packit fd8b60
    _outfile.write(msg)
Packit fd8b60
    if verbose or force_verbose:
Packit fd8b60
        sys.stdout.write(msg)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Return the location of progname in the executable path, or None if
Packit fd8b60
# it is not found.
Packit fd8b60
def which(progname):
Packit fd8b60
    for dir in os.environ["PATH"].split(os.pathsep):
Packit fd8b60
        path = os.path.join(dir, progname)
Packit fd8b60
        if os.access(path, os.X_OK):
Packit fd8b60
            return path
Packit fd8b60
    return None
Packit fd8b60
Packit fd8b60
Packit fd8b60
def password(name):
Packit fd8b60
    """Choose a weakly random password from name, consistent across calls."""
Packit fd8b60
    return name + str(os.getpid())
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Exit handler which ensures processes are cleaned up and, on failure,
Packit fd8b60
# prints messages to help developers debug the problem.
Packit fd8b60
def _onexit():
Packit fd8b60
    global _daemons, _success, srctop, verbose
Packit fd8b60
    global _debug, _stop_before, _stop_after, _shell_before, _shell_after
Packit fd8b60
    if _debug or _stop_before or _stop_after or _shell_before or _shell_after:
Packit fd8b60
        # Wait before killing daemons in case one is being debugged.
Packit fd8b60
        sys.stdout.write('*** Press return to kill daemons and exit script: ')
Packit fd8b60
        sys.stdout.flush()
Packit fd8b60
        sys.stdin.readline()
Packit fd8b60
    for proc in _daemons:
Packit fd8b60
        if _check_daemon(proc) is None:
Packit fd8b60
            os.kill(proc.pid, signal.SIGTERM)
Packit fd8b60
    if not _success:
Packit fd8b60
        print
Packit fd8b60
        if not verbose:
Packit fd8b60
            testlogfile = os.path.join(os.getcwd(), 'testlog')
Packit fd8b60
            utildir = os.path.join(srctop, 'util')
Packit fd8b60
            print('For details, see: %s' % testlogfile)
Packit fd8b60
            print('Or re-run this test script with the -v flag:')
Packit fd8b60
            print('    cd %s' % os.getcwd())
Packit fd8b60
            print('    PYTHONPATH=%s %s %s -v' %
Packit fd8b60
                  (utildir, sys.executable, sys.argv[0]))
Packit fd8b60
            print()
Packit fd8b60
        print('Use --debug=NUM to run a command under a debugger.  Use')
Packit fd8b60
        print('--stop-after=NUM to stop after a daemon is started in order to')
Packit fd8b60
        print('attach to it with a debugger.  Use --help to see other')
Packit fd8b60
        print('options.')
Packit fd8b60
Packit fd8b60
Packit fd8b60
def _onsigint(signum, frame):
Packit fd8b60
    # Exit without displaying a stack trace.  Suppress messages from _onexit.
Packit fd8b60
    global _success
Packit fd8b60
    _success = True
Packit fd8b60
    sys.exit(1)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Find the parent of dir which is at the root of a build or source directory.
Packit fd8b60
def _find_root(dir):
Packit fd8b60
    while True:
Packit fd8b60
        if os.path.exists(os.path.join(dir, 'lib', 'krb5', 'krb')):
Packit fd8b60
            break
Packit fd8b60
        parent = os.path.dirname(dir)
Packit fd8b60
        if (parent == dir):
Packit fd8b60
            return None
Packit fd8b60
        dir = parent
Packit fd8b60
    return dir
Packit fd8b60
Packit fd8b60
Packit fd8b60
def _find_buildtop():
Packit fd8b60
    root = _find_root(os.getcwd())
Packit fd8b60
    if root is None:
Packit fd8b60
        fail('Cannot find root of krb5 build directory.')
Packit fd8b60
    if not os.path.exists(os.path.join(root, 'config.status')):
Packit fd8b60
        # Looks like an unbuilt source directory.
Packit fd8b60
        fail('This script must be run inside a krb5 build directory.')
Packit fd8b60
    return root
Packit fd8b60
Packit fd8b60
Packit fd8b60
def _find_srctop():
Packit fd8b60
    scriptdir = os.path.abspath(os.path.dirname(sys.argv[0]))
Packit fd8b60
    if not scriptdir:
Packit fd8b60
        scriptdir = os.getcwd()
Packit fd8b60
    root = _find_root(scriptdir)
Packit fd8b60
    if root is None:
Packit fd8b60
        fail('Cannot find root of krb5 source directory.')
Packit fd8b60
    return os.path.abspath(root)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Return the local hostname as it will be canonicalized by
Packit fd8b60
# krb5_sname_to_principal.  We can't simply use socket.getfqdn()
Packit fd8b60
# because it explicitly prefers results containing periods and
Packit fd8b60
# krb5_sname_to_principal doesn't care.
Packit fd8b60
def _get_hostname():
Packit fd8b60
    hostname = socket.gethostname()
Packit fd8b60
    try:
Packit fd8b60
        ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
Packit fd8b60
    except socket.gaierror as e:
Packit fd8b60
        fail('Local hostname "%s" does not resolve: %s.' % (hostname, e[1]))
Packit fd8b60
    (family, socktype, proto, canonname, sockaddr) = ai[0]
Packit fd8b60
    try:
Packit fd8b60
        name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
Packit fd8b60
    except socket.gaierror:
Packit fd8b60
        return canonname.lower()
Packit fd8b60
    return name[0].lower()
Packit fd8b60
Packit fd8b60
# Parse command line arguments, setting global option variables.  Also
Packit fd8b60
# sets the global variable args to the positional arguments, which may
Packit fd8b60
# be used by the test script.
Packit fd8b60
def _parse_args():
Packit fd8b60
    global args, verbose, testpass, _debug, _debugger_command
Packit fd8b60
    global _stop_before, _stop_after, _shell_before, _shell_after
Packit fd8b60
    parser = optparse.OptionParser()
Packit fd8b60
    parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
Packit fd8b60
                      default=False, help='Display verbose output')
Packit fd8b60
    parser.add_option('-p', '--pass', dest='testpass', metavar='PASS',
Packit fd8b60
                      help='If a multi-pass test, run only PASS')
Packit fd8b60
    parser.add_option('--debug', dest='debug', metavar='NUM',
Packit fd8b60
                      help='Debug numbered command (or "all")')
Packit fd8b60
    parser.add_option('--debugger', dest='debugger', metavar='COMMAND',
Packit fd8b60
                      help='Debugger command (default is gdb --args)',
Packit fd8b60
                      default='gdb --args')
Packit fd8b60
    parser.add_option('--stop-before', dest='stopb', metavar='NUM',
Packit fd8b60
                      help='Stop before numbered command (or "all")')
Packit fd8b60
    parser.add_option('--stop-after', dest='stopa', metavar='NUM',
Packit fd8b60
                      help='Stop after numbered command (or "all")')
Packit fd8b60
    parser.add_option('--shell-before', dest='shellb', metavar='NUM',
Packit fd8b60
                      help='Spawn shell before numbered command (or "all")')
Packit fd8b60
    parser.add_option('--shell-after', dest='shella', metavar='NUM',
Packit fd8b60
                      help='Spawn shell after numbered command (or "all")')
Packit fd8b60
    (options, args) = parser.parse_args()
Packit fd8b60
    verbose = options.verbose
Packit fd8b60
    testpass = options.testpass
Packit fd8b60
    _debug = _parse_cmdnum('--debug', options.debug)
Packit fd8b60
    _debugger_command = shlex.split(options.debugger)
Packit fd8b60
    _stop_before = _parse_cmdnum('--stop-before', options.stopb)
Packit fd8b60
    _stop_after = _parse_cmdnum('--stop-after', options.stopa)
Packit fd8b60
    _shell_before = _parse_cmdnum('--shell-before', options.shellb)
Packit fd8b60
    _shell_after = _parse_cmdnum('--shell-after', options.shella)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Translate a command number spec.  -1 means all, None means none.
Packit fd8b60
def _parse_cmdnum(optname, str):
Packit fd8b60
    if not str:
Packit fd8b60
        return None
Packit fd8b60
    if str == 'all':
Packit fd8b60
        return -1
Packit fd8b60
    try:
Packit fd8b60
        return int(str)
Packit fd8b60
    except ValueError:
Packit fd8b60
        fail('%s value must be "all" or a number' % optname)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Test if a command index matches a translated command number spec.
Packit fd8b60
def _match_cmdnum(cmdnum, ind):
Packit fd8b60
    if cmdnum is None:
Packit fd8b60
        return False
Packit fd8b60
    elif cmdnum == -1:
Packit fd8b60
        return True
Packit fd8b60
    else:
Packit fd8b60
        return cmdnum == ind
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Return an environment suitable for running programs in the build
Packit fd8b60
# tree.  It is safe to modify the result.
Packit fd8b60
def _build_env():
Packit fd8b60
    global buildtop, runenv
Packit fd8b60
    env = os.environ.copy()
Packit fd8b60
    for (k, v) in runenv.env.items():
Packit fd8b60
        if v.find('./') == 0:
Packit fd8b60
            env[k] = os.path.join(buildtop, v)
Packit fd8b60
        else:
Packit fd8b60
            env[k] = v
Packit fd8b60
    # Make sure we don't get confused by translated messages
Packit fd8b60
    # or localized times.
Packit fd8b60
    env['LC_ALL'] = 'C'
Packit fd8b60
    return env
Packit fd8b60
Packit fd8b60
Packit fd8b60
def _import_runenv():
Packit fd8b60
    global buildtop
Packit fd8b60
    runenv_py = os.path.join(buildtop, 'runenv.py')
Packit fd8b60
    if not os.path.exists(runenv_py):
Packit fd8b60
        fail('You must run "make runenv.py" in %s first.' % buildtop)
Packit fd8b60
    return imp.load_source('runenv', runenv_py)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Merge the nested dictionaries cfg1 and cfg2 into a new dictionary.
Packit fd8b60
# cfg1 or cfg2 may be None, in which case the other is returned.  If
Packit fd8b60
# cfg2 contains keys mapped to None, the corresponding keys will be
Packit fd8b60
# mapped to None in the result.  The result may contain references to
Packit fd8b60
# parts of cfg1 or cfg2, so is not safe to modify.
Packit fd8b60
def _cfg_merge(cfg1, cfg2):
Packit fd8b60
    if not cfg2:
Packit fd8b60
        return cfg1
Packit fd8b60
    if not cfg1:
Packit fd8b60
        return cfg2
Packit fd8b60
    result = cfg1.copy()
Packit fd8b60
    for key, value2 in cfg2.items():
Packit fd8b60
        if value2 is None:
Packit fd8b60
            result.pop(key, None)
Packit fd8b60
        elif key not in result:
Packit fd8b60
            result[key] = value2
Packit fd8b60
        else:
Packit fd8b60
            value1 = result[key]
Packit fd8b60
            if isinstance(value1, dict):
Packit fd8b60
                if not isinstance(value2, dict):
Packit fd8b60
                    raise TypeError()
Packit fd8b60
                result[key] = _cfg_merge(value1, value2)
Packit fd8b60
            else:
Packit fd8b60
                result[key] = value2
Packit fd8b60
    return result
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Python gives us shlex.split() to turn a shell command into a list of
Packit fd8b60
# arguments, but oddly enough, not the easier reverse operation.  For
Packit fd8b60
# now, do a bad job of faking it.
Packit fd8b60
def _shell_equiv(args):
Packit fd8b60
    return " ".join(args)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Add a valgrind prefix to the front of args if specified in the
Packit fd8b60
# environment.  Under normal circumstances this just returns args.
Packit fd8b60
def _valgrind(args):
Packit fd8b60
    valgrind = os.getenv('VALGRIND')
Packit fd8b60
    if valgrind:
Packit fd8b60
        args = shlex.split(valgrind) + args
Packit fd8b60
    return args
Packit fd8b60
Packit fd8b60
Packit fd8b60
def _stop_or_shell(stop, shell, env, ind):
Packit fd8b60
    if (_match_cmdnum(stop, ind)):
Packit fd8b60
        sys.stdout.write('*** [%d] Waiting for return: ' % ind)
Packit fd8b60
        sys.stdout.flush()
Packit fd8b60
        sys.stdin.readline()
Packit fd8b60
    if (_match_cmdnum(shell, ind)):
Packit fd8b60
        output('*** [%d] Spawning shell\n' % ind, True)
Packit fd8b60
        subprocess.call(os.getenv('SHELL'), env=env)
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Look for the expected strings in successive lines of trace.
Packit fd8b60
def _check_trace(trace, expected):
Packit fd8b60
    i = 0
Packit fd8b60
    for line in trace.splitlines():
Packit fd8b60
        if i < len(expected) and expected[i] in line:
Packit fd8b60
            i += 1
Packit fd8b60
    if i < len(expected):
Packit fd8b60
        fail('Expected string not found in trace output: ' + expected[i])
Packit fd8b60
Packit fd8b60
Packit fd8b60
def _run_cmd(args, env, input=None, expected_code=0, expected_msg=None,
Packit fd8b60
             expected_trace=None, return_trace=False):
Packit fd8b60
    global null_input, _cmd_index, _last_cmd, _last_cmd_output, _debug
Packit fd8b60
    global _stop_before, _stop_after, _shell_before, _shell_after
Packit fd8b60
Packit fd8b60
    tracefile = None
Packit fd8b60
    if expected_trace is not None or return_trace:
Packit fd8b60
        tracefile = 'testtrace'
Packit fd8b60
        if os.path.exists(tracefile):
Packit fd8b60
            os.remove(tracefile)
Packit fd8b60
        env = env.copy()
Packit fd8b60
        env['KRB5_TRACE'] = tracefile
Packit fd8b60
Packit fd8b60
    if (_match_cmdnum(_debug, _cmd_index)):
Packit fd8b60
        return _debug_cmd(args, env, input)
Packit fd8b60
Packit fd8b60
    args = _valgrind(args)
Packit fd8b60
    _last_cmd = _shell_equiv(args)
Packit fd8b60
Packit fd8b60
    output('*** [%d] Executing: %s\n' % (_cmd_index, _last_cmd))
Packit fd8b60
    _stop_or_shell(_stop_before, _shell_before, env, _cmd_index)
Packit fd8b60
Packit fd8b60
    if input:
Packit fd8b60
        infile = subprocess.PIPE
Packit fd8b60
    else:
Packit fd8b60
        infile = null_input
Packit fd8b60
Packit fd8b60
    # Run the command and log the result, folding stderr into stdout.
Packit fd8b60
    proc = subprocess.Popen(args, stdin=infile, stdout=subprocess.PIPE,
Packit fd8b60
                            stderr=subprocess.STDOUT, env=env,
Packit fd8b60
                            universal_newlines=True)
Packit fd8b60
    (outdata, dummy_errdata) = proc.communicate(input)
Packit fd8b60
    _last_cmd_output = outdata
Packit fd8b60
    code = proc.returncode
Packit fd8b60
    output(outdata)
Packit fd8b60
    output('*** [%d] Completed with return code %d\n' % (_cmd_index, code))
Packit fd8b60
    _stop_or_shell(_stop_after, _shell_after, env, _cmd_index)
Packit fd8b60
    _cmd_index += 1
Packit fd8b60
Packit fd8b60
    # Check the return code and return the output.
Packit fd8b60
    if code != expected_code:
Packit fd8b60
        fail('%s failed with code %d.' % (args[0], code))
Packit fd8b60
Packit fd8b60
    if expected_msg is not None and expected_msg not in outdata:
Packit fd8b60
        fail('Expected string not found in command output: ' + expected_msg)
Packit fd8b60
Packit fd8b60
    if tracefile is not None:
Packit fd8b60
        with open(tracefile, 'r') as f:
Packit fd8b60
            trace = f.read()
Packit fd8b60
        output('*** Trace output for previous command:\n')
Packit fd8b60
        output(trace)
Packit fd8b60
        if expected_trace is not None:
Packit fd8b60
            _check_trace(trace, expected_trace)
Packit fd8b60
Packit fd8b60
    return (outdata, trace) if return_trace else outdata
Packit fd8b60
Packit fd8b60
Packit fd8b60
def _debug_cmd(args, env, input):
Packit fd8b60
    global _cmd_index, _debugger_command
Packit fd8b60
Packit fd8b60
    args = _debugger_command + list(args)
Packit fd8b60
    output('*** [%d] Executing in debugger: %s\n' %
Packit fd8b60
           (_cmd_index, _shell_equiv(args)), True)
Packit fd8b60
    if input:
Packit fd8b60
        print
Packit fd8b60
        print('*** Enter the following input when appropriate:')
Packit fd8b60
        print()
Packit fd8b60
        print(input)
Packit fd8b60
        print()
Packit fd8b60
    code = subprocess.call(args, env=env)
Packit fd8b60
    output('*** [%d] Completed in debugger with return code %d\n' %
Packit fd8b60
           (_cmd_index, code))
Packit fd8b60
    _cmd_index += 1
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Start a daemon process with the specified args and env.  Wait until
Packit fd8b60
# we see sentinel as a substring of a line on either stdout or stderr.
Packit fd8b60
# Clean up the daemon process on exit.
Packit fd8b60
def _start_daemon(args, env, sentinel):
Packit fd8b60
    global null_input, _cmd_index, _last_cmd, _last_cmd_output, _debug
Packit fd8b60
    global _stop_before, _stop_after, _shell_before, _shell_after
Packit fd8b60
Packit fd8b60
    if (_match_cmdnum(_debug, _cmd_index)):
Packit fd8b60
        output('*** [%d] Warning: ' % _cmd_index, True)
Packit fd8b60
        output( 'test script cannot proceed after debugging a daemon\n', True)
Packit fd8b60
        _debug_cmd(args, env, None)
Packit fd8b60
        output('*** Exiting after debugging daemon\n', True)
Packit fd8b60
        sys.exit(1)
Packit fd8b60
Packit fd8b60
    args = _valgrind(args)
Packit fd8b60
    _last_cmd = _shell_equiv(args)
Packit fd8b60
    output('*** [%d] Starting: %s\n' % (_cmd_index, _last_cmd))
Packit fd8b60
    _stop_or_shell(_stop_before, _shell_before, env, _cmd_index)
Packit fd8b60
Packit fd8b60
    # Start the daemon and look for the sentinel in stdout or stderr.
Packit fd8b60
    proc = subprocess.Popen(args, stdin=null_input, stdout=subprocess.PIPE,
Packit fd8b60
                            stderr=subprocess.STDOUT, env=env,
Packit fd8b60
                            universal_newlines=True)
Packit fd8b60
    _last_cmd_output = ''
Packit fd8b60
    while True:
Packit fd8b60
        line = proc.stdout.readline()
Packit fd8b60
        _last_cmd_output += line
Packit fd8b60
        if line == "":
Packit fd8b60
            code = proc.wait()
Packit fd8b60
            fail('%s failed to start with code %d.' % (args[0], code))
Packit fd8b60
        output(line)
Packit fd8b60
        if sentinel in line:
Packit fd8b60
            break
Packit fd8b60
    output('*** [%d] Started with pid %d\n' % (_cmd_index, proc.pid))
Packit fd8b60
    _stop_or_shell(_stop_after, _shell_after, env, _cmd_index)
Packit fd8b60
    _cmd_index += 1
Packit fd8b60
Packit fd8b60
    # Save the daemon in a list for cleanup.  Note that we won't read
Packit fd8b60
    # any more of the daemon's output after the sentinel, which will
Packit fd8b60
    # cause the daemon to block if it generates enough.  For now we
Packit fd8b60
    # assume all daemon processes are quiet enough to avoid this
Packit fd8b60
    # problem.  If it causes an issue, some alternatives are:
Packit fd8b60
    #   - Output to a file and poll the file for the sentinel
Packit fd8b60
    #     (undesirable because it slows down the test suite by the
Packit fd8b60
    #     polling interval times the number of daemons started)
Packit fd8b60
    #   - Create an intermediate subprocess which discards output
Packit fd8b60
    #     after the sentinel.
Packit fd8b60
    _daemons.append(proc)
Packit fd8b60
Packit fd8b60
    # Return the process; the caller can stop it with stop_daemon.
Packit fd8b60
    return proc
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Check a daemon's status prior to terminating it.  Display its return
Packit fd8b60
# code if it already exited, and display any output it has generated.
Packit fd8b60
# Return the daemon's exit status or None if it is still running.
Packit fd8b60
def _check_daemon(proc):
Packit fd8b60
    exited = False
Packit fd8b60
    code = proc.poll()
Packit fd8b60
    if code is not None:
Packit fd8b60
        output('*** Daemon pid %d exited with code %d\n' % (proc.pid, code))
Packit fd8b60
Packit fd8b60
    flags = fcntl.fcntl(proc.stdout, fcntl.F_GETFL)
Packit fd8b60
    fcntl.fcntl(proc.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
Packit fd8b60
    try:
Packit fd8b60
        out = proc.stdout.read()
Packit fd8b60
    except:
Packit fd8b60
        return
Packit fd8b60
Packit fd8b60
    output('*** Daemon pid %d output:\n' % proc.pid)
Packit fd8b60
    output(out)
Packit fd8b60
    return code
Packit fd8b60
Packit fd8b60
Packit fd8b60
# Check all tracked daemon processes.  If any daemons already exited,
Packit fd8b60
# remove them from the list (so we don't try to terminate them again).
Packit fd8b60
# If any daemons exited with an error, fail out.
Packit fd8b60
def _check_daemons():
Packit fd8b60
    exited = []
Packit fd8b60
    daemon_error = False
Packit fd8b60
    for proc in _daemons:
Packit fd8b60
        code = _check_daemon(proc)
Packit fd8b60
        if code is not None:
Packit fd8b60
            exited.append(proc)
Packit fd8b60
            if code != 0:
Packit fd8b60
                daemon_error = True
Packit fd8b60
Packit fd8b60
    for proc in exited:
Packit fd8b60
        _daemons.remove(proc)
Packit fd8b60
Packit fd8b60
    if daemon_error:
Packit fd8b60
        fail('One or more daemon processes exited with an error')
Packit fd8b60
Packit fd8b60
Packit fd8b60
def stop_daemon(proc):
Packit fd8b60
    code = _check_daemon(proc)
Packit fd8b60
    if code is not None:
Packit fd8b60
        _daemons.remove(proc)
Packit fd8b60
        if code != 0:
Packit fd8b60
            fail('Daemon process %d exited early' % proc.pid)
Packit fd8b60
    else:
Packit fd8b60
        output('*** Terminating process %d\n' % proc.pid)
Packit fd8b60
        os.kill(proc.pid, signal.SIGTERM)
Packit fd8b60
        proc.wait()
Packit fd8b60
        _daemons.remove(proc)
Packit fd8b60
Packit fd8b60
Packit fd8b60
class K5Realm(object):
Packit fd8b60
    """An object representing a functional krb5 test realm."""
Packit fd8b60
Packit fd8b60
    def __init__(self, realm='KRBTEST.COM', portbase=61000, testdir='testdir',
Packit fd8b60
                 krb5_conf=None, kdc_conf=None, create_kdb=True,
Packit fd8b60
                 krbtgt_keysalt=None, create_user=True, get_creds=True,
Packit fd8b60
                 create_host=True, start_kdc=True, start_kadmind=False,
Packit fd8b60
                 start_kpropd=False, bdb_only=False):
Packit fd8b60
        global hostname, _default_krb5_conf, _default_kdc_conf
Packit fd8b60
        global _lmdb_kdc_conf, _current_db
Packit fd8b60
Packit fd8b60
        self.realm = realm
Packit fd8b60
        self.testdir = os.path.join(os.getcwd(), testdir)
Packit fd8b60
        self.portbase = portbase
Packit fd8b60
        self.user_princ = 'user@' + self.realm
Packit fd8b60
        self.admin_princ = 'user/admin@' + self.realm
Packit fd8b60
        self.host_princ = 'host/%s@%s' % (hostname, self.realm)
Packit fd8b60
        self.nfs_princ = 'nfs/%s@%s' % (hostname, self.realm)
Packit fd8b60
        self.krbtgt_princ = 'krbtgt/%s@%s' % (self.realm, self.realm)
Packit fd8b60
        self.keytab = os.path.join(self.testdir, 'keytab')
Packit fd8b60
        self.client_keytab = os.path.join(self.testdir, 'client_keytab')
Packit fd8b60
        self.ccache = os.path.join(self.testdir, 'ccache')
Packit fd8b60
        self.gss_mech_config = os.path.join(self.testdir, 'mech.conf')
Packit fd8b60
        self.kadmin_ccache = os.path.join(self.testdir, 'kadmin_ccache')
Packit fd8b60
        self._krb5_conf = _cfg_merge(_default_krb5_conf, krb5_conf)
Packit fd8b60
        base_kdc_conf = _default_kdc_conf
Packit fd8b60
        if (os.getenv('K5TEST_LMDB') is not None and
Packit fd8b60
            not bdb_only and not _current_db):
Packit fd8b60
            base_kdc_conf = _cfg_merge(base_kdc_conf, _lmdb_kdc_conf)
Packit fd8b60
        self._kdc_conf = _cfg_merge(base_kdc_conf, kdc_conf)
Packit fd8b60
        self._kdc_proc = None
Packit fd8b60
        self._kadmind_proc = None
Packit fd8b60
        self._kpropd_procs = []
Packit fd8b60
        krb5_conf_path = os.path.join(self.testdir, 'krb5.conf')
Packit fd8b60
        kdc_conf_path = os.path.join(self.testdir, 'kdc.conf')
Packit fd8b60
        self.env = self._make_env(krb5_conf_path, kdc_conf_path)
Packit fd8b60
Packit fd8b60
        self._create_empty_dir()
Packit fd8b60
        self._create_conf(self._krb5_conf, krb5_conf_path)
Packit fd8b60
        self._create_conf(self._kdc_conf, kdc_conf_path)
Packit fd8b60
        self._create_acl()
Packit fd8b60
        self._create_dictfile()
Packit fd8b60
Packit fd8b60
        if create_kdb:
Packit fd8b60
            self.create_kdb()
Packit fd8b60
        if krbtgt_keysalt and create_kdb:
Packit fd8b60
            self.run([kadminl, 'cpw', '-randkey', '-e', krbtgt_keysalt,
Packit fd8b60
                      self.krbtgt_princ])
Packit fd8b60
        if create_user and create_kdb:
Packit fd8b60
            self.addprinc(self.user_princ, password('user'))
Packit fd8b60
            self.addprinc(self.admin_princ, password('admin'))
Packit fd8b60
        if create_host and create_kdb:
Packit fd8b60
            self.addprinc(self.host_princ)
Packit fd8b60
            self.extract_keytab(self.host_princ, self.keytab)
Packit fd8b60
        if start_kdc and create_kdb:
Packit fd8b60
            self.start_kdc()
Packit fd8b60
        if start_kadmind and create_kdb:
Packit fd8b60
            self.start_kadmind()
Packit fd8b60
        if get_creds and create_kdb and create_user and start_kdc:
Packit fd8b60
            self.kinit(self.user_princ, password('user'))
Packit fd8b60
            self.klist(self.user_princ)
Packit fd8b60
Packit fd8b60
    def _create_empty_dir(self):
Packit fd8b60
        dir = self.testdir
Packit fd8b60
        shutil.rmtree(dir, True)
Packit fd8b60
        if (os.path.exists(dir)):
Packit fd8b60
            fail('Cannot remove %s to create test realm.' % dir)
Packit fd8b60
        os.mkdir(dir)
Packit fd8b60
Packit fd8b60
    def _create_conf(self, profile, filename):
Packit fd8b60
        file = open(filename, 'w')
Packit fd8b60
        for section, contents in profile.items():
Packit fd8b60
            file.write('[%s]\n' % section)
Packit fd8b60
            self._write_cfg_section(file, contents, 1)
Packit fd8b60
        file.close()
Packit fd8b60
Packit fd8b60
    def _write_cfg_section(self, file, contents, indent_level):
Packit fd8b60
        indent = '\t' * indent_level
Packit fd8b60
        for name, value in contents.items():
Packit fd8b60
            name = self._subst_cfg_value(name)
Packit fd8b60
            if isinstance(value, dict):
Packit fd8b60
                # A dictionary value yields a list subsection.
Packit fd8b60
                file.write('%s%s = {\n' % (indent, name))
Packit fd8b60
                self._write_cfg_section(file, value, indent_level + 1)
Packit fd8b60
                file.write('%s}\n' % indent)
Packit fd8b60
            elif isinstance(value, list):
Packit fd8b60
                # A list value yields multiple values for the same name.
Packit fd8b60
                for item in value:
Packit fd8b60
                    item = self._subst_cfg_value(item)
Packit fd8b60
                    file.write('%s%s = %s\n' % (indent, name, item))
Packit fd8b60
            elif isinstance(value, str):
Packit fd8b60
                # A string value yields a straightforward variable setting.
Packit fd8b60
                value = self._subst_cfg_value(value)
Packit fd8b60
                file.write('%s%s = %s\n' % (indent, name, value))
Packit fd8b60
            else:
Packit fd8b60
                raise TypeError()
Packit fd8b60
Packit fd8b60
    def _subst_cfg_value(self, value):
Packit fd8b60
        global buildtop, srctop, hostname
Packit fd8b60
        template = string.Template(value)
Packit fd8b60
        subst = template.substitute(realm=self.realm,
Packit fd8b60
                                    testdir=self.testdir,
Packit fd8b60
                                    buildtop=buildtop,
Packit fd8b60
                                    srctop=srctop,
Packit fd8b60
                                    plugins=plugins,
Packit fd8b60
                                    hostname=hostname,
Packit fd8b60
                                    port0=self.portbase,
Packit fd8b60
                                    port1=self.portbase + 1,
Packit fd8b60
                                    port2=self.portbase + 2,
Packit fd8b60
                                    port3=self.portbase + 3,
Packit fd8b60
                                    port4=self.portbase + 4,
Packit fd8b60
                                    port5=self.portbase + 5,
Packit fd8b60
                                    port6=self.portbase + 6,
Packit fd8b60
                                    port7=self.portbase + 7,
Packit fd8b60
                                    port8=self.portbase + 8,
Packit fd8b60
                                    port9=self.portbase + 9)
Packit fd8b60
        # Empty values must be quoted to avoid a syntax error.
Packit fd8b60
        return subst if subst else '""'
Packit fd8b60
Packit fd8b60
    def _create_acl(self):
Packit fd8b60
        global hostname
Packit fd8b60
        filename = os.path.join(self.testdir, 'acl')
Packit fd8b60
        file = open(filename, 'w')
Packit fd8b60
        file.write('%s *e\n' % self.admin_princ)
Packit fd8b60
        file.write('kiprop/%s@%s p\n' % (hostname, self.realm))
Packit fd8b60
        file.close()
Packit fd8b60
Packit fd8b60
    def _create_dictfile(self):
Packit fd8b60
        filename = os.path.join(self.testdir, 'dictfile')
Packit fd8b60
        file = open(filename, 'w')
Packit fd8b60
        file.write('weak_password\n')
Packit fd8b60
        file.close()
Packit fd8b60
Packit fd8b60
    def _make_env(self, krb5_conf_path, kdc_conf_path):
Packit fd8b60
        env = _build_env()
Packit fd8b60
        env['KRB5_CONFIG'] = krb5_conf_path
Packit fd8b60
        env['KRB5_KDC_PROFILE'] = kdc_conf_path or os.devnull
Packit fd8b60
        env['KRB5CCNAME'] = self.ccache
Packit fd8b60
        env['KRB5_KTNAME'] = self.keytab
Packit fd8b60
        env['KRB5_CLIENT_KTNAME'] = self.client_keytab
Packit fd8b60
        env['KRB5RCACHEDIR'] = self.testdir
Packit fd8b60
        env['KPROPD_PORT'] = str(self.kprop_port())
Packit fd8b60
        env['KPROP_PORT'] = str(self.kprop_port())
Packit fd8b60
        env['GSS_MECH_CONFIG'] = self.gss_mech_config
Packit fd8b60
        return env
Packit fd8b60
Packit fd8b60
    def run(self, args, env=None, **keywords):
Packit fd8b60
        if env is None:
Packit fd8b60
            env = self.env
Packit fd8b60
        return _run_cmd(args, env, **keywords)
Packit fd8b60
Packit fd8b60
    def kprop_port(self):
Packit fd8b60
        return self.portbase + 3
Packit fd8b60
Packit fd8b60
    def server_port(self):
Packit fd8b60
        return self.portbase + 5
Packit fd8b60
Packit fd8b60
    def start_server(self, args, sentinel, env=None):
Packit fd8b60
        if env is None:
Packit fd8b60
            env = self.env
Packit fd8b60
        return _start_daemon(args, env, sentinel)
Packit fd8b60
Packit fd8b60
    def start_in_inetd(self, args, port=None, env=None):
Packit fd8b60
        if not port:
Packit fd8b60
            port = self.server_port()
Packit fd8b60
        if env is None:
Packit fd8b60
            env = self.env
Packit fd8b60
        inetd_args = [t_inetd, str(port)] + args
Packit fd8b60
        return _start_daemon(inetd_args, env, 'Ready!')
Packit fd8b60
Packit fd8b60
    def create_kdb(self):
Packit fd8b60
        global kdb5_util
Packit fd8b60
        self.run([kdb5_util, 'create', '-W', '-s', '-P', 'master'])
Packit fd8b60
Packit fd8b60
    def start_kdc(self, args=[], env=None):
Packit fd8b60
        global krb5kdc
Packit fd8b60
        if env is None:
Packit fd8b60
            env = self.env
Packit fd8b60
        assert(self._kdc_proc is None)
Packit fd8b60
        self._kdc_proc = _start_daemon([krb5kdc, '-n'] + args, env,
Packit fd8b60
                                       'starting...')
Packit fd8b60
Packit fd8b60
    def stop_kdc(self):
Packit fd8b60
        assert(self._kdc_proc is not None)
Packit fd8b60
        stop_daemon(self._kdc_proc)
Packit fd8b60
        self._kdc_proc = None
Packit fd8b60
Packit fd8b60
    def start_kadmind(self, env=None):
Packit fd8b60
        global krb5kdc
Packit fd8b60
        if env is None:
Packit fd8b60
            env = self.env
Packit fd8b60
        assert(self._kadmind_proc is None)
Packit fd8b60
        dump_path = os.path.join(self.testdir, 'dump')
Packit fd8b60
        self._kadmind_proc = _start_daemon([kadmind, '-nofork', '-W',
Packit fd8b60
                                            '-p', kdb5_util, '-K', kprop,
Packit fd8b60
                                            '-F', dump_path], env,
Packit fd8b60
                                           'starting...')
Packit fd8b60
Packit fd8b60
    def stop_kadmind(self):
Packit fd8b60
        assert(self._kadmind_proc is not None)
Packit fd8b60
        stop_daemon(self._kadmind_proc)
Packit fd8b60
        self._kadmind_proc = None
Packit fd8b60
Packit fd8b60
    def _kpropd_args(self):
Packit fd8b60
        datatrans_path = os.path.join(self.testdir, 'incoming-datatrans')
Packit fd8b60
        kpropdacl_path = os.path.join(self.testdir, 'kpropd-acl')
Packit fd8b60
        return [kpropd, '-D', '-P', str(self.kprop_port()),
Packit fd8b60
                '-f', datatrans_path, '-p', kdb5_util, '-a', kpropdacl_path]
Packit fd8b60
Packit fd8b60
    def start_kpropd(self, env, args=[]):
Packit fd8b60
        proc = _start_daemon(self._kpropd_args() + args, env, 'ready')
Packit fd8b60
        self._kpropd_procs.append(proc)
Packit fd8b60
        return proc
Packit fd8b60
Packit fd8b60
    def stop_kpropd(self, proc):
Packit fd8b60
        stop_daemon(proc)
Packit fd8b60
        self._kpropd_procs.remove(proc)
Packit fd8b60
Packit fd8b60
    def run_kpropd_once(self, env, args=[]):
Packit fd8b60
        return self.run(self._kpropd_args() + ['-t'] + args, env=env)
Packit fd8b60
Packit fd8b60
    def stop(self):
Packit fd8b60
        if self._kdc_proc:
Packit fd8b60
            self.stop_kdc()
Packit fd8b60
        if self._kadmind_proc:
Packit fd8b60
            self.stop_kadmind()
Packit fd8b60
        for p in self._kpropd_procs:
Packit fd8b60
            stop_daemon(p)
Packit fd8b60
        self._kpropd_procs = []
Packit fd8b60
Packit fd8b60
    def addprinc(self, princname, password=None):
Packit fd8b60
        if password:
Packit fd8b60
            self.run([kadminl, 'addprinc', '-pw', password, princname])
Packit fd8b60
        else:
Packit fd8b60
            self.run([kadminl, 'addprinc', '-randkey', princname])
Packit fd8b60
Packit fd8b60
    def extract_keytab(self, princname, keytab):
Packit fd8b60
        self.run([kadminl, 'ktadd', '-k', keytab, '-norandkey', princname])
Packit fd8b60
Packit fd8b60
    def kinit(self, princname, password=None, flags=[], **keywords):
Packit fd8b60
        if password:
Packit fd8b60
            input = password + "\n"
Packit fd8b60
        else:
Packit fd8b60
            input = None
Packit fd8b60
        return self.run([kinit] + flags + [princname], input=input, **keywords)
Packit fd8b60
Packit fd8b60
    def klist(self, client_princ, service_princ=None, ccache=None, **keywords):
Packit fd8b60
        if service_princ is None:
Packit fd8b60
            service_princ = self.krbtgt_princ
Packit fd8b60
        if ccache is None:
Packit fd8b60
            ccache = self.ccache
Packit fd8b60
        ccachestr = ccache
Packit fd8b60
        if len(ccachestr) < 2 or ':' not in ccachestr[2:]:
Packit fd8b60
            ccachestr = 'FILE:' + ccachestr
Packit fd8b60
        output = self.run([klist, ccache], **keywords)
Packit fd8b60
        if (('Ticket cache: %s\n' % ccachestr) not in output or
Packit fd8b60
            ('Default principal: %s\n' % client_princ) not in output or
Packit fd8b60
            service_princ not in output):
Packit fd8b60
            fail('Unexpected klist output.')
Packit fd8b60
Packit fd8b60
    def klist_keytab(self, princ, keytab=None, **keywords):
Packit fd8b60
        if keytab is None:
Packit fd8b60
            keytab = self.keytab
Packit fd8b60
        output = self.run([klist, '-k', keytab], **keywords)
Packit fd8b60
        if (('Keytab name: FILE:%s\n' % keytab) not in output or
Packit fd8b60
            'KVNO Principal\n----' not in output or
Packit fd8b60
            princ not in output):
Packit fd8b60
            fail('Unexpected klist output.')
Packit fd8b60
Packit fd8b60
    def prep_kadmin(self, princname=None, pw=None, flags=[]):
Packit fd8b60
        if princname is None:
Packit fd8b60
            princname = self.admin_princ
Packit fd8b60
            pw = password('admin')
Packit fd8b60
        return self.kinit(princname, pw,
Packit fd8b60
                          flags=['-S', 'kadmin/admin',
Packit fd8b60
                                 '-c', self.kadmin_ccache] + flags)
Packit fd8b60
Packit fd8b60
    def run_kadmin(self, args, **keywords):
Packit fd8b60
        return self.run([kadmin, '-c', self.kadmin_ccache] + args, **keywords)
Packit fd8b60
Packit fd8b60
    def special_env(self, name, has_kdc_conf, krb5_conf=None, kdc_conf=None):
Packit fd8b60
        krb5_conf_path = os.path.join(self.testdir, 'krb5.conf.%s' % name)
Packit fd8b60
        krb5_conf = _cfg_merge(self._krb5_conf, krb5_conf)
Packit fd8b60
        self._create_conf(krb5_conf, krb5_conf_path)
Packit fd8b60
        if has_kdc_conf:
Packit fd8b60
            kdc_conf_path = os.path.join(self.testdir, 'kdc.conf.%s' % name)
Packit fd8b60
            kdc_conf = _cfg_merge(self._kdc_conf, kdc_conf)
Packit fd8b60
            self._create_conf(kdc_conf, kdc_conf_path)
Packit fd8b60
        else:
Packit fd8b60
            kdc_conf_path = None
Packit fd8b60
        return self._make_env(krb5_conf_path, kdc_conf_path)
Packit fd8b60
Packit fd8b60
Packit fd8b60
def multipass_realms(**keywords):
Packit fd8b60
    global _current_pass, _passes, testpass
Packit fd8b60
    caller_krb5_conf = keywords.get('krb5_conf')
Packit fd8b60
    caller_kdc_conf = keywords.get('kdc_conf')
Packit fd8b60
    for p in _passes:
Packit fd8b60
        (name, krbtgt_keysalt, krb5_conf, kdc_conf) = p
Packit fd8b60
        if testpass and name != testpass:
Packit fd8b60
            continue
Packit fd8b60
        output('*** Beginning pass %s\n' % name)
Packit fd8b60
        keywords['krb5_conf'] = _cfg_merge(krb5_conf, caller_krb5_conf)
Packit fd8b60
        keywords['kdc_conf'] = _cfg_merge(kdc_conf, caller_kdc_conf)
Packit fd8b60
        keywords['krbtgt_keysalt'] = krbtgt_keysalt
Packit fd8b60
        _current_pass = name
Packit fd8b60
        realm = K5Realm(**keywords)
Packit fd8b60
        yield realm
Packit fd8b60
        realm.stop()
Packit fd8b60
        _current_pass = None
Packit fd8b60
Packit fd8b60
Packit fd8b60
def multidb_realms(**keywords):
Packit fd8b60
    global _current_db, _dbpasses
Packit fd8b60
    caller_kdc_conf = keywords.get('kdc_conf')
Packit fd8b60
    for p in _dbpasses:
Packit fd8b60
        (name, kdc_conf) = p
Packit fd8b60
        output('*** Using DB type %s\n' % name)
Packit fd8b60
        keywords['kdc_conf'] = _cfg_merge(kdc_conf, caller_kdc_conf)
Packit fd8b60
        _current_db = name
Packit fd8b60
        realm = K5Realm(**keywords)
Packit fd8b60
        yield realm
Packit fd8b60
        realm.stop()
Packit fd8b60
        _current_db = None
Packit fd8b60
Packit fd8b60
Packit fd8b60
def cross_realms(num, xtgts=None, args=None, **keywords):
Packit fd8b60
    # Build keyword args for each realm.
Packit fd8b60
    realm_args = []
Packit fd8b60
    for i in range(num):
Packit fd8b60
        realmnumber = i + 1
Packit fd8b60
        # Start with any global keyword arguments to this function.
Packit fd8b60
        a = keywords.copy()
Packit fd8b60
        if args and args[i]:
Packit fd8b60
            # Merge in specific arguments for this realm.  Use
Packit fd8b60
            # _cfg_merge for config fragments.
Packit fd8b60
            a.update(args[i])
Packit fd8b60
            for cf in ('krb5_conf', 'kdc_conf'):
Packit fd8b60
                if cf in keywords and cf in args[i]:
Packit fd8b60
                    a[cf] = _cfg_merge(keywords[cf], args[i][cf])
Packit fd8b60
        # Set defaults for the realm name, testdir, and portbase.
Packit fd8b60
        if not 'realm' in a:
Packit fd8b60
            a['realm'] = 'KRBTEST%d.COM' % realmnumber
Packit fd8b60
        if not 'testdir' in a:
Packit fd8b60
            a['testdir'] = os.path.join('testdir', str(realmnumber))
Packit fd8b60
        if not 'portbase' in a:
Packit fd8b60
            a['portbase'] = 61000 + 10 * realmnumber
Packit fd8b60
        realm_args.append(a)
Packit fd8b60
        
Packit fd8b60
    # Build a [realms] config fragment containing all of the realms.
Packit fd8b60
    realmsection = { '$realm' : None }
Packit fd8b60
    for a in realm_args:
Packit fd8b60
        name = a['realm']
Packit fd8b60
        portbase = a['portbase']
Packit fd8b60
        realmsection[name] = {
Packit fd8b60
            'kdc' : '$hostname:%d' % portbase,
Packit fd8b60
            'admin_server' : '$hostname:%d' % (portbase + 1),
Packit fd8b60
            'kpasswd_server' : '$hostname:%d' % (portbase + 2)
Packit fd8b60
            }
Packit fd8b60
    realmscfg = {'realms': realmsection}
Packit fd8b60
Packit fd8b60
    # Set realmsection in each realm's krb5_conf keyword argument.
Packit fd8b60
    for a in realm_args:
Packit fd8b60
        a['krb5_conf'] = _cfg_merge(realmscfg, a.get('krb5_conf'))
Packit fd8b60
Packit fd8b60
    if xtgts is None:
Packit fd8b60
        # Default to cross tgts for every pair of realms.
Packit fd8b60
        # (itertools.permutations would work here but is new in 2.6.)
Packit fd8b60
        xtgts = [(x,y) for x in range(num) for y in range(num) if x != y]
Packit fd8b60
Packit fd8b60
    # Create the realms.
Packit fd8b60
    realms = []
Packit fd8b60
    for i in range(num):
Packit fd8b60
        r = K5Realm(**realm_args[i])
Packit fd8b60
        # Create specified cross TGTs in this realm's db.
Packit fd8b60
        for j in range(num):
Packit fd8b60
            if j == i:
Packit fd8b60
                continue
Packit fd8b60
            iname = r.realm
Packit fd8b60
            jname = realm_args[j]['realm']
Packit fd8b60
            if (i, j) in xtgts:
Packit fd8b60
                # This realm can authenticate to realm j.
Packit fd8b60
                r.addprinc('krbtgt/%s' % jname, password('cr-%d-%d-' % (i, j)))
Packit fd8b60
            if (j, i) in xtgts:
Packit fd8b60
                # Realm j can authenticate to this realm.
Packit fd8b60
                r.addprinc('krbtgt/%s@%s' % (iname, jname),
Packit fd8b60
                           password('cr-%d-%d-' % (j, i)))
Packit fd8b60
        realms.append(r)
Packit fd8b60
    return realms
Packit fd8b60
Packit fd8b60
Packit fd8b60
_default_krb5_conf = {
Packit fd8b60
    'libdefaults': {
Packit fd8b60
        'default_realm': '$realm',
Packit fd8b60
        'dns_lookup_kdc': 'false',
Packit fd8b60
        'plugin_base_dir': '$plugins'},
Packit fd8b60
    'realms': {'$realm': {
Packit fd8b60
            'kdc': '$hostname:$port0',
Packit fd8b60
            'admin_server': '$hostname:$port1',
Packit fd8b60
            'kpasswd_server': '$hostname:$port2'}}}
Packit fd8b60
Packit fd8b60
Packit fd8b60
_default_kdc_conf = {
Packit fd8b60
    'realms': {'$realm': {
Packit fd8b60
            'database_module': 'db',
Packit fd8b60
            'iprop_port': '$port4',
Packit fd8b60
            'key_stash_file': '$testdir/stash',
Packit fd8b60
            'acl_file': '$testdir/acl',
Packit fd8b60
            'dictfile': '$testdir/dictfile',
Packit fd8b60
            'kadmind_port': '$port1',
Packit fd8b60
            'kpasswd_port': '$port2',
Packit fd8b60
            'kdc_listen': '$port0',
Packit fd8b60
            'kdc_tcp_listen': '$port0'}},
Packit fd8b60
    'dbmodules': {
Packit fd8b60
        'db_module_dir': '$plugins/kdb',
Packit fd8b60
        'db': {'db_library': 'db2', 'database_name' : '$testdir/db'}},
Packit fd8b60
    'logging': {
Packit fd8b60
        'admin_server': 'FILE:$testdir/kadmind5.log',
Packit fd8b60
        'kdc': 'FILE:$testdir/kdc.log',
Packit fd8b60
        'default': 'FILE:$testdir/others.log'}}
Packit fd8b60
Packit fd8b60
Packit fd8b60
_lmdb_kdc_conf = {'dbmodules': {'db': {'db_library': 'klmdb',
Packit fd8b60
                                       'nosync': 'true'}}}
Packit fd8b60
Packit fd8b60
Packit fd8b60
# A pass is a tuple of: name, krbtgt_keysalt, krb5_conf, kdc_conf.
Packit fd8b60
_passes = [
Packit fd8b60
    # No special settings; exercises AES256.
Packit fd8b60
    ('default', None, None, None),
Packit fd8b60
Packit Service a81408
    # Exercise the DES3 enctype.
Packit Service a81408
    ('des3', None,
Packit Service a81408
     {'libdefaults': {'permitted_enctypes': 'des3'}},
Packit Service a81408
     {'realms': {'$realm': {
Packit Service a81408
                    'supported_enctypes': 'des3-cbc-sha1:normal',
Packit Service a81408
                    'master_key_type': 'des3-cbc-sha1'}}}),
Packit Service a81408
Packit fd8b60
    # Exercise the arcfour enctype.
Packit fd8b60
    ('arcfour', None,
Packit fd8b60
     {'libdefaults': {'permitted_enctypes': 'rc4'}},
Packit fd8b60
     {'realms': {'$realm': {
Packit fd8b60
                    'supported_enctypes': 'arcfour-hmac:normal',
Packit fd8b60
                    'master_key_type': 'arcfour-hmac'}}}),
Packit fd8b60
Packit fd8b60
    # Exercise the AES128 enctype.
Packit fd8b60
    ('aes128', None,
Packit fd8b60
      {'libdefaults': {'permitted_enctypes': 'aes128-cts'}},
Packit fd8b60
      {'realms': {'$realm': {
Packit fd8b60
                    'supported_enctypes': 'aes128-cts:normal',
Packit fd8b60
                    'master_key_type': 'aes128-cts'}}}),
Packit fd8b60
Packit fd8b60
    # Exercise the camellia256-cts enctype.
Packit fd8b60
    ('camellia256', None,
Packit fd8b60
      {'libdefaults': {'permitted_enctypes': 'camellia256-cts'}},
Packit fd8b60
      {'realms': {'$realm': {
Packit fd8b60
                    'supported_enctypes': 'camellia256-cts:normal',
Packit fd8b60
                    'master_key_type': 'camellia256-cts'}}}),
Packit fd8b60
Packit fd8b60
    # Exercise the aes128-sha2 enctype.
Packit fd8b60
    ('aes128-sha2', None,
Packit fd8b60
      {'libdefaults': {'permitted_enctypes': 'aes128-sha2'}},
Packit fd8b60
      {'realms': {'$realm': {
Packit fd8b60
                    'supported_enctypes': 'aes128-sha2:normal',
Packit fd8b60
                    'master_key_type': 'aes128-sha2'}}}),
Packit fd8b60
Packit fd8b60
    # Exercise the aes256-sha2 enctype.
Packit fd8b60
    ('aes256-sha2', None,
Packit fd8b60
      {'libdefaults': {'permitted_enctypes': 'aes256-sha2'}},
Packit fd8b60
      {'realms': {'$realm': {
Packit fd8b60
                    'supported_enctypes': 'aes256-sha2:normal',
Packit fd8b60
                    'master_key_type': 'aes256-sha2'}}}),
Packit fd8b60
Packit fd8b60
    # Test a setup with modern principal keys but an old TGT key.
Packit fd8b60
    ('aes256.destgt', 'arcfour-hmac:normal',
Packit fd8b60
     {'libdefaults': {'allow_weak_crypto': 'true'}},
Packit fd8b60
     None)
Packit fd8b60
]
Packit fd8b60
Packit fd8b60
_success = False
Packit fd8b60
_current_pass = None
Packit fd8b60
_current_db = None
Packit fd8b60
_daemons = []
Packit fd8b60
_parse_args()
Packit fd8b60
atexit.register(_onexit)
Packit fd8b60
signal.signal(signal.SIGINT, _onsigint)
Packit fd8b60
_outfile = open('testlog', 'w')
Packit fd8b60
_cmd_index = 1
Packit fd8b60
_last_mark = None
Packit fd8b60
_last_cmd = None
Packit fd8b60
_last_cmd_output = None
Packit fd8b60
buildtop = _find_buildtop()
Packit fd8b60
srctop = _find_srctop()
Packit fd8b60
plugins = os.path.join(buildtop, 'plugins')
Packit fd8b60
runenv = _import_runenv()
Packit fd8b60
hostname = _get_hostname()
Packit fd8b60
null_input = open(os.devnull, 'r')
Packit fd8b60
Packit fd8b60
# A DB pass is a tuple of: name, kdc_conf.
Packit fd8b60
_dbpasses = [('db2', None)]
Packit fd8b60
if runenv.have_lmdb == 'yes':
Packit fd8b60
    _dbpasses.append(('lmdb', _lmdb_kdc_conf))
Packit fd8b60
Packit fd8b60
krb5kdc = os.path.join(buildtop, 'kdc', 'krb5kdc')
Packit fd8b60
kadmind = os.path.join(buildtop, 'kadmin', 'server', 'kadmind')
Packit fd8b60
kadmin = os.path.join(buildtop, 'kadmin', 'cli', 'kadmin')
Packit fd8b60
kadminl = os.path.join(buildtop, 'kadmin', 'cli', 'kadmin.local')
Packit fd8b60
kdb5_ldap_util = os.path.join(buildtop, 'plugins', 'kdb', 'ldap', 'ldap_util',
Packit fd8b60
                              'kdb5_ldap_util')
Packit fd8b60
kdb5_util = os.path.join(buildtop, 'kadmin', 'dbutil', 'kdb5_util')
Packit fd8b60
ktutil = os.path.join(buildtop, 'kadmin', 'ktutil', 'ktutil')
Packit fd8b60
kinit = os.path.join(buildtop, 'clients', 'kinit', 'kinit')
Packit fd8b60
klist = os.path.join(buildtop, 'clients', 'klist', 'klist')
Packit fd8b60
kswitch = os.path.join(buildtop, 'clients', 'kswitch', 'kswitch')
Packit fd8b60
kvno = os.path.join(buildtop, 'clients', 'kvno', 'kvno')
Packit fd8b60
kdestroy = os.path.join(buildtop, 'clients', 'kdestroy', 'kdestroy')
Packit fd8b60
kpasswd = os.path.join(buildtop, 'clients', 'kpasswd', 'kpasswd')
Packit fd8b60
t_inetd = os.path.join(buildtop, 'tests', 'dejagnu', 't_inetd')
Packit fd8b60
kproplog = os.path.join(buildtop, 'kprop', 'kproplog')
Packit fd8b60
kpropd = os.path.join(buildtop, 'kprop', 'kpropd')
Packit fd8b60
kprop = os.path.join(buildtop, 'kprop', 'kprop')