1*7f2fe78bSCy Schubert# Copyright (C) 2010 by the Massachusetts Institute of Technology. 2*7f2fe78bSCy Schubert# All rights reserved. 3*7f2fe78bSCy Schubert 4*7f2fe78bSCy Schubert# Export of this software from the United States of America may 5*7f2fe78bSCy Schubert# require a specific license from the United States Government. 6*7f2fe78bSCy Schubert# It is the responsibility of any person or organization contemplating 7*7f2fe78bSCy Schubert# export to obtain such a license before exporting. 8*7f2fe78bSCy Schubert# 9*7f2fe78bSCy Schubert# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 10*7f2fe78bSCy Schubert# distribute this software and its documentation for any purpose and 11*7f2fe78bSCy Schubert# without fee is hereby granted, provided that the above copyright 12*7f2fe78bSCy Schubert# notice appear in all copies and that both that copyright notice and 13*7f2fe78bSCy Schubert# this permission notice appear in supporting documentation, and that 14*7f2fe78bSCy Schubert# the name of M.I.T. not be used in advertising or publicity pertaining 15*7f2fe78bSCy Schubert# to distribution of the software without specific, written prior 16*7f2fe78bSCy Schubert# permission. Furthermore if you modify this software you must label 17*7f2fe78bSCy Schubert# your software as modified software and not distribute it in such a 18*7f2fe78bSCy Schubert# fashion that it might be confused with the original M.I.T. software. 19*7f2fe78bSCy Schubert# M.I.T. makes no representations about the suitability of 20*7f2fe78bSCy Schubert# this software for any purpose. It is provided "as is" without express 21*7f2fe78bSCy Schubert# or implied warranty. 22*7f2fe78bSCy Schubert 23*7f2fe78bSCy Schubert"""A module for krb5 test scripts 24*7f2fe78bSCy Schubert 25*7f2fe78bSCy SchubertTo run test scripts during "make check" (if Python 2.5 or later is 26*7f2fe78bSCy Schubertavailable), add rules like the following to Makefile.in: 27*7f2fe78bSCy Schubert 28*7f2fe78bSCy Schubert check-pytests:: 29*7f2fe78bSCy Schubert $(RUNPYTEST) $(srcdir)/t_testname.py $(PYTESTFLAGS) 30*7f2fe78bSCy Schubert 31*7f2fe78bSCy SchubertA sample test script: 32*7f2fe78bSCy Schubert 33*7f2fe78bSCy Schubert from k5test import * 34*7f2fe78bSCy Schubert 35*7f2fe78bSCy Schubert # Run a test program under a variety of configurations: 36*7f2fe78bSCy Schubert for realm in multipass_realms(): 37*7f2fe78bSCy Schubert realm.run(['./testprog', 'arg']) 38*7f2fe78bSCy Schubert 39*7f2fe78bSCy Schubert # Run a test server and client under just the default configuration: 40*7f2fe78bSCy Schubert realm = K5Realm() 41*7f2fe78bSCy Schubert realm.start_server(['./serverprog'], 'starting...') 42*7f2fe78bSCy Schubert realm.run(['./clientprog', realm.host_princ]) 43*7f2fe78bSCy Schubert 44*7f2fe78bSCy Schubert # Inform framework that tests completed successfully. 45*7f2fe78bSCy Schubert success('World peace and cure for cancer') 46*7f2fe78bSCy Schubert 47*7f2fe78bSCy SchubertBy default, the realm will have: 48*7f2fe78bSCy Schubert 49*7f2fe78bSCy Schubert* The name KRBTEST.COM 50*7f2fe78bSCy Schubert* Listener ports starting at 61000 51*7f2fe78bSCy Schubert* krb5.conf and kdc.conf files 52*7f2fe78bSCy Schubert* A fresh DB2 KDB 53*7f2fe78bSCy Schubert* Running krb5kdc (but not kadmind) 54*7f2fe78bSCy Schubert* Principals named realm.user_princ and realm.admin_princ; call 55*7f2fe78bSCy Schubert password('user') and password('admin') to get the password 56*7f2fe78bSCy Schubert* Credentials for realm.user_princ in realm.ccache 57*7f2fe78bSCy Schubert* Admin rights for realm.admin_princ in the kadmind acl file 58*7f2fe78bSCy Schubert* A host principal named realm.host_princ with a random key 59*7f2fe78bSCy Schubert* A keytab for the host principal in realm.keytab 60*7f2fe78bSCy Schubert 61*7f2fe78bSCy SchubertThe realm's behaviour can be modified with the following constructor 62*7f2fe78bSCy Schubertkeyword arguments: 63*7f2fe78bSCy Schubert 64*7f2fe78bSCy Schubert* realm='realmname': Override the realm name 65*7f2fe78bSCy Schubert 66*7f2fe78bSCy Schubert* portbase=NNN: Override the listener port base; currently three ports are 67*7f2fe78bSCy Schubert used 68*7f2fe78bSCy Schubert 69*7f2fe78bSCy Schubert* testdir='dirname': Override the storage area for the realm's files 70*7f2fe78bSCy Schubert (path may be specified relative to the current working dir) 71*7f2fe78bSCy Schubert 72*7f2fe78bSCy Schubert* krb5_conf={ ... }: krb5.conf options, expressed as a nested 73*7f2fe78bSCy Schubert dictionary, to be merged with the default krb5.conf settings. A key 74*7f2fe78bSCy Schubert may be mapped to None to delete a setting from the defaults. A key 75*7f2fe78bSCy Schubert may be mapped to a list in order to create multiple settings for the 76*7f2fe78bSCy Schubert same variable name. Keys and values undergo the following template 77*7f2fe78bSCy Schubert substitutions: 78*7f2fe78bSCy Schubert 79*7f2fe78bSCy Schubert - $realm: The realm name 80*7f2fe78bSCy Schubert - $testdir: The realm storage directory (absolute path) 81*7f2fe78bSCy Schubert - $buildtop: The root of the build directory 82*7f2fe78bSCy Schubert - $srctop: The root of the source directory 83*7f2fe78bSCy Schubert - $plugins: The plugin directory in the build tree 84*7f2fe78bSCy Schubert - $certs: The PKINIT certificate directory in the source tree 85*7f2fe78bSCy Schubert - $hostname: The FQDN of the host 86*7f2fe78bSCy Schubert - $port0: The first listener port (portbase) 87*7f2fe78bSCy Schubert - ... 88*7f2fe78bSCy Schubert - $port9: The tenth listener port (portbase + 9) 89*7f2fe78bSCy Schubert 90*7f2fe78bSCy Schubert When choosing ports, note the following: 91*7f2fe78bSCy Schubert 92*7f2fe78bSCy Schubert - port0 is used in the default krb5.conf for the KDC 93*7f2fe78bSCy Schubert - port1 is used in the default krb5.conf for kadmind 94*7f2fe78bSCy Schubert - port2 is used in the default krb5.conf for kpasswd 95*7f2fe78bSCy Schubert - port3 is used in the default krb5.conf for kpropd 96*7f2fe78bSCy Schubert - port4 is used in the default krb5.conf for iprop (in kadmind) 97*7f2fe78bSCy Schubert - port5 is the return value of realm.server_port() 98*7f2fe78bSCy Schubert 99*7f2fe78bSCy Schubert* kdc_conf={...}: kdc.conf options, expressed as a nested dictionary, 100*7f2fe78bSCy Schubert to be merged with the default kdc.conf settings. The same 101*7f2fe78bSCy Schubert conventions and substitutions for krb5_conf apply. 102*7f2fe78bSCy Schubert 103*7f2fe78bSCy Schubert* create_kdb=False: Don't create a KDB. Implicitly disables all of 104*7f2fe78bSCy Schubert the other options since they all require a KDB. 105*7f2fe78bSCy Schubert 106*7f2fe78bSCy Schubert* krbtgt_keysalt='enctype:salttype': After creating the KDB, 107*7f2fe78bSCy Schubert regenerate the krbtgt key using the specified key/salt combination, 108*7f2fe78bSCy Schubert using a kadmin.local cpw query. 109*7f2fe78bSCy Schubert 110*7f2fe78bSCy Schubert* create_user=False: Don't create the user principal. Implies 111*7f2fe78bSCy Schubert get_creds=False. 112*7f2fe78bSCy Schubert 113*7f2fe78bSCy Schubert* create_host=False: Don't create the host principal or the associated 114*7f2fe78bSCy Schubert keytab. 115*7f2fe78bSCy Schubert 116*7f2fe78bSCy Schubert* start_kdc=False: Don't start the KDC. Implies get_creds=False. 117*7f2fe78bSCy Schubert 118*7f2fe78bSCy Schubert* start_kadmind=True: Start kadmind. 119*7f2fe78bSCy Schubert 120*7f2fe78bSCy Schubert* get_creds=False: Don't get user credentials. 121*7f2fe78bSCy Schubert 122*7f2fe78bSCy Schubert* bdb_only=True: Use the DB2 KDB module even if K5TEST_LMDB is set in 123*7f2fe78bSCy Schubert the environment. 124*7f2fe78bSCy Schubert 125*7f2fe78bSCy Schubert* pkinit=True: Configure a PKINIT anchor and KDC certificate. 126*7f2fe78bSCy Schubert 127*7f2fe78bSCy SchubertScripts may use the following functions and variables: 128*7f2fe78bSCy Schubert 129*7f2fe78bSCy Schubert* fail(message): Display message (plus leading marker and trailing 130*7f2fe78bSCy Schubert newline) and explanatory messages about debugging. 131*7f2fe78bSCy Schubert 132*7f2fe78bSCy Schubert* success(message): Indicate that the test script has completed 133*7f2fe78bSCy Schubert successfully. Suppresses the display of explanatory debugging 134*7f2fe78bSCy Schubert messages in the on-exit handler. message should briefly summarize 135*7f2fe78bSCy Schubert the operations tested; it will only be displayed (with leading 136*7f2fe78bSCy Schubert marker and trailing newline) if the script is running verbosely. 137*7f2fe78bSCy Schubert 138*7f2fe78bSCy Schubert* skipped(whatmsg, whymsg): Indicate that some tests were skipped. 139*7f2fe78bSCy Schubert whatmsg should concisely say what was skipped (e.g. "LDAP KDB 140*7f2fe78bSCy Schubert tests") and whymsg should give the reason (e.g. "because LDAP module 141*7f2fe78bSCy Schubert not built"). 142*7f2fe78bSCy Schubert 143*7f2fe78bSCy Schubert* skip_rest(message): Indicate that some tests were skipped, then exit 144*7f2fe78bSCy Schubert the current script. 145*7f2fe78bSCy Schubert 146*7f2fe78bSCy Schubert* output(message, force_verbose=False): Place message (without any 147*7f2fe78bSCy Schubert added newline) in testlog, and write it to stdout if running 148*7f2fe78bSCy Schubert verbosely. 149*7f2fe78bSCy Schubert 150*7f2fe78bSCy Schubert* mark(message): Place a divider message in the test output, to make 151*7f2fe78bSCy Schubert it easier to determine what part of the test script a command 152*7f2fe78bSCy Schubert invocation belongs to. The last mark message will also be displayed 153*7f2fe78bSCy Schubert if a command invocation fails. Do not include a newline in message. 154*7f2fe78bSCy Schubert 155*7f2fe78bSCy Schubert* which(progname): Return the location of progname in the executable 156*7f2fe78bSCy Schubert path, or None if it is not found. 157*7f2fe78bSCy Schubert 158*7f2fe78bSCy Schubert* password(name): Return a weakly random password based on name. The 159*7f2fe78bSCy Schubert password will be consistent across calls with the same name. 160*7f2fe78bSCy Schubert 161*7f2fe78bSCy Schubert* canonicalize_hostname(name, rdns=True): Return the DNS 162*7f2fe78bSCy Schubert canonicalization of name, optionally using reverse DNS. On error, 163*7f2fe78bSCy Schubert return name converted to lowercase. 164*7f2fe78bSCy Schubert 165*7f2fe78bSCy Schubert* stop_daemon(proc): Stop a daemon process started with 166*7f2fe78bSCy Schubert realm.start_server() or realm.start_in_inetd(). Only necessary if 167*7f2fe78bSCy Schubert the port needs to be reused; daemon processes will be stopped 168*7f2fe78bSCy Schubert automatically when the script exits. 169*7f2fe78bSCy Schubert 170*7f2fe78bSCy Schubert* multipass_realms(**keywords): This is an iterator function. Yields 171*7f2fe78bSCy Schubert a realm for each of the standard test passes, each of which alters 172*7f2fe78bSCy Schubert the default configuration in some way to exercise different parts of 173*7f2fe78bSCy Schubert the krb5 code base. keywords may contain any K5Realm initializer 174*7f2fe78bSCy Schubert keyword with the exception of krbtgt_keysalt, which will not be 175*7f2fe78bSCy Schubert honored. If keywords contains krb5_conf and/or kdc_conf fragments, 176*7f2fe78bSCy Schubert they will be merged with the default and per-pass specifications. 177*7f2fe78bSCy Schubert 178*7f2fe78bSCy Schubert* multidb_realms(**keywords): Yields a realm for multiple DB modules. 179*7f2fe78bSCy Schubert Currently DB2 and LMDB are included. Ideally LDAP would be 180*7f2fe78bSCy Schubert included, but setting up a test LDAP server currently requires a 181*7f2fe78bSCy Schubert one-second delay, so all LDAP tests are currently confined to 182*7f2fe78bSCy Schubert t_kdb.py. keywords may contain any K5Realm initializer. 183*7f2fe78bSCy Schubert 184*7f2fe78bSCy Schubert* cross_realms(num, xtgts=None, args=None, **keywords): This function 185*7f2fe78bSCy Schubert returns a list of num realms, where each realm's configuration knows 186*7f2fe78bSCy Schubert how to contact all of the realms. By default, each realm will 187*7f2fe78bSCy Schubert contain cross TGTs in both directions for all other realms; this 188*7f2fe78bSCy Schubert default may be overridden by specifying a collection of tuples in 189*7f2fe78bSCy Schubert the xtgts parameter, where each tuple is a pair of zero-based realm 190*7f2fe78bSCy Schubert indexes, indicating that the first realm can authenticate to the 191*7f2fe78bSCy Schubert second (i.e. krbtgt/secondrealm@firstrealm exists in both realm's 192*7f2fe78bSCy Schubert databases). If args is given, it should be a list of keyword 193*7f2fe78bSCy Schubert arguments specific to each realm; these will be merged with the 194*7f2fe78bSCy Schubert global keyword arguments passed to cross_realms, with specific 195*7f2fe78bSCy Schubert arguments taking priority. 196*7f2fe78bSCy Schubert 197*7f2fe78bSCy Schubert* buildtop: The top of the build directory (absolute path). 198*7f2fe78bSCy Schubert 199*7f2fe78bSCy Schubert* srctop: The top of the source directory (absolute path). 200*7f2fe78bSCy Schubert 201*7f2fe78bSCy Schubert* plugins: The plugin directory in the build tree (absolute path). 202*7f2fe78bSCy Schubert 203*7f2fe78bSCy Schubert* pkinit_enabled: True if the PKINIT plugin module is present in the 204*7f2fe78bSCy Schubert build directory. 205*7f2fe78bSCy Schubert 206*7f2fe78bSCy Schubert* pkinit_certs: The directory containing test PKINIT certificates. 207*7f2fe78bSCy Schubert 208*7f2fe78bSCy Schubert* hostname: The local hostname as it will initially appear in 209*7f2fe78bSCy Schubert krb5_sname_to_principal() results. (Shortname qualification is 210*7f2fe78bSCy Schubert turned off in the test environment to make this value easy to 211*7f2fe78bSCy Schubert discover from Python.) 212*7f2fe78bSCy Schubert 213*7f2fe78bSCy Schubert* null_input: A file opened to read /dev/null. 214*7f2fe78bSCy Schubert 215*7f2fe78bSCy Schubert* args: Positional arguments left over after flags are processed. 216*7f2fe78bSCy Schubert 217*7f2fe78bSCy Schubert* runenv: The contents of $srctop/runenv.py, containing a dictionary 218*7f2fe78bSCy Schubert 'env' which specifies additional variables to be added to the realm 219*7f2fe78bSCy Schubert environment, and a variable 'tls_impl', which indicates which TLS 220*7f2fe78bSCy Schubert implementation (if any) is being used by libkrb5's support for 221*7f2fe78bSCy Schubert contacting KDCs and kpasswd servers over HTTPS. 222*7f2fe78bSCy Schubert 223*7f2fe78bSCy Schubert* verbose: Whether the script is running verbosely. 224*7f2fe78bSCy Schubert 225*7f2fe78bSCy Schubert* testpass: The command-line test pass argument. The script does not 226*7f2fe78bSCy Schubert need to examine this argument in most cases; it will be honored in 227*7f2fe78bSCy Schubert multipass_realms(). 228*7f2fe78bSCy Schubert 229*7f2fe78bSCy Schubert* Pathname variables for programs within the build directory: 230*7f2fe78bSCy Schubert - krb5kdc 231*7f2fe78bSCy Schubert - kadmind 232*7f2fe78bSCy Schubert - kadmin 233*7f2fe78bSCy Schubert - kadminl (kadmin.local) 234*7f2fe78bSCy Schubert - kdb5_ldap_util 235*7f2fe78bSCy Schubert - kdb5_util 236*7f2fe78bSCy Schubert - ktutil 237*7f2fe78bSCy Schubert - kinit 238*7f2fe78bSCy Schubert - klist 239*7f2fe78bSCy Schubert - kswitch 240*7f2fe78bSCy Schubert - kvno 241*7f2fe78bSCy Schubert - kdestroy 242*7f2fe78bSCy Schubert - kpasswd 243*7f2fe78bSCy Schubert - t_inetd 244*7f2fe78bSCy Schubert - kproplog 245*7f2fe78bSCy Schubert - kpropd 246*7f2fe78bSCy Schubert - kprop 247*7f2fe78bSCy Schubert 248*7f2fe78bSCy SchubertScripts may use the following realm methods and attributes: 249*7f2fe78bSCy Schubert 250*7f2fe78bSCy Schubert* realm.run(args, env=None, **keywords): Run a command in a specified 251*7f2fe78bSCy Schubert environment (or the realm's environment by default), obeying the 252*7f2fe78bSCy Schubert command-line debugging options. Fail if the command does not return 253*7f2fe78bSCy Schubert 0. Log the command output appropriately, and return it as a single 254*7f2fe78bSCy Schubert multi-line string. Keyword arguments can contain input='string' to 255*7f2fe78bSCy Schubert send an input string to the command, expected_code=N to expect a 256*7f2fe78bSCy Schubert return code other than 0, expected_msg=MSG to expect a substring in 257*7f2fe78bSCy Schubert the command output, and expected_trace=('a', 'b', ...) to expect an 258*7f2fe78bSCy Schubert ordered series of line substrings in the command's KRB5_TRACE 259*7f2fe78bSCy Schubert output, or return_trace=True to return a tuple of the command output 260*7f2fe78bSCy Schubert and the trace output. 261*7f2fe78bSCy Schubert 262*7f2fe78bSCy Schubert* realm.kprop_port(): Returns a port number based on realm.portbase 263*7f2fe78bSCy Schubert intended for use by kprop and kpropd. 264*7f2fe78bSCy Schubert 265*7f2fe78bSCy Schubert* realm.server_port(): Returns a port number based on realm.portbase 266*7f2fe78bSCy Schubert intended for use by server processes. 267*7f2fe78bSCy Schubert 268*7f2fe78bSCy Schubert* realm.start_server(args, sentinel, env=None): Start a daemon 269*7f2fe78bSCy Schubert process. Wait until sentinel appears as a substring of a line in 270*7f2fe78bSCy Schubert the server process's stdout or stderr (which are folded together). 271*7f2fe78bSCy Schubert Returns a subprocess.Popen object which can be passed to 272*7f2fe78bSCy Schubert stop_daemon() to stop the server, or used to read from the server's 273*7f2fe78bSCy Schubert output. 274*7f2fe78bSCy Schubert 275*7f2fe78bSCy Schubert* realm.start_in_inetd(args, port=None, env=None): Begin a t_inetd 276*7f2fe78bSCy Schubert process which will spawn a server process after accepting a client 277*7f2fe78bSCy Schubert connection. If port is not specified, realm.server_port() will be 278*7f2fe78bSCy Schubert used. Returns a process object which can be passed to stop_daemon() 279*7f2fe78bSCy Schubert to stop the server. 280*7f2fe78bSCy Schubert 281*7f2fe78bSCy Schubert* realm.create_kdb(): Create a new KDB. 282*7f2fe78bSCy Schubert 283*7f2fe78bSCy Schubert* realm.start_kdc(args=[], env=None): Start a krb5kdc process. Errors 284*7f2fe78bSCy Schubert if a KDC is already running. If args is given, it contains a list 285*7f2fe78bSCy Schubert of additional krb5kdc arguments. 286*7f2fe78bSCy Schubert 287*7f2fe78bSCy Schubert* realm.stop_kdc(): Stop the krb5kdc process. Errors if no KDC is 288*7f2fe78bSCy Schubert running. 289*7f2fe78bSCy Schubert 290*7f2fe78bSCy Schubert* realm.start_kadmind(env=None): Start a kadmind process. Errors if a 291*7f2fe78bSCy Schubert kadmind is already running. 292*7f2fe78bSCy Schubert 293*7f2fe78bSCy Schubert* realm.stop_kadmind(): Stop the kadmind process. Errors if no 294*7f2fe78bSCy Schubert kadmind is running. 295*7f2fe78bSCy Schubert 296*7f2fe78bSCy Schubert* realm.stop(): Stop any daemon processes running on behalf of the 297*7f2fe78bSCy Schubert realm. 298*7f2fe78bSCy Schubert 299*7f2fe78bSCy Schubert* realm.addprinc(princname, password=None): Using kadmin.local, create 300*7f2fe78bSCy Schubert a principal in the KDB named princname, with either a random or 301*7f2fe78bSCy Schubert specified key. 302*7f2fe78bSCy Schubert 303*7f2fe78bSCy Schubert* realm.extract_keytab(princname, keytab): Using kadmin.local, create 304*7f2fe78bSCy Schubert a keytab for princname in the filename keytab. Uses the -norandkey 305*7f2fe78bSCy Schubert option to avoid re-randomizing princname's key. 306*7f2fe78bSCy Schubert 307*7f2fe78bSCy Schubert* realm.kinit(princname, password=None, flags=[]): Acquire credentials 308*7f2fe78bSCy Schubert for princname using kinit, with additional flags []. If password is 309*7f2fe78bSCy Schubert specified, it will be used as input to the kinit process; otherwise 310*7f2fe78bSCy Schubert flags must cause kinit not to need a password (e.g. by specifying a 311*7f2fe78bSCy Schubert keytab). 312*7f2fe78bSCy Schubert 313*7f2fe78bSCy Schubert* realm.pkinit(princ, **keywords): Acquire credentials for princ, 314*7f2fe78bSCy Schubert supplying a PKINIT identity of the basic user test certificate 315*7f2fe78bSCy Schubert (matching user@KRBTEST.COM). 316*7f2fe78bSCy Schubert 317*7f2fe78bSCy Schubert* realm.klist(client_princ, service_princ=None, ccache=None): Using 318*7f2fe78bSCy Schubert klist, list the credentials cache ccache (must be a filename; 319*7f2fe78bSCy Schubert self.ccache if not specified) and verify that the output shows 320*7f2fe78bSCy Schubert credentials for client_princ and service_princ (self.krbtgt_princ if 321*7f2fe78bSCy Schubert not specified). 322*7f2fe78bSCy Schubert 323*7f2fe78bSCy Schubert* realm.klist_keytab(princ, keytab=None): Using klist, list keytab 324*7f2fe78bSCy Schubert (must be a filename; self.keytab if not specified) and verify that 325*7f2fe78bSCy Schubert the output shows the keytab name and principal name. 326*7f2fe78bSCy Schubert 327*7f2fe78bSCy Schubert* realm.prep_kadmin(princname=None, password=None, flags=[]): Populate 328*7f2fe78bSCy Schubert realm.kadmin_ccache with a ticket which can be used to run kadmin. 329*7f2fe78bSCy Schubert If princname is not specified, realm.admin_princ and its default 330*7f2fe78bSCy Schubert password will be used. 331*7f2fe78bSCy Schubert 332*7f2fe78bSCy Schubert* realm.run_kadmin(args, **keywords): Run the specified query in 333*7f2fe78bSCy Schubert kadmin, using realm.kadmin_ccache to authenticate. Accepts the same 334*7f2fe78bSCy Schubert keyword arguments as run. 335*7f2fe78bSCy Schubert 336*7f2fe78bSCy Schubert* realm.special_env(name, has_kdc_conf, krb5_conf=None, 337*7f2fe78bSCy Schubert kdc_conf=None): Create an environment with a modified krb5.conf 338*7f2fe78bSCy Schubert and/or kdc.conf. The specified krb5_conf and kdc_conf fragments, if 339*7f2fe78bSCy Schubert any, will be merged with the realm's existing configuration. If 340*7f2fe78bSCy Schubert has_kdc_conf is false, the new environment will have no kdc.conf. 341*7f2fe78bSCy Schubert The environment returned by this method can be used with realm.run() 342*7f2fe78bSCy Schubert or similar methods. 343*7f2fe78bSCy Schubert 344*7f2fe78bSCy Schubert* realm.start_kpropd(env, args=[]): Start a kpropd process. Pass an 345*7f2fe78bSCy Schubert environment created with realm.special_env() for the replica. If 346*7f2fe78bSCy Schubert args is given, it contains a list of additional kpropd arguments. 347*7f2fe78bSCy Schubert Returns a handle to the kpropd process. 348*7f2fe78bSCy Schubert 349*7f2fe78bSCy Schubert* realm.run_kpropd_once(env, args=[]): Run kpropd once, using the -t 350*7f2fe78bSCy Schubert flag. Pass an environment created with realm.special_env() for the 351*7f2fe78bSCy Schubert replica. If args is given, it contains a list of additional kpropd 352*7f2fe78bSCy Schubert arguments. Returns the kpropd output. 353*7f2fe78bSCy Schubert 354*7f2fe78bSCy Schubert* realm.realm: The realm's name. 355*7f2fe78bSCy Schubert 356*7f2fe78bSCy Schubert* realm.testdir: The realm's storage directory (absolute path). 357*7f2fe78bSCy Schubert 358*7f2fe78bSCy Schubert* realm.portbase: The realm's first listener port. 359*7f2fe78bSCy Schubert 360*7f2fe78bSCy Schubert* realm.user_princ: The principal name user@<realmname>. 361*7f2fe78bSCy Schubert 362*7f2fe78bSCy Schubert* realm.admin_princ: The principal name user/admin@<realmname>. 363*7f2fe78bSCy Schubert 364*7f2fe78bSCy Schubert* realm.host_princ: The name of the host principal for this machine, 365*7f2fe78bSCy Schubert with realm. 366*7f2fe78bSCy Schubert 367*7f2fe78bSCy Schubert* realm.nfs_princ: The name of the nfs principal for this machine, 368*7f2fe78bSCy Schubert with realm. 369*7f2fe78bSCy Schubert 370*7f2fe78bSCy Schubert* realm.krbtgt_princ: The name of the krbtgt principal for the realm. 371*7f2fe78bSCy Schubert 372*7f2fe78bSCy Schubert* realm.keytab: A keytab file in realm.testdir. Initially contains a 373*7f2fe78bSCy Schubert host keytab unless disabled by the realm construction options. 374*7f2fe78bSCy Schubert 375*7f2fe78bSCy Schubert* realm.client_keytab: A keytab file in realm.testdir. Initially 376*7f2fe78bSCy Schubert nonexistent. 377*7f2fe78bSCy Schubert 378*7f2fe78bSCy Schubert* realm.ccache: A ccache file in realm.testdir. Initially contains 379*7f2fe78bSCy Schubert credentials for user unless disabled by the realm construction 380*7f2fe78bSCy Schubert options. 381*7f2fe78bSCy Schubert 382*7f2fe78bSCy Schubert* realm.kadmin_ccache: The ccache file initialized by prep_kadmin and 383*7f2fe78bSCy Schubert used by run_kadmin. 384*7f2fe78bSCy Schubert 385*7f2fe78bSCy Schubert* env: The realm's environment, extended from os.environ to point at 386*7f2fe78bSCy Schubert the realm's config files and the build tree's shared libraries. 387*7f2fe78bSCy Schubert 388*7f2fe78bSCy SchubertWhen the test script is run, its behavior can be modified with 389*7f2fe78bSCy Schubertcommand-line flags. These are documented in the --help output. 390*7f2fe78bSCy Schubert 391*7f2fe78bSCy Schubert""" 392*7f2fe78bSCy Schubert 393*7f2fe78bSCy Schubertimport atexit 394*7f2fe78bSCy Schubertimport fcntl 395*7f2fe78bSCy Schubertimport optparse 396*7f2fe78bSCy Schubertimport os 397*7f2fe78bSCy Schubertimport shlex 398*7f2fe78bSCy Schubertimport shutil 399*7f2fe78bSCy Schubertimport signal 400*7f2fe78bSCy Schubertimport socket 401*7f2fe78bSCy Schubertimport string 402*7f2fe78bSCy Schubertimport subprocess 403*7f2fe78bSCy Schubertimport sys 404*7f2fe78bSCy Schubert 405*7f2fe78bSCy Schubert# Used when most things go wrong (other than programming errors) so 406*7f2fe78bSCy Schubert# that the user sees an error message rather than a Python traceback, 407*7f2fe78bSCy Schubert# without help from the test script. The on-exit handler will display 408*7f2fe78bSCy Schubert# additional explanatory text. 409*7f2fe78bSCy Schubertdef fail(msg): 410*7f2fe78bSCy Schubert """Print a message and exit with failure.""" 411*7f2fe78bSCy Schubert global _current_pass 412*7f2fe78bSCy Schubert print("*** Failure:", msg) 413*7f2fe78bSCy Schubert if _last_mark: 414*7f2fe78bSCy Schubert print("*** Last mark: %s" % _last_mark) 415*7f2fe78bSCy Schubert if _last_cmd: 416*7f2fe78bSCy Schubert print("*** Last command (#%d): %s" % (_cmd_index - 1, _last_cmd)) 417*7f2fe78bSCy Schubert if _failed_daemon_output: 418*7f2fe78bSCy Schubert print('*** Output of failed daemon:') 419*7f2fe78bSCy Schubert sys.stdout.write(_failed_daemon_output) 420*7f2fe78bSCy Schubert elif _last_cmd_output: 421*7f2fe78bSCy Schubert print("*** Output of last command:") 422*7f2fe78bSCy Schubert sys.stdout.write(_last_cmd_output) 423*7f2fe78bSCy Schubert if _current_pass: 424*7f2fe78bSCy Schubert print("*** Failed in test pass:", _current_pass) 425*7f2fe78bSCy Schubert if _current_db: 426*7f2fe78bSCy Schubert print("*** Failed with db:", _current_db) 427*7f2fe78bSCy Schubert sys.exit(1) 428*7f2fe78bSCy Schubert 429*7f2fe78bSCy Schubert 430*7f2fe78bSCy Schubertdef success(msg): 431*7f2fe78bSCy Schubert global _success 432*7f2fe78bSCy Schubert _stop_daemons() 433*7f2fe78bSCy Schubert output('*** Success: %s\n' % msg) 434*7f2fe78bSCy Schubert _success = True 435*7f2fe78bSCy Schubert 436*7f2fe78bSCy Schubert 437*7f2fe78bSCy Schubertdef mark(msg): 438*7f2fe78bSCy Schubert global _last_mark 439*7f2fe78bSCy Schubert output('\n====== %s ======\n' % msg) 440*7f2fe78bSCy Schubert _last_mark = msg 441*7f2fe78bSCy Schubert 442*7f2fe78bSCy Schubert 443*7f2fe78bSCy Schubertdef skipped(whatmsg, whymsg): 444*7f2fe78bSCy Schubert output('*** Skipping: %s: %s\n' % (whatmsg, whymsg), force_verbose=True) 445*7f2fe78bSCy Schubert f = open(os.path.join(buildtop, 'skiptests'), 'a') 446*7f2fe78bSCy Schubert f.write('Skipped %s: %s\n' % (whatmsg, whymsg)) 447*7f2fe78bSCy Schubert f.close() 448*7f2fe78bSCy Schubert 449*7f2fe78bSCy Schubert 450*7f2fe78bSCy Schubertdef skip_rest(whatmsg, whymsg): 451*7f2fe78bSCy Schubert global _success 452*7f2fe78bSCy Schubert skipped(whatmsg, whymsg) 453*7f2fe78bSCy Schubert _stop_daemons() 454*7f2fe78bSCy Schubert _success = True 455*7f2fe78bSCy Schubert sys.exit(0) 456*7f2fe78bSCy Schubert 457*7f2fe78bSCy Schubert 458*7f2fe78bSCy Schubertdef output(msg, force_verbose=False): 459*7f2fe78bSCy Schubert """Output a message to testlog, and to stdout if running verbosely.""" 460*7f2fe78bSCy Schubert _outfile.write(msg) 461*7f2fe78bSCy Schubert if verbose or force_verbose: 462*7f2fe78bSCy Schubert sys.stdout.write(msg) 463*7f2fe78bSCy Schubert 464*7f2fe78bSCy Schubert 465*7f2fe78bSCy Schubert# Return the location of progname in the executable path, or None if 466*7f2fe78bSCy Schubert# it is not found. 467*7f2fe78bSCy Schubertdef which(progname): 468*7f2fe78bSCy Schubert for dir in os.environ["PATH"].split(os.pathsep): 469*7f2fe78bSCy Schubert path = os.path.join(dir, progname) 470*7f2fe78bSCy Schubert if os.access(path, os.X_OK): 471*7f2fe78bSCy Schubert return path 472*7f2fe78bSCy Schubert return None 473*7f2fe78bSCy Schubert 474*7f2fe78bSCy Schubert 475*7f2fe78bSCy Schubertdef password(name): 476*7f2fe78bSCy Schubert """Choose a weakly random password from name, consistent across calls.""" 477*7f2fe78bSCy Schubert return name + str(os.getpid()) 478*7f2fe78bSCy Schubert 479*7f2fe78bSCy Schubert 480*7f2fe78bSCy Schubertdef canonicalize_hostname(name, rdns=True): 481*7f2fe78bSCy Schubert """Canonicalize name using DNS, optionally with reverse DNS.""" 482*7f2fe78bSCy Schubert try: 483*7f2fe78bSCy Schubert ai = socket.getaddrinfo(name, None, 0, 0, 0, socket.AI_CANONNAME) 484*7f2fe78bSCy Schubert except socket.gaierror as e: 485*7f2fe78bSCy Schubert return name.lower() 486*7f2fe78bSCy Schubert (family, socktype, proto, canonname, sockaddr) = ai[0] 487*7f2fe78bSCy Schubert 488*7f2fe78bSCy Schubert if not rdns: 489*7f2fe78bSCy Schubert return canonname.lower() 490*7f2fe78bSCy Schubert 491*7f2fe78bSCy Schubert try: 492*7f2fe78bSCy Schubert rname = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD) 493*7f2fe78bSCy Schubert except socket.gaierror: 494*7f2fe78bSCy Schubert return canonname.lower() 495*7f2fe78bSCy Schubert return rname[0].lower() 496*7f2fe78bSCy Schubert 497*7f2fe78bSCy Schubert 498*7f2fe78bSCy Schubert# Exit handler which ensures processes are cleaned up and, on failure, 499*7f2fe78bSCy Schubert# prints messages to help developers debug the problem. 500*7f2fe78bSCy Schubertdef _onexit(): 501*7f2fe78bSCy Schubert global _daemons, _success, srctop, verbose 502*7f2fe78bSCy Schubert global _debug, _stop_before, _stop_after, _shell_before, _shell_after 503*7f2fe78bSCy Schubert if _debug or _stop_before or _stop_after or _shell_before or _shell_after: 504*7f2fe78bSCy Schubert # Wait before killing daemons in case one is being debugged. 505*7f2fe78bSCy Schubert sys.stdout.write('*** Press return to kill daemons and exit script: ') 506*7f2fe78bSCy Schubert sys.stdout.flush() 507*7f2fe78bSCy Schubert sys.stdin.readline() 508*7f2fe78bSCy Schubert for proc in _daemons: 509*7f2fe78bSCy Schubert os.kill(proc.pid, signal.SIGTERM) 510*7f2fe78bSCy Schubert _check_daemon(proc) 511*7f2fe78bSCy Schubert if not _success: 512*7f2fe78bSCy Schubert print 513*7f2fe78bSCy Schubert if not verbose: 514*7f2fe78bSCy Schubert testlogfile = os.path.join(os.getcwd(), 'testlog') 515*7f2fe78bSCy Schubert utildir = os.path.join(srctop, 'util') 516*7f2fe78bSCy Schubert print('For details, see: %s' % testlogfile) 517*7f2fe78bSCy Schubert print('Or re-run this test script with the -v flag:') 518*7f2fe78bSCy Schubert print(' cd %s' % os.getcwd()) 519*7f2fe78bSCy Schubert print(' PYTHONPATH=%s %s %s -v' % 520*7f2fe78bSCy Schubert (utildir, sys.executable, sys.argv[0])) 521*7f2fe78bSCy Schubert print() 522*7f2fe78bSCy Schubert print('Use --debug=NUM to run a command under a debugger. Use') 523*7f2fe78bSCy Schubert print('--stop-after=NUM to stop after a daemon is started in order to') 524*7f2fe78bSCy Schubert print('attach to it with a debugger. Use --help to see other') 525*7f2fe78bSCy Schubert print('options.') 526*7f2fe78bSCy Schubert 527*7f2fe78bSCy Schubert 528*7f2fe78bSCy Schubertdef _onsigint(signum, frame): 529*7f2fe78bSCy Schubert # Exit without displaying a stack trace. Suppress messages from _onexit. 530*7f2fe78bSCy Schubert global _success 531*7f2fe78bSCy Schubert _success = True 532*7f2fe78bSCy Schubert sys.exit(1) 533*7f2fe78bSCy Schubert 534*7f2fe78bSCy Schubert 535*7f2fe78bSCy Schubert# Find the parent of dir which is at the root of a build or source directory. 536*7f2fe78bSCy Schubertdef _find_root(dir): 537*7f2fe78bSCy Schubert while True: 538*7f2fe78bSCy Schubert if os.path.exists(os.path.join(dir, 'lib', 'krb5', 'krb')): 539*7f2fe78bSCy Schubert break 540*7f2fe78bSCy Schubert parent = os.path.dirname(dir) 541*7f2fe78bSCy Schubert if (parent == dir): 542*7f2fe78bSCy Schubert return None 543*7f2fe78bSCy Schubert dir = parent 544*7f2fe78bSCy Schubert return dir 545*7f2fe78bSCy Schubert 546*7f2fe78bSCy Schubert 547*7f2fe78bSCy Schubertdef _find_buildtop(): 548*7f2fe78bSCy Schubert root = _find_root(os.getcwd()) 549*7f2fe78bSCy Schubert if root is None: 550*7f2fe78bSCy Schubert fail('Cannot find root of krb5 build directory.') 551*7f2fe78bSCy Schubert if not os.path.exists(os.path.join(root, 'config.status')): 552*7f2fe78bSCy Schubert # Looks like an unbuilt source directory. 553*7f2fe78bSCy Schubert fail('This script must be run inside a krb5 build directory.') 554*7f2fe78bSCy Schubert return root 555*7f2fe78bSCy Schubert 556*7f2fe78bSCy Schubert 557*7f2fe78bSCy Schubertdef _find_srctop(): 558*7f2fe78bSCy Schubert scriptdir = os.path.abspath(os.path.dirname(sys.argv[0])) 559*7f2fe78bSCy Schubert if not scriptdir: 560*7f2fe78bSCy Schubert scriptdir = os.getcwd() 561*7f2fe78bSCy Schubert root = _find_root(scriptdir) 562*7f2fe78bSCy Schubert if root is None: 563*7f2fe78bSCy Schubert fail('Cannot find root of krb5 source directory.') 564*7f2fe78bSCy Schubert return os.path.abspath(root) 565*7f2fe78bSCy Schubert 566*7f2fe78bSCy Schubert 567*7f2fe78bSCy Schubert# Parse command line arguments, setting global option variables. Also 568*7f2fe78bSCy Schubert# sets the global variable args to the positional arguments, which may 569*7f2fe78bSCy Schubert# be used by the test script. 570*7f2fe78bSCy Schubertdef _parse_args(): 571*7f2fe78bSCy Schubert global args, verbose, testpass, _debug, _debugger_command 572*7f2fe78bSCy Schubert global _stop_before, _stop_after, _shell_before, _shell_after 573*7f2fe78bSCy Schubert parser = optparse.OptionParser() 574*7f2fe78bSCy Schubert parser.add_option('-v', '--verbose', action='store_true', dest='verbose', 575*7f2fe78bSCy Schubert default=False, help='Display verbose output') 576*7f2fe78bSCy Schubert parser.add_option('-p', '--pass', dest='testpass', metavar='PASS', 577*7f2fe78bSCy Schubert help='If a multi-pass test, run only PASS') 578*7f2fe78bSCy Schubert parser.add_option('--debug', dest='debug', metavar='NUM', 579*7f2fe78bSCy Schubert help='Debug numbered command (or "all")') 580*7f2fe78bSCy Schubert parser.add_option('--debugger', dest='debugger', metavar='COMMAND', 581*7f2fe78bSCy Schubert help='Debugger command (default is gdb --args)') 582*7f2fe78bSCy Schubert parser.add_option('--stop-before', dest='stopb', metavar='NUM', 583*7f2fe78bSCy Schubert help='Stop before numbered command (or "all")') 584*7f2fe78bSCy Schubert parser.add_option('--stop-after', dest='stopa', metavar='NUM', 585*7f2fe78bSCy Schubert help='Stop after numbered command (or "all")') 586*7f2fe78bSCy Schubert parser.add_option('--shell-before', dest='shellb', metavar='NUM', 587*7f2fe78bSCy Schubert help='Spawn shell before numbered command (or "all")') 588*7f2fe78bSCy Schubert parser.add_option('--shell-after', dest='shella', metavar='NUM', 589*7f2fe78bSCy Schubert help='Spawn shell after numbered command (or "all")') 590*7f2fe78bSCy Schubert (options, args) = parser.parse_args() 591*7f2fe78bSCy Schubert verbose = options.verbose 592*7f2fe78bSCy Schubert testpass = options.testpass 593*7f2fe78bSCy Schubert _debug = _parse_cmdnum('--debug', options.debug) 594*7f2fe78bSCy Schubert _stop_before = _parse_cmdnum('--stop-before', options.stopb) 595*7f2fe78bSCy Schubert _stop_after = _parse_cmdnum('--stop-after', options.stopa) 596*7f2fe78bSCy Schubert _shell_before = _parse_cmdnum('--shell-before', options.shellb) 597*7f2fe78bSCy Schubert _shell_after = _parse_cmdnum('--shell-after', options.shella) 598*7f2fe78bSCy Schubert 599*7f2fe78bSCy Schubert if options.debugger is not None: 600*7f2fe78bSCy Schubert _debugger_command = shlex.split(options.debugger) 601*7f2fe78bSCy Schubert elif which('gdb') is not None: 602*7f2fe78bSCy Schubert _debugger_command = ['gdb', '--args'] 603*7f2fe78bSCy Schubert elif which('lldb') is not None: 604*7f2fe78bSCy Schubert _debugger_command = ['lldb', '--'] 605*7f2fe78bSCy Schubert elif options.debug is not None: 606*7f2fe78bSCy Schubert print('Cannot find a debugger; use --debugger=COMMAND') 607*7f2fe78bSCy Schubert sys.exit(1) 608*7f2fe78bSCy Schubert 609*7f2fe78bSCy Schubert 610*7f2fe78bSCy Schubert# Translate a command number spec. -1 means all, None means none. 611*7f2fe78bSCy Schubertdef _parse_cmdnum(optname, str): 612*7f2fe78bSCy Schubert if not str: 613*7f2fe78bSCy Schubert return None 614*7f2fe78bSCy Schubert if str == 'all': 615*7f2fe78bSCy Schubert return -1 616*7f2fe78bSCy Schubert try: 617*7f2fe78bSCy Schubert return int(str) 618*7f2fe78bSCy Schubert except ValueError: 619*7f2fe78bSCy Schubert fail('%s value must be "all" or a number' % optname) 620*7f2fe78bSCy Schubert 621*7f2fe78bSCy Schubert 622*7f2fe78bSCy Schubert# Test if a command index matches a translated command number spec. 623*7f2fe78bSCy Schubertdef _match_cmdnum(cmdnum, ind): 624*7f2fe78bSCy Schubert if cmdnum is None: 625*7f2fe78bSCy Schubert return False 626*7f2fe78bSCy Schubert elif cmdnum == -1: 627*7f2fe78bSCy Schubert return True 628*7f2fe78bSCy Schubert else: 629*7f2fe78bSCy Schubert return cmdnum == ind 630*7f2fe78bSCy Schubert 631*7f2fe78bSCy Schubert 632*7f2fe78bSCy Schubert# Return an environment suitable for running programs in the build 633*7f2fe78bSCy Schubert# tree. It is safe to modify the result. 634*7f2fe78bSCy Schubertdef _build_env(): 635*7f2fe78bSCy Schubert global buildtop, runenv 636*7f2fe78bSCy Schubert env = os.environ.copy() 637*7f2fe78bSCy Schubert for (k, v) in runenv.env.items(): 638*7f2fe78bSCy Schubert if v.find('./') == 0: 639*7f2fe78bSCy Schubert env[k] = os.path.join(buildtop, v) 640*7f2fe78bSCy Schubert else: 641*7f2fe78bSCy Schubert env[k] = v 642*7f2fe78bSCy Schubert # Make sure we don't get confused by translated messages 643*7f2fe78bSCy Schubert # or localized times. 644*7f2fe78bSCy Schubert env['LC_ALL'] = 'C' 645*7f2fe78bSCy Schubert return env 646*7f2fe78bSCy Schubert 647*7f2fe78bSCy Schubert 648*7f2fe78bSCy Schubert# Merge the nested dictionaries cfg1 and cfg2 into a new dictionary. 649*7f2fe78bSCy Schubert# cfg1 or cfg2 may be None, in which case the other is returned. If 650*7f2fe78bSCy Schubert# cfg2 contains keys mapped to None, the corresponding keys will be 651*7f2fe78bSCy Schubert# mapped to None in the result. The result may contain references to 652*7f2fe78bSCy Schubert# parts of cfg1 or cfg2, so is not safe to modify. 653*7f2fe78bSCy Schubertdef _cfg_merge(cfg1, cfg2): 654*7f2fe78bSCy Schubert if not cfg2: 655*7f2fe78bSCy Schubert return cfg1 656*7f2fe78bSCy Schubert if not cfg1: 657*7f2fe78bSCy Schubert return cfg2 658*7f2fe78bSCy Schubert result = cfg1.copy() 659*7f2fe78bSCy Schubert for key, value2 in cfg2.items(): 660*7f2fe78bSCy Schubert if value2 is None: 661*7f2fe78bSCy Schubert result.pop(key, None) 662*7f2fe78bSCy Schubert elif key not in result: 663*7f2fe78bSCy Schubert result[key] = value2 664*7f2fe78bSCy Schubert else: 665*7f2fe78bSCy Schubert value1 = result[key] 666*7f2fe78bSCy Schubert if isinstance(value1, dict): 667*7f2fe78bSCy Schubert if not isinstance(value2, dict): 668*7f2fe78bSCy Schubert raise TypeError() 669*7f2fe78bSCy Schubert result[key] = _cfg_merge(value1, value2) 670*7f2fe78bSCy Schubert else: 671*7f2fe78bSCy Schubert result[key] = value2 672*7f2fe78bSCy Schubert return result 673*7f2fe78bSCy Schubert 674*7f2fe78bSCy Schubert 675*7f2fe78bSCy Schubert# Python gives us shlex.split() to turn a shell command into a list of 676*7f2fe78bSCy Schubert# arguments, but oddly enough, not the easier reverse operation. For 677*7f2fe78bSCy Schubert# now, do a bad job of faking it. 678*7f2fe78bSCy Schubertdef _shell_equiv(args): 679*7f2fe78bSCy Schubert return " ".join(args) 680*7f2fe78bSCy Schubert 681*7f2fe78bSCy Schubert 682*7f2fe78bSCy Schubert# Add a valgrind prefix to the front of args if specified in the 683*7f2fe78bSCy Schubert# environment. Under normal circumstances this just returns args. 684*7f2fe78bSCy Schubertdef _valgrind(args): 685*7f2fe78bSCy Schubert valgrind = os.getenv('VALGRIND') 686*7f2fe78bSCy Schubert if valgrind: 687*7f2fe78bSCy Schubert args = shlex.split(valgrind) + args 688*7f2fe78bSCy Schubert return args 689*7f2fe78bSCy Schubert 690*7f2fe78bSCy Schubert 691*7f2fe78bSCy Schubertdef _stop_or_shell(stop, shell, env, ind): 692*7f2fe78bSCy Schubert if (_match_cmdnum(stop, ind)): 693*7f2fe78bSCy Schubert sys.stdout.write('*** [%d] Waiting for return: ' % ind) 694*7f2fe78bSCy Schubert sys.stdout.flush() 695*7f2fe78bSCy Schubert sys.stdin.readline() 696*7f2fe78bSCy Schubert if (_match_cmdnum(shell, ind)): 697*7f2fe78bSCy Schubert output('*** [%d] Spawning shell\n' % ind, True) 698*7f2fe78bSCy Schubert subprocess.call(os.getenv('SHELL'), env=env) 699*7f2fe78bSCy Schubert 700*7f2fe78bSCy Schubert 701*7f2fe78bSCy Schubert# Look for the expected strings in successive lines of trace. 702*7f2fe78bSCy Schubertdef _check_trace(trace, expected): 703*7f2fe78bSCy Schubert i = 0 704*7f2fe78bSCy Schubert for line in trace.splitlines(): 705*7f2fe78bSCy Schubert if i < len(expected) and expected[i] in line: 706*7f2fe78bSCy Schubert i += 1 707*7f2fe78bSCy Schubert if i < len(expected): 708*7f2fe78bSCy Schubert fail('Expected string not found in trace output: ' + expected[i]) 709*7f2fe78bSCy Schubert 710*7f2fe78bSCy Schubert 711*7f2fe78bSCy Schubertdef _run_cmd(args, env, input=None, expected_code=0, expected_msg=None, 712*7f2fe78bSCy Schubert expected_trace=None, return_trace=False): 713*7f2fe78bSCy Schubert global null_input, _cmd_index, _last_cmd, _last_cmd_output, _debug 714*7f2fe78bSCy Schubert global _stop_before, _stop_after, _shell_before, _shell_after 715*7f2fe78bSCy Schubert 716*7f2fe78bSCy Schubert tracefile = None 717*7f2fe78bSCy Schubert if expected_trace is not None or return_trace: 718*7f2fe78bSCy Schubert tracefile = 'testtrace' 719*7f2fe78bSCy Schubert if os.path.exists(tracefile): 720*7f2fe78bSCy Schubert os.remove(tracefile) 721*7f2fe78bSCy Schubert env = env.copy() 722*7f2fe78bSCy Schubert env['KRB5_TRACE'] = tracefile 723*7f2fe78bSCy Schubert 724*7f2fe78bSCy Schubert if (_match_cmdnum(_debug, _cmd_index)): 725*7f2fe78bSCy Schubert return _debug_cmd(args, env, input) 726*7f2fe78bSCy Schubert 727*7f2fe78bSCy Schubert args = _valgrind(args) 728*7f2fe78bSCy Schubert _last_cmd = _shell_equiv(args) 729*7f2fe78bSCy Schubert 730*7f2fe78bSCy Schubert output('*** [%d] Executing: %s\n' % (_cmd_index, _last_cmd)) 731*7f2fe78bSCy Schubert _stop_or_shell(_stop_before, _shell_before, env, _cmd_index) 732*7f2fe78bSCy Schubert 733*7f2fe78bSCy Schubert if input: 734*7f2fe78bSCy Schubert infile = subprocess.PIPE 735*7f2fe78bSCy Schubert else: 736*7f2fe78bSCy Schubert infile = null_input 737*7f2fe78bSCy Schubert 738*7f2fe78bSCy Schubert # Run the command and log the result, folding stderr into stdout. 739*7f2fe78bSCy Schubert proc = subprocess.Popen(args, stdin=infile, stdout=subprocess.PIPE, 740*7f2fe78bSCy Schubert stderr=subprocess.STDOUT, env=env, 741*7f2fe78bSCy Schubert universal_newlines=True) 742*7f2fe78bSCy Schubert (outdata, dummy_errdata) = proc.communicate(input) 743*7f2fe78bSCy Schubert _last_cmd_output = outdata 744*7f2fe78bSCy Schubert code = proc.returncode 745*7f2fe78bSCy Schubert output(outdata) 746*7f2fe78bSCy Schubert output('*** [%d] Completed with return code %d\n' % (_cmd_index, code)) 747*7f2fe78bSCy Schubert _stop_or_shell(_stop_after, _shell_after, env, _cmd_index) 748*7f2fe78bSCy Schubert _cmd_index += 1 749*7f2fe78bSCy Schubert 750*7f2fe78bSCy Schubert # Check the return code and return the output. 751*7f2fe78bSCy Schubert if code != expected_code: 752*7f2fe78bSCy Schubert fail('%s failed with code %d.' % (args[0], code)) 753*7f2fe78bSCy Schubert 754*7f2fe78bSCy Schubert if expected_msg is not None and expected_msg not in outdata: 755*7f2fe78bSCy Schubert fail('Expected string not found in command output: ' + expected_msg) 756*7f2fe78bSCy Schubert 757*7f2fe78bSCy Schubert if tracefile is not None: 758*7f2fe78bSCy Schubert with open(tracefile, 'r') as f: 759*7f2fe78bSCy Schubert trace = f.read() 760*7f2fe78bSCy Schubert output('*** Trace output for previous command:\n') 761*7f2fe78bSCy Schubert output(trace) 762*7f2fe78bSCy Schubert if expected_trace is not None: 763*7f2fe78bSCy Schubert _check_trace(trace, expected_trace) 764*7f2fe78bSCy Schubert 765*7f2fe78bSCy Schubert return (outdata, trace) if return_trace else outdata 766*7f2fe78bSCy Schubert 767*7f2fe78bSCy Schubert 768*7f2fe78bSCy Schubertdef _debug_cmd(args, env, input): 769*7f2fe78bSCy Schubert global _cmd_index, _debugger_command 770*7f2fe78bSCy Schubert 771*7f2fe78bSCy Schubert args = _debugger_command + list(args) 772*7f2fe78bSCy Schubert output('*** [%d] Executing in debugger: %s\n' % 773*7f2fe78bSCy Schubert (_cmd_index, _shell_equiv(args)), True) 774*7f2fe78bSCy Schubert if input: 775*7f2fe78bSCy Schubert print 776*7f2fe78bSCy Schubert print('*** Enter the following input when appropriate:') 777*7f2fe78bSCy Schubert print() 778*7f2fe78bSCy Schubert print(input) 779*7f2fe78bSCy Schubert print() 780*7f2fe78bSCy Schubert code = subprocess.call(args, env=env) 781*7f2fe78bSCy Schubert output('*** [%d] Completed in debugger with return code %d\n' % 782*7f2fe78bSCy Schubert (_cmd_index, code)) 783*7f2fe78bSCy Schubert _cmd_index += 1 784*7f2fe78bSCy Schubert 785*7f2fe78bSCy Schubert 786*7f2fe78bSCy Schubert# Start a daemon process with the specified args and env. Wait until 787*7f2fe78bSCy Schubert# we see sentinel as a substring of a line on either stdout or stderr. 788*7f2fe78bSCy Schubert# Clean up the daemon process on exit. 789*7f2fe78bSCy Schubertdef _start_daemon(args, env, sentinel): 790*7f2fe78bSCy Schubert global null_input, _cmd_index, _last_cmd, _last_cmd_output, _debug 791*7f2fe78bSCy Schubert global _stop_before, _stop_after, _shell_before, _shell_after 792*7f2fe78bSCy Schubert 793*7f2fe78bSCy Schubert if (_match_cmdnum(_debug, _cmd_index)): 794*7f2fe78bSCy Schubert output('*** [%d] Warning: ' % _cmd_index, True) 795*7f2fe78bSCy Schubert output( 'test script cannot proceed after debugging a daemon\n', True) 796*7f2fe78bSCy Schubert _debug_cmd(args, env, None) 797*7f2fe78bSCy Schubert output('*** Exiting after debugging daemon\n', True) 798*7f2fe78bSCy Schubert sys.exit(1) 799*7f2fe78bSCy Schubert 800*7f2fe78bSCy Schubert args = _valgrind(args) 801*7f2fe78bSCy Schubert _last_cmd = _shell_equiv(args) 802*7f2fe78bSCy Schubert output('*** [%d] Starting: %s\n' % (_cmd_index, _last_cmd)) 803*7f2fe78bSCy Schubert _stop_or_shell(_stop_before, _shell_before, env, _cmd_index) 804*7f2fe78bSCy Schubert 805*7f2fe78bSCy Schubert # Start the daemon and look for the sentinel in stdout or stderr. 806*7f2fe78bSCy Schubert proc = subprocess.Popen(args, stdin=null_input, stdout=subprocess.PIPE, 807*7f2fe78bSCy Schubert stderr=subprocess.STDOUT, env=env, 808*7f2fe78bSCy Schubert universal_newlines=True) 809*7f2fe78bSCy Schubert _last_cmd_output = '' 810*7f2fe78bSCy Schubert while True: 811*7f2fe78bSCy Schubert line = proc.stdout.readline() 812*7f2fe78bSCy Schubert _last_cmd_output += line 813*7f2fe78bSCy Schubert if line == "": 814*7f2fe78bSCy Schubert code = proc.wait() 815*7f2fe78bSCy Schubert fail('%s failed to start with code %d.' % (args[0], code)) 816*7f2fe78bSCy Schubert output(line) 817*7f2fe78bSCy Schubert if sentinel in line: 818*7f2fe78bSCy Schubert break 819*7f2fe78bSCy Schubert output('*** [%d] Started with pid %d\n' % (_cmd_index, proc.pid)) 820*7f2fe78bSCy Schubert _stop_or_shell(_stop_after, _shell_after, env, _cmd_index) 821*7f2fe78bSCy Schubert _cmd_index += 1 822*7f2fe78bSCy Schubert 823*7f2fe78bSCy Schubert # Save the daemon in a list for cleanup. Note that we won't read 824*7f2fe78bSCy Schubert # any more of the daemon's output after the sentinel, which will 825*7f2fe78bSCy Schubert # cause the daemon to block if it generates enough. For now we 826*7f2fe78bSCy Schubert # assume all daemon processes are quiet enough to avoid this 827*7f2fe78bSCy Schubert # problem. If it causes an issue, some alternatives are: 828*7f2fe78bSCy Schubert # - Output to a file and poll the file for the sentinel 829*7f2fe78bSCy Schubert # (undesirable because it slows down the test suite by the 830*7f2fe78bSCy Schubert # polling interval times the number of daemons started) 831*7f2fe78bSCy Schubert # - Create an intermediate subprocess which discards output 832*7f2fe78bSCy Schubert # after the sentinel. 833*7f2fe78bSCy Schubert _daemons.append(proc) 834*7f2fe78bSCy Schubert 835*7f2fe78bSCy Schubert # Return the process; the caller can stop it with stop_daemon. 836*7f2fe78bSCy Schubert return proc 837*7f2fe78bSCy Schubert 838*7f2fe78bSCy Schubert 839*7f2fe78bSCy Schubert# Await a daemon process's exit status and display it if it isn't 840*7f2fe78bSCy Schubert# successful. Display any output it generated after the sentinel. 841*7f2fe78bSCy Schubert# Return the daemon's exit status (0 if it terminated with SIGTERM). 842*7f2fe78bSCy Schubertdef _check_daemon(proc): 843*7f2fe78bSCy Schubert global _failed_daemon_output 844*7f2fe78bSCy Schubert code = proc.wait() 845*7f2fe78bSCy Schubert # If a daemon doesn't catch SIGTERM (like gss-server), treat it as 846*7f2fe78bSCy Schubert # a normal exit. 847*7f2fe78bSCy Schubert if code == -signal.SIGTERM: 848*7f2fe78bSCy Schubert code = 0 849*7f2fe78bSCy Schubert if code != 0: 850*7f2fe78bSCy Schubert output('*** Daemon pid %d exited with code %d\n' % (proc.pid, code)) 851*7f2fe78bSCy Schubert 852*7f2fe78bSCy Schubert out, err = proc.communicate() 853*7f2fe78bSCy Schubert if code != 0: 854*7f2fe78bSCy Schubert _failed_daemon_output = out 855*7f2fe78bSCy Schubert output('*** Daemon pid %d output:\n' % proc.pid) 856*7f2fe78bSCy Schubert output(out) 857*7f2fe78bSCy Schubert 858*7f2fe78bSCy Schubert return code 859*7f2fe78bSCy Schubert 860*7f2fe78bSCy Schubert 861*7f2fe78bSCy Schubert# Terminate all active daemon processes. Fail out if any of them 862*7f2fe78bSCy Schubert# exited unsuccessfully. 863*7f2fe78bSCy Schubertdef _stop_daemons(): 864*7f2fe78bSCy Schubert global _daemons 865*7f2fe78bSCy Schubert daemon_error = False 866*7f2fe78bSCy Schubert for proc in _daemons: 867*7f2fe78bSCy Schubert os.kill(proc.pid, signal.SIGTERM) 868*7f2fe78bSCy Schubert code = _check_daemon(proc) 869*7f2fe78bSCy Schubert if code != 0: 870*7f2fe78bSCy Schubert daemon_error = True 871*7f2fe78bSCy Schubert _daemons = [] 872*7f2fe78bSCy Schubert if daemon_error: 873*7f2fe78bSCy Schubert fail('One or more daemon processes exited with an error') 874*7f2fe78bSCy Schubert 875*7f2fe78bSCy Schubert 876*7f2fe78bSCy Schubert# Wait for a daemon process to exit. Fail out if it exits 877*7f2fe78bSCy Schubert# unsuccessfully. 878*7f2fe78bSCy Schubertdef await_daemon_exit(proc): 879*7f2fe78bSCy Schubert code = _check_daemon(proc) 880*7f2fe78bSCy Schubert _daemons.remove(proc) 881*7f2fe78bSCy Schubert if code != 0: 882*7f2fe78bSCy Schubert fail('Daemon exited unsuccessfully') 883*7f2fe78bSCy Schubert 884*7f2fe78bSCy Schubert 885*7f2fe78bSCy Schubert# Terminate one daemon process. Fail out if it exits unsuccessfully. 886*7f2fe78bSCy Schubertdef stop_daemon(proc): 887*7f2fe78bSCy Schubert os.kill(proc.pid, signal.SIGTERM) 888*7f2fe78bSCy Schubert return await_daemon_exit(proc) 889*7f2fe78bSCy Schubert 890*7f2fe78bSCy Schubert 891*7f2fe78bSCy Schubertclass K5Realm(object): 892*7f2fe78bSCy Schubert """An object representing a functional krb5 test realm.""" 893*7f2fe78bSCy Schubert 894*7f2fe78bSCy Schubert def __init__(self, realm='KRBTEST.COM', portbase=61000, testdir='testdir', 895*7f2fe78bSCy Schubert krb5_conf=None, kdc_conf=None, create_kdb=True, 896*7f2fe78bSCy Schubert krbtgt_keysalt=None, create_user=True, get_creds=True, 897*7f2fe78bSCy Schubert create_host=True, start_kdc=True, start_kadmind=False, 898*7f2fe78bSCy Schubert start_kpropd=False, bdb_only=False, pkinit=False): 899*7f2fe78bSCy Schubert global hostname, _default_krb5_conf, _default_kdc_conf 900*7f2fe78bSCy Schubert global _lmdb_kdc_conf, _current_db 901*7f2fe78bSCy Schubert 902*7f2fe78bSCy Schubert self.realm = realm 903*7f2fe78bSCy Schubert self.testdir = os.path.join(os.getcwd(), testdir) 904*7f2fe78bSCy Schubert self.portbase = portbase 905*7f2fe78bSCy Schubert self.user_princ = 'user@' + self.realm 906*7f2fe78bSCy Schubert self.admin_princ = 'user/admin@' + self.realm 907*7f2fe78bSCy Schubert self.host_princ = 'host/%s@%s' % (hostname, self.realm) 908*7f2fe78bSCy Schubert self.nfs_princ = 'nfs/%s@%s' % (hostname, self.realm) 909*7f2fe78bSCy Schubert self.krbtgt_princ = 'krbtgt/%s@%s' % (self.realm, self.realm) 910*7f2fe78bSCy Schubert self.keytab = os.path.join(self.testdir, 'keytab') 911*7f2fe78bSCy Schubert self.client_keytab = os.path.join(self.testdir, 'client_keytab') 912*7f2fe78bSCy Schubert self.ccache = os.path.join(self.testdir, 'ccache') 913*7f2fe78bSCy Schubert self.gss_mech_config = os.path.join(self.testdir, 'mech.conf') 914*7f2fe78bSCy Schubert self.kadmin_ccache = os.path.join(self.testdir, 'kadmin_ccache') 915*7f2fe78bSCy Schubert base_krb5_conf = _default_krb5_conf 916*7f2fe78bSCy Schubert base_kdc_conf = _default_kdc_conf 917*7f2fe78bSCy Schubert if (os.getenv('K5TEST_LMDB') is not None and 918*7f2fe78bSCy Schubert not bdb_only and not _current_db): 919*7f2fe78bSCy Schubert base_kdc_conf = _cfg_merge(base_kdc_conf, _lmdb_kdc_conf) 920*7f2fe78bSCy Schubert if pkinit: 921*7f2fe78bSCy Schubert base_krb5_conf = _cfg_merge(base_krb5_conf, _pkinit_krb5_conf) 922*7f2fe78bSCy Schubert base_kdc_conf = _cfg_merge(base_kdc_conf, _pkinit_kdc_conf) 923*7f2fe78bSCy Schubert self._krb5_conf = _cfg_merge(base_krb5_conf, krb5_conf) 924*7f2fe78bSCy Schubert self._kdc_conf = _cfg_merge(base_kdc_conf, kdc_conf) 925*7f2fe78bSCy Schubert self._kdc_proc = None 926*7f2fe78bSCy Schubert self._kadmind_proc = None 927*7f2fe78bSCy Schubert self._kpropd_procs = [] 928*7f2fe78bSCy Schubert krb5_conf_path = os.path.join(self.testdir, 'krb5.conf') 929*7f2fe78bSCy Schubert kdc_conf_path = os.path.join(self.testdir, 'kdc.conf') 930*7f2fe78bSCy Schubert self.env = self._make_env(krb5_conf_path, kdc_conf_path) 931*7f2fe78bSCy Schubert 932*7f2fe78bSCy Schubert self._create_empty_dir() 933*7f2fe78bSCy Schubert self._create_conf(self._krb5_conf, krb5_conf_path) 934*7f2fe78bSCy Schubert self._create_conf(self._kdc_conf, kdc_conf_path) 935*7f2fe78bSCy Schubert self._create_acl() 936*7f2fe78bSCy Schubert self._create_dictfile() 937*7f2fe78bSCy Schubert 938*7f2fe78bSCy Schubert if create_kdb: 939*7f2fe78bSCy Schubert self.create_kdb() 940*7f2fe78bSCy Schubert if krbtgt_keysalt and create_kdb: 941*7f2fe78bSCy Schubert self.run([kadminl, 'cpw', '-randkey', '-e', krbtgt_keysalt, 942*7f2fe78bSCy Schubert self.krbtgt_princ]) 943*7f2fe78bSCy Schubert if create_user and create_kdb: 944*7f2fe78bSCy Schubert self.addprinc(self.user_princ, password('user')) 945*7f2fe78bSCy Schubert self.addprinc(self.admin_princ, password('admin')) 946*7f2fe78bSCy Schubert if create_host and create_kdb: 947*7f2fe78bSCy Schubert self.addprinc(self.host_princ) 948*7f2fe78bSCy Schubert self.extract_keytab(self.host_princ, self.keytab) 949*7f2fe78bSCy Schubert if start_kdc and create_kdb: 950*7f2fe78bSCy Schubert self.start_kdc() 951*7f2fe78bSCy Schubert if start_kadmind and create_kdb: 952*7f2fe78bSCy Schubert self.start_kadmind() 953*7f2fe78bSCy Schubert if get_creds and create_kdb and create_user and start_kdc: 954*7f2fe78bSCy Schubert self.kinit(self.user_princ, password('user')) 955*7f2fe78bSCy Schubert self.klist(self.user_princ) 956*7f2fe78bSCy Schubert 957*7f2fe78bSCy Schubert def _create_empty_dir(self): 958*7f2fe78bSCy Schubert dir = self.testdir 959*7f2fe78bSCy Schubert shutil.rmtree(dir, True) 960*7f2fe78bSCy Schubert if (os.path.exists(dir)): 961*7f2fe78bSCy Schubert fail('Cannot remove %s to create test realm.' % dir) 962*7f2fe78bSCy Schubert os.mkdir(dir) 963*7f2fe78bSCy Schubert 964*7f2fe78bSCy Schubert def _create_conf(self, profile, filename): 965*7f2fe78bSCy Schubert file = open(filename, 'w') 966*7f2fe78bSCy Schubert for section, contents in profile.items(): 967*7f2fe78bSCy Schubert file.write('[%s]\n' % section) 968*7f2fe78bSCy Schubert self._write_cfg_section(file, contents, 1) 969*7f2fe78bSCy Schubert file.close() 970*7f2fe78bSCy Schubert 971*7f2fe78bSCy Schubert def _write_cfg_section(self, file, contents, indent_level): 972*7f2fe78bSCy Schubert indent = '\t' * indent_level 973*7f2fe78bSCy Schubert for name, value in contents.items(): 974*7f2fe78bSCy Schubert name = self._subst_cfg_value(name) 975*7f2fe78bSCy Schubert if isinstance(value, dict): 976*7f2fe78bSCy Schubert # A dictionary value yields a list subsection. 977*7f2fe78bSCy Schubert file.write('%s%s = {\n' % (indent, name)) 978*7f2fe78bSCy Schubert self._write_cfg_section(file, value, indent_level + 1) 979*7f2fe78bSCy Schubert file.write('%s}\n' % indent) 980*7f2fe78bSCy Schubert elif isinstance(value, list): 981*7f2fe78bSCy Schubert # A list value yields multiple values for the same name. 982*7f2fe78bSCy Schubert for item in value: 983*7f2fe78bSCy Schubert item = self._subst_cfg_value(item) 984*7f2fe78bSCy Schubert file.write('%s%s = %s\n' % (indent, name, item)) 985*7f2fe78bSCy Schubert elif isinstance(value, str): 986*7f2fe78bSCy Schubert # A string value yields a straightforward variable setting. 987*7f2fe78bSCy Schubert value = self._subst_cfg_value(value) 988*7f2fe78bSCy Schubert file.write('%s%s = %s\n' % (indent, name, value)) 989*7f2fe78bSCy Schubert else: 990*7f2fe78bSCy Schubert raise TypeError() 991*7f2fe78bSCy Schubert 992*7f2fe78bSCy Schubert def _subst_cfg_value(self, value): 993*7f2fe78bSCy Schubert global buildtop, srctop, hostname 994*7f2fe78bSCy Schubert template = string.Template(value) 995*7f2fe78bSCy Schubert subst = template.substitute(realm=self.realm, 996*7f2fe78bSCy Schubert testdir=self.testdir, 997*7f2fe78bSCy Schubert buildtop=buildtop, 998*7f2fe78bSCy Schubert srctop=srctop, 999*7f2fe78bSCy Schubert plugins=plugins, 1000*7f2fe78bSCy Schubert certs=pkinit_certs, 1001*7f2fe78bSCy Schubert hostname=hostname, 1002*7f2fe78bSCy Schubert port0=self.portbase, 1003*7f2fe78bSCy Schubert port1=self.portbase + 1, 1004*7f2fe78bSCy Schubert port2=self.portbase + 2, 1005*7f2fe78bSCy Schubert port3=self.portbase + 3, 1006*7f2fe78bSCy Schubert port4=self.portbase + 4, 1007*7f2fe78bSCy Schubert port5=self.portbase + 5, 1008*7f2fe78bSCy Schubert port6=self.portbase + 6, 1009*7f2fe78bSCy Schubert port7=self.portbase + 7, 1010*7f2fe78bSCy Schubert port8=self.portbase + 8, 1011*7f2fe78bSCy Schubert port9=self.portbase + 9) 1012*7f2fe78bSCy Schubert # Empty values must be quoted to avoid a syntax error. 1013*7f2fe78bSCy Schubert return subst if subst else '""' 1014*7f2fe78bSCy Schubert 1015*7f2fe78bSCy Schubert def _create_acl(self): 1016*7f2fe78bSCy Schubert global hostname 1017*7f2fe78bSCy Schubert filename = os.path.join(self.testdir, 'acl') 1018*7f2fe78bSCy Schubert file = open(filename, 'w') 1019*7f2fe78bSCy Schubert file.write('%s *e\n' % self.admin_princ) 1020*7f2fe78bSCy Schubert file.write('kiprop/%s@%s p\n' % (hostname, self.realm)) 1021*7f2fe78bSCy Schubert file.close() 1022*7f2fe78bSCy Schubert 1023*7f2fe78bSCy Schubert def _create_dictfile(self): 1024*7f2fe78bSCy Schubert filename = os.path.join(self.testdir, 'dictfile') 1025*7f2fe78bSCy Schubert file = open(filename, 'w') 1026*7f2fe78bSCy Schubert file.write('weak_password\n') 1027*7f2fe78bSCy Schubert file.close() 1028*7f2fe78bSCy Schubert 1029*7f2fe78bSCy Schubert def _make_env(self, krb5_conf_path, kdc_conf_path): 1030*7f2fe78bSCy Schubert env = _build_env() 1031*7f2fe78bSCy Schubert env['KRB5_CONFIG'] = krb5_conf_path 1032*7f2fe78bSCy Schubert env['KRB5_KDC_PROFILE'] = kdc_conf_path or os.devnull 1033*7f2fe78bSCy Schubert env['KRB5CCNAME'] = self.ccache 1034*7f2fe78bSCy Schubert env['KRB5_KTNAME'] = self.keytab 1035*7f2fe78bSCy Schubert env['KRB5_CLIENT_KTNAME'] = self.client_keytab 1036*7f2fe78bSCy Schubert env['KRB5RCACHEDIR'] = self.testdir 1037*7f2fe78bSCy Schubert env['KPROPD_PORT'] = str(self.kprop_port()) 1038*7f2fe78bSCy Schubert env['KPROP_PORT'] = str(self.kprop_port()) 1039*7f2fe78bSCy Schubert env['GSS_MECH_CONFIG'] = self.gss_mech_config 1040*7f2fe78bSCy Schubert return env 1041*7f2fe78bSCy Schubert 1042*7f2fe78bSCy Schubert def run(self, args, env=None, **keywords): 1043*7f2fe78bSCy Schubert if env is None: 1044*7f2fe78bSCy Schubert env = self.env 1045*7f2fe78bSCy Schubert return _run_cmd(args, env, **keywords) 1046*7f2fe78bSCy Schubert 1047*7f2fe78bSCy Schubert def kprop_port(self): 1048*7f2fe78bSCy Schubert return self.portbase + 3 1049*7f2fe78bSCy Schubert 1050*7f2fe78bSCy Schubert def server_port(self): 1051*7f2fe78bSCy Schubert return self.portbase + 5 1052*7f2fe78bSCy Schubert 1053*7f2fe78bSCy Schubert def start_server(self, args, sentinel, env=None): 1054*7f2fe78bSCy Schubert if env is None: 1055*7f2fe78bSCy Schubert env = self.env 1056*7f2fe78bSCy Schubert return _start_daemon(args, env, sentinel) 1057*7f2fe78bSCy Schubert 1058*7f2fe78bSCy Schubert def start_in_inetd(self, args, port=None, env=None): 1059*7f2fe78bSCy Schubert if not port: 1060*7f2fe78bSCy Schubert port = self.server_port() 1061*7f2fe78bSCy Schubert if env is None: 1062*7f2fe78bSCy Schubert env = self.env 1063*7f2fe78bSCy Schubert inetd_args = [t_inetd, str(port), args[0]] + args 1064*7f2fe78bSCy Schubert return _start_daemon(inetd_args, env, 'Ready!') 1065*7f2fe78bSCy Schubert 1066*7f2fe78bSCy Schubert def create_kdb(self): 1067*7f2fe78bSCy Schubert global kdb5_util 1068*7f2fe78bSCy Schubert self.run([kdb5_util, 'create', '-s', '-P', 'master']) 1069*7f2fe78bSCy Schubert 1070*7f2fe78bSCy Schubert def start_kdc(self, args=[], env=None): 1071*7f2fe78bSCy Schubert global krb5kdc 1072*7f2fe78bSCy Schubert if env is None: 1073*7f2fe78bSCy Schubert env = self.env 1074*7f2fe78bSCy Schubert assert(self._kdc_proc is None) 1075*7f2fe78bSCy Schubert self._kdc_proc = _start_daemon([krb5kdc, '-n'] + args, env, 1076*7f2fe78bSCy Schubert 'starting...') 1077*7f2fe78bSCy Schubert 1078*7f2fe78bSCy Schubert def stop_kdc(self): 1079*7f2fe78bSCy Schubert assert(self._kdc_proc is not None) 1080*7f2fe78bSCy Schubert stop_daemon(self._kdc_proc) 1081*7f2fe78bSCy Schubert self._kdc_proc = None 1082*7f2fe78bSCy Schubert 1083*7f2fe78bSCy Schubert def start_kadmind(self, env=None): 1084*7f2fe78bSCy Schubert global krb5kdc 1085*7f2fe78bSCy Schubert if env is None: 1086*7f2fe78bSCy Schubert env = self.env 1087*7f2fe78bSCy Schubert assert(self._kadmind_proc is None) 1088*7f2fe78bSCy Schubert dump_path = os.path.join(self.testdir, 'dump') 1089*7f2fe78bSCy Schubert self._kadmind_proc = _start_daemon([kadmind, '-nofork', 1090*7f2fe78bSCy Schubert '-p', kdb5_util, '-K', kprop, 1091*7f2fe78bSCy Schubert '-F', dump_path], env, 1092*7f2fe78bSCy Schubert 'starting...') 1093*7f2fe78bSCy Schubert 1094*7f2fe78bSCy Schubert def stop_kadmind(self): 1095*7f2fe78bSCy Schubert assert(self._kadmind_proc is not None) 1096*7f2fe78bSCy Schubert stop_daemon(self._kadmind_proc) 1097*7f2fe78bSCy Schubert self._kadmind_proc = None 1098*7f2fe78bSCy Schubert 1099*7f2fe78bSCy Schubert def _kpropd_args(self): 1100*7f2fe78bSCy Schubert datatrans_path = os.path.join(self.testdir, 'incoming-datatrans') 1101*7f2fe78bSCy Schubert kpropdacl_path = os.path.join(self.testdir, 'kpropd-acl') 1102*7f2fe78bSCy Schubert return [kpropd, '-D', '-P', str(self.kprop_port()), 1103*7f2fe78bSCy Schubert '-f', datatrans_path, '-p', kdb5_util, '-a', kpropdacl_path] 1104*7f2fe78bSCy Schubert 1105*7f2fe78bSCy Schubert def start_kpropd(self, env, args=[]): 1106*7f2fe78bSCy Schubert proc = _start_daemon(self._kpropd_args() + args, env, 'ready') 1107*7f2fe78bSCy Schubert self._kpropd_procs.append(proc) 1108*7f2fe78bSCy Schubert return proc 1109*7f2fe78bSCy Schubert 1110*7f2fe78bSCy Schubert def stop_kpropd(self, proc): 1111*7f2fe78bSCy Schubert stop_daemon(proc) 1112*7f2fe78bSCy Schubert self._kpropd_procs.remove(proc) 1113*7f2fe78bSCy Schubert 1114*7f2fe78bSCy Schubert def run_kpropd_once(self, env, args=[]): 1115*7f2fe78bSCy Schubert return self.run(self._kpropd_args() + ['-t'] + args, env=env) 1116*7f2fe78bSCy Schubert 1117*7f2fe78bSCy Schubert def stop(self): 1118*7f2fe78bSCy Schubert if self._kdc_proc: 1119*7f2fe78bSCy Schubert self.stop_kdc() 1120*7f2fe78bSCy Schubert if self._kadmind_proc: 1121*7f2fe78bSCy Schubert self.stop_kadmind() 1122*7f2fe78bSCy Schubert for p in self._kpropd_procs: 1123*7f2fe78bSCy Schubert stop_daemon(p) 1124*7f2fe78bSCy Schubert self._kpropd_procs = [] 1125*7f2fe78bSCy Schubert 1126*7f2fe78bSCy Schubert def addprinc(self, princname, password=None): 1127*7f2fe78bSCy Schubert if password: 1128*7f2fe78bSCy Schubert self.run([kadminl, 'addprinc', '-pw', password, princname]) 1129*7f2fe78bSCy Schubert else: 1130*7f2fe78bSCy Schubert self.run([kadminl, 'addprinc', '-randkey', princname]) 1131*7f2fe78bSCy Schubert 1132*7f2fe78bSCy Schubert def extract_keytab(self, princname, keytab): 1133*7f2fe78bSCy Schubert self.run([kadminl, 'ktadd', '-k', keytab, '-norandkey', princname]) 1134*7f2fe78bSCy Schubert 1135*7f2fe78bSCy Schubert def kinit(self, princname, password=None, flags=[], **keywords): 1136*7f2fe78bSCy Schubert if password: 1137*7f2fe78bSCy Schubert input = password + "\n" 1138*7f2fe78bSCy Schubert else: 1139*7f2fe78bSCy Schubert input = None 1140*7f2fe78bSCy Schubert return self.run([kinit] + flags + [princname], input=input, **keywords) 1141*7f2fe78bSCy Schubert 1142*7f2fe78bSCy Schubert def pkinit(self, princ, flags=[], **kw): 1143*7f2fe78bSCy Schubert id = 'FILE:%s,%s' % (os.path.join(pkinit_certs, 'user.pem'), 1144*7f2fe78bSCy Schubert os.path.join(pkinit_certs, 'privkey.pem')) 1145*7f2fe78bSCy Schubert flags = flags + ['-X', 'X509_user_identity=%s' % id] 1146*7f2fe78bSCy Schubert self.kinit(princ, flags=flags, **kw) 1147*7f2fe78bSCy Schubert 1148*7f2fe78bSCy Schubert def klist(self, client_princ, service_princ=None, ccache=None, **keywords): 1149*7f2fe78bSCy Schubert if service_princ is None: 1150*7f2fe78bSCy Schubert service_princ = self.krbtgt_princ 1151*7f2fe78bSCy Schubert if ccache is None: 1152*7f2fe78bSCy Schubert ccache = self.ccache 1153*7f2fe78bSCy Schubert ccachestr = ccache 1154*7f2fe78bSCy Schubert if len(ccachestr) < 2 or ':' not in ccachestr[2:]: 1155*7f2fe78bSCy Schubert ccachestr = 'FILE:' + ccachestr 1156*7f2fe78bSCy Schubert output = self.run([klist, ccache], **keywords) 1157*7f2fe78bSCy Schubert if (('Ticket cache: %s\n' % ccachestr) not in output or 1158*7f2fe78bSCy Schubert ('Default principal: %s\n' % client_princ) not in output or 1159*7f2fe78bSCy Schubert service_princ not in output): 1160*7f2fe78bSCy Schubert fail('Unexpected klist output.') 1161*7f2fe78bSCy Schubert 1162*7f2fe78bSCy Schubert def klist_keytab(self, princ, keytab=None, **keywords): 1163*7f2fe78bSCy Schubert if keytab is None: 1164*7f2fe78bSCy Schubert keytab = self.keytab 1165*7f2fe78bSCy Schubert output = self.run([klist, '-k', keytab], **keywords) 1166*7f2fe78bSCy Schubert if (('Keytab name: FILE:%s\n' % keytab) not in output or 1167*7f2fe78bSCy Schubert 'KVNO Principal\n----' not in output or 1168*7f2fe78bSCy Schubert princ not in output): 1169*7f2fe78bSCy Schubert fail('Unexpected klist output.') 1170*7f2fe78bSCy Schubert 1171*7f2fe78bSCy Schubert def prep_kadmin(self, princname=None, pw=None, flags=[]): 1172*7f2fe78bSCy Schubert if princname is None: 1173*7f2fe78bSCy Schubert princname = self.admin_princ 1174*7f2fe78bSCy Schubert pw = password('admin') 1175*7f2fe78bSCy Schubert return self.kinit(princname, pw, 1176*7f2fe78bSCy Schubert flags=['-S', 'kadmin/admin', 1177*7f2fe78bSCy Schubert '-c', self.kadmin_ccache] + flags) 1178*7f2fe78bSCy Schubert 1179*7f2fe78bSCy Schubert def run_kadmin(self, args, **keywords): 1180*7f2fe78bSCy Schubert return self.run([kadmin, '-c', self.kadmin_ccache] + args, **keywords) 1181*7f2fe78bSCy Schubert 1182*7f2fe78bSCy Schubert def special_env(self, name, has_kdc_conf, krb5_conf=None, kdc_conf=None): 1183*7f2fe78bSCy Schubert krb5_conf_path = os.path.join(self.testdir, 'krb5.conf.%s' % name) 1184*7f2fe78bSCy Schubert krb5_conf = _cfg_merge(self._krb5_conf, krb5_conf) 1185*7f2fe78bSCy Schubert self._create_conf(krb5_conf, krb5_conf_path) 1186*7f2fe78bSCy Schubert if has_kdc_conf: 1187*7f2fe78bSCy Schubert kdc_conf_path = os.path.join(self.testdir, 'kdc.conf.%s' % name) 1188*7f2fe78bSCy Schubert kdc_conf = _cfg_merge(self._kdc_conf, kdc_conf) 1189*7f2fe78bSCy Schubert self._create_conf(kdc_conf, kdc_conf_path) 1190*7f2fe78bSCy Schubert else: 1191*7f2fe78bSCy Schubert kdc_conf_path = None 1192*7f2fe78bSCy Schubert return self._make_env(krb5_conf_path, kdc_conf_path) 1193*7f2fe78bSCy Schubert 1194*7f2fe78bSCy Schubert 1195*7f2fe78bSCy Schubertdef multipass_realms(**keywords): 1196*7f2fe78bSCy Schubert global _current_pass, _passes, testpass 1197*7f2fe78bSCy Schubert caller_krb5_conf = keywords.get('krb5_conf') 1198*7f2fe78bSCy Schubert caller_kdc_conf = keywords.get('kdc_conf') 1199*7f2fe78bSCy Schubert for p in _passes: 1200*7f2fe78bSCy Schubert (name, krbtgt_keysalt, krb5_conf, kdc_conf) = p 1201*7f2fe78bSCy Schubert if testpass and name != testpass: 1202*7f2fe78bSCy Schubert continue 1203*7f2fe78bSCy Schubert output('*** Beginning pass %s\n' % name) 1204*7f2fe78bSCy Schubert keywords['krb5_conf'] = _cfg_merge(krb5_conf, caller_krb5_conf) 1205*7f2fe78bSCy Schubert keywords['kdc_conf'] = _cfg_merge(kdc_conf, caller_kdc_conf) 1206*7f2fe78bSCy Schubert keywords['krbtgt_keysalt'] = krbtgt_keysalt 1207*7f2fe78bSCy Schubert _current_pass = name 1208*7f2fe78bSCy Schubert realm = K5Realm(**keywords) 1209*7f2fe78bSCy Schubert yield realm 1210*7f2fe78bSCy Schubert realm.stop() 1211*7f2fe78bSCy Schubert _current_pass = None 1212*7f2fe78bSCy Schubert 1213*7f2fe78bSCy Schubert 1214*7f2fe78bSCy Schubertdef multidb_realms(**keywords): 1215*7f2fe78bSCy Schubert global _current_db, _dbpasses 1216*7f2fe78bSCy Schubert caller_kdc_conf = keywords.get('kdc_conf') 1217*7f2fe78bSCy Schubert for p in _dbpasses: 1218*7f2fe78bSCy Schubert (name, kdc_conf) = p 1219*7f2fe78bSCy Schubert output('*** Using DB type %s\n' % name) 1220*7f2fe78bSCy Schubert keywords['kdc_conf'] = _cfg_merge(kdc_conf, caller_kdc_conf) 1221*7f2fe78bSCy Schubert _current_db = name 1222*7f2fe78bSCy Schubert realm = K5Realm(**keywords) 1223*7f2fe78bSCy Schubert yield realm 1224*7f2fe78bSCy Schubert realm.stop() 1225*7f2fe78bSCy Schubert _current_db = None 1226*7f2fe78bSCy Schubert 1227*7f2fe78bSCy Schubert 1228*7f2fe78bSCy Schubertdef cross_realms(num, xtgts=None, args=None, **keywords): 1229*7f2fe78bSCy Schubert # Build keyword args for each realm. 1230*7f2fe78bSCy Schubert realm_args = [] 1231*7f2fe78bSCy Schubert for i in range(num): 1232*7f2fe78bSCy Schubert realmnumber = i + 1 1233*7f2fe78bSCy Schubert # Start with any global keyword arguments to this function. 1234*7f2fe78bSCy Schubert a = keywords.copy() 1235*7f2fe78bSCy Schubert if args and args[i]: 1236*7f2fe78bSCy Schubert # Merge in specific arguments for this realm. Use 1237*7f2fe78bSCy Schubert # _cfg_merge for config fragments. 1238*7f2fe78bSCy Schubert a.update(args[i]) 1239*7f2fe78bSCy Schubert for cf in ('krb5_conf', 'kdc_conf'): 1240*7f2fe78bSCy Schubert if cf in keywords and cf in args[i]: 1241*7f2fe78bSCy Schubert a[cf] = _cfg_merge(keywords[cf], args[i][cf]) 1242*7f2fe78bSCy Schubert # Set defaults for the realm name, testdir, and portbase. 1243*7f2fe78bSCy Schubert if not 'realm' in a: 1244*7f2fe78bSCy Schubert a['realm'] = 'KRBTEST%d.COM' % realmnumber 1245*7f2fe78bSCy Schubert if not 'testdir' in a: 1246*7f2fe78bSCy Schubert a['testdir'] = os.path.join('testdir', str(realmnumber)) 1247*7f2fe78bSCy Schubert if not 'portbase' in a: 1248*7f2fe78bSCy Schubert a['portbase'] = 61000 + 10 * realmnumber 1249*7f2fe78bSCy Schubert realm_args.append(a) 1250*7f2fe78bSCy Schubert 1251*7f2fe78bSCy Schubert # Build a [realms] config fragment containing all of the realms. 1252*7f2fe78bSCy Schubert realmsection = { '$realm' : None } 1253*7f2fe78bSCy Schubert for a in realm_args: 1254*7f2fe78bSCy Schubert name = a['realm'] 1255*7f2fe78bSCy Schubert portbase = a['portbase'] 1256*7f2fe78bSCy Schubert realmsection[name] = { 1257*7f2fe78bSCy Schubert 'kdc' : '$hostname:%d' % portbase, 1258*7f2fe78bSCy Schubert 'admin_server' : '$hostname:%d' % (portbase + 1), 1259*7f2fe78bSCy Schubert 'kpasswd_server' : '$hostname:%d' % (portbase + 2) 1260*7f2fe78bSCy Schubert } 1261*7f2fe78bSCy Schubert realmscfg = {'realms': realmsection} 1262*7f2fe78bSCy Schubert 1263*7f2fe78bSCy Schubert # Set realmsection in each realm's krb5_conf keyword argument. 1264*7f2fe78bSCy Schubert for a in realm_args: 1265*7f2fe78bSCy Schubert a['krb5_conf'] = _cfg_merge(realmscfg, a.get('krb5_conf')) 1266*7f2fe78bSCy Schubert 1267*7f2fe78bSCy Schubert if xtgts is None: 1268*7f2fe78bSCy Schubert # Default to cross tgts for every pair of realms. 1269*7f2fe78bSCy Schubert # (itertools.permutations would work here but is new in 2.6.) 1270*7f2fe78bSCy Schubert xtgts = [(x,y) for x in range(num) for y in range(num) if x != y] 1271*7f2fe78bSCy Schubert 1272*7f2fe78bSCy Schubert # Create the realms. 1273*7f2fe78bSCy Schubert realms = [] 1274*7f2fe78bSCy Schubert for i in range(num): 1275*7f2fe78bSCy Schubert r = K5Realm(**realm_args[i]) 1276*7f2fe78bSCy Schubert # Create specified cross TGTs in this realm's db. 1277*7f2fe78bSCy Schubert for j in range(num): 1278*7f2fe78bSCy Schubert if j == i: 1279*7f2fe78bSCy Schubert continue 1280*7f2fe78bSCy Schubert iname = r.realm 1281*7f2fe78bSCy Schubert jname = realm_args[j]['realm'] 1282*7f2fe78bSCy Schubert if (i, j) in xtgts: 1283*7f2fe78bSCy Schubert # This realm can authenticate to realm j. 1284*7f2fe78bSCy Schubert r.addprinc('krbtgt/%s' % jname, password('cr-%d-%d-' % (i, j))) 1285*7f2fe78bSCy Schubert if (j, i) in xtgts: 1286*7f2fe78bSCy Schubert # Realm j can authenticate to this realm. 1287*7f2fe78bSCy Schubert r.addprinc('krbtgt/%s@%s' % (iname, jname), 1288*7f2fe78bSCy Schubert password('cr-%d-%d-' % (j, i))) 1289*7f2fe78bSCy Schubert realms.append(r) 1290*7f2fe78bSCy Schubert return realms 1291*7f2fe78bSCy Schubert 1292*7f2fe78bSCy Schubert 1293*7f2fe78bSCy Schubert_default_krb5_conf = { 1294*7f2fe78bSCy Schubert 'libdefaults': { 1295*7f2fe78bSCy Schubert 'default_realm': '$realm', 1296*7f2fe78bSCy Schubert 'dns_lookup_kdc': 'false', 1297*7f2fe78bSCy Schubert 'dns_canonicalize_hostname': 'fallback', 1298*7f2fe78bSCy Schubert 'qualify_shortname': '', 1299*7f2fe78bSCy Schubert 'plugin_base_dir': '$plugins'}, 1300*7f2fe78bSCy Schubert 'realms': {'$realm': { 1301*7f2fe78bSCy Schubert 'kdc': '$hostname:$port0', 1302*7f2fe78bSCy Schubert 'admin_server': '$hostname:$port1', 1303*7f2fe78bSCy Schubert 'kpasswd_server': '$hostname:$port2'}}} 1304*7f2fe78bSCy Schubert 1305*7f2fe78bSCy Schubert 1306*7f2fe78bSCy Schubert_default_kdc_conf = { 1307*7f2fe78bSCy Schubert 'realms': {'$realm': { 1308*7f2fe78bSCy Schubert 'database_module': 'db', 1309*7f2fe78bSCy Schubert 'iprop_port': '$port4', 1310*7f2fe78bSCy Schubert 'key_stash_file': '$testdir/stash', 1311*7f2fe78bSCy Schubert 'acl_file': '$testdir/acl', 1312*7f2fe78bSCy Schubert 'dict_file': '$testdir/dictfile', 1313*7f2fe78bSCy Schubert 'kadmind_port': '$port1', 1314*7f2fe78bSCy Schubert 'kpasswd_port': '$port2', 1315*7f2fe78bSCy Schubert 'kdc_listen': '$port0', 1316*7f2fe78bSCy Schubert 'kdc_tcp_listen': '$port0'}}, 1317*7f2fe78bSCy Schubert 'dbmodules': { 1318*7f2fe78bSCy Schubert 'db_module_dir': '$plugins/kdb', 1319*7f2fe78bSCy Schubert 'db': {'db_library': 'db2', 'database_name' : '$testdir/db'}}, 1320*7f2fe78bSCy Schubert 'logging': { 1321*7f2fe78bSCy Schubert 'admin_server': 'FILE:$testdir/kadmind5.log', 1322*7f2fe78bSCy Schubert 'kdc': 'FILE:$testdir/kdc.log', 1323*7f2fe78bSCy Schubert 'default': 'FILE:$testdir/others.log'}} 1324*7f2fe78bSCy Schubert 1325*7f2fe78bSCy Schubert 1326*7f2fe78bSCy Schubert_lmdb_kdc_conf = {'dbmodules': {'db': {'db_library': 'klmdb', 1327*7f2fe78bSCy Schubert 'nosync': 'true'}}} 1328*7f2fe78bSCy Schubert 1329*7f2fe78bSCy Schubert 1330*7f2fe78bSCy Schubert_pkinit_krb5_conf = {'realms': {'$realm': { 1331*7f2fe78bSCy Schubert 'pkinit_anchors': 'FILE:$certs/ca.pem'}}} 1332*7f2fe78bSCy Schubert_pkinit_kdc_conf = {'realms': {'$realm': { 1333*7f2fe78bSCy Schubert 'pkinit_identity': 'FILE:$certs/kdc.pem,$certs/privkey.pem'}}} 1334*7f2fe78bSCy Schubert 1335*7f2fe78bSCy Schubert 1336*7f2fe78bSCy Schubert# A pass is a tuple of: name, krbtgt_keysalt, krb5_conf, kdc_conf. 1337*7f2fe78bSCy Schubert_passes = [ 1338*7f2fe78bSCy Schubert # No special settings; exercises AES256. 1339*7f2fe78bSCy Schubert ('default', None, None, None), 1340*7f2fe78bSCy Schubert 1341*7f2fe78bSCy Schubert # Exercise the DES3 enctype. 1342*7f2fe78bSCy Schubert ('des3', None, 1343*7f2fe78bSCy Schubert {'libdefaults': {'permitted_enctypes': 'des3 aes256-sha1'}}, 1344*7f2fe78bSCy Schubert {'realms': {'$realm': { 1345*7f2fe78bSCy Schubert 'supported_enctypes': 'des3-cbc-sha1:normal', 1346*7f2fe78bSCy Schubert 'master_key_type': 'des3-cbc-sha1'}}}), 1347*7f2fe78bSCy Schubert 1348*7f2fe78bSCy Schubert # Exercise the arcfour enctype. 1349*7f2fe78bSCy Schubert ('arcfour', None, 1350*7f2fe78bSCy Schubert {'libdefaults': {'permitted_enctypes': 'rc4 aes256-sha1'}}, 1351*7f2fe78bSCy Schubert {'realms': {'$realm': { 1352*7f2fe78bSCy Schubert 'supported_enctypes': 'arcfour-hmac:normal', 1353*7f2fe78bSCy Schubert 'master_key_type': 'arcfour-hmac'}}}), 1354*7f2fe78bSCy Schubert 1355*7f2fe78bSCy Schubert # Exercise the AES128 enctype. 1356*7f2fe78bSCy Schubert ('aes128', None, 1357*7f2fe78bSCy Schubert {'libdefaults': {'permitted_enctypes': 'aes128-cts'}}, 1358*7f2fe78bSCy Schubert {'realms': {'$realm': { 1359*7f2fe78bSCy Schubert 'supported_enctypes': 'aes128-cts:normal', 1360*7f2fe78bSCy Schubert 'master_key_type': 'aes128-cts'}}}), 1361*7f2fe78bSCy Schubert 1362*7f2fe78bSCy Schubert # Exercise the camellia256-cts enctype. 1363*7f2fe78bSCy Schubert ('camellia256', None, 1364*7f2fe78bSCy Schubert {'libdefaults': {'permitted_enctypes': 'camellia256-cts'}}, 1365*7f2fe78bSCy Schubert {'realms': {'$realm': { 1366*7f2fe78bSCy Schubert 'supported_enctypes': 'camellia256-cts:normal', 1367*7f2fe78bSCy Schubert 'master_key_type': 'camellia256-cts'}}}), 1368*7f2fe78bSCy Schubert 1369*7f2fe78bSCy Schubert # Exercise the aes128-sha2 enctype. 1370*7f2fe78bSCy Schubert ('aes128-sha2', None, 1371*7f2fe78bSCy Schubert {'libdefaults': {'permitted_enctypes': 'aes128-sha2'}}, 1372*7f2fe78bSCy Schubert {'realms': {'$realm': { 1373*7f2fe78bSCy Schubert 'supported_enctypes': 'aes128-sha2:normal', 1374*7f2fe78bSCy Schubert 'master_key_type': 'aes128-sha2'}}}), 1375*7f2fe78bSCy Schubert 1376*7f2fe78bSCy Schubert # Exercise the aes256-sha2 enctype. 1377*7f2fe78bSCy Schubert ('aes256-sha2', None, 1378*7f2fe78bSCy Schubert {'libdefaults': {'permitted_enctypes': 'aes256-sha2'}}, 1379*7f2fe78bSCy Schubert {'realms': {'$realm': { 1380*7f2fe78bSCy Schubert 'supported_enctypes': 'aes256-sha2:normal', 1381*7f2fe78bSCy Schubert 'master_key_type': 'aes256-sha2'}}}), 1382*7f2fe78bSCy Schubert 1383*7f2fe78bSCy Schubert # Test a setup with modern principal keys but an old TGT key. 1384*7f2fe78bSCy Schubert ('aes256.destgt', 'arcfour-hmac:normal', 1385*7f2fe78bSCy Schubert {'libdefaults': {'allow_weak_crypto': 'true'}}, 1386*7f2fe78bSCy Schubert None) 1387*7f2fe78bSCy Schubert] 1388*7f2fe78bSCy Schubert 1389*7f2fe78bSCy Schubert_success = False 1390*7f2fe78bSCy Schubert_current_pass = None 1391*7f2fe78bSCy Schubert_current_db = None 1392*7f2fe78bSCy Schubert_daemons = [] 1393*7f2fe78bSCy Schubert_parse_args() 1394*7f2fe78bSCy Schubertatexit.register(_onexit) 1395*7f2fe78bSCy Schubertsignal.signal(signal.SIGINT, _onsigint) 1396*7f2fe78bSCy Schubert_outfile = open('testlog', 'w') 1397*7f2fe78bSCy Schubert_cmd_index = 1 1398*7f2fe78bSCy Schubert_last_mark = None 1399*7f2fe78bSCy Schubert_last_cmd = None 1400*7f2fe78bSCy Schubert_last_cmd_output = None 1401*7f2fe78bSCy Schubert_failed_daemon_output = None 1402*7f2fe78bSCy Schubertbuildtop = _find_buildtop() 1403*7f2fe78bSCy Schubertsrctop = _find_srctop() 1404*7f2fe78bSCy Schubertplugins = os.path.join(buildtop, 'plugins') 1405*7f2fe78bSCy Schubertpkinit_enabled = os.path.exists(os.path.join(plugins, 'preauth', 'pkinit.so')) 1406*7f2fe78bSCy Schubertpkinit_certs = os.path.join(srctop, 'tests', 'pkinit-certs') 1407*7f2fe78bSCy Schuberthostname = socket.gethostname().lower() 1408*7f2fe78bSCy Schubertnull_input = open(os.devnull, 'r') 1409*7f2fe78bSCy Schubert 1410*7f2fe78bSCy Schubertif not os.path.exists(os.path.join(buildtop, 'runenv.py')): 1411*7f2fe78bSCy Schubert fail('You must run "make runenv.py" in %s first.' % buildtop) 1412*7f2fe78bSCy Schubertsys.path = [buildtop] + sys.path 1413*7f2fe78bSCy Schubertimport runenv 1414*7f2fe78bSCy Schubert 1415*7f2fe78bSCy Schubert# A DB pass is a tuple of: name, kdc_conf. 1416*7f2fe78bSCy Schubert_dbpasses = [('db2', None)] 1417*7f2fe78bSCy Schubertif runenv.have_lmdb == 'yes': 1418*7f2fe78bSCy Schubert _dbpasses.append(('lmdb', _lmdb_kdc_conf)) 1419*7f2fe78bSCy Schubert 1420*7f2fe78bSCy Schubertkrb5kdc = os.path.join(buildtop, 'kdc', 'krb5kdc') 1421*7f2fe78bSCy Schubertkadmind = os.path.join(buildtop, 'kadmin', 'server', 'kadmind') 1422*7f2fe78bSCy Schubertkadmin = os.path.join(buildtop, 'kadmin', 'cli', 'kadmin') 1423*7f2fe78bSCy Schubertkadminl = os.path.join(buildtop, 'kadmin', 'cli', 'kadmin.local') 1424*7f2fe78bSCy Schubertkdb5_ldap_util = os.path.join(buildtop, 'plugins', 'kdb', 'ldap', 'ldap_util', 1425*7f2fe78bSCy Schubert 'kdb5_ldap_util') 1426*7f2fe78bSCy Schubertkdb5_util = os.path.join(buildtop, 'kadmin', 'dbutil', 'kdb5_util') 1427*7f2fe78bSCy Schubertktutil = os.path.join(buildtop, 'kadmin', 'ktutil', 'ktutil') 1428*7f2fe78bSCy Schubertkinit = os.path.join(buildtop, 'clients', 'kinit', 'kinit') 1429*7f2fe78bSCy Schubertklist = os.path.join(buildtop, 'clients', 'klist', 'klist') 1430*7f2fe78bSCy Schubertkswitch = os.path.join(buildtop, 'clients', 'kswitch', 'kswitch') 1431*7f2fe78bSCy Schubertkvno = os.path.join(buildtop, 'clients', 'kvno', 'kvno') 1432*7f2fe78bSCy Schubertkdestroy = os.path.join(buildtop, 'clients', 'kdestroy', 'kdestroy') 1433*7f2fe78bSCy Schubertkpasswd = os.path.join(buildtop, 'clients', 'kpasswd', 'kpasswd') 1434*7f2fe78bSCy Schubertt_inetd = os.path.join(buildtop, 'tests', 't_inetd') 1435*7f2fe78bSCy Schubertkproplog = os.path.join(buildtop, 'kprop', 'kproplog') 1436*7f2fe78bSCy Schubertkpropd = os.path.join(buildtop, 'kprop', 'kpropd') 1437*7f2fe78bSCy Schubertkprop = os.path.join(buildtop, 'kprop', 'kprop') 1438